I am currently working on a larger Arduino Mega 2560 project; servo controlling and sensor readings involved. I am using ultrasonic proximity sensors (HC-SR04) with the 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 library.
The mess begins as soon as the NewPing library calls the ISR when the ultrasonic echo is detected. This is the function called by the NewPing library when distance data is available:
void sendSonarData(uint8_t sensorId, uint16_t distance) {
//noInterrupts();
cmdMsg3.sendCmdStart(kReadSonar);
cmdMsg3.sendCmdArg(sensorId);
cmdMsg3.sendCmdArg(distance);
cmdMsg3.sendCmdEnd();
//interrupts();
}
Here's another callback that sends temperature data to the host computer by the cmdMessenger3 library:
void sendTemperatureData(uint8_t sensorId, uint16_t temperature) {
//noInterrupts();
cmdMsg3.sendCmdStart(kReadTemperature);
cmdMsg3.sendCmdArg(sensorId);
cmdMsg3.sendCmdArg(temperature);
cmdMsg3.sendCmdEnd();
//interrupts();
}
Problem: While the Arduino e.g. tries to send the temperature data, the ISR from the ultrasonic sensor might jump-in and writes it's own data to the serial stream; ending up in a mess regarding the serial data sent to the host computer, because the sending process is not atomic, consisting of multiple commands to send one message (sendCmdStart->sendCmdArg->sendCmdEnd).
Here's an example:
- Temperature is read an
sendTemperatureData(...)is called cmdMsg3.sendCmdStart(kReadTemperature);is calledcmdMsg3.sendCmdArg(sensorId);is called- ISR from sonar sensor jumps-in
sendTemperatureData();is calledcmdMsg3.sendCmdStart(kReadSonar);is calledcmdMsg3.sendCmdArg(sensorId);cmdMsg3.sendCmdArg(distance);cmdMsg3.sendCmdEnd();- remaining statements from
sendTemperatureData(...)are called cmdMsg3.sendCmdArg(temperature);cmdMsg3.sendCmdEnd();- resulting in a big mess on the serial communication ...
I then tried to prevent ISR calls during the send process by using noInterrupts()/interrupts(); making the send process kind of 'atomic'. But this leads to lots of other problems, millis()/micros() functions are not precise anymore, Serial communication breaks down, etc.; all relying on the timers that are disabled by noInterrupts(). Moreover, the servos behave also quite strange, since timing for the PWM signal generation seems to be messed up also.
Any ideas how to solve this 'concurrency' issue without breaking the interrupt-based paradigm in my program?