diff --git a/Readme.md b/Readme.md index 5b5ce92..9bb7a72 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -PinChangeInterrupt Library 1.2.1 +PinChangeInterrupt Library 1.2.2 ================================ ![Header Picture](header.png) @@ -25,12 +25,15 @@ See [PCINT pin table](https://github.com/NicoHood/PinChangeInterrupt/#pinchangei A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) HoodLoader2: All (broken out 1-7) pins are usable - Attiny 24/44/84: All pins are usable - Attiny 25/45/85: All pins are usable - ATmega644P/ATmega1284P: All pins are usable + Attiny 24/44/84: All pins are usable + Attiny 25/45/85: All pins are usable + Attiny 13: All pins are usable + ATmega644P/ATmega1284P: All pins are usable ``` -**[Comment for feedback on my blog.](http://www.nicohood.de)** +Contact information can be found here: + +www.nicohood.de Installation ============ @@ -49,7 +52,7 @@ How to use It is important that you know at least the basic difference between **PinInterrupts** and **PinChangeInterrupts**. I will explain the basics of **PinChangeInterrupts** (PCINTs) based on an Arduino Uno. -On a standard Arduino Pin 2 and 3 have **PinInterrupts**. Those are exclusively for a single pin and can detect RISING, FALLING and CHANGE. +On a standard Arduino Uno Pin 2 and 3 have **PinInterrupts**. Those are exclusively for a single pin and can detect RISING, FALLING and CHANGE. **PinChangeInterrupts** instead are used for a whole port (they should have better named them PortChangeInterrupts) and can only detect CHANGE for a whole port. Each pin row (0-7, 8-13, A0-A5) represents a port. If an interrupt (ISR) occurs on one pin of a port @@ -79,29 +82,68 @@ https://github.com/NicoHood/IRLremote ###API Reference -#####`void attachPinChangeInterrupt(uint8_t pcintNum, void(*userFunc)(void), uint8_t mode)` -Attaches a user function to a specific pin. The pin number has to be a pcint number. -It is recommended to use the digitalPinToPinChangeInterrupt(p) makro with this function. -Valid modes are `RISING`, `FALLING` and `CHANGE`. -After this function is called all interrupts on the selected pin will execute the attached function. -For the LowLevel mode no user function is required. -`attachPCINT` is an equivalent alias. - -#####`void detachPinChangeInterrupt(uint8_t pcintNum)` -Detaches the pin and its user function. Interrupts will no longer occur for this pin. -Call the attachPinChangeInterrupt() function again to reactivate any interrupt. -It is recommended to use the digitalPinToPinChangeInterrupt(p) makro with this function. -`detachPCINT` is an equivalent alias. - -#####`digitalPinToPinChangeInterrupt(p)` -Makro to convert a pin to its PCINT number. Only input valid PCINT pins or it won't work. -`digitalPinToPCINT` is an equivalent alias. - -#####`PinChangeInterruptEvent(n)` -LowLevel function that is called when an interrupt occurs for a specific PCINT. -It is required to know the exact PCINT number, no Arduino pin number will work here. -See LowLevel example for more information. -`PCINTEvent(n)` is an equivalent alias. +#####Attach a PinChangeInterrupt +```cpp +// The pin has to be a PCINT number. Use the makro to convert a pin to a PCINT number. +// Enables event functions which need to be defined in the sketch. +// Valid interrupt modes are: RISING, FALLING or CHANGE +attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick), tick, RISING); + +// You can also input the PCINT number (see table below) +attachPinChangeInterrupt(5, tock, FALLING); + +// PinChangeInterrupt can always be abbreviated with PCINT +attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE); +``` + +#####Detach a PinChangeInterrupt +```cpp +// Similar usage as the attachPCINT function. +// Interrupts will no longer occur. +detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); +detachPinChangeInterrupt(5); +detachPCINT(digitalPinToPCINT(pinTock)); +``` + +#####Enable/Disable a PinChangeInterrupt +```cpp +// Similar usage as the attachPCINT function. +// Use this to temporary enable/disable the Interrupt +disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); +disablePinChangeInterrupt(5); +disablePCINT(digitalPinToPCINT(pinBlink)); + +// Enable the PCINT with the old settings again (function + mode) +enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); +enablePinChangeInterrupt(5); +enablePCINT(digitalPinToPCINT(pinBlink)); +``` + +#####Get Trigger on mode CHANGE +```cpp +// Differenciate between RISING and FALLING on mode CHANGE. +// Only use this in the attached interrupt function. +uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(pinTick)); +if(trigger == RISING) + // Do something +else if(trigger == FALLING) + // Do something +else + // Wrong usage (trigger == CHANGE) +``` + +#####LowLevel API +See [LowLevel example](examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino) for more details. +```cpp +// Use the attach function as you are used to, just leave out the function name +attachPinChangeInterrupt(interruptBlink, CHANGE); + +// LowLevel function that is called when an interrupt occurs for a specific PCINT. +// It is required to know the exact PCINT number, no Arduino pin number will work here. +void PinChangeInterruptEvent(5)(void) { + // Do something +} +``` PinchangeInterrupt Table ======================== @@ -145,46 +187,45 @@ Not all MCUs have all Ports/Pins physically available. ``` ####Other Atmel MCUs - ``` -| PCINT | Attiny x4 | Attiny x5 | ATmega644P/1284P | -| ----- | --------------- | ------------- | ----------------- | -| 0 | 0 (PA0) | 0 MOSI (PB0) | A0/D24 (PA0) | -| 1 | 1 (PA1) | 1 MISO (PB1) | A1/D25 (PA1) | -| 2 | 2 (PA2) | 2 SCK (PB2) | A2/D26 (PA2) | -| 3 | 3 (PA3) | 3 XTAL1 (PB3) | A3/D27 (PA3) | -| 4 | 4 SCK (PA4) | 4 XTAL2 (PB4) | A4/D28 (PA4) | -| 5 | 5 MISO (PA5) | 5 RST (PB5) | A5/D29 (PA5) | -| 6 | 6 MOSI (PA6) | | A6/D30 (PA6) | -| 7 | 7 (PA7) | | A7/D31 (PA7) | -| ----- | --------------- | ------------- | ----------------- | -| 8 | 10 XTAL1 (PB0)* | | 0 (PB0) | -| 9 | 9 XTAL2 (PB1)* | | 1 (PB1) | -| 10 | 8 INT0 (PB2)* | | 2 INT2 (PB2) | -| 11 | RST (PB3)* | | 3 PWM (PB3) | -| 12 | | | 4 SS/PWM (PB4) | -| 13 | | | 5 MOSI/PWM (PB5) | -| 14 | | | 6 MISO/PWM (PB6) | -| 15 | | | 7 SCK (PB7) | -| ----- | --------------- | ------------- | ----------------- | -| 16 | | | 16 SCL (PC0) | -| 17 | | | 17 SDA (PC1) | -| 18 | | | 18 TCK (PC2) | -| 19 | | | 19 TMS (PC3) | -| 20 | | | 20 TDO (PC4) | -| 21 | | | 21 TDI (PC5) | -| 22 | | | 22 (PC6) | -| 23 | | | 23 (PC7) | -| ----- | --------------- | ------------- | ----------------- | -| 24 | | | 8 RX0 (PD0) | -| 25 | | | 9 TX0 (PD1) | -| 26 | | | 10 RX1/INT0 (PD2) | -| 27 | | | 11 TX1/INT1 (PD3) | -| 28 | | | 12 PWM (PD4) | -| 29 | | | 13 PWM (PD5) | -| 30 | | | 14 PWM (PD6) | -| 31 | | | 15 PWM (PD7) | -| ----- | --------------- | ------------- | ----------------- | +| PCINT | Attiny13 | Attiny x4 | Attiny x5 | ATmega644P/1284P | +| ----- | ------------ | --------------- | ------------- | ----------------- | +| 0 | 0 MOSI (PB0) | 0 (PA0) | 0 MOSI (PB0) | A0/D24 (PA0) | +| 1 | 1 MISO (PB1) | 1 (PA1) | 1 MISO (PB1) | A1/D25 (PA1) | +| 2 | 2 SCK (PB2) | 2 (PA2) | 2 SCK (PB2) | A2/D26 (PA2) | +| 3 | 3 (PB3) | 3 (PA3) | 3 XTAL1 (PB3) | A3/D27 (PA3) | +| 4 | 4 (PB4) | 4 SCK (PA4) | 4 XTAL2 (PB4) | A4/D28 (PA4) | +| 5 | 5 RST (PB5) | 5 MISO (PA5) | 5 RST (PB5) | A5/D29 (PA5) | +| 6 | | 6 MOSI (PA6) | | A6/D30 (PA6) | +| 7 | | 7 (PA7) | | A7/D31 (PA7) | +| ----- | ------------ | --------------- | ------------- | ----------------- | +| 8 | | 10 XTAL1 (PB0)* | | 0 (PB0) | +| 9 | | 9 XTAL2 (PB1)* | | 1 (PB1) | +| 10 | | 8 INT0 (PB2)* | | 2 INT2 (PB2) | +| 11 | | RST (PB3)* | | 3 PWM (PB3) | +| 12 | | | | 4 SS/PWM (PB4) | +| 13 | | | | 5 MOSI/PWM (PB5) | +| 14 | | | | 6 MISO/PWM (PB6) | +| 15 | | | | 7 SCK (PB7) | +| ----- | ------------ | --------------- | ------------- | ----------------- | +| 16 | | | | 16 SCL (PC0) | +| 17 | | | | 17 SDA (PC1) | +| 18 | | | | 18 TCK (PC2) | +| 19 | | | | 19 TMS (PC3) | +| 20 | | | | 20 TDO (PC4) | +| 21 | | | | 21 TDI (PC5) | +| 22 | | | | 22 (PC6) | +| 23 | | | | 23 (PC7) | +| ----- | ------------ | --------------- | ------------- | ----------------- | +| 24 | | | | 8 RX0 (PD0) | +| 25 | | | | 9 TX0 (PD1) | +| 26 | | | | 10 RX1/INT0 (PD2) | +| 27 | | | | 11 TX1/INT1 (PD3) | +| 28 | | | | 12 PWM (PD4) | +| 29 | | | | 13 PWM (PD5) | +| 30 | | | | 14 PWM (PD6) | +| 31 | | | | 15 PWM (PD7) | +| ----- | ------------ | --------------- | ------------- | ----------------- | ``` Developer Information @@ -217,6 +258,14 @@ the new PinChangeInterrupts may help you a lot. Version History =============== ``` +1.2.2 Release (05.12.2015) +* Fixed initial value when enabled issue +* Enabled official dot_a_linkage +* Added Attiny13 support Issue #4 +* Updated documentation +* Improved detaching function +* Improved attaching and enabling + 1.2.1 Release (24.05.2015) * Fix Attiny Issue #1 * Added enable/disable function diff --git a/examples/PinChangeInterrupt_HowItWorks/PinChangeInterrupt_HowItWorks.ino b/examples/PinChangeInterrupt_HowItWorks/PinChangeInterrupt_HowItWorks.ino index 70d5448..fb6da27 100644 --- a/examples/PinChangeInterrupt_HowItWorks/PinChangeInterrupt_HowItWorks.ino +++ b/examples/PinChangeInterrupt_HowItWorks/PinChangeInterrupt_HowItWorks.ino @@ -1,120 +1,121 @@ -/* - Copyright (c) 2014-2015 NicoHood - See the readme for credit to other people. - - PinChangeInterrupt_HowItWorks - Shows how to manually setup a single PCINT function with a few helper functions. - - Connect a button/cable to pin 7 and ground. - The led will change its state if pin 7 changes. - - PinChangeInterrupts are different than normal Interrupts. - See readme for more information. - Dont use Serial or delay inside interrupts! - This library is not compatible with SoftSerial. - - The following pins are usable for PinChangeInterrupt: - Arduino Uno/Nano/Mini: All pins are usable - Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), - A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) - Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) - HoodLoader2: All (broken out 1-7) pins are usable - Attiny 24/44/84: All pins are usable - Attiny 25/45/85: All pins are usable - ATmega644P/ATmega1284P: All pins are usable - */ - -//================================================================================ -// User Settings -//================================================================================ - -// choose a valid PinChangeInterrupt pin of your Arduino board -#define PCINT_PIN 7 -#define PCINT_MODE CHANGE -#define PCINT_FUNCTION blinkLed - -void setup() -{ - // set pins to input with a pullup, led to output - pinMode(PCINT_PIN, INPUT_PULLUP); - pinMode(LED_BUILTIN, OUTPUT); - - // attach the new PinChangeInterrupt - attachPinChangeInterrupt(); -} - -void loop() { - // empty -} - -void blinkLed(void) { - // switch Led state - digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); -} - -//================================================================================ -// PCINT Definitions -//================================================================================ - -#define PCMSK *digitalPinToPCMSK(PCINT_PIN) -#define PCINT digitalPinToPCMSKbit(PCINT_PIN) -#define PCIE digitalPinToPCICRbit(PCINT_PIN) -#define PCPIN *portInputRegister(digitalPinToPort(PCINT_PIN)) - -#if (PCIE == 0) -#define PCINT_vect PCINT0_vect -#elif (PCIE == 1) -#define PCINT_vect PCINT1_vect -#elif (PCIE == 2) -#define PCINT_vect PCINT2_vect -#else -#error This board doesnt support PCINT ? -#endif - -volatile uint8_t oldPort = 0x00; - -void attachPinChangeInterrupt(void) { - // update the old state to the actual state - oldPort = PCPIN; - - // pin change mask registers decide which pins are enabled as triggers - PCMSK |= (1 << PCINT); - - // PCICR: Pin Change Interrupt Control Register - enables interrupt vectors - PCICR |= (1 << PCIE); -} - -void detachPinChangeInterrupt(void) { - // disable the mask. - PCMSK &= ~(1 << PCINT); - - // if that's the last one, disable the interrupt. - if (PCMSK == 0) - PCICR &= ~(0x01 << PCIE); -} - -ISR(PCINT_vect) { - // get the new and old pin states for port - uint8_t newPort = PCPIN; - - // compare with the old value to detect a rising or falling - uint8_t change = newPort ^ oldPort; - - // check which pins are triggered, compared with the settings - uint8_t trigger = 0x00; -#if (PCINT_MODE == RISING) || (PCINT_MODE == CHANGE) - uint8_t rising = change & newPort; - trigger |= (rising & (1 << PCINT)); -#endif -#if (PCINT_MODE == FALLING) || (PCINT_MODE == CHANGE) - uint8_t falling = change & oldPort; - trigger |= (falling & (1 << PCINT)); -#endif - - // save the new state for next comparison - oldPort = newPort; - - // if our needed pin has changed, call the IRL interrupt function - if (trigger & (1 << PCINT)) - PCINT_FUNCTION(); -} \ No newline at end of file +/* + Copyright (c) 2014-2015 NicoHood + See the readme for credit to other people. + + PinChangeInterrupt_HowItWorks + Shows how to manually setup a single PCINT function with a few helper functions. + + Connect a button/cable to pin 7 and ground. + The led will change its state if pin 7 changes. + + PinChangeInterrupts are different than normal Interrupts. + See readme for more information. + Dont use Serial or delay inside interrupts! + This library is not compatible with SoftSerial. + + The following pins are usable for PinChangeInterrupt: + Arduino Uno/Nano/Mini: All pins are usable + Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), + A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) + Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) + HoodLoader2: All (broken out 1-7) pins are usable + Attiny 24/44/84: All pins are usable + Attiny 25/45/85: All pins are usable + Attiny 13: All pins are usable + ATmega644P/ATmega1284P: All pins are usable + */ + +//================================================================================ +// User Settings +//================================================================================ + +// choose a valid PinChangeInterrupt pin of your Arduino board +#define PCINT_PIN 7 +#define PCINT_MODE CHANGE +#define PCINT_FUNCTION blinkLed + +void setup() +{ + // set pins to input with a pullup, led to output + pinMode(PCINT_PIN, INPUT_PULLUP); + pinMode(LED_BUILTIN, OUTPUT); + + // attach the new PinChangeInterrupt + attachPinChangeInterrupt(); +} + +void loop() { + // empty +} + +void blinkLed(void) { + // switch Led state + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); +} + +//================================================================================ +// PCINT Definitions +//================================================================================ + +#define PCMSK *digitalPinToPCMSK(PCINT_PIN) +#define PCINT digitalPinToPCMSKbit(PCINT_PIN) +#define PCIE digitalPinToPCICRbit(PCINT_PIN) +#define PCPIN *portInputRegister(digitalPinToPort(PCINT_PIN)) + +#if (PCIE == 0) +#define PCINT_vect PCINT0_vect +#elif (PCIE == 1) +#define PCINT_vect PCINT1_vect +#elif (PCIE == 2) +#define PCINT_vect PCINT2_vect +#else +#error This board doesnt support PCINT ? +#endif + +volatile uint8_t oldPort = 0x00; + +void attachPinChangeInterrupt(void) { + // update the old state to the actual state + oldPort = PCPIN; + + // pin change mask registers decide which pins are enabled as triggers + PCMSK |= (1 << PCINT); + + // PCICR: Pin Change Interrupt Control Register - enables interrupt vectors + PCICR |= (1 << PCIE); +} + +void detachPinChangeInterrupt(void) { + // disable the mask. + PCMSK &= ~(1 << PCINT); + + // if that's the last one, disable the interrupt. + if (PCMSK == 0) + PCICR &= ~(0x01 << PCIE); +} + +ISR(PCINT_vect) { + // get the new and old pin states for port + uint8_t newPort = PCPIN; + + // compare with the old value to detect a rising or falling + uint8_t change = newPort ^ oldPort; + + // check which pins are triggered, compared with the settings + uint8_t trigger = 0x00; +#if (PCINT_MODE == RISING) || (PCINT_MODE == CHANGE) + uint8_t rising = change & newPort; + trigger |= (rising & (1 << PCINT)); +#endif +#if (PCINT_MODE == FALLING) || (PCINT_MODE == CHANGE) + uint8_t falling = change & oldPort; + trigger |= (falling & (1 << PCINT)); +#endif + + // save the new state for next comparison + oldPort = newPort; + + // if our needed pin has changed, call the IRL interrupt function + if (trigger & (1 << PCINT)) + PCINT_FUNCTION(); +} diff --git a/examples/PinChangeInterrupt_Led/PinChangeInterrupt_Led.ino b/examples/PinChangeInterrupt_Led/PinChangeInterrupt_Led.ino index 574156e..6a34532 100644 --- a/examples/PinChangeInterrupt_Led/PinChangeInterrupt_Led.ino +++ b/examples/PinChangeInterrupt_Led/PinChangeInterrupt_Led.ino @@ -1,48 +1,49 @@ -/* -Copyright (c) 2014-2015 NicoHood -See the readme for credit to other people. - -PinChangeInterrupt_TickTock -Demonstrates how to use the library - -Connect a button/cable to pin 7 and ground. -The Led state will change if the pin state does. - -PinChangeInterrupts are different than normal Interrupts. -See readme for more information. -Dont use Serial or delay inside interrupts! -This library is not compatible with SoftSerial. - -The following pins are usable for PinChangeInterrupt: -Arduino Uno/Nano/Mini: All pins are usable -Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), - A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) -Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) -HoodLoader2: All (broken out 1-7) pins are usable -Attiny 24/44/84: All pins are usable -Attiny 25/45/85: All pins are usable -ATmega644P/ATmega1284P: All pins are usable -*/ - -#include "PinChangeInterrupt.h" - -// choose a valid PinChangeInterrupt pin of your Arduino board -#define pinBlink 7 - -void setup() { - // set pin to input with a pullup, led to output - pinMode(pinBlink, INPUT_PULLUP); - pinMode(LED_BUILTIN, OUTPUT); - - // attach the new PinChangeInterrupt and enable event function below - attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE); -} - -void blinkLed(void) { - // switch Led state - digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); -} - -void loop() { - // nothing to do here -} +/* +Copyright (c) 2014-2015 NicoHood +See the readme for credit to other people. + +PinChangeInterrupt_TickTock +Demonstrates how to use the library + +Connect a button/cable to pin 7 and ground. +The Led state will change if the pin state does. + +PinChangeInterrupts are different than normal Interrupts. +See readme for more information. +Dont use Serial or delay inside interrupts! +This library is not compatible with SoftSerial. + +The following pins are usable for PinChangeInterrupt: +Arduino Uno/Nano/Mini: All pins are usable +Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), + A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) +Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) +HoodLoader2: All (broken out 1-7) pins are usable +Attiny 24/44/84: All pins are usable +Attiny 25/45/85: All pins are usable +Attiny 13: All pins are usable +ATmega644P/ATmega1284P: All pins are usable +*/ + +#include "PinChangeInterrupt.h" + +// choose a valid PinChangeInterrupt pin of your Arduino board +#define pinBlink 7 + +void setup() { + // set pin to input with a pullup, led to output + pinMode(pinBlink, INPUT_PULLUP); + pinMode(LED_BUILTIN, OUTPUT); + + // attach the new PinChangeInterrupt and enable event function below + attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE); +} + +void blinkLed(void) { + // switch Led state + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); +} + +void loop() { + // nothing to do here +} diff --git a/examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino b/examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino index ecc2abe..1c508a3 100644 --- a/examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino +++ b/examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino @@ -1,58 +1,59 @@ -/* - Copyright (c) 2014-2015 NicoHood - See the readme for credit to other people. - - PinChangeInterrupt_LowLevel - Demonstrates how to use the library without the API - - Make sure to comment "//#define PCINT_API" in the settings file. - - To maximize speed and size also uncomment all not used pins above. - Then you could also uncomment "#define PCINT_COMPILE_ENABLED_ISR" - to get away if the .a linkage overhead. - - Connect a button/cable to pin 7 and ground (Uno). - Strong overwritten callback functions are called when an interrupt occurs. - The Led state will change if the pin state does. - - PinChangeInterrupts are different than normal Interrupts. - See readme for more information. - Dont use Serial or delay inside interrupts! - This library is not compatible with SoftSerial. - - The following pins are usable for PinChangeInterrupt: - Arduino Uno/Nano/Mini: All pins are usable - Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), - A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) - Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) - HoodLoader2: All (broken out 1-7) pins are usable - Attiny 24/44/84: All pins are usable - Attiny 25/45/85: All pins are usable - ATmega644P/ATmega1284P: All pins are usable - */ - -#include "PinChangeInterrupt.h" - -// choose a valid PinChangeInterrupt pin of your Arduino board -// manually defined pcint number -#define pinBlink 7 -#define interruptBlink 23 - -void setup() -{ - // set pin to input with a pullup, led to output - pinMode(pinBlink, INPUT_PULLUP); - pinMode(LED_BUILTIN, OUTPUT); - - // attach the new PinChangeInterrupts and enable event functions below - attachPinChangeInterrupt(interruptBlink, CHANGE); -} - -void PinChangeInterruptEvent(interruptBlink)(void) { - // switch Led state - digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); -} - -void loop() { - // nothing to do here -} +/* + Copyright (c) 2014-2015 NicoHood + See the readme for credit to other people. + + PinChangeInterrupt_LowLevel + Demonstrates how to use the library without the API + + Make sure to comment "//#define PCINT_API" in the settings file. + + To maximize speed and size also uncomment all not used pins above. + Then you could also uncomment "#define PCINT_COMPILE_ENABLED_ISR" + to get away the .a linkage overhead. + + Connect a button/cable to pin 7 and ground (Uno). + Strong overwritten callback functions are called when an interrupt occurs. + The Led state will change if the pin state does. + + PinChangeInterrupts are different than normal Interrupts. + See readme for more information. + Dont use Serial or delay inside interrupts! + This library is not compatible with SoftSerial. + + The following pins are usable for PinChangeInterrupt: + Arduino Uno/Nano/Mini: All pins are usable + Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), + A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) + Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) + HoodLoader2: All (broken out 1-7) pins are usable + Attiny 24/44/84: All pins are usable + Attiny 25/45/85: All pins are usable + Attiny 13: All pins are usable + ATmega644P/ATmega1284P: All pins are usable + */ + +#include "PinChangeInterrupt.h" + +// choose a valid PinChangeInterrupt pin of your Arduino board +// manually defined pcint number +#define pinBlink 7 +#define interruptBlink 23 + +void setup() +{ + // set pin to input with a pullup, led to output + pinMode(pinBlink, INPUT_PULLUP); + pinMode(LED_BUILTIN, OUTPUT); + + // attach the new PinChangeInterrupts and enable event functions below + attachPinChangeInterrupt(interruptBlink, CHANGE); +} + +void PinChangeInterruptEvent(interruptBlink)(void) { + // switch Led state + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); +} + +void loop() { + // nothing to do here +} diff --git a/examples/PinChangeInterrupt_TickTock/PinChangeInterrupt_TickTock.ino b/examples/PinChangeInterrupt_TickTock/PinChangeInterrupt_TickTock.ino index bbff6ae..126151b 100644 --- a/examples/PinChangeInterrupt_TickTock/PinChangeInterrupt_TickTock.ino +++ b/examples/PinChangeInterrupt_TickTock/PinChangeInterrupt_TickTock.ino @@ -1,78 +1,97 @@ -/* - Copyright (c) 2014-2015 NicoHood - See the readme for credit to other people. - - PinChangeInterrupt_TickTock - Demonstrates how to use the library - - Connect a button/cable to pin 10/11 and ground. - The value printed on the serial port will increase - if pin 10 is rising and decrease if pin 11 is falling. - - PinChangeInterrupts are different than normal Interrupts. - See readme for more information. - Dont use Serial or delay inside interrupts! - This library is not compatible with SoftSerial. - - The following pins are usable for PinChangeInterrupt: - Arduino Uno/Nano/Mini: All pins are usable - Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), - A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) - Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) - HoodLoader2: All (broken out 1-7) pins are usable - Attiny 24/44/84: All pins are usable - Attiny 25/45/85: All pins are usable - ATmega644P/ATmega1284P: All pins are usable - */ - -#include "PinChangeInterrupt.h" - -// choose a valid PinChangeInterrupt pin of your Arduino board -#define pinTick 10 -#define pinTock 11 - -volatile long ticktocks = 0; - -void setup() -{ - // start serial debug output - Serial.begin(115200); - Serial.println(F("Startup")); - - // set pins to input with a pullup - pinMode(pinTick, INPUT_PULLUP); - pinMode(pinTock, INPUT_PULLUP); - - // attach the new PinChangeInterrupts and enable event functions below - attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick), tick, RISING); - attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock), tock, FALLING); -} - -void loop() { - // integer to count the number of prints - static int i = 0; - delay(1000); - - // print values - Serial.print(i, DEC); - Serial.print(F(" ")); - Serial.println(ticktocks); - - // abort if we printed 100 times - if (i >= 100) { - detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); - detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); - } - else - i++; -} - -void tick(void) { - // increase value - ticktocks++; -} - -void tock(void) { - // decrease value - ticktocks--; -} \ No newline at end of file +/* + Copyright (c) 2014-2015 NicoHood + See the readme for credit to other people. + + PinChangeInterrupt_TickTock + Demonstrates how to use the library + + Connect a button/cable to pin 10/11 and ground. + The value printed on the serial port will increase + if pin 10 is rising and decrease if pin 11 is falling. + + PinChangeInterrupts are different than normal Interrupts. + See readme for more information. + Dont use Serial or delay inside interrupts! + This library is not compatible with SoftSerial. + + The following pins are usable for PinChangeInterrupt: + Arduino Uno/Nano/Mini: All pins are usable + Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), + A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) + Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) + HoodLoader2: All (broken out 1-7) pins are usable + Attiny 24/44/84: All pins are usable + Attiny 25/45/85: All pins are usable + Attiny 13: All pins are usable + ATmega644P/ATmega1284P: All pins are usable +*/ + +#include "PinChangeInterrupt.h" + +// choose a valid PinChangeInterrupt pin of your Arduino board +#define pinTick 10 +#define pinTock 11 + +volatile long ticktocks = 0; + +void setup() +{ + // start serial debug output + Serial.begin(115200); + Serial.println(F("Startup")); + + // set pins to input with a pullup + pinMode(pinTick, INPUT_PULLUP); + pinMode(pinTock, INPUT_PULLUP); + + // attach the new PinChangeInterrupts and enable event functions below + attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick), tick, RISING); + attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock), tock, FALLING); +} + +void loop() { + // integer to count the number of prints + static int i = 0; + delay(1000); + + // print values + Serial.print(i, DEC); + Serial.print(F(" ")); + Serial.println(ticktocks); + + // abort if we printed 100 times + if (i >= 100) { + Serial.println(F("Detaching Interrupts.")); + detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); + detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); + return; + } + else + i++; + + // Temporary pause interrupts + if (ticktocks > 500) { + Serial.println(F("Disabling Tick Interrupt.")); + disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); + enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); + } + else if (ticktocks < -500) { + Serial.println(F("Disabling Tock Interrupt.")); + disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); + enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); + } + else { + enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); + enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock)); + } +} + +void tick(void) { + // increase value + ticktocks++; +} + +void tock(void) { + // decrease value + ticktocks--; +} diff --git a/library.properties b/library.properties index f0ac21c..b2880fe 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=PinChangeInterrupt -version=1.2.1 +version=1.2.2 author=NicoHood maintainer=NicoHood sentence=A simple & compact PinChangeInterrupt library for Arduino. @@ -7,3 +7,4 @@ paragraph=PinChangeInterrupt library with a resource friendly implementation (AP category=Signal Input/Output url=https://github.com/NicoHood/PinChangeInterrupt architectures=avr +dot_a_linkage=true diff --git a/src/PinChangeInterrupt.cpp b/src/PinChangeInterrupt.cpp index d57e5a1..44ce0fe 100644 --- a/src/PinChangeInterrupt.cpp +++ b/src/PinChangeInterrupt.cpp @@ -96,21 +96,32 @@ uint8_t oldPorts[PCINT_NUM_USED_PORTS] = { 0 }; uint8_t fallingPorts[PCINT_NUM_USED_PORTS] = { 0 }; uint8_t risingPorts[PCINT_NUM_USED_PORTS] = { 0 }; -void attachPinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintBit, const uint8_t mode) { - // get bitmask and array position - uint8_t pcintMask = (1 << pcintBit); - uint8_t arrayPos = getArrayPosPCINT(pcintPort); - - // save settings related to mode and registers - if (mode == CHANGE || mode == RISING) - risingPorts[arrayPos] |= pcintMask; - if (mode == CHANGE || mode == FALLING) - fallingPorts[arrayPos] |= pcintMask; - - // update the old state to the actual state - oldPorts[arrayPos] = *portInputRegister(pcintPort); +void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos){ + // Update the old state to the actual state + switch(pcintPort){ +#ifdef PCINT_INPUT_PORT0_USED + case 0: + oldPorts[arrayPos] = PCINT_INPUT_PORT0; + break; +#endif +#ifdef PCINT_INPUT_PORT1_USED + case 1: + oldPorts[arrayPos] = PCINT_INPUT_PORT1; + break; +#endif +#ifdef PCINT_INPUT_PORT2_USED + case 2: + oldPorts[arrayPos] = PCINT_INPUT_PORT2; + break; +#endif +#ifdef PCINT_INPUT_PORT3_USED + case 3: + oldPorts[arrayPos] = PCINT_INPUT_PORT3; + break; +#endif + } - // pin change mask registers decide which pins are ENABLE as triggers + // Pin change mask registers decide which pins are ENABLE as triggers #ifdef PCMSK0 *(&PCMSK0 + pcintPort) |= pcintMask; #elif defined(PCMSK) @@ -129,15 +140,7 @@ void attachPinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcint #endif } -void detachPinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintBit) { - // get bitmask and array position - uint8_t pcintMask = (1 << pcintBit); - uint8_t arrayPos = getArrayPosPCINT(pcintPort); - - // delete setting - risingPorts[arrayPos] &= ~pcintMask; - fallingPorts[arrayPos] &= ~pcintMask; - +void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask) { #ifdef PCMSK0 // disable the mask. *(&PCMSK0 + pcintPort) &= ~pcintMask; diff --git a/src/PinChangeInterrupt.h b/src/PinChangeInterrupt.h index efaf245..e3bb770 100644 --- a/src/PinChangeInterrupt.h +++ b/src/PinChangeInterrupt.h @@ -25,11 +25,11 @@ THE SOFTWARE. #pragma once // software version -#define PCINT_VERSION 121 +#define PCINT_VERSION 122 #include "Arduino.h" -#ifdef ARDUINO_ARCH_ARM +#ifndef ARDUINO_ARCH_AVR #error This library can only be used with AVR #endif @@ -86,9 +86,7 @@ PinChangeInterruptEventPCINT ## pcint PCINT_MACRO_BRACKETS #define attachPCINT attachPinChangeInterrupt #define enablePCINT enablePinChangeInterrupt #define detachPCINT detachPinChangeInterrupt -// detach does not delete the function, so we can use this for detaching as well -#define disablePCINT detachPinChangeInterrupt -#define disablePinChangeInterrupt detachPinChangeInterrupt +#define disablePCINT disablePinChangeInterrupt #define getPCINTTrigger getPinChangeInterruptTrigger //================================================================================ @@ -141,8 +139,8 @@ extern uint8_t fallingPorts[PCINT_NUM_USED_PORTS]; extern uint8_t risingPorts[PCINT_NUM_USED_PORTS]; -static inline uint8_t getArrayPosPCINT(uint8_t pcintPort)__attribute__((alway_inline)); -static inline uint8_t getArrayPosPCINT(uint8_t pcintPort) { +static inline uint8_t getArrayPosPCINT(uint8_t pcintPort) __attribute__((always_inline)); +uint8_t getArrayPosPCINT(uint8_t pcintPort) { /* Maps the port to the array. This is needed since you can deactivate ports @@ -244,7 +242,7 @@ static inline uint8_t getArrayPosPCINT(uint8_t pcintPort) { // Attach Function (partly inlined) //================================================================================ -void attachPinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintBit, const uint8_t mode); +void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos); void attachPinChangeInterrupt0(void); void attachPinChangeInterrupt1(void); void attachPinChangeInterrupt2(void); @@ -376,10 +374,10 @@ Serial.println("#endif"); */ // API attach function -static void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) __attribute__((always_inline)); +static inline void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) __attribute__((always_inline)); void attachPinChangeInterrupt(const uint8_t pcintNum, void(*userFunc)(void), const uint8_t mode) { #else // no API attach function -static void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) __attribute__((always_inline)); +static inline void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) __attribute__((always_inline)); void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) { #endif // PCINT_API @@ -562,13 +560,23 @@ void attachPinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) { } else return; + // get bitmask and array position + uint8_t pcintMask = (1 << pcintBit); + uint8_t arrayPos = getArrayPosPCINT(pcintPort); + + // save settings related to mode and registers + if (mode == CHANGE || mode == RISING) + risingPorts[arrayPos] |= pcintMask; + if (mode == CHANGE || mode == FALLING) + fallingPorts[arrayPos] |= pcintMask; + // call the actual hardware attach function - attachPinChangeInterruptHelper(pcintPort, pcintBit, mode); + enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos); } // enable interrupt again if temporary disabled -static void enablePinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) __attribute__((always_inline)); -void enablePinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) { +static inline void enablePinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline)); +void enablePinChangeInterrupt(const uint8_t pcintNum) { // get PCINT registers uint8_t pcintPort = pcintNum / 8; uint8_t pcintBit = pcintNum % 8; @@ -593,7 +601,9 @@ void enablePinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) { else return; // call the actual hardware attach function - attachPinChangeInterruptHelper(pcintPort, pcintBit, mode); + uint8_t pcintMask = (1 << pcintBit); + uint8_t arrayPos = getArrayPosPCINT(pcintPort); + enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos); } @@ -601,14 +611,190 @@ void enablePinChangeInterrupt(const uint8_t pcintNum, const uint8_t mode) { // Detach Function (partly inlined) //================================================================================ -void detachPinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintBit); -static void detachPinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline)); +void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask); +static inline void detachPinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline)); void detachPinChangeInterrupt(const uint8_t pcintNum) { // get PCINT registers uint8_t pcintPort = pcintNum / 8; uint8_t pcintBit = pcintNum % 8; + // check if pcint is a valid pcint, exclude deactivated ports + // port 0 + if (pcintPort == 0 && PCINT_USE_PORT0 == true) { + // attache the function pointers for the API +#if defined(PCINT_API) +#if (PCINT_USE_PCINT0 == true) + if (pcintNum == 0) + callbackPCINT0 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT1 == true) + if (pcintNum == 1) + callbackPCINT1 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT2 == true) + if (pcintNum == 2) + callbackPCINT2 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT3 == true) + if (pcintNum == 3) + callbackPCINT3 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT4 == true) + if (pcintNum == 4) + callbackPCINT4 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT5 == true) + if (pcintNum == 5) + callbackPCINT5 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT6 == true) + if (pcintNum == 6) + callbackPCINT6 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT7 == true) + if (pcintNum == 7) + callbackPCINT7 = pcint_null_callback; +#endif +#endif // PCINT_API + } + + // port 1 + else if (pcintPort == 1 && PCINT_USE_PORT1 == true) { + // attache the function pointers for the API +#if defined(PCINT_API) +#if (PCINT_USE_PCINT8 == true) + if (pcintNum == 8) + callbackPCINT8 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT9 == true) + if (pcintNum == 9) + callbackPCINT9 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT10 == true) + if (pcintNum == 10) + callbackPCINT10 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT11 == true) + if (pcintNum == 11) + callbackPCINT11 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT12 == true) + if (pcintNum == 12) + callbackPCINT12 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT13 == true) + if (pcintNum == 13) + callbackPCINT13 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT14 == true) + if (pcintNum == 14) + callbackPCINT14 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT15 == true) + if (pcintNum == 15) + callbackPCINT15 = pcint_null_callback; +#endif +#endif // PCINT_API + } + + // port 2 + else if (pcintPort == 2 && PCINT_USE_PORT2 == true) { + // attache the function pointers for the API +#if defined(PCINT_API) +#if (PCINT_USE_PCINT16 == true) + if (pcintNum == 16) + callbackPCINT16 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT17 == true) + if (pcintNum == 17) + callbackPCINT17 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT18 == true) + if (pcintNum == 18) + callbackPCINT18 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT19 == true) + if (pcintNum == 19) + callbackPCINT19 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT20 == true) + if (pcintNum == 20) + callbackPCINT20 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT21 == true) + if (pcintNum == 21) + callbackPCINT21 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT22 == true) + if (pcintNum == 22) + callbackPCINT22 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT23 == true) + if (pcintNum == 23) + callbackPCINT23 = pcint_null_callback; +#endif +#endif // PCINT_API + } + + // port 3 + else if (pcintPort == 3 && PCINT_USE_PORT3 == true) { + // attache the function pointers for the API +#if defined(PCINT_API) +#if (PCINT_USE_PCINT24 == true) + if (pcintNum == 24) + callbackPCINT24 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT25 == true) + if (pcintNum == 25) + callbackPCINT25 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT26 == true) + if (pcintNum == 26) + callbackPCINT26 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT27 == true) + if (pcintNum == 27) + callbackPCINT27 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT28 == true) + if (pcintNum == 28) + callbackPCINT28 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT29 == true) + if (pcintNum == 29) + callbackPCINT29 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT30 == true) + if (pcintNum == 30) + callbackPCINT30 = pcint_null_callback; +#endif +#if (PCINT_USE_PCINT31 == true) + if (pcintNum == 31) + callbackPCINT31 = pcint_null_callback; +#endif +#endif // PCINT_API + } + else return; + + // get bitmask and array position + uint8_t pcintMask = (1 << pcintBit); + uint8_t arrayPos = getArrayPosPCINT(pcintPort); + + // delete setting + risingPorts[arrayPos] &= ~pcintMask; + fallingPorts[arrayPos] &= ~pcintMask; + + // call the actual hardware disable function + disablePinChangeInterruptHelper(pcintPort, pcintMask); +} + +static inline void disablePinChangeInterrupt(const uint8_t pcintNum) __attribute__((always_inline)); +void disablePinChangeInterrupt(const uint8_t pcintNum) { + // get PCINT registers + uint8_t pcintPort = pcintNum / 8; + uint8_t pcintBit = pcintNum % 8; + // check if pcint is a valid pcint, exclude deactivated ports if (pcintPort == 0) { if (PCINT_USE_PORT0 == false) @@ -628,16 +814,21 @@ void detachPinChangeInterrupt(const uint8_t pcintNum) { } else return; - // call the actual hardware detach function - detachPinChangeInterruptHelper(pcintPort, pcintBit); -} + // get bitmask + uint8_t pcintMask = (1 << pcintBit); + // Do not delete mode settings nor detach the user function + // Just turn off interrupts + + // call the actual hardware disable function + disablePinChangeInterruptHelper(pcintPort, pcintMask); +} //================================================================================ // getTrigger Function (inlined) //================================================================================ -static uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) __attribute__((always_inline)); +static inline uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) __attribute__((always_inline)); uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) { // get PCINT registers uint8_t pcintPort = pcintNum / 8; @@ -664,9 +855,13 @@ uint8_t getPinChangeInterruptTrigger(const uint8_t pcintNum) { uint8_t arrayPos = getArrayPosPCINT(pcintPort); + // Check if no mode was set, return an error + if(!(risingPorts[arrayPos] & (1 << pcintBit)) && !(fallingPorts[arrayPos] & (1 << pcintBit))) + return CHANGE; + // specify the CHANGE mode if (oldPorts[arrayPos] & (1 << pcintBit)) return RISING; else return FALLING; -} \ No newline at end of file +} diff --git a/src/PinChangeInterrupt0.cpp b/src/PinChangeInterrupt0.cpp index 8076c3b..c8dfba8 100644 --- a/src/PinChangeInterrupt0.cpp +++ b/src/PinChangeInterrupt0.cpp @@ -146,4 +146,4 @@ void PinChangeInterruptEventPCINT7(void) { #endif // PCINT_USE_PORT0 -#endif // PCINT_INCLUDE_FROM_CPP \ No newline at end of file +#endif // PCINT_INCLUDE_FROM_CPP diff --git a/src/PinChangeInterrupt1.cpp b/src/PinChangeInterrupt1.cpp index e30d928..e9953cd 100644 --- a/src/PinChangeInterrupt1.cpp +++ b/src/PinChangeInterrupt1.cpp @@ -146,4 +146,4 @@ void PinChangeInterruptEventPCINT15(void) { #endif // PCINT_USE_PORT1 -#endif // PCINT_INCLUDE_FROM_CPP \ No newline at end of file +#endif // PCINT_INCLUDE_FROM_CPP diff --git a/src/PinChangeInterruptBoards.h b/src/PinChangeInterruptBoards.h index 3fefc9c..2b98227 100644 --- a/src/PinChangeInterruptBoards.h +++ b/src/PinChangeInterruptBoards.h @@ -74,6 +74,13 @@ THE SOFTWARE. // Attiny x5 #define PCINT_INPUT_PORT0 PINB +#elif defined(__AVR_ATtiny13__) +// Attiny 13A +#define PCINT_INPUT_PORT0 PINB +#ifndef portInputRegister +#define portInputRegister(P) ( (volatile uint8_t *)(PINB) ) +#endif + #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) // Attiny x4 #define PCINT_INPUT_PORT0 PINA @@ -97,13 +104,21 @@ THE SOFTWARE. // add fakes if ports are not used #ifndef PCINT_INPUT_PORT0 #define PCINT_INPUT_PORT0 0 +#else +#define PCINT_INPUT_PORT0_USED #endif #ifndef PCINT_INPUT_PORT1 #define PCINT_INPUT_PORT1 0 +#else +#define PCINT_INPUT_PORT1_USED #endif #ifndef PCINT_INPUT_PORT2 #define PCINT_INPUT_PORT2 0 +#else +#define PCINT_INPUT_PORT2_USED #endif #ifndef PCINT_INPUT_PORT3 #define PCINT_INPUT_PORT3 0 +#else +#define PCINT_INPUT_PORT3_USED #endif diff --git a/src/PinChangeInterruptPins.h b/src/PinChangeInterruptPins.h index 5c08925..54b2683 100644 --- a/src/PinChangeInterruptPins.h +++ b/src/PinChangeInterruptPins.h @@ -746,4 +746,4 @@ PCINT_NUM_USED_PINS_PORT3) PCINT_USE_PORT0 + \ PCINT_USE_PORT1 + \ PCINT_USE_PORT2 + \ -PCINT_USE_PORT3) \ No newline at end of file +PCINT_USE_PORT3) diff --git a/src/PinChangeInterruptSettings.h b/src/PinChangeInterruptSettings.h index 828d0e5..190c9d2 100644 --- a/src/PinChangeInterruptSettings.h +++ b/src/PinChangeInterruptSettings.h @@ -220,4 +220,4 @@ The order is also okay. */ #if defined(PCINT_ENABLE_PCINT1) #undef PCINT_ENABLE_PCINT1 #endif -#endif \ No newline at end of file +#endif