我目前正在开发更大的Arduino Mega 2560项目;涉及伺服控制和传感器读数。我正在使用超声波接近传感器(HC-SR04)和NewPing 1.8库,它使用中断来检测传感器的回声。此外,我还阅读了温度和光强度测量。通过使用cmdMessenger3库,从HC-SR04超声波传感器接收的距离数据通过USB转发到主机。 Servos由来自主机的消息使用标准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
- > {{ 1}})。
以下是一个例子:
sendCmdEnd
称为sendTemperatureData(...)
被称为cmdMsg3.sendCmdStart(kReadTemperature);
被称为cmdMsg3.sendCmdArg(sensorId);
被称为sendTemperatureData();
被称为cmdMsg3.sendCmdStart(kReadSonar);
cmdMsg3.sendCmdArg(sensorId);
cmdMsg3.sendCmdArg(distance);
cmdMsg3.sendCmdEnd();
的剩余陈述称为sendTemperatureData(...)
cmdMsg3.sendCmdArg(temperature);
然后我尝试使用cmdMsg3.sendCmdEnd();
在发送过程中阻止ISR呼叫;使发送过程有点'原子'。但这导致了许多其他问题,noInterrupts()/interrupts()
函数不再精确,串行通信中断等等;所有这些都依赖于millis()/micros()
禁用的计时器。此外,伺服系统的行为也很奇怪,因为PWM信号的生成时间似乎也搞砸了。
如何在不破坏程序中基于中断的范例的情况下解决这个“并发”问题的任何想法?
答案 0 :(得分:5)
你正试图在你的ISR中做很多工作;一般来说,他们不应该做任何需要延迟的事情(任何超过1个字节的串行消息都属于该类别)。更合理的实现将使ISR简单地将传感器读数存储在全局变量中,并设置主程序检查以查看是否应该发送串行消息的标志。如果来自同一传感器的第二次读取可能在前一次有机会被发送之前到达,则可能需要更高级的东西(如消息队列)。