Git Product home page Git Product logo

pinchangeinterrupt's Introduction

PinChangeInterrupt Library 1.2.9

Header Picture

PinChangeInterrupt library with a resource friendly implementation (API and LowLevel). PinChangeInterrupts are different than normal Interrupts. See detail below.

Features:
  • PinChangeInterrupt for a lot of pins
  • Rising, Falling or Change detection for every pin separately
  • Usable on a lot Arduino compatible boards
  • Implementation is fast, compact and resource friendly
  • Ports/Pins can be manually deactivated in the Settings file
  • API and LowLevel option
  • Full Port0-3 support
  • .a linkage optimization (Arduino IDE)

Buy Me A Coffee

Supported pins for PinChangeInterrupt:

See PCINT pin table at the bottom for more details.

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
Attiny24/44/84: All pins are usable
Attiny25/45/85: All pins are usable
Attiny13: All pins are usable
Attiny441/841: All pins are usable
Attiny261/461/861: All pins are usable
Attiny2313/2313A/4313: PORTB is usable
ATmega644/ATmega644P/ATmega1284P: All pins are usable
ATmega162: PORTA and PORTC usable
ATmega48/88/168/328/328PB: All pins are usable

Contact information can be found here:

www.nicohood.de

Installation

Download the zip, extract and remove the "-master" of the folder. Install the library as described here.

This library can also be used with the DMBS AVR Library Collection and a pure makefile.

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 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 it is still unclear what pin of the port caused this interrupt. Therefore this library saves the state of the whole port and compares with the last state. This way we can also see if it was a RISING or FALLING edge instead of only knowing the CHANGE.

A PinChangeInterrupt will only be triggered for the attached pins per port. Meaning if you set PCINT for a pin and another pin on the same port is changing a lot it will not interrupt your code.

PinChangeInterrupts might be a tiny bit slower and not that reliable because of that detection overhead (talking about micro seconds). Make sure to not use longer function calls inside the ISR or Serial print. You have the same issues on normal PinInterrupts and interrupts in general.

The library is coded to get maximum speed and minimum code size. The LowLevel example without the API takes 4uS to enter the interrupt function in the worst case which is pretty good and might be even better than the PinInterrupt code from the official Arduino core due to high optimization. If you need very precise interrupts you better use PinInterrupts without the Arduino IDE at all.

Examples

To see how the code works just check the Led and TickTock example. The LowLevel example is for advanced users with more optimization and more direct access. The HowItWorks example shows the basic PinChangeInterrupt setup and decoding routine, similar to the library. See the notes in the examples about more details.

An useful "real use" example of the PinChangeInterrupt library can be found here: https://github.com/NicoHood/IRLremote

API Reference

Attach a PinChangeInterrupt
// 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
// Similar usage as the attachPCINT function.
// Interrupts will no longer occur.
detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
detachPinChangeInterrupt(5);
detachPCINT(digitalPinToPCINT(pinTock));
Enable/Disable a PinChangeInterrupt
// 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
// 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 for more details.

// 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

Pins with * are not broken out/deactivated by default. You may activate them in the setting file (advanced).

Each row section represents a port(0-3). Not all MCUs have all Ports/Pins physically available.

Note: Not all supported AVRs are listed here. There are way more supported, please refer to the shorter list above.

Official Arduinos

| PCINT |  Uno/Nano/Mini  |   Mega/2560    | Leonardo/Micro | HL2 (8/16/32u2) |
| ----- | --------------- | -------------- | -------------- | --------------- |
|     0 |  8       (PB0)  | 53 SS   (PB0)  |    SS   (PB0)* |  0 SS   (PB0)*  |
|     1 |  9       (PB1)  | 52 SCK  (PB1)  |    SCK  (PB1)  |  1 SCK  (PB1)   |
|     2 | 10 SS    (PB2)  | 51 MOSI (PB2)  |    MOSI (PB2)  |  2 MOSI (PB2)   |
|     3 | 11 MISO  (PB3)  | 50 MISO (PB3)  |    MISO (PB3)  |  3 MISO (PB3)   |
|     4 | 12 MOSI  (PB4)  | 10      (PB4)  |  8/A8   (PB4)  |  4      (PB4)   |
|     5 | 13 SCK   (PB5)  | 11      (PB5)  |  9/A9   (PB5)  |  5      (PB5)   |
|     6 |    XTAL1 (PB6)* | 12      (PB6)  | 10/A10  (PB6)  |  6      (PB6)   |
|     7 |    XTAL2 (PB7)* | 13      (PB7)  | 11      (PB7)  |  7      (PB7)   |
| ----- | --------------- | -------------- | -------------- | --------------- |
|     8 | A0       (PC0)  |  0 RX   (PE0)* |                |         (PC6)*  |
|     9 | A1       (PC1)  | 15 RX3  (PJ0)* |                |         (PC5)*  |
|    10 | A2       (PC2)  | 14 TX3  (PJ1)* |                |         (PC4)*  |
|    11 | A3       (PC3)  |    NC   (PJ2)* |                |         (PC2)*  |
|    12 | A4 SDA   (PC4)  |    NC   (PJ3)* |                |         (PD5)*  |
|    13 | A5 SDC   (PC5)  |    NC   (PJ4)* |                |                 |
|    14 |    RST   (PC6)* |    NC   (PJ5)* |                |                 |
|    15 |                 |    NC   (PJ6)* |                |                 |
| ----- | --------------- | -------------- | -------------- | --------------- |
|    16 |  0 RX    (PD0)  | A8      (PK0)  |                |                 |
|    17 |  1 TX    (PD1)  | A9      (PK1)  |                |                 |
|    18 |  2 INT0  (PD2)  | A10     (PK2)  |                |                 |
|    19 |  3 INT1  (PD3)  | A11     (PK3)  |                |                 |
|    20 |  4       (PD4)  | A12     (PK4)  |                |                 |
|    21 |  5       (PD5)  | A13     (PK5)  |                |                 |
|    22 |  6       (PD6)  | A14     (PK6)  |                |                 |
|    23 |  7       (PD7)  | A15     (PK7)  |                |                 |
| ----- | --------------- | -------------- | -------------- | --------------- |

Atmel Attinys

| PCINT |   Attiny13   |    Attiny x4    |   Attiny x5   |     Attiny x41      |
| ----- | ------------ | --------------- | ------------- | ------------------- |
|     0 | 0 MOSI (PB0) |  0       (PA0)  | 0 MOSI  (PB0) | A0/D0         (PA0) |
|     1 | 1 MISO (PB1) |  1       (PA1)  | 1 MISO  (PB1) | A1/D1         (PA1) |
|     2 | 2 SCK  (PB2) |  2       (PA2)  | 2 SCK   (PB2) | A2/D2         (PA2) |
|     3 | 3      (PB3) |  3       (PA3)  | 3 XTAL1 (PB3) | A3/D3         (PA3) |
|     4 | 4      (PB4) |  4 SCK   (PA4)  | 4 XTAL2 (PB4) | A4/D4         (PA4) |
|     5 | 5 RST  (PB5) |  5 MISO  (PA5)  | 5 RST   (PB5) | A5/D5   PWM   (PA5) |
|     6 |              |  6 MOSI  (PA6)  |               | A7/D7   PWM   (PA6) |
|     7 |              |  7       (PA7)  |               | A6/D6   PWM   (PA7) |
| ----- | ------------ | --------------- | ------------- | ------------------- |
|     8 |              | 10 XTAL1 (PB0)* |               | A10/D10 XTAL1 (PB0) |
|     9 |              |  9 XTAL2 (PB1)* |               | A9/D9   XTAL2 (PB1) |
|    10 |              |  8 INT0  (PB2)* |               | A8/D8   PWM   (PB2) |
|    11 |              |    RST   (PB3)* |               |         RST   (PB3) |
|    12 |              |                 |               |                     |
|    13 |              |                 |               |                     |
|    14 |              |                 |               |                     |
|    15 |              |                 |               |                     |
| ----- | ------------ | --------------- | ------------- | ------------------- |

Other Atmel MCUs

| PCINT | ATmega644P/1284P  |
| ----- | ----------------- |
|     0 | A0/D24      (PA0) |
|     1 | A1/D25      (PA1) |
|     2 | A2/D26      (PA2) |
|     3 | A3/D27      (PA3) |
|     4 | A4/D28      (PA4) |
|     5 | A5/D29      (PA5) |
|     6 | A6/D30      (PA6) |
|     7 | A7/D31      (PA7) |
| ----- | ----------------- |
|     8 |  0          (PB0) |
|     9 |  1          (PB1) |
|    10 |  2 INT2     (PB2) |
|    11 |  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

If a PinChangeInterrupt occurs it will determine the triggered pin(s). The library uses weak callback functions that are called for the triggered pins(s). This way we can easily skip not triggered pins (I looked at the assembler) and also implement a fast LowLevel version.

Also the order of the function execution is (normally) ordered from the lower pin number to the higher. Meaning pin 8 will be checked faster as pin 13 (Arduino Uno). Talking about micro seconds here! You can change the order in the settings. For example by default pin 0-3 have a low priority order than pin 4-7 (Arduino Uno). Because they are used for Serial and normal PinInterrupts. I don't expect anyone to use those pins at all with PCINT but at least the priority is lowered compared to the other pins.

The API takes those weak functions and just overwrites all of them and call the function pointers of the attached functions instead. This way the function can be changed at runtime and its also easier to integrate into other libraries. The function pointers take a bit flash though (LowLevel: 1526/18, API: 1790/58 for Led example).

You can get better performance and less code size if you deactivate the not used pins/ports manually in the settings file. This way only the needed pins get compiled and the code is optimized by the preprocessor. For a bit more comfortable/automatic optimization you can install the library into the core to get use of the .a linkage. This way only the used ports get compiled. So if you only use pins on a single port (eg 8-13) then only this port gets compiled. This only works with the core installation.

That's it! I hope you like the library. I tried to make it as simple and small as possible. Keep in mind that PCINTs are not useful for every project but in most cases the new PinChangeInterrupts may help you a lot.

Version History

1.2.9 Release (18.05.2021)
* Added Attiny261/461/861 support #39
* Added Attiny2313/2313A/4313 support #37
* Added ATMega328PB support #30
* Added ATMega48 support #38
* Fixed ATMega88/168 support #38

1.2.8 Release (22.11.2020)
* Add support for ATmega644 #34

1.2.7 Release (07.10.2018)
* Add support for ATmega162 #21

1.2.6 Release (10.02.2018)
* Fix makefile compilation problems

1.2.5 Release (02.09.2017)
* Fixed makefile compilation
* Added support to disable pcint/port via -DPCINT_DISABLE_PORT0 etc.
* Added ATtinyX313 support
* Fix ATmega1284P

1.2.4 Release (16.04.2016)
* Fixed Attinyx4/x5 Issue #8

1.2.3 Release (24.12.2015)
* Added Attiny441/841 support

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
* Added getPinChangeInterruptTrigger() function
* Added to Arduino IDE library manager

1.2 Release (19.04.2015)
* Added weak interrupt function
* Improved interrupt function calls
* Fixed attach/detach array position when ports are deactivated
* Improved manual PCINT deactivation by user
* Improved definitions for different boards
* HoodLoader2 definition fixes
* Improved speed
* Improved specific boards
* Moved attach function to .cpp file
* Updated examples
* Added API and LowLevel
* Added Port3 support (ATmega644P/ATmega1284P)
* Added PCINT_VERSION definition

1.1 Release (06.12.2014)
* Added port deactivation
* Ram usage improvements for AVRs with <3 PCINT ports

1.0 Release (04.12.2014)
* Added general PinChangeInterrupt functions
* Added support for most Arduino boards
* Added basic example
* Added an example with IRLremote

pinchangeinterrupt's People

Contributors

bucienator avatar chbmuc avatar naggie avatar nicohood avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pinchangeinterrupt's Issues

Compile issue with attachPinChangeInterrupt3()

When trying to compile my project on MightyCore (ATMega1284P), I get this compile error:

PinChangeInterrupt3.cpp.o (symbol from plugin): In function `attachPinChangeInterrupt3()':
(.text+0x0): multiple definition of `__vector_7'
C:\Users\chris\AppData\Local\Temp\arduino_build_675222\libraries\SoftwareSerial\SoftwareSerial.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

PB6 and PB7

Hi

I'm using a 328P on a breadboard and i set PB6 and PB7 as a digital I/O pins. I tested with a led and they are working ok.
Now i want to use those pins with PinChangeInterrupt, but they don't respond to changes. I read that i need to enable those pins on PinChangeInterruptSettings.h, but i don't know how to do it.
Can you please help?

Thanks

disablePinChangeInterrupt(25) does not work on atmega328pb (PE1)

I found that calling mentioned function (either with direct PCINT number or with digitalPinToPCINT() macro) doesn't disable PCINT on that pin (PE1) on atmega328pb. I've tested two more inputs (PCINT0 and PCINT21) and both works good. I think it might be related to PORTE as it is specific only on PB variant.

Incompatible with I2C ?

Hello there,

is there any known incompatibilities with the Wire library ?
This is the project I am working on https://github.com/mistic100/my-aurora

I have 5 command buttons wired to pins D2 to D6 and using PinChangeInterrupt (setup here). Each ISR sends the message "Pressed buton XXX" to serial and do something else, this is working fine.

I just added an OLED display connected in I2C to pins A4 and A5 (this is using Adafruit SSD1306 lib over the Wire lib).
Since then when I press a button, I just get "Pr" in the serial monitor (only the first 2 chars), the corresponding action is not executed and the controller crashes (loop is not executed anymore).

Am I missing something ?


I also tried to only enable the necessary pins with manual definition but then it's not working at all (no serial output, no action), is this the right way to do it ?

#define PCINT_ENABLE_MANUAL
#define PCINT_ENABLE_PORT2
#define PCINT_ENABLE_PCINT18
#define PCINT_ENABLE_PCINT19
#define PCINT_ENABLE_PCINT20
#define PCINT_ENABLE_PCINT21
#define PCINT_ENABLE_PCINT22

#include <PinChangeInterrupt.h>

Question : When does PCIFx get cleared? (Pulse counting)

Working with a ATMega328

Looking at an 8 channel pulse counting app and for this question assume each pulse is at least 10ms long or greater

My concern is that with pulses originating from different sources being fed into pins on the same port some might be missed due to the sharing of PCIF flags as 1 per port bank.

I can mitigate this to a degree by using multiple ports and making use of the 2 dedicated INTx lines, even with this though the best setup I can obtain for 8 channels is 5 separate interrupts +3 PCINT overlaps

The scenario I'm concerned with is (for example) if PD4 and PD5 are both set for PCINT operation and PD4 has gone from low to high due to a pulse input, the system triggers an PCINT as a result. What happens if PD5 also goes from low to high a very short time later and whilst we're still dealing with the ISR for PD4? Is it lost due to the PCIF flag still being set for PD4?

As far as I can see from the timing diagram on page 79 of the datasheet PCIF flags are set interdependently of any gating other than the PCMSK setup (which as I understand it is the register responsible for enabling PCINT on that pin)

I'm reading this diagram as PCINT(0) is the activity of the actual pin and not a subsequent interrupt generation (which would change my understanding of the diagram)

Page 82 says
"When a logic change on any PCINT[x:x] pin triggers an interrupt request, PCIFx becomes set (one). If the Ibit
in SREG and the PCIEx bit in PCICR are set (one), the MCU will jump to the corresponding Interrupt Vector.
The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a
logical one to it
."

I don't follow what PCIEx register does, this isn't referenced on the timing diagram, or is that responsible for gating whether or not PCINT(x) is created?

If the system works such that any pin state change locks out generating PCIFx flags for other PCINT enabled pins on the same port until the current ISR is processed, after which the system will start looking at pin states again and generate any new ones, then in my example provided the pulse for PD5 is active for longer than the time it takes to complete the ISR for PD4 (very likely) and we'll not miss counting any pulses.

But I'm not sure that's how it works or not and I'm struggling to find more information on this.

If that's not the case then from your front page text I must assume that PCIF flags are generated regardless of whether we're dealing with ISRs or not so for the overlap pins pulses must appear at least 4 microseconds apart to avoid missing the new PCINT event (allowing PCIF to be cleared in-between)

In that situation I'm confused over when/where exactly the PCIFx flags are reset, is it at say line 40 of PinChangeInterrupt0.cpp or is it in the ISR that we setup for the individual pin?

As you can tell I'm finding this a real head-fit to understand so if you have some time I would greatly appreciate it if you can help with my appreciation of how this works.

Thank you in advance

Andrew.

Add Support For Arduino Nano RP2040 Connect

The 2040 has a lot more interrupt functionality built-in, which is handy, but I have a fairly large project already in place that uses this library on a "regular" Nano and would like to swap out to use a Nano RP2040 without a lot of code changes. It would be quite convenient if PinChangeInterrupt would continue to work when building for that target.

Thanks for the library, by the way! This has been a life saver for my own projects :-)

'PCICR' not declared for ATtiny44

I was trying to use this library with an ATtiny44, however I get:

PinChangeInterrupt.cpp: In function 'void attachPinChangeInterruptHelper(uint8_t, uint8_t, uint8_t)':
PinChangeInterrupt.cpp:117:2: error: 'PCICR' was not declared in this scope
PCICR |= (1 << pcintPort);
^
PinChangeInterrupt.cpp: In function 'void detachPinChangeInterruptHelper(uint8_t, uint8_t)':
PinChangeInterrupt.cpp:134:3: error: 'PCICR' was not declared in this scope
PCICR &= ~(1 << pcintPort);

I think this is because the ATtiny has no PCICR.

Add enable/disable Interrupt

It would be nice to keep the attached function, but disable it instead of removing the function and enable it again.

Not Compiling with SoftwareSerial

Hi there, I am using a PCINT on A1 (PCINT9 according to the table) on an Arduino Uno but this library doesn't compile with the SoftwareSerial library because it also uses interrupts. I get this error:

libraries\SoftwareSerial\SoftwareSerial.cpp.o: In function __vector_3':

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SoftwareSerial\src/SoftwareSerial.cpp:229: multiple definition of `__vector_4'

libraries\PinChangeInterrupt\PinChangeInterrupt.a(PinChangeInterrupt.cpp.o):C:\Users\Timothy Woo\Documents\Arduino\libraries\PinChangeInterrupt\src/PinChangeInterrupt1.cpp:40: first defined here

collect2.exe: error: ld returned 1 exit status`

How can I get rid of this error?

How to enable at least one PCINT port and pin

Hi Nico
I am stuck, I use your IRLremote library and have the signal attached at A0 PC0. Therefore I included <PinChangeInterrupt.h> before
<IRLremote.h> https://github.com/ArminJo/QuadrupedControl/blob/504561d053f1939da62ddb7e9c2d038050b99f22/src/IRCommandDispatcher.cpp.h#L72
The difference in code size between using pin 2 and pin A0 is now 500 bytes. How can I restrict your PinChangeInterrupt library to support only Pin PC0 aka A0.
Using

#define PCINT_ENABLE_PCINT8
#define PCINT_ENABLE_MANUAL

leads to #error Please enable at least one PCINT port and pin!
But I do not know how to enable at least one PCINT port and pin ๐Ÿ˜Ÿ
Why
using

#define PCINT_ENABLE_PCINT8
#define PCINT_ENABLE_PORT1
#define PCINT_ENABLE_MANUAL

gives no error (I feel the define PCINT_ENABLE_PORT1 is redundant) but also does not save one byte.

BTW: Whats about enabling discussions?

Activate pin on Attiny84

Hello,
I would like use pin PB2 on Attiny84 but I don't know how make.
You say :

You may activate them in the setting file (advanced).

But where is this file and how make ?
Thank you

Add Support for LGT8F328P

The LGT8F328P is a processor very similar to the ATMega328P. It is not a clone so it requires its own core. To support the PinChangeInterrupt library for the LGT8FxP family, please add the LGT8FxP to the supported platforms. This is easily done by adding the processor as LGT8FX8P in PinChangeInterrupt,Settings.h and PinChangeInterrupt.Boards.h like an ATmega328P.

multiple definition of `__vector_3'

Hi

I'm using your library to detect a change on PCINT=7 (xtal pin) and it is working.
Later i added neoSWSerial library to comunicate on pins D7 and D8, and i got this error when compiling.

multiple definition of `__vector_3'

In this related issue you say it is possible to have both libraries working, but i don't know where to modify.

Can you please help?

Attiny13a, MicroCore and PinChangeInterrupt problem.

Attiny13a, 9.6 Mhz
MicroCore 2.0.3
PinChangeInterrupt 1.2.9
Arduino IDE 1.8.15

Trying MicroCore 2.0.3 and the PinChangeInterrupt 1.2.9 library in connection with the Attiny13a, I ran into problems.

Of course, I might have overlooked something obvious as this it the first time I tried pin change interrupt
on an attiny13a.

No interrupts were caught.
After modifying and testing PinChangeInterrupt_HowItWorks.ino on the attiny13a, at first nothing happened.
In the attiny13a documentaion, page 47, it says:

When the PCIE bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin
change interrupt is enabled.

Skimming though the PinChangeInterrupt sources, I did not come across enabling of the pin change interrupt.

And no option to enable pin change interrupt in MicroCore core_settings.h

Adding a sei(); after the attachPCINT function(s), it finally worked.

#include "PinChangeInterrupt.h"

// Choose a valid PinChangeInterrupt pin of your Arduino board
#define pinBlink 2
#undef LED_BUILTIN
#define LED_BUILTIN 4

void setup() {
  // set pin to input with a pullup, led to output
  pinMode(pinBlink, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);

  // Manually blink once to test if LED is functional
  blinkLed();
  delay(1000);
  blinkLed();

  // Attach the new PinChangeInterrupt and enable event function below
  attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE);

  **interrupts();    //Or sei(); needed here to enable interrupts.**
}

void blinkLed(void) {
  // Switch Led state
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

void loop() {
  // Nothing to do here
}

Testing using three attachPCINT and serial output, it still left memory enough to catch data and transmit.
Well done.

ATTiny85 different interrupt pins only respond to different HIGH/LOW states

This is with a Digispark ATTiny85 having two input buttons, each coded to trigger a different routine. THIS PART IS WORKING FINE.
ISSUE: one button ONLY works when changed to HIGH, the other button ONLY works when changed to LOW.

Sketch explanation: One button activates a slow cycle rate, the other button activates a fast cycle rate.

I've also posted this on the DigiStump Forum Site: https://digistump.com/board/index.php/topic,2714.0.html

(Code changed to remove the 'delay' in the interrupt routine)

#include "PinChangeInterrupt.h"

// Choose a valid PinChangeInterrupt pin of your Arduino board
#define pinBlink1 3     // PhysPin 2 Orange
#define pinBlink2 4     // PhysPin 3 Blue
#define relayPin 1      // Phys Pin 6
volatile byte state = 0; // state of relays

void setup() {
  pinMode(pinBlink1, INPUT_PULLUP);
  pinMode(pinBlink2, INPUT_PULLUP);
  pinMode(relayPin, OUTPUT);

  attachPCINT(digitalPinToPCINT(pinBlink1), blinkLed1, CHANGE);
  attachPCINT(digitalPinToPCINT(pinBlink2), blinkLed2, FALLING);
}

void blinkLed1(void) {
state = 1;
}
void blinkLed2(void) {
state = 2;
}

void loop() {
  switch (state){
  case 0: break;
  
  case 1: 
   for (int i = 0; i <= 10; i++) {
    digitalWrite(relayPin, HIGH);
    delayMicroseconds(60000);
    digitalWrite(relayPin, LOW);
    delayMicroseconds(60000);
    }
    state = 0;
    break;
  
  case 2:
   for (int i = 0; i <= 10; i++) {
    digitalWrite(relayPin, HIGH);
    delayMicroseconds(6000);
    digitalWrite(relayPin, LOW);
    delayMicroseconds(6000);
    }
    state = 0;
    break;
  } 
}

multiple definition of `__vector_2'

Thanks for the nice library. I am trying to use it with my Attiny85 in combination with Platformio.

#include <Arduino.h>
#include <PinChangeInterrupt.h>
#include <avr/sleep.h>

#define WAKEUP_PIN PCINT0

void setup() {
  pinMode(WAKEUP_PIN, INPUT);
  attachPCINT(digitalPinToPinChangeInterrupt(WAKEUP_PIN), wakeUpNow, FALLING);
}

When using it, I get the following error:

Compiling .pio/build/attiny85/src/main.cpp.o
Compiling .pio/build/attiny85/lib881/PinChangeInterrupt/PinChangeInterrupt.cpp.o
Compiling .pio/build/attiny85/lib881/PinChangeInterrupt/PinChangeInterrupt0.cpp.o
Compiling .pio/build/attiny85/lib881/PinChangeInterrupt/PinChangeInterrupt1.cpp.o
Compiling .pio/build/attiny85/lib881/PinChangeInterrupt/PinChangeInterrupt2.cpp.o
Compiling .pio/build/attiny85/lib881/PinChangeInterrupt/PinChangeInterrupt3.cpp.o
Archiving .pio/build/attiny85/lib881/libPinChangeInterrupt.a
Indexing .pio/build/attiny85/lib881/libPinChangeInterrupt.a
Linking .pio/build/attiny85/firmware.elf
PinChangeInterrupt.cpp.o (symbol from plugin): In function `pcint_null_callback':
(.text+0x0): multiple definition of `__vector_2'
.pio/build/attiny85/src/main.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
*** [.pio/build/attiny85/firmware.elf] Error 1

Do you have an idea why the linker has a problem? Thanks in advance for your help!

Cheers,
Felix

Problem getting Pin Change Interrupts to work on ATtiny84

I have been trying to get Pin Change interrupts to work on an ATtiny84.

Code:

#include "PinChangeInterrupt.h"

#define BUTTON  2
#define LED 8

void setup() {

  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  attachPCINT(digitalPinToPCINT(BUTTON), buttonInterrupt, CHANGE);

}

void buttonInterrupt() {
  digitalWrite(LED, digitalRead(BUTTON));
}


void loop() {

}

With the code shown above, nothing happens when the button is pressed or released. However, if I move the digitalWrite() line of code out of the buttonInterrupt() function and into loop(), the led goes off and on perfectly as the button is pressed and released. So it seems the interrupt function is not getting called.

I have tried the same code on Nano 3 and that works perfectly, the interrupt function gets called.

I am using:

  • IDE 1.6.5
  • Tiny core: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json. Have tried version 1.0.0 and 1.0.1
    
  • Pin change library: https://github.com/NicoHood/PinChangeInterrupt version 1.2.3
    

Does not work above pin 7 on ATmega1284P

The library does not work for pin 8 and above on the ATmega1284P.
I have been using the pinchangeinterrupt_led example to test. It works fine below pin 8 and at pin 8 and above the interrupt is not activated.

atmega8 support

Hi
I tried to use your library for atmega8 chip (MiniCore) but during verify procedure arduino give error "PinChangeInterrupt library does not support this MCU".
Can you add support for Atmega8 ?

ISR is not called for RISING edge!

The Arduino sketch below runs on my Uno board:

#include <PinChangeInterrupt.h>

#define TRIG_PIN 2
#define ECHO_PIN 4

typedef void(*interrupt_service_routine)(void);

struct HC_SR04 {
  int16_t trig_pin, echo_pin;
  interrupt_service_routine echo_high_isr, echo_low_isr;
  volatile uint32_t echo_start, echo_end;
  volatile bool finished;
  
  HC_SR04(int16_t _trig_pin, int16_t _echo_pin, interrupt_service_routine _echo_high_isr, interrupt_service_routine _echo_low_isr) : 
    trig_pin{ _trig_pin }, echo_pin{ _echo_pin }, echo_high_isr{ _echo_high_isr }, echo_low_isr{ _echo_low_isr }, 
    echo_start{ 0 }, echo_end{ 0 }, finished{ false } {}

  void begin() {
    pinMode(this->trig_pin, OUTPUT);
    digitalWrite(this->trig_pin, LOW);
    pinMode(this->echo_pin, INPUT);
    attachPCINT(digitalPinToPCINT(this->echo_pin), this->echo_high_isr, RISING);
    attachPCINT(digitalPinToPCINT(this->echo_pin), this->echo_low_isr, FALLING);
  }

  void start_measurement() {
    this->finished = false;
    digitalWrite(this->trig_pin, HIGH);
    delayMicroseconds(10);
    digitalWrite(this->trig_pin, LOW);
  }

  uint32_t try_get_distance() {
    if(this->finished) {
      return this->echo_end - this->echo_start;
    }
    return 0;
  }

  uint32_t get_distance() {
    while(this->finished == false);
    return this->echo_end - this->echo_start;
  }
};

static void echo_high_isr0();
static void echo_low_isr0();
HC_SR04 range_sensor(TRIG_PIN, ECHO_PIN, &echo_high_isr0, &echo_low_isr0);

static void echo_high_isr0() {
  range_sensor.echo_start = micros();
}
static void echo_low_isr0() {
  range_sensor.echo_end = micros();
  range_sensor.finished = true;
}


uint32_t measurement_count = 1;
float avg_dist = 0.0;

void setup() {
  // put your setup code here, to run once:
  range_sensor.begin();
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  range_sensor.start_measurement();
  float distance = range_sensor.get_distance() / 58.8235294118;
  Serial.print("Echo start: ");
  Serial.print(range_sensor.echo_start);
  Serial.print(", ");
  if(distance > 400.0) {
    Serial.print("Out of range! (");
    Serial.print(distance);
    Serial.println(" cm)");
  } else {
    avg_dist += (distance - avg_dist)/measurement_count;
    measurement_count++;
    Serial.print("Distance: ");
    Serial.print(distance);
    Serial.print(" cm, avg. distance: ");
    Serial.print(avg_dist);
    Serial.println(" cm");
  }
  // no more than 1 measurement every 60 ms !!!
  delay(60);
}

However, according to the output of the serial port, echo_high_isr0 interrupt service routine is never called (echo_start always stays as 0).

PORT NAMES

hello,

is there any reason why did not have port names corresponding with datasheet?

PORTA,PORTB...

I have to grep PCINT10 in whole src directory to find out that it is in port1 so I can disable port0,port2 and port3

Question on combining this with sleep function

Is the pinchangeinterrupt trigger a wake up from sleep? Do you issue a sei() somewhere or do I have to do it in the main program?

/*
ATTINY13A Pins
--------------
PB0: reed switch      over 10kOhm to GND
PB1: same reed switch resp. connected to PB0
PB2: 433Mhz sender
PB4: tempering switch over 10kOhm to GND


*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>
#include "PinChangeInterrupt.h"

volatile int message = 0;

const int SPEED = 350;
const byte START = 31;
const byte _SHORT = 1;
const byte _LONG = 3;
const byte OPEN =  0b00000001;//Decimal: 131586 (24Bit) Binary: 000000100000001000000010
const byte CLOSE = 0b00000010;//Decimal: 65793 (24Bit) Binary: 000000010000000100000001
const byte TEMPER = 0b00000011;//Decimal: 197379 (24Bit) Binary: 000000110000001100000011

#define TRANS_PIN PB2
#define INPUT_PIN0 PB0
#define INPUT_PIN1 PB1
#define TEMPER_PIN PB4

void setup(){
  // Configure TRANS_PIN as output
  DDRB |= (1 << TRANS_PIN);
  // Set INPUT_PIN as Input
  DDRB &= ~(1 << INPUT_PIN0 | 1 << INPUT_PIN1 | 1 << TEMPER_PIN);
  //pinMode(INPUT_PIN0, INPUT);//INPUT_PULLUP
  //pinMode(INPUT_PIN1, INPUT);
  MCUCR = (1 << SE)     // To enter any sleep modes, the SE bit in MCUCR must be written to logic one
        | (1 << SM1);   // power down sleep mode
  // attach the new PinChangeInterrupts and enable event functions below
  attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(INPUT_PIN0), tick, RISING);
  attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(INPUT_PIN1), tock, FALLING);
  attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(TEMPER_PIN), temper, RISING);
  enable_PinChange_interrupts ();
}


void loop() {
  // change into sleep mode
  // Set TRANS_PIN low
  PORTB &= ~(1 << TRANS_PIN);
  ADCSRA = 0 << ADEN;   // Power reduction ADC
  sleep_cpu(); 
  ADCSRA = 1 << ADEN;   // Power reduction ADC reverse
  disable_PinChange_interrupts ();
  switch (message) {
    case 1:
      send(OPEN); 
    break;
    case 2:
      send(CLOSE);
    break;
    case 3:
      send(TEMPER);
    break;
  }
  message = 0;
  _delay_ms(50);
  enable_PinChange_interrupts ();  
}

void tick(void) {
  message = 1;
}

void tock(void) {
  message = 2;
}

void temper(void) {
  message = 3;
}

void enable_PinChange_interrupts () {
  enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(INPUT_PIN0));
  enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(INPUT_PIN1));
  enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(TEMPER_PIN));
}


void disable_PinChange_interrupts () {
  disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(INPUT_PIN0));
  disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(INPUT_PIN1));
  disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(TEMPER_PIN));
}


void send(byte id){
  for(byte i=0;i<13;i++) {
    sendStart();
    sendUniqueId(id);
  }
}


void sendStart() {
  digitalWrite(1);
  _delay_us((SPEED*_SHORT));
  digitalWrite(0);
  _delay_us((SPEED*START));
}


void sendUniqueId(byte id) {
  for(byte x=0;x<3;x++) {//  send 3 times same 8 bits = 24 bit code
    for (unsigned int y = 8; y-- > 0;){ 
      if(bitRead(id,y)) sendPulse1();
      else sendPulse0();
    }
  }
}


void sendPulse0() {
  digitalWrite(1);
  _delay_us((SPEED*_SHORT));
  digitalWrite(0);
  _delay_us((SPEED*_LONG));
}


void sendPulse1() {
  digitalWrite(1);
  _delay_us((SPEED*_LONG));
  digitalWrite(0);
  _delay_us((SPEED*_SHORT));
}


void digitalWrite(bool val){
  if(val)PORTB |= (1 << TRANS_PIN);
  else PORTB &= ~(1 << TRANS_PIN);
}
``

Conflict with SoftwareSerial.h

Compiling .pio\build\uno\src\PinChangeInterrupt_Led.ino.cpp.o
Linking .pio\build\uno\firmware.elf
SoftwareSerial.cpp.o (symbol from plugin): In function SoftwareSerial::read()': (.text+0x0): multiple definition of __vector_3'
.pio\build\uno\src\PinChangeInterrupt0.cpp.o (symbol from plugin):(.text+0x0): first defined here
SoftwareSerial.cpp.o (symbol from plugin): In function SoftwareSerial::read()': (.text+0x0): multiple definition of __vector_4'
.pio\build\uno\src\PinChangeInterrupt1.cpp.o (symbol from plugin):(.text+0x0): first defined here
SoftwareSerial.cpp.o (symbol from plugin): In function SoftwareSerial::read()': (.text+0x0): multiple definition of __vector_5'
.pio\build\uno\src\PinChangeInterrupt2.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\uno\firmware.elf] Error 1

Not a issue but a doubt

can we use the new interrupt pins (we got by using pinchangeinterrupt ) only for external interrupt or it can be used for timer interrupt too?

on pc level change interrupt, disable/enable not working

on uno, d2, i trigger interrupt on level going falling.
in my int handler, I call disablePinChangeInterrupt ( digitalPinToPinChangeInterrupt ( 2 ) );
and then my loop() comes alive.
all is well.

however, if i press my button which triggers int handler TOO fast, I see that the int handler is called BUT the Loop() is never called.

Any ideas?

error MCU has no such a register Attiny84

Hello,
I have been trying to get Pin Change interrupts to work on an ATtiny84.

My code:

#include "PinChangeInterrupt.h"

#define pinBlink 3

void setup() {
  // set pin to input with a pullup, led to output
  pinMode(pinBlink, INPUT_PULLUP);
  pinMode(2, OUTPUT);

  // Attach the new PinChangeInterrupt and enable event function below
  attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE);
}

void blinkLed(void) {
  digitalWrite(2, !digitalRead(2));
}

void loop() {
  // Nothing to do here
}

Error Debug :

`In file included from C:\******\Arduino\libraries\PinChangeInterrupt\src/PinChangeInterrupt.h:43:0,

from C:\******\Arduino\libraries\PinChangeInterrupt\examples\PinChangeInterrupt_Led\PinChangeInterrupt_Led.ino:29:

C:\******\Arduino\libraries\PinChangeInterrupt\src/PinChangeInterruptBoards.h:117:2: error: #error PinChangeInterrupt library does not support this MCU.

 #error PinChangeInterrupt library does not support this MCU.

  ^

In file included from C:\******\Arduino\libraries\PinChangeInterrupt\examples\PinChangeInterrupt_Led\PinChangeInterrupt_Led.ino:29:0:

C:\******\Arduino\libraries\PinChangeInterrupt\src/PinChangeInterrupt.h:47:2: error: #error Please enable at least one PCINT port!

 #error Please enable at least one PCINT port!

  ^

In file included from C:\******\Arduino\libraries\PinChangeInterrupt\examples\PinChangeInterrupt_Led\PinChangeInterrupt_Led.ino:29:0:

C:\******\Arduino\libraries\PinChangeInterrupt\src/PinChangeInterrupt.h:86:2: error: #error MCU has no such a register

 #error MCU has no such a register

Can you help me ?
Thank you

Please consider adding support for member function ISR registration

Currently, the attachPCINT() macro accepts a pointer to an argument-less void function, which makes it cumbersome to pass a non-static member-function pointer. We could use std::bind and other library features to get around this, but in general, the C++ Standard Library is inaccessible to most Arduino architectures.

It would be great if attachPCINT() (or other construct) had an overload that accepted a void* parameter in addition to the callback function pointer as arguments, then called the ISR with the given void* parameter as the sole argument. This should allow for binding to non-static member functions.

I'm sure I can eventually produce a pull request for such a feature, but I'm currently wrapping my head around the casts and function pointer syntax required to do so and am getting very confused.

millis() issue

I have 2 pushbuttons and want to record elapsed time between button1 press and button2 press. I used your library, inside each event function i use millis() to record time and in main code i print de elapsed time. Everything is working ok.

To preserve power, i added rocketscream/Low-Power library and put this line in the main loop:

LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);

Pushbutton events are still fired but elapsed time is not working, it always report less than 70ms, no matter time between button presses.

Than i tested without your library, using external interrupts (pins 2,3). millis() with lowpower library works as expected.

So, it seems that the problem with millis() happens when joining your library with lowpower library.
Any idea why?

Unsupported libraries

Hello world.
I'm wondering if HX711 library and PinChangeInterrupt should never been used together ?
My setup stops at scale.tare();
I'm wondering if it is because i'm using https://github.com/bogde/HX711 library and PinChangeInterrupt together ?
SCA and SCL are the same as A4 and A5, so using PinChangeInterrupt may cause some trouble to HX711
scale.set_scale(calibration_factor); works but i think it sends nothing on SCA & SCL lines.
Any insight ?
Best

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.