Sorry to reply to this topic two years later, but this is the first result I get by Google to the query "Arduino serial interrupt".
I see that someone solved this problem and even provided a library to handle Serial I/O via interrupts. In one case an extension to HardwareSerial provided with Arduino has been written.
You can find that here:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1191505972http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265509976/3http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1242292909/2I don't know if this helps, but I just succeeded in doing that in a very simple way.Maybe it uses the same priciples used by the above solutions, but I don't know, since the provided code is quite complex to me.
My humble solution is to reenable interrupts while in the interrupt service routine to allow Serial to work.
Then wait for data in the Serial data to be available.
Drawback: this steals a bit of CPU when receiving data: the ISR activates on the Start bit of the serial data. Then it has to wait for the 10 bits on 8N1 protocol to be received. At 9600bps this means wasting about 1/960 seconds, i.e. about 16.000 cpu cycles.
The worst thing is that if multiple bytes are sent without any rest, the ISR will be stealing the CPU for about 1/960 seconds and then leave it free for 1/9600, the mere time between the end of a byte and the biginning of the next one, and then continue cycling like this.
So my approach is not suitable for every application.
A solution to this problem might be to disasbile interrupts and reenable them in the main loop, using noInterrupts() and interrupts() functions, reducing the number of ISR calls during main loop.
This is my humble code:
// To use this example, you have to connect Rx pin (digital pin 0) to interrupt 0 pin (digital pin 2).
void setup()
{
// Using interrupt 0 on digital pin 2.
pinMode(2, INPUT);
digitalWrite(2, LOW);
Serial.begin(9600);
attachInterrupt(0, serialInterrupt, CHANGE);
// Used to signal that main loop is alive.
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
// Used to signal that Serial input was read.
pinMode(5, OUTPUT);
digitalWrite(5, LOW);
}
void loop()
{
// Do something using even delays. There is an interrupt for that (Serial I/O)!
// Blink led to signal loop is alive.
digitalWrite(4, HIGH);
delay(500);
digitalWrite(4, LOW);
delay(500);
}
// Volatile, since it is modified in an ISR.
volatile boolean inService = false;
void serialInterrupt()
{
// Trick: since Serial I/O in interrupt driven, we must reenable interrupts while in this Interrupt Service Routine.
// But doing so will cause the routine to be called nestedly, causing problems.
// So we mark we are already in service.
// Already in service? Do nothing.
if (inService) return;
// You was not in service. Now you are.
inService = true;
// Reenable interrupts, to allow Serial to work. We do this only if inService is false.
interrupts();
// Allow serial to read at least one byte.
while(!Serial.available());
// Blink led to signal Serial data arrived.
digitalWrite(5, !digitalRead(5));
byte data = Serial.read();
// Echo data back to developer ;-)
Serial.print(data);
// Job done.
inService = false;
}
I tried this other approach, detaching and reattaching ISR, but it stops the main loop. Do know why.
void serialInterrupt()
{
detachInterrupt(0);
interrupts();
while(!Serial.available());
digitalWrite(5, !digitalRead(5));
byte data = Serial.read();
Serial.print(data);
attachInterrupt(0, serialInterrupt, CHANGE);
}