robobuggy / arduino / InterruptRCRecieverReference / PinChangeInt.h @ c5d6b0e8
History | View | Annotate | Download (20.6 KB)
1 |
// We use 4-character tabstops, so IN VIM: <esc>:set ts=4 and <esc>:set sw=4
|
---|---|
2 |
// ...that's: ESCAPE key, colon key, then "s-e-t SPACE key t-s-=-4"
|
3 |
//
|
4 |
/*
|
5 |
* This is the PinChangeInt library for the Arduino.
|
6 |
|
7 |
See google code project for latest, bugs and info http://code.google.com/p/arduino-pinchangeint/
|
8 |
For more information Refer to avr-gcc header files, arduino source and atmega datasheet.
|
9 |
|
10 |
This library was inspired by and derived from "johnboiles" (it seems)
|
11 |
PCInt Arduino Playground example here: http://www.arduino.cc/playground/Main/PcInt
|
12 |
If you are the original author, please let us know at the google code page
|
13 |
|
14 |
It provides an extension to the interrupt support for arduino by
|
15 |
adding pin change interrupts, giving a way for users to have
|
16 |
interrupts drive off of any pin.
|
17 |
|
18 |
This program is free software: you can redistribute it and/or modify
|
19 |
it under the terms of the GNU General Public License as published by
|
20 |
the Free Software Foundation, either version 3 of the License, or
|
21 |
(at your option) any later version.
|
22 |
|
23 |
This program is distributed in the hope that it will be useful,
|
24 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
25 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
26 |
GNU General Public License for more details.
|
27 |
|
28 |
You should have received a copy of the GNU General Public License
|
29 |
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
30 |
(the file gpl.txt is included with the library's zip package)
|
31 |
*/
|
32 |
//-------- define these in your sketch, if applicable ----------------------------------------------------------
|
33 |
//-------- These must go in your sketch ahead of the #include <PinChangeInt.h> statement -----------------------
|
34 |
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
|
35 |
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline
|
36 |
// reducing the size and latency of the handler.
|
37 |
// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
38 |
// #define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
|
39 |
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
|
40 |
// --- Mega support ---
|
41 |
// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
42 |
// #define NO_PORTJ_PINCHANGES // to indicate that port c will not be used for pin change interrupts
|
43 |
// #define NO_PORTK_PINCHANGES // to indicate that port d will not be used for pin change interrupts
|
44 |
// In the Mega, there is no Port C, no Port D. Instead, you get Port J and Port K. Port B remains.
|
45 |
// Port J, however, is practically useless because there is only 1 pin available for interrupts. Most
|
46 |
// of the Port J pins are not even connected to a header connection. // </end> "Mega Support" notes
|
47 |
// --- Sanguino, Mioduino support ---
|
48 |
// #define NO_PORTA_PINCHANGES // to indicate that port a will not be used for pin change interrupts
|
49 |
// --------------------
|
50 |
//
|
51 |
// Other preprocessor directives...
|
52 |
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine
|
53 |
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or
|
54 |
// PCintPort::arduinoPin are set and made available to your interrupt routine.
|
55 |
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
56 |
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
57 |
// #define DISABLE_PCINT_MULTI_SERVICE // to limit the handler to servicing a single interrupt per invocation.
|
58 |
// #define GET_PCINT_VERSION // to enable the uint16_t getPCIintVersion () function.
|
59 |
// The following is intended for testing purposes. If defined, then a whole host of static variables can be read
|
60 |
// in your interrupt subroutine. It is not defined by default, and you DO NOT want to define this in
|
61 |
// Production code!:
|
62 |
// #define PINMODE
|
63 |
//-------- define the above in your sketch, if applicable ------------------------------------------------------
|
64 |
|
65 |
/*
|
66 |
PinChangeInt.h
|
67 |
---- VERSIONS --- (NOTE TO SELF: Update the PCINT_VERSION define, below) -----------------
|
68 |
Version 2.19 (beta) Tue Nov 20 07:33:37 CST 2012
|
69 |
Version 2.17 (beta) Sat Nov 17 09:46:50 CST 2012
|
70 |
Version 2.11 (beta) Mon Nov 12 09:33:06 CST 2012
|
71 |
|
72 |
Version 2.01 (beta) Thu Jun 28 12:35:48 CDT 2012
|
73 |
|
74 |
Version 1.72 Wed Mar 14 18:57:55 CDT 2012
|
75 |
|
76 |
Version 1.71beta Sat Mar 10 12:57:05 CST 2012
|
77 |
|
78 |
Version 1.6beta Fri Feb 10 08:48:35 CST 2012
|
79 |
|
80 |
Version 1.51 Sun Feb 5 23:28:02 CST 2012
|
81 |
|
82 |
Version 1.5 Thu Feb 2 18:09:49 CST 2012
|
83 |
|
84 |
Version 1.4 Tue Jan 10 09:41:14 CST 2012
|
85 |
|
86 |
Version 1.3 Sat Dec 3 22:56:20 CST 2011
|
87 |
|
88 |
Version 1.2 Sat Dec 3 Sat Dec 3 09:15:52 CST 2011
|
89 |
|
90 |
Version 1.1 Sat Dec 3 00:06:03 CST 2011
|
91 |
*/
|
92 |
|
93 |
#ifndef PinChangeInt_h
|
94 |
#define PinChangeInt_h
|
95 |
|
96 |
#define PCINT_VERSION 2190 // This number MUST agree with the version number, above. |
97 |
|
98 |
#include "stddef.h" |
99 |
|
100 |
// Thanks to Maurice Beelen, nms277, Akesson Karlpetter, and Orly Andico for these fixes.
|
101 |
#if defined(ARDUINO) && ARDUINO >= 100 |
102 |
#include <Arduino.h> |
103 |
#include <new.h> |
104 |
#include <wiring_private.h> // cby and sbi defined here |
105 |
#else
|
106 |
#include <WProgram.h> |
107 |
#include <pins_arduino.h> |
108 |
#ifndef LIBCALL_PINCHANGEINT
|
109 |
#include "../cppfix/cppfix.h" |
110 |
#endif
|
111 |
#endif
|
112 |
|
113 |
|
114 |
#undef DEBUG
|
115 |
|
116 |
/*
|
117 |
* Theory: all IO pins on Atmega168 are covered by Pin Change Interrupts.
|
118 |
* The PCINT corresponding to the pin must be enabled and masked, and
|
119 |
* an ISR routine provided. Since PCINTs are per port, not per pin, the ISR
|
120 |
* must use some logic to actually implement a per-pin interrupt service.
|
121 |
*/
|
122 |
|
123 |
/* Pin to interrupt map:
|
124 |
* D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
|
125 |
* D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
|
126 |
* A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
|
127 |
*/
|
128 |
|
129 |
#undef INLINE_PCINT
|
130 |
#define INLINE_PCINT
|
131 |
// Thanks to cserveny...@gmail.com for MEGA support!
|
132 |
#if defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__
|
133 |
#define __USE_PORT_JK
|
134 |
// Mega does not have PORTA, C or D
|
135 |
#define NO_PORTA_PINCHANGES
|
136 |
#define NO_PORTC_PINCHANGES
|
137 |
#define NO_PORTD_PINCHANGES
|
138 |
#if ((defined(NO_PORTB_PINCHANGES) && defined(NO_PORTJ_PINCHANGES)) || \
|
139 |
(defined(NO_PORTJ_PINCHANGES) && defined(NO_PORTK_PINCHANGES)) || \ |
140 |
(defined(NO_PORTK_PINCHANGES) && defined(NO_PORTB_PINCHANGES))) |
141 |
#define INLINE_PCINT inline |
142 |
#endif
|
143 |
#else
|
144 |
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
145 |
#ifndef NO_PORTA_PINCHANGES
|
146 |
#define __USE_PORT_A
|
147 |
#endif
|
148 |
#else
|
149 |
#define NO_PORTA_PINCHANGES
|
150 |
#endif
|
151 |
// if defined only D .OR. only C .OR. only B .OR. only A, then inline it
|
152 |
#if ( (defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES)) || \
|
153 |
(defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \ |
154 |
(defined(NO_PORTA_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \ |
155 |
(defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) ) |
156 |
#define INLINE_PCINT inline |
157 |
#endif
|
158 |
#endif
|
159 |
|
160 |
// Provide drop in compatibility with johnboiles PCInt project at
|
161 |
// http://www.arduino.cc/playground/Main/PcInt
|
162 |
#define PCdetachInterrupt(pin) PCintPort::detachInterrupt(pin)
|
163 |
#define PCattachInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, userFunc,mode)
|
164 |
#define PCgetArduinoPin() PCintPort::getArduinoPin()
|
165 |
|
166 |
|
167 |
typedef void (*PCIntvoidFuncPtr)(void); |
168 |
|
169 |
class PCintPort { |
170 |
public:
|
171 |
PCintPort(int index,int pcindex, volatile uint8_t& maskReg) : |
172 |
portInputReg(*portInputRegister(index)), |
173 |
portPCMask(maskReg), |
174 |
PCICRbit(1 << pcindex),
|
175 |
portRisingPins(0),
|
176 |
portFallingPins(0),
|
177 |
firstPin(NULL)
|
178 |
#ifdef PINMODE
|
179 |
,intrCount(0)
|
180 |
#endif
|
181 |
{ |
182 |
#ifdef FLASH
|
183 |
ledsetup(); |
184 |
#endif
|
185 |
} |
186 |
volatile uint8_t& portInputReg;
|
187 |
static int8_t attachInterrupt(uint8_t pin, PCIntvoidFuncPtr userFunc, int mode); |
188 |
static void detachInterrupt(uint8_t pin); |
189 |
INLINE_PCINT void PCint();
|
190 |
static volatile uint8_t curr; |
191 |
#ifndef NO_PIN_NUMBER
|
192 |
static volatile uint8_t arduinoPin; |
193 |
#endif
|
194 |
#ifndef NO_PIN_STATE
|
195 |
static volatile uint8_t pinState; |
196 |
#endif
|
197 |
#ifdef PINMODE
|
198 |
static volatile uint8_t pinmode; |
199 |
static volatile uint8_t s_portRisingPins; |
200 |
static volatile uint8_t s_portFallingPins; |
201 |
static volatile uint8_t s_lastPinView; |
202 |
static volatile uint8_t s_pmask; |
203 |
static volatile char s_PORT; |
204 |
static volatile uint8_t s_changedPins; |
205 |
static volatile uint8_t s_portRisingPins_nCurr; |
206 |
static volatile uint8_t s_portFallingPins_nNCurr; |
207 |
static volatile uint8_t s_currXORlastPinView; |
208 |
volatile uint8_t intrCount;
|
209 |
static volatile uint8_t s_count; |
210 |
static volatile uint8_t pcint_multi; |
211 |
static volatile uint8_t PCIFRbug; |
212 |
#endif
|
213 |
#ifdef FLASH
|
214 |
static void ledsetup(void); |
215 |
#endif
|
216 |
|
217 |
protected:
|
218 |
class PCintPin { |
219 |
public:
|
220 |
PCintPin() : |
221 |
PCintFunc((PCIntvoidFuncPtr)NULL),
|
222 |
mode(0) {}
|
223 |
PCIntvoidFuncPtr PCintFunc; |
224 |
uint8_t mode; |
225 |
uint8_t mask; |
226 |
uint8_t arduinoPin; |
227 |
PCintPin* next; |
228 |
}; |
229 |
void enable(PCintPin* pin, PCIntvoidFuncPtr userFunc, uint8_t mode);
|
230 |
int8_t addPin(uint8_t arduinoPin,PCIntvoidFuncPtr userFunc, uint8_t mode); |
231 |
volatile uint8_t& portPCMask;
|
232 |
const uint8_t PCICRbit;
|
233 |
volatile uint8_t portRisingPins;
|
234 |
volatile uint8_t portFallingPins;
|
235 |
volatile uint8_t lastPinView;
|
236 |
PCintPin* firstPin; |
237 |
}; |
238 |
|
239 |
#ifndef LIBCALL_PINCHANGEINT // LIBCALL_PINCHANGEINT *********************************************** |
240 |
volatile uint8_t PCintPort::curr=0; |
241 |
#ifndef NO_PIN_NUMBER
|
242 |
volatile uint8_t PCintPort::arduinoPin=0; |
243 |
#endif
|
244 |
#ifndef NO_PIN_STATE
|
245 |
volatile uint8_t PCintPort::pinState=0; |
246 |
#endif
|
247 |
#ifdef PINMODE
|
248 |
volatile uint8_t PCintPort::pinmode=0; |
249 |
volatile uint8_t PCintPort::s_portRisingPins=0; |
250 |
volatile uint8_t PCintPort::s_portFallingPins=0; |
251 |
volatile uint8_t PCintPort::s_lastPinView=0; |
252 |
volatile uint8_t PCintPort::s_pmask=0; |
253 |
volatile char PCintPort::s_PORT='x'; |
254 |
volatile uint8_t PCintPort::s_changedPins=0; |
255 |
volatile uint8_t PCintPort::s_portRisingPins_nCurr=0; |
256 |
volatile uint8_t PCintPort::s_portFallingPins_nNCurr=0; |
257 |
volatile uint8_t PCintPort::s_currXORlastPinView=0; |
258 |
volatile uint8_t PCintPort::s_count=0; |
259 |
volatile uint8_t PCintPort::pcint_multi=0; |
260 |
volatile uint8_t PCintPort::PCIFRbug=0; |
261 |
#endif
|
262 |
|
263 |
#ifdef FLASH
|
264 |
#define PINLED 13 |
265 |
volatile uint8_t *led_port;
|
266 |
uint8_t led_mask; |
267 |
uint8_t not_led_mask; |
268 |
boolean ledsetup_run=false;
|
269 |
void PCintPort::ledsetup(void) { |
270 |
if (! ledsetup_run) {
|
271 |
led_port=portOutputRegister(digitalPinToPort(PINLED)); |
272 |
led_mask=digitalPinToBitMask(PINLED); |
273 |
not_led_mask=led_mask^0xFF;
|
274 |
pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW); |
275 |
ledsetup_run=true;
|
276 |
} |
277 |
}; |
278 |
#endif
|
279 |
|
280 |
|
281 |
// ATMEGA 644
|
282 |
//
|
283 |
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino, Mosquino uino bobino bonanafannafofino, me my momino... |
284 |
|
285 |
#ifndef NO_PORTA_PINCHANGES
|
286 |
PCintPort portA=PCintPort(1, 0,PCMSK0); // port PB==2 (from Arduino.h, Arduino version 1.0) |
287 |
#endif
|
288 |
#ifndef NO_PORTB_PINCHANGES
|
289 |
PCintPort portB=PCintPort(2, 1,PCMSK1); // port PB==2 (from Arduino.h, Arduino version 1.0) |
290 |
#endif
|
291 |
#ifndef NO_PORTC_PINCHANGES
|
292 |
PCintPort portC=PCintPort(3, 2,PCMSK2); // port PC==3 (also in pins_arduino.c, Arduino version 022) |
293 |
#endif
|
294 |
#ifndef NO_PORTD_PINCHANGES
|
295 |
PCintPort portD=PCintPort(4, 3,PCMSK3); // port PD==4 |
296 |
#endif
|
297 |
|
298 |
#else // others |
299 |
|
300 |
#ifndef NO_PORTB_PINCHANGES
|
301 |
PCintPort portB=PCintPort(2, 0,PCMSK0); // port PB==2 (from Arduino.h, Arduino version 1.0) |
302 |
#endif
|
303 |
#ifndef NO_PORTC_PINCHANGES // note: no PORTC on MEGA |
304 |
PCintPort portC=PCintPort(3, 1,PCMSK1); // port PC==3 (also in pins_arduino.c, Arduino version 022) |
305 |
#endif
|
306 |
#ifndef NO_PORTD_PINCHANGES // note: no PORTD on MEGA |
307 |
PCintPort portD=PCintPort(4, 2,PCMSK2); // port PD==4 |
308 |
#endif
|
309 |
|
310 |
#endif // defined __AVR_ATmega644__ |
311 |
|
312 |
#ifdef __USE_PORT_JK
|
313 |
#ifndef NO_PORTJ_PINCHANGES
|
314 |
PCintPort portJ=PCintPort(10,1,PCMSK1); // port PJ==10 |
315 |
#endif
|
316 |
#ifndef NO_PORTK_PINCHANGES
|
317 |
PCintPort portK=PCintPort(11,2,PCMSK2); // port PK==11 |
318 |
#endif
|
319 |
#endif // USE_PORT_JK |
320 |
|
321 |
static PCintPort *lookupPortNumToPort( int portNum ) { |
322 |
PCintPort *port = NULL;
|
323 |
|
324 |
switch (portNum) {
|
325 |
#ifndef NO_PORTA_PINCHANGES
|
326 |
case 1: |
327 |
port=&portA; |
328 |
break;
|
329 |
#endif
|
330 |
#ifndef NO_PORTB_PINCHANGES
|
331 |
case 2: |
332 |
port=&portB; |
333 |
break;
|
334 |
#endif
|
335 |
#ifndef NO_PORTC_PINCHANGES
|
336 |
case 3: |
337 |
port=&portC; |
338 |
break;
|
339 |
#endif
|
340 |
#ifndef NO_PORTD_PINCHANGES
|
341 |
case 4: |
342 |
port=&portD; |
343 |
break;
|
344 |
#endif
|
345 |
#ifdef __USE_PORT_JK
|
346 |
|
347 |
#ifndef NO_PORTJ_PINCHANGES
|
348 |
case 10: |
349 |
port=&portJ; |
350 |
break;
|
351 |
#endif
|
352 |
|
353 |
#ifndef NO_PORTK_PINCHANGES
|
354 |
case 11: |
355 |
port=&portK; |
356 |
break;
|
357 |
#endif
|
358 |
|
359 |
#endif
|
360 |
} |
361 |
|
362 |
return port;
|
363 |
} |
364 |
|
365 |
|
366 |
void PCintPort::enable(PCintPin* p, PCIntvoidFuncPtr userFunc, uint8_t mode) {
|
367 |
// Enable the pin for interrupts by adding to the PCMSKx register.
|
368 |
// ...The final steps; at this point the interrupt is enabled on this pin.
|
369 |
p->mode=mode; |
370 |
p->PCintFunc=userFunc; |
371 |
portPCMask |= p->mask; |
372 |
if ((p->mode == RISING) || (p->mode == CHANGE)) portRisingPins |= p->mask;
|
373 |
if ((p->mode == FALLING) || (p->mode == CHANGE)) portFallingPins |= p->mask;
|
374 |
PCICR |= PCICRbit; |
375 |
} |
376 |
|
377 |
int8_t PCintPort::addPin(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, uint8_t mode) |
378 |
{ |
379 |
PCintPin* tmp; |
380 |
|
381 |
// Add to linked list, starting with firstPin. If pin already exists, just enable.
|
382 |
if (firstPin != NULL) { |
383 |
tmp=firstPin; |
384 |
do {
|
385 |
if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); } |
386 |
if (tmp->next == NULL) break; |
387 |
tmp=tmp->next; |
388 |
} while (true); |
389 |
} |
390 |
|
391 |
// Create pin p: fill in the data.
|
392 |
PCintPin* p=new PCintPin; |
393 |
if (p == NULL) return(-1); |
394 |
p->arduinoPin=arduinoPin; |
395 |
p->mode = mode; |
396 |
p->next=NULL;
|
397 |
p->mask = digitalPinToBitMask(arduinoPin); // the mask
|
398 |
|
399 |
if (firstPin == NULL) firstPin=p; |
400 |
else tmp->next=p;
|
401 |
|
402 |
#ifdef DEBUG
|
403 |
Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC);
|
404 |
int addr = (int) p; |
405 |
Serial.print(" instance addr: "); Serial.println(addr, HEX);
|
406 |
Serial.print("userFunc addr: "); Serial.println((int)p->PCintFunc, HEX); |
407 |
#endif
|
408 |
|
409 |
enable(p, userFunc, mode); |
410 |
#ifdef DEBUG
|
411 |
Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC), Serial.print (" pin stored: "); |
412 |
int addr = (int) p; |
413 |
Serial.print(" instance addr: "); Serial.println(addr, HEX);
|
414 |
#endif
|
415 |
return(1); |
416 |
} |
417 |
|
418 |
/*
|
419 |
* attach an interrupt to a specific pin using pin change interrupts.
|
420 |
*/
|
421 |
int8_t PCintPort::attachInterrupt(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, int mode)
|
422 |
{ |
423 |
PCintPort *port; |
424 |
uint8_t portNum = digitalPinToPort(arduinoPin); |
425 |
if ((portNum == NOT_A_PORT) || (userFunc == NULL)) return(-1); |
426 |
|
427 |
port=lookupPortNumToPort(portNum); |
428 |
// Added by GreyGnome... must set the initial value of lastPinView for it to be correct on the 1st interrupt.
|
429 |
// ...but even then, how do you define "correct"? Ultimately, the user must specify (not provisioned for yet).
|
430 |
port->lastPinView=port->portInputReg; |
431 |
|
432 |
#ifdef DEBUG
|
433 |
Serial.print("attachInterrupt FUNC: "); Serial.println(arduinoPin, DEC);
|
434 |
#endif
|
435 |
// map pin to PCIR register
|
436 |
return(port->addPin(arduinoPin,userFunc,mode));
|
437 |
} |
438 |
|
439 |
void PCintPort::detachInterrupt(uint8_t arduinoPin)
|
440 |
{ |
441 |
PCintPort *port; |
442 |
PCintPin* current; |
443 |
uint8_t mask; |
444 |
#ifdef DEBUG
|
445 |
Serial.print("detachInterrupt: "); Serial.println(arduinoPin, DEC);
|
446 |
#endif
|
447 |
uint8_t portNum = digitalPinToPort(arduinoPin); |
448 |
if (portNum == NOT_A_PORT) return; |
449 |
port=lookupPortNumToPort(portNum); |
450 |
mask=digitalPinToBitMask(arduinoPin); |
451 |
current=port->firstPin; |
452 |
//PCintPin* prev=NULL;
|
453 |
while (current) {
|
454 |
if (current->mask == mask) { // found the target |
455 |
uint8_t oldSREG = SREG; |
456 |
cli(); // disable interrupts
|
457 |
port->portPCMask &= ~mask; // disable the mask entry.
|
458 |
if (port->portPCMask == 0) PCICR &= ~(port->PCICRbit); |
459 |
port->portRisingPins &= ~current->mask; port->portFallingPins &= ~current->mask; |
460 |
// Link the previous' next to the found next. Then remove the found.
|
461 |
//if (prev != NULL) prev->next=current->next; // linked list skips over current.
|
462 |
//else firstPin=current->next; // at the first pin; save the new first pin
|
463 |
SREG = oldSREG; // Restore register; reenables interrupts
|
464 |
return;
|
465 |
} |
466 |
//prev=current;
|
467 |
current=current->next; |
468 |
} |
469 |
} |
470 |
|
471 |
// common code for isr handler. "port" is the PCINT number.
|
472 |
// there isn't really a good way to back-map ports and masks to pins.
|
473 |
void PCintPort::PCint() {
|
474 |
uint8_t thisChangedPin; //MIKE
|
475 |
|
476 |
#ifdef FLASH
|
477 |
if (*led_port & led_mask) *led_port&=not_led_mask;
|
478 |
else *led_port|=led_mask;
|
479 |
#endif
|
480 |
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
481 |
uint8_t pcifr; |
482 |
while (true) { |
483 |
#endif
|
484 |
// get the pin states for the indicated port.
|
485 |
#ifdef PINMODE
|
486 |
PCintPort::s_lastPinView=lastPinView; |
487 |
intrCount++; |
488 |
PCintPort::s_count=intrCount; |
489 |
#endif
|
490 |
// OLD v. 2.01 technique: Test 1: 3163; Test 7: 3993
|
491 |
// From robtillaart online: ------------ (starting v. 2.11beta)
|
492 |
// uint8_t changedPins = PCintPort::curr ^ lastPinView;
|
493 |
// lastPinView = PCintPort::curr;
|
494 |
// uint8_t fastMask = changedPins & ((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr ));
|
495 |
// NEW v. 2.11 technique: Test 1: 3270 Test 7: 3987
|
496 |
// -------------------------------------
|
497 |
// was: uint8_t changedPins = PCintPort::curr ^ lastPinView;
|
498 |
// makes test 6 of the PinChangeIntSpeedTest go from 3867 to 3923. Not good.
|
499 |
uint8_t changedPins = (PCintPort::curr ^ lastPinView) & |
500 |
((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr )); |
501 |
|
502 |
#ifdef PINMODE
|
503 |
PCintPort::s_currXORlastPinView=PCintPort::curr ^ lastPinView; |
504 |
PCintPort::s_portRisingPins_nCurr=portRisingPins & PCintPort::curr; |
505 |
PCintPort::s_portFallingPins_nNCurr=portFallingPins & ~PCintPort::curr; |
506 |
#endif
|
507 |
lastPinView = PCintPort::curr; |
508 |
|
509 |
PCintPin* p = firstPin; |
510 |
while (p) {
|
511 |
// Trigger interrupt if the bit is high and it's set to trigger on mode RISING or CHANGE
|
512 |
// Trigger interrupt if the bit is low and it's set to trigger on mode FALLING or CHANGE
|
513 |
thisChangedPin=p->mask & changedPins; // PinChangeIntSpeedTest makes this 3673... weird. But GOOD!!!
|
514 |
if (p->mask & changedPins) {
|
515 |
#ifndef NO_PIN_STATE
|
516 |
PCintPort::pinState=PCintPort::curr & p->mask ? HIGH : LOW; |
517 |
#endif
|
518 |
#ifndef NO_PIN_NUMBER
|
519 |
PCintPort::arduinoPin=p->arduinoPin; |
520 |
#endif
|
521 |
#ifdef PINMODE
|
522 |
PCintPort::pinmode=p->mode; |
523 |
PCintPort::s_portRisingPins=portRisingPins; |
524 |
PCintPort::s_portFallingPins=portFallingPins; |
525 |
PCintPort::s_pmask=p->mask; |
526 |
PCintPort::s_changedPins=changedPins; |
527 |
#endif
|
528 |
p->PCintFunc(); |
529 |
} |
530 |
p=p->next; |
531 |
} |
532 |
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
533 |
pcifr = PCIFR & PCICRbit; |
534 |
if (pcifr == 0) break; |
535 |
PCIFR |= PCICRbit; |
536 |
#ifdef PINMODE
|
537 |
PCintPort::pcint_multi++; |
538 |
if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1; // PCIFR & PCICRbit should ALWAYS be 0 here! |
539 |
#endif
|
540 |
PCintPort::curr=portInputReg; |
541 |
} |
542 |
#endif
|
543 |
} |
544 |
|
545 |
#ifndef NO_PORTA_PINCHANGES
|
546 |
ISR(PCINT0_vect) { |
547 |
#ifdef PINMODE
|
548 |
PCintPort::s_PORT='A';
|
549 |
#endif
|
550 |
PCintPort::curr = portA.portInputReg; |
551 |
portA.PCint(); |
552 |
} |
553 |
#define PORTBVECT PCINT1_vect
|
554 |
#define PORTCVECT PCINT2_vect
|
555 |
#define PORTDVECT PCINT3_vect
|
556 |
#else
|
557 |
#define PORTBVECT PCINT0_vect
|
558 |
#define PORTCVECT PCINT1_vect
|
559 |
#define PORTDVECT PCINT2_vect
|
560 |
#endif
|
561 |
|
562 |
#ifndef NO_PORTB_PINCHANGES
|
563 |
ISR(PORTBVECT) { |
564 |
#ifdef PINMODE
|
565 |
PCintPort::s_PORT='B';
|
566 |
#endif
|
567 |
PCintPort::curr = portB.portInputReg; |
568 |
portB.PCint(); |
569 |
} |
570 |
#endif
|
571 |
|
572 |
#ifndef NO_PORTC_PINCHANGES
|
573 |
ISR(PORTCVECT) { |
574 |
#ifdef PINMODE
|
575 |
PCintPort::s_PORT='C';
|
576 |
#endif
|
577 |
PCintPort::curr = portC.portInputReg; |
578 |
portC.PCint(); |
579 |
} |
580 |
#endif
|
581 |
|
582 |
#ifndef NO_PORTD_PINCHANGES
|
583 |
ISR(PORTDVECT){ |
584 |
#ifdef PINMODE
|
585 |
PCintPort::s_PORT='D';
|
586 |
#endif
|
587 |
PCintPort::curr = portD.portInputReg; |
588 |
portD.PCint(); |
589 |
} |
590 |
#endif
|
591 |
|
592 |
#ifdef __USE_PORT_JK
|
593 |
#ifndef NO_PORTJ_PINCHANGES
|
594 |
ISR(PCINT1_vect) { |
595 |
#ifdef PINMODE
|
596 |
PCintPort::s_PORT='J';
|
597 |
#endif
|
598 |
PCintPort::curr = portJ.portInputReg; |
599 |
portJ.PCint(); |
600 |
} |
601 |
#endif
|
602 |
|
603 |
#ifndef NO_PORTK_PINCHANGES
|
604 |
ISR(PCINT2_vect){ |
605 |
#ifdef PINMODE
|
606 |
PCintPort::s_PORT='K';
|
607 |
#endif
|
608 |
PCintPort::curr = portK.portInputReg; |
609 |
portK.PCint(); |
610 |
} |
611 |
#endif
|
612 |
|
613 |
#endif // __USE_PORT_JK |
614 |
|
615 |
#ifdef GET_PCINT_VERSION
|
616 |
uint16_t getPCIntVersion () { |
617 |
return ((uint16_t) PCINT_VERSION);
|
618 |
} |
619 |
#endif // GET_PCINT_VERSION |
620 |
#endif // #ifndef LIBCALL_PINCHANGEINT ************************************************************* |
621 |
#endif // #ifndef PinChangeInt_h ******************************************************************* |