初始化提交

This commit is contained in:
王立帮
2024-07-20 22:09:06 +08:00
commit c247dd07a6
6876 changed files with 2743096 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

View File

@@ -0,0 +1,19 @@
Copyright (c) 2014-2021 NicoHood
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,357 @@
PinChangeInterrupt Library 1.2.9
================================
![Header Picture](header.png)
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)
<a href="https://www.buymeacoffee.com/nicohood"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: auto !important;width: auto !important;" ></a>
#### Supported pins for PinChangeInterrupt:
See [PCINT pin table](https://github.com/NicoHood/PinChangeInterrupt/#pinchangeinterrupt-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](http://arduino.cc/en/pmwiki.php?n=Guide/Libraries).
This library can also be used with the [DMBS AVR Library Collection](https://github.com/NicoHood/avr) 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
```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
========================
Pins with * are not broken out/deactivated by default.
You may activate them in the [setting file](https://github.com/NicoHood/PinChangeInterrupt/blob/master/src/PinChangeInterruptSettings.h#L98) (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](https://github.com/NicoHood/PinChangeInterrupt/#optional-installation)
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
```

View File

@@ -0,0 +1,122 @@
/*
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
Attiny 441/841: 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();
}

View File

@@ -0,0 +1,55 @@
/*
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
Attiny 441/841: 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);
// 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);
}
void blinkLed(void) {
// Switch Led state
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
void loop() {
// Nothing to do here
}

View File

@@ -0,0 +1,60 @@
/*
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
Attiny 441/841: 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
}

View File

@@ -0,0 +1,98 @@
/*
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
Attiny 441/841: 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--;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -0,0 +1,32 @@
#######################################
# Syntax Coloring Map For PinChangeInterrupt
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
#######################################
# Methods and Functions (KEYWORD2)
#######################################
attachPinChangeInterrupt KEYWORD2
detachPinChangeInterrupt KEYWORD2
attachPCINT KEYWORD2
detachPCINT KEYWORD2
PinChangeInterruptEvent KEYWORD2
PCINTEvent KEYWORD2
enablePCINT KEYWORD2
enablePinChangeInterrupt KEYWORD2
disablePCINT KEYWORD2
disablePinChangeInterrupt KEYWORD2
getPCINTTrigger KEYWORD2
getPinChangeInterruptTrigger KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
#######################################
# Constants (LITERAL1)
#######################################

View File

@@ -0,0 +1,10 @@
name=PinChangeInterrupt
version=1.2.9
author=NicoHood
maintainer=NicoHood <blog@NicoHood.de>
sentence=A simple & compact PinChangeInterrupt library for Arduino.
paragraph=PinChangeInterrupt library with a resource friendly implementation (API and LowLevel). PinChangeInterrupts are different than normal Interrupts. See readme for more information.
category=Signal Input/Output
url=https://github.com/NicoHood/PinChangeInterrupt
architectures=avr
dot_a_linkage=true

View File

@@ -0,0 +1,348 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "PinChangeInterrupt.h"
// manually include cpp files here to save flash if only 1 ISR is present
// or if the user knows he just wants to compile all enabled ports.
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR)
#define PCINT_INCLUDE_FROM_CPP
#include "PinChangeInterrupt0.cpp"
#include "PinChangeInterrupt1.cpp"
#include "PinChangeInterrupt2.cpp"
#include "PinChangeInterrupt3.cpp"
#else
//================================================================================
// Weak Callbacks
//================================================================================
// create all weak functions which are all (if not used) alias of the pcint_null_callback above
/*
for (int i = 0; i < 32; i++) {
Serial.print("void PinChangeInterruptEventPCINT");
Serial.print(i);
Serial.println("(void) __attribute__((weak, alias(\"pcint_null_callback\")));");
}
*/
void PinChangeInterruptEventPCINT0(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT1(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT2(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT3(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT4(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT5(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT6(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT7(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT8(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT9(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT10(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT11(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT12(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT13(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT14(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT15(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT16(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT17(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT18(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT19(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT20(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT21(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT22(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT23(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT24(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT25(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT26(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT27(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT28(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT29(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT30(void) __attribute__((weak, alias("pcint_null_callback")));
void PinChangeInterruptEventPCINT31(void) __attribute__((weak, alias("pcint_null_callback")));
#endif // PCINT_INCLUDE_FROM_CPP
// useless function for weak implemented/not used functions, extern c needed for the alias
extern "C" {
void pcint_null_callback(void) {
// useless
}
}
//================================================================================
// PinChangeInterrupt User Functions
//================================================================================
// variables to save the last port states and the interrupt settings
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 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
#ifdef PCMSK0
#ifdef PCMSK1
#ifdef PCMSK3
// Special case for ATmega1284P where PCMSK3 is not directly after PCMSK2
if(false){
#else
// Special case for Attinyx4 where PCMSK1 and PCMSK0 are not next to each other
if(&PCMSK1 - &PCMSK0 == 1){
#endif
#endif
*(&PCMSK0 + pcintPort) |= pcintMask;
#ifdef PCMSK1
}
else{
switch(pcintPort){
case 0:
PCMSK0 |= pcintMask;
break;
case 1:
PCMSK1 |= pcintMask;
break;
#ifdef PCMSK2
case 2:
PCMSK2 |= pcintMask;
break;
#endif
#ifdef PCMSK3
case 3:
PCMSK3 |= pcintMask;
break;
#endif
}
}
#endif
#elif defined(PCMSK)
*(&PCMSK + pcintPort) |= pcintMask;
#endif
// PCICR: Pin Change Interrupt Control Register - enables interrupt vectors
#ifdef PCICR
PCICR |= (1 << (pcintPort + PCIE0));
#elif defined(GICR) /* e.g. ATmega162 */
GICR |= (1 << (pcintPort + PCIE0));
#elif defined(GIMSK) && defined(PCIE0) /* e.g. ATtiny X4 */
GIMSK |= (1 << (pcintPort + PCIE0));
#elif defined(GIMSK) && defined(PCIE) /* e.g. ATtiny X5 */
GIMSK |= (1 << (pcintPort + PCIE));
#else
#error MCU has no such a register
#endif
}
void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask) {
bool disable = false;
#ifdef PCMSK0
#ifdef PCMSK1
#ifdef PCMSK3
// Special case for ATmega1284P where PCMSK3 is not directly after PCMSK2
if (false){
#else
// Special case for Attinyx4 where PCMSK1 and PCMSK0 are not next to each other
if (&PCMSK1 - &PCMSK0 == 1) {
#endif // ifdef PCMSK3
#endif // ifdef PCMSK1
// disable the mask.
*(&PCMSK0 + pcintPort) &= ~pcintMask;
// if that's the last one, disable the interrupt.
if (*(&PCMSK0 + pcintPort) == 0) {
disable = true;
}
#ifdef PCMSK1
}
else {
switch (pcintPort) {
case 0:
// disable the mask.
PCMSK0 &= ~pcintMask;
// if that's the last one, disable the interrupt.
if (!PCMSK0) {
disable = true;
}
break;
case 1:
// disable the mask.
PCMSK1 &= ~pcintMask;
// if that's the last one, disable the interrupt.
if (!PCMSK1) {
disable = true;
}
break;
#ifdef PCMSK2
case 2:
// disable the mask.
PCMSK2 &= ~pcintMask;
// if that's the last one, disable the interrupt.
if (!PCMSK2) {
disable = true;
}
break;
#endif // ifdef PCMSK2
#ifdef PCMSK3
case 3:
// disable the mask.
PCMSK3 &= ~pcintMask;
// if that's the last one, disable the interrupt.
if (!PCMSK3) {
disable = true;
}
break;
#endif // ifdef PCMSK3
}
}
#endif // ifdef PCMSK1
#elif defined(PCMSK)
// disable the mask.
*(&PCMSK + pcintPort) &= ~pcintMask;
// if that's the last one, disable the interrupt.
if (*(&PCMSK + pcintPort) == 0) {
disable = true;
}
#endif // ifdef PCMSK0
if(disable)
{
#ifdef PCICR
PCICR &= ~(1 << (pcintPort + PCIE0));
#elif defined(GICR) /* e.g. ATmega162 */
GICR &= ~(1 << (pcintPort + PCIE0));
#elif defined(GIMSK) && defined(PCIE0) /* e.g. ATtiny X4 */
GIMSK &= ~(1 << (pcintPort + PCIE0));
#elif defined(GIMSK) && defined(PCIE) /* e.g. ATtiny X5 */
GIMSK &= ~(1 << (pcintPort + PCIE));
#else
#error MCU has no such a register
#endif
}
}
/*
asm output (nothing to optimize here)
ISR(PCINT0_vect) {
push r1
push r0
in r0, 0x3f ; 63
push r0
eor r1, r1
push r18
push r19
push r20
push r21
push r22
push r23
push r24
push r25
push r26
push r27
push r28
push r30
push r31
// get the new and old pin states for port
// uint8_t newPort = pinChangeInterruptPortToInput(port);
in r24, 0x03; 3 //(1) loads byte into newPort from I/O register
// loads old port and high + low setting
lds r18, 0x011E //(1 or 2) loads oldPorts into register
lds r28, 0x011B //(1 or 2) loads fallingPorts into register
lds r25, 0x0118 //(1 or 2) loads risingPorts into register
and r28, r18 // oldPorts & fallingPorts
and r25, r24 // newPort & risingPorts
or r28, r25 // (oldPorts & fallingPorts) | (newPort & risingPorts)
eor r18, r24 // oldPorts^newPort
and r28, r18 // ((oldPorts & fallingPorts) | (newPort & risingPorts)) & (oldPorts^newPort)
// save the new state for next comparison
// oldPorts[arrayPos] = newPort;
sts 0x011E, r24
// Execute all functions that should be triggered
sbrc r28, 0
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
sbrc r28, 1
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
sbrc r28, 2
call 0x318 ; 0x318 <_Z20PinChangeInterruptEventPCINT2v>
sbrc r28, 3
call 0x340 ; 0x340 <_Z20PinChangeInterruptEventPCINT3v>
sbrc r28, 4
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
sbrc r28, 5
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
sbrc r28, 6
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
sbrc r28, 7
call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v>
pop r31
pop r30
pop r28
pop r27
pop r26
pop r25
pop r24
pop r23
pop r22
pop r21
pop r20
pop r19
pop r18
pop r0
out 0x3f, r0 ; 63
pop r0
pop r1
reti
}
*/

View File

@@ -0,0 +1,898 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Include Guard
#pragma once
// Software Version
#define PCINT_VERSION 129
#include <avr/io.h>
#include <avr/interrupt.h>
#ifdef ARDUINO
#include "Arduino.h"
#ifndef ARDUINO_ARCH_AVR
#error This library can only be used with AVR
#endif
#else
#ifndef LOW
#define LOW 0x0
#endif
#ifndef CHANGE
#define CHANGE 0x1
#endif
#ifndef FALLING
#define FALLING 0x2
#endif
#ifndef RISING
#define RISING 0x3
#endif
#endif
//================================================================================
// General Helper Definitions and Mappings
//================================================================================
// Settings and Board definitions are seperated to get an better overview.
// The order and position of the inclusion is important!
#include "PinChangeInterruptSettings.h"
#include "PinChangeInterruptBoards.h"
#include "PinChangeInterruptPins.h"
#if !PCINT_NUM_USED_PORTS
#error Please enable at least one PCINT port and pin!
#endif
// manually include cpp files to save flash if only 1 ISR is present
// it includes all ISR files but only the 1 available ISR will/can be compiled
#if (PCINT_NUM_USED_PORTS == 1)
#ifndef PCINT_COMPILE_ENABLED_ISR
#define PCINT_COMPILE_ENABLED_ISR
#endif
#endif
//================================================================================
// Makro Definitions
//================================================================================
// generates the callback for easier reordering in Settings
#define PCINT_MACRO_BRACKETS ()
#define PCINT_MACRO_TRUE == true)
#define PCINT_CALLBACK(bit, pcint) \
if (PCINT_USE_PCINT ## pcint PCINT_MACRO_TRUE \
if (trigger & (1 << bit)) \
PinChangeInterruptEventPCINT ## pcint PCINT_MACRO_BRACKETS
// definition used by the user to create custom LowLevel PCINT Events
#define PinChangeInterruptEvent_Wrapper(n) PinChangeInterruptEventPCINT ## n
#define PinChangeInterruptEvent(n) PinChangeInterruptEvent_Wrapper(n)
// missing 1.0.6 definition workaround
#ifndef NOT_AN_INTERRUPT
#define NOT_AN_INTERRUPT -1
#endif
// convert a normal pin to its PCINT number (0 - max 23), used by the user
// calculates the pin by the Arduino definitions
#if defined(PCIE0)
#define digitalPinToPinChangeInterrupt(p) (digitalPinToPCICR(p) ? ((8 * (digitalPinToPCICRbit(p) - PCIE0)) + digitalPinToPCMSKbit(p)) : NOT_AN_INTERRUPT)
#elif defined(PCIE)
#define digitalPinToPinChangeInterrupt(p) (digitalPinToPCICR(p) ? ((8 * (digitalPinToPCICRbit(p) - PCIE)) + digitalPinToPCMSKbit(p)) : NOT_AN_INTERRUPT)
#else
#error MCU has no such a register
#endif
// alias for shorter writing
#define PCINTEvent(n) PinChangeInterruptEvent_Wrapper(n)
#define digitalPinToPCINT digitalPinToPinChangeInterrupt
#define attachPCINT attachPinChangeInterrupt
#define enablePCINT enablePinChangeInterrupt
#define detachPCINT detachPinChangeInterrupt
#define disablePCINT disablePinChangeInterrupt
#define getPCINTTrigger getPinChangeInterruptTrigger
//================================================================================
// Function Prototypes + Variables
//================================================================================
// typedef for our callback function pointers
typedef void(*callback)(void);
// useless function for weak implemented/not used functions, extern c needed for the alias
#ifdef __cplusplus
extern "C" {
#endif
void pcint_null_callback(void);
#ifdef __cplusplus
}
#endif
void PinChangeInterruptEventPCINT0(void);
void PinChangeInterruptEventPCINT1(void);
void PinChangeInterruptEventPCINT2(void);
void PinChangeInterruptEventPCINT3(void);
void PinChangeInterruptEventPCINT4(void);
void PinChangeInterruptEventPCINT5(void);
void PinChangeInterruptEventPCINT6(void);
void PinChangeInterruptEventPCINT7(void);
void PinChangeInterruptEventPCINT8(void);
void PinChangeInterruptEventPCINT9(void);
void PinChangeInterruptEventPCINT10(void);
void PinChangeInterruptEventPCINT11(void);
void PinChangeInterruptEventPCINT12(void);
void PinChangeInterruptEventPCINT13(void);
void PinChangeInterruptEventPCINT14(void);
void PinChangeInterruptEventPCINT15(void);
void PinChangeInterruptEventPCINT16(void);
void PinChangeInterruptEventPCINT17(void);
void PinChangeInterruptEventPCINT18(void);
void PinChangeInterruptEventPCINT19(void);
void PinChangeInterruptEventPCINT20(void);
void PinChangeInterruptEventPCINT21(void);
void PinChangeInterruptEventPCINT22(void);
void PinChangeInterruptEventPCINT23(void);
void PinChangeInterruptEventPCINT24(void);
void PinChangeInterruptEventPCINT25(void);
void PinChangeInterruptEventPCINT26(void);
void PinChangeInterruptEventPCINT27(void);
void PinChangeInterruptEventPCINT28(void);
void PinChangeInterruptEventPCINT29(void);
void PinChangeInterruptEventPCINT30(void);
void PinChangeInterruptEventPCINT31(void);
extern uint8_t oldPorts[PCINT_NUM_USED_PORTS];
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__((always_inline));
uint8_t getArrayPosPCINT(uint8_t pcintPort) {
/*
Maps the port to the array.
This is needed since you can deactivate ports
and the array will dynamically resize to save ram.
The function does not need that much flash since the if and else
are known at compile time, so the compiler removes all the complex logic.
The return is is the input if all pins are activated for example.
That's why the function is inline.
*/
if (PCINT_NUM_USED_PORTS == 1) {
// only the first element is used for a single port
return 0;
}
else if (PCINT_NUM_USED_PORTS == PCINT_NUM_PORTS) {
// use all ports and down remap the array position.
return pcintPort;
}
else if (PCINT_NUM_PORTS - PCINT_NUM_USED_PORTS == 1) {
// one port is not used
if (PCINT_USE_PORT0 == 0) {
// first port is not used, decrease all port numbers
return (pcintPort - 1);
}
else if (PCINT_HAS_PORT3 == 0) {
// 3 ports (standard)
if (PCINT_USE_PORT2 == 0) {
// last port not used, no mapping needed
return pcintPort;
}
else {
// worst case, port in the middle not used, remap
return ((pcintPort >> 1) & 0x01);
//if (pcintPort == 0) return 0;
//else return 1;
}
}
else {
// 4 ports (special case for a few AVRs)
if (PCINT_USE_PORT3 == 0) {
// last port not used, no mapping needed
return pcintPort;
}
else {
// worst case, one of two ports in the middle not used, remap
if (PCINT_USE_PORT1 == 0) {
// port1 not used, mapping needed
if (pcintPort == 0)
return 0;
else
return pcintPort - 1;
}
else if (PCINT_USE_PORT2 == 0) {
// port2 not used, mapping needed
if (pcintPort == 3)
return 2;
else
return pcintPort;
}
}
}
// use all ports and down remap the array position.
return pcintPort;
}
else if (PCINT_NUM_PORTS - PCINT_NUM_USED_PORTS == 2) {
if (PCINT_USE_PORT2 == 0 && PCINT_USE_PORT3 == 0) {
// no need for mapping
return pcintPort;
}
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT3 == 0) {
// 1 offset
return (pcintPort - 1);
}
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT1 == 0) {
// 2 offset
return (pcintPort - 2);
}
else if (PCINT_USE_PORT0 == 0 && PCINT_USE_PORT2 == 0) {
// 2 -> 1
return (pcintPort >> 1);
}
else if (PCINT_USE_PORT1 == 0 && PCINT_USE_PORT2 == 0) {
// 3 -> 1
return (pcintPort >> 1);
}
else if (PCINT_USE_PORT1 == 0 && PCINT_USE_PORT3 == 0) {
// 3 -> 1, 1 -> 0
return (pcintPort >> 1);
}
}
// error
return 0;
}
//================================================================================
// Attach Function (partly inlined)
//================================================================================
void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos);
void attachPinChangeInterrupt0(void);
void attachPinChangeInterrupt1(void);
void attachPinChangeInterrupt2(void);
void attachPinChangeInterrupt3(void);
#if defined(PCINT_API)
/*
for (int i = 0; i < 32; i++) {
Serial.print("#if (PCINT_USE_PCINT");
Serial.print(i);
Serial.println(" == true)");
Serial.print("extern volatile callback callbackPCINT");
Serial.print(i);
Serial.println(";");
Serial.println("#endif");
}
*/
#if (PCINT_USE_PCINT0 == true)
extern volatile callback callbackPCINT0;
#endif
#if (PCINT_USE_PCINT1 == true)
extern volatile callback callbackPCINT1;
#endif
#if (PCINT_USE_PCINT2 == true)
extern volatile callback callbackPCINT2;
#endif
#if (PCINT_USE_PCINT3 == true)
extern volatile callback callbackPCINT3;
#endif
#if (PCINT_USE_PCINT4 == true)
extern volatile callback callbackPCINT4;
#endif
#if (PCINT_USE_PCINT5 == true)
extern volatile callback callbackPCINT5;
#endif
#if (PCINT_USE_PCINT6 == true)
extern volatile callback callbackPCINT6;
#endif
#if (PCINT_USE_PCINT7 == true)
extern volatile callback callbackPCINT7;
#endif
#if (PCINT_USE_PCINT8 == true)
extern volatile callback callbackPCINT8;
#endif
#if (PCINT_USE_PCINT9 == true)
extern volatile callback callbackPCINT9;
#endif
#if (PCINT_USE_PCINT10 == true)
extern volatile callback callbackPCINT10;
#endif
#if (PCINT_USE_PCINT11 == true)
extern volatile callback callbackPCINT11;
#endif
#if (PCINT_USE_PCINT12 == true)
extern volatile callback callbackPCINT12;
#endif
#if (PCINT_USE_PCINT13 == true)
extern volatile callback callbackPCINT13;
#endif
#if (PCINT_USE_PCINT14 == true)
extern volatile callback callbackPCINT14;
#endif
#if (PCINT_USE_PCINT15 == true)
extern volatile callback callbackPCINT15;
#endif
#if (PCINT_USE_PCINT16 == true)
extern volatile callback callbackPCINT16;
#endif
#if (PCINT_USE_PCINT17 == true)
extern volatile callback callbackPCINT17;
#endif
#if (PCINT_USE_PCINT18 == true)
extern volatile callback callbackPCINT18;
#endif
#if (PCINT_USE_PCINT19 == true)
extern volatile callback callbackPCINT19;
#endif
#if (PCINT_USE_PCINT20 == true)
extern volatile callback callbackPCINT20;
#endif
#if (PCINT_USE_PCINT21 == true)
extern volatile callback callbackPCINT21;
#endif
#if (PCINT_USE_PCINT22 == true)
extern volatile callback callbackPCINT22;
#endif
#if (PCINT_USE_PCINT23 == true)
extern volatile callback callbackPCINT23;
#endif
#if (PCINT_USE_PCINT24 == true)
extern volatile callback callbackPCINT24;
#endif
#if (PCINT_USE_PCINT25 == true)
extern volatile callback callbackPCINT25;
#endif
#if (PCINT_USE_PCINT26 == true)
extern volatile callback callbackPCINT26;
#endif
#if (PCINT_USE_PCINT27 == true)
extern volatile callback callbackPCINT27;
#endif
#if (PCINT_USE_PCINT28 == true)
extern volatile callback callbackPCINT28;
#endif
#if (PCINT_USE_PCINT29 == true)
extern volatile callback callbackPCINT29;
#endif
#if (PCINT_USE_PCINT30 == true)
extern volatile callback callbackPCINT30;
#endif
#if (PCINT_USE_PCINT31 == true)
extern volatile callback callbackPCINT31;
#endif
/*
for (int i = 0; i < 32; i++) {
Serial.print("#if (PCINT_USE_PCINT");
Serial.print(i);
Serial.println(" == true)");
Serial.print("if (pcintNum == ");
Serial.print(i);
Serial.println(")");
Serial.print("callbackPCINT");
Serial.print(i);
Serial.println(" = userFunc;");
Serial.println("#endif");
}
*/
// API attach function
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 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
// check if pcint is a valid pcint, exclude deactivated ports
uint8_t pcintPort = pcintNum / 8;
uint8_t pcintBit = pcintNum % 8;
// port 0
if (pcintPort == 0 && PCINT_USE_PORT0 == true) {
// use fake functions to make the ISRs compile with .a linkage
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
attachPinChangeInterrupt0();
#endif
// attache the function pointers for the API
#if defined(PCINT_API)
#if (PCINT_USE_PCINT0 == true)
if (pcintNum == 0)
callbackPCINT0 = userFunc;
#endif
#if (PCINT_USE_PCINT1 == true)
if (pcintNum == 1)
callbackPCINT1 = userFunc;
#endif
#if (PCINT_USE_PCINT2 == true)
if (pcintNum == 2)
callbackPCINT2 = userFunc;
#endif
#if (PCINT_USE_PCINT3 == true)
if (pcintNum == 3)
callbackPCINT3 = userFunc;
#endif
#if (PCINT_USE_PCINT4 == true)
if (pcintNum == 4)
callbackPCINT4 = userFunc;
#endif
#if (PCINT_USE_PCINT5 == true)
if (pcintNum == 5)
callbackPCINT5 = userFunc;
#endif
#if (PCINT_USE_PCINT6 == true)
if (pcintNum == 6)
callbackPCINT6 = userFunc;
#endif
#if (PCINT_USE_PCINT7 == true)
if (pcintNum == 7)
callbackPCINT7 = userFunc;
#endif
#endif // PCINT_API
}
// port 1
else if (pcintPort == 1 && PCINT_USE_PORT1 == true) {
// use fake functions to make the ISRs compile with .a linkage
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
attachPinChangeInterrupt1();
#endif
// attache the function pointers for the API
#if defined(PCINT_API)
#if (PCINT_USE_PCINT8 == true)
if (pcintNum == 8)
callbackPCINT8 = userFunc;
#endif
#if (PCINT_USE_PCINT9 == true)
if (pcintNum == 9)
callbackPCINT9 = userFunc;
#endif
#if (PCINT_USE_PCINT10 == true)
if (pcintNum == 10)
callbackPCINT10 = userFunc;
#endif
#if (PCINT_USE_PCINT11 == true)
if (pcintNum == 11)
callbackPCINT11 = userFunc;
#endif
#if (PCINT_USE_PCINT12 == true)
if (pcintNum == 12)
callbackPCINT12 = userFunc;
#endif
#if (PCINT_USE_PCINT13 == true)
if (pcintNum == 13)
callbackPCINT13 = userFunc;
#endif
#if (PCINT_USE_PCINT14 == true)
if (pcintNum == 14)
callbackPCINT14 = userFunc;
#endif
#if (PCINT_USE_PCINT15 == true)
if (pcintNum == 15)
callbackPCINT15 = userFunc;
#endif
#endif // PCINT_API
}
// port 2
else if (pcintPort == 2 && PCINT_USE_PORT2 == true) {
// use fake functions to make the ISRs compile with .a linkage
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
attachPinChangeInterrupt2();
#endif
// attache the function pointers for the API
#if defined(PCINT_API)
#if (PCINT_USE_PCINT16 == true)
if (pcintNum == 16)
callbackPCINT16 = userFunc;
#endif
#if (PCINT_USE_PCINT17 == true)
if (pcintNum == 17)
callbackPCINT17 = userFunc;
#endif
#if (PCINT_USE_PCINT18 == true)
if (pcintNum == 18)
callbackPCINT18 = userFunc;
#endif
#if (PCINT_USE_PCINT19 == true)
if (pcintNum == 19)
callbackPCINT19 = userFunc;
#endif
#if (PCINT_USE_PCINT20 == true)
if (pcintNum == 20)
callbackPCINT20 = userFunc;
#endif
#if (PCINT_USE_PCINT21 == true)
if (pcintNum == 21)
callbackPCINT21 = userFunc;
#endif
#if (PCINT_USE_PCINT22 == true)
if (pcintNum == 22)
callbackPCINT22 = userFunc;
#endif
#if (PCINT_USE_PCINT23 == true)
if (pcintNum == 23)
callbackPCINT23 = userFunc;
#endif
#endif // PCINT_API
}
// port 3
else if (pcintPort == 3 && PCINT_USE_PORT3 == true) {
// use fake functions to make the ISRs compile with .a linkage
#if defined(PCINT_ALINKAGE) && !defined(PCINT_COMPILE_ENABLED_ISR)
attachPinChangeInterrupt3();
#endif
// attache the function pointers for the API
#if defined(PCINT_API)
#if (PCINT_USE_PCINT24 == true)
if (pcintNum == 24)
callbackPCINT24 = userFunc;
#endif
#if (PCINT_USE_PCINT25 == true)
if (pcintNum == 25)
callbackPCINT25 = userFunc;
#endif
#if (PCINT_USE_PCINT26 == true)
if (pcintNum == 26)
callbackPCINT26 = userFunc;
#endif
#if (PCINT_USE_PCINT27 == true)
if (pcintNum == 27)
callbackPCINT27 = userFunc;
#endif
#if (PCINT_USE_PCINT28 == true)
if (pcintNum == 28)
callbackPCINT28 = userFunc;
#endif
#if (PCINT_USE_PCINT29 == true)
if (pcintNum == 29)
callbackPCINT29 = userFunc;
#endif
#if (PCINT_USE_PCINT30 == true)
if (pcintNum == 30)
callbackPCINT30 = userFunc;
#endif
#if (PCINT_USE_PCINT31 == true)
if (pcintNum == 31)
callbackPCINT31 = userFunc;
#endif
#endif // PCINT_API
}
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
enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos);
}
// enable interrupt again if temporary disabled
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;
// check if pcint is a valid pcint, exclude deactivated ports
if (pcintPort == 0) {
if (PCINT_USE_PORT0 == false)
return;
}
else if (pcintPort == 1) {
if (PCINT_USE_PORT1 == false)
return;
}
else if (pcintPort == 2) {
if (PCINT_USE_PORT2 == false)
return;
}
else if (pcintPort == 3) {
if (PCINT_USE_PORT3 == false)
return;
}
else return;
// call the actual hardware attach function
uint8_t pcintMask = (1 << pcintBit);
uint8_t arrayPos = getArrayPosPCINT(pcintPort);
enablePinChangeInterruptHelper(pcintPort, pcintMask, arrayPos);
}
//================================================================================
// Detach Function (partly inlined)
//================================================================================
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)
return;
}
else if (pcintPort == 1) {
if (PCINT_USE_PORT1 == false)
return;
}
else if (pcintPort == 2) {
if (PCINT_USE_PORT2 == false)
return;
}
else if (pcintPort == 3) {
if (PCINT_USE_PORT3 == false)
return;
}
else return;
// 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 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;
uint8_t pcintBit = pcintNum % 8;
// check if pcint is a valid pcint, exclude deactivated ports
if (pcintPort == 0) {
if (PCINT_USE_PORT0 == false)
return CHANGE;
}
else if (pcintPort == 1) {
if (PCINT_USE_PORT1 == false)
return CHANGE;
}
else if (pcintPort == 2) {
if (PCINT_USE_PORT2 == false)
return CHANGE;
}
else if (pcintPort == 3) {
if (PCINT_USE_PORT3 == false)
return CHANGE;
}
else return CHANGE;
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;
}

View File

@@ -0,0 +1,149 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "PinChangeInterrupt.h"
//================================================================================
// Interrupt Handler
//================================================================================
// prevent compilation twice if included from the .cpp to force compile all ISRs
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \
|| !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR)
#if (PCINT_USE_PORT0 == true)
void attachPinChangeInterrupt0(void) {
// fake function to make the IDE link this file
}
ISR(PCINT0_vect) {
// get the new and old pin states for port
uint8_t newPort = PCINT_INPUT_PORT0;
// compare with the old value to detect a rising or falling
uint8_t arrayPos = getArrayPosPCINT(0);
uint8_t change = newPort ^ oldPorts[arrayPos];
uint8_t rising = change & newPort;
uint8_t falling = change & oldPorts[arrayPos];
// check which pins are triggered, compared with the settings
uint8_t risingTrigger = rising & risingPorts[arrayPos];
uint8_t fallingTrigger = falling & fallingPorts[arrayPos];
uint8_t trigger = risingTrigger | fallingTrigger;
// save the new state for next comparison
oldPorts[arrayPos] = newPort;
// Execute all functions that should be triggered
// This way we can exclude a single function
// and the calling is also much faster
// We may also reorder the pins for different priority
#if !defined(PCINT_CALLBACK_PORT0)
PCINT_CALLBACK(0, 0);
PCINT_CALLBACK(1, 1);
PCINT_CALLBACK(2, 2);
PCINT_CALLBACK(3, 3);
PCINT_CALLBACK(4, 4);
PCINT_CALLBACK(5, 5);
PCINT_CALLBACK(6, 6);
PCINT_CALLBACK(7, 7);
#else
PCINT_CALLBACK_PORT0
#endif
}
#if defined(PCINT_API)
/*
for (int i = 0; i < 32; i++) {
Serial.print("#if (PCINT_USE_PCINT");
Serial.print(i);
Serial.println(" == true)");
Serial.print("volatile callback callbackPCINT");
Serial.print(i);
Serial.println(" = pcint_null_callback;");
Serial.print("void PinChangeInterruptEventPCINT");
Serial.print(i);
Serial.println("(void){");
Serial.print(" callbackPCINT");
Serial.print(i);
Serial.println("();");
Serial.println("}");
Serial.println("#endif");
}
*/
#if (PCINT_USE_PCINT0 == true)
volatile callback callbackPCINT0 = pcint_null_callback;
void PinChangeInterruptEventPCINT0(void) {
callbackPCINT0();
}
#endif
#if (PCINT_USE_PCINT1 == true)
volatile callback callbackPCINT1 = pcint_null_callback;
void PinChangeInterruptEventPCINT1(void) {
callbackPCINT1();
}
#endif
#if (PCINT_USE_PCINT2 == true)
volatile callback callbackPCINT2 = pcint_null_callback;
void PinChangeInterruptEventPCINT2(void) {
callbackPCINT2();
}
#endif
#if (PCINT_USE_PCINT3 == true)
volatile callback callbackPCINT3 = pcint_null_callback;
void PinChangeInterruptEventPCINT3(void) {
callbackPCINT3();
}
#endif
#if (PCINT_USE_PCINT4 == true)
volatile callback callbackPCINT4 = pcint_null_callback;
void PinChangeInterruptEventPCINT4(void) {
callbackPCINT4();
}
#endif
#if (PCINT_USE_PCINT5 == true)
volatile callback callbackPCINT5 = pcint_null_callback;
void PinChangeInterruptEventPCINT5(void) {
callbackPCINT5();
}
#endif
#if (PCINT_USE_PCINT6 == true)
volatile callback callbackPCINT6 = pcint_null_callback;
void PinChangeInterruptEventPCINT6(void) {
callbackPCINT6();
}
#endif
#if (PCINT_USE_PCINT7 == true)
volatile callback callbackPCINT7 = pcint_null_callback;
void PinChangeInterruptEventPCINT7(void) {
callbackPCINT7();
}
#endif
#endif // PCINT_API
#endif // PCINT_USE_PORT0
#endif // PCINT_INCLUDE_FROM_CPP

View File

@@ -0,0 +1,149 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "PinChangeInterrupt.h"
//================================================================================
// Interrupt Handler
//================================================================================
// prevent compilation twice if included from the .cpp to force compile all ISRs
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \
|| !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR)
#if (PCINT_USE_PORT1 == true)
void attachPinChangeInterrupt1(void) {
// fake function to make the IDE link this file
}
ISR(PCINT1_vect) {
// get the new and old pin states for port
uint8_t newPort = PCINT_INPUT_PORT1;
// compare with the old value to detect a rising or falling
uint8_t arrayPos = getArrayPosPCINT(1);
uint8_t change = newPort ^ oldPorts[arrayPos];
uint8_t rising = change & newPort;
uint8_t falling = change & oldPorts[arrayPos];
// check which pins are triggered, compared with the settings
uint8_t risingTrigger = rising & risingPorts[arrayPos];
uint8_t fallingTrigger = falling & fallingPorts[arrayPos];
uint8_t trigger = risingTrigger | fallingTrigger;
// save the new state for next comparison
oldPorts[arrayPos] = newPort;
// Execute all functions that should be triggered
// This way we can exclude a single function
// and the calling is also much faster
// We may also reorder the pins for different priority
#if !defined(PCINT_CALLBACK_PORT1)
PCINT_CALLBACK(0, 8);
PCINT_CALLBACK(1, 9);
PCINT_CALLBACK(2, 10);
PCINT_CALLBACK(3, 11);
PCINT_CALLBACK(4, 12);
PCINT_CALLBACK(5, 13);
PCINT_CALLBACK(6, 14);
PCINT_CALLBACK(7, 15);
#else
PCINT_CALLBACK_PORT1
#endif
}
#if defined(PCINT_API)
/*
for (int i = 0; i < 32; i++) {
Serial.print("#if (PCINT_USE_PCINT");
Serial.print(i);
Serial.println(" == true)");
Serial.print("volatile callback callbackPCINT");
Serial.print(i);
Serial.println(" = pcint_null_callback;");
Serial.print("void PinChangeInterruptEventPCINT");
Serial.print(i);
Serial.println("(void){");
Serial.print(" callbackPCINT");
Serial.print(i);
Serial.println("();");
Serial.println("}");
Serial.println("#endif");
}
*/
#if (PCINT_USE_PCINT8 == true)
volatile callback callbackPCINT8 = pcint_null_callback;
void PinChangeInterruptEventPCINT8(void) {
callbackPCINT8();
}
#endif
#if (PCINT_USE_PCINT9 == true)
volatile callback callbackPCINT9 = pcint_null_callback;
void PinChangeInterruptEventPCINT9(void) {
callbackPCINT9();
}
#endif
#if (PCINT_USE_PCINT10 == true)
volatile callback callbackPCINT10 = pcint_null_callback;
void PinChangeInterruptEventPCINT10(void) {
callbackPCINT10();
}
#endif
#if (PCINT_USE_PCINT11 == true)
volatile callback callbackPCINT11 = pcint_null_callback;
void PinChangeInterruptEventPCINT11(void) {
callbackPCINT11();
}
#endif
#if (PCINT_USE_PCINT12 == true)
volatile callback callbackPCINT12 = pcint_null_callback;
void PinChangeInterruptEventPCINT12(void) {
callbackPCINT12();
}
#endif
#if (PCINT_USE_PCINT13 == true)
volatile callback callbackPCINT13 = pcint_null_callback;
void PinChangeInterruptEventPCINT13(void) {
callbackPCINT13();
}
#endif
#if (PCINT_USE_PCINT14 == true)
volatile callback callbackPCINT14 = pcint_null_callback;
void PinChangeInterruptEventPCINT14(void) {
callbackPCINT14();
}
#endif
#if (PCINT_USE_PCINT15 == true)
volatile callback callbackPCINT15 = pcint_null_callback;
void PinChangeInterruptEventPCINT15(void) {
callbackPCINT15();
}
#endif
#endif // PCINT_API
#endif // PCINT_USE_PORT1
#endif // PCINT_INCLUDE_FROM_CPP

View File

@@ -0,0 +1,149 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "PinChangeInterrupt.h"
//================================================================================
// Interrupt Handler
//================================================================================
// prevent compilation twice if included from the .cpp to force compile all ISRs
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \
|| !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR)
#if (PCINT_USE_PORT2 == true)
void attachPinChangeInterrupt2(void) {
// fake function to make the IDE link this file
}
ISR(PCINT2_vect) {
// get the new and old pin states for port
uint8_t newPort = PCINT_INPUT_PORT2;
// compare with the old value to detect a rising or falling
uint8_t arrayPos = getArrayPosPCINT(2);
uint8_t change = newPort ^ oldPorts[arrayPos];
uint8_t rising = change & newPort;
uint8_t falling = change & oldPorts[arrayPos];
// check which pins are triggered, compared with the settings
uint8_t risingTrigger = rising & risingPorts[arrayPos];
uint8_t fallingTrigger = falling & fallingPorts[arrayPos];
uint8_t trigger = risingTrigger | fallingTrigger;
// save the new state for next comparison
oldPorts[arrayPos] = newPort;
// Execute all functions that should be triggered
// This way we can exclude a single function
// and the calling is also much faster
// We may also reorder the pins for different priority
#if !defined(PCINT_CALLBACK_PORT2)
PCINT_CALLBACK(0, 16);
PCINT_CALLBACK(1, 17);
PCINT_CALLBACK(2, 18);
PCINT_CALLBACK(3, 19);
PCINT_CALLBACK(4, 20);
PCINT_CALLBACK(5, 21);
PCINT_CALLBACK(6, 22);
PCINT_CALLBACK(7, 23);
#else
PCINT_CALLBACK_PORT2
#endif
}
#if defined(PCINT_API)
/*
for (int i = 0; i < 32; i++) {
Serial.print("#if (PCINT_USE_PCINT");
Serial.print(i);
Serial.println(" == true)");
Serial.print("volatile callback callbackPCINT");
Serial.print(i);
Serial.println(" = pcint_null_callback;");
Serial.print("void PinChangeInterruptEventPCINT");
Serial.print(i);
Serial.println("(void){");
Serial.print(" callbackPCINT");
Serial.print(i);
Serial.println("();");
Serial.println("}");
Serial.println("#endif");
}
*/
#if (PCINT_USE_PCINT16 == true)
volatile callback callbackPCINT16 = pcint_null_callback;
void PinChangeInterruptEventPCINT16(void) {
callbackPCINT16();
}
#endif
#if (PCINT_USE_PCINT17 == true)
volatile callback callbackPCINT17 = pcint_null_callback;
void PinChangeInterruptEventPCINT17(void) {
callbackPCINT17();
}
#endif
#if (PCINT_USE_PCINT18 == true)
volatile callback callbackPCINT18 = pcint_null_callback;
void PinChangeInterruptEventPCINT18(void) {
callbackPCINT18();
}
#endif
#if (PCINT_USE_PCINT19 == true)
volatile callback callbackPCINT19 = pcint_null_callback;
void PinChangeInterruptEventPCINT19(void) {
callbackPCINT19();
}
#endif
#if (PCINT_USE_PCINT20 == true)
volatile callback callbackPCINT20 = pcint_null_callback;
void PinChangeInterruptEventPCINT20(void) {
callbackPCINT20();
}
#endif
#if (PCINT_USE_PCINT21 == true)
volatile callback callbackPCINT21 = pcint_null_callback;
void PinChangeInterruptEventPCINT21(void) {
callbackPCINT21();
}
#endif
#if (PCINT_USE_PCINT22 == true)
volatile callback callbackPCINT22 = pcint_null_callback;
void PinChangeInterruptEventPCINT22(void) {
callbackPCINT22();
}
#endif
#if (PCINT_USE_PCINT23 == true)
volatile callback callbackPCINT23 = pcint_null_callback;
void PinChangeInterruptEventPCINT23(void) {
callbackPCINT23();
}
#endif
#endif // PCINT_API
#endif // PCINT_USE_PORT2
#endif // PCINT_INCLUDE_FROM_CPP

View File

@@ -0,0 +1,149 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "PinChangeInterrupt.h"
//================================================================================
// Interrupt Handler
//================================================================================
// prevent compilation twice if included from the .cpp to force compile all ISRs
#if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \
|| !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR)
#if (PCINT_USE_PORT3 == true)
void attachPinChangeInterrupt3(void) {
// fake function to make the IDE link this file
}
ISR(PCINT3_vect) {
// get the new and old pin states for port
uint8_t newPort = PCINT_INPUT_PORT3;
// compare with the old value to detect a rising or falling
uint8_t arrayPos = getArrayPosPCINT(3);
uint8_t change = newPort ^ oldPorts[arrayPos];
uint8_t rising = change & newPort;
uint8_t falling = change & oldPorts[arrayPos];
// check which pins are triggered, compared with the settings
uint8_t risingTrigger = rising & risingPorts[arrayPos];
uint8_t fallingTrigger = falling & fallingPorts[arrayPos];
uint8_t trigger = risingTrigger | fallingTrigger;
// save the new state for next comparison
oldPorts[arrayPos] = newPort;
// Execute all functions that should be triggered
// This way we can exclude a single function
// and the calling is also much faster
// We may also reorder the pins for different priority
#if !defined(PCINT_CALLBACK_PORT3)
PCINT_CALLBACK(0, 24);
PCINT_CALLBACK(1, 25);
PCINT_CALLBACK(2, 26);
PCINT_CALLBACK(3, 27);
PCINT_CALLBACK(4, 28);
PCINT_CALLBACK(5, 29);
PCINT_CALLBACK(6, 30);
PCINT_CALLBACK(7, 31);
#else
PCINT_CALLBACK_PORT3
#endif
}
#if defined(PCINT_API)
/*
for (int i = 0; i < 32; i++) {
Serial.print("#if (PCINT_USE_PCINT");
Serial.print(i);
Serial.println(" == true)");
Serial.print("volatile callback callbackPCINT");
Serial.print(i);
Serial.println(" = pcint_null_callback;");
Serial.print("void PinChangeInterruptEventPCINT");
Serial.print(i);
Serial.println("(void){");
Serial.print(" callbackPCINT");
Serial.print(i);
Serial.println("();");
Serial.println("}");
Serial.println("#endif");
}
*/
#if (PCINT_USE_PCINT24 == true)
volatile callback callbackPCINT24 = pcint_null_callback;
void PinChangeInterruptEventPCINT24(void) {
callbackPCINT24();
}
#endif
#if (PCINT_USE_PCINT25 == true)
volatile callback callbackPCINT25 = pcint_null_callback;
void PinChangeInterruptEventPCINT25(void) {
callbackPCINT25();
}
#endif
#if (PCINT_USE_PCINT26 == true)
volatile callback callbackPCINT26 = pcint_null_callback;
void PinChangeInterruptEventPCINT26(void) {
callbackPCINT26();
}
#endif
#if (PCINT_USE_PCINT27 == true)
volatile callback callbackPCINT27 = pcint_null_callback;
void PinChangeInterruptEventPCINT27(void) {
callbackPCINT27();
}
#endif
#if (PCINT_USE_PCINT28 == true)
volatile callback callbackPCINT28 = pcint_null_callback;
void PinChangeInterruptEventPCINT28(void) {
callbackPCINT28();
}
#endif
#if (PCINT_USE_PCINT29 == true)
volatile callback callbackPCINT29 = pcint_null_callback;
void PinChangeInterruptEventPCINT29(void) {
callbackPCINT29();
}
#endif
#if (PCINT_USE_PCINT30 == true)
volatile callback callbackPCINT30 = pcint_null_callback;
void PinChangeInterruptEventPCINT30(void) {
callbackPCINT30();
}
#endif
#if (PCINT_USE_PCINT31 == true)
volatile callback callbackPCINT31 = pcint_null_callback;
void PinChangeInterruptEventPCINT31(void) {
callbackPCINT31();
}
#endif
#endif // PCINT_API
#endif // PCINT_USE_PORT3
#endif // PCINT_INCLUDE_FROM_CPP

View File

@@ -0,0 +1,174 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// include guard
#pragma once
//================================================================================
// Board Definitions
//================================================================================
// Microcontroller specific definitions
// Avr Variants are defined here: https://svn.savannah.gnu.org/viewvc/avr-libc/trunk/avr-libc/include/avr/io.h?view=markup
#if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328A__) || defined(__AVR_ATmega328PA__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) \
|| defined(__AVR_ATmega168__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168PB__) \
|| defined(__AVR_ATmega88__) || defined(__AVR_ATmega88A__) || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88PB__) \
|| defined(__AVR_ATmega48__) || defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega48PB__)
// Arduino Uno
#define PCINT_INPUT_PORT0 PINB
#define PCINT_INPUT_PORT1 PINC
#define PCINT_INPUT_PORT2 PIND
#if defined(__AVR_ATmega328PB__)
#define PCINT_INPUT_PORT3 PINE
#endif
#elif defined(__AVR_ATmega162__)
#define PCINT_INPUT_PORT0 PINA
#define PCINT_INPUT_PORT1 PINC
#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega640__)
// Arduino Mega/Mega2560
#define PCINT_INPUT_PORT0 PINB
#define PCINT_INPUT_PORT2 PINK
// special Port1 case, pins are on 2 HW Pin Ports (E,J)
#if defined(PCINT_ENABLE_PCINT16) // PortE
#if defined(PCINT_ENABLE_PCINT17) || defined(PCINT_ENABLE_PCINT18) \
|| defined(PCINT_ENABLE_PCINT19) || defined(PCINT_ENABLE_PCINT20) \
|| defined(PCINT_ENABLE_PCINT21) || defined(PCINT_ENABLE_PCINT22) \
|| defined(PCINT_ENABLE_PCINT23) // PortJ
// PortE and PortJ selected
#define PCINT_INPUT_PORT1 ((PINE & 0x01) | (PINJ << 1))
#else
// PortE only selected
#define PCINT_INPUT_PORT1 PINE
#endif
#else
// PortJ only selected
// we still have to do the shift because the attach
// function is not designed for this optimization
#define PCINT_INPUT_PORT1 (PINJ << 1)
#endif
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
// Arduino Leonardo/Micro
#define PCINT_INPUT_PORT0 PINB
#elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
// u2 Series/HoodLoader2
// u2 Series has crappy pin mappings for port 1
#define PCINT_INPUT_PORT0 PINB
#define PCINT_INPUT_PORT1 (((PINC >> 6) & (1 << 0)) | ((PINC >> 4) & (1 << 1)) | ((PINC >> 2) & (1 << 2)) | ((PINC << 1) & (1 << 3)) | ((PIND >> 1) & (1 << 4)))
#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
// Attiny x5
#define PCINT_INPUT_PORT0 PINB
#elif defined(__AVR_ATtiny13__)
// Attiny 13A
#define PCINT_INPUT_PORT0 PINB
// This is just a workaround for the missing definition in the following core: https://sourceforge.net/projects/ard-core13/
// It should work fine with: https://github.com/MCUdude/MicroCore
#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
#define PCINT_INPUT_PORT1 PINB
#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
// 1284p and 644p, special 4 port case
#define PCINT_INPUT_PORT0 PINA
#define PCINT_INPUT_PORT1 PINB
#define PCINT_INPUT_PORT2 PINC
#define PCINT_INPUT_PORT3 PIND
#elif defined(__AVR_ATtinyX41__) || defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny841__)
// Attiny x41
#define PCINT_INPUT_PORT0 PINA
#define PCINT_INPUT_PORT1 PINB
// "iotn841.h" is missing those definitions, so we add them here
#define PCINT0 0
#define PCINT1 1
#define PCINT2 2
#define PCINT3 3
#define PCINT4 4
#define PCINT5 5
#define PCINT6 6
#define PCINT7 7
#define PCINT8 0
#define PCINT9 1
#define PCINT10 2
#define PCINT11 3
#elif defined(__AVR_ATtiny2313__)
#define PCINT_INPUT_PORT0 PINB
#elif defined(__AVR_ATtiny2313A__) || defined(__AVR_ATtiny4313__)
// All 8 pins
#define PCINT_INPUT_PORT0 PINB
// PinA has 3 PCINTs on the reset and clock lines, we do not use this port
// PIND has 7 pins available, but the pin ordering is so messed up,
// that it does not work with the current library structure.
#elif defined(__AVR_ATtiny261__) || defined(__AVR_ATtiny461__) || defined(__AVR_ATtiny861__)
// PORTB has Reset, clock and SPI while PORTA has I2C and Analog Pins. We just enable all pins.
#define PCINT_INPUT_PORT0 PINA
#define PCINT_INPUT_PORT1 PINB
#else // Microcontroller not supported
#error PinChangeInterrupt library does not support this MCU.
#endif
//================================================================================
// Add missing definitions
//================================================================================
// 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

View File

@@ -0,0 +1,926 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// include guard
#pragma once
/*
The strategy in this file:
0. Makefile optimization:
To disable PCINT/PORTs via makefile use -DPCINT_DISABLE_PORT0 etc.
This will undef a previously defined PCINT_ENABLE_PORT0.
1. Reduce the user settings to the enabled pins.
If the whole port is deactivated, also disable all pins on this port.
2. Define the hardware available pins/ports.
3. Compare the hardware definition with the enabled pin definitions.
If the pin is available and enabled, create a makro to use the pin.
4. Count all used pins (for each port).
5. If there are no pins used on a port, do not use the port
6. Finally we have a clear defintion of the used pins/ports like this:
PCINT_USE_PCINT0 (true/false)
PCINT_USE_PORT0 (true/false)
Other definitions that can be used:
PCINT_HAS_PORT0 (true/false)
PCINT_HAS_PCINT0 (true/false)
PCINT_NUM_PINS_PORT0 (0-8)
PCINT_NUM_USED_PINS_PORT0 (0-8)
EXTERNAL_NUM_PINCHANGEINTERRUPT (0-24)
EXTERNAL_NUM_USED_PINCHANGEINTERRUPT (0-24)
PCINT_NUM_PORTS (0-3)
PCINT_NUM_USED_PORTS (0-3)
*/
//================================================================================
// Disabled Pins
//================================================================================
/*
for (int port = 0; port < 4; port++) {
Serial.print("#if defined(PCINT_ENABLE_PORT");
Serial.print(port);
Serial.print(") && defined(PCINT_DISABLE_PORT");
Serial.print(port);
Serial.println(")");
Serial.print("#undef PCINT_ENABLE_PORT");
Serial.println(port);
Serial.println("#endif");
Serial.println();
}
for (int i = 0; i < 32; i++) {
Serial.print("#if defined(PCINT_ENABLE_PCINT");
Serial.print(i);
Serial.print(") && defined(PCINT_DISABLE_PCINT");
Serial.print(i);
Serial.println(")");
Serial.print("#undef PCINT_ENABLE_PCINT");
Serial.println(i);
Serial.println("#endif");
Serial.println();
}
*/
#if defined(PCINT_ENABLE_PORT0) && defined(PCINT_DISABLE_PORT0)
#undef PCINT_ENABLE_PORT0
#endif
#if defined(PCINT_ENABLE_PORT1) && defined(PCINT_DISABLE_PORT1)
#undef PCINT_ENABLE_PORT1
#endif
#if defined(PCINT_ENABLE_PORT2) && defined(PCINT_DISABLE_PORT2)
#undef PCINT_ENABLE_PORT2
#endif
#if defined(PCINT_ENABLE_PORT3) && defined(PCINT_DISABLE_PORT3)
#undef PCINT_ENABLE_PORT3
#endif
#if defined(PCINT_ENABLE_PCINT0) && defined(PCINT_DISABLE_PCINT0)
#undef PCINT_ENABLE_PCINT0
#endif
#if defined(PCINT_ENABLE_PCINT1) && defined(PCINT_DISABLE_PCINT1)
#undef PCINT_ENABLE_PCINT1
#endif
#if defined(PCINT_ENABLE_PCINT2) && defined(PCINT_DISABLE_PCINT2)
#undef PCINT_ENABLE_PCINT2
#endif
#if defined(PCINT_ENABLE_PCINT3) && defined(PCINT_DISABLE_PCINT3)
#undef PCINT_ENABLE_PCINT3
#endif
#if defined(PCINT_ENABLE_PCINT4) && defined(PCINT_DISABLE_PCINT4)
#undef PCINT_ENABLE_PCINT4
#endif
#if defined(PCINT_ENABLE_PCINT5) && defined(PCINT_DISABLE_PCINT5)
#undef PCINT_ENABLE_PCINT5
#endif
#if defined(PCINT_ENABLE_PCINT6) && defined(PCINT_DISABLE_PCINT6)
#undef PCINT_ENABLE_PCINT6
#endif
#if defined(PCINT_ENABLE_PCINT7) && defined(PCINT_DISABLE_PCINT7)
#undef PCINT_ENABLE_PCINT7
#endif
#if defined(PCINT_ENABLE_PCINT8) && defined(PCINT_DISABLE_PCINT8)
#undef PCINT_ENABLE_PCINT8
#endif
#if defined(PCINT_ENABLE_PCINT9) && defined(PCINT_DISABLE_PCINT9)
#undef PCINT_ENABLE_PCINT9
#endif
#if defined(PCINT_ENABLE_PCINT10) && defined(PCINT_DISABLE_PCINT10)
#undef PCINT_ENABLE_PCINT10
#endif
#if defined(PCINT_ENABLE_PCINT11) && defined(PCINT_DISABLE_PCINT11)
#undef PCINT_ENABLE_PCINT11
#endif
#if defined(PCINT_ENABLE_PCINT12) && defined(PCINT_DISABLE_PCINT12)
#undef PCINT_ENABLE_PCINT12
#endif
#if defined(PCINT_ENABLE_PCINT13) && defined(PCINT_DISABLE_PCINT13)
#undef PCINT_ENABLE_PCINT13
#endif
#if defined(PCINT_ENABLE_PCINT14) && defined(PCINT_DISABLE_PCINT14)
#undef PCINT_ENABLE_PCINT14
#endif
#if defined(PCINT_ENABLE_PCINT15) && defined(PCINT_DISABLE_PCINT15)
#undef PCINT_ENABLE_PCINT15
#endif
#if defined(PCINT_ENABLE_PCINT16) && defined(PCINT_DISABLE_PCINT16)
#undef PCINT_ENABLE_PCINT16
#endif
#if defined(PCINT_ENABLE_PCINT17) && defined(PCINT_DISABLE_PCINT17)
#undef PCINT_ENABLE_PCINT17
#endif
#if defined(PCINT_ENABLE_PCINT18) && defined(PCINT_DISABLE_PCINT18)
#undef PCINT_ENABLE_PCINT18
#endif
#if defined(PCINT_ENABLE_PCINT19) && defined(PCINT_DISABLE_PCINT19)
#undef PCINT_ENABLE_PCINT19
#endif
#if defined(PCINT_ENABLE_PCINT20) && defined(PCINT_DISABLE_PCINT20)
#undef PCINT_ENABLE_PCINT20
#endif
#if defined(PCINT_ENABLE_PCINT21) && defined(PCINT_DISABLE_PCINT21)
#undef PCINT_ENABLE_PCINT21
#endif
#if defined(PCINT_ENABLE_PCINT22) && defined(PCINT_DISABLE_PCINT22)
#undef PCINT_ENABLE_PCINT22
#endif
#if defined(PCINT_ENABLE_PCINT23) && defined(PCINT_DISABLE_PCINT23)
#undef PCINT_ENABLE_PCINT23
#endif
#if defined(PCINT_ENABLE_PCINT24) && defined(PCINT_DISABLE_PCINT24)
#undef PCINT_ENABLE_PCINT24
#endif
#if defined(PCINT_ENABLE_PCINT25) && defined(PCINT_DISABLE_PCINT25)
#undef PCINT_ENABLE_PCINT25
#endif
#if defined(PCINT_ENABLE_PCINT26) && defined(PCINT_DISABLE_PCINT26)
#undef PCINT_ENABLE_PCINT26
#endif
#if defined(PCINT_ENABLE_PCINT27) && defined(PCINT_DISABLE_PCINT27)
#undef PCINT_ENABLE_PCINT27
#endif
#if defined(PCINT_ENABLE_PCINT28) && defined(PCINT_DISABLE_PCINT28)
#undef PCINT_ENABLE_PCINT28
#endif
#if defined(PCINT_ENABLE_PCINT29) && defined(PCINT_DISABLE_PCINT29)
#undef PCINT_ENABLE_PCINT29
#endif
#if defined(PCINT_ENABLE_PCINT30) && defined(PCINT_DISABLE_PCINT30)
#undef PCINT_ENABLE_PCINT30
#endif
#if defined(PCINT_ENABLE_PCINT31) && defined(PCINT_DISABLE_PCINT31)
#undef PCINT_ENABLE_PCINT31
#endif
//================================================================================
// Enabled Pins
//================================================================================
/* Disable all pins on a port, if port is deactivated
We could then check every pin -> port definition
But that'd be a mess and doesnt help
Users who deactivate stuff should know
what the are doing.
So we use the enabled pins for all next definitions*/
/*
for (int port = 0; port < 4; port++) {
Serial.print("#if !defined(PCINT_ENABLE_PORT");
Serial.print(port);
Serial.println(")");
for (int i = 0; i < 8; i++) {
Serial.print("#if defined(PCINT_ENABLE_PCINT");
Serial.print(port * 8 + i);
Serial.println(")");
Serial.print("#undef PCINT_ENABLE_PCINT");
Serial.println(port * 8 + i);
Serial.println("#endif");
}
Serial.println("#endif");
Serial.println();
}
*/
#if !defined(PCINT_ENABLE_PORT0)
#if defined(PCINT_ENABLE_PCINT0)
#undef PCINT_ENABLE_PCINT0
#endif
#if defined(PCINT_ENABLE_PCINT1)
#undef PCINT_ENABLE_PCINT1
#endif
#if defined(PCINT_ENABLE_PCINT2)
#undef PCINT_ENABLE_PCINT2
#endif
#if defined(PCINT_ENABLE_PCINT3)
#undef PCINT_ENABLE_PCINT3
#endif
#if defined(PCINT_ENABLE_PCINT4)
#undef PCINT_ENABLE_PCINT4
#endif
#if defined(PCINT_ENABLE_PCINT5)
#undef PCINT_ENABLE_PCINT5
#endif
#if defined(PCINT_ENABLE_PCINT6)
#undef PCINT_ENABLE_PCINT6
#endif
#if defined(PCINT_ENABLE_PCINT7)
#undef PCINT_ENABLE_PCINT7
#endif
#endif
#if !defined(PCINT_ENABLE_PORT1)
#if defined(PCINT_ENABLE_PCINT8)
#undef PCINT_ENABLE_PCINT8
#endif
#if defined(PCINT_ENABLE_PCINT9)
#undef PCINT_ENABLE_PCINT9
#endif
#if defined(PCINT_ENABLE_PCINT10)
#undef PCINT_ENABLE_PCINT10
#endif
#if defined(PCINT_ENABLE_PCINT11)
#undef PCINT_ENABLE_PCINT11
#endif
#if defined(PCINT_ENABLE_PCINT12)
#undef PCINT_ENABLE_PCINT12
#endif
#if defined(PCINT_ENABLE_PCINT13)
#undef PCINT_ENABLE_PCINT13
#endif
#if defined(PCINT_ENABLE_PCINT14)
#undef PCINT_ENABLE_PCINT14
#endif
#if defined(PCINT_ENABLE_PCINT15)
#undef PCINT_ENABLE_PCINT15
#endif
#endif
#if !defined(PCINT_ENABLE_PORT2)
#if defined(PCINT_ENABLE_PCINT16)
#undef PCINT_ENABLE_PCINT16
#endif
#if defined(PCINT_ENABLE_PCINT17)
#undef PCINT_ENABLE_PCINT17
#endif
#if defined(PCINT_ENABLE_PCINT18)
#undef PCINT_ENABLE_PCINT18
#endif
#if defined(PCINT_ENABLE_PCINT19)
#undef PCINT_ENABLE_PCINT19
#endif
#if defined(PCINT_ENABLE_PCINT20)
#undef PCINT_ENABLE_PCINT20
#endif
#if defined(PCINT_ENABLE_PCINT21)
#undef PCINT_ENABLE_PCINT21
#endif
#if defined(PCINT_ENABLE_PCINT22)
#undef PCINT_ENABLE_PCINT22
#endif
#if defined(PCINT_ENABLE_PCINT23)
#undef PCINT_ENABLE_PCINT23
#endif
#endif
#if !defined(PCINT_ENABLE_PORT3)
#if defined(PCINT_ENABLE_PCINT24)
#undef PCINT_ENABLE_PCINT24
#endif
#if defined(PCINT_ENABLE_PCINT25)
#undef PCINT_ENABLE_PCINT25
#endif
#if defined(PCINT_ENABLE_PCINT26)
#undef PCINT_ENABLE_PCINT26
#endif
#if defined(PCINT_ENABLE_PCINT27)
#undef PCINT_ENABLE_PCINT27
#endif
#if defined(PCINT_ENABLE_PCINT28)
#undef PCINT_ENABLE_PCINT28
#endif
#if defined(PCINT_ENABLE_PCINT29)
#undef PCINT_ENABLE_PCINT29
#endif
#if defined(PCINT_ENABLE_PCINT30)
#undef PCINT_ENABLE_PCINT30
#endif
#if defined(PCINT_ENABLE_PCINT31)
#undef PCINT_ENABLE_PCINT31
#endif
#endif
//================================================================================
// Hardware Definitions
//================================================================================
#if defined(PCINT0_vect)
#define PCINT_HAS_PORT0 true
#else
#define PCINT_HAS_PORT0 false
#endif
#if defined(PCINT1_vect)
#define PCINT_HAS_PORT1 true
#else
#define PCINT_HAS_PORT1 false
#endif
#if defined(PCINT2_vect)
#define PCINT_HAS_PORT2 true
#else
#define PCINT_HAS_PORT2 false
#endif
#if defined(PCINT3_vect)
#define PCINT_HAS_PORT3 true
#else
#define PCINT_HAS_PORT3 false
#endif
// number of available ports
#define PCINT_NUM_PORTS ( \
PCINT_HAS_PORT0 + \
PCINT_HAS_PORT1 + \
PCINT_HAS_PORT2 + \
PCINT_HAS_PORT3)
/*
for (int i = 0; i < 32; i++) {
Serial.print("#ifdef PCINT");
Serial.println(i);
Serial.print("#define PCINT_HAS_PCINT");
Serial.print(i);
Serial.println(" true");
Serial.println("#else");
Serial.print("#define PCINT_HAS_PCINT");
Serial.print(i);
Serial.println(" false");
Serial.println("#endif");
}
*/
#ifdef PCINT0
#define PCINT_HAS_PCINT0 true
#else
#define PCINT_HAS_PCINT0 false
#endif
#ifdef PCINT1
#define PCINT_HAS_PCINT1 true
#else
#define PCINT_HAS_PCINT1 false
#endif
#ifdef PCINT2
#define PCINT_HAS_PCINT2 true
#else
#define PCINT_HAS_PCINT2 false
#endif
#ifdef PCINT3
#define PCINT_HAS_PCINT3 true
#else
#define PCINT_HAS_PCINT3 false
#endif
#ifdef PCINT4
#define PCINT_HAS_PCINT4 true
#else
#define PCINT_HAS_PCINT4 false
#endif
#ifdef PCINT5
#define PCINT_HAS_PCINT5 true
#else
#define PCINT_HAS_PCINT5 false
#endif
#ifdef PCINT6
#define PCINT_HAS_PCINT6 true
#else
#define PCINT_HAS_PCINT6 false
#endif
#ifdef PCINT7
#define PCINT_HAS_PCINT7 true
#else
#define PCINT_HAS_PCINT7 false
#endif
#ifdef PCINT8
#define PCINT_HAS_PCINT8 true
#else
#define PCINT_HAS_PCINT8 false
#endif
#ifdef PCINT9
#define PCINT_HAS_PCINT9 true
#else
#define PCINT_HAS_PCINT9 false
#endif
#ifdef PCINT10
#define PCINT_HAS_PCINT10 true
#else
#define PCINT_HAS_PCINT10 false
#endif
#ifdef PCINT11
#define PCINT_HAS_PCINT11 true
#else
#define PCINT_HAS_PCINT11 false
#endif
#ifdef PCINT12
#define PCINT_HAS_PCINT12 true
#else
#define PCINT_HAS_PCINT12 false
#endif
#ifdef PCINT13
#define PCINT_HAS_PCINT13 true
#else
#define PCINT_HAS_PCINT13 false
#endif
#ifdef PCINT14
#define PCINT_HAS_PCINT14 true
#else
#define PCINT_HAS_PCINT14 false
#endif
#ifdef PCINT15
#define PCINT_HAS_PCINT15 true
#else
#define PCINT_HAS_PCINT15 false
#endif
#ifdef PCINT16
#define PCINT_HAS_PCINT16 true
#else
#define PCINT_HAS_PCINT16 false
#endif
#ifdef PCINT17
#define PCINT_HAS_PCINT17 true
#else
#define PCINT_HAS_PCINT17 false
#endif
#ifdef PCINT18
#define PCINT_HAS_PCINT18 true
#else
#define PCINT_HAS_PCINT18 false
#endif
#ifdef PCINT19
#define PCINT_HAS_PCINT19 true
#else
#define PCINT_HAS_PCINT19 false
#endif
#ifdef PCINT20
#define PCINT_HAS_PCINT20 true
#else
#define PCINT_HAS_PCINT20 false
#endif
#ifdef PCINT21
#define PCINT_HAS_PCINT21 true
#else
#define PCINT_HAS_PCINT21 false
#endif
#ifdef PCINT22
#define PCINT_HAS_PCINT22 true
#else
#define PCINT_HAS_PCINT22 false
#endif
#ifdef PCINT23
#define PCINT_HAS_PCINT23 true
#else
#define PCINT_HAS_PCINT23 false
#endif
#ifdef PCINT24
#define PCINT_HAS_PCINT24 true
#else
#define PCINT_HAS_PCINT24 false
#endif
#ifdef PCINT25
#define PCINT_HAS_PCINT25 true
#else
#define PCINT_HAS_PCINT25 false
#endif
#ifdef PCINT26
#define PCINT_HAS_PCINT26 true
#else
#define PCINT_HAS_PCINT26 false
#endif
#ifdef PCINT27
#define PCINT_HAS_PCINT27 true
#else
#define PCINT_HAS_PCINT27 false
#endif
#ifdef PCINT28
#define PCINT_HAS_PCINT28 true
#else
#define PCINT_HAS_PCINT28 false
#endif
#ifdef PCINT29
#define PCINT_HAS_PCINT29 true
#else
#define PCINT_HAS_PCINT29 false
#endif
#ifdef PCINT30
#define PCINT_HAS_PCINT30 true
#else
#define PCINT_HAS_PCINT30 false
#endif
#ifdef PCINT31
#define PCINT_HAS_PCINT31 true
#else
#define PCINT_HAS_PCINT31 false
#endif
// count numbers of available pins on each port
/*
for (int port = 0; port < 4; port++) {
Serial.print("#define PCINT_NUM_PINS_PORT");
Serial.print(port);
Serial.println(" ( \\");
for (int i = 0; i < 8; i++) {
Serial.print("PCINT_HAS_PCINT");
Serial.print(port * 8 + i);
if (i != 7)
Serial.println(" + \\");
}
Serial.println(")");
Serial.println();
}
*/
#define PCINT_NUM_PINS_PORT0 ( \
PCINT_HAS_PCINT0 + \
PCINT_HAS_PCINT1 + \
PCINT_HAS_PCINT2 + \
PCINT_HAS_PCINT3 + \
PCINT_HAS_PCINT4 + \
PCINT_HAS_PCINT5 + \
PCINT_HAS_PCINT6 + \
PCINT_HAS_PCINT7)
#define PCINT_NUM_PINS_PORT1 ( \
PCINT_HAS_PCINT8 + \
PCINT_HAS_PCINT9 + \
PCINT_HAS_PCINT10 + \
PCINT_HAS_PCINT11 + \
PCINT_HAS_PCINT12 + \
PCINT_HAS_PCINT13 + \
PCINT_HAS_PCINT14 + \
PCINT_HAS_PCINT15)
#define PCINT_NUM_PINS_PORT2 ( \
PCINT_HAS_PCINT16 + \
PCINT_HAS_PCINT17 + \
PCINT_HAS_PCINT18 + \
PCINT_HAS_PCINT19 + \
PCINT_HAS_PCINT20 + \
PCINT_HAS_PCINT21 + \
PCINT_HAS_PCINT22 + \
PCINT_HAS_PCINT23)
#define PCINT_NUM_PINS_PORT3 ( \
PCINT_HAS_PCINT24 + \
PCINT_HAS_PCINT25 + \
PCINT_HAS_PCINT26 + \
PCINT_HAS_PCINT27 + \
PCINT_HAS_PCINT28 + \
PCINT_HAS_PCINT29 + \
PCINT_HAS_PCINT30 + \
PCINT_HAS_PCINT31)
// number of available hardware pins
#define EXTERNAL_NUM_PINCHANGEINTERRUPT ( \
PCINT_NUM_PINS_PORT0 + \
PCINT_NUM_PINS_PORT1 + \
PCINT_NUM_PINS_PORT2 + \
PCINT_NUM_PINS_PORT3)
//================================================================================
// Used Pins
//================================================================================
// check if pins are physically available and enabled
/*
for (int i = 0; i < 32; i++) {
Serial.print("#if (PCINT_HAS_PCINT");
Serial.print(i);
Serial.print(" == true) && defined(PCINT_ENABLE_PCINT");
Serial.print(i);
Serial.println(")");
Serial.print("#define PCINT_USE_PCINT");
Serial.print(i);
Serial.println(" true");
Serial.println("#else");
Serial.print("#define PCINT_USE_PCINT");
Serial.print(i);
Serial.println(" false");
Serial.println("#endif");
}
*/
#if (PCINT_HAS_PCINT0 == true) && defined(PCINT_ENABLE_PCINT0)
#define PCINT_USE_PCINT0 true
#else
#define PCINT_USE_PCINT0 false
#endif
#if (PCINT_HAS_PCINT1 == true) && defined(PCINT_ENABLE_PCINT1)
#define PCINT_USE_PCINT1 true
#else
#define PCINT_USE_PCINT1 false
#endif
#if (PCINT_HAS_PCINT2 == true) && defined(PCINT_ENABLE_PCINT2)
#define PCINT_USE_PCINT2 true
#else
#define PCINT_USE_PCINT2 false
#endif
#if (PCINT_HAS_PCINT3 == true) && defined(PCINT_ENABLE_PCINT3)
#define PCINT_USE_PCINT3 true
#else
#define PCINT_USE_PCINT3 false
#endif
#if (PCINT_HAS_PCINT4 == true) && defined(PCINT_ENABLE_PCINT4)
#define PCINT_USE_PCINT4 true
#else
#define PCINT_USE_PCINT4 false
#endif
#if (PCINT_HAS_PCINT5 == true) && defined(PCINT_ENABLE_PCINT5)
#define PCINT_USE_PCINT5 true
#else
#define PCINT_USE_PCINT5 false
#endif
#if (PCINT_HAS_PCINT6 == true) && defined(PCINT_ENABLE_PCINT6)
#define PCINT_USE_PCINT6 true
#else
#define PCINT_USE_PCINT6 false
#endif
#if (PCINT_HAS_PCINT7 == true) && defined(PCINT_ENABLE_PCINT7)
#define PCINT_USE_PCINT7 true
#else
#define PCINT_USE_PCINT7 false
#endif
#if (PCINT_HAS_PCINT8 == true) && defined(PCINT_ENABLE_PCINT8)
#define PCINT_USE_PCINT8 true
#else
#define PCINT_USE_PCINT8 false
#endif
#if (PCINT_HAS_PCINT9 == true) && defined(PCINT_ENABLE_PCINT9)
#define PCINT_USE_PCINT9 true
#else
#define PCINT_USE_PCINT9 false
#endif
#if (PCINT_HAS_PCINT10 == true) && defined(PCINT_ENABLE_PCINT10)
#define PCINT_USE_PCINT10 true
#else
#define PCINT_USE_PCINT10 false
#endif
#if (PCINT_HAS_PCINT11 == true) && defined(PCINT_ENABLE_PCINT11)
#define PCINT_USE_PCINT11 true
#else
#define PCINT_USE_PCINT11 false
#endif
#if (PCINT_HAS_PCINT12 == true) && defined(PCINT_ENABLE_PCINT12)
#define PCINT_USE_PCINT12 true
#else
#define PCINT_USE_PCINT12 false
#endif
#if (PCINT_HAS_PCINT13 == true) && defined(PCINT_ENABLE_PCINT13)
#define PCINT_USE_PCINT13 true
#else
#define PCINT_USE_PCINT13 false
#endif
#if (PCINT_HAS_PCINT14 == true) && defined(PCINT_ENABLE_PCINT14)
#define PCINT_USE_PCINT14 true
#else
#define PCINT_USE_PCINT14 false
#endif
#if (PCINT_HAS_PCINT15 == true) && defined(PCINT_ENABLE_PCINT15)
#define PCINT_USE_PCINT15 true
#else
#define PCINT_USE_PCINT15 false
#endif
#if (PCINT_HAS_PCINT16 == true) && defined(PCINT_ENABLE_PCINT16)
#define PCINT_USE_PCINT16 true
#else
#define PCINT_USE_PCINT16 false
#endif
#if (PCINT_HAS_PCINT17 == true) && defined(PCINT_ENABLE_PCINT17)
#define PCINT_USE_PCINT17 true
#else
#define PCINT_USE_PCINT17 false
#endif
#if (PCINT_HAS_PCINT18 == true) && defined(PCINT_ENABLE_PCINT18)
#define PCINT_USE_PCINT18 true
#else
#define PCINT_USE_PCINT18 false
#endif
#if (PCINT_HAS_PCINT19 == true) && defined(PCINT_ENABLE_PCINT19)
#define PCINT_USE_PCINT19 true
#else
#define PCINT_USE_PCINT19 false
#endif
#if (PCINT_HAS_PCINT20 == true) && defined(PCINT_ENABLE_PCINT20)
#define PCINT_USE_PCINT20 true
#else
#define PCINT_USE_PCINT20 false
#endif
#if (PCINT_HAS_PCINT21 == true) && defined(PCINT_ENABLE_PCINT21)
#define PCINT_USE_PCINT21 true
#else
#define PCINT_USE_PCINT21 false
#endif
#if (PCINT_HAS_PCINT22 == true) && defined(PCINT_ENABLE_PCINT22)
#define PCINT_USE_PCINT22 true
#else
#define PCINT_USE_PCINT22 false
#endif
#if (PCINT_HAS_PCINT23 == true) && defined(PCINT_ENABLE_PCINT23)
#define PCINT_USE_PCINT23 true
#else
#define PCINT_USE_PCINT23 false
#endif
#if (PCINT_HAS_PCINT24 == true) && defined(PCINT_ENABLE_PCINT24)
#define PCINT_USE_PCINT24 true
#else
#define PCINT_USE_PCINT24 false
#endif
#if (PCINT_HAS_PCINT25 == true) && defined(PCINT_ENABLE_PCINT25)
#define PCINT_USE_PCINT25 true
#else
#define PCINT_USE_PCINT25 false
#endif
#if (PCINT_HAS_PCINT26 == true) && defined(PCINT_ENABLE_PCINT26)
#define PCINT_USE_PCINT26 true
#else
#define PCINT_USE_PCINT26 false
#endif
#if (PCINT_HAS_PCINT27 == true) && defined(PCINT_ENABLE_PCINT27)
#define PCINT_USE_PCINT27 true
#else
#define PCINT_USE_PCINT27 false
#endif
#if (PCINT_HAS_PCINT28 == true) && defined(PCINT_ENABLE_PCINT28)
#define PCINT_USE_PCINT28 true
#else
#define PCINT_USE_PCINT28 false
#endif
#if (PCINT_HAS_PCINT29 == true) && defined(PCINT_ENABLE_PCINT29)
#define PCINT_USE_PCINT29 true
#else
#define PCINT_USE_PCINT29 false
#endif
#if (PCINT_HAS_PCINT30 == true) && defined(PCINT_ENABLE_PCINT30)
#define PCINT_USE_PCINT30 true
#else
#define PCINT_USE_PCINT30 false
#endif
#if (PCINT_HAS_PCINT31 == true) && defined(PCINT_ENABLE_PCINT31)
#define PCINT_USE_PCINT31 true
#else
#define PCINT_USE_PCINT31 false
#endif
//================================================================================
// Number Used Pins
//================================================================================
// count numbers of used pins on each port
/*
for (int port = 0; port < 4; port++) {
Serial.print("#define PCINT_NUM_USED_PINS_PORT");
Serial.print(port);
Serial.println(" ( \\");
for (int i = 0; i < 8; i++) {
Serial.print("PCINT_USE_PCINT");
Serial.print(port * 8 + i);
if (i != 7)
Serial.println(" + \\");
}
Serial.println(")");
Serial.println();
}
*/
#define PCINT_NUM_USED_PINS_PORT0 ( \
PCINT_USE_PCINT0 + \
PCINT_USE_PCINT1 + \
PCINT_USE_PCINT2 + \
PCINT_USE_PCINT3 + \
PCINT_USE_PCINT4 + \
PCINT_USE_PCINT5 + \
PCINT_USE_PCINT6 + \
PCINT_USE_PCINT7)
#define PCINT_NUM_USED_PINS_PORT1 ( \
PCINT_USE_PCINT8 + \
PCINT_USE_PCINT9 + \
PCINT_USE_PCINT10 + \
PCINT_USE_PCINT11 + \
PCINT_USE_PCINT12 + \
PCINT_USE_PCINT13 + \
PCINT_USE_PCINT14 + \
PCINT_USE_PCINT15)
#define PCINT_NUM_USED_PINS_PORT2 ( \
PCINT_USE_PCINT16 + \
PCINT_USE_PCINT17 + \
PCINT_USE_PCINT18 + \
PCINT_USE_PCINT19 + \
PCINT_USE_PCINT20 + \
PCINT_USE_PCINT21 + \
PCINT_USE_PCINT22 + \
PCINT_USE_PCINT23)
#define PCINT_NUM_USED_PINS_PORT3 ( \
PCINT_USE_PCINT24 + \
PCINT_USE_PCINT25 + \
PCINT_USE_PCINT26 + \
PCINT_USE_PCINT27 + \
PCINT_USE_PCINT28 + \
PCINT_USE_PCINT29 + \
PCINT_USE_PCINT30 + \
PCINT_USE_PCINT31)
// number of used hardware pins
#define EXTERNAL_NUM_USED_PINCHANGEINTERRUPT ( \
PCINT_NUM_USED_PINS_PORT0 + \
PCINT_NUM_USED_PINS_PORT1 + \
PCINT_NUM_USED_PINS_PORT2 + \
PCINT_NUM_USED_PINS_PORT3)
//================================================================================
// Used Ports
//================================================================================
// check if ports are used
#if PCINT_NUM_USED_PINS_PORT0
#define PCINT_USE_PORT0 true
#else
#define PCINT_USE_PORT0 false
#endif
#if PCINT_NUM_USED_PINS_PORT1
#define PCINT_USE_PORT1 true
#else
#define PCINT_USE_PORT1 false
#endif
#if PCINT_NUM_USED_PINS_PORT2
#define PCINT_USE_PORT2 true
#else
#define PCINT_USE_PORT2 false
#endif
#if PCINT_NUM_USED_PINS_PORT3
#define PCINT_USE_PORT3 true
#else
#define PCINT_USE_PORT3 false
#endif
// number of used ports
#define PCINT_NUM_USED_PORTS ( \
PCINT_USE_PORT0 + \
PCINT_USE_PORT1 + \
PCINT_USE_PORT2 + \
PCINT_USE_PORT3)

View File

@@ -0,0 +1,230 @@
/*
Copyright (c) 2014-2021 NicoHood
See the readme for credit to other people.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// include guard
#pragma once
//================================================================================
// General Settings
//================================================================================
/* Settings to de/activate ports/pins
This will save you flash and ram because the arrays
are managed dynamically with the definitions below.
Make sure you still have all needed ports activated.
Each deactivated port saves 3 bytes of ram.
If you deactivate the whole port,
you dont need to deactivate the pins.
Same for the port if you deactivate all 8 pins.
You dont have to deactivate pins/ports that dont exist.
That is done by the macros. */
#ifndef PCINT_ENABLE_MANUAL
#define PCINT_ENABLE_PORT0
#define PCINT_ENABLE_PORT1
#define PCINT_ENABLE_PORT2
#define PCINT_ENABLE_PORT3
#define PCINT_ENABLE_PCINT0
#define PCINT_ENABLE_PCINT1
#define PCINT_ENABLE_PCINT2
#define PCINT_ENABLE_PCINT3
#define PCINT_ENABLE_PCINT4
#define PCINT_ENABLE_PCINT5
#define PCINT_ENABLE_PCINT6
#define PCINT_ENABLE_PCINT7
#define PCINT_ENABLE_PCINT8
#define PCINT_ENABLE_PCINT9
#define PCINT_ENABLE_PCINT10
#define PCINT_ENABLE_PCINT11
#define PCINT_ENABLE_PCINT12
#define PCINT_ENABLE_PCINT13
#define PCINT_ENABLE_PCINT14
#define PCINT_ENABLE_PCINT15
#define PCINT_ENABLE_PCINT16
#define PCINT_ENABLE_PCINT17
#define PCINT_ENABLE_PCINT18
#define PCINT_ENABLE_PCINT19
#define PCINT_ENABLE_PCINT20
#define PCINT_ENABLE_PCINT21
#define PCINT_ENABLE_PCINT22
#define PCINT_ENABLE_PCINT23
#define PCINT_ENABLE_PCINT24
#define PCINT_ENABLE_PCINT25
#define PCINT_ENABLE_PCINT26
#define PCINT_ENABLE_PCINT27
#define PCINT_ENABLE_PCINT28
#define PCINT_ENABLE_PCINT29
#define PCINT_ENABLE_PCINT30
#define PCINT_ENABLE_PCINT31
#endif
#ifdef ARDUINO
// use API with function pointers (better optimized with .a linkage)
#define PCINT_API
// is the library compiled via .a file?
// see readme for more information
#define PCINT_ALINKAGE
// force compile all enabled port ISRs (with .a linkage)
//#define PCINT_COMPILE_ENABLED_ISR
#endif
//================================================================================
// Suggested Settings
//================================================================================
// Arduino Uno (328)
#if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega88__)
/* Reordering interrupt callbacks priority
Port0 has SPI on higher pins, ordering is fine
Port1 has I2C on higher pins, ordering is fine
Port2 has USART and Pin Interrupt on lower pins,
move the priority down
Its more likely the user will use pin 4-7
*/
#if !defined(PCINT_CALLBACK_PORT2)
#define PCINT_CALLBACK_PORT2 \
PCINT_CALLBACK(4, 20); \
PCINT_CALLBACK(5, 21); \
PCINT_CALLBACK(6, 22); \
PCINT_CALLBACK(7, 23); \
PCINT_CALLBACK(0, 16); /* USART RX */ \
PCINT_CALLBACK(1, 17); /* USART TX */ \
PCINT_CALLBACK(2, 18); /* Pin Interrupt 0 */ \
PCINT_CALLBACK(3, 19); /* Pin Interrupt 1 */
#endif
// deactivate crystal and reset pins by default
#if defined(PCINT_ENABLE_PCINT6)
#undef PCINT_ENABLE_PCINT6 // crystal
#endif
#if defined(PCINT_ENABLE_PCINT7)
#undef PCINT_ENABLE_PCINT7 // crystal
#endif
#if defined(PCINT_ENABLE_PCINT14)
#undef PCINT_ENABLE_PCINT14 // reset
#endif
#endif
// Arduino Mega (2560)
#if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_MEGA)
/* Port1 is structured a bit more complicated
Also only 3 pins are connected on standard boards
Seeeduino Mega has these pins optional!
Disabling Port1 gives more speed and uses less flash
Pins: 0(RX0), 14(TX3), 15(RX3) */
#if defined(PCINT_ENABLE_PORT1)
#undef PCINT_ENABLE_PORT1 // better performence
#endif
/* Reordering interrupt callbacks priority
Port2 has SPI on lower pins, move the priority down
Its more likely the user will use pin 10-13
Port1 by default deactivated, ordering is fine
Port2 only has ADCs, ordering is fine
*/
#if !defined(PCINT_CALLBACK_PORT0)
#define PCINT_CALLBACK_PORT0 \
PCINT_CALLBACK(4, 4); \
PCINT_CALLBACK(5, 5); \
PCINT_CALLBACK(6, 6); \
PCINT_CALLBACK(7, 7); \
PCINT_CALLBACK(0, 0); /* SPI SS */ \
PCINT_CALLBACK(1, 1); /* SPI SCK */ \
PCINT_CALLBACK(2, 2); /* SPI MISO */ \
PCINT_CALLBACK(3, 3); /* SPI MOSI */
#endif
#endif
// Arduino Leonardo/Micro (32u4)
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
/* Reordering interrupt callbacks priority
Port0 has SPI on lower pins, move the priority down
Its more likely the user will use pin 8-11 */
#if !defined(PCINT_CALLBACK_PORT0)
#define PCINT_CALLBACK_PORT0 \
PCINT_CALLBACK(4, 4); \
PCINT_CALLBACK(5, 5); \
PCINT_CALLBACK(6, 6); \
PCINT_CALLBACK(7, 7); \
PCINT_CALLBACK(0, 0); /* SPI SS / RX LED */ \
PCINT_CALLBACK(1, 1); /* SPI SCK */ \
PCINT_CALLBACK(2, 2); /* SPI MISO */ \
PCINT_CALLBACK(3, 3); /* SPI MOSI */
#endif
// RX LED on normal leonardo/micro
#if defined(PCINT_ENABLE_PCINT0) && (defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_MICRO))
#undef PCINT_ENABLE_PCINT0
#endif
#endif
// Hoodloader2 (u2 Series)
#if defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
#if defined(ARDUINO_HOODLOADER2)
// on HoodLoader2 Arduino boards only PB1-7 (port0) is broken out, save this flash
#if defined(PCINT_ENABLE_PORT1)
#undef PCINT_ENABLE_PORT1
#endif
// SS (PB0) is not connected on normal Arduino boards
#if defined(PCINT_ENABLE_PCINT0)
#undef PCINT_ENABLE_PCINT0
#endif
/* Reordering interrupt callbacks priority
Port0 has SPI on lower pins, move the priority down
Its more likely the user will use PB4-7
Pretend the User has not soldered the 4 Pinheader
so only do this for non Arduino boards. */
#else
#if !defined(PCINT_CALLBACK_PORT0)
#define PCINT_CALLBACK_PORT0 \
PCINT_CALLBACK(4, 4); \
PCINT_CALLBACK(5, 5); \
PCINT_CALLBACK(6, 6); \
PCINT_CALLBACK(7, 7); \
PCINT_CALLBACK(0, 0); /* SPI SS */ \
PCINT_CALLBACK(1, 1); /* SPI SCK */ \
PCINT_CALLBACK(2, 2); /* SPI MISO */ \
PCINT_CALLBACK(3, 3); /* SPI MOSI */
#endif
#endif
#endif
/* Attiny 25/45/85 only has a very few pins
activate all by default
The order is also okay. */
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
// Port1 is connected to reset, crystal and Pin Interrupt 0
// Deactivate it by default
#if defined(PCINT_ENABLE_PORT1)
#undef PCINT_ENABLE_PORT1
#endif
#endif