【发布时间】:2017-11-06 09:03:47
【问题描述】:
我目前正在从事一个更大的 Arduino Mega 2560 项目;涉及伺服控制和传感器读数。我正在使用带有NewPing 1.8 库的超声波接近传感器(HC-SR04),该库使用中断来检测传感器的回波。此外,我还阅读了温度和光强度测量值。从 HC-SR04 超声波传感器接收到的距离数据通过 USB 使用cmdMessenger3 库转发到主机。伺服系统由来自主机的消息控制,使用标准的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 调用;使发送过程具有“原子性”。但这会导致很多其他问题,millis()/micros() 函数不再精确,串行通信中断等;都依赖于noInterrupts() 禁用的计时器。此外,舵机的行为也很奇怪,因为 PWM 信号生成的时间似乎也搞砸了。
任何想法如何在不破坏我的程序中基于中断的范例的情况下解决这个“并发”问题?
【问题讨论】:
标签: arduino interrupt interrupt-handling