attachInterrupt use problem

I am having a problem using the attachinterrupt routine. After completing the routine that attachInterrupt is calling, it fails to return to the main program that was running when the interrupt occured. I am not sure if I have left out some required lines in the setup. The program normally scans the analog pins and and sends the values on the standard serial line, pin1(tx). At the falling edge of a software serial Rx pin, (pin 2, Int0), it should read the serial data, save the value and continue with scanning the analog pins. But my program gets stuck in the software serial read function waiting for the start bit even after completing a reading. Can someone tell me what is wrong? Here is the code.

#include <ctype.h>

#define bit9600Delay 100 // was 84, actual bit width 104 - 100 and 50 works
#define halfBit9600Delay 50 // was 42 before
#define bit4800Delay 188
#define halfBit4800Delay 94

byte rx = 2; // receive pin and inturrupt 0

byte SWval;
int anaval[5];
volatile byte ID[16];

int i = 0;
int streamRate = 100; // default stream rate is 10 samples per second

int mode = 1; // default data mode is ASCII

void setup() {
pinMode(rx,INPUT);
Serial.begin(19200);
attachInterrupt(0, readID, FALLING);
}

void readID(){
//detachInterrupt(1);
for (int i=0; i<16; i++){
ID = SWread();
_ //Serial.print(ID*, BYTE);_
_
}_
_ for (int i=1; i<11; i++) Serial.print(ID); // print ID # only*
* //Serial.println(i);
//attachInterrupt(1, readID, FALLING);
}
int SWread()
{
byte val = 0;
while (digitalRead(rx));
//wait for start bit*
* if (digitalRead(rx) == LOW) {
delayMicroseconds(halfBit9600Delay);
for (int offset = 0; offset < 8; offset++) {
delayMicroseconds(bit9600Delay);
val |= digitalRead(rx) << offset;
}
//wait for stop bit + extra*
* delayMicroseconds(bit9600Delay); // add as many as the stop bits*
* //delayMicroseconds(bit9600Delay);
return val;
}
}
void loop()
{
for (int i=0; i<5; i++)
anaval = analogRead(i);
//anaval = anaval/4; // downsample to 8 bit*

* if (mode == 1){
for (int i=0; i<5; i++){
Serial.print(anaval, DEC);
Serial.print("\t");
}
}
if (mode == 0){
for (int i=0; i<5; i++){
Serial.print(anaval, HEX);
Serial.print(9, HEX);
}
}
Serial.print("ID ");
for (int i=1; i<11; i++) Serial.print(ID); // print ID # only*

* Serial.println();
delay(streamRate);
}*_

Can you tell us what output you receive? How do you know where the code is hanging?

I'm not sure that Serial.print() will work inside an interrupt handler; can you try commenting it out?

Can you also say a few words about what task this sketch is intended to perform. What generates the incoming data and what do you want to happen when the data arrives.

Ok. Here is more details. The Arduino initially scans the 5 analog inputs and an ID value initially all zeros and reports the values at the rate of 10Hz on the serial port configured at 19200 baud. So I see the data coming until the interrupt is triggered by the device sending 16 bytes of data on a software serial line configured at 9600 baud. So the idea is when the device sends the 16 bytes data(only 10 will be used since the rest are formating and checksum) the start bit generates the interrupt (Rx pin is INT0). After reading the 16 bytes and saving them, the interrupt routine is complete and I want the program to contnue the previous task of reading the 5 analog values and reporting them along with the last reading of the device that were saved. So right now, the Arduino sends the analog values with ID of zeros. As soon as the device sends the 16 bytes they are read correctly and saved. But then instead of going back to the main program that scans the analog lines, it stays in SWread() routine waiting for the start bit. I know this because ...

  1. There is no more analog value report.
  2. Everytime the device sends a new 16 byte value it is stored properly.

So my question is why is the program not returning to where it was when the interrupt occured after completing IDread in AttachInterrupt(0, IDread, FALLING).

I have tried commenting out the serial.Print in the IDread() function and it did not make any difference. It is currently there only for debugging purposes to make sure the device values are saved properly.

I understand that the Arduino initially scans the 5 analog inputs and an ID value and sends these values to the serial port.

But I am not clear why you need an interrupt. What is sending the data that is triggering the receive interrupt, and why not just poll in your loop until serial data is available?

by an chance is the board trying to send to itself?

OK, here is my bet…

In
int SWread()
{
byte val = 0;
while (digitalRead(rx));
//wait for start bit
if (digitalRead(rx) == LOW) {
delayMicroseconds(halfBit9600Delay);
for (int offset = 0; offset < 8; offset++) {
delayMicroseconds(bit9600Delay);
val |= digitalRead(rx) << offset;
}
//wait for stop bit + extra
delayMicroseconds(bit9600Delay); // add as many as the stop bits
//delayMicroseconds(bit9600Delay);
return val;
}
}

I have just spent a week getting “flacky” results doing a “digitalRead” in an ISR routine.
That “while” would have hung my code.

It would be helpfull if maybe one of the experts can explain why…

Dave

OK, here is my bet....

In
int SWread()
{
while (digitalRead(rx)); //wait for start bit
// ...other stuff removed
}

I have just spent a week getting "flacky" results doing a "digitalRead" in an ISR routine.
That "while" would have hung my code.

It would be helpfull if maybe one of the experts can explain why.....

Dave

Although that while loop with digitalRead is not good in an ISR because it will block other interrupts until the external event on the rx pin occurs, I am surprised to hear that a simple digitalRead or two caused you a problem. If you can post a barebones sketch with the minimum code that demonstrates the problem then perhaps one of the experts could explain what is happening. I Have seen a number of Arduino sketches that use digitalRead in an ISR apparently without problem, here is one example: Arduino Playground - HomePage

No offense ardgui but your code is, from everything I have ever been taught a really good example of what should not be done in an ISR. An ISR typically blocks interupts and the general idea is to get in, do something, and get out ASAP. Ignoring the serial.prints , Your code catches that first falling edge then "hangs arround" polling, trying to assemble the rest of the character. SWread with its while loop gets called 16 times.

IMHO a better way would be to let the ISR set a flag that the mainline code can detect and go into a polling routine to assemble the rest of the chatacter. Also a while loop like that in SWread without a timeout is asking for problems.

My bet is that if you run the same code outside the ISR it works.

All that said I do bieleve there is something "funny" going on with digitalRead inside an ISR. I saw numerous instances where a digitalRead in the ISR on the same pin that generated the interupt on a RISING edge returned false. I also bieleve I saw instances where a pin that was not the IRQ source but was high was misreported as false by digitalRead inside the ISR.

In the interest of full disclosure ...
My results were not consistant, sometimes it worked and my IRQ source is a relay contact that "bounces" so I had to do some filtering.

I note that the example mentioned above turns on the internal pullup and I am using external sources.
humm...

I will try to put an example together.

Dave