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

基于Arduino与红外传感器的无接触电子骰子制作全解析 1. 项目概述与核心思路前阵子想和孩子玩桌游但普通的骰子大家轮流摸来摸去总觉得不太卫生。作为一个喜欢折腾硬件的“老父亲”我琢磨着能不能做个不用手碰、隔空一晃就能出结果的电子骰子。这个想法听起来有点意思做起来其实并不复杂核心就是用一块Arduino板子搭配一个红外传感器和一个LED点阵屏把传统骰子的随机性和物理交互用电子化的方式无接触地实现出来。这个“无接触电子骰子”本质上是一个基于中断响应机制的嵌入式交互设备。它的工作逻辑很清晰红外传感器持续检测前方是否有物体比如手经过一旦检测到就向Arduino发送一个中断信号。Arduino收到中断后立即暂停当前的主循环去执行一个生成1到6随机数的函数然后将这个数字对应的骰子点数图案显示在8x8的LED矩阵上。整个过程中用户完全不需要触碰设备既卫生又有科技感。项目适合有一定Arduino和焊接基础的朋友尝试总成本可以控制在百元以内。它不仅仅是一个玩具更是一个理解中断、传感器应用、LED矩阵驱动以及随机数生成等嵌入式核心概念的绝佳实践案例。下面我就把从电路设计、代码编写到外壳组装的全过程以及我踩过的坑和总结的经验毫无保留地分享出来。2. 核心硬件选型与电路设计解析硬件是整个项目的骨架选对元件并设计好电路项目就成功了一半。我的核心思路是低功耗、易集成、高可靠性毕竟这玩意儿是拿来玩的不能动不动就出问题或者没电。2.1 主控与显示单元为什么是Arduino Nano和MAX7219主控芯片我选择了Arduino Nano。相比UNONano体积更小巧非常适合塞进骰子这种有限的空间里而且其核心的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接升压模块输出的5VGNDGND共地DIND11 (MOSI)数据输入也可接其他数字口CSD10 (SS)片选低电平有效CLKD13 (SCK)时钟信号红外传感器VCC5VGNDGNDOUTD2关键接外部中断0引脚按键可选一脚D3 (或其它)用于手动触发/重置接外部中断1另一脚GND按下时接地升压模块OUTNano 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; // 当前显示的点数关键点解析LedControl lc(...)这个对象是我们与屏幕对话的“话筒”。最后一个参数1表示我们只连接了1个MAX7219模块即一个8x8点阵。图案数据diceFaces是一个二维数组。点阵是8行8列在代码中用8个字节byte表示每个字节的8个bit对应一行的8个LED1亮0灭。例如数字“1”的图案就是中间两个LED亮起。用十六进制如0x18表示比二进制更简洁。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-158适中 lc.clearDisplay(0); // 清屏 // 2. 配置红外传感器引脚 pinMode(IR_SENSOR_PIN, INPUT_PULLUP); // 设置为输入并启用内部上拉电阻 // 3. 配置外部中断 // attachInterrupt(digitalPinToInterrupt(中断引脚), 中断服务函数, 触发模式) attachInterrupt(digitalPinToInterrupt(IR_SENSOR_PIN), rollTheDice, FALLING); // 4. 显示开机动画 showStartupAnimation(); }关键点解析lc.shutdown(0, false)MAX7219有省电模式初始化时需要将其“唤醒”。pinMode(IR_SENSOR_PIN, INPUT_PULLUP)这里启用了Arduino的内部上拉电阻。当没有物体靠近时传感器输出高电平当检测到物体输出变为低电平。上拉电阻确保了空闲时引脚有稳定的高电平避免悬空状态下的误触发。attachInterrupt(...)这是中断配置的核心。digitalPinToInterrupt(IR_SENSOR_PIN)将物理引脚号转换为中断号D2对应中断0。rollTheDice是中断发生时自动调用的函数名。FALLING是触发模式意为“下降沿触发”即当传感器引脚电平从高变低手挥过导致的瞬间触发中断。开机动画这是一个提升用户体验的小技巧让设备启动时有明确的反馈。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; }关键点解析中断服务程序ISR要短rollTheDice()函数极其简单只设置一个标志位。这是因为在ISR执行期间其他中断可能被禁用长时间执行ISR会影响系统对其他事件的响应甚至可能导致看门狗复位。复杂的逻辑如动画、显示应放在主循环中基于标志位去执行。随机数生成random(1,7)看似简单但randomSeed()很重要。如果不设置种子每次上电后生成的随机数序列是相同的。用micros()返回从开始运行起的微秒数作为种子由于上电时间点不可预测能获得较好的随机效果。防抖处理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 分步组装流程第一步底板与供电系统固定将AA电池盒用双面胶或热熔胶固定在底板中央。将MT3608升压模块焊接在电池盒的输出端。务必在焊接前用万用表将输出电压调节至5.0V-5.1V。从升压模块的输出端引出两根较长的电源线建议使用红黑硅胶线区分正负作为整个系统的电源总线。第二步安装交互与显示模块在作为“顶面”的板子中央开一个与8x8 LED点阵屏外框大小一致的方孔。将点阵屏从内侧放入用热熔胶从四周固定。注意屏的正面LED面朝外。在点阵屏的旁边或上下方钻两个小孔用于安装红外传感器的发射管和接收管。让它们略微凸出板面并确保发射和接收孔之间没有遮挡。用热熔胶固定传感器。在另一个侧面如“前面”钻一个孔安装复位按钮可选。这个按钮可以接在Arduino的RESET引脚和GND之间用于重启系统。第三步主控板安装与内部布线将Arduino Nano和其他模块如果传感器是分离的还有其小板子用热熔胶或尼龙柱固定在底板上注意布局整齐便于走线。开始焊接。遵循“先电源后信号”的原则先将电源总线的正极5V连接到Arduino Nano的VIN或5V引脚注意如果接5V则电源必须已经是稳定的5V接VIN则可接受7-12V输入我们这里用5V接5V引脚更直接。将电源总线负极GND连接到Nano的GND。按照第2.4节的接线表焊接MAX7219模块和红外传感器到Nano的对应引脚。建议使用不同颜色的杜邦线或导线方便后续排查。所有GND线最后应汇接到一起形成“星型接地”或单点接地可以减少干扰。第四步合体与总装将安装好点阵和传感器的“顶板”与其他四个侧面用热熔胶或小螺丝垂直粘合在底板的四个边上。将最后一块侧板如“底面”的对立面粘上完成立方体结构。在点阵屏表面贴一层半透明的深色亚克力板或磨砂贴纸。这能让LED光点变得柔和看起来更像一个整体显示面而不是一堆离散的灯珠质感提升巨大。装入电池进行最终功能测试。避坑指南热熔胶在夏天高温环境下可能变软导致脱落。对于承重或易活动的部件如电池盒可以在热熔胶固定后再用扎带或螺丝辅助加固。内部走线一定要用扎带捆扎整齐避免线材缠绕或碰到尖锐焊点造成短路。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 性能与体验优化降低功耗这个电路持续工作时两节AA电池可能只能用几小时。优化方法在loop()中如果没有掷骰动作可以让Arduino进入休眠模式。这需要LowPower等库的支持能极大降低待机电流。降低LED点阵的亮度lc.setIntensity(0, 1)。考虑使用容量更大的锂电池和相应的充电管理模块。增强交互反馈除了视觉可以增加听觉反馈。加入一个有源蜂鸣器在掷骰和显示结果时发出不同的提示音体验更沉浸。改进随机性micros()作为种子在快速连续上电时可能不够随机。可以尝试读取一个未连接的模拟引脚如A0的“浮空”噪声作为种子randomSeed(analogRead(A0));。5.3 功能扩展思路这个项目是一个完美的起点你可以在此基础上玩出更多花样多玩家模式就像原项目评论区有人问的可以为每个玩家配备一个独立的小红外发射器类似电视遥控器骰子端增加一个红外接收头。不同玩家的发射器发射不同编码的信号骰子解码后不仅显示点数还能通过LED颜色如果用RGB点阵或声音指示是哪位玩家掷出的。无线记录与统计将主控换成ESP8266或ESP32。每次掷骰的结果通过Wi-Fi发送到手机App或云端服务器自动记录游戏历史、统计点数分布甚至实现多人联网游戏。加入运动传感除了红外感应可以集成一个MPU-6050陀螺仪。通过检测骰子被“摇动”的动作来触发掷骰交互方式更直觉。结合加速度数据甚至可以模拟骰子在桌上弹跳的动画。升级显示将单色8x8点阵换成OLED显示屏或更大的LED点阵。可以显示更复杂的动画、数字甚至简单的游戏状态信息。这个无接触电子骰子从想法到实现整个过程充满了动手的乐趣和解决问题的成就感。它教会我们的不仅仅是几个元件的连接和一段代码的编写更是一种“用技术解决生活小问题”的思维方式。硬件项目最迷人的地方在于当你按下开关看到灯光如预期般亮起传感器对你的手势做出响应时那种与物理世界对话的真实感是纯软件无法比拟的。希望我的这份详细记录能帮你少走弯路顺利做出属于自己的那个炫酷骰子。如果在制作过程中遇到任何问题欢迎随时交流很多时候问题的答案就在下一次耐心的测量和调试中。