-
-
Save boop5/0cad063d281f181d31f84593eaffd12a to your computer and use it in GitHub Desktop.
| /* | |
| SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - | |
| Multi-instance software serial library for Arduino/Wiring | |
| -- Interrupt-driven receive and other improvements by ladyada | |
| (http://ladyada.net) | |
| -- Tuning, circular buffer, derivation from class Print/Stream, | |
| multi-instance support, porting to 8MHz processors, | |
| various optimizations, PROGMEM delay tables, inverse logic and | |
| direct port writing by Mikal Hart (http://www.arduiniana.org) | |
| -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) | |
| -- 20MHz processor support by Garrett Mace (http://www.macetech.com) | |
| -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) | |
| This library is free software; you can redistribute it and/or | |
| modify it under the terms of the GNU Lesser General Public | |
| License as published by the Free Software Foundation; either | |
| version 2.1 of the License, or (at your option) any later version. | |
| This library is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| Lesser General Public License for more details. | |
| You should have received a copy of the GNU Lesser General Public | |
| License along with this library; if not, write to the Free Software | |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
| The latest version of this library can always be found at | |
| http://arduiniana.org. | |
| */ | |
| // When set, _DEBUG co-opts pins 11 and 13 for debugging with an | |
| // oscilloscope or logic analyzer. Beware: it also slightly modifies | |
| // the bit times, so don't rely on it too much at high baud rates | |
| #define _DEBUG 0 | |
| #define _DEBUG_PIN1 11 | |
| #define _DEBUG_PIN2 13 | |
| // | |
| // Includes | |
| // | |
| #include <avr/interrupt.h> | |
| #include <avr/pgmspace.h> | |
| #include <Arduino.h> | |
| #include <LemonSerial.h> | |
| #include <util/delay_basic.h> | |
| // | |
| // Statics | |
| // | |
| LemonSerial *LemonSerial::active_object = 0; | |
| uint8_t LemonSerial::_receive_buffer[_SS_MAX_RX_BUFF]; | |
| volatile uint8_t LemonSerial::_receive_buffer_tail = 0; | |
| volatile uint8_t LemonSerial::_receive_buffer_head = 0; | |
| // | |
| // Debugging | |
| // | |
| // This function generates a brief pulse | |
| // for debugging or measuring on an oscilloscope. | |
| #if _DEBUG | |
| inline void DebugPulse(uint8_t pin, uint8_t count) | |
| { | |
| volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin)); | |
| uint8_t val = *pport; | |
| while (count--) | |
| { | |
| *pport = val | digitalPinToBitMask(pin); | |
| *pport = val; | |
| } | |
| } | |
| #else | |
| inline void DebugPulse(uint8_t, uint8_t) {} | |
| #endif | |
| // | |
| // Private methods | |
| // | |
| /* static */ | |
| inline void LemonSerial::tunedDelay(uint16_t delay) { | |
| _delay_loop_2(delay); | |
| } | |
| // This function sets the current object as the "listening" | |
| // one and returns true if it replaces another | |
| bool LemonSerial::listen() | |
| { | |
| if (!_rx_delay_stopbit) | |
| return false; | |
| if (active_object != this) | |
| { | |
| if (active_object) | |
| active_object->stopListening(); | |
| _buffer_overflow = false; | |
| _receive_buffer_head = _receive_buffer_tail = 0; | |
| active_object = this; | |
| setRxIntMsk(true); | |
| return true; | |
| } | |
| return false; | |
| } | |
| // Stop listening. Returns true if we were actually listening. | |
| bool LemonSerial::stopListening() | |
| { | |
| if (active_object == this) | |
| { | |
| setRxIntMsk(false); | |
| active_object = NULL; | |
| return true; | |
| } | |
| return false; | |
| } | |
| // | |
| // The receive routine called by the interrupt handler | |
| // | |
| void LemonSerial::recv() | |
| { | |
| #if GCC_VERSION < 40302 | |
| // Work-around for avr-gcc 4.3.0 OSX version bug | |
| // Preserve the registers that the compiler misses | |
| // (courtesy of Arduino forum user *etracer*) | |
| asm volatile( | |
| "push r18 \n\t" | |
| "push r19 \n\t" | |
| "push r20 \n\t" | |
| "push r21 \n\t" | |
| "push r22 \n\t" | |
| "push r23 \n\t" | |
| "push r26 \n\t" | |
| "push r27 \n\t" | |
| ::); | |
| #endif | |
| uint8_t d = 0; | |
| // If RX line is high, then we don't see any start bit | |
| // so interrupt is probably not for us | |
| if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) | |
| { | |
| // Disable further interrupts during reception, this prevents | |
| // triggering another interrupt directly after we return, which can | |
| // cause problems at higher baudrates. | |
| setRxIntMsk(false); | |
| // Wait approximately 1/2 of a bit width to "center" the sample | |
| tunedDelay(_rx_delay_centering); | |
| DebugPulse(_DEBUG_PIN2, 1); | |
| // Read each of the 8 bits | |
| for (uint8_t i=8; i > 0; --i) | |
| { | |
| tunedDelay(_rx_delay_intrabit); | |
| d >>= 1; | |
| DebugPulse(_DEBUG_PIN2, 1); | |
| if (rx_pin_read()) | |
| d |= 0x80; | |
| } | |
| if (_inverse_logic) | |
| d = ~d; | |
| // if buffer full, set the overflow flag and return | |
| uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; | |
| if (next != _receive_buffer_head) | |
| { | |
| // save new data in buffer: tail points to where byte goes | |
| _receive_buffer[_receive_buffer_tail] = d; // save new byte | |
| _receive_buffer_tail = next; | |
| } | |
| else | |
| { | |
| DebugPulse(_DEBUG_PIN1, 1); | |
| _buffer_overflow = true; | |
| } | |
| // skip the stop bit | |
| tunedDelay(_rx_delay_stopbit); | |
| DebugPulse(_DEBUG_PIN1, 1); | |
| // Re-enable interrupts when we're sure to be inside the stop bit | |
| setRxIntMsk(true); | |
| } | |
| #if GCC_VERSION < 40302 | |
| // Work-around for avr-gcc 4.3.0 OSX version bug | |
| // Restore the registers that the compiler misses | |
| asm volatile( | |
| "pop r27 \n\t" | |
| "pop r26 \n\t" | |
| "pop r23 \n\t" | |
| "pop r22 \n\t" | |
| "pop r21 \n\t" | |
| "pop r20 \n\t" | |
| "pop r19 \n\t" | |
| "pop r18 \n\t" | |
| ::); | |
| #endif | |
| } | |
| uint8_t LemonSerial::rx_pin_read() | |
| { | |
| return *_receivePortRegister & _receiveBitMask; | |
| } | |
| // | |
| // Interrupt handling | |
| // | |
| // change here: removed the inline keyword | |
| /* static */ | |
| void LemonSerial::handle_interrupt() | |
| { | |
| if (active_object) | |
| { | |
| active_object->recv(); | |
| } | |
| } | |
| // change here: commented out the ISR section | |
| // #if defined(PCINT0_vect) | |
| // ISR(PCINT0_vect) | |
| // { | |
| // LemonSerial::handle_interrupt(); | |
| // } | |
| // #endif | |
| // #if defined(PCINT1_vect) | |
| // ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect)); | |
| // #endif | |
| // #if defined(PCINT2_vect) | |
| // ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect)); | |
| // #endif | |
| // #if defined(PCINT3_vect) | |
| // ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect)); | |
| // #endif | |
| // | |
| // Constructor | |
| // | |
| LemonSerial::LemonSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : | |
| _rx_delay_centering(0), | |
| _rx_delay_intrabit(0), | |
| _rx_delay_stopbit(0), | |
| _tx_delay(0), | |
| _buffer_overflow(false), | |
| _inverse_logic(inverse_logic) | |
| { | |
| setTX(transmitPin); | |
| setRX(receivePin); | |
| } | |
| // | |
| // Destructor | |
| // | |
| LemonSerial::~LemonSerial() | |
| { | |
| end(); | |
| } | |
| void LemonSerial::setTX(uint8_t tx) | |
| { | |
| // First write, then set output. If we do this the other way around, | |
| // the pin would be output low for a short while before switching to | |
| // output high. Now, it is input with pullup for a short while, which | |
| // is fine. With inverse logic, either order is fine. | |
| digitalWrite(tx, _inverse_logic ? LOW : HIGH); | |
| pinMode(tx, OUTPUT); | |
| _transmitBitMask = digitalPinToBitMask(tx); | |
| uint8_t port = digitalPinToPort(tx); | |
| _transmitPortRegister = portOutputRegister(port); | |
| } | |
| void LemonSerial::setRX(uint8_t rx) | |
| { | |
| pinMode(rx, INPUT); | |
| if (!_inverse_logic) | |
| digitalWrite(rx, HIGH); // pullup for normal logic! | |
| _receivePin = rx; | |
| _receiveBitMask = digitalPinToBitMask(rx); | |
| uint8_t port = digitalPinToPort(rx); | |
| _receivePortRegister = portInputRegister(port); | |
| } | |
| uint16_t LemonSerial::subtract_cap(uint16_t num, uint16_t sub) { | |
| if (num > sub) | |
| return num - sub; | |
| else | |
| return 1; | |
| } | |
| // | |
| // Public methods | |
| // | |
| void LemonSerial::begin(long speed) | |
| { | |
| _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; | |
| // Precalculate the various delays, in number of 4-cycle delays | |
| uint16_t bit_delay = (F_CPU / speed) / 4; | |
| // 12 (gcc 4.8.2) or 13 (gcc 4.3.2) cycles from start bit to first bit, | |
| // 15 (gcc 4.8.2) or 16 (gcc 4.3.2) cycles between bits, | |
| // 12 (gcc 4.8.2) or 14 (gcc 4.3.2) cycles from last bit to stop bit | |
| // These are all close enough to just use 15 cycles, since the inter-bit | |
| // timings are the most critical (deviations stack 8 times) | |
| _tx_delay = subtract_cap(bit_delay, 15 / 4); | |
| // Only setup rx when we have a valid PCINT for this pin | |
| if (digitalPinToPCICR((int8_t)_receivePin)) { | |
| #if GCC_VERSION > 40800 | |
| // Timings counted from gcc 4.8.2 output. This works up to 115200 on | |
| // 16Mhz and 57600 on 8Mhz. | |
| // | |
| // When the start bit occurs, there are 3 or 4 cycles before the | |
| // interrupt flag is set, 4 cycles before the PC is set to the right | |
| // interrupt vector address and the old PC is pushed on the stack, | |
| // and then 75 cycles of instructions (including the RJMP in the | |
| // ISR vector table) until the first delay. After the delay, there | |
| // are 17 more cycles until the pin value is read (excluding the | |
| // delay in the loop). | |
| // We want to have a total delay of 1.5 bit time. Inside the loop, | |
| // we already wait for 1 bit time - 23 cycles, so here we wait for | |
| // 0.5 bit time - (71 + 18 - 22) cycles. | |
| _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4); | |
| // There are 23 cycles in each loop iteration (excluding the delay) | |
| _rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4); | |
| // There are 37 cycles from the last bit read to the start of | |
| // stopbit delay and 11 cycles from the delay until the interrupt | |
| // mask is enabled again (which _must_ happen during the stopbit). | |
| // This delay aims at 3/4 of a bit time, meaning the end of the | |
| // delay will be at 1/4th of the stopbit. This allows some extra | |
| // time for ISR cleanup, which makes 115200 baud at 16Mhz work more | |
| // reliably | |
| _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4); | |
| #else // Timings counted from gcc 4.3.2 output | |
| // Note that this code is a _lot_ slower, mostly due to bad register | |
| // allocation choices of gcc. This works up to 57600 on 16Mhz and | |
| // 38400 on 8Mhz. | |
| _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 97 + 29 - 11) / 4); | |
| _rx_delay_intrabit = subtract_cap(bit_delay, 11 / 4); | |
| _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (44 + 17) / 4); | |
| #endif | |
| // Enable the PCINT for the entire port here, but never disable it | |
| // (others might also need it, so we disable the interrupt by using | |
| // the per-pin PCMSK register). | |
| *digitalPinToPCICR((int8_t)_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin)); | |
| // Precalculate the pcint mask register and value, so setRxIntMask | |
| // can be used inside the ISR without costing too much time. | |
| _pcint_maskreg = digitalPinToPCMSK(_receivePin); | |
| _pcint_maskvalue = _BV(digitalPinToPCMSKbit(_receivePin)); | |
| tunedDelay(_tx_delay); // if we were low this establishes the end | |
| } | |
| #if _DEBUG | |
| pinMode(_DEBUG_PIN1, OUTPUT); | |
| pinMode(_DEBUG_PIN2, OUTPUT); | |
| #endif | |
| listen(); | |
| } | |
| void LemonSerial::setRxIntMsk(bool enable) | |
| { | |
| if (enable) | |
| *_pcint_maskreg |= _pcint_maskvalue; | |
| else | |
| *_pcint_maskreg &= ~_pcint_maskvalue; | |
| } | |
| void LemonSerial::end() | |
| { | |
| stopListening(); | |
| } | |
| // Read data from buffer | |
| int LemonSerial::read() | |
| { | |
| if (!isListening()) | |
| return -1; | |
| // Empty buffer? | |
| if (_receive_buffer_head == _receive_buffer_tail) | |
| return -1; | |
| // Read from "head" | |
| uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte | |
| _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF; | |
| return d; | |
| } | |
| int LemonSerial::available() | |
| { | |
| if (!isListening()) | |
| return 0; | |
| return ((unsigned int)(_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head)) % _SS_MAX_RX_BUFF; | |
| } | |
| size_t LemonSerial::write(uint8_t b) | |
| { | |
| if (_tx_delay == 0) { | |
| setWriteError(); | |
| return 0; | |
| } | |
| // By declaring these as local variables, the compiler will put them | |
| // in registers _before_ disabling interrupts and entering the | |
| // critical timing sections below, which makes it a lot easier to | |
| // verify the cycle timings | |
| volatile uint8_t *reg = _transmitPortRegister; | |
| uint8_t reg_mask = _transmitBitMask; | |
| uint8_t inv_mask = ~_transmitBitMask; | |
| uint8_t oldSREG = SREG; | |
| bool inv = _inverse_logic; | |
| uint16_t delay = _tx_delay; | |
| if (inv) | |
| b = ~b; | |
| cli(); // turn off interrupts for a clean txmit | |
| // Write the start bit | |
| if (inv) | |
| *reg |= reg_mask; | |
| else | |
| *reg &= inv_mask; | |
| tunedDelay(delay); | |
| // Write each of the 8 bits | |
| for (uint8_t i = 8; i > 0; --i) | |
| { | |
| if (b & 1) // choose bit | |
| *reg |= reg_mask; // send 1 | |
| else | |
| *reg &= inv_mask; // send 0 | |
| tunedDelay(delay); | |
| b >>= 1; | |
| } | |
| // restore pin to natural state | |
| if (inv) | |
| *reg &= inv_mask; | |
| else | |
| *reg |= reg_mask; | |
| SREG = oldSREG; // turn interrupts back on | |
| tunedDelay(_tx_delay); | |
| return 1; | |
| } | |
| void LemonSerial::flush() | |
| { | |
| // There is no tx buffering, simply return | |
| } | |
| int LemonSerial::peek() | |
| { | |
| if (!isListening()) | |
| return -1; | |
| // Empty buffer? | |
| if (_receive_buffer_head == _receive_buffer_tail) | |
| return -1; | |
| // Read from "head" | |
| return _receive_buffer[_receive_buffer_head]; | |
| } |
| /* | |
| SoftwareSerial.h (formerly NewSoftSerial.h) - | |
| Multi-instance software serial library for Arduino/Wiring | |
| -- Interrupt-driven receive and other improvements by ladyada | |
| (http://ladyada.net) | |
| -- Tuning, circular buffer, derivation from class Print/Stream, | |
| multi-instance support, porting to 8MHz processors, | |
| various optimizations, PROGMEM delay tables, inverse logic and | |
| direct port writing by Mikal Hart (http://www.arduiniana.org) | |
| -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) | |
| -- 20MHz processor support by Garrett Mace (http://www.macetech.com) | |
| -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) | |
| This library is free software; you can redistribute it and/or | |
| modify it under the terms of the GNU Lesser General Public | |
| License as published by the Free Software Foundation; either | |
| version 2.1 of the License, or (at your option) any later version. | |
| This library is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| Lesser General Public License for more details. | |
| You should have received a copy of the GNU Lesser General Public | |
| License along with this library; if not, write to the Free Software | |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
| The latest version of this library can always be found at | |
| http://arduiniana.org. | |
| */ | |
| #ifndef LemonSerial_h | |
| #define LemonSerial_h | |
| #include <inttypes.h> | |
| #include <Stream.h> | |
| /****************************************************************************** | |
| * Definitions | |
| ******************************************************************************/ | |
| #ifndef _SS_MAX_RX_BUFF | |
| #define _SS_MAX_RX_BUFF 64 // RX buffer size | |
| #endif | |
| #ifndef GCC_VERSION | |
| #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) | |
| #endif | |
| class LemonSerial : public Stream | |
| { | |
| private: | |
| // per object data | |
| uint8_t _receivePin; | |
| uint8_t _receiveBitMask; | |
| volatile uint8_t *_receivePortRegister; | |
| uint8_t _transmitBitMask; | |
| volatile uint8_t *_transmitPortRegister; | |
| volatile uint8_t *_pcint_maskreg; | |
| uint8_t _pcint_maskvalue; | |
| // Expressed as 4-cycle delays (must never be 0!) | |
| uint16_t _rx_delay_centering; | |
| uint16_t _rx_delay_intrabit; | |
| uint16_t _rx_delay_stopbit; | |
| uint16_t _tx_delay; | |
| uint16_t _buffer_overflow:1; | |
| uint16_t _inverse_logic:1; | |
| // static data | |
| static uint8_t _receive_buffer[_SS_MAX_RX_BUFF]; | |
| static volatile uint8_t _receive_buffer_tail; | |
| static volatile uint8_t _receive_buffer_head; | |
| static LemonSerial *active_object; | |
| // private methods | |
| inline void recv() __attribute__((__always_inline__)); | |
| uint8_t rx_pin_read(); | |
| void setTX(uint8_t transmitPin); | |
| void setRX(uint8_t receivePin); | |
| inline void setRxIntMsk(bool enable) __attribute__((__always_inline__)); | |
| // Return num - sub, or 1 if the result would be < 1 | |
| static uint16_t subtract_cap(uint16_t num, uint16_t sub); | |
| // private static method for timing | |
| static inline void tunedDelay(uint16_t delay); | |
| public: | |
| // public methods | |
| LemonSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); | |
| ~LemonSerial(); | |
| void begin(long speed); | |
| bool listen(); | |
| void end(); | |
| bool isListening() { return this == active_object; } | |
| bool stopListening(); | |
| bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; } | |
| int peek(); | |
| virtual size_t write(uint8_t byte); | |
| virtual int read(); | |
| virtual int available(); | |
| virtual void flush(); | |
| operator bool() { return true; } | |
| using Print::write; | |
| // change here: removed the inline keyword and always_inline attribute | |
| // public only for easy access by interrupt handlers | |
| static void handle_interrupt(); | |
| }; | |
| #endif |
Hi, I am trying to use an ATTiny85 with serial communication and to an ESP8266. I want to use PinChangeInterrupt to monitor bucket tips on a rain gauge (has a reed switch) attached to pin 2 (PB3) on the ATTiny85, when the bucket tips, the ATTiny wakes up the ESP8255 and sends the data over serial - using pins PB0(tx) and PB1(rx).
Everything works apart from the monitoring of the interupt.
The cut-down code I have tried is:
#define INT_PINRAIN PB3
void setup() {
pinMode(INT_PINRAIN, INPUT);
attachPCINT(digitalPinToPCINT(INT_PINRAIN), RAIN, FALLING);
}
void RAIN()
{
if ((millis() - ContactBounceTimeRain) > 250 ) { // debounce the switch contact.
PluvioFlag++;
RainFlag = 1;
ContactBounceTimeRain = millis();
time1 = millis();
}
}
however I get the following error:
PinChangeInterrupt.cpp.o (symbol from plugin): In function pcint_null_callback :
(.text+0x0): multiple definition of __vector_2
C:\Users\Default User.DESKTOP-UR53KBO\AppData\Local\Temp\arduino\sketches\A06F401CFE2202C1EFB8281DA88A3AC5\sketch\ATTiny_serial_send_20231107_2.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
Using library LemonSerial in folder: C:\Users\Default User.DESKTOP-UR53KBO\Documents\Arduino\libraries\LemonSerial (legacy)
Using library PinChangeInterrupt at version 1.2.9 in folder: C:\Users\Default User.DESKTOP-UR53KBO\Documents\Arduino\libraries\PinChangeInterrupt
exit status 1
Compilation error: exit status 1
Do you know what I am doing wrong or have any example code I could look at.
Thanks
Davo
are you using the arduino IDE or vscode with PIO?
look for PCINT2_vect definitions in your libraries. for some reason you have defined it more than once. that was the whole reason I modified the original SoftwareSerial library
I've commented the changes I made in the files above
// change here: commented out the ISR section
// #if defined(PCINT0_vect)
// ISR(PCINT0_vect)
// {
// LemonSerial::handle_interrupt();
// }
// #endif
// #if defined(PCINT1_vect)
// ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect));
// #endif
// #if defined(PCINT2_vect)
// ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect));
// #endif
// #if defined(PCINT3_vect)
// ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect));
// #endif
Hi, Thanks for the quick reply.
I am using arduino IDE 2.2.0.
The only PCINT2_vect definitions I can find in pinchangeinterrupt library are..
PinChangeInterruptPins.h
#if defined(PCINT2_vect)
#define PCINT_HAS_PORT2 true
#else
#define PCINT_HAS_PORT2 false
#endif
PinChangeInterrupt2.cpp
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
}
I dont really understand any of this.. any help would be great.
Thanks
Davo
Don't forget to call handle_interrupt from the outside