Skip to main content
Arduino

Return to Answer

More on PCINT numbering.
Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

Addendum: Extra question:

why it doesn't work [with ISR(PCINT1_vect) {...}]?

Gcc tells me "warning: ‘PCINT1_vect’ appears to be a misspelled signal handler". And indeed, there is no such interrupt vector on the ATtiny45: there is only PCINT0_vect, and this interrupt is shared by all the pins that can generate a pin change interrupt. If you want to know which pin triggered the interrupt, you will have to figure that out within the interrupt handler itself.

This is the single point that makes the PCINTs trickier to work with than INT0 and co.: each PCINT interrupt is shared by a group of pins. On the ATtiny45, there is only one such group, and PCINT0_vect is the only interrupt handler. Larger AVRs have more groups (3 on the Uno/ATmega328P), and PCINT1_vect makes sense on them.

Also beware of the somewhat confusing naming scheme. Avr-libc defines some macros PCINTn, where n is a number. These macros expand to bit numbers, and are meant to be used in code like this:

PCMSK = _BV(PCINT0) // sense changes in pin PCINT0 = PB0...
 | _BV(PCINT1) // and PCINT1 = PB1...
 | _BV(PCINT2); // and PCINT2 = PB2

In these macros, the number n identifies an individual pin. Avr-libc also defines the macros PCINTm_vect for defining interrupt handlers. In these macros, the number m identifies a pin group.


Addendum: Extra question:

why it doesn't work [with ISR(PCINT1_vect) {...}]?

Gcc tells me "warning: ‘PCINT1_vect’ appears to be a misspelled signal handler". And indeed, there is no such interrupt vector on the ATtiny45: there is only PCINT0_vect, and this interrupt is shared by all the pins that can generate a pin change interrupt. If you want to know which pin triggered the interrupt, you will have to figure that out within the interrupt handler itself.

This is the single point that makes the PCINTs trickier to work with than INT0 and co.: each PCINT interrupt is shared by a group of pins. On the ATtiny45, there is only one such group, and PCINT0_vect is the only interrupt handler. Larger AVRs have more groups (3 on the Uno/ATmega328P), and PCINT1_vect makes sense on them.

Also beware of the somewhat confusing naming scheme. Avr-libc defines some macros PCINTn, where n is a number. These macros expand to bit numbers, and are meant to be used in code like this:

PCMSK = _BV(PCINT0) // sense changes in pin PCINT0 = PB0...
 | _BV(PCINT1) // and PCINT1 = PB1...
 | _BV(PCINT2); // and PCINT2 = PB2

In these macros, the number n identifies an individual pin. Avr-libc also defines the macros PCINTm_vect for defining interrupt handlers. In these macros, the number m identifies a pin group.

Awnsering comments.
Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

Look at the datasheet of the ATtiny45. In the section "Sleep Modes", there is a table that lists the wake-up sources available for each sleep mode. For the mode "power-down", INT0 is listed as a possible wake-up source, but there is a small footnote:

For INT0, only level interrupt.

This means that the CHANGE mode you are trying to use will not wake-up the MCU out of power-down. You have to instead

attachInterrupt(0, wake, LOW);

In my real code, I have 3 buttons, on pin #5, #6, #7, so eventually I'd like to have interrupts for all these three pins.

You may then have to look into the "pin-change" interrupt. This is something different from the INT0 you are using here, and is not generally supported by the Arduino core. You will have to either get some pin-change-interrupt library, or work with no library using the information from the datasheet (not that hard). Pin-change interrupt is also a wake-up source for power-down.


Edit: Answering extra questions from comments.

How did you know that "only level interrupt" means only "LOW"?

The Arduino documentation states that the mode parameter of attachInterrupt() can be either LOW, CHANGE, RISING or FALLING. A few boards also support HIGH, but the ATtinies are not among them. A "level" can be either LOW or HIGH, whereas CHANGE, RISING and FALLING are "edges".

This is corroborated by the ATtiny45 datasheet : "The INT0 interrupts can be triggered by a falling or rising edge or a low level."

Is pin-change interrupt PCINT?

Yes.

why do you think it isn't supported by the Arduino core?

The attachInterrupt() API only really makes sense for INT0, INT1, etc... not for PCINT. You can also look at the source code .

Isn't it standard to interrupt when a pin changes states?

If you wish, you can configure INT0 to interrupt on a rising edge, a falling edge, or any logical change. But this uses an edge-detection logic which relies on the main clock, and thus does not work in power-down mode.

For more details on INT0 vs. PCINT, their differences, and how to use them, please refer to the datasheet, specifically to the "External Interrupts" section I linked to above.

Look at the datasheet of the ATtiny45. In the section "Sleep Modes", there is a table that lists the wake-up sources available for each sleep mode. For the mode "power-down", INT0 is listed as a possible wake-up source, but there is a small footnote:

For INT0, only level interrupt.

This means that the CHANGE mode you are trying to use will not wake-up the MCU out of power-down. You have to instead

attachInterrupt(0, wake, LOW);

In my real code, I have 3 buttons, on pin #5, #6, #7, so eventually I'd like to have interrupts for all these three pins.

You may then have to look into the "pin-change" interrupt. This is something different from the INT0 you are using here, and is not generally supported by the Arduino core. You will have to either get some pin-change-interrupt library, or work with no library using the information from the datasheet (not that hard). Pin-change interrupt is also a wake-up source for power-down.

Look at the datasheet of the ATtiny45. In the section "Sleep Modes", there is a table that lists the wake-up sources available for each sleep mode. For the mode "power-down", INT0 is listed as a possible wake-up source, but there is a small footnote:

For INT0, only level interrupt.

This means that the CHANGE mode you are trying to use will not wake-up the MCU out of power-down. You have to instead

attachInterrupt(0, wake, LOW);

In my real code, I have 3 buttons, on pin #5, #6, #7, so eventually I'd like to have interrupts for all these three pins.

You may then have to look into the "pin-change" interrupt. This is something different from the INT0 you are using here, and is not generally supported by the Arduino core. You will have to either get some pin-change-interrupt library, or work with no library using the information from the datasheet (not that hard). Pin-change interrupt is also a wake-up source for power-down.


Edit: Answering extra questions from comments.

How did you know that "only level interrupt" means only "LOW"?

The Arduino documentation states that the mode parameter of attachInterrupt() can be either LOW, CHANGE, RISING or FALLING. A few boards also support HIGH, but the ATtinies are not among them. A "level" can be either LOW or HIGH, whereas CHANGE, RISING and FALLING are "edges".

This is corroborated by the ATtiny45 datasheet : "The INT0 interrupts can be triggered by a falling or rising edge or a low level."

Is pin-change interrupt PCINT?

Yes.

why do you think it isn't supported by the Arduino core?

The attachInterrupt() API only really makes sense for INT0, INT1, etc... not for PCINT. You can also look at the source code .

Isn't it standard to interrupt when a pin changes states?

If you wish, you can configure INT0 to interrupt on a rising edge, a falling edge, or any logical change. But this uses an edge-detection logic which relies on the main clock, and thus does not work in power-down mode.

For more details on INT0 vs. PCINT, their differences, and how to use them, please refer to the datasheet, specifically to the "External Interrupts" section I linked to above.

Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

Look at the datasheet of the ATtiny45. In the section "Sleep Modes", there is a table that lists the wake-up sources available for each sleep mode. For the mode "power-down", INT0 is listed as a possible wake-up source, but there is a small footnote:

For INT0, only level interrupt.

This means that the CHANGE mode you are trying to use will not wake-up the MCU out of power-down. You have to instead

attachInterrupt(0, wake, LOW);

In my real code, I have 3 buttons, on pin #5, #6, #7, so eventually I'd like to have interrupts for all these three pins.

You may then have to look into the "pin-change" interrupt. This is something different from the INT0 you are using here, and is not generally supported by the Arduino core. You will have to either get some pin-change-interrupt library, or work with no library using the information from the datasheet (not that hard). Pin-change interrupt is also a wake-up source for power-down.

AltStyle によって変換されたページ (->オリジナル) /