首页 文章

如何处理ISR回调?

提问于
浏览
0

我目前正在开发一个更大的Arduino Mega 2560项目;涉及 Servo 控制和传感器读数 . 我正在使用超声波接近传感器(HC-SR04)和NewPing 1.8库,它使用中断来检测传感器的回声 . 此外,我还阅读了温度和光强度测量 . 通过使用cmdMessenger3库,从HC-SR04超声波传感器接收的距离数据通过USB转发到主机 . 使用标准Servo库,来自主机的消息控制 Servo 系统 .

一旦NewPing库在检测到超声回波时调用 ISR ,就会开始乱码 . 当距离数据可用时,这是NewPing库调用的函数:

void sendSonarData(uint8_t sensorId, uint16_t distance) {
  //noInterrupts();   
  cmdMsg3.sendCmdStart(kReadSonar);
  cmdMsg3.sendCmdArg(sensorId);
  cmdMsg3.sendCmdArg(distance);
  cmdMsg3.sendCmdEnd();
  //interrupts();
}

这是另一个回调函数,它通过cmdMessenger3库将温度数据发送到主机:

void sendTemperatureData(uint8_t sensorId, uint16_t temperature) {
  //noInterrupts();   
  cmdMsg3.sendCmdStart(kReadTemperature);
  cmdMsg3.sendCmdArg(sensorId);
  cmdMsg3.sendCmdArg(temperature);
  cmdMsg3.sendCmdEnd();
  //interrupts();
}

问题:虽然Arduino例如尝试发送温度数据,超声波传感器的ISR可能会跳入并将其自己的数据写入串行流;关于发送到主机的串行数据一团糟,因为发送过程不是原子的,包含多个命令发送一条消息( sendCmdStart - > sendCmdArg - > sendCmdEnd ) .

这是一个例子:

  • 读取温度 sendTemperatureData(...) 被调用

  • cmdMsg3.sendCmdStart(kReadTemperature); 被调用

  • cmdMsg3.sendCmdArg(sensorId); 被调用
    来自声纳传感器的

  • ISR跳入

  • sendTemperatureData(); 被调用

  • cmdMsg3.sendCmdStart(kReadSonar); 被调用

  • cmdMsg3.sendCmdArg(sensorId);

  • cmdMsg3.sendCmdArg(distance);

  • cmdMsg3.sendCmdEnd();
    调用 sendTemperatureData(...)

  • 个剩余语句

  • cmdMsg3.sendCmdArg(temperature);

  • cmdMsg3.sendCmdEnd();

  • 导致串口通信大乱...

然后我尝试使用 noInterrupts()/interrupts() 在发送过程中阻止ISR调用;使发送过程类型'atomic' . 但这导致了许多其他问题, millis()/micros() 功能不再精确,串行通信发生故障等;所有都依赖于 noInterrupts() 禁用的计时器 . 此外,舵机的行为也很奇怪,因为PWM信号发生的时序似乎也搞砸了 .

任何想法如何解决这个'并发'问题而不打破我的程序中基于中断的范例?

1 回答

  • 5

    你正试图在你的ISR中做很多工作;一般来说,他们不应该做任何需要延迟的事情(任何超过1个字节的串行消息都属于该类别) . 更合理的实现将使ISR简单地将传感器读数存储在全局变量中,并设置主程序检查以查看是否应该发送串行消息的标志 . 如果来自同一传感器的第二次读取可能在前一次有机会被发送之前到达,则可能需要更高级的东西(如消息队列) .

相关问题