Arduino Uno投币器与出币器代码冲突:继电器误触发中断问题
问题分析与修复方案
核心问题
- 投币中断误触发:继电器切换产生的电磁干扰会在引脚2(投币接收器)形成毛刺信号,直接触发
RISING中断;原中断服务函数无消抖逻辑,导致误判为投币事件。 - 出币计数逻辑不可靠:使用
char sen移位检测硬币的方式容错性差,sen==1的判断条件过于严苛,容易漏检有效信号或误触发计数。 - 阻塞式延时拖垮程序:
loop()中的delay(1000)会阻塞整个程序,导致出币逻辑、串口响应完全停滞,引发异常。 - 位运算误用:判断继电器超时的条件中使用按位与
&而非逻辑与&&,会导致不必要的硬件读取和逻辑错误。
修复步骤
1. 给投币中断加消抖
在中断服务函数中加入软件消抖逻辑,通过检测电平持续稳定状态来确认真实投币信号,过滤电磁干扰产生的毛刺。
2. 重构出币计数逻辑
改用引脚状态变化(下降沿)计数硬币:利用INPUT_PULLUP模式下,硬币经过时传感器从高电平变低电平的特性,替代移位判断的不可靠方式。
3. 替换阻塞式延时
用非阻塞的millis()计时替代delay(1000),确保程序始终能响应串口指令和出币传感器信号。
4. 修正逻辑细节
- 将按位与
&改为逻辑与&&; - 优化
volatile变量的访问方式,避免竞态条件。
修改后的完整代码
#define SENSOR 3 #define RELAY 7 #define ACCEPTOR 2 volatile boolean insert = false; // 投币消抖变量 volatile unsigned long interruptTriggerTime = 0; const unsigned int DEBOUNCE_DELAY = 50; // 出币相关变量 int pulse = 0; int targetCoins = 0; unsigned long hopperTimer = 0; const unsigned int HOPPER_TIMEOUT = 2000; // 传感器状态跟踪 int lastSensorState = HIGH; // 非阻塞投币通知计时 unsigned int coinNotifyDelay = 1000; unsigned long lastCoinNotifyTime = 0; boolean needNotifyCoin = false; void setup() { Serial.begin(9600); pinMode(SENSOR, INPUT_PULLUP); pinMode(RELAY, OUTPUT); digitalWrite(RELAY, HIGH); // 默认关闭出币器 // 初始化传感器状态 lastSensorState = digitalRead(SENSOR); // 绑定投币中断 attachInterrupt(digitalPinToInterrupt(ACCEPTOR), coinInterrupt, RISING); } void loop() { // 非阻塞处理投币通知 if (needNotifyCoin) { if (millis() - lastCoinNotifyTime >= coinNotifyDelay) { Serial.println("coin"); needNotifyCoin = false; } } // 处理串口出币指令 if (Serial.available()) { int input = Serial.parseInt(); if (input > 0) { targetCoins = input; pulse = 0; digitalWrite(RELAY, LOW); // 启动出币器 hopperTimer = millis(); // 重置超时计时器 } // 清空串口残留字符 while (Serial.available()) Serial.read(); } // 检测出币传感器下降沿(硬币经过) int currentSensorState = digitalRead(SENSOR); if (lastSensorState == HIGH && currentSensorState == LOW) { pulse++; Serial.println("out 1"); hopperTimer = millis(); // 达到目标数量,停止出币 if (pulse >= targetCoins) { digitalWrite(RELAY, HIGH); targetCoins = 0; pulse = 0; } } lastSensorState = currentSensorState; // 出币超时处理:无硬币输出超过设定时间,强制停止 if (digitalRead(RELAY) == LOW && (millis() - hopperTimer >= HOPPER_TIMEOUT)) { digitalWrite(RELAY, HIGH); targetCoins = 0; pulse = 0; Serial.println("Hopper timeout, stopped"); } } void coinInterrupt() { unsigned long currentTime = millis(); // 消抖:间隔大于消抖时间且电平稳定,才判定为有效投币 if (currentTime - interruptTriggerTime >= DEBOUNCE_DELAY) { if (digitalRead(ACCEPTOR) == HIGH) { needNotifyCoin = true; lastCoinNotifyTime = currentTime; } interruptTriggerTime = currentTime; } }
额外硬件建议
若电磁干扰导致的误中断仍存在,可在投币接收器的引脚2与GND之间并联100nF电容,通过硬件RC滤波进一步抑制毛刺信号。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

