news 2026/6/2 13:21:13

基于Arduino与红外传感器的无接触电子骰子制作全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Arduino与红外传感器的无接触电子骰子制作全解析

1. 项目概述与核心思路

前阵子想和孩子玩桌游,但普通的骰子大家轮流摸来摸去,总觉得不太卫生。作为一个喜欢折腾硬件的“老父亲”,我琢磨着能不能做个不用手碰、隔空一晃就能出结果的电子骰子。这个想法听起来有点意思,做起来其实并不复杂,核心就是用一块Arduino板子,搭配一个红外传感器和一个LED点阵屏,把传统骰子的随机性和物理交互,用电子化的方式无接触地实现出来。

这个“无接触电子骰子”本质上是一个基于中断响应机制的嵌入式交互设备。它的工作逻辑很清晰:红外传感器持续检测前方是否有物体(比如手)经过,一旦检测到,就向Arduino发送一个中断信号。Arduino收到中断后,立即暂停当前的主循环,去执行一个生成1到6随机数的函数,然后将这个数字对应的骰子点数图案,显示在8x8的LED矩阵上。整个过程中,用户完全不需要触碰设备,既卫生又有科技感。

项目适合有一定Arduino和焊接基础的朋友尝试,总成本可以控制在百元以内。它不仅仅是一个玩具,更是一个理解中断传感器应用LED矩阵驱动以及随机数生成等嵌入式核心概念的绝佳实践案例。下面,我就把从电路设计、代码编写到外壳组装的全过程,以及我踩过的坑和总结的经验,毫无保留地分享出来。

2. 核心硬件选型与电路设计解析

硬件是整个项目的骨架,选对元件并设计好电路,项目就成功了一半。我的核心思路是低功耗、易集成、高可靠性,毕竟这玩意儿是拿来玩的,不能动不动就出问题或者没电。

2.1 主控与显示单元:为什么是Arduino Nano和MAX7219?

主控芯片我选择了Arduino Nano。相比UNO,Nano体积更小巧,非常适合塞进骰子这种有限的空间里,而且其核心的ATmega328P芯片性能完全够用。有朋友问能不能用ESP8266,当然可以,它自带Wi-Fi,可以实现结果上传云端等高级功能,但对于我们这个“保持简单”的核心需求,Nano更便宜、更省电,也避免了无线模块带来的额外复杂度。

显示部分,我用了最常见的8x8 LED点阵屏,并自带MAX7219驱动芯片。这是关键选择。如果直接用Arduino的IO口去驱动64个LED,需要占用大量引脚,电路复杂,编程也麻烦。MAX7219芯片相当于一个“显示屏管家”,它通过简单的三线串行接口(DIN, CLK, CS)与Arduino通信,接收指令后,自己负责管理每一行每一列LED的亮灭。这样一来,Arduino只需要发几个字节的命令,就能控制整个屏幕,极大地简化了硬件连接和软件负担。市面上这种模块很便宜,集成度高,是点阵项目的不二之选。

2.2 传感与交互单元:红外传感器的妙用

实现“无接触”的核心是传感器。我选择了最普通的红外反射传感器(TCRT5000型)。它内部有一个红外发射管和一个红外接收管。发射管持续发出红外光,当有物体靠近时,红外光被反射回来,接收管接收到信号,其输出电平就会发生变化。

这里有一个重要的设计点:我将其输出端连接到Arduino Nano的外部中断引脚(Digital Pin 2)。在Arduino中,中断引脚(如D2, D3)可以配置为在电平变化时,立即打断主程序loop()的执行,转而去执行一个特定的中断服务函数。这意味着,只要手一挥过传感器,程序会立刻响应,几乎没有延迟,体验非常“跟手”。如果只是用普通的digitalRead()loop()里轮询检测,响应速度和可靠性都会差一些。

注意:红外传感器容易受环境光干扰,尤其是阳光或强日光灯。在组装时,最好将传感器稍微嵌入外壳内部,或者在其上方加一个小遮光罩,以减少杂散光的影响。实测在室内灯光下,工作非常稳定。

2.3 供电系统设计:升压模块的考量

整个系统需要稳定的5V电压。我使用了两节**AA电池(镍氢充电电池)**供电,单节标称1.2V,两节串联约2.4V,无法直接驱动需要5V的Arduino Nano和MAX7219模块。

因此,一个DC-DC升压(Boost)模块是必需的。我选用的是基于MT3608芯片的微型升压模块。它的效率高,体积小,带有一个可调电位器。在焊接前,必须先用万用表测量输出,调节电位器将电压精确设定在5.0V-5.1V。电压过高会烧毁元件,过低则可能导致系统工作不稳定。调好后,将电池盒的正负极分别焊接到升压模块的输入“IN+”和“IN-”,模块输出的“OUT+”和“OUT-”则提供给整个电路系统。

2.4 电路连接详解

理解了每个模块的作用,连接就水到渠成了。下面是详细的接线表,你可以像“抄作业”一样对照着接:

元件引脚/接口连接到 Arduino Nano说明
MAX7219 点阵模块VCC5V接升压模块输出的5V
GNDGND共地
DIND11 (MOSI)数据输入,也可接其他数字口
CSD10 (SS)片选,低电平有效
CLKD13 (SCK)时钟信号
红外传感器VCC5V
GNDGND
OUTD2关键!接外部中断0引脚
按键(可选)一脚D3 (或其它)用于手动触发/重置,接外部中断1
另一脚GND按下时接地
升压模块OUT+Nano VIN 或 5V*为整个系统供电
OUT-Nano GND系统公共地
电池盒正极升压模块 IN+
负极升压模块 IN-

提示:为便于调试,可以先在面包板上搭建整个电路,确认所有功能正常后再进行焊接。焊接时,建议使用热熔胶或胶棒固定主要模块,防止震动导致虚焊。

3. 软件逻辑与代码深度剖析

硬件是身体,软件是灵魂。这段代码虽然不长,但每一部分都体现了嵌入式编程的关键思想。

3.1 库文件与引脚定义

首先,必须安装驱动MAX7219点阵的库。我使用的是经典的“LedControl”库,在Arduino IDE的库管理中直接搜索安装即可。这个库封装了与MAX7219通信的底层细节,让我们可以用高级命令来控制显示。

#include <LedControl.h> // 引入LED控制库 // 定义MAX7219模块与Arduino的连接引脚 #define DIN_PIN 11 #define CS_PIN 10 #define CLK_PIN 13 // 定义红外传感器输出引脚(中断引脚) #define IR_SENSOR_PIN 2 // 初始化LedControl对象,参数为:(DIN, CLK, CS, 模块数量) LedControl lc = LedControl(DIN_PIN, CLK_PIN, CS_PIN, 1); // 定义骰子点数图案的字节数组(共6个面,每个面8字节) byte diceFaces[6][8] = { {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, // 1点 {0x00, 0x60, 0x60, 0x00, 0x00, 0x06, 0x06, 0x00}, // 2点 {0x60, 0x60, 0x00, 0x18, 0x18, 0x00, 0x06, 0x06}, // 3点 {0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00}, // 4点 {0x66, 0x66, 0x00, 0x18, 0x18, 0x00, 0x66, 0x66}, // 5点 {0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x66, 0x66} // 6点 }; volatile bool diceRolled = false; // 中断标志位,用volatile声明 int currentDiceNumber = 1; // 当前显示的点数

关键点解析

  1. LedControl lc(...):这个对象是我们与屏幕对话的“话筒”。最后一个参数1表示我们只连接了1个MAX7219模块(即一个8x8点阵)。
  2. 图案数据:diceFaces是一个二维数组。点阵是8行8列,在代码中用8个字节(byte)表示,每个字节的8个bit对应一行的8个LED(1亮0灭)。例如,数字“1”的图案,就是中间两个LED亮起。用十六进制(如0x18)表示比二进制更简洁。
  3. volatile bool diceRolled:这是一个在中断服务程序中会被修改的全局变量。volatile关键字告诉编译器,这个变量可能被程序主体之外的流程(即中断)改变,不要对它进行激进的优化,确保每次读取都从内存中获取最新值。这是使用中断时一个非常重要且容易忽略的细节。

3.2 初始化设置(setup函数)

setup()函数负责一次性初始化工作。

void setup() { // 初始化串口,用于调试输出(可选) Serial.begin(9600); // 1. 初始化LED点阵 lc.shutdown(0, false); // 唤醒第0个MAX7219模块(退出省电模式) lc.setIntensity(0, 8); // 设置亮度(0-15,8适中) lc.clearDisplay(0); // 清屏 // 2. 配置红外传感器引脚 pinMode(IR_SENSOR_PIN, INPUT_PULLUP); // 设置为输入,并启用内部上拉电阻 // 3. 配置外部中断 // attachInterrupt(digitalPinToInterrupt(中断引脚), 中断服务函数, 触发模式) attachInterrupt(digitalPinToInterrupt(IR_SENSOR_PIN), rollTheDice, FALLING); // 4. 显示开机动画 showStartupAnimation(); }

关键点解析

  1. lc.shutdown(0, false):MAX7219有省电模式,初始化时需要将其“唤醒”。
  2. pinMode(IR_SENSOR_PIN, INPUT_PULLUP):这里启用了Arduino的内部上拉电阻。当没有物体靠近时,传感器输出高电平;当检测到物体,输出变为低电平。上拉电阻确保了空闲时引脚有稳定的高电平,避免悬空状态下的误触发。
  3. attachInterrupt(...):这是中断配置的核心。digitalPinToInterrupt(IR_SENSOR_PIN)将物理引脚号转换为中断号(D2对应中断0)。rollTheDice是中断发生时自动调用的函数名。FALLING是触发模式,意为“下降沿触发”,即当传感器引脚电平从高变低(手挥过导致)的瞬间,触发中断。
  4. 开机动画:这是一个提升用户体验的小技巧,让设备启动时有明确的反馈。

3.3 主循环与中断服务程序

这是程序逻辑的核心,体现了中断如何与主程序协作。

void loop() { // 主循环大部分时间是空闲的,或者可以执行一些低优先级的任务 // 例如,可以在这里添加一个呼吸灯效果,或者低功耗睡眠(需要额外库) // 但为了简单,这里主循环什么都不做,等待中断 // 如果中断发生了(diceRolled被设为true) if (diceRolled) { // 清除中断标志,防止重复处理 diceRolled = false; // 生成一个1-6的随机数 // 注意:使用micros()作为随机种子,增加随机性 randomSeed(micros()); int newNumber = random(1, 7); // random(min, max) 生成 [min, max)区间 // 显示骰子滚动动画(视觉反馈) showRollingAnimation(); // 显示最终点数 showDiceFace(newNumber); currentDiceNumber = newNumber; // 短暂延时,防止一次挥手触发多次(防抖) delay(300); } } // 中断服务函数 (ISR) // 注意:ISR函数应尽可能短小,快进快出! void rollTheDice() { // 只做一件事:设置一个标志位。具体处理逻辑交给主循环。 diceRolled = true; }

关键点解析

  1. 中断服务程序(ISR)要短rollTheDice()函数极其简单,只设置一个标志位。这是因为在ISR执行期间,其他中断可能被禁用,长时间执行ISR会影响系统对其他事件的响应,甚至可能导致看门狗复位。复杂的逻辑(如动画、显示)应放在主循环中基于标志位去执行。
  2. 随机数生成random(1,7)看似简单,但randomSeed()很重要。如果不设置种子,每次上电后生成的随机数序列是相同的。用micros()(返回从开始运行起的微秒数)作为种子,由于上电时间点不可预测,能获得较好的随机效果。
  3. 防抖处理delay(300)在主循环中。红外传感器在检测到物体时,输出可能因手部微动或光线反射产生细微抖动,导致短时间内多次触发中断。这个延时可以有效地“忽略”掉第一次触发后300毫秒内的其他触发,保证一次手势只产生一次掷骰动作。这个值可以根据实际传感器灵敏度调整。

3.4 显示功能函数

这些函数封装了具体的显示操作,让主逻辑更清晰。

// 显示特定的骰子面 void showDiceFace(int number) { if (number < 1 || number > 6) return; // 安全校验 int faceIndex = number - 1; for (int row = 0; row < 8; row++) { lc.setRow(0, row, diceFaces[faceIndex][row]); } } // 骰子滚动动画(模拟骰子旋转) void showRollingAnimation() { int animationSteps = 15; // 动画帧数 for (int i = 0; i < animationSteps; i++) { int randomFace = random(0, 6); // 快速切换随机面 showDiceFace(randomFace + 1); delay(30 + i*2); // 动画速度逐渐变慢,增强真实感 } } // 开机动画(数字6飞入) void showStartupAnimation() { lc.clearDisplay(0); byte flyingSix[8] = {0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x66, 0x66}; for (int col = 7; col >= 0; col--) { lc.clearDisplay(0); for (int row = 0; row < 8; row++) { // 将图案逐列左移显示 lc.setColumn(0, col, flyingSix[row]); } delay(80); } showDiceFace(6); delay(500); }

实操心得:在编写showRollingAnimation()时,最初我用了固定的延时,动画看起来机械。后来改为延时逐渐增加(delay(30 + i*2)),模拟骰子旋转从快到慢最后停下的物理过程,视觉效果立刻自然了很多。这些小细节对提升用户体验至关重要。

4. 机械结构与外壳组装实战

电路和代码调试成功后,一个结实、美观的外壳能让项目从“实验品”变成“产品”。我的设计目标是:稳固、紧凑、散热良好、外观像骰子。

4.1 材料准备与加工

我找了一块废弃的**芯片板(或亚克力板、薄木板)**作为外壳材料。你需要切割出7个正方形:6个作为骰子的面,1个作为底板。边长根据你的LED点阵屏和电池盒尺寸决定,比它们大一圈即可,预留安装和走线空间。

工具清单

  • 尺子、铅笔、直角尺(用于精确画线)
  • 手锯或微型台锯(切割板材)
  • 电钻和不同直径的钻头(开孔)
  • 锉刀和砂纸(打磨毛边)
  • 热熔胶枪和胶棒(主要粘合剂)
  • 螺丝刀、螺丝(可选,用于可拆卸设计)

4.2 分步组装流程

第一步:底板与供电系统固定

  1. AA电池盒用双面胶或热熔胶固定在底板中央。
  2. MT3608升压模块焊接在电池盒的输出端。务必在焊接前,用万用表将输出电压调节至5.0V-5.1V
  3. 从升压模块的输出端引出两根较长的电源线(建议使用红黑硅胶线,区分正负),作为整个系统的电源总线。

第二步:安装交互与显示模块

  1. 在作为“顶面”的板子中央,开一个与8x8 LED点阵屏外框大小一致的方孔。将点阵屏从内侧放入,用热熔胶从四周固定。注意屏的正面(LED面)朝外。
  2. 在点阵屏的旁边(或上下方),钻两个小孔,用于安装红外传感器的发射管和接收管。让它们略微凸出板面,并确保发射和接收孔之间没有遮挡。用热熔胶固定传感器。
  3. 在另一个侧面(如“前面”)钻一个孔,安装复位按钮(可选)。这个按钮可以接在Arduino的RESET引脚和GND之间,用于重启系统。

第三步:主控板安装与内部布线

  1. Arduino Nano和其他模块(如果传感器是分离的,还有其小板子)用热熔胶或尼龙柱固定在底板上,注意布局整齐,便于走线。
  2. 开始焊接。遵循“先电源,后信号”的原则:
    • 先将电源总线的正极(+5V)连接到Arduino Nano的VIN5V引脚(注意:如果接5V,则电源必须已经是稳定的5V;接VIN则可接受7-12V输入,我们这里用5V接5V引脚更直接)。
    • 将电源总线负极(GND)连接到Nano的GND
    • 按照第2.4节的接线表,焊接MAX7219模块和红外传感器到Nano的对应引脚。建议使用不同颜色的杜邦线或导线,方便后续排查。
    • 所有GND线最后应汇接到一起,形成“星型接地”或单点接地,可以减少干扰。

第四步:合体与总装

  1. 将安装好点阵和传感器的“顶板”与其他四个侧面,用热熔胶或小螺丝垂直粘合在底板的四个边上。
  2. 将最后一块侧板(如“底面”的对立面)粘上,完成立方体结构。
  3. 在点阵屏表面贴一层半透明的深色亚克力板或磨砂贴纸。这能让LED光点变得柔和,看起来更像一个整体显示面,而不是一堆离散的灯珠,质感提升巨大。
  4. 装入电池,进行最终功能测试。

避坑指南:热熔胶在夏天高温环境下可能变软导致脱落。对于承重或易活动的部件(如电池盒),可以在热熔胶固定后,再用扎带或螺丝辅助加固。内部走线一定要用扎带捆扎整齐,避免线材缠绕或碰到尖锐焊点,造成短路。

5. 调试、优化与功能扩展

项目做完了,但让它更稳定、更好玩的工作才刚刚开始。

5.1 常见问题排查速查表

现象可能原因排查步骤与解决方案
上电后无任何反应1. 电池没电或装反。
2. 升压模块未调至5V。
3. 电源线虚焊或断开。
1. 用万用表测电池电压(应>2V)。
2. 测升压模块输出,调节至5V。
3. 检查所有电源连接点。
LED点阵屏不亮或乱码1. 引脚接错(DIN, CS, CLK)。
2. 库未正确安装或初始化。
3. 模块损坏。
1. 对照接线表再三检查。
2. 在setup()中加Serial.print调试信息,确认库函数被调用。
3. 用示例代码单独测试点阵屏。
挥手无反应(不触发)1. 红外传感器引脚未接中断引脚。
2. 中断配置模式错误。
3. 传感器被环境光干扰。
4. 中断标志位逻辑错误。
1. 确认传感器OUT线接在D2或D3。
2. 检查attachInterrupt触发模式(FALLING)。
3. 遮挡环境光或调整传感器灵敏度电位器(如果有)。
4. 在loop里打印diceRolled变量值,看中断是否触发。
一次挥手触发多次滚动传感器信号抖动(抖动)。增加主循环中的防抖延时(delay(300)),或尝试在中断服务程序中加短暂延时(但需谨慎,ISR中尽量不用delay)。
随机数序列固定随机数种子未设置或固定。确保在生成随机数前调用randomSeed(analogRead(A0))randomSeed(micros())

5.2 性能与体验优化

  1. 降低功耗:这个电路持续工作时,两节AA电池可能只能用几小时。优化方法:

    • loop()中,如果没有掷骰动作,可以让Arduino进入休眠模式。这需要LowPower等库的支持,能极大降低待机电流。
    • 降低LED点阵的亮度(lc.setIntensity(0, 1))。
    • 考虑使用容量更大的锂电池和相应的充电管理模块。
  2. 增强交互反馈:除了视觉,可以增加听觉反馈。

    • 加入一个有源蜂鸣器,在掷骰和显示结果时发出不同的提示音,体验更沉浸。
  3. 改进随机性micros()作为种子在快速连续上电时可能不够随机。可以尝试读取一个未连接的模拟引脚(如A0)的“浮空”噪声作为种子:randomSeed(analogRead(A0));

5.3 功能扩展思路

这个项目是一个完美的起点,你可以在此基础上玩出更多花样:

  1. 多玩家模式:就像原项目评论区有人问的,可以为每个玩家配备一个独立的小红外发射器(类似电视遥控器),骰子端增加一个红外接收头。不同玩家的发射器发射不同编码的信号,骰子解码后,不仅显示点数,还能通过LED颜色(如果用RGB点阵)或声音指示是哪位玩家掷出的。

  2. 无线记录与统计:将主控换成ESP8266ESP32。每次掷骰的结果,通过Wi-Fi发送到手机App或云端服务器,自动记录游戏历史、统计点数分布,甚至实现多人联网游戏。

  3. 加入运动传感:除了红外感应,可以集成一个MPU-6050陀螺仪。通过检测骰子被“摇动”的动作来触发掷骰,交互方式更直觉。结合加速度数据,甚至可以模拟骰子在桌上弹跳的动画。

  4. 升级显示:将单色8x8点阵换成OLED显示屏更大的LED点阵。可以显示更复杂的动画、数字,甚至简单的游戏状态信息。

这个无接触电子骰子从想法到实现,整个过程充满了动手的乐趣和解决问题的成就感。它教会我们的不仅仅是几个元件的连接和一段代码的编写,更是一种“用技术解决生活小问题”的思维方式。硬件项目最迷人的地方在于,当你按下开关,看到灯光如预期般亮起,传感器对你的手势做出响应时,那种与物理世界对话的真实感是纯软件无法比拟的。希望我的这份详细记录,能帮你少走弯路,顺利做出属于自己的那个炫酷骰子。如果在制作过程中遇到任何问题,欢迎随时交流,很多时候,问题的答案就在下一次耐心的测量和调试中。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/2 13:20:55

跨平台资源下载终极指南:5分钟掌握智能代理工具完整教程

跨平台资源下载终极指南&#xff1a;5分钟掌握智能代理工具完整教程 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 你是否曾…

作者头像 李华
网站建设 2026/6/2 13:19:55

告别网盘限速:3分钟学会用LinkSwift实现全平台高速下载

告别网盘限速&#xff1a;3分钟学会用LinkSwift实现全平台高速下载 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…

作者头像 李华
网站建设 2026/6/2 13:18:56

如何彻底解决Cursor高负载限制:go-cursor-help终极指南

如何彻底解决Cursor高负载限制&#xff1a;go-cursor-help终极指南 【免费下载链接】go-cursor-help 解决Cursor在免费订阅期间出现以下提示的问题: Your request has been blocked as our system has detected suspicious activity / Youve reached your trial request limit.…

作者头像 李华
网站建设 2026/6/2 13:17:56

一屏透明化三维立体重构安全信息哪个公司好

在数字化转型的浪潮中&#xff0c;城市管理、园区运营、港口调度等领域的“一屏看尽”需求日趋强烈。但现实往往是&#xff1a;各种监控系统、传感器数据、业务平台各自为政&#xff0c;信息碎片化&#xff0c;三维空间信息缺失&#xff0c;缺乏统一的空间基准&#xff0c;部门…

作者头像 李华
网站建设 2026/6/2 13:17:55

基于NodeMCU与超声波传感器的低成本智能门铃DIY方案

1. 项目概述想给家里的老式门铃加点“智能”&#xff0c;让它能自动感知访客并给你手机发通知&#xff0c;但又不想花大几百甚至上千块去买市面上的成品智能门铃&#xff1f;这个基于NodeMCU和超声波传感器的DIY方案&#xff0c;可能就是你要找的答案。它成本低廉&#xff0c;核…

作者头像 李华