What's wrong with my interrupt?

I’m working on a project that will have the microcontroller sending serial data out a digital pin at 512 baud and I’m trying to get the speed consistent. I decided to try using the Timer2 overflow interrupt to synchronize the data stream.

Global variables used for this process:

boolean BitSend = false;
int DelayCount = 0;

Interrupt service routine:

ISR(TIMER2_OVF_vect) {                    // Interrupt service routine for Timer2 overflow
  DelayCount++;                           // Increment DelayCount by 1
  if (DelayCount > 121)  {                // Check to see if it's time to send the next bit (122*16uS or 1.952mS)
    BitSend = true;                       // Sets "BitSend" to let the transmit subroutine know it's time
    DelayCount = 0;                       // Reset Timer2's overflow count

Configuring Timer2 and the Interrupt in Setup() :

  TCCR2A = 0;                             // Set Timer2 to normal operation
  TCCR2B = 0<<CS22 | 0<<CS21 | 1<<CS20;   // Set Timer2 to run at 16 MHz
  TIMSK2 = 1<<TOIE2;                      // Enable Timer2 overflow interrupt

Sending a data bit and waiting until it’s time to send the next one (this takes place within a loop that cycles through all the binary bits to be sent in the data packet, with txState being assigned to the bit’s value each time):

  digitalWrite(dataPin, txState);         // Send the data bit
  while (!BitSend){}                      // Wait here until BitSend trigger is set
  BitSend = false;                        // Clear the BitSend trigger to begin new cycle

The trouble is that the program seems to get stuck in that “while” loop.

When troubleshooting the program I ended up adding a visual indicator (the pin 13 LED) so I could get a clue as to what was going on and I expanded the “while” line:

  while (!BitSend){  digitalWrite(13,HIGH);  }                      // Wait here until BitSend trigger is set

Strange thing is, now the program doesn’t get stuck in the loop any more. I can’t figure out why writing to the digital pin makes a difference in how the loop and/or interrupt actually function.

volatile boolean BitSend = false;

I can't figure out why writing to the digital pin makes a difference in how the loop and/or interrupt actually function.

As Coding Badly (a misnomer if ever there was) pointed out, you need to use the volatile keyword. When you use the volatile keyword, you are telling the compiler that there are other ways that the value of the variable can change (like your ISR). So, the compiler needs to check the value of the variable every time is accesses it.

Without that, the compiler sees that nothing in the body of the loop can change the value of the variable, so it never fetches the new value, and you sit in your while loop referring only to the last value read from the variable.

Ok, that certainly clears that up! Thank you for the answer and for the explanation. I also went and read what the Language Reference has to say about it.

Now I'm guessing that the extra bit of code I added had the effect of forcing the variable into RAM so that the registers would be available to process the digitalWrite command. And once the variable was in RAM the interrupt eventually toggled the value and the proessor correctly read its updated value back from RAM. Does this sound correct?


Note: DelayCount does not need to be volatile because the variable is only used by the interrupt service routine.

Ok. Cool, I learned something! :)

This may help…