Revision c5d6b0e8
Adding better arduino code.
arduino/Encoder/encoder/Enc/Enc.ino | ||
---|---|---|
1 |
// declare pins |
|
2 |
int enc = 1; |
|
3 |
|
|
4 |
// declare globals |
|
5 |
int count = 0; |
|
6 |
int state = 1; // 1 if was high, 0 if was low |
|
7 |
|
|
8 |
//code that keeps loop time constant each loop |
|
9 |
int STD_LOOP_TIME = 9; |
|
10 |
int hz = 40; |
|
11 |
int print_period = 1000 / hz; |
|
12 |
unsigned long last_time = 0; |
|
13 |
|
|
14 |
void setup(){ |
|
15 |
Serial.begin(9600); |
|
16 |
pinMode(enc, INPUT); |
|
17 |
} |
|
18 |
|
|
19 |
/* returns 1 if there is a magnet |
|
20 |
* returns 0 otherwise |
|
21 |
*/ |
|
22 |
int isMagnet(){ |
|
23 |
int val = analogRead(enc); |
|
24 |
if (val < 512){ |
|
25 |
return 0; |
|
26 |
} else { |
|
27 |
return 1; |
|
28 |
} |
|
29 |
} |
|
30 |
|
|
31 |
|
|
32 |
void loop(){ |
|
33 |
// START Loop timing control ******************************** |
|
34 |
if (last_time < (millis() - print_period)) { |
|
35 |
Serial.println(count); |
|
36 |
last_time = millis(); |
|
37 |
} |
|
38 |
// END loop timing control ******************************** |
|
39 |
|
|
40 |
if (state != isMagnet()){ |
|
41 |
count++; |
|
42 |
state = !state; |
|
43 |
} |
|
44 |
} |
|
45 |
|
|
46 |
|
|
47 |
|
|
48 |
|
|
49 |
|
|
50 |
|
|
51 |
|
|
52 |
|
arduino/Encoder/encoder/encoder.ino | ||
---|---|---|
1 |
int enc = 10; |
|
2 |
|
|
3 |
void setup(){ |
|
4 |
Serial.begin(115200); |
|
5 |
pinMode(enc, OUTPUT); |
|
6 |
} |
|
7 |
|
|
8 |
|
|
9 |
void loop(){ |
|
10 |
for(int i = 0; i < 100000; i++){ |
|
11 |
|
|
12 |
} |
|
13 |
} |
|
14 |
|
arduino/Encoder/encoder/sketch_mar02a/sketch_mar02a.ino | ||
---|---|---|
1 |
int enc = 10; |
|
2 |
|
|
3 |
void setup(){ |
|
4 |
Serial.begin(9600); |
|
5 |
pinMode(enc, OUTPUT); |
|
6 |
} |
|
7 |
|
|
8 |
|
|
9 |
|
arduino/InterruptRCRecieverReference/InterruptRCReciever.ino | ||
---|---|---|
1 |
#include "RCArduinoFastLib.h" |
|
2 |
|
|
3 |
// include the pinchangeint library - see the links in the related topics section above for details |
|
4 |
#include "PinChangeInt.h" |
|
5 |
|
|
6 |
// Assign your channel in pins |
|
7 |
#define THROTTLE_IN_PIN 5 |
|
8 |
#define STEERING_IN_PIN 6 |
|
9 |
#define AUX_IN_PIN 7 |
|
10 |
|
|
11 |
// Assign your channel out pins |
|
12 |
#define THROTTLE_OUT_PIN 9//8 |
|
13 |
#define STEERING_OUT_PIN 8//9 |
|
14 |
#define AUX_OUT_PIN 10 |
|
15 |
|
|
16 |
// Assign servo indexes |
|
17 |
#define SERVO_THROTTLE 0 |
|
18 |
#define SERVO_STEERING 1 |
|
19 |
#define SERVO_AUX 2 |
|
20 |
#define SERVO_FRAME_SPACE 3 |
|
21 |
|
|
22 |
// These bit flags are set in bUpdateFlagsShared to indicate which |
|
23 |
// channels have new signals |
|
24 |
#define THROTTLE_FLAG 1 |
|
25 |
#define STEERING_FLAG 2 |
|
26 |
#define AUX_FLAG 4 |
|
27 |
|
|
28 |
// holds the update flags defined above |
|
29 |
volatile uint8_t bUpdateFlagsShared; |
|
30 |
|
|
31 |
// shared variables are updated by the ISR and read by loop. |
|
32 |
// In loop we immediatley take local copies so that the ISR can keep ownership of the |
|
33 |
// shared ones. To access these in loop |
|
34 |
// we first turn interrupts off with noInterrupts |
|
35 |
// we take a copy to use in loop and the turn interrupts back on |
|
36 |
// as quickly as possible, this ensures that we are always able to receive new signals |
|
37 |
volatile uint16_t unThrottleInShared; |
|
38 |
volatile uint16_t unSteeringInShared; |
|
39 |
volatile uint16_t unAuxInShared; |
|
40 |
|
|
41 |
// These are used to record the rising edge of a pulse in the calcInput functions |
|
42 |
// They do not need to be volatile as they are only used in the ISR. If we wanted |
|
43 |
// to refer to these in loop and the ISR then they would need to be declared volatile |
|
44 |
uint16_t unThrottleInStart; |
|
45 |
uint16_t unSteeringInStart; |
|
46 |
uint16_t unAuxInStart; |
|
47 |
|
|
48 |
uint16_t unLastAuxIn = 0; |
|
49 |
uint32_t ulVariance = 0; |
|
50 |
uint32_t ulGetNextSampleMillis = 0; |
|
51 |
uint16_t unMaxDifference = 0; |
|
52 |
|
|
53 |
void setup() |
|
54 |
{ |
|
55 |
Serial.begin(115200); |
|
56 |
|
|
57 |
Serial.println("multiChannels"); |
|
58 |
|
|
59 |
// attach servo objects, these will generate the correct |
|
60 |
// pulses for driving Electronic speed controllers, servos or other devices |
|
61 |
// designed to interface directly with RC Receivers |
|
62 |
CRCArduinoFastServos::attach(SERVO_THROTTLE,THROTTLE_OUT_PIN); |
|
63 |
CRCArduinoFastServos::attach(SERVO_STEERING,STEERING_OUT_PIN); |
|
64 |
CRCArduinoFastServos::attach(SERVO_AUX,AUX_OUT_PIN); |
|
65 |
|
|
66 |
// lets set a standard rate of 50 Hz by setting a frame space of 10 * 2000 = 3 Servos + 7 times 2000 |
|
67 |
CRCArduinoFastServos::setFrameSpaceA(SERVO_FRAME_SPACE,7*2000); |
|
68 |
|
|
69 |
CRCArduinoFastServos::begin(); |
|
70 |
|
|
71 |
// using the PinChangeInt library, attach the interrupts |
|
72 |
// used to read the channels |
|
73 |
PCintPort::attachInterrupt(THROTTLE_IN_PIN, calcThrottle,CHANGE); |
|
74 |
PCintPort::attachInterrupt(STEERING_IN_PIN, calcSteering,CHANGE); |
|
75 |
PCintPort::attachInterrupt(AUX_IN_PIN, calcAux,CHANGE); |
|
76 |
} |
|
77 |
|
|
78 |
void loop() |
|
79 |
{ |
|
80 |
// create local variables to hold a local copies of the channel inputs |
|
81 |
// these are declared static so that thier values will be retained |
|
82 |
// between calls to loop. |
|
83 |
static uint16_t unThrottleIn; |
|
84 |
static uint16_t unSteeringIn; |
|
85 |
static uint16_t unAuxIn; |
|
86 |
// local copy of update flags |
|
87 |
static uint8_t bUpdateFlags; |
|
88 |
|
|
89 |
// check shared update flags to see if any channels have a new signal |
|
90 |
if(bUpdateFlagsShared) |
|
91 |
{ |
|
92 |
noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables |
|
93 |
|
|
94 |
// take a local copy of which channels were updated in case we need to use this in the rest of loop |
|
95 |
bUpdateFlags = bUpdateFlagsShared; |
|
96 |
|
|
97 |
// in the current code, the shared values are always populated |
|
98 |
// so we could copy them without testing the flags |
|
99 |
// however in the future this could change, so lets |
|
100 |
// only copy when the flags tell us we can. |
|
101 |
|
|
102 |
if(bUpdateFlags & THROTTLE_FLAG) |
|
103 |
{ |
|
104 |
unThrottleIn = unThrottleInShared; |
|
105 |
} |
|
106 |
|
|
107 |
if(bUpdateFlags & STEERING_FLAG) |
|
108 |
{ |
|
109 |
unSteeringIn = unSteeringInShared; |
|
110 |
} |
|
111 |
|
|
112 |
if(bUpdateFlags & AUX_FLAG) |
|
113 |
{ |
|
114 |
unAuxIn = unAuxInShared; |
|
115 |
} |
|
116 |
|
|
117 |
// clear shared copy of updated flags as we have already taken the updates |
|
118 |
// we still have a local copy if we need to use it in bUpdateFlags |
|
119 |
bUpdateFlagsShared = 0; |
|
120 |
|
|
121 |
interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on |
|
122 |
// as soon as interrupts are back on, we can no longer use the shared copies, the interrupt |
|
123 |
// service routines own these and could update them at any time. During the update, the |
|
124 |
// shared copies may contain junk. Luckily we have our local copies to work with :-) |
|
125 |
} |
|
126 |
|
|
127 |
// do any processing from here onwards |
|
128 |
// only use the local values unAuxIn, unThrottleIn and unSteeringIn, the shared |
|
129 |
// variables unAuxInShared, unThrottleInShared, unSteeringInShared are always owned by |
|
130 |
// the interrupt routines and should not be used in loop |
|
131 |
|
|
132 |
// the following code provides simple pass through |
|
133 |
// this is a good initial test, the Arduino will pass through |
|
134 |
// receiver input as if the Arduino is not there. |
|
135 |
// This should be used to confirm the circuit and power |
|
136 |
// before attempting any custom processing in a project. |
|
137 |
|
|
138 |
// we are checking to see if the channel value has changed, this is indicated |
|
139 |
// by the flags. For the simple pass through we don't really need this check, |
|
140 |
// but for a more complex project where a new signal requires significant processing |
|
141 |
// this allows us to only calculate new values when we have new inputs, rather than |
|
142 |
// on every cycle. |
|
143 |
if(bUpdateFlags & THROTTLE_FLAG) |
|
144 |
{ |
|
145 |
CRCArduinoFastServos::writeMicroseconds(SERVO_THROTTLE,unThrottleIn); |
|
146 |
} |
|
147 |
|
|
148 |
if(bUpdateFlags & STEERING_FLAG) |
|
149 |
{ |
|
150 |
CRCArduinoFastServos::writeMicroseconds(SERVO_STEERING,unSteeringIn); |
|
151 |
} |
|
152 |
|
|
153 |
if(bUpdateFlags & AUX_FLAG) |
|
154 |
{ |
|
155 |
CRCArduinoFastServos::writeMicroseconds(SERVO_AUX,unAuxIn); |
|
156 |
} |
|
157 |
|
|
158 |
delay(500); |
|
159 |
bUpdateFlags = 0; |
|
160 |
} |
|
161 |
|
|
162 |
|
|
163 |
// simple interrupt service routine |
|
164 |
void calcThrottle() |
|
165 |
{ |
|
166 |
if(PCintPort::pinState) |
|
167 |
{ |
|
168 |
unThrottleInStart = TCNT1; |
|
169 |
} |
|
170 |
else |
|
171 |
{ |
|
172 |
unThrottleInShared = (TCNT1 - unThrottleInStart)>>1; |
|
173 |
bUpdateFlagsShared |= THROTTLE_FLAG; |
|
174 |
} |
|
175 |
} |
|
176 |
|
|
177 |
void calcSteering() |
|
178 |
{ |
|
179 |
if(PCintPort::pinState) |
|
180 |
{ |
|
181 |
unSteeringInStart = TCNT1; |
|
182 |
} |
|
183 |
else |
|
184 |
{ |
|
185 |
unSteeringInShared = (TCNT1 - unSteeringInStart)>>1; |
|
186 |
|
|
187 |
bUpdateFlagsShared |= STEERING_FLAG; |
|
188 |
} |
|
189 |
} |
|
190 |
|
|
191 |
void calcAux() |
|
192 |
{ |
|
193 |
if(PCintPort::pinState) |
|
194 |
{ |
|
195 |
unAuxInStart = TCNT1; |
|
196 |
} |
|
197 |
else |
|
198 |
{ |
|
199 |
unAuxInShared = (TCNT1 - unAuxInStart)>>1; |
|
200 |
bUpdateFlagsShared |= AUX_FLAG; } |
|
201 |
} |
|
202 |
|
arduino/InterruptRCRecieverReference/PinChangeInt.h | ||
---|---|---|
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 ******************************************************************* |
arduino/InterruptRCRecieverReference/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp | ||
---|---|---|
1 |
/* |
|
2 |
ByteBuffer.cpp - A circular buffer implementation for Arduino |
|
3 |
Created by Sigurdur Orn, July 19, 2010. |
|
4 |
siggi@mit.edu |
|
5 |
Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012 |
|
6 |
added the putString() method and the fillError variable. |
|
7 |
added the checkError() and resetError() methods. The checkError() method resets the fillError variable |
|
8 |
to false as a side effect. |
|
9 |
added the ByteBuffer(unsigned int buf_size) constructor. |
|
10 |
added the init() method, and had the constructor call it automagically. |
|
11 |
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts. |
|
12 |
*/ |
|
13 |
|
|
14 |
#include "ByteBuffer.h" |
|
15 |
|
|
16 |
void ByteBuffer::init(){ |
|
17 |
ByteBuffer::init(DEFAULTBUFSIZE); |
|
18 |
} |
|
19 |
|
|
20 |
void ByteBuffer::init(unsigned int buf_length){ |
|
21 |
data = (byte*)malloc(sizeof(byte)*buf_length); |
|
22 |
capacity = buf_length; |
|
23 |
position = 0; |
|
24 |
length = 0; |
|
25 |
fillError=false; |
|
26 |
} |
|
27 |
|
|
28 |
void ByteBuffer::deAllocate(){ |
|
29 |
free(data); |
|
30 |
} |
|
31 |
|
|
32 |
void ByteBuffer::clear(){ |
|
33 |
position = 0; |
|
34 |
length = 0; |
|
35 |
} |
|
36 |
|
|
37 |
void ByteBuffer::resetError(){ |
|
38 |
fillError=false; |
|
39 |
} |
|
40 |
|
|
41 |
boolean ByteBuffer::checkError(){ |
|
42 |
/* |
|
43 |
if (fillError) { |
|
44 |
Serial.print("E: checkError: length "); |
|
45 |
Serial.println(length, DEC); |
|
46 |
} |
|
47 |
*/ |
|
48 |
|
|
49 |
boolean result=fillError; |
|
50 |
fillError=false; |
|
51 |
return(result); |
|
52 |
} |
|
53 |
|
|
54 |
int ByteBuffer::getSize(){ |
|
55 |
return length; |
|
56 |
} |
|
57 |
|
|
58 |
int ByteBuffer::getCapacity(){ |
|
59 |
return capacity; |
|
60 |
} |
|
61 |
|
|
62 |
byte ByteBuffer::peek(unsigned int index){ |
|
63 |
byte b = data[(position+index)%capacity]; |
|
64 |
return b; |
|
65 |
} |
|
66 |
|
|
67 |
uint8_t ByteBuffer::put(byte in){ |
|
68 |
if(length < capacity){ |
|
69 |
// save data byte at end of buffer |
|
70 |
data[(position+length) % capacity] = in; |
|
71 |
// increment the length |
|
72 |
length++; |
|
73 |
return 1; |
|
74 |
} |
|
75 |
// return failure |
|
76 |
//Serial.print("E: put: "); |
|
77 |
//Serial.println(length, DEC); |
|
78 |
fillError=true; |
|
79 |
return 0; |
|
80 |
} |
|
81 |
|
|
82 |
|
|
83 |
uint8_t ByteBuffer::putString(char *in){ |
|
84 |
uint8_t count=0; |
|
85 |
char *inString; |
|
86 |
|
|
87 |
inString=in; |
|
88 |
uint8_t oldSREG = SREG; cli(); |
|
89 |
while(length <= capacity){ |
|
90 |
if (length == capacity) { |
|
91 |
fillError=true; |
|
92 |
return count; |
|
93 |
} |
|
94 |
// save data byte at end of buffer |
|
95 |
data[(position+length) % capacity] = *inString; |
|
96 |
// increment the length |
|
97 |
length++; |
|
98 |
inString++; |
|
99 |
count++; |
|
100 |
if (*inString == 0) { |
|
101 |
if (count==0) fillError=true; // Serial.println("E: putString"); }; |
|
102 |
SREG = oldSREG; // Restore register; reenables interrupts |
|
103 |
return count; |
|
104 |
} |
|
105 |
} |
|
106 |
SREG = oldSREG; // Restore register; reenables interrupts |
|
107 |
return count; |
|
108 |
} |
|
109 |
|
|
110 |
uint8_t ByteBuffer::putInFront(byte in){ |
|
111 |
uint8_t oldSREG = SREG; cli(); |
|
112 |
if(length < capacity){ |
|
113 |
// save data byte at end of buffer |
|
114 |
if( position == 0 ) |
|
115 |
position = capacity-1; |
|
116 |
else |
|
117 |
position = (position-1)%capacity; |
|
118 |
data[position] = in; |
|
119 |
// increment the length |
|
120 |
length++; |
|
121 |
SREG = oldSREG; // Restore register; reenables interrupts |
|
122 |
return 1; |
|
123 |
} |
|
124 |
// return failure |
|
125 |
//Serial.println("E: putInFront"); |
|
126 |
fillError=true; |
|
127 |
SREG = oldSREG; // Restore register; reenables interrupts |
|
128 |
return 0; |
|
129 |
} |
|
130 |
|
|
131 |
byte ByteBuffer::get(){ |
|
132 |
uint8_t oldSREG = SREG; cli(); |
|
133 |
byte b = 0; |
|
134 |
|
|
135 |
if(length > 0){ |
|
136 |
b = data[position]; |
|
137 |
// move index down and decrement length |
|
138 |
position = (position+1)%capacity; |
|
139 |
length--; |
|
140 |
} |
|
141 |
SREG = oldSREG; // Restore register; reenables interrupts |
|
142 |
return b; |
|
143 |
} |
|
144 |
|
|
145 |
byte ByteBuffer::getFromBack(){ |
|
146 |
byte b = 0; |
|
147 |
if(length > 0){ |
|
148 |
uint8_t oldSREG = SREG; cli(); |
|
149 |
b = data[(position+length-1)%capacity]; |
|
150 |
length--; |
|
151 |
SREG = oldSREG; // Restore register; reenables interrupts |
|
152 |
} |
|
153 |
|
|
154 |
return b; |
|
155 |
} |
|
156 |
|
|
157 |
// |
|
158 |
// Ints |
|
159 |
// |
|
160 |
|
|
161 |
void ByteBuffer::putIntInFront(int in){ |
|
162 |
byte *pointer = (byte *)∈ |
|
163 |
putInFront(pointer[0]); |
|
164 |
putInFront(pointer[1]); |
|
165 |
} |
|
166 |
|
|
167 |
void ByteBuffer::putInt(int in){ |
|
168 |
byte *pointer = (byte *)∈ |
|
169 |
put(pointer[1]); |
|
170 |
put(pointer[0]); |
|
171 |
} |
|
172 |
|
|
173 |
|
|
174 |
int ByteBuffer::getInt(){ |
|
175 |
int ret; |
|
176 |
byte *pointer = (byte *)&ret; |
|
177 |
pointer[1] = get(); |
|
178 |
pointer[0] = get(); |
|
179 |
return ret; |
|
180 |
} |
|
181 |
|
|
182 |
int ByteBuffer::getIntFromBack(){ |
|
183 |
int ret; |
|
184 |
byte *pointer = (byte *)&ret; |
|
185 |
pointer[0] = getFromBack(); |
|
186 |
pointer[1] = getFromBack(); |
|
187 |
return ret; |
|
188 |
} |
|
189 |
|
|
190 |
// |
|
191 |
// Longs |
|
192 |
// |
|
193 |
|
|
194 |
void ByteBuffer::putLongInFront(long in){ |
|
195 |
byte *pointer = (byte *)∈ |
|
196 |
putInFront(pointer[0]); |
|
197 |
putInFront(pointer[1]); |
|
198 |
putInFront(pointer[2]); |
|
199 |
putInFront(pointer[3]); |
|
200 |
} |
|
201 |
|
|
202 |
void ByteBuffer::putLong(long in){ |
|
203 |
byte *pointer = (byte *)∈ |
|
204 |
put(pointer[3]); |
|
205 |
put(pointer[2]); |
|
206 |
put(pointer[1]); |
|
207 |
put(pointer[0]); |
|
208 |
} |
|
209 |
|
|
210 |
|
|
211 |
long ByteBuffer::getLong(){ |
|
212 |
long ret; |
|
213 |
byte *pointer = (byte *)&ret; |
|
214 |
pointer[3] = get(); |
|
215 |
pointer[2] = get(); |
|
216 |
pointer[1] = get(); |
|
217 |
pointer[0] = get(); |
|
218 |
return ret; |
|
219 |
} |
|
220 |
|
|
221 |
long ByteBuffer::getLongFromBack(){ |
|
222 |
long ret; |
|
223 |
byte *pointer = (byte *)&ret; |
|
224 |
pointer[0] = getFromBack(); |
|
225 |
pointer[1] = getFromBack(); |
|
226 |
pointer[2] = getFromBack(); |
|
227 |
pointer[3] = getFromBack(); |
|
228 |
return ret; |
|
229 |
} |
|
230 |
|
|
231 |
|
|
232 |
// |
|
233 |
// Floats |
|
234 |
// |
|
235 |
|
|
236 |
void ByteBuffer::putFloatInFront(float in){ |
|
237 |
byte *pointer = (byte *)∈ |
|
238 |
putInFront(pointer[0]); |
|
239 |
putInFront(pointer[1]); |
|
240 |
putInFront(pointer[2]); |
|
241 |
putInFront(pointer[3]); |
|
242 |
} |
|
243 |
|
|
244 |
void ByteBuffer::putFloat(float in){ |
|
245 |
byte *pointer = (byte *)∈ |
|
246 |
put(pointer[3]); |
|
247 |
put(pointer[2]); |
|
248 |
put(pointer[1]); |
|
249 |
put(pointer[0]); |
|
250 |
} |
|
251 |
|
|
252 |
float ByteBuffer::getFloat(){ |
|
253 |
float ret; |
|
254 |
byte *pointer = (byte *)&ret; |
|
255 |
pointer[3] = get(); |
|
256 |
pointer[2] = get(); |
|
257 |
pointer[1] = get(); |
|
258 |
pointer[0] = get(); |
|
259 |
return ret; |
|
260 |
} |
|
261 |
|
|
262 |
float ByteBuffer::getFloatFromBack(){ |
|
263 |
float ret; |
|
264 |
byte *pointer = (byte *)&ret; |
|
265 |
pointer[0] = getFromBack(); |
|
266 |
pointer[1] = getFromBack(); |
|
267 |
pointer[2] = getFromBack(); |
|
268 |
pointer[3] = getFromBack(); |
|
269 |
return ret; |
|
270 |
} |
|
271 |
|
|
272 |
|
arduino/InterruptRCRecieverReference/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h | ||
---|---|---|
1 |
/* |
|
2 |
ByteBuffer.h - A circular buffer implementation for Arduino |
|
3 |
Created by Sigurdur Orn, July 19, 2010. siggi@mit.edu |
|
4 |
Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012 |
|
5 |
added the putString() method and the fillError variable. |
|
6 |
added the checkError() and resetError() methods. The checkError() method resets the fillError variable |
|
7 |
to false as a side effect. |
|
8 |
added the ByteBuffer(unsigned int buf_size) constructor. |
|
9 |
added the init() method, and had the constructor call it automagically. |
|
10 |
protected certain sections of the code with cli()/sei() calls, for safe use by interrupts. |
|
11 |
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts. |
|
12 |
*/ |
|
13 |
|
|
14 |
#ifndef ByteBuffer_h |
|
15 |
#define ByteBuffer_h |
|
16 |
|
|
17 |
#if defined(ARDUINO) && ARDUINO >= 100 |
|
18 |
#include <Arduino.h> |
|
19 |
#else |
|
20 |
#include <WProgram.h> |
|
21 |
#endif |
|
22 |
//#include <util/atomic.h> |
|
23 |
|
|
24 |
#define DEFAULTBUFSIZE 32 |
|
25 |
class ByteBuffer |
|
26 |
{ |
|
27 |
public: |
|
28 |
ByteBuffer() { |
|
29 |
init(); |
|
30 |
}; |
|
31 |
ByteBuffer(unsigned int buf_size) { |
|
32 |
init(buf_size); |
|
33 |
}; |
|
34 |
|
|
35 |
// This method initializes the datastore of the buffer to a certain size. |
|
36 |
void init(unsigned int buf_size); |
|
37 |
|
|
38 |
// This method initializes the datastore of the buffer to the default size. |
|
39 |
void init(); |
|
40 |
|
|
41 |
// This method resets the buffer into an original state (with no data) |
|
42 |
void clear(); |
|
43 |
|
|
44 |
// This method resets the fillError variable to false. |
|
45 |
void resetError(); |
|
46 |
|
|
47 |
// This method tells you if your buffer overflowed at some time since the last |
|
48 |
// check. The error state will be reset to false. |
|
49 |
boolean checkError(); |
|
50 |
|
|
51 |
// This releases resources for this buffer, after this has been called the buffer should NOT be used |
|
52 |
void deAllocate(); |
|
53 |
|
|
54 |
// Returns how much space is used in the buffer |
|
55 |
int getSize(); |
|
56 |
|
|
57 |
// Returns the maximum capacity of the buffer |
|
58 |
int getCapacity(); |
|
59 |
|
|
60 |
// This method returns the byte that is located at index in the buffer but doesn't modify the buffer like the get methods (doesn't remove the retured byte from the buffer) |
|
61 |
byte peek(unsigned int index); |
|
62 |
|
|
63 |
// |
|
64 |
// Put methods, either a regular put in back or put in front |
|
65 |
// |
|
66 |
uint8_t putInFront(byte in); |
|
67 |
uint8_t put(byte in); |
|
68 |
uint8_t putString(char *in); |
|
69 |
|
|
70 |
void putIntInFront(int in); |
|
71 |
void putInt(int in); |
|
72 |
|
|
73 |
void putLongInFront(long in); |
|
74 |
void putLong(long in); |
|
75 |
|
|
76 |
void putFloatInFront(float in); |
|
77 |
void putFloat(float in); |
|
78 |
|
|
79 |
// |
|
80 |
// Get methods, either a regular get from front or from back |
|
81 |
// |
|
82 |
byte get(); |
|
83 |
byte getFromBack(); |
|
84 |
|
|
85 |
int getInt(); |
|
86 |
int getIntFromBack(); |
|
87 |
|
|
88 |
long getLong(); |
|
89 |
long getLongFromBack(); |
|
90 |
|
|
91 |
float getFloat(); |
|
92 |
float getFloatFromBack(); |
|
93 |
|
|
94 |
private: |
|
95 |
byte* data; |
|
96 |
|
|
97 |
volatile unsigned int capacity; |
|
98 |
volatile unsigned int position; |
|
99 |
volatile unsigned int length; |
|
100 |
volatile boolean fillError; |
|
101 |
}; |
|
102 |
|
|
103 |
#endif |
|
104 |
|
arduino/InterruptRCRecieverReference/PinChangeInt/Examples/GetPSTR/GetPSTR.h | ||
---|---|---|
1 |
#ifndef INCLUDE_GETPSTR |
|
2 |
#define INCLUDE_GETPSTR |
|
3 |
|
|
4 |
#if defined(ARDUINO) && ARDUINO >= 100 |
|
5 |
#include <Arduino.h> |
|
6 |
#else |
|
7 |
#include "pins_arduino.h" |
|
8 |
#include "WProgram.h" |
|
9 |
#include "wiring.h" |
|
10 |
#endif |
|
11 |
|
|
12 |
#define getPSTR(s) pgmStrToRAM(PSTR(s)) |
|
13 |
|
|
14 |
char *_pstr_to_print; |
|
15 |
char *pgmStrToRAM(PROGMEM char *theString) { |
|
16 |
free(_pstr_to_print); |
|
17 |
_pstr_to_print=(char *) malloc(strlen_P(theString)); |
|
18 |
strcpy_P(_pstr_to_print, theString); |
|
19 |
return (_pstr_to_print); |
|
20 |
} |
|
21 |
#endif |
arduino/InterruptRCRecieverReference/PinChangeInt/Examples/PinChangeIntExample/PinChangeIntExample.pde | ||
---|---|---|
1 |
// PinChangeIntExample, version 1.1 Sun Jan 15 06:24:19 CST 2012 |
|
2 |
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information. |
|
3 |
//-------- define these in your sketch, if applicable ---------------------------------------------------------- |
|
4 |
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts |
|
5 |
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline |
|
6 |
// reducing the size and latency of the handler. |
|
7 |
//#define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts |
|
8 |
//#define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts |
|
9 |
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts |
|
10 |
// if there is only one PCInt vector in use the code can be inlined |
|
11 |
// reducing latency and code size |
|
12 |
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation. |
|
13 |
// #define DISABLE_PCINT_MULTI_SERVICE |
|
14 |
//-------- define the above in your sketch, if applicable ------------------------------------------------------ |
|
15 |
#include <PinChangeInt.h> |
|
16 |
|
|
17 |
// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions. |
|
18 |
// All interrupts are serviced immediately, but one of the pins (pin 4) will show you immediately |
|
19 |
// on the Terminal. The other function connected to 2 pins sets an array member that is queried in loop(). |
|
20 |
// You can then query the array at your leisure. |
|
21 |
// This makes loop timing non-critical. |
|
22 |
|
|
23 |
// Add more Pins at your leisure. |
|
24 |
// For the Analog Input pins used as digital input pins, and you can use 14, 15, 16, etc. |
|
25 |
// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's |
|
26 |
// for the Analog Input pins and will properly recognize e.g., pinMode(A0, INPUT); |
|
27 |
#define PIN1 2 |
|
28 |
#define PIN2 3 |
|
29 |
#define PIN3 4 |
|
30 |
|
|
31 |
uint8_t latest_interrupted_pin; |
|
32 |
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins |
|
33 |
void quicfunc() { |
|
34 |
latest_interrupted_pin=PCintPort::arduinoPin; |
|
35 |
interrupt_count[latest_interrupted_pin]++; |
|
36 |
}; |
|
37 |
|
|
38 |
// You can assign any number of functions to any number of pins. |
|
39 |
// How cool is that? |
|
40 |
void pin3func() { |
|
41 |
Serial.print("Pin "); Serial.print(PIN3, DEC); Serial.println("!"); |
|
42 |
} |
|
43 |
|
|
44 |
void setup() { |
|
45 |
pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH); |
|
46 |
PCintPort::attachInterrupt(PIN1, &quicfunc, FALLING); // add more attachInterrupt code as required |
|
47 |
pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH); |
|
48 |
PCintPort::attachInterrupt(PIN2, &quicfunc, FALLING); |
|
49 |
pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH); |
|
50 |
PCintPort::attachInterrupt(PIN3, &pin3func, CHANGE); |
|
51 |
Serial.begin(115200); |
|
52 |
Serial.println("---------------------------------------"); |
|
53 |
} |
|
54 |
|
|
55 |
uint8_t i; |
|
56 |
void loop() { |
|
57 |
uint8_t count; |
|
58 |
Serial.print("."); |
|
59 |
delay(1000); |
|
60 |
for (i=0; i < 20; i++) { |
|
61 |
if (interrupt_count[i] != 0) { |
|
62 |
count=interrupt_count[i]; |
|
63 |
interrupt_count[i]=0; |
|
64 |
Serial.print("Count for pin "); |
|
65 |
if (i < 14) { |
|
66 |
Serial.print("D"); |
|
67 |
Serial.print(i, DEC); |
|
68 |
} else { |
|
69 |
Serial.print("A"); |
|
70 |
Serial.print(i-14, DEC); |
|
71 |
} |
|
72 |
Serial.print(" is "); |
|
73 |
Serial.println(count, DEC); |
|
74 |
} |
|
75 |
} |
|
76 |
} |
|
77 |
|
arduino/InterruptRCRecieverReference/PinChangeInt/Examples/PinChangeIntSpeedTest/PinChangeIntSpeedTest.pde | ||
---|---|---|
1 |
// PinChangeIntSpeedTest by GreyGnome aka Mike Schwager. Version numbers here refer to this sketch. |
|
2 |
// Version 1.0 - initial version |
|
3 |
// Version 1.1 - added code to test digitalRead() |
|
4 |
// Version 1.2 - added new comments for the #define's for the NO_PORTx_PINCHANGES. |
|
5 |
// Version 1.3 - includes cbiface.h with ooPinChangeInt, rather than cb.h |
|
6 |
// Version 1.4 - testing version 2.10Beta with robtillaart's optimization |
|
7 |
// Also added a #define/#undef INLINE_PCINTFUNC for inlining of the function called by the interrupt. |
|
8 |
// Default: #undef for using the function as per usual. Changed PCIVERSION so that |
|
9 |
// ooPinChangeInt starts at 1000 instead of 200. Modified the "Start" message to show "Start..", pause |
|
10 |
// for 1 second, show "*\n" (where \n is a newline), pause for 1 second, then run the test. |
|
11 |
// Version 1.4 - made this compatible with version 1.5 of PinChangeInt |
|
12 |
// Version 1.5 - modified it to use #define OOPCIVERSION for ooPinChangeInt |
|
13 |
|
|
14 |
// This version number is for ooPinChangeInt |
|
15 |
//#define OOPCIVERSION 1030 |
|
16 |
#ifndef OOPCIVERSION |
|
17 |
#define PCIVERSION 217 // 110 if using PinChangeInt-1.1, 120 for version 1.2 |
|
18 |
// 1000 for ooPinChangeIntversion 1.00, 1001 for ooPinChangeInt version 1.01, etc. |
|
19 |
#endif |
|
20 |
|
|
21 |
//-------- define these in your sketch, if applicable ---------------------------------------------------------- |
|
22 |
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts |
|
23 |
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline |
|
24 |
// reducing the size and latency of the handler. |
|
25 |
#undef NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts |
|
26 |
#undef NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts |
|
27 |
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts |
|
28 |
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine |
|
29 |
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or |
|
30 |
// PCintPort::arduinoPin are set and made available to your interrupt routine. |
|
31 |
// #define NO_PIN_STATE // to indicate that you don't need the pinState |
|
32 |
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin |
|
33 |
// if there is only one PCInt vector in use the code can be inlined |
|
34 |
// reducing latency and code size |
|
35 |
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation. |
|
36 |
//#define DISABLE_PCINT_MULTI_SERVICE |
|
37 |
//-------- define the above in your sketch, if applicable ------------------------------------------------------ |
|
38 |
#if defined(OOPCIVERSION) |
|
39 |
#define LIBRARYUNDERTEST "ooPinChangeInt" |
|
40 |
#include <ooPinChangeInt.h> |
|
41 |
#if PCIVERSION == 1001 |
|
42 |
#include <cb.h> |
|
43 |
#else |
|
44 |
#include <cbiface.h> |
|
45 |
#endif |
|
46 |
#else |
|
47 |
#define LIBRARYUNDERTEST "PinChangeInt" |
|
48 |
#include <PinChangeInt.h> |
|
49 |
#endif |
|
50 |
|
|
51 |
#define SERIALSTUFF // undef to take out all serial statements. Default: #define for measuring time. |
|
52 |
#undef MEMTEST // undef to take out memory tests. Default: #undef for measuring time. |
|
53 |
#undef INLINE_PCINTFUNC // define to inline the function called from the interrupt. This should have no effect, |
|
54 |
// because the compiler will store the registers upon calling the interrupt routine, just |
|
55 |
// like calling a function. Still, we test all assumptions. |
|
56 |
//----------------------- |
|
57 |
// NOTE: BECAUSE OF COLLISIONS in these libraries, you CANNOT have both libraries: PinChangeInt |
|
58 |
// and ooPinChangeInt in the libraries directory at the same time. That said, under UNIX-y operating |
|
59 |
// systems, it's easy to move the library directory to a name such as "PinChangeInt-1.3", which the |
|
60 |
// Arduino will not recognize, and then create a symbolic link when you want to use a library. Such as: |
|
61 |
// cd ~/Documents/Arduino/libaries |
|
62 |
// mv PinChangeInt PinChangeInt-1.30 |
|
63 |
// mv ooPinChangeInt ooPinChangeInt-1.00 |
Also available in: Unified diff