如何处理 ISR 回调?
How to handle ISR callback?
我目前正在从事一个更大的 Arduino Mega 2560 项目;涉及伺服控制和传感器读数。我在 NewPing 1.8 library that uses interrupts for detecting the echo of the sensors. Furthermore, I read temperature and light intensity measurements also. Distance data received from the HC-SR04 ultrasonic sensors are forwarded over USB to the host computer by using the cmdMessenger3 library. Servos are controlled by messages from the host computer using the standard Servo 库中使用超声波接近传感器 (HC-SR04)。
当检测到超声波回波时,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 信号生成的时序似乎也乱七八糟。
有什么想法可以解决这个 'concurrency' 问题而不破坏我程序中基于中断的范式吗?
您正在尝试在 ISR 中做很多工作;一般来说,他们不应该做任何需要延迟的事情(任何超过 1 字节的串行消息都属于该类别)。一个更合理的实现是让 ISR 简单地将传感器读数存储在全局变量中,并设置一个标志,主程序检查它是否应该发送串行消息。如果来自同一个传感器的第二个读数可能在前一个有机会发送之前到达,您可能需要一些更高级的东西(比如消息队列)。
我目前正在从事一个更大的 Arduino Mega 2560 项目;涉及伺服控制和传感器读数。我在 NewPing 1.8 library that uses interrupts for detecting the echo of the sensors. Furthermore, I read temperature and light intensity measurements also. Distance data received from the HC-SR04 ultrasonic sensors are forwarded over USB to the host computer by using the cmdMessenger3 library. Servos are controlled by messages from the host computer using the standard Servo 库中使用超声波接近传感器 (HC-SR04)。
当检测到超声波回波时,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 信号生成的时序似乎也乱七八糟。
有什么想法可以解决这个 'concurrency' 问题而不破坏我程序中基于中断的范式吗?
您正在尝试在 ISR 中做很多工作;一般来说,他们不应该做任何需要延迟的事情(任何超过 1 字节的串行消息都属于该类别)。一个更合理的实现是让 ISR 简单地将传感器读数存储在全局变量中,并设置一个标志,主程序检查它是否应该发送串行消息。如果来自同一个传感器的第二个读数可能在前一个有机会发送之前到达,您可能需要一些更高级的东西(比如消息队列)。