Interrupts on ARDUINO NANO ATmega168PA

Hi! I am using Arduino NANO with ATmega168PA microprocessor. My task is to check the operation of interrupts and timers for their joint work. I use three LEDs: red, yellow and green.

I wrote the following code:

int32_t volatile  i;
int32_t volatile  j;
int32_t volatile  u;
void setup() {

  Serial.begin(9600);     // setting the port speed (bps, baud)

  cli();                  // instruction to disable interrupts immediately
  DDRD = 0xFF;            // port D to OUTPUT
  //SMCR |= (0 << SM0) | (0 << SM1) | (0 << SM2);
  TCCR1A = 0b00000000;    // OC1A Disabled
  TCCR1B = 0b00001100;    // divider 256, reset on match 1A (CTC mode)
  TIMSK1 = 0b00000110;     // start interrupt A and B timer 1
  OCR1A = 0xF424;         // 1s 0xC350 0.8s 0x30D4 0.2s 0xF424 1s
  OCR1B = 0x7A12;         //  0xF424 0.5s
  //TCCR1A = 0b00000000;    // OC1A Disabled
  //TCCR1B = 0b00001100;    // divider 256, reset on match 1B (CTC mode)
  //TIMSK1 = 0b0000100;     // start interrupt B timer 1
  TCCR2A = 0b00000000;    // OC2A Disabled
  TCCR2B = 0b00001101;    // divider 1024, reset on match 2V (CTC mode)
  OCR2A = 0xFFFF;         // 0.016s
  //TIMSK2 = 0b00000010;     // start interrupt B timer 2
  TIMSK2 |= (1 << OCIE2A);

  sei();                  // instruction to enable interrupts


}
void loop() {
  // put your main code here, to run repeatedly:

}
ISR(TIMER1_COMPA_vect) {      //timer 1 coincident interrupt handler A, counter reset to 0
  Serial.println('i');
  Serial.println(i);
  i ++;
  if (i % 2 == 0)
    PORTD = 0b00000100;

  if (i % 2 == 1)
    PORTD = 0b00000000;
}
ISR(TIMER1_COMPB_vect) {    //timer 1 coincident interrupt handler A, counter reset to 0
  j ++;
  Serial.println('j');
  Serial.println(j);

  if (j % 2 == 0)
    PORTD = 0b00010000;

  if (j % 2 == 1)
    PORTD = 0b00000000;
}
ISR(TIMER2_COMPA_vect) {      //timer 2 coincident interrupt handler A, counter reset to 0
  u ++;
  Serial.println('u');
  Serial.println(u);

  if (u % 2 == 0)
    PORTD = 0b00001000;

  if (u % 2 == 1)
    PORTD = 0b00000000;
}

If both the first timer interrupt and the second timer interrupt are enabled, only the interrupt of the first timer is triggered. If both the first timer interrupt and the second timer interrupt are enabled, only the interrupt of the first timer is triggered. If interrupts of the first timer are enabled separately, then the first interrupt works (LEDs red (1 second), green (0.5 seconds) blink). I have the yellow LED set to interrupt the second timer. I do not understand why all the LEDs do not light up together (only the yellow LED blinks when working together)? If you change the second timer to a zero timer, then the LEDs all blink together (each at its own time). Why is it not possible to start interrupts of the second and first interrupts together? Interestingly, when the zero and second timer interrupts work together, only the second timer interrupts are triggered.

Most probably the output to Serial inside the ISR blocks the controller. Remove these statements and try again.

1 Like

On atmega168/328 the register OCR2A is 8 bit only

Thank you! When I removed Serial from interrupts, the LEDs lit up, though the yellow LED blinks worse (just glows) when blinking occurs on an interrupt from the second timer than when blinking occurs from an interrupt from the zero timer (the LED actually blinks and the light is brighter).

Thank you! I know. It just takes half of the given value at 8-bit resolution.

This will turn off all LEDs connected to port D, not only the one related to the current ISR.

2 Likes

In addition to the @DrDiettrich post#6 - you are turning your LEDs on and off in interrupts completely wrong:

The line PORTD = 0b00000100; not only turn D2 pin HIGH, but also turn off all others pins on PORTD.
The same is true for two other interrupts. Each of them influences the others two.

To turn pins on and off independently you need to change the defined pin ONLY.
For example

 i ++;
  if (i % 2 == 0)
    PORTD | = 0b00000100;   // turn D2 HIGH exclusively

  if (i % 2 == 1)
    PORTD &=  ~ 0b00000100;  // turn D2 LOW
1 Like

Thank you! These are really good decisions. I agree. Already rewrote my code!

int32_t volatile  i;
int32_t volatile  j;
int32_t volatile  u;
void setup() {

  Serial.begin(9600);     // setting the port speed (bps, baud)

  cli();                  // instruction to disable interrupts immediately
  DDRD = 0xFF;            // port D to OUTPUT
  //SMCR |= (0 << SM0) | (0 << SM1) | (0 << SM2);
  TCCR1A = 0b00000000;    // OC1A Disabled
  TCCR1B = 0b00001100;    // divider 256, reset on match 1A (CTC mode)
  TIMSK1 = 0b00000110;     // start interrupt A and B timer 1
  OCR1A = 0xF424;         // 1s 0xC350 0.8s 0x30D4 0.2s 0xF424 1s
  OCR1B = 0x7A12;         //  0xF424 0.5s
  //TCCR1A = 0b00000000;    // OC1A Disabled
  //TCCR1B = 0b00001100;    // divider 256, reset on match 1B (CTC mode)
  //TIMSK1 = 0b0000100;     // start interrupt B timer 1
  TCCR2A = 0b00000000;    // OC2A Disabled
  TCCR2B = 0b00001101;    // divider 1024, reset on match 2V (CTC mode)
  OCR2A = 0xFFFF;         // 0.016s
  //TIMSK2 = 0b00000010;     // start interrupt B timer 2
  TIMSK2 |= (1 << OCIE2A);

  sei();                  // instruction to enable interrupts


}
void loop() {
  // put your main code here, to run repeatedly:

}
ISR(TIMER1_COMPA_vect) {      //timer 1 coincident interrupt handler A, counter reset to 0
  //Serial.println('i');
  //Serial.println(i);
  i ++;
  if (i % 2 == 0)
    PORTD |= 0b00000100;

  if (i % 2 == 1)
    PORTD &= ~0b00000100;
}
ISR(TIMER1_COMPB_vect) {    //timer 1 coincident interrupt handler A, counter reset to 0
  j ++;
  //Serial.println('j');
  //Serial.println(j);

  if (j % 2 == 0)
    PORTD |= 0b00010000;

  if (j % 2 == 1)
    PORTD &= ~0b00010000;
}
ISR(TIMER2_COMPA_vect) {      //timer 2 coincident interrupt handler A, counter reset to 0
  u ++;
  //Serial.println('u');
  //Serial.println(u);

  if (u % 2 == 0)
    PORTD |= 0b00001000;

  if (u % 2 == 1)
    PORTD &= ~0b00000000;
}

Do you want more tips for improvement or you are happy with the solution?

Yes, I'll ask for more help. I can’t understand, the red and green LEDs blink (the first timer), and for some reason the yellow LED only glows when I blink the yellow LED according to the second timer. If I switch the work of the yellow LED to the zero timer, there are no questions (there is blinking). Why is that? After all, both the zero and second timers are 8-bit timers, they are similar.

This should be equivalent to

PIND = 0b00000100; // toggle D2

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.