
1. 项目概述硬币分拣计数器的核心价值如果你曾经在零售小店、社区超市甚至是家里整理过一大堆零散的硬币你就能立刻理解这个项目的痛点所在。手动将不同面额的硬币分开再一枚一枚地数不仅耗时费力而且极其容易出错。硬币分拣计数机这个听起来有点“硬核”的小设备正是为了解决这个看似微小却普遍存在的效率问题而生的。它本质上是一个集成了机械分拣、传感器识别和电子计数功能的自动化装置能够将混合的硬币按面额自动分类并快速、准确地统计出各类硬币的数量及总金额。这个项目非常适合电子爱好者、创客甚至是相关专业的学生来动手实践。它不像纯粹的软件项目那样抽象也不像大型工业设备那样复杂而是一个能看得见、摸得着融合了机械结构设计、基础电路知识和简单程序逻辑的综合性实践。通过制作一台属于自己的硬币分拣计数机你不仅能收获一个实用的工具更能系统地学习到如何将想法转化为实物如何协调硬件与软件以及如何解决在实现过程中遇到的各种实际问题。无论是用于个人兴趣、课程设计还是作为小型商业场景的辅助工具原型其价值都远超一个简单的计数功能本身。2. 核心设计思路与方案选型制作一台硬币分拣计数机核心思路可以概括为“先分后数数完汇总”。但具体如何实现“分”和“数”则有多种技术路径每种选择都直接关系到最终设备的复杂度、成本和可靠性。2.1 分拣机制机械结构是基石分拣是整个流程的第一步也是最关键的一环。常见的分拣方案主要有两种方案一基于尺寸的斜坡滑道分拣这是最经典、也最直观的方法。其原理是利用不同面额硬币在直径和厚度上的差异。我们设计一个带有逐渐变宽缝隙的倾斜滑道。硬币从滑道顶端投入在重力作用下向下滑动。滑道底部的缝隙最初很窄只能让最薄的硬币例如1角掉落。随着滑道变宽稍厚的硬币例如5角会在后续的缝隙处掉落最后最厚的硬币例如1元会滑到最底端的收集槽。这种方法完全依赖物理尺寸无需电源和传感器结构简单可靠成本极低。但它的精度严重依赖于硬币尺寸的标准度和滑道加工精度对于新旧磨损程度不同的硬币可能会出现误分。方案二基于传感器的智能识别分拣这种方法更为先进。它先通过传感器如电感式接近传感器、红外对管、甚至摄像头识别出硬币的特征如材质、直径然后通过执行机构如舵机控制的挡板、电磁铁将硬币引导至对应的收集通道。例如利用电感传感器可以区分铁质如部分1角和非铁质如5角、1元硬币利用红外对管阵列可以测量硬币直径。这种方案适应性更强能应对更复杂的硬币组合比如不同国家的硬币但相应地电路和程序会复杂很多成本也更高。选型心得对于入门和大多数国内硬币1角、5角、1元场景斜坡滑道分拣方案是首选。它直观、稳定、易于制作能让你把精力更多集中在计数和显示部分。本项目的解析也将主要围绕此方案展开。2.2 计数方案传感器的选择与布局分拣之后我们需要对每个通道的硬币进行计数。这里的关键是选择一款响应快速、安装方便且抗干扰能力强的传感器。1. 红外对管计数这是最常用的计数传感器。它由一个红外发射管和一个接收管组成。当硬币通过它们之间时会遮挡红外光接收管的信号会产生跳变从高电平到低电平或反之单片机检测到这个跳变信号就完成一次计数。其优点是价格低廉、电路简单、响应速度快。安装时需注意对齐并避免环境光干扰最好使用调制红外信号或加装遮光罩。2. 接近开关计数包括电感式接近开关检测金属和电容式接近开关。对于硬币电感式是很好的选择。当金属硬币靠近传感器感应面时内部振荡电路参数变化输出开关信号。它的优点是无需精确对位安装灵活且几乎不受灰尘、油污影响非常适合工业环境。缺点是成本略高于红外对管且对非金属物体无效。3. 微动开关计数这是一种纯机械接触式方案。硬币落下时压动一个轻触开关或杠杆开关产生电信号。优点是结构简单、绝对可靠。缺点是存在机械磨损长期使用后可能接触不良且对硬币的下落冲击力有要求可能不适合非常轻的硬币或低速下落场景。实操建议红外对管是DIY项目的性价比之王。建议选择那种已经集成好发射接收头、信号经过比较器整形后直接输出高低电平的模块通常有DO数字输出口。这样你就不需要自己搭建复杂的放大和整形电路直接用单片机的IO口读取即可非常省心。2.3 控制与显示核心微控制器的选型这是设备的“大脑”负责处理传感器信号、执行计数逻辑、计算总额并驱动显示。Arduino Uno/Nano创客的万能钥匙。生态丰富资料海量编程简单基于C/C的简化版。对于本项目其IO口数量和性能绰绰有余。非常适合快速原型验证和初学者。STM32系列如STM32F103C8T6俗称“蓝色药丸”性能更强价格可能与Arduino相当甚至更低。但开发环境如Keil, STM32CubeIDE和编程方式更接近专业嵌入式开发学习曲线稍陡。如果你希望挑战更复杂的逻辑或未来添加更多功能如无线通信它是一个好选择。ESP8266/ESP32特点是集成了Wi-FiESP32还有蓝牙。如果你想让你的硬币机具备联网功能比如将计数数据上传到服务器、通过手机APP查看那么它们是不二之选。但单纯做计数显示有点“杀鸡用牛刀”。我的选择与理由对于绝大多数首次尝试者我强烈推荐Arduino Nano。原因有三第一价格极其便宜第二可以直接插在面包板或洞洞板上搭建电路无需焊接转接板第三其串口通信功能可以非常方便地将数据输出到电脑进行调试或者连接一个常见的1602液晶屏I2C接口来显示整个系统构建起来非常顺畅。3. 核心细节解析与实操要点确定了“斜坡分拣红外计数Arduino控制”的总体方案后我们来深入每个环节的魔鬼细节。这些细节直接决定了你的机器是“玩具”还是“工具”。3.1 分拣滑道的设计与制作这是整个项目的机械核心设计不合理会导致分拣失败。1. 关键参数测量首先你必须精确测量你所在地区流通硬币的尺寸。以中国现行硬币为例数据仅供参考请以实物测量为准1角硬币直径约19毫米厚度约1.67毫米钢芯镀镍。5角硬币直径约20.5毫米厚度约1.65毫米钢芯镀铜。1元硬币直径约25毫米厚度约1.85毫米钢芯镀镍。你会发现5角和1角的厚度非常接近单纯靠厚度分拣会很困难。但它们的直径有显著差异。因此一个更可靠的方案是利用直径进行初筛再利用厚度进行精分。2. 滑道结构设计我建议采用“两级分拣”结构第一级直径分拣。在滑道入口下方设置一个宽度约21毫米的垂直缝隙。这样1角19mm和5角20.5mm硬币会直接掉落进入下一级滑道而1元硬币25mm因为直径太大会卡在缝隙上方继续沿主滑道滑入专属的“1元收集通道”。第二级厚度分拣。1角和5角硬币掉入一个倾斜的、带有逐渐增宽缝隙的滑道。缝隙的起始宽度略小于1角硬币的厚度例如1.5mm终点宽度介于1角和5角厚度之间例如1.7mm。理论上1角硬币会先掉落5角硬币会后掉落。但由于两者厚度差极小这里需要极其精密的加工和反复调试。3. 材料与加工材料亚克力板是理想选择。它透明便于观察易于用激光切割机进行高精度加工。如果没有激光切割也可以用薄木板或铝板配合尺子、刀和锉刀手工制作但对精度要求很高。表面处理滑道表面必须光滑减少摩擦。可以粘贴透明胶带或涂抹少许润滑脂如凡士林。滑道倾斜角度需要实验确定通常15-30度之间角度太小硬币不下滑角度太大会导致硬币速度过快影响分拣和计数精度。避坑指南手工制作滑道时最大的敌人是“毛刺”。任何一点毛刺都可能挂住硬币导致堵塞。务必用细砂纸将所有的切割边缘尤其是分拣缝隙的边缘打磨得无比光滑。在调试阶段可以用一包混合硬币反复测试观察每一枚硬币的路径并用记号笔标记出容易卡住的位置再进行精细修整。3.2 传感器电路的搭建与调试我们选择红外对管模块进行计数。电路搭建简单但调试决定成败。1. 电路连接红外对管模块通常有三根线VCC接5V、GND接GND、OUT信号输出线接Arduino的数字输入引脚如D2。在Arduino程序中需要将该引脚设置为INPUT_PULLUP模式启用内部上拉电阻这样常态下无遮挡读到的就是高电平1当硬币落下遮挡时模块输出低电平0我们检测这个下降沿来进行计数。2. 安装位置传感器必须安装在每个硬币通道的“必经之路”上且确保硬币通过时能有效遮挡光束。最佳位置是硬币掉落轨迹的末端、落入收集容器之前的一个狭窄通道内。安装时发射管和接收管必须严格对准。可以使用热熔胶或专门的小支架来固定。3. 软件防抖硬币在掉落过程中可能会轻微弹跳导致传感器输出信号在短时间内多次跳变即“抖动”从而引发误计数。必须在软件中消除抖动。// 简单的软件防抖示例 const int sensorPin 2; // 红外传感器连接的引脚 int lastState HIGH; // 传感器上一次的状态 int currentState; unsigned long lastDebounceTime 0; unsigned long debounceDelay 10; // 防抖延时单位毫秒根据实际情况调整 int count 0; void setup() { pinMode(sensorPin, INPUT_PULLUP); Serial.begin(9600); } void loop() { int reading digitalRead(sensorPin); // 读取传感器当前值 // 如果状态发生变化说明有遮挡或取消遮挡事件 if (reading ! lastState) { lastDebounceTime millis(); // 重置防抖计时器 } // 等待防抖延时结束再看状态是否稳定 if ((millis() - lastDebounceTime) debounceDelay) { // 延时结束后确认最终的状态 if (reading ! currentState) { currentState reading; // 只有当状态变为低电平下降沿时才计数 if (currentState LOW) { count; Serial.print(Count: ); Serial.println(count); // 这里可以添加更新显示、计算金额等逻辑 } } } lastState reading; // 更新上一次的状态 }这段代码的核心思想是当检测到引脚状态变化时不立即行动而是等待一小段时间debounceDelay如果这段时间后状态稳定在一个新值才认为这是一个有效的动作。调试技巧调试时先用一张纸片反复穿过传感器同时在串口监视器中观察计数是否准确。然后使用单枚硬币测试。重点关注是否有漏计硬币太快传感器响应慢或多计抖动未消除安装不牢有振动。debounceDelay参数需要根据硬币下落速度和传感器特性微调通常在5-50毫秒之间。4. 系统集成与程序设计当机械结构和传感器单元都调试完毕后就可以进行系统集成和总控程序的编写了。4.1 硬件系统集成假设我们设计有三个通道通道A1元、通道B5角、通道C1角。每个通道安装一个红外传感器分别连接到Arduino的D2、D3、D4引脚。显示部分使用一个I2C接口的1602液晶屏其SDA接A4SCL接A5。电源部分整个系统可以用一个9V的直流电源适配器供电通过Arduino的电源插座输入再由Arduino的5V引脚为传感器和液晶屏供电。如果硬币数量多电机如果有功耗大建议传感器和显示部分单独供电并与Arduino共地。4.2 核心程序设计逻辑程序需要持续监控三个传感器管理三个独立的计数器并根据面额计算总金额最后刷新显示。#include Wire.h #include LiquidCrystal_I2C.h // 用于I2C液晶屏的库 // 定义传感器引脚 #define SENSOR_1YUAN 2 #define SENSOR_5JIAO 3 #define SENSOR_1JIAO 4 // 定义硬币面额单位分便于计算 #define VALUE_1YUAN 100 #define VALUE_5JIAO 50 #define VALUE_1JIAO 10 // 初始化液晶屏I2C地址通常是0x27或0x3F根据你的屏幕调整 LiquidCrystal_I2C lcd(0x27, 16, 2); // 计数器变量 volatile long count1Yuan 0; volatile long count5Jiao 0; volatile long count1Jiao 0; // 防抖相关变量 unsigned long lastDebounceTime1 0; unsigned long lastDebounceTime2 0; unsigned long lastDebounceTime3 0; const unsigned long debounceDelay 15; int lastState1 HIGH; int lastState2 HIGH; int lastState3 HIGH; void setup() { Serial.begin(9600); // 初始化传感器引脚为上拉输入模式 pinMode(SENSOR_1YUAN, INPUT_PULLUP); pinMode(SENSOR_5JIAO, INPUT_PULLUP); pinMode(SENSOR_1JIAO, INPUT_PULLUP); // 初始化液晶屏 lcd.init(); lcd.backlight(); lcd.setCursor(0, 0); lcd.print(Coin Counter); delay(1000); lcd.clear(); // 显示初始信息 updateDisplay(); } void loop() { // 分别处理三个传感器的信号 checkSensor(SENSOR_1YUAN, lastState1, lastDebounceTime1, count1Yuan); checkSensor(SENSOR_5JIAO, lastState2, lastDebounceTime2, count5Jiao); checkSensor(SENSOR_1JIAO, lastState3, lastDebounceTime3, count1Jiao); // 可以添加一个手动复位按钮的检测逻辑用于清零计数 // if (digitalRead(RESET_PIN) LOW) { resetCounters(); } } // 通用的传感器检查函数使用引用传递以修改对应的变量 void checkSensor(int pin, int lastState, unsigned long lastDebounceTime, volatile long counter) { int reading digitalRead(pin); if (reading ! lastState) { lastDebounceTime millis(); } if ((millis() - lastDebounceTime) debounceDelay) { // 状态稳定后检测下降沿从HIGH到LOW if (reading LOW lastState HIGH) { counter; Serial.print(Pin ); Serial.print(pin); Serial.print( Count: ); Serial.println(counter); updateDisplay(); // 每次计数后更新显示 } } lastState reading; } // 更新液晶屏显示 void updateDisplay() { long totalCents (count1Yuan * VALUE_1YUAN) (count5Jiao * VALUE_5JIAO) (count1Jiao * VALUE_1JIAO); float totalYuan totalCents / 100.0; lcd.clear(); // 第一行显示各面额数量 lcd.setCursor(0, 0); lcd.print(1Y:); lcd.print(count1Yuan); lcd.print( 5J:); lcd.print(count5Jiao); lcd.print( 1J:); lcd.print(count1Jiao); // 第二行显示总金额 lcd.setCursor(0, 1); lcd.print(Total: ); lcd.print(totalYuan, 2); // 显示两位小数 lcd.print( Y); } // 清零计数器函数 void resetCounters() { count1Yuan 0; count5Jiao 0; count1Jiao 0; updateDisplay(); Serial.println(Counters Reset.); }这个程序框架实现了基本的计数、防抖、金额计算和显示功能。checkSensor函数封装了防抖逻辑使代码更清晰。volatile关键字用于在中断服务程序虽然本例未用中断中可能被修改的变量这里出于良好习惯加上。4.3 外壳与整体装配一个结实、美观的外壳能让你的项目从“实验原型”升级为“实用产品”。外壳需要容纳投币口位于顶部大小要能容纳一把硬币投入但不宜过大以防异物掉入。分拣滑道总成稳固地安装在外壳内部框架上。电路板将Arduino、传感器连接线等整合在一块洞洞板或定制PCB上固定在外壳内。显示窗为液晶屏开一个透明的窗口。硬币收集抽屉底部设计三个可抽拉的小抽屉分别对应三个面额方便取出清点。电源接口与开关安装DC电源插座和电源总开关。材料可以使用木板、亚克力板拼接或者使用3D打印来制作一个更精致的外壳。设计时务必考虑维护的便利性比如上盖可以打开以便清理卡住的硬币或维修传感器。5. 调试、优化与问题排查实录即使按照图纸和代码一丝不苟地制作第一台原型机也几乎一定会遇到问题。下面是我在多次制作中遇到的典型问题及解决方法。5.1 常见问题速查表问题现象可能原因排查与解决方法硬币卡在滑道中1. 滑道有毛刺或不平整。2. 滑道倾斜角度不合适太缓。3. 硬币太旧边缘有卷边或污垢粘连。1. 取出滑道用砂纸或锉刀仔细打磨光滑。2. 增大滑道倾斜角度或用手拍打外壳轻微振动辅助。3. 清洁硬币对于严重变形的硬币机器可能无法处理需手动挑出。分拣错误如1元分到5角通道1. 分拣缝隙尺寸不精确。2. 硬币下落速度过快惯性导致“跳过”了应有的缝隙。1. 重新测量硬币尺寸精细调整缝隙宽度。对于直径分拣级缝隙宽度应比目标硬币直径大0.5-1mm。2. 在滑道关键位置粘贴一小块海绵或软橡胶作为“减速带”降低硬币速度。传感器漏计数1. 硬币未完全遮挡光束传感器安装位置偏。2. 硬币下落速度过快传感器响应不及。3. 传感器信号线接触不良。1. 调整传感器位置确保硬币轨迹中心穿过光束中心。可以用激光笔辅助对准注意安全。2. 同上述“减速带”方法或尝试优化程序减少防抖延时但需平衡防抖效果。3. 检查并重新焊接或压接信号线。传感器多计数跳数1. 软件防抖延时设置太短无法过滤机械振动或硬币弹跳。2. 传感器安装不牢固硬币撞击导致其振动。3. 环境光干扰对红外对管而言。1. 逐步增加debounceDelay值如从5ms加到20ms直到计数稳定。2. 用热熔胶或螺丝将传感器模块牢牢固定。3. 为红外对管加装遮光套管或使用调制型红外传感器模块。液晶屏不显示或乱码1. I2C地址不正确。2. 接线错误SDA/SCL接反或接触不良。3. 对比度不合适。1. 使用Arduino的I2C扫描程序查找正确的设备地址。2. 检查接线确保牢固。SDA接A4SCL接A5对于Arduino Uno/Nano。3. 调整液晶屏模块背后的电位器如果有或通过程序初始化时设置对比度。计数偶尔清零或数据错乱1. 电源不稳定特别是当电机如有启动时造成电压跌落。2. 程序逻辑有bug变量溢出或被意外修改。1. 为电机单独供电或使用更大功率的电源适配器。在Arduino的VIN和GND之间并联一个100-1000uF的电解电容稳压。2. 检查代码中所有对计数器变量的操作确保没有在中断或其它地方冲突。使用volatile关键字修饰。5.2 性能优化与功能扩展基础功能稳定后你可以考虑以下优化和扩展让你的机器更智能、更好用1. 增加启动/停止按钮和清零按钮在面板上安装两个按钮。一个用于启动/暂停计数防止在倒入硬币过程中误触发另一个用于将所有计数器和金额归零。2. 添加声音提示每次计数成功时用一个有源蜂鸣器发出短暂的“滴”声提供即时反馈这在嘈杂环境中很有用。3. 数据存储与导出使用Arduino的EEPROM电可擦可编程只读存储器来保存最后一次的计数数据这样即使断电数据也不会丢失。更进一步可以添加一个蓝牙模块如HC-05或Wi-Fi模块ESP8266将每次的清点结果发送到手机或电脑方便生成统计报表。4. 改进分拣算法针对传感器识别方案如果你采用传感器识别方案可以引入简单的算法。例如用两个距离已知的红外对管测量硬币通过的时间差从而推算其直径速度恒定情况下。或者使用一个颜色传感器来识别硬币的颜色特征。这需要更复杂的电路和程序但分拣准确率会大幅提升并能适应更多种类的硬币。5. 机械优化为投币口增加一个振动器小型振动电机当投入大量硬币时开启振动可以帮助硬币更顺畅地进入分拣滑道防止在入口处堆积堵塞。制作一台硬币分拣计数机从构思到实现是一个充满挑战和乐趣的过程。它没有唯一的正确答案我的方案也只是众多可能性中的一种。你在实践中可能会发现更好的结构设计、更巧妙的传感器安装方式或者写出更优雅的代码。最重要的是动手去做在调试中学习在失败中成长。当听到硬币叮叮当当滑过看到液晶屏上的数字准确跳动最终得出总金额的那一刻所有的努力都是值得的。这个项目带给你的远不止一台机器更是一整套解决实际问题的工程思维和动手能力。