You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino Uno投币器与出币器代码冲突:继电器误触发中断问题

问题分析与修复方案

核心问题

  1. 投币中断误触发:继电器切换产生的电磁干扰会在引脚2(投币接收器)形成毛刺信号,直接触发RISING中断;原中断服务函数无消抖逻辑,导致误判为投币事件。
  2. 出币计数逻辑不可靠:使用char sen移位检测硬币的方式容错性差,sen==1的判断条件过于严苛,容易漏检有效信号或误触发计数。
  3. 阻塞式延时拖垮程序:loop()中的delay(1000)会阻塞整个程序,导致出币逻辑、串口响应完全停滞,引发异常。
  4. 位运算误用:判断继电器超时的条件中使用按位与&而非逻辑与&&,会导致不必要的硬件读取和逻辑错误。

修复步骤

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 09:05:14