Interrupts? Timers? Interrupts and Timers?

I need to interface to another processor that will, at random times, send me 100 bits, 1 every millisecond. The data will start with a transition from a '0' to a '1'.

The 'random time' part says INTERRUPT to me.

But, an interrupt service routine can evidently only collect 16 bits of data, and probably can't have a delay for the 1 millisecond requirement.

My thinking is that I need an interrupt to sense the start of the data, followed by a 500 microsecond delay to get me to the middle of the incoming bit, and then collect a bit every time a 1 millisecond timer goes off.

My gift for the obvious evidently doesn't apply to Arduino code yet. I am only coming up with very complicated solutions.

The incoming data will be important, so I don't want to miss any.

The main loop will consist mainly of back and forth communication with the computer.

What is a great way to do this?

lurkingBear: But, an interrupt service routine can evidently only collect 16 bits of data, and probably can't have a delay for the 1 millisecond requirement.

16 bits? That's not evident to me. The ISR can do whatever it wants. Sounds like a variant of software serial to me. You could use delayMicroseconds to wait for a millisecond to pass. Or do various other things. One would be to start up a timer set to go off every millisecond, exit the ISR and let the timer kick in and do an interrupt, until you get 100 of them.

Nick,

My questions are at the end of the post.

Here’s my code:

// Interrupt on rising edge of data
// for now, just the 100 samples, add timing later
// Put samples in array to process or send to PC

boolean dataIn[100];
const int dataInSize = sizeof(dataIn);
volatile boolean dataReady = 0;
const long dataTime = 1000;  //1000 uSeconds
const long halfdataTime = 500;  //500 uSeconds
const int dataPin = 2;
int test = 0; 
int outPin = 7;  //for testing, wire pin 7 to pin 2
int temp = 0;

void setup() {
  pinMode(dataPin, INPUT);
  pinMode(outPin, OUTPUT);
  Serial.begin(115200);
  attachInterrupt(0, dataISR, RISING);
  Serial.println("Ready");
}  //end setup

void loop() 
{
  delay(500);
  if (Serial.available())  //get info to drive test pin 
  {
    temp = Serial.read() - '0';
    digitalWrite(outPin, temp);
  }
  test = digitalRead(dataPin);  //wired outPin to dataPin for testing
  Serial.print("dataPin = ");
  Serial.println(test);
  if (dataReady)
  {
     for (int index = 0; index < dataInSize; index++)
     {
       Serial.println("printing array of 100 "); 
       Serial.println(dataIn[index]);
      }
  Serial.println("attaching interrupt 0 ");  
  dataReady = 0;  //clear dataReady, to be set by dataISR
  attachInterrupt(0, dataISR, RISING); 
}
}  //end loop


void dataISR()
{ 
  //turn off interrupts, I'm already here
  //Then, go in a loop and get the next 100 values, sampling every dataTime
  //Store the data in the dataIn array
  detachInterrupt(0);
  Serial.println("In ISR...");
  
  for (int index2 = 0; index2 < 16; index2++)
  {
    dataIn[index2] = digitalRead(dataPin);
    Serial.println(index2);
  }
  dataReady = 1;
} 
// end dataISR

If index2 is > 15, the program stops responding.

I believe this is mentioned in the old forum: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261124850

Based on these 2 things, I thought I could only get 15 readings in my ISR?

Moderator edit: [code][/code] tags added. (Nick Gammon)

Why do you read the same digital signal more than once?

Do you rely on the speed of Serial.println(index2); in your dataISR ???

Very bad idea, IMO. I think you should not try to do 16 Serial.print() in an ISR, but rather none.

The Serial.println statements in the interrupt service routine are only there to help me see where the program hangs.

I will remove them once I get the interrupt service routine working.

I believe my current problem is that this line in the interrupt service routine:
for (int index2 = 0; index2 < 16; index2++)

causes the program to hang.

If I change it to this:
for (int index2 = 0; index2 < 15; index2++)

it does not hang.

Since I want to collect 100 readings, and this seems to limit me to 16, it appears to be a problem.

lurkingBear:
I believe my current problem is that this line in the interrupt service routine:
for (int index2 = 0; index2 < 16; index2++)

causes the program to hang.

You can easily add a line
for (int index2 = 0; index2 < 100; index2++) dataIn[index2] = digitalRead(dataPin);

which is way too fast and won’t help you at all, but you can’t call other interrupt depending stuff like Serial.print (), especially when you are going to exceed the Serial buffer size ( after 15 outputs ? ) …

The ISR is nice to detect the start, but to read a digital pin in a strictly timed way you need a timer, triggering a single digitalRead(dataPin) per timer event. ( Or do 100 delayMicroseconds() in loop() if you don’t have anything else to do … )

lurkingBear:
The Serial.println statements in the interrupt service routine are only there to help me see where the program hangs.

Perhaps, but a Serial.println inside an ISR will cause your program to hang if you print more than the serial buffer size, so that is a self-defeating exercise.

lurkingBear: Based on these 2 things, I thought I could only get 15 readings in my ISR?

The serial buffer size on this processor is, I think, 64 bytes. You are printing 3/4 bytes per reading (one or two digits, plus carriage return, plus newline).

So, you are printing:

10 * 3 bytes = 30 6 * 4 bytes = 24 "In ISR..." = 12

Total = 66 bytes.

The serial print will hang at 64 bytes as it waits for the buffer to empty, which it won't inside an ISR. However for 15 prints you just squeeze under 64 bytes.

So all your code proves, all it proves, is that you cannot print more than 64 bytes inside an ISR. Nothing else.

you cannot print more than 64 bytes inside an ISR

... and you cannot use the assumed serial speed to slow down your digitalRead cycle.

Absolutely right. I was wondering where the 1 mS delays were coming from.

Thank you, Nick and Michael, for your very informative replies.

I will have another go at it now that I understand things a little better.