Added some more projects and libraries.
This commit is contained in:
parent
f7151392ab
commit
1e1459fa50
94 changed files with 11904 additions and 0 deletions
324
libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp
Executable file
324
libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.cpp
Executable file
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
ByteBuffer.cpp - A circular buffer implementation for Arduino
|
||||
Created by Sigurdur Orn, July 19, 2010.
|
||||
siggi@mit.edu
|
||||
Updated by GreyGnome (aka Mike Schwager) Mon Apr 8 21:11:15 CDT 2013
|
||||
Fixed putString() so it reenables inputs correctly. In the if (length == capacity) section,
|
||||
it was missing this line:
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012
|
||||
added the putString() method and the fillError variable.
|
||||
added the checkError() and resetError() methods. The checkError() method resets the fillError variable
|
||||
to false as a side effect.
|
||||
added the ByteBuffer(unsigned int buf_size) constructor.
|
||||
added the init() method, and had the constructor call it automagically.
|
||||
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts.
|
||||
Mon Dec 3 07:55:04 CST 2012
|
||||
Added the putHex() and putDec() methods.
|
||||
*/
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
|
||||
void ByteBuffer::init(){
|
||||
ByteBuffer::init(DEFAULTBUFSIZE);
|
||||
}
|
||||
|
||||
void ByteBuffer::init(unsigned int buf_length){
|
||||
data = (byte*)malloc(sizeof(byte)*buf_length);
|
||||
capacity = buf_length;
|
||||
position = 0;
|
||||
length = 0;
|
||||
fillError=false;
|
||||
}
|
||||
|
||||
// Arduino 1.0: free() doesn't free. :-( This is a no-op as of 11/2012.
|
||||
void ByteBuffer::deAllocate(){
|
||||
free(data);
|
||||
}
|
||||
|
||||
void ByteBuffer::clear(){
|
||||
position = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
void ByteBuffer::resetError(){
|
||||
fillError=false;
|
||||
}
|
||||
|
||||
boolean ByteBuffer::checkError(){
|
||||
/*
|
||||
if (fillError) {
|
||||
Serial.print("E: checkError: length ");
|
||||
Serial.println(length, DEC);
|
||||
}
|
||||
*/
|
||||
|
||||
boolean result=fillError;
|
||||
fillError=false;
|
||||
return(result);
|
||||
}
|
||||
|
||||
int ByteBuffer::getSize(){
|
||||
return length;
|
||||
}
|
||||
|
||||
int ByteBuffer::getCapacity(){
|
||||
return capacity;
|
||||
}
|
||||
|
||||
byte ByteBuffer::peek(unsigned int index){
|
||||
byte b = data[(position+index)%capacity];
|
||||
return b;
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::put(byte in){
|
||||
if(length < capacity){
|
||||
// save data byte at end of buffer
|
||||
data[(position+length) % capacity] = in;
|
||||
// increment the length
|
||||
length++;
|
||||
return 1;
|
||||
}
|
||||
// return failure
|
||||
//Serial.print("E: put: ");
|
||||
//Serial.println(length, DEC);
|
||||
fillError=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint8_t ByteBuffer::putString(const char *in) {
|
||||
return(putString((char *) in));
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::putString(char *in){
|
||||
uint8_t count=0;
|
||||
char *inString;
|
||||
|
||||
inString=in;
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
while(length <= capacity){
|
||||
if (length == capacity) {
|
||||
fillError=true;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
// save data byte at end of buffer
|
||||
data[(position+length) % capacity] = *inString;
|
||||
// increment the length
|
||||
length++;
|
||||
inString++;
|
||||
count++;
|
||||
if (*inString == 0) {
|
||||
if (count==0) fillError=true; // Serial.println("E: putString"); };
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
}
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t ByteBuffer::putInFront(byte in){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
if(length < capacity){
|
||||
// save data byte at end of buffer
|
||||
if( position == 0 )
|
||||
position = capacity-1;
|
||||
else
|
||||
position = (position-1)%capacity;
|
||||
data[position] = in;
|
||||
// increment the length
|
||||
length++;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return 1;
|
||||
}
|
||||
// return failure
|
||||
//Serial.println("E: putInFront");
|
||||
fillError=true;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns 0 if length of data is 0.
|
||||
byte ByteBuffer::get(){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
byte b = 0;
|
||||
|
||||
if(length > 0){
|
||||
b = data[position];
|
||||
// move index down and decrement length
|
||||
position = (position+1)%capacity;
|
||||
length--;
|
||||
}
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return b;
|
||||
}
|
||||
|
||||
byte ByteBuffer::getFromBack(){
|
||||
byte b = 0;
|
||||
if(length > 0){
|
||||
uint8_t oldSREG = SREG; cli();
|
||||
b = data[(position+length-1)%capacity];
|
||||
length--;
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
//
|
||||
// Ints
|
||||
//
|
||||
|
||||
void ByteBuffer::putIntInFront(int in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putInt(int in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
|
||||
int ByteBuffer::getInt(){
|
||||
int ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ByteBuffer::getIntFromBack(){
|
||||
int ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ByteBuffer::putHex(uint8_t theByte) {
|
||||
put('0'); put('x');
|
||||
uint8_t hinybble=theByte>>4;
|
||||
uint8_t lonybble=theByte & 0x0F;
|
||||
uint8_t addend=0;
|
||||
if (hinybble >= 0x0a) addend=7;
|
||||
put(hinybble+48+addend);
|
||||
if (lonybble >= 0x0a) addend=7;
|
||||
else addend=0;
|
||||
put(lonybble+48+addend);
|
||||
}
|
||||
|
||||
void ByteBuffer::putDec(uint8_t number) {
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
uint8_t tmp=number;
|
||||
|
||||
while (tmp >= 100 ) {
|
||||
hundreds++;
|
||||
tmp-=100;
|
||||
}
|
||||
while (tmp >= 10 ) {
|
||||
tens++;
|
||||
tmp-=10;
|
||||
}
|
||||
ones=tmp;
|
||||
hundreds+=48; tens+=48; ones+=48;
|
||||
if (number >= 100) { put(hundreds); }
|
||||
if (number >= 10) { put(tens); }
|
||||
put(ones);
|
||||
}
|
||||
|
||||
void ByteBuffer::putDec(int8_t number) {
|
||||
uint8_t absNumber=abs(number);
|
||||
if (number < 0) put('-');
|
||||
putDec(absNumber);
|
||||
}
|
||||
|
||||
//
|
||||
// Longs
|
||||
//
|
||||
|
||||
void ByteBuffer::putLongInFront(long in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
putInFront(pointer[2]);
|
||||
putInFront(pointer[3]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putLong(long in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[3]);
|
||||
put(pointer[2]);
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
|
||||
long ByteBuffer::getLong(){
|
||||
long ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[3] = get();
|
||||
pointer[2] = get();
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ByteBuffer::getLongFromBack(){
|
||||
long ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
pointer[2] = getFromBack();
|
||||
pointer[3] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Floats
|
||||
//
|
||||
|
||||
void ByteBuffer::putFloatInFront(float in){
|
||||
byte *pointer = (byte *)∈
|
||||
putInFront(pointer[0]);
|
||||
putInFront(pointer[1]);
|
||||
putInFront(pointer[2]);
|
||||
putInFront(pointer[3]);
|
||||
}
|
||||
|
||||
void ByteBuffer::putFloat(float in){
|
||||
byte *pointer = (byte *)∈
|
||||
put(pointer[3]);
|
||||
put(pointer[2]);
|
||||
put(pointer[1]);
|
||||
put(pointer[0]);
|
||||
}
|
||||
|
||||
float ByteBuffer::getFloat(){
|
||||
float ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[3] = get();
|
||||
pointer[2] = get();
|
||||
pointer[1] = get();
|
||||
pointer[0] = get();
|
||||
return ret;
|
||||
}
|
||||
|
||||
float ByteBuffer::getFloatFromBack(){
|
||||
float ret;
|
||||
byte *pointer = (byte *)&ret;
|
||||
pointer[0] = getFromBack();
|
||||
pointer[1] = getFromBack();
|
||||
pointer[2] = getFromBack();
|
||||
pointer[3] = getFromBack();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
104
libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h
Executable file
104
libraries/PinChangeInt/Examples/ByteBuffer/ByteBuffer.h
Executable file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
ByteBuffer.h - A circular buffer implementation for Arduino
|
||||
Created by Sigurdur Orn, July 19, 2010. siggi@mit.edu
|
||||
Updated by GreyGnome (aka Mike Schwager) Thu Feb 23 17:25:14 CST 2012
|
||||
added the putString() method and the fillError variable.
|
||||
added the checkError() and resetError() methods. The checkError() method resets the fillError variable
|
||||
to false as a side effect.
|
||||
added the ByteBuffer(unsigned int buf_size) constructor.
|
||||
added the init() method, and had the constructor call it automagically.
|
||||
protected certain sections of the code with cli()/sei() calls, for safe use by interrupts.
|
||||
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts.
|
||||
*/
|
||||
|
||||
#ifndef ByteBuffer_h
|
||||
#define ByteBuffer_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
//#include <util/atomic.h>
|
||||
|
||||
#define DEFAULTBUFSIZE 32
|
||||
class ByteBuffer
|
||||
{
|
||||
public:
|
||||
ByteBuffer() {
|
||||
init();
|
||||
};
|
||||
ByteBuffer(unsigned int buf_size) {
|
||||
init(buf_size);
|
||||
};
|
||||
|
||||
// This method initializes the datastore of the buffer to a certain size.
|
||||
void init(unsigned int buf_size);
|
||||
|
||||
// This method initializes the datastore of the buffer to the default size.
|
||||
void init();
|
||||
|
||||
// This method resets the buffer into an original state (with no data)
|
||||
void clear();
|
||||
|
||||
// This method resets the fillError variable to false.
|
||||
void resetError();
|
||||
|
||||
// This method tells you if your buffer overflowed at some time since the last
|
||||
// check. The error state will be reset to false.
|
||||
boolean checkError();
|
||||
|
||||
// This releases resources for this buffer, after this has been called the buffer should NOT be used
|
||||
void deAllocate();
|
||||
|
||||
// Returns how much space is used in the buffer
|
||||
int getSize();
|
||||
|
||||
// Returns the maximum capacity of the buffer
|
||||
int getCapacity();
|
||||
|
||||
// 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)
|
||||
byte peek(unsigned int index);
|
||||
|
||||
//
|
||||
// Put methods, either a regular put in back or put in front
|
||||
//
|
||||
uint8_t putInFront(byte in);
|
||||
uint8_t put(byte in);
|
||||
uint8_t putString(char *in);
|
||||
|
||||
void putIntInFront(int in);
|
||||
void putInt(int in);
|
||||
|
||||
void putLongInFront(long in);
|
||||
void putLong(long in);
|
||||
|
||||
void putFloatInFront(float in);
|
||||
void putFloat(float in);
|
||||
|
||||
//
|
||||
// Get methods, either a regular get from front or from back
|
||||
//
|
||||
byte get();
|
||||
byte getFromBack();
|
||||
|
||||
int getInt();
|
||||
int getIntFromBack();
|
||||
|
||||
long getLong();
|
||||
long getLongFromBack();
|
||||
|
||||
float getFloat();
|
||||
float getFloatFromBack();
|
||||
|
||||
private:
|
||||
byte* data;
|
||||
|
||||
volatile unsigned int capacity;
|
||||
volatile unsigned int position;
|
||||
volatile unsigned int length;
|
||||
volatile boolean fillError;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
21
libraries/PinChangeInt/Examples/GetPSTR/GetPSTR.h
Normal file
21
libraries/PinChangeInt/Examples/GetPSTR/GetPSTR.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef INCLUDE_GETPSTR
|
||||
#define INCLUDE_GETPSTR
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include "pins_arduino.h"
|
||||
#include "WProgram.h"
|
||||
#include "wiring.h"
|
||||
#endif
|
||||
|
||||
#define getPSTR(s) pgmStrToRAM(PSTR(s))
|
||||
|
||||
char *_pstr_to_print;
|
||||
char *pgmStrToRAM(PROGMEM char *theString) {
|
||||
free(_pstr_to_print);
|
||||
_pstr_to_print=(char *) malloc(strlen_P(theString));
|
||||
strcpy_P(_pstr_to_print, theString);
|
||||
return (_pstr_to_print);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
// PinChangeIntDebug
|
||||
// version 1.0 Wed Jul 9 16:20:56 CDT 2014
|
||||
// Lean project for debugging. Don't expect a lot of commentary in here. This is for hacking.
|
||||
// This code taken from Examples/PinChangeIntTest, so refer there for more information and commentary.
|
||||
|
||||
#define PINMODE
|
||||
#define FLASH
|
||||
#include <ByteBuffer.h>
|
||||
#include <MemoryFree.h>
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// This example demonstrates a configuration of 6 interrupting pins and 3 interrupt functions.
|
||||
// A variety of interrupting pins have been chosen, so as to test all PORTs on the Arduino.
|
||||
// The pins are as follows:
|
||||
#define INTERRUPT_PIN1 2 // port D
|
||||
#define INTERRUPT_PIN2 3
|
||||
#define INTERRUPT_PIN3 11 // Port B
|
||||
#define INTERRUPT_PIN4 12
|
||||
#define INTERRUPT_PIN5 A3 // Port C, also can be given as "17"
|
||||
#define INTERRUPT_PIN6 A4
|
||||
|
||||
uint8_t pins[6]={ INTERRUPT_PIN1, INTERRUPT_PIN2, INTERRUPT_PIN3, INTERRUPT_PIN4, INTERRUPT_PIN5, INTERRUPT_PIN6 };
|
||||
uint8_t ports[6]={ 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
uint8_t latest_interrupted_pin;
|
||||
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
|
||||
uint8_t port;
|
||||
uint8_t mode;
|
||||
|
||||
ByteBuffer printBuffer(200);
|
||||
char charArray[16];
|
||||
char numBuffer[5] = { 0, 0, 0, 0, 0 };
|
||||
uint8_t printFull=0;
|
||||
|
||||
volatile boolean start=0;
|
||||
volatile boolean initial=true;
|
||||
long begintime=0;
|
||||
long now=0;
|
||||
|
||||
void smallIntToString(char *outString, int number) {
|
||||
uint8_t thousands=0;
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
|
||||
if (number > 9999) {
|
||||
outString[0]='S'; outString[1]='I'; outString[2]='Z'; outString[3]='E'; outString[4]=0;
|
||||
return;
|
||||
}
|
||||
while (number >= 1000 ) {
|
||||
thousands++;
|
||||
number-=1000;
|
||||
}
|
||||
while (number >= 100 ) {
|
||||
hundreds++;
|
||||
number-=100;
|
||||
}
|
||||
while (number >= 10 ) {
|
||||
tens++;
|
||||
number-=10;
|
||||
}
|
||||
ones=number;
|
||||
ones+=48;
|
||||
if (thousands > 0) {
|
||||
thousands+=48; hundreds+=48; tens+=48;
|
||||
outString[0]=thousands; outString[1]=hundreds; outString[2]=tens;
|
||||
outString[3]=ones; outString[4]=0;
|
||||
}
|
||||
else if (hundreds > 0) {
|
||||
hundreds+=48; tens+=48;
|
||||
outString[0]=hundreds; outString[1]=tens; outString[2]=ones; outString[3]=0;
|
||||
}
|
||||
else if (tens > 0) {
|
||||
tens+=48;
|
||||
outString[0]=tens; outString[1]=ones; outString[2]=0;
|
||||
}
|
||||
else { outString[0]=ones; outString[1]=0; };
|
||||
}
|
||||
|
||||
void showMode() {
|
||||
switch (mode) {
|
||||
case FALLING:
|
||||
printBuffer.putString((char *) "-F-");
|
||||
break;
|
||||
case RISING:
|
||||
printBuffer.putString((char *) "+R+");
|
||||
break;
|
||||
case CHANGE:
|
||||
printBuffer.putString((char *) "*C*");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void quicfunc0() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
smallIntToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString((char *) "f0p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
smallIntToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) "\n");
|
||||
};
|
||||
|
||||
#define MAXPINCOUNT 6
|
||||
void attachInterrupts() {
|
||||
uint8_t i;
|
||||
for (i=0; i < MAXPINCOUNT; i++) {
|
||||
pinMode(pins[i], INPUT); digitalWrite(pins[i], HIGH);
|
||||
ports[i]=digitalPinToPort(pins[i]);
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
void detachInterrupts() {
|
||||
uint8_t i;
|
||||
for (i=0; i < MAXPINCOUNT; i++) {
|
||||
PCintPort::detachInterrupt(pins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i;
|
||||
bool interrupts_are_attached=false;
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(250);
|
||||
Serial.println("Test");
|
||||
delay(250);
|
||||
Serial.print("*---*");
|
||||
begintime=millis();
|
||||
attachInterrupts(); interrupts_are_attached=true;
|
||||
Serial.println("NOTICE: Interrupts ATTACHED.");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#define LOOPDELAY 2000
|
||||
now=millis();
|
||||
uint8_t count;
|
||||
char outChar;
|
||||
uint8_t pinState;
|
||||
while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar);
|
||||
if ((now - begintime) > LOOPDELAY) {
|
||||
Serial.print(".");
|
||||
pinState=digitalRead(INTERRUPT_PIN1);
|
||||
if (pinState == HIGH){
|
||||
Serial.print("H");
|
||||
}
|
||||
else { Serial.print("L");
|
||||
}
|
||||
if (printBuffer.checkError()) {
|
||||
Serial.println("NOTICE: Some output lost due to filled buffer.");
|
||||
}
|
||||
for (i=0; i < 20; i++) {
|
||||
if (interrupt_count[i] != 0) {
|
||||
count=interrupt_count[i];
|
||||
interrupt_count[i]=0;
|
||||
Serial.print("Count for pin ");
|
||||
if (i < 14) {
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-14, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
begintime=millis();
|
||||
if (interrupts_are_attached) {
|
||||
detachInterrupts(); interrupts_are_attached=false;
|
||||
Serial.print("NOTICE: Interrupts DETACHED. Memory: ");
|
||||
Serial.print(freeMemory(), DEC);
|
||||
Serial.println(" bytes");
|
||||
}
|
||||
else {
|
||||
Serial.print("NOTICE: ATTACHING Interrupts. Memory: ");
|
||||
Serial.print(freeMemory(), DEC);
|
||||
Serial.println(" bytes");
|
||||
attachInterrupts(); interrupts_are_attached=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
// PinChangeIntExample2560
|
||||
// This only works for ATMega2560-based boards.
|
||||
// See the Arduino and the chip documentation for more details.
|
||||
|
||||
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
|
||||
// for vim editing: :set et ts=2 sts=2 sw=2
|
||||
|
||||
// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions.
|
||||
// The functions set the values of some global variables. All interrupts are serviced immediately,
|
||||
// and the sketch can then query the values at our leisure. This makes loop timing non-critical.
|
||||
|
||||
// The interrupt functions are a simple count of the number of times the pin was brought high.
|
||||
// For 2 of the pins, the values are stored and retrieved from an array and they are reset after
|
||||
// every read. For one of the pins ("MYPIN3"), there is a monotonically increasing count; that is,
|
||||
// until the 8-bit value reaches 255. Then it will go back to 0.
|
||||
|
||||
// For a more introductory sketch, see the SimpleExample328.ino sketch in the PinChangeInt
|
||||
// library distribution.
|
||||
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// PIN NAMING
|
||||
// For the Analog Input pins used as digital input pins, you can call them 14, 15, 16, etc.
|
||||
// or you can use A0, A1, A2, etc. (the Arduino code will properly recognize the symbolic names,
|
||||
// for example, pinMode(A0, INPUT_PULLUP);
|
||||
|
||||
// For Arduino MEGA (AT2560-based), besides the regular pins and the A (analog) pins,
|
||||
// you have 4 more pins with defined names:
|
||||
// SS = 53
|
||||
// MOSI = 51
|
||||
// MISO = 50
|
||||
// SCK = 52
|
||||
|
||||
// NOW CHOOSE PINS
|
||||
#if ! ( defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__ )
|
||||
#error "This sketch only works on chips in the ATmega2560 family."
|
||||
#endif
|
||||
|
||||
#define FIRST_ANALOG_PIN 54
|
||||
#define TOTAL_PINS 69 // But only 18 of them (not including RX0) are PinChangeInt-compatible
|
||||
// Don't use RX0 (Arduino pin 0) in this program- it won't work this is the
|
||||
// pin that Serial.print() uses!
|
||||
// See the Arduino and the chip documentation for more details.
|
||||
#define MYPIN1 SS
|
||||
#define MYPIN2 SCK
|
||||
#define MYPIN3 MOSI
|
||||
#define PIN3TEXT "MOSI" // This will say what MYPIN3 is, on the serial monitor
|
||||
|
||||
volatile uint8_t latest_interrupted_pin;
|
||||
volatile uint8_t interrupt_count[TOTAL_PINS]={0}; // possible arduino pins
|
||||
volatile uint8_t pin3Count=0;
|
||||
|
||||
// Do not use any Serial.print() in this function. Serial.print() uses interrupts, and is not compatible
|
||||
// with an interrupt routine...!
|
||||
void quicfunc() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
};
|
||||
|
||||
// You can assign any number of functions to different pins. How cool is that?
|
||||
void pin3func() {
|
||||
pin3Count++;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(MYPIN1, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN1, quicfunc, FALLING); // add more attachInterrupt code as required
|
||||
pinMode(MYPIN2, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN2, quicfunc, FALLING);
|
||||
pinMode(MYPIN3, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN3, pin3func, CHANGE);
|
||||
Serial.begin(115200);
|
||||
Serial.println("---------------------------------------");
|
||||
}
|
||||
|
||||
uint8_t i;
|
||||
uint8_t currentPIN3Count=0;
|
||||
void loop() {
|
||||
uint8_t count;
|
||||
Serial.print(".");
|
||||
delay(1000); // every second,
|
||||
for (i=0; i < TOTAL_PINS; i++) {
|
||||
if (interrupt_count[i] != 0) { // look at all the interrupted pins
|
||||
count=interrupt_count[i]; // store its count since the last iteration
|
||||
interrupt_count[i]=0; // and reset it to 0.
|
||||
Serial.print("Count for pin ");
|
||||
if (i == 50) { Serial.print("MISO"); } // then tell the user what it was, in a friendly way.
|
||||
else if (i == 51) { Serial.print("MOSI"); }
|
||||
else if (i == 52) { Serial.print("SCK"); }
|
||||
else if (i == 53) { Serial.print("SS"); }
|
||||
else if (i < FIRST_ANALOG_PIN) {
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-FIRST_ANALOG_PIN, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
if (currentPIN3Count != pin3Count) { // Print our monotonically increasing counter (no reset to 0)
|
||||
Serial.print(PIN3TEXT);
|
||||
Serial.print(" count update: "); Serial.print(pin3Count, DEC); Serial.println();
|
||||
currentPIN3Count=pin3Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// PinChangeIntExample
|
||||
// This only works for ATMega328-compatibles; ie, Leonardo is not covered here.
|
||||
// See the Arduino and the chip documentation for more details.
|
||||
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
|
||||
|
||||
// for vim editing: :set et ts=2 sts=2 sw=2
|
||||
|
||||
// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions.
|
||||
// The functions set the values of some global variables. All interrupts are serviced immediately,
|
||||
// and the sketch can then query the values at our leisure. This makes loop timing non-critical.
|
||||
|
||||
// The interrupt functions are a simple count of the number of times the pin was brought high.
|
||||
// For 2 of the pins, the values are stored and retrieved from an array and they are reset after
|
||||
// every read. For one of the pins ("MYPIN3"), there is a monotonically increasing count; that is,
|
||||
// until the 8-bit value reaches 255. Then it will go back to 0.
|
||||
|
||||
// For a more introductory sketch, see the SimpleExample328.ino sketch in the PinChangeInt
|
||||
// library distribution.
|
||||
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// Modify these at your leisure.
|
||||
#define MYPIN1 A3
|
||||
#define MYPIN2 A4
|
||||
#define MYPIN3 A5
|
||||
|
||||
// Don't change these.
|
||||
#define FIRST_ANALOG_PIN 14
|
||||
#define TOTAL_PINS 19
|
||||
// Notice that anything that gets modified inside an interrupt, that I wish to access
|
||||
// outside the interrupt, is marked "volatile". That tells the compiler not to optimize
|
||||
// them.
|
||||
volatile uint8_t latest_interrupted_pin;
|
||||
volatile uint8_t interrupt_count[TOTAL_PINS]={0}; // possible arduino pins
|
||||
volatile uint8_t pin3Count=0;
|
||||
|
||||
// Do not use any Serial.print() in interrupt subroutines. Serial.print() uses interrupts,
|
||||
// and by default interrupts are off in interrupt subroutines.
|
||||
// Here we update a counter corresponding to whichever pin interrupted.
|
||||
void quicfunc() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
};
|
||||
|
||||
// You can assign any number of functions to different pins. How cool is that?
|
||||
// Here we have a global variable that we increment. We can access this variable outside the interrupt,
|
||||
// and we know it will be valid because it was declared "volatile"- meaning, the compiler performs
|
||||
// no optimizations on it.
|
||||
void pin3func() {
|
||||
pin3Count++;
|
||||
}
|
||||
|
||||
// Attach the interrupts in setup()
|
||||
void setup() {
|
||||
pinMode(MYPIN1, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN1, quicfunc, RISING);
|
||||
pinMode(MYPIN2, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN2, quicfunc, RISING);
|
||||
pinMode(MYPIN3, INPUT_PULLUP);
|
||||
attachPinChangeInterrupt(MYPIN3, pin3func, CHANGE); // Any state change will trigger the interrupt.
|
||||
Serial.begin(115200);
|
||||
Serial.println("---------------------------------------");
|
||||
}
|
||||
|
||||
uint8_t i;
|
||||
uint8_t currentPIN3Count=0;
|
||||
|
||||
void loop() {
|
||||
uint8_t count;
|
||||
Serial.print(".");
|
||||
delay(1000); // every second,
|
||||
for (i=0; i < TOTAL_PINS; i++) {
|
||||
if (interrupt_count[i] != 0) { // look at all the interrupted pins
|
||||
count=interrupt_count[i]; // store its count since the last iteration
|
||||
interrupt_count[i]=0; // and reset it to 0
|
||||
Serial.print("Count for pin ");
|
||||
if (i < FIRST_ANALOG_PIN) { // then tell the user what it was, in a friendly way
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-FIRST_ANALOG_PIN, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
if (currentPIN3Count != pin3Count) { // Print our monotonically increasing counter (no reset to 0).
|
||||
Serial.print("Pin 3 count update: "); Serial.print(pin3Count, DEC); Serial.println();
|
||||
currentPIN3Count=pin3Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
// PinChangeIntSpeedTest by GreyGnome aka Mike Schwager. Version numbers here refer to this sketch.
|
||||
// Version 1.0 - initial version
|
||||
// Version 1.1 - added code to test digitalRead()
|
||||
// Version 1.2 - added new comments for the #define's for the NO_PORTx_PINCHANGES.
|
||||
// Version 1.3 - includes cbiface.h with ooPinChangeInt, rather than cb.h
|
||||
// Version 1.4 - testing version 2.10Beta with robtillaart's optimization
|
||||
// Also added a #define/#undef INLINE_PCINTFUNC for inlining of the function called by the interrupt.
|
||||
// Default: #undef for using the function as per usual. Changed PCIVERSION so that
|
||||
// ooPinChangeInt starts at 1000 instead of 200. Modified the "Start" message to show "Start..", pause
|
||||
// for 1 second, show "*\n" (where \n is a newline), pause for 1 second, then run the test.
|
||||
// Version 1.4 - made this compatible with version 1.5 of PinChangeInt
|
||||
// Version 1.5 - modified it to use #define OOPCIVERSION for ooPinChangeInt
|
||||
|
||||
// This version number is for ooPinChangeInt
|
||||
//#define OOPCIVERSION 1030
|
||||
#ifndef OOPCIVERSION
|
||||
#define PCIVERSION 217 // 110 if using PinChangeInt-1.1, 120 for version 1.2
|
||||
// 1000 for ooPinChangeIntversion 1.00, 1001 for ooPinChangeInt version 1.01, etc.
|
||||
#endif
|
||||
|
||||
//-------- define these in your sketch, if applicable ----------------------------------------------------------
|
||||
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
|
||||
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline
|
||||
// reducing the size and latency of the handler.
|
||||
#undef NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
||||
#undef NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
|
||||
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
|
||||
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine
|
||||
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or
|
||||
// PCintPort::arduinoPin are set and made available to your interrupt routine.
|
||||
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
||||
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
||||
// if there is only one PCInt vector in use the code can be inlined
|
||||
// reducing latency and code size
|
||||
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation.
|
||||
//#define DISABLE_PCINT_MULTI_SERVICE
|
||||
//-------- define the above in your sketch, if applicable ------------------------------------------------------
|
||||
#if defined(OOPCIVERSION)
|
||||
#define LIBRARYUNDERTEST "ooPinChangeInt"
|
||||
#include <ooPinChangeInt.h>
|
||||
#if PCIVERSION == 1001
|
||||
#include <cb.h>
|
||||
#else
|
||||
#include <cbiface.h>
|
||||
#endif
|
||||
#else
|
||||
#define LIBRARYUNDERTEST "PinChangeInt"
|
||||
#include <PinChangeInt.h>
|
||||
#endif
|
||||
|
||||
#define SERIALSTUFF // undef to take out all serial statements. Default: #define for measuring time.
|
||||
#undef MEMTEST // undef to take out memory tests. Default: #undef for measuring time.
|
||||
#undef INLINE_PCINTFUNC // define to inline the function called from the interrupt. This should have no effect,
|
||||
// because the compiler will store the registers upon calling the interrupt routine, just
|
||||
// like calling a function. Still, we test all assumptions.
|
||||
//-----------------------
|
||||
// NOTE: BECAUSE OF COLLISIONS in these libraries, you CANNOT have both libraries: PinChangeInt
|
||||
// and ooPinChangeInt in the libraries directory at the same time. That said, under UNIX-y operating
|
||||
// systems, it's easy to move the library directory to a name such as "PinChangeInt-1.3", which the
|
||||
// Arduino will not recognize, and then create a symbolic link when you want to use a library. Such as:
|
||||
// cd ~/Documents/Arduino/libaries
|
||||
// mv PinChangeInt PinChangeInt-1.30
|
||||
// mv ooPinChangeInt ooPinChangeInt-1.00
|
||||
// ln -s PinChangeInt-1.30 PinChangeInt
|
||||
|
||||
#undef FLASH // to flash LED on pin 13 during test
|
||||
|
||||
#ifdef MEMTEST
|
||||
#include <MemoryFree.h>
|
||||
#endif
|
||||
|
||||
#define TEST 6
|
||||
|
||||
#if TEST == 1
|
||||
#define PTEST 2 // pin to trigger interrupt. pins 0 and 1 are used
|
||||
#define PLOW 2 // by Serial, so steer clear of them!
|
||||
#define PHIGH 2 // Interrupts are attached to these pins
|
||||
|
||||
#elif TEST == 2 // see the #if TEST == 2 || TEST == 3 code, below
|
||||
#define PTEST 2
|
||||
#define PLOW 2
|
||||
#define PHIGH 2 // need to attachInterrupt to 5 in the code
|
||||
|
||||
#elif TEST == 3 // see the #if TEST == 2 || TEST == 3 code, below
|
||||
#define PTEST 5
|
||||
#define PLOW 2
|
||||
#define PHIGH 2 // need to attachInterrupt to 5 in the code
|
||||
|
||||
#elif TEST == 4
|
||||
#define PTEST 2
|
||||
#define PLOW 2
|
||||
#define PHIGH 5
|
||||
|
||||
#elif TEST == 5
|
||||
#define PTEST 3
|
||||
#define PLOW 2
|
||||
#define PHIGH 5
|
||||
|
||||
#elif TEST == 6
|
||||
#define PTEST 4
|
||||
#define PLOW 2
|
||||
#define PHIGH 5
|
||||
|
||||
#elif TEST == 7
|
||||
#define PTEST 5
|
||||
#define PLOW 2
|
||||
#define PHIGH 5
|
||||
#endif
|
||||
|
||||
uint8_t qf0;
|
||||
|
||||
#ifdef INLINE_PCINTFUNC
|
||||
#define INLINE_PCINTFUNC inline
|
||||
#else
|
||||
#define INLINE_PCINTFUNC
|
||||
#endif
|
||||
INLINE_PCINTFUNC void quicfunc();
|
||||
void quicfunc() {
|
||||
qf0=TCNT0;
|
||||
}
|
||||
|
||||
#if defined(OOPCIVERSION)
|
||||
class speedy : public CallBackInterface
|
||||
{
|
||||
public:
|
||||
uint8_t id;
|
||||
static uint8_t var0;
|
||||
speedy () { id=0; };
|
||||
speedy (uint8_t _i): id(_i) {};
|
||||
|
||||
void cbmethod() {
|
||||
speedy::var0=TCNT0;
|
||||
//Serial.print("Speedy method "); // debugging
|
||||
//Serial.println(id, DEC);
|
||||
};
|
||||
};
|
||||
uint8_t speedy::var0=0;
|
||||
#endif
|
||||
|
||||
volatile uint8_t *led_port;
|
||||
volatile uint8_t *pinT_OP;
|
||||
volatile uint8_t *pinT_IP;
|
||||
uint8_t led_mask, not_led_mask;
|
||||
uint8_t pinT_M, not_pinT_M;
|
||||
volatile uint8_t pintest, pinIntLow, pinIntHigh;
|
||||
uint8_t totalpins;
|
||||
#if defined(OOPCIVERSION)
|
||||
speedy speedster[8]={speedy(0), speedy(1), speedy(2), speedy(3), speedy(4), speedy(5), speedy(6), speedy(7) };
|
||||
#endif
|
||||
#ifdef MEMTEST
|
||||
int freemem;
|
||||
#endif
|
||||
|
||||
int i=0;
|
||||
|
||||
#define PINLED 13
|
||||
void setup()
|
||||
{
|
||||
#ifdef SERIALSTUFF
|
||||
Serial.begin(115200); Serial.println("---------------------------------------");
|
||||
#endif // SERIALSTUFF
|
||||
// set up ports for trigger
|
||||
pinMode(0, OUTPUT); digitalWrite(0, HIGH);
|
||||
pinMode(1, OUTPUT); digitalWrite(1, HIGH);
|
||||
pinMode(2, OUTPUT); digitalWrite(2, HIGH);
|
||||
pinMode(3, OUTPUT); digitalWrite(3, HIGH);
|
||||
pinMode(4, OUTPUT); digitalWrite(4, HIGH);
|
||||
pinMode(5, OUTPUT); digitalWrite(5, HIGH);
|
||||
pinMode(6, OUTPUT); digitalWrite(6, HIGH);
|
||||
pinMode(7, OUTPUT); digitalWrite(7, HIGH);
|
||||
#ifdef FLASH
|
||||
led_port=portOutputRegister(digitalPinToPort(PINLED));
|
||||
led_mask=digitalPinToBitMask(PINLED);
|
||||
not_led_mask=led_mask^0xFF;
|
||||
pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW);
|
||||
#endif
|
||||
// *****************************************************************************
|
||||
// set up ports for output ************ PIN TO TEST IS GIVEN HERE **************
|
||||
// *****************************************************************************
|
||||
pintest=PTEST;
|
||||
pinIntLow=PLOW; pinIntHigh=PHIGH; // Interrupts are attached to these pins
|
||||
// *****************************************************************************
|
||||
// *****************************************************************************
|
||||
pinT_OP=portOutputRegister(digitalPinToPort(pintest)); // output port
|
||||
pinT_IP=portInputRegister(digitalPinToPort(pintest)); // input port
|
||||
pinT_M=digitalPinToBitMask(pintest); // mask
|
||||
not_pinT_M=pinT_M^0xFF; // not-mask
|
||||
*pinT_OP|=pinT_M;
|
||||
for (i=pinIntLow; i <= pinIntHigh; i++) {
|
||||
#if defined(OOPCIVERSION)
|
||||
PCintPort::attachInterrupt(i, &speedster[i], CHANGE); // C++ technique; v1.3 or better
|
||||
#endif
|
||||
#if defined(PCIVERSION)
|
||||
PCintPort::attachInterrupt((uint8_t) i, &quicfunc, CHANGE); // C technique; v1.2 or earlier
|
||||
#endif
|
||||
}
|
||||
#if TEST == 2 || TEST == 3
|
||||
i=5; totalpins=2;
|
||||
#if defined(OOPCIVERSION)
|
||||
PCintPort::attachInterrupt(i, &speedster[i], CHANGE); // C++ technique; v1.3 or better
|
||||
#endif
|
||||
#if defined(PCIVERSION)
|
||||
PCintPort::attachInterrupt(i, &quicfunc, CHANGE); // C technique; v1.2 or earlier
|
||||
#endif
|
||||
#else
|
||||
totalpins=pinIntHigh - pinIntLow + 1;
|
||||
#endif
|
||||
i=0;
|
||||
} // end setup()
|
||||
|
||||
uint8_t k=0;
|
||||
unsigned long milliStart, milliEnd, elapsed;
|
||||
void loop() {
|
||||
k=0;
|
||||
*pinT_OP|=pinT_M; // pintest to 1
|
||||
#ifdef SERIALSTUFF
|
||||
Serial.print(LIBRARYUNDERTEST); Serial.print(" ");
|
||||
Serial.print("TEST: "); Serial.print(TEST, DEC); Serial.print(" ");
|
||||
#ifndef MEMTEST
|
||||
Serial.print("test pin mask: "); Serial.print(pinT_M, HEX);
|
||||
Serial.print(". Total of "); Serial.print(totalpins, DEC); Serial.println(" pins enabled.");
|
||||
#endif
|
||||
#ifdef MEMTEST
|
||||
freemem=freeMemory(); Serial.print("Free memory: "); Serial.println(freemem, DEC);
|
||||
#endif
|
||||
#endif
|
||||
delay(1000);
|
||||
Serial.print("Start..");
|
||||
delay(1000); Serial.print("*");
|
||||
#ifdef FLASH
|
||||
*led_port|=led_mask;
|
||||
#endif
|
||||
milliStart=millis();
|
||||
while (k < 10) {
|
||||
i=0;
|
||||
while (i < 10000) {
|
||||
*pinT_OP&=not_pinT_M; // pintest to 0 ****************************** 16.8 us
|
||||
*pinT_OP|=pinT_M; // pintest to 1 ****************************** ...to get here
|
||||
i++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
milliEnd=millis();
|
||||
#ifdef FLASH
|
||||
*led_port&=not_led_mask;
|
||||
#endif
|
||||
elapsed=milliEnd-milliStart;
|
||||
#ifndef MEMTEST
|
||||
Serial.print(" Elapsed: ");
|
||||
Serial.println(elapsed, DEC);
|
||||
#endif
|
||||
#ifdef SERIALSTUFF
|
||||
Serial.print("Interrupted pin: ");
|
||||
#if defined(OOPCIVERSION)
|
||||
Serial.println(speedster[pintest].id, DEC);
|
||||
#else
|
||||
Serial.println(PCintPort::arduinoPin, DEC);
|
||||
#endif
|
||||
#ifdef MEMTEST
|
||||
freemem=freeMemory(); Serial.print("END-Free memory: "); Serial.println(freemem, DEC);
|
||||
#endif
|
||||
#endif
|
||||
delay(500);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
// PinChangeIntTest
|
||||
//
|
||||
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
|
||||
// This sketch requires the ByteBuffer library, which is found in the PinChangeInt zipfile.
|
||||
// for vim editing: :set et ts=2 sts=2 sw=2
|
||||
//-------- define these in your sketch, if applicable ----------------------------------------------------------
|
||||
//-------- This must go ahead of the #include statement --------------------------------------------------------
|
||||
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
|
||||
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline
|
||||
// reducing the size and latency of the handler.
|
||||
// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
||||
// #define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
|
||||
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
|
||||
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine
|
||||
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or
|
||||
// PCintPort::arduinoPin are set and made available to your interrupt routine.
|
||||
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
||||
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
||||
// if there is only one PCInt vector in use the code can be inlined
|
||||
// reducing latency and code size
|
||||
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation.
|
||||
// #define DISABLE_PCINT_MULTI_SERVICE
|
||||
// The following is intended for testing purposes. If defined, then a variable PCintPort::pinMode can be read
|
||||
// in your interrupt subroutine. It is not defined by default:
|
||||
// #define PINMODE
|
||||
//-------- define the above in your sketch, if applicable ------------------------------------------------------
|
||||
#define PINMODE
|
||||
#define FLASH
|
||||
#include <ByteBuffer.h>
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
#define NEWLINE "\r\n" // Programs like "screen" in Linux don't return with a "\n" character.
|
||||
|
||||
// This example demonstrates a configuration of 6 interrupting pins and 3 interrupt functions.
|
||||
// A variety of interrupting pins have been chosen, so as to test all PORTs on the Arduino.
|
||||
// The pins are as follows:
|
||||
// quicfunc0 is attached to tPIN1-4.
|
||||
// quicfunc1 is attached to tPIN5.
|
||||
// quicfunc2 is attached to tPIN6.
|
||||
// Pins tPIN1 and tPIN6 interrupt on FALLING.
|
||||
// tPIN2 and tPIN4 interrupt on RISING.
|
||||
// tPIN3 and tPIN5 interrupt on CHANGE.
|
||||
// NOTE:
|
||||
// For the Analog Input pins used as digital input pins, you can use numbers such as 14, 15, 16, etc.
|
||||
// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's for the Analog Input pin
|
||||
// names and will properly recognize e.g., pinMode(A0, INPUT_PULLUP));
|
||||
#if defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__
|
||||
#define tPIN1 14 // port J
|
||||
#define tPIN2 15
|
||||
#define tPIN3 A8 // Port K
|
||||
#define tPIN4 A12
|
||||
#define tPIN5 SS // Port B, also can be given as "57"
|
||||
#define tPIN6 MOSI // This pin starts and stops the count
|
||||
#else
|
||||
// These only work for ATMega328-compatibles; ie, Leonardo is not covered here.
|
||||
#define tPIN1 2 // port D
|
||||
#define tPIN2 3
|
||||
#define tPIN3 11 // Port B
|
||||
#define tPIN4 12
|
||||
#define tPIN5 A3 // Port C, also can be given as "17"
|
||||
#define tPIN6 A4 // This pin starts and stops the count
|
||||
#endif
|
||||
|
||||
// HOW IT WORKS (ATmega328-specific; replace the references with the proper pins for the other chip types)
|
||||
// The interrupt on Arduino pin A4 (tPIN6) will, when triggered, start the counting of interrupts.
|
||||
// The array interrupt_count0[20] is updated in the interrupts; each cell keeps track of the number
|
||||
// of interrupts on one of the 20 available interrupt pins on the Arduino. Every second in the main
|
||||
// loop the array is scanned and registered interrupts are reported for all pins interrupted since
|
||||
// the previous second. If no interrupts, the output is quiet.
|
||||
|
||||
// tPIN6 is special. Not only does it start the counting of the interrups, but it turns on and off
|
||||
// interrupts on pins 2, 11, and A3/17 (tPIN1, tPIN3, tPIN5). All pins start by interrupting, but after
|
||||
// the count is turned on and then turned off, the 3 pins are detached from interrupts.
|
||||
// Everytime thereafter when the count is turned off the 3 pins are detached. They are reattached
|
||||
// when turned on.
|
||||
|
||||
// Output is copied to a buffer, because we can't do a Serial.print() statement in an interrupt
|
||||
// routine. The main loop checks for entries in the buffer and prints them if found.
|
||||
// Output looks like this:
|
||||
// -F- - an interrupt triggered by a falling signal occurred.
|
||||
// +R+ - an interrupt triggered by a rising signal occurred.
|
||||
// *C* - an interrupt triggered by a change in signal occurred.
|
||||
// f#p#-P# - f# shows the interrupt subroutine that was called: 0, 1, or 2
|
||||
// - p# shows the pin number that triggered the interrupt
|
||||
// - P# shows the port that this pin number is attached to. 2 is PORTB, 3 is PORTC, 4 is PORTD
|
||||
|
||||
// HOW TO CONNECT
|
||||
// Each pin gets a momentary contact switch connected to it. One side of the switch should connect
|
||||
// to ground. The other side of the switch connects to the Arduino pin. For my purposes, I am using
|
||||
// two rotary encoders. Each encoder contains 3 switches. But 6 regular pushbuttons would work, too.
|
||||
|
||||
/* WHAT TO LOOK FOR
|
||||
Output is sent to the serial line, so the Arduino IDE's serial terminal should be opened.
|
||||
Upon startup, press tPINS1-5. You will see output like this:
|
||||
-F-f0p2-P4 (counting off)
|
||||
..*C*f0p11-P2 (counting off)
|
||||
+R+f0p3-P4 (counting off)
|
||||
This shows that
|
||||
1. an interrupt was triggered on a falling signal (*F*). It called (f0) function 0, which is quicfunc0.
|
||||
The triggering pin was (p2) Arduuino pin 2, which is on (P4) Port 4 (PORTD). Counting of this interrupt is
|
||||
off, so you will not see any output from the main loop.
|
||||
2. Two dots appeared. Dots came from iterations of loop(), so these 2 dots show that the two interrupts happened 2 seconds apart.
|
||||
3. an interrupt was triggered on a change in signal (*C*). It called quicfunc0, from Arduino pin 11, on Port 2 (PORTB).
|
||||
The interrupt was not counted.
|
||||
4. an interrupt was triggered on a rising signal (+R+). It called quicfunc0, from Arduino pin 3, on Purt 4 (PORTD).
|
||||
The pin should have started out at the high level, so likely the signal fell during onother interrupt, and now
|
||||
the rise has been caught.
|
||||
|
||||
Now press the button attached to tPIN6 (in our case, A4 or D18). You will see something like this:
|
||||
-F-START! f2p18-P3
|
||||
.Count for pin A4 is 1
|
||||
This shows that
|
||||
1. The counting machanism (START!) was triggered by a folling signal (-F-) on pin 18 (p18) which is in Port 3 (P3) (which == PORTC) and
|
||||
function f2 was called (f2).
|
||||
2. A dot appeared, which came from loop() because a second passed.
|
||||
3. The count for p18 or A4 was displayed.
|
||||
|
||||
Now you will see messages for all the pins that you manipulate, for example:
|
||||
*C*f0p11-P2
|
||||
+R+f0p3-P4
|
||||
*C*f0p11-P2
|
||||
+R+f0p3-P4
|
||||
*C*f0p11-P2
|
||||
.Count for pin D3 is 6
|
||||
Count for pin D11 is 9
|
||||
.+R+f0p3-P4
|
||||
-F-f0p2-P4
|
||||
.Count for pin D2 is 1
|
||||
Count for pin D3 is 1
|
||||
These codes reflect the interrupts, as described above. This output will take place until you press tPIN6:
|
||||
-F-f2: STOP! Counting off.
|
||||
Interrupt OFF on tPIN1 (2) tPIN3 (11) tPIN5 (17)
|
||||
Then you will see output like this:
|
||||
.....................+R+f0p12-P2 (counting off)
|
||||
.+R+f0p12-P2 (counting off)
|
||||
+R+f0p12-P2 (counting off)
|
||||
+R+f0p12-P2 (counting off)
|
||||
and tPIN1, tPIN3, and tPIN5 will not trigger interrupts.
|
||||
*/
|
||||
// NOTES
|
||||
// Output overwrites:
|
||||
// It's possible during moderately fast interrupts to see your print output get garbled; eg,
|
||||
// +R+f0p12-P2 (+R+f0p12-P2 (counting +R+f0p12-P2 (cou+R+f0p12-P+R+f0p12
|
||||
// This is because the print of the buffer takes place inside a while loop, and it can
|
||||
// be interrupted and new data inserted into the buffer at a midpoint of the buffer's text.
|
||||
// Just by spinning my rotary encoders I can readily generate over 200 interrupts per second
|
||||
// on a pin, which is easily fast enough to overrun Serial output at 115,200 bps.
|
||||
// The lesson here? ...Interrupts are tricky, and interrupt service routines should be fast.
|
||||
// Just sayin'.
|
||||
|
||||
// Pins:
|
||||
// We want to use pins from each of ports B, C and D. So choose wisely. Ports are shown in
|
||||
// this diagram of the ATmega328P chip. PD0 means "Port D, pin 0". PC3 means "Port C, Pin 3",
|
||||
// PB2 means "Port B, pin 2" and so on. The corresponding Arduino pins are in parentheses.
|
||||
// So PB2 is Arduino pin D 10, for example.
|
||||
/*
|
||||
+-\/-+
|
||||
PC6 1| |28 PC5 (AI 5)
|
||||
(D 0) PD0 2| |27 PC4 (AI 4)
|
||||
(D 1) PD1 3| |26 PC3 (AI 3)
|
||||
(D 2) PD2 4| |25 PC2 (AI 2)
|
||||
PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
|
||||
(D 4) PD4 6| |23 PC0 (AI 0)
|
||||
VCC 7| |22 GND
|
||||
GND 8| |21 AREF
|
||||
PB6 9| |20 AVCC
|
||||
PB7 10| |19 PB5 (D 13)
|
||||
PWM+ (D 5) PD5 11| |18 PB4 (D 12)
|
||||
PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
|
||||
(D 7) PD7 13| |16 PB2 (D 10) PWM
|
||||
(D 8) PB0 14| |15 PB1 (D 9) PWM
|
||||
+----+
|
||||
*/
|
||||
|
||||
uint8_t pins[6]={ tPIN1, tPIN2, tPIN3, tPIN4, tPIN5, tPIN6 };
|
||||
uint8_t ports[6]={ 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
uint8_t latest_interrupted_pin;
|
||||
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
|
||||
uint8_t port;
|
||||
uint8_t mode;
|
||||
|
||||
ByteBuffer printBuffer(80);
|
||||
char charArray[16];
|
||||
char numBuffer[4] = { 0, 0, 0, 0 };
|
||||
uint8_t printFull=0;
|
||||
|
||||
volatile boolean start=0;
|
||||
volatile boolean initial=true;
|
||||
long begintime=0;
|
||||
long now=0;
|
||||
|
||||
void uint8ToString(char *outString, uint8_t number) {
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
|
||||
while (number >= 100 ) {
|
||||
hundreds++;
|
||||
number-=100;
|
||||
}
|
||||
while (number >= 10 ) {
|
||||
tens++;
|
||||
number-=10;
|
||||
}
|
||||
ones=number;
|
||||
ones+=48;
|
||||
if (hundreds > 0) { hundreds+=48; tens+=48; outString[0]=hundreds; outString[1]=tens; outString[2]=ones; outString[3]=0; }
|
||||
else if (tens > 0) { tens+=48; outString[0]=tens; outString[1]=ones; outString[2]=0; }
|
||||
else { outString[0]=ones; outString[1]=0; };
|
||||
}
|
||||
|
||||
void showMode() {
|
||||
switch (mode) {
|
||||
case FALLING:
|
||||
printBuffer.putString((char *) "-F-");
|
||||
break;
|
||||
case RISING:
|
||||
printBuffer.putString((char *) "+R+");
|
||||
break;
|
||||
case CHANGE:
|
||||
printBuffer.putString((char *) "*C*");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void quicfunc0() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString((char *) "f0p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
if (start !=1) printBuffer.putString((char *) " (counting off)");
|
||||
printBuffer.putString((char *) NEWLINE);
|
||||
};
|
||||
|
||||
void quicfunc1() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString((char *) "f1p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
if (start !=1) printBuffer.putString((char *) " (counting off)");
|
||||
printBuffer.putString((char *) NEWLINE);
|
||||
};
|
||||
|
||||
void quicfunc2() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start == 1) {
|
||||
printBuffer.putString((char *) "f2: STOP! Counting off.\n");
|
||||
printBuffer.putString((char *) "Interrupt OFF on tPIN1 ("); uint8ToString(numBuffer, tPIN1), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) ") tPIN3 (");uint8ToString(numBuffer, tPIN3), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) ") tPIN5 (");uint8ToString(numBuffer, tPIN5), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) ")");
|
||||
printBuffer.putString((char *) NEWLINE);
|
||||
PCintPort::detachInterrupt(tPIN1); PCintPort::detachInterrupt(tPIN3); PCintPort::detachInterrupt(tPIN5);
|
||||
start=0;
|
||||
} else {
|
||||
start=1;
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
printBuffer.putString((char *) "START! f2p");
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer); printBuffer.putString((char *) NEWLINE);
|
||||
if (! initial) {
|
||||
PCintPort::attachInterrupt(tPIN1, &quicfunc0, FALLING);
|
||||
PCintPort::attachInterrupt(tPIN3, &quicfunc0, CHANGE);
|
||||
PCintPort::attachInterrupt(tPIN5, &quicfunc1, CHANGE);
|
||||
} else {
|
||||
initial=false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uint8_t i;
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(250);
|
||||
Serial.println("Test");
|
||||
for (i=0; i < 6; i++) {
|
||||
pinMode(pins[i], INPUT_PULLUP);
|
||||
ports[i]=digitalPinToPort(pins[i]);
|
||||
switch (pins[i]) {
|
||||
case tPIN1:
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING);
|
||||
break;
|
||||
case tPIN3:
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE);
|
||||
break;
|
||||
case tPIN2:
|
||||
case tPIN4:
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING);
|
||||
break;
|
||||
case tPIN5:
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE);
|
||||
break;
|
||||
case tPIN6:
|
||||
attachPinChangeInterrupt(pins[i], quicfunc2, FALLING); // attachPinChangeInterrupt is a #define
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Serial.println(printBuffer.getCapacity(), DEC);
|
||||
//Serial.println("*---------------------------------------*");
|
||||
Serial.print("*---*");
|
||||
delay(250);
|
||||
begintime=millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
now=millis();
|
||||
uint8_t count;
|
||||
char outChar;
|
||||
// uint8_t bufsize;
|
||||
//if (printBuffer.getSize() != 0) { Serial.print("SZ:"); Serial.println (printBuffer.getSize(), DEC); };
|
||||
//bufsize=printBuffer.getSize();
|
||||
//if (bufsize > 0) { Serial.print("S:"); Serial.println(bufsize); }
|
||||
while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar);
|
||||
if ((now - begintime) > 1000) {
|
||||
Serial.print(".");
|
||||
if (printBuffer.checkError()) {
|
||||
Serial.println("NOTICE: Some output lost due to filled buffer.");
|
||||
}
|
||||
for (i=0; i < 20; i++) {
|
||||
if (interrupt_count[i] != 0) {
|
||||
count=interrupt_count[i];
|
||||
interrupt_count[i]=0;
|
||||
Serial.print("Count for pin ");
|
||||
if (i < 14) {
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-14, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
begintime=millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
//#define DISABLE_PCINT_MULTI_SERVICE
|
||||
#define PINMODE
|
||||
#define FLASH
|
||||
#include <GetPSTR.h>
|
||||
#include <ByteBuffer.h>
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// This example demonstrates a configuration of 6 interrupting pins and 3 interrupt functions.
|
||||
// A variety of interrupting pins have been chosen, so as to test all PORTs on the Arduino.
|
||||
// The pins are as follows:
|
||||
#define tPIN1 2 // port D
|
||||
#define tPIN2 3
|
||||
#define tPIN3 11 // Port B
|
||||
#define tPIN4 12
|
||||
#define tPIN5 A3 // Port C, also can be given as "17"
|
||||
#define tPIN6 A4 // starts and stops the count
|
||||
|
||||
uint8_t pins[6]={ tPIN1, tPIN2, tPIN3, tPIN4, tPIN5, tPIN6 };
|
||||
uint8_t ports[6]={ 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
uint8_t latest_interrupted_pin;
|
||||
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
|
||||
uint8_t port;
|
||||
uint8_t mode;
|
||||
|
||||
ByteBuffer printBuffer(200);
|
||||
char charArray[16];
|
||||
char numBuffer[5] = { 0, 0, 0, 0, 0 };
|
||||
uint8_t printFull=0;
|
||||
|
||||
volatile boolean start=0;
|
||||
volatile boolean initial=true;
|
||||
long begintime=0;
|
||||
long now=0;
|
||||
|
||||
void uint8ToHexString(char *outString, uint8_t theByte) {
|
||||
outString[0]='0'; outString[1]='x';
|
||||
uint8_t hinybble=theByte>>4;
|
||||
uint8_t lonybble=theByte & 0x0F;
|
||||
if (hinybble < 0x0a) outString[2]=hinybble+48;
|
||||
else outString[2]=hinybble+55;
|
||||
if (lonybble < 0x0a) outString[3]=lonybble+48;
|
||||
else outString[3]=lonybble+55;
|
||||
outString[4]=0;
|
||||
}
|
||||
|
||||
void uint8ToString(char *outString, uint8_t number) {
|
||||
uint8_t hundreds=0;
|
||||
uint8_t tens=0;
|
||||
uint8_t ones=0;
|
||||
|
||||
while (number >= 100 ) {
|
||||
hundreds++;
|
||||
number-=100;
|
||||
}
|
||||
while (number >= 10 ) {
|
||||
tens++;
|
||||
number-=10;
|
||||
}
|
||||
ones=number;
|
||||
ones+=48;
|
||||
if (hundreds > 0) { hundreds+=48; tens+=48; outString[0]=hundreds; outString[1]=tens; outString[2]=ones; outString[3]=0; }
|
||||
else if (tens > 0) { tens+=48; outString[0]=tens; outString[1]=ones; outString[2]=0; }
|
||||
else { outString[0]=ones; outString[1]=0; };
|
||||
}
|
||||
|
||||
void showMode() {
|
||||
switch (mode) {
|
||||
case FALLING:
|
||||
printBuffer.putString(getPSTR("-F-"));
|
||||
break;
|
||||
case RISING:
|
||||
printBuffer.putString(getPSTR("+R+"));
|
||||
break;
|
||||
case CHANGE:
|
||||
printBuffer.putString(getPSTR("*C*"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void quicfunc0() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString((char *) "f0p"); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
if (start !=1) printBuffer.putString(getPSTR(" no count"));
|
||||
printBuffer.putString((char *) "\n");
|
||||
};
|
||||
|
||||
void quicfunc1() {
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
if (start==1) {
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
}
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString(getPSTR("f1p")); printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer);
|
||||
if (start !=1) printBuffer.putString(getPSTR(" (counting off)"));
|
||||
printBuffer.putString((char *) "\n");
|
||||
};
|
||||
*/
|
||||
|
||||
void quicfunc2() {
|
||||
//*led_port|=led_mask;
|
||||
//*led_port&=not_led_mask; // 2 micros to here (ie, 2 micros used to push registers and call subroutine)
|
||||
latest_interrupted_pin=PCintPort::arduinoPin;
|
||||
mode=PCintPort::pinmode;
|
||||
showMode();
|
||||
*led_port|=led_mask; // 73 micros to get here from above. Used in "Rigol Timing Example"
|
||||
*led_port&=not_led_mask;
|
||||
//uint8ToString(numBuffer, PCintPort::s_count); printBuffer.putString(numBuffer);
|
||||
*led_port|=led_mask; // 73 micros to get here from above. Second pulse in "Rigol Timing Example"
|
||||
*led_port&=not_led_mask;
|
||||
printBuffer.putString(getPSTR(" f2: P"));/*
|
||||
uint8ToHexString(numBuffer, *portInputRegister(3)); printBuffer.putString(numBuffer);// C port
|
||||
printBuffer.putString(getPSTR(" pin:")); uint8ToString(numBuffer, latest_interrupted_pin); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" c")); uint8ToHexString(numBuffer, PCintPort::curr); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" l")); uint8ToHexString(numBuffer, PCintPort::s_lastPinView); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" r")); uint8ToHexString(numBuffer, PCintPort::s_portRisingPins); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" f")); uint8ToHexString(numBuffer, PCintPort::s_portFallingPins); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" m")); uint8ToHexString(numBuffer, PCintPort::s_pmask); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" P")); printBuffer.put(PCintPort::s_PORT); printBuffer.putString("\r\n");
|
||||
printBuffer.putString(getPSTR("cp")); uint8ToHexString(numBuffer, PCintPort::s_changedPins); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" cXORlpv")); uint8ToHexString(numBuffer, PCintPort::s_currXORlastPinView); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" rp_nCurr")); uint8ToHexString(numBuffer, PCintPort::s_portRisingPins_nCurr); printBuffer.putString(numBuffer);
|
||||
printBuffer.putString(getPSTR(" fp_nNCurr")); uint8ToHexString(numBuffer, PCintPort::s_portFallingPins_nNCurr); printBuffer.putString(numBuffer);
|
||||
*/printBuffer.putString("\r\n");
|
||||
if (PCintPort::pcint_multi > 0) {
|
||||
printBuffer.putString("MULTI!\n"); PCintPort::pcint_multi=0;
|
||||
}
|
||||
if (PCintPort::PCIFRbug > 0) { printBuffer.putString("ERROR: BUG- PCIFR should be reset!"); PCintPort::PCIFRbug=0; }
|
||||
//s_registers, if it existed, could be used to keep a running queue of the latest interrupts that have
|
||||
//been serviced by the PCint(). But generally I don't think it's necessary for debugging at this point (famous last words?)
|
||||
/*if (PCintPort::s_count > 2) {
|
||||
for (uint8_t i=0; i < PCintPort::s_count; i++) {
|
||||
uint8ToHexString(numBuffer, PCintPort::s_registers[i]); printBuffer.putString(numBuffer); printBuffer.putString(" ");
|
||||
}
|
||||
}
|
||||
PCintPort::s_count=0;*/
|
||||
/*
|
||||
if (start == 1) {
|
||||
printBuffer.putString(getPSTR("STOP Count off\n"));
|
||||
printBuffer.putString(getPSTR("Intr OFF: (")); uint8ToString(numBuffer, tPIN1), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) " "); uint8ToString(numBuffer, tPIN3), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) " "); uint8ToString(numBuffer, tPIN5), printBuffer.putString(numBuffer);
|
||||
printBuffer.putString((char *) ")\n");
|
||||
PCintPort::detachInterrupt(tPIN1); PCintPort::detachInterrupt(tPIN3); PCintPort::detachInterrupt(tPIN5);
|
||||
start=0;
|
||||
} else {
|
||||
start=1;
|
||||
interrupt_count[latest_interrupted_pin]++;
|
||||
printBuffer.putString(getPSTR("START! p"));
|
||||
uint8ToString(numBuffer, latest_interrupted_pin);
|
||||
printBuffer.putString(numBuffer); printBuffer.putString((char *) "-P");
|
||||
// MIKE put the REAL PORT HERE
|
||||
uint8ToString(numBuffer, digitalPinToPort(latest_interrupted_pin));
|
||||
printBuffer.putString(numBuffer); printBuffer.putString((char *) "\n");
|
||||
if (! initial) {
|
||||
PCintPort::attachInterrupt(tPIN1, &quicfunc0, FALLING);
|
||||
PCintPort::attachInterrupt(tPIN3, &quicfunc0, CHANGE);
|
||||
PCintPort::attachInterrupt(tPIN5, &quicfunc1, CHANGE);
|
||||
} else {
|
||||
initial=false;
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
||||
uint8_t i;
|
||||
char hexBuffer[5];
|
||||
void setup() {
|
||||
int8_t returncode=1;
|
||||
Serial.begin(115200);
|
||||
Serial.println("Test");
|
||||
delay(500);
|
||||
for (i=5; i < 6; i++) {
|
||||
pinMode(pins[i], INPUT); digitalWrite(pins[i], HIGH);
|
||||
ports[i]=digitalPinToPort(pins[i]);
|
||||
switch (pins[i]) {
|
||||
/*case tPIN1:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, FALLING);
|
||||
#endif
|
||||
Serial.println(getPSTR("FIRST FAILURE OK."));
|
||||
break;
|
||||
case tPIN3:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, CHANGE);
|
||||
#endif
|
||||
break;
|
||||
case tPIN2:
|
||||
case tPIN4:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc0, RISING);
|
||||
#endif
|
||||
break;
|
||||
case tPIN5:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc1, CHANGE);
|
||||
#endif
|
||||
break;*/
|
||||
case tPIN6:
|
||||
#if PCINT_VERSION > 2100
|
||||
returncode=PCintPort::attachInterrupt(pins[i], &quicfunc2, FALLING);
|
||||
#else
|
||||
PCintPort::attachInterrupt(pins[i], &quicfunc2, FALLING);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#if PCINT_VERSION > 2100
|
||||
Serial.print(getPSTR("setup(): Interrupt attach "));
|
||||
if (returncode != 1) Serial.print(getPSTR("unsuccessful "));
|
||||
else Serial.print(getPSTR("GOOD "));
|
||||
Serial.print(pins[i], DEC);
|
||||
Serial.print(getPSTR(":pin, code: ")); Serial.println(returncode, DEC);
|
||||
#endif
|
||||
}
|
||||
//Serial.println(printBuffer.getCapacity(), DEC);
|
||||
//Serial.println("*---------------------------------------*");
|
||||
Serial.print("*---*");
|
||||
delay(250);
|
||||
begintime=millis();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
now=millis();
|
||||
uint8_t count;
|
||||
char outChar;
|
||||
// uint8_t bufsize;
|
||||
//if (printBuffer.getSize() != 0) { Serial.print("SZ:"); Serial.println (printBuffer.getSize(), DEC); };
|
||||
//bufsize=printBuffer.getSize();
|
||||
//if (bufsize > 0) { Serial.print("S:"); Serial.println(bufsize); }
|
||||
while ((outChar=(char)printBuffer.get()) != 0) Serial.print(outChar);
|
||||
if ((now - begintime) > 1000) {
|
||||
Serial.print(".");
|
||||
if (printBuffer.checkError()) {
|
||||
Serial.println(getPSTR("!Some output lost due to full buffer!"));
|
||||
}
|
||||
for (i=0; i < 20; i++) {
|
||||
if (interrupt_count[i] != 0) {
|
||||
count=interrupt_count[i];
|
||||
interrupt_count[i]=0;
|
||||
Serial.print(getPSTR("Count for pin "));
|
||||
if (i < 14) {
|
||||
Serial.print("D");
|
||||
Serial.print(i, DEC);
|
||||
} else {
|
||||
Serial.print("A");
|
||||
Serial.print(i-14, DEC);
|
||||
}
|
||||
Serial.print(" is ");
|
||||
Serial.println(count, DEC);
|
||||
}
|
||||
}
|
||||
begintime=millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// PinChangeInt SimpleExample sketch
|
||||
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
|
||||
|
||||
// for vim editing: :set et ts=2 sts=2 sw=2 et
|
||||
|
||||
// This example demonstrates the use of the PinChangeInt library on a single pin of your choice.
|
||||
// This only works for ATMega328-compatibles; ie, Leonardo is not covered here.
|
||||
// To use:
|
||||
|
||||
// 1. You must be using a fairly recent version of the Arduino IDE software on your PC/Mac,
|
||||
// that is, version 1.0.1 or later. Check Help->About Arduino in the IDE.
|
||||
|
||||
// 2. Wire a simple switch to any Analog or Digital pin (known as ARDUINOPIN, defined below).
|
||||
// Attach the other end to a GND pin. A "single pole single throw momentary contact"
|
||||
// pushbutton switch is best for the best interrupting fun.
|
||||
|
||||
// 3. When pressed, the switch will connect the pin to ground ("low", or "0") voltage, and interrupt the
|
||||
// processor. Don't let it confuse you that a switch press means the pin's voltage goes to 0; it
|
||||
// may seem more intuitive to apply a "1" or high voltage to the pin to represent "pressed".
|
||||
// But the processor is perfectly happy that we've made "0" equal "Pressed". The reason we've done so
|
||||
// is because we are using the "internal pullup resistor" feature of the processor... the chip gives
|
||||
// us a free resistor on every pin!
|
||||
// See http://arduino.cc/en/Tutorial/DigitalPins for a complete explanation.
|
||||
|
||||
// 4. The interrupt is serviced immediately, and the ISR (Interrupt SubRoutine) sets the value of a global
|
||||
// variable. The sketch can then query the value at its leisure. This makes loop timing non-critical.
|
||||
// Open Tools->Serial Monitor in the IDE to see the results of your interrupts.
|
||||
|
||||
// 5. See PinChangeIntExample328.ino (in the PinChangeInt distribution) for a more elaborate example.
|
||||
|
||||
// 6. Create your own sketch using the PinChangeInt library!
|
||||
|
||||
#include <PinChangeInt.h>
|
||||
|
||||
// Modify this at your leisure.
|
||||
#define ARDUINOPIN A4
|
||||
|
||||
// Notice that values that get modified inside an interrupt, that I wish to access
|
||||
// outside the interrupt, are marked "volatile". It tells the compiler not to optimize
|
||||
// the variable.
|
||||
volatile uint16_t interruptCount=0; // The count will go back to 0 after hitting 65535.
|
||||
|
||||
// Do not use any Serial.print() in interrupt subroutines. Serial.print() uses interrupts,
|
||||
// and by default interrupts are off in interrupt subroutines. Interrupt routines should also
|
||||
// be as fast as possible. Here we just increment a counter.
|
||||
void interruptFunction() {
|
||||
interruptCount++;
|
||||
}
|
||||
|
||||
// Attach the interrupt in setup()
|
||||
void setup() {
|
||||
pinMode(ARDUINOPIN, INPUT_PULLUP); // Configure the pin as an input, and turn on the pullup resistor.
|
||||
// See http://arduino.cc/en/Tutorial/DigitalPins
|
||||
attachPinChangeInterrupt(ARDUINOPIN, interruptFunction, FALLING);
|
||||
Serial.begin(115200);
|
||||
Serial.println("---------------------------------------");
|
||||
}
|
||||
|
||||
// In the loop, we just check to see where the interrupt count is at. The value gets updated by the
|
||||
// interrupt routine.
|
||||
void loop() {
|
||||
delay(1000); // Every second,
|
||||
Serial.print("Pin was interrupted: ");
|
||||
Serial.print(interruptCount, DEC); // print the interrupt count.
|
||||
Serial.println(" times so far.");
|
||||
}
|
||||
54
libraries/PinChangeInt/LICENSE
Normal file
54
libraries/PinChangeInt/LICENSE
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
27
libraries/PinChangeInt/NOTICE
Normal file
27
libraries/PinChangeInt/NOTICE
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
NOTICE
|
||||
PinChangeInt Arduino Library
|
||||
Copyright 2008 Chris J. Kiick
|
||||
Copyright 2009-2011 Lex Talionis
|
||||
Copyright 2010-2014 Michael Schwager (aka "GreyGnome")
|
||||
|
||||
This product includes software developed by Chris J. Kiick, Lex Talionis,
|
||||
and Mike Schwager (aka, 'GreyGnome').
|
||||
|
||||
This library was inspired by and derived from Chris J. Kiick's PCInt Arduino
|
||||
Playground example here: http://www.arduino.cc/playground/Main/PcInt
|
||||
|
||||
Lex Talionis picked it up, refined it, and created a Google Code page for
|
||||
it, found here: http://code.google.com/p/arduino-pinchangeint/
|
||||
|
||||
GreyGnome is the current maintainer, and would like to thank all those
|
||||
Open Source coders, the Arduino makers and community, and especially Chris
|
||||
and Lex for lighting the flame and showing the way! And a big thank you to
|
||||
the users who have contributed comments and bug fixes along the way.
|
||||
Without you this project would not have overcome some significant hurdles.
|
||||
A more complete list can be found in the README file.
|
||||
|
||||
A HUGE thanks to Jan Baeyens ("jantje"), who has graciously DONATED an
|
||||
Arduino Mega ADK board to the PinChangeInt project!!! Wow, thanks Jan!
|
||||
This makes the 2560-based Arduino Mega a first class supported platform-
|
||||
I will be able to test it and verify that it works.
|
||||
|
||||
652
libraries/PinChangeInt/PinChangeInt.h
Normal file
652
libraries/PinChangeInt/PinChangeInt.h
Normal file
|
|
@ -0,0 +1,652 @@
|
|||
// This file is part of the PinChangeInt library for the Arduino. This library will work on any ATmega328-based
|
||||
// or ATmega2560-based Arduino, as well as the Sanguino or Mioduino.
|
||||
|
||||
// Most of the pins of an Arduino Uno use Pin Change Interrupts, and because of the way the ATmega interrupt
|
||||
// system is designed it is difficult to trigger an Interrupt Service Request off of any single pin, and on
|
||||
// any change of state (either rising, or falling, or both). The goal of this library is to make it easy for
|
||||
// the programmer to attach an ISR so it will trigger on any change of state on any Pin Change Interrupt pin.
|
||||
|
||||
// (NOTE TO SELF: Update the PCINT_VERSION define, below) -----------------
|
||||
#define PCINT_VERSION 2402
|
||||
/*
|
||||
Copyright 2008 Chris J. Kiick
|
||||
Copyright 2009-2011 Lex Talionis
|
||||
Copyright 2010-2014 Michael Schwager (aka, "GreyGnome")
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* QUICKSTART
|
||||
*
|
||||
* For the beginners/lazy/busy/wreckless:
|
||||
* To attach an interrupt to your Arduino Pin, calling your function "userFunc", and acting on
|
||||
* the "mode", which is a change in the pin's state; either RISING or FALLING or CHANGE:
|
||||
* attachPinChangeInterrupt(pin,userFunc,mode)
|
||||
* Your function must not return any values and it cannot take any arguments (that is, its definition
|
||||
* has to look like this:
|
||||
* void userFunc() {
|
||||
* ...your code here...
|
||||
* }
|
||||
*
|
||||
* That's it. Everything else are details.
|
||||
*
|
||||
* If you need to exchange information to/from the interrupt, you can use global volatile variables.
|
||||
* See the example for more information.
|
||||
*
|
||||
* You probably will not need to do this, but later in your sketch you can detach the interrupt:
|
||||
* detachPinChangeInterrupt(pin)
|
||||
*
|
||||
* If you want to see what the *last* pin that triggered an interrupt was, you can get it this way:
|
||||
* getInterruptedPin()
|
||||
* Note: If you have multiple pins that are triggering interrupts and they are sufficiently fast,
|
||||
* you will not be able to find all the pins that interrupted.
|
||||
*/
|
||||
|
||||
//
|
||||
// For the beginners
|
||||
//
|
||||
#define detachPinChangeInterrupt(pin) PCintPort::detachInterrupt(pin)
|
||||
#define attachPinChangeInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, &userFunc,mode)
|
||||
#define getInterruptedPin() PCintPort::getArduinoPin()
|
||||
|
||||
// We use 4-character tabstops, so IN VIM: <esc>:set ts=4 sw=4 sts=4
|
||||
// ...that's: ESCAPE key, colon key, then
|
||||
// "s-e-t SPACE key t-s = 4 SPACE key s-w = 4 SPACE key s-t-s = 4"
|
||||
|
||||
/*
|
||||
* This is the PinChangeInt library for the Arduino.
|
||||
This library provides an extension to the interrupt support for arduino by adding pin change
|
||||
interrupts, giving a way for users to have interrupts drive off of any pin (ATmega328-based
|
||||
Arduinos) and by the Port B, J, and K pins on the Arduino Mega and its ilk (see the README file).
|
||||
|
||||
See the README for license, acknowledgments, and other details (especially concerning the Arduino MEGA).
|
||||
|
||||
See google code project for latest, bugs and info http://code.google.com/p/arduino-pinchangeint/
|
||||
See github for the bleeding edge code: https://github.com/GreyGnome/PinChangeInt
|
||||
For more information Refer to avr-gcc header files, arduino source and atmega datasheet.
|
||||
|
||||
This library was inspired by and derived from Chris J. Kiick's PCInt Arduino Playground
|
||||
example here: http://www.arduino.cc/playground/Main/PcInt
|
||||
Nice job, Chris!
|
||||
*/
|
||||
|
||||
//-------- define these in your sketch, if applicable ----------------------------------------------------------
|
||||
//-------- These must go in your sketch ahead of the #include <PinChangeInt.h> statement -----------------------
|
||||
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
|
||||
// on any one or two of the three ports. If only a single port remains, the handler will be declared inline
|
||||
// reducing the size and latency of the handler.
|
||||
// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
||||
// #define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
|
||||
// #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
|
||||
// --- Mega support ---
|
||||
// #define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
|
||||
// #define NO_PORTJ_PINCHANGES // to indicate that port j will not be used for pin change interrupts
|
||||
// #define NO_PORTK_PINCHANGES // to indicate that port k will not be used for pin change interrupts
|
||||
// In the Mega, there is no Port C, no Port D. Instead, you get Port J and Port K. Port B remains.
|
||||
// Port J, however, is practically useless because there is only 1 pin available for interrupts. Most
|
||||
// of the Port J pins are not even connected to a header connection. // </end> "Mega Support" notes
|
||||
// --- Sanguino, Mioduino support ---
|
||||
// #define NO_PORTA_PINCHANGES // to indicate that port a will not be used for pin change interrupts
|
||||
|
||||
// You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine
|
||||
// slightly by declaring that you don't care if the static variables PCintPort::pinState and/or
|
||||
// PCintPort::arduinoPin are set and made available to your interrupt routine.
|
||||
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
||||
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
||||
// #define DISABLE_PCINT_MULTI_SERVICE // to limit the handler to servicing a single interrupt per invocation.
|
||||
// #define GET_PCINT_VERSION // to enable the uint16_t getPCIintVersion () function.
|
||||
// The following is intended for testing purposes. If defined, then a whole host of static variables can be read
|
||||
// in your interrupt subroutine. It is not defined by default, and you DO NOT want to define this in
|
||||
// Production code!:
|
||||
// #define PINMODE
|
||||
//-------- define the above in your sketch, if applicable ------------------------------------------------------
|
||||
|
||||
/*
|
||||
VERSIONS found in moved to RELEASE_NOTES.
|
||||
|
||||
See the README file for the License and more details.
|
||||
*/
|
||||
|
||||
#ifndef PinChangeInt_h
|
||||
#define PinChangeInt_h
|
||||
|
||||
#include "stddef.h"
|
||||
|
||||
// Maurice Beelen, nms277, Akesson Karlpetter, and Orly Andico
|
||||
// sent in fixes to work with Arduino >= version 1.0
|
||||
#include <Arduino.h>
|
||||
#include <new.h>
|
||||
#include <wiring_private.h> // cbi and sbi defined here
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
/*
|
||||
* Theory: For the IO pins covered by Pin Change Interrupts
|
||||
* (== all of them on the Atmega168/328, and a subset on the Atmega2560),
|
||||
* the PCINT corresponding to the pin must be enabled and masked, and
|
||||
* an ISR routine provided. Since PCINTs are per port, not per pin, the ISR
|
||||
* must use some logic to actually implement a per-pin interrupt service.
|
||||
*/
|
||||
|
||||
/* Pin to interrupt map, ATmega328:
|
||||
* D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
|
||||
* D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
|
||||
* A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
|
||||
*/
|
||||
|
||||
#undef INLINE_PCINT
|
||||
#define INLINE_PCINT
|
||||
// Thanks to cserveny...@gmail.com for MEGA support!
|
||||
#if defined __AVR_ATmega2560__ || defined __AVR_ATmega1280__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__ || defined __AVR_ATmega640__
|
||||
#define __USE_PORT_JK
|
||||
// Mega does not have PORTA, C or D
|
||||
#define NO_PORTA_PINCHANGES
|
||||
#define NO_PORTC_PINCHANGES
|
||||
#define NO_PORTD_PINCHANGES
|
||||
#if ((defined(NO_PORTB_PINCHANGES) && defined(NO_PORTJ_PINCHANGES)) || \
|
||||
(defined(NO_PORTJ_PINCHANGES) && defined(NO_PORTK_PINCHANGES)) || \
|
||||
(defined(NO_PORTK_PINCHANGES) && defined(NO_PORTB_PINCHANGES)))
|
||||
#define INLINE_PCINT inline
|
||||
#endif
|
||||
#else
|
||||
#define NO_PORTJ_PINCHANGES
|
||||
#define NO_PORTK_PINCHANGES
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
#ifndef NO_PORTA_PINCHANGES
|
||||
#define __USE_PORT_A
|
||||
#endif
|
||||
#else
|
||||
#define NO_PORTA_PINCHANGES
|
||||
#endif
|
||||
// if defined only D .OR. only C .OR. only B .OR. only A, then inline it
|
||||
#if ( (defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES)) || \
|
||||
(defined(NO_PORTA_PINCHANGES) && defined(NO_PORTB_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \
|
||||
(defined(NO_PORTA_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) || \
|
||||
(defined(NO_PORTB_PINCHANGES) && defined(NO_PORTC_PINCHANGES) && defined(NO_PORTD_PINCHANGES)) )
|
||||
#define INLINE_PCINT inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Provide drop in compatibility with Chris J. Kiick's PCInt project at
|
||||
// http://www.arduino.cc/playground/Main/PcInt
|
||||
#define PCdetachInterrupt(pin) PCintPort::detachInterrupt(pin)
|
||||
#define PCattachInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, userFunc,mode)
|
||||
#define PCgetArduinoPin() PCintPort::getArduinoPin()
|
||||
|
||||
typedef void (*PCIntvoidFuncPtr)(void);
|
||||
|
||||
class PCintPort {
|
||||
public:
|
||||
// portB=PCintPort(2, 1,PCMSK1);
|
||||
// index: portInputReg(*portInputRegister(index)),
|
||||
// pcindex: PCICRbit(1 << pcindex)
|
||||
// maskReg: portPCMask(maskReg)
|
||||
PCintPort(int index,int pcindex, volatile uint8_t& maskReg) :
|
||||
portInputReg(*portInputRegister(index)),
|
||||
portPCMask(maskReg),
|
||||
PCICRbit(1 << pcindex),
|
||||
portRisingPins(0),
|
||||
portFallingPins(0),
|
||||
firstPin(NULL)
|
||||
#ifdef PINMODE
|
||||
,intrCount(0)
|
||||
#endif
|
||||
{
|
||||
#ifdef FLASH
|
||||
ledsetup();
|
||||
#endif
|
||||
}
|
||||
volatile uint8_t& portInputReg;
|
||||
static int8_t attachInterrupt(uint8_t pin, PCIntvoidFuncPtr userFunc, int mode);
|
||||
static void detachInterrupt(uint8_t pin);
|
||||
INLINE_PCINT void PCint();
|
||||
static volatile uint8_t curr;
|
||||
#ifndef NO_PIN_NUMBER
|
||||
static volatile uint8_t arduinoPin;
|
||||
#endif
|
||||
#ifndef NO_PIN_STATE
|
||||
static volatile uint8_t pinState;
|
||||
#endif
|
||||
#ifdef PINMODE
|
||||
static volatile uint8_t pinmode;
|
||||
static volatile uint8_t s_portRisingPins;
|
||||
static volatile uint8_t s_portFallingPins;
|
||||
static volatile uint8_t s_lastPinView;
|
||||
static volatile uint8_t s_pmask;
|
||||
static volatile char s_PORT;
|
||||
static volatile uint8_t s_changedPins;
|
||||
static volatile uint8_t s_portRisingPins_nCurr;
|
||||
static volatile uint8_t s_portFallingPins_nNCurr;
|
||||
static volatile uint8_t s_currXORlastPinView;
|
||||
volatile uint8_t intrCount;
|
||||
static volatile uint8_t s_count;
|
||||
static volatile uint8_t pcint_multi;
|
||||
static volatile uint8_t PCIFRbug;
|
||||
#endif
|
||||
#ifdef FLASH
|
||||
static void ledsetup(void);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
class PCintPin {
|
||||
public:
|
||||
PCintPin() :
|
||||
PCintFunc((PCIntvoidFuncPtr)NULL),
|
||||
mode(0) {}
|
||||
PCIntvoidFuncPtr PCintFunc;
|
||||
uint8_t mode;
|
||||
uint8_t mask;
|
||||
uint8_t arduinoPin;
|
||||
PCintPin* next;
|
||||
};
|
||||
void enable(PCintPin* pin, PCIntvoidFuncPtr userFunc, uint8_t mode);
|
||||
int8_t addPin(uint8_t arduinoPin,PCIntvoidFuncPtr userFunc, uint8_t mode);
|
||||
volatile uint8_t& portPCMask;
|
||||
const uint8_t PCICRbit;
|
||||
volatile uint8_t portRisingPins;
|
||||
volatile uint8_t portFallingPins;
|
||||
volatile uint8_t lastPinView;
|
||||
PCintPin* firstPin;
|
||||
};
|
||||
|
||||
#ifndef LIBCALL_PINCHANGEINT // LIBCALL_PINCHANGEINT ***********************************************
|
||||
volatile uint8_t PCintPort::curr=0;
|
||||
#ifndef NO_PIN_NUMBER
|
||||
volatile uint8_t PCintPort::arduinoPin=0;
|
||||
#endif
|
||||
#ifndef NO_PIN_STATE
|
||||
volatile uint8_t PCintPort::pinState=0;
|
||||
#endif
|
||||
#ifdef PINMODE
|
||||
volatile uint8_t PCintPort::pinmode=0;
|
||||
volatile uint8_t PCintPort::s_portRisingPins=0;
|
||||
volatile uint8_t PCintPort::s_portFallingPins=0;
|
||||
volatile uint8_t PCintPort::s_lastPinView=0;
|
||||
volatile uint8_t PCintPort::s_pmask=0;
|
||||
volatile char PCintPort::s_PORT='x';
|
||||
volatile uint8_t PCintPort::s_changedPins=0;
|
||||
volatile uint8_t PCintPort::s_portRisingPins_nCurr=0;
|
||||
volatile uint8_t PCintPort::s_portFallingPins_nNCurr=0;
|
||||
volatile uint8_t PCintPort::s_currXORlastPinView=0;
|
||||
volatile uint8_t PCintPort::s_count=0;
|
||||
volatile uint8_t PCintPort::pcint_multi=0;
|
||||
volatile uint8_t PCintPort::PCIFRbug=0;
|
||||
#endif
|
||||
|
||||
#ifdef FLASH
|
||||
#define PINLED 13
|
||||
volatile uint8_t *led_port;
|
||||
uint8_t led_mask;
|
||||
uint8_t not_led_mask;
|
||||
boolean ledsetup_run=false;
|
||||
void PCintPort::ledsetup(void) {
|
||||
if (! ledsetup_run) {
|
||||
led_port=portOutputRegister(digitalPinToPort(PINLED));
|
||||
led_mask=digitalPinToBitMask(PINLED);
|
||||
not_led_mask=led_mask^0xFF;
|
||||
pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW);
|
||||
ledsetup_run=true;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
//
|
||||
// ATMEGA 644
|
||||
//
|
||||
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino, Mosquino uino bobino bonanafannafofino, me my momino...
|
||||
|
||||
#ifndef NO_PORTA_PINCHANGES
|
||||
PCintPort portA=PCintPort(1, 0,PCMSK0); // port PA==1 (from Arduino.h, Arduino version 1.0)
|
||||
#endif
|
||||
#ifndef NO_PORTB_PINCHANGES
|
||||
PCintPort portB=PCintPort(2, 1,PCMSK1); // port PB==2 (from Arduino.h, Arduino version 1.0)
|
||||
#endif
|
||||
#ifndef NO_PORTC_PINCHANGES
|
||||
PCintPort portC=PCintPort(3, 2,PCMSK2); // port PC==3 (also in pins_arduino.c, Arduino version 022)
|
||||
#endif
|
||||
#ifndef NO_PORTD_PINCHANGES
|
||||
PCintPort portD=PCintPort(4, 3,PCMSK3); // port PD==4
|
||||
#endif
|
||||
|
||||
#else // others
|
||||
|
||||
#ifndef NO_PORTB_PINCHANGES
|
||||
PCintPort portB=PCintPort(2, 0,PCMSK0); // port PB==2 (from Arduino.h, Arduino version 1.0)
|
||||
#endif
|
||||
#ifndef NO_PORTC_PINCHANGES // note: no PORTC on MEGA
|
||||
PCintPort portC=PCintPort(3, 1,PCMSK1); // port PC==3 (also in pins_arduino.c, Arduino version 022)
|
||||
#endif
|
||||
#ifndef NO_PORTD_PINCHANGES // note: no PORTD on MEGA
|
||||
PCintPort portD=PCintPort(4, 2,PCMSK2); // port PD==4
|
||||
#endif
|
||||
|
||||
#endif // defined __AVR_ATmega644__
|
||||
|
||||
#ifdef __USE_PORT_JK
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
PCintPort portJ=PCintPort(10,1,PCMSK1); // port PJ==10
|
||||
#endif
|
||||
#ifndef NO_PORTK_PINCHANGES
|
||||
PCintPort portK=PCintPort(11,2,PCMSK2); // port PK==11
|
||||
#endif
|
||||
#endif // USE_PORT_JK
|
||||
|
||||
static PCintPort *lookupPortNumToPort( int portNum ) {
|
||||
PCintPort *port = NULL;
|
||||
|
||||
switch (portNum) {
|
||||
#ifndef NO_PORTA_PINCHANGES
|
||||
case 1:
|
||||
port=&portA;
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_PORTB_PINCHANGES
|
||||
case 2:
|
||||
port=&portB;
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_PORTC_PINCHANGES
|
||||
case 3:
|
||||
port=&portC;
|
||||
break;
|
||||
#endif
|
||||
#ifndef NO_PORTD_PINCHANGES
|
||||
case 4:
|
||||
port=&portD;
|
||||
break;
|
||||
#endif
|
||||
#ifdef __USE_PORT_JK
|
||||
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
case 10:
|
||||
port=&portJ;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTK_PINCHANGES
|
||||
case 11:
|
||||
port=&portK;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#endif // __USE_PORT_JK
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
void PCintPort::enable(PCintPin* p, PCIntvoidFuncPtr userFunc, uint8_t mode) {
|
||||
// Enable the pin for interrupts by adding to the PCMSKx register.
|
||||
// ...The final steps; at this point the interrupt is enabled on this pin.
|
||||
p->mode=mode;
|
||||
p->PCintFunc=userFunc;
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
// A big shout out to jrhelbert for this fix! Thanks!!!
|
||||
if ((p->arduinoPin == 14) || (p->arduinoPin == 15)) {
|
||||
portPCMask |= (p->mask << 1); // PORTJ's PCMSK1 is a little odd...
|
||||
}
|
||||
else {
|
||||
portPCMask |= p->mask;
|
||||
}
|
||||
#else
|
||||
portPCMask |= p->mask;
|
||||
#endif
|
||||
if ((p->mode == RISING) || (p->mode == CHANGE)) portRisingPins |= p->mask;
|
||||
if ((p->mode == FALLING) || (p->mode == CHANGE)) portFallingPins |= p->mask;
|
||||
PCICR |= PCICRbit;
|
||||
}
|
||||
|
||||
int8_t PCintPort::addPin(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, uint8_t mode)
|
||||
{
|
||||
PCintPin* tmp;
|
||||
|
||||
tmp=firstPin;
|
||||
// Add to linked list, starting with firstPin. If pin already exists, just enable.
|
||||
if (firstPin != NULL) {
|
||||
do {
|
||||
if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); }
|
||||
if (tmp->next == NULL) break;
|
||||
tmp=tmp->next;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
// Create pin p: fill in the data.
|
||||
PCintPin* p=new PCintPin;
|
||||
if (p == NULL) return(-1);
|
||||
p->arduinoPin=arduinoPin;
|
||||
p->mode = mode;
|
||||
p->next=NULL;
|
||||
p->mask = digitalPinToBitMask(arduinoPin); // the mask
|
||||
|
||||
if (firstPin == NULL) firstPin=p;
|
||||
else tmp->next=p; // NOTE that tmp cannot be NULL.
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC);
|
||||
int addr = (int) p;
|
||||
Serial.print(" instance addr: "); Serial.println(addr, HEX);
|
||||
Serial.print("userFunc addr: "); Serial.println((int)p->PCintFunc, HEX);
|
||||
#endif
|
||||
|
||||
enable(p, userFunc, mode);
|
||||
#ifdef DEBUG
|
||||
Serial.print("addPin. pin given: "); Serial.print(arduinoPin, DEC), Serial.print (" pin stored: ");
|
||||
int addr = (int) p;
|
||||
Serial.print(" instance addr: "); Serial.println(addr, HEX);
|
||||
#endif
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* attach an interrupt to a specific pin using pin change interrupts.
|
||||
*/
|
||||
int8_t PCintPort::attachInterrupt(uint8_t arduinoPin, PCIntvoidFuncPtr userFunc, int mode)
|
||||
{
|
||||
PCintPort *port;
|
||||
uint8_t portNum = digitalPinToPort(arduinoPin);
|
||||
if ((portNum == NOT_A_PORT) || (userFunc == NULL)) return(-1);
|
||||
|
||||
port=lookupPortNumToPort(portNum);
|
||||
// Added by GreyGnome... must set the initial value of lastPinView for it to be correct on the 1st interrupt.
|
||||
// ...but even then, how do you define "correct"? Ultimately, the user must specify (not provisioned for yet).
|
||||
port->lastPinView=port->portInputReg;
|
||||
#ifdef DEBUG
|
||||
Serial.print("attachInterrupt- pin: "); Serial.println(arduinoPin, DEC);
|
||||
#endif
|
||||
// map pin to PCIR register
|
||||
return(port->addPin(arduinoPin,userFunc,mode));
|
||||
}
|
||||
|
||||
void PCintPort::detachInterrupt(uint8_t arduinoPin)
|
||||
{
|
||||
PCintPort *port;
|
||||
PCintPin* current;
|
||||
uint8_t mask;
|
||||
uint8_t portNum = digitalPinToPort(arduinoPin);
|
||||
if (portNum == NOT_A_PORT) return;
|
||||
port=lookupPortNumToPort(portNum);
|
||||
mask=digitalPinToBitMask(arduinoPin);
|
||||
current=port->firstPin;
|
||||
while (current) {
|
||||
if (current->mask == mask) { // found the target
|
||||
uint8_t oldSREG = SREG;
|
||||
cli(); // disable interrupts
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
// A big shout out to jrhelbert for this fix! Thanks!!!
|
||||
if ((arduinoPin == 14) || (arduinoPin == 15)) {
|
||||
port->portPCMask &= ~(mask << 1); // PORTJ's PCMSK1 is a little odd...
|
||||
}
|
||||
else {
|
||||
port->portPCMask &= ~mask; // disable the mask entry.
|
||||
}
|
||||
#else
|
||||
port->portPCMask &= ~mask; // disable the mask entry.
|
||||
#endif
|
||||
if (port->portPCMask == 0) PCICR &= ~(port->PCICRbit);
|
||||
port->portRisingPins &= ~current->mask; port->portFallingPins &= ~current->mask;
|
||||
// TODO: This is removed until we can add code that frees memory.
|
||||
// Note that in the addPin() function, above, we do not define a new pin if it was
|
||||
// once already defined.
|
||||
// ... ...
|
||||
// Link the previous' next to the found next. Then remove the found.
|
||||
//if (prev != NULL) prev->next=current->next; // linked list skips over current.
|
||||
//else firstPin=current->next; // at the first pin; save the new first pin
|
||||
SREG = oldSREG; // Restore register; reenables interrupts
|
||||
return;
|
||||
}
|
||||
current=current->next;
|
||||
}
|
||||
}
|
||||
|
||||
// common code for isr handler. "port" is the PCINT number.
|
||||
// there isn't really a good way to back-map ports and masks to pins.
|
||||
void PCintPort::PCint() {
|
||||
|
||||
#ifdef FLASH
|
||||
if (*led_port & led_mask) *led_port&=not_led_mask;
|
||||
else *led_port|=led_mask;
|
||||
#endif
|
||||
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
||||
uint8_t pcifr;
|
||||
while (true) {
|
||||
#endif
|
||||
// get the pin states for the indicated port.
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_lastPinView=lastPinView;
|
||||
intrCount++;
|
||||
PCintPort::s_count=intrCount;
|
||||
#endif
|
||||
uint8_t changedPins = (PCintPort::curr ^ lastPinView) &
|
||||
((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr ));
|
||||
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_currXORlastPinView=PCintPort::curr ^ lastPinView;
|
||||
PCintPort::s_portRisingPins_nCurr=portRisingPins & PCintPort::curr;
|
||||
PCintPort::s_portFallingPins_nNCurr=portFallingPins & ~PCintPort::curr;
|
||||
#endif
|
||||
lastPinView = PCintPort::curr;
|
||||
|
||||
PCintPin* p = firstPin;
|
||||
while (p) {
|
||||
// Trigger interrupt if the bit is high and it's set to trigger on mode RISING or CHANGE
|
||||
// Trigger interrupt if the bit is low and it's set to trigger on mode FALLING or CHANGE
|
||||
if (p->mask & changedPins) {
|
||||
#ifndef NO_PIN_STATE
|
||||
PCintPort::pinState=PCintPort::curr & p->mask ? HIGH : LOW;
|
||||
#endif
|
||||
#ifndef NO_PIN_NUMBER
|
||||
PCintPort::arduinoPin=p->arduinoPin;
|
||||
#endif
|
||||
#ifdef PINMODE
|
||||
PCintPort::pinmode=p->mode;
|
||||
PCintPort::s_portRisingPins=portRisingPins;
|
||||
PCintPort::s_portFallingPins=portFallingPins;
|
||||
PCintPort::s_pmask=p->mask;
|
||||
PCintPort::s_changedPins=changedPins;
|
||||
#endif
|
||||
p->PCintFunc();
|
||||
}
|
||||
p=p->next;
|
||||
}
|
||||
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
||||
pcifr = PCIFR & PCICRbit;
|
||||
if (pcifr == 0) break;
|
||||
PCIFR |= PCICRbit;
|
||||
#ifdef PINMODE
|
||||
PCintPort::pcint_multi++;
|
||||
if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1; // PCIFR & PCICRbit should ALWAYS be 0 here!
|
||||
#endif
|
||||
PCintPort::curr=portInputReg;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NO_PORTA_PINCHANGES
|
||||
ISR(PCINT0_vect) {
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='A';
|
||||
#endif
|
||||
PCintPort::curr = portA.portInputReg;
|
||||
portA.PCint();
|
||||
}
|
||||
#define PORTBVECT PCINT1_vect
|
||||
#define PORTCVECT PCINT2_vect
|
||||
#define PORTDVECT PCINT3_vect
|
||||
#else
|
||||
#define PORTBVECT PCINT0_vect
|
||||
#define PORTCVECT PCINT1_vect
|
||||
#define PORTDVECT PCINT2_vect
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTB_PINCHANGES
|
||||
ISR(PORTBVECT) {
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='B';
|
||||
#endif
|
||||
PCintPort::curr = portB.portInputReg;
|
||||
portB.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTC_PINCHANGES
|
||||
ISR(PORTCVECT) {
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='C';
|
||||
#endif
|
||||
PCintPort::curr = portC.portInputReg;
|
||||
portC.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTD_PINCHANGES
|
||||
ISR(PORTDVECT){
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='D';
|
||||
#endif
|
||||
PCintPort::curr = portD.portInputReg;
|
||||
portD.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __USE_PORT_JK
|
||||
#ifndef NO_PORTJ_PINCHANGES
|
||||
ISR(PCINT1_vect) {
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='J';
|
||||
#endif
|
||||
PCintPort::curr = portJ.portInputReg;
|
||||
portJ.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_PORTK_PINCHANGES
|
||||
ISR(PCINT2_vect){
|
||||
#ifdef PINMODE
|
||||
PCintPort::s_PORT='K';
|
||||
#endif
|
||||
PCintPort::curr = portK.portInputReg;
|
||||
portK.PCint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __USE_PORT_JK
|
||||
|
||||
#ifdef GET_PCINT_VERSION
|
||||
uint16_t getPCIntVersion () {
|
||||
return ((uint16_t) PCINT_VERSION);
|
||||
}
|
||||
#endif // GET_PCINT_VERSION
|
||||
#endif // #ifndef LIBCALL_PINCHANGEINT *************************************************************
|
||||
#endif // #ifndef PinChangeInt_h *******************************************************************
|
||||
45
libraries/PinChangeInt/Posting_Raising_Question.txt
Normal file
45
libraries/PinChangeInt/Posting_Raising_Question.txt
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
Prompted by this thread: https://groups.google.com/a/arduino.cc/forum/#!topic/developers/GkCunoVbuVA , I thought I would introduce a thread to spur discussion of creating a bona fide library that would enable Pin Change Interrupts on the Arduino (ATmega-based) processors, as first class interrupts equivalent to attachInterrupt(). I have been maintaining a library for the Arduino, and thinking about the technical details of such a thing for a while now as well.
|
||||
|
||||
Ultimately, any solution is going to carry with it some ugliness because the ATmega328p's interrupt model is, at least to a beginning user, ugly. Having two interrupt types is confusing and annoying; the attachInterrupt() function, like the whole concept of External vs Pin Change Interrupts, contains complexities specific to the ATmega 8-bit line. At the moment, the programmer needs to keep in mind this translation table:
|
||||
Board int.0 int.1 int.2 int.3 int.4 int.5
|
||||
Uno, Ethernet 2 3
|
||||
Mega2560 2 3 21 20 19 18
|
||||
Leonardo 3 2 0 1 7
|
||||
Due (no translation necessary, the pin number is referenced)
|
||||
|
||||
So if you have an 8-bit processor, there's no official support for "interrupt on any pin" so you must translate External Interrupts as per the table. If you are not (eg, Due): just use the pin number. To me that's the most intuitive and it's what I expected to see back when I was first working on the Arduino. But the situation is hard to fix: Different types of interrupts don't all respond to the same stimuli. External Interrupts respond on rising, or falling, or change (either high or low), or low level. Interrupts on 32-bit processors appear to support all of that, plus high level. Pin Change Interrupts by default only support change.
|
||||
|
||||
That said, what would be the ultimate goal of such a library? I think it makes the most sense to have a library that supports the concept of "Interrupt by pin number", and it would support as many modes as possible, with the PinChangeInterrupt mimicking the low and high modes in software. Here's some ideas:
|
||||
|
||||
* create a new enable function in the Arduino API, referencing the proper interrupt type under the covers. Only Arduino pin numbers are given as arguments but many of those pin numbers will not be available as External Interrupts on (especially) the ATmega328. So, to use the other pins, you have to make them Pin Change Interrupts, and OR the pin number with the flag PINCHANGEINTERRUPT. As its value is 0 on other architectures, it has no effect on the Due and Galileo.
|
||||
* Or, add code to the attachInterrupt() call to make it work with Pin Change Interrupts. Essentially, it would operate like the above.
|
||||
* Or, just create another library call, just for 8-bit Arduinos and their wonky Pin Change Interrupts (this is what I'd created).
|
||||
|
||||
Concerning a new function in the Arduino API, called for example, "enableInterrupt()":
|
||||
This call could look the same on any platform, and for 8-bit chips you'd need a flag so as to create the proper interrupt type for the programmer. The flag would be a no-op on other (32-bit) chips. For example:
|
||||
#ifdef defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
||||
#define PINCHANGEINTERRUPT 0x80
|
||||
#define SLOWINTERRUPT 0x80
|
||||
...
|
||||
#ifdef NOT_ATMEGA
|
||||
#define PINCHANGEINTERRUPT 0
|
||||
#define SLOWINTERRUPT 0
|
||||
#endif
|
||||
|
||||
void enableInterrupt(interruptNumber, function, mode); // declaration
|
||||
enableInterrupt(2, 0, myFunction, LOW); // Usage example; this sets an interrupt on Arduino pin 2.
|
||||
// It is an external interrupt.
|
||||
// The following examples show that the 8-bit chips will create Pin Change Interrupts.
|
||||
// On the Due and Galileo, they will be regular interrupts (Because SLOWINTERRUPT==0 there).
|
||||
enableInterrupt(PINCHANGEINTERRUPT | 4, myFunction, RISING); // usage example for pin 4
|
||||
enableInterrupt(SLOWINTERRUPT | 4, myFunction, RISING); // same thing.
|
||||
enableInterrupt(4, myFunction, RISING); // ...as will this.
|
||||
|
||||
I don't see a way around the complexity and confusion of this call:
|
||||
enableInterrupt(PINCHANGEINTERRUPT | 4, myFunction, RISING); // usage example for pin 4
|
||||
but I think it's clearer than our current situation, where External Interrupts are officially supported but for Pin Change Interrupts the user is on his or her own, or they find a library somewhere.
|
||||
|
||||
On Monday, August 11, 2014 9:54:11 AM UTC-5, David A. Mellis wrote:
|
||||
|
||||
Just to throw in a random opinion: I think something like this would be good to include, although I haven't thought about the technical details. If it does get added, though, it should probably be called something like attachPinChangeInterrupt() as opposed to something with "PCINT" or "int".
|
||||
|
||||
109
libraries/PinChangeInt/README
Normal file
109
libraries/PinChangeInt/README
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
---- README --------------------------------------------------------------------
|
||||
PinChangeInt README. Find instructions and more information at
|
||||
http://code.google.com/p/arduino-pinchangeint/
|
||||
|
||||
---- DESCRIPTION ---------------------------------------------------------------
|
||||
This is the PinChangeInt library for the Arduino. It provides an extension to
|
||||
the interrupt support for ATmega328 and ATmega2560-based Arduinos, and some
|
||||
ATmega32u4 and Sanguinos. It adds pin change interrupts, giving a way for users
|
||||
to have interrupts drive off of any pin (ATmega328-based Arduinos), by the Port
|
||||
B, J, and K pins on the Arduino Mega and its ilk, and on the appropriate ports
|
||||
(including Port A) on the Sanguino and its ilk. Yun and Sanguino support are
|
||||
weak, quite honestly, as I don't have either a Sanguino or a Yun. Theoretically
|
||||
the library would work with a Leonardo but I have no reports regarding that
|
||||
platform. The ATmega32u4 has port B (8 pins) pin change interrupts only.
|
||||
|
||||
See Google Code project for latest, bugs and info:
|
||||
http://code.google.com/p/arduino-pinchangeint/
|
||||
See Github for the bleeding edge code:
|
||||
https://github.com/GreyGnome/PinChangeInt
|
||||
For more information refer to avr-gcc header files, Arduino source and Atmega
|
||||
datasheet.
|
||||
|
||||
This library was inspired by and derived from Chris J. Kiick's PCInt Arduino
|
||||
Playground example here: http://playground.arduino.cc/Main/PcInt
|
||||
|
||||
Regarding the MEGA and friends, Cserveny says: "J is mostly useless, because of
|
||||
the hardware UART... (many) pins are not connected on the arduino boards." The
|
||||
following pins are usable PinChangeInt pins on the Mega (ATmega1280 and
|
||||
ATmega2560-based Arduinos**):
|
||||
|
||||
Arduino Arduino Arduino
|
||||
Pin* PORT PCINT Pin PORT PCINT Pin PORT PCINT
|
||||
A8 PK0 16 10 PB4 4 SS PB0 0
|
||||
A9 PK1 17 11 PB5 5 SCK PB1 1
|
||||
A10 PK2 18 12 PB6 6 MOSI PB2 2
|
||||
A11 PK3 19 13 PB7 7** MISO PB3 3
|
||||
A12 PK4 20 14 PJ1 10
|
||||
A13 PK5 21 15 PJ0 9
|
||||
A14 PK6 22
|
||||
A15 PK7 23
|
||||
...indeed, the ATmega2560 chip supports many more Pin Change Interrupt pins but
|
||||
they are unavailable on the Arduino, unless you want to solder teeny tiny wires.
|
||||
|
||||
* Note: Arduino Pin 0 is PE0 (PCINT8), which is RX0 and thus is not supported by
|
||||
this library. It is the same pin the Arduino uses to upload sketches, and they
|
||||
are connected to the FT232RL USB-to-Serial chip (ATmega16U2 on the R3).
|
||||
** On the MegaADK, according to http://arduino.cc/en/Main/ArduinoBoardMegaADK:
|
||||
"USB Host: MAX3421E. The MAX3421E comunicate with Arduino with the SPI bus. So
|
||||
it uses the following pins:
|
||||
Digital: 7 (RST), 50 (MISO), 51 (MOSI), 52 (SCK). NB: Please do not use Digital
|
||||
pin 7 as input or output because is used in the comunication (sic) with
|
||||
MAX3421E "
|
||||
|
||||
---- LICENSE -------------------------------------------------------------------
|
||||
Licensed under the Apache2.0 license. See the source files for the license
|
||||
boilerplate, the LICENSE file for the full text, and the NOTICE file which the
|
||||
Apache2.0 license requires that you distribute with any code that you distribute
|
||||
that uses this library. The copyright holders for this code are Chris J. Kiick,
|
||||
Lex Talionis, and Michael Schwager. Chris and Lex have graciously agreed to the
|
||||
Apache 2.0 license for this code, and beginning with version 2.40-rc1 this is
|
||||
the license that applies.
|
||||
|
||||
---- ACKNOWLEDGMENTS -----------------------------------------------------------
|
||||
This library was originally written by Chris J. Kiick, Robot builder and all
|
||||
around geek, who said of it,
|
||||
"Hi, Yeah, I wrote the original PCint library. It was a bit of a hack
|
||||
and the new one has better features. I intended the code to be freely
|
||||
usable. Didn't really think about a license. Feel free to use it in
|
||||
your code: I hereby grant you permission."
|
||||
Thanks, Chris! A hack? I dare say not, if I have taken this any further it's
|
||||
merely by standing on the shoulders of giants. This library was the best
|
||||
"tutorial" I found on Arduino Pin Change Interrupts and because of that I
|
||||
decided to continue to maintain and (hopefully) improve it. We, the Arduino
|
||||
community of robot builders and geeks, owe you a great debt of gratitude for
|
||||
your hack- a hack in the finest sense.
|
||||
|
||||
The library was then picked up by Lex Talionis, who created the Google Code
|
||||
website. We all owe a debt of thanks to Lex, too, for all his hard work! He is
|
||||
currently the other official maintainer of this code.
|
||||
|
||||
Many thanks to all the contributors who have contributed bug fixes, code, and
|
||||
suggestions to this project:
|
||||
|
||||
John Boiles and Baziki (who added fixes to PcInt), Maurice Beelen, nms277,
|
||||
Akesson Karlpetter, and Orly Andico for various fixes to this code, Rob Tillaart
|
||||
for some excellent code reviews and nice optimizations, Andre' Franken for a
|
||||
good bug report that kept me thinking, cserveny.tamas a special shout out for
|
||||
providing the MEGA code to PinChangeInt, and Pat O'Brien for testing and
|
||||
reporting on the Arduino Yun.- Thanks!
|
||||
|
||||
A HUGE thanks to JRHelbert for fixing the PJ0 and PJ1 interrupt PCMSK1 issue on
|
||||
the Mega... 06/2014
|
||||
|
||||
A HUGE thanks to Jan Baeyens ("jantje"), who has graciously DONATED an Arduino
|
||||
Mega ADK to the PinChangeInt project!!! Wow, thanks Jan! This makes the
|
||||
2560-based Arduino Mega a first class supported platform- I will be able to test
|
||||
it and verify that it works.
|
||||
|
||||
Finally, a shout out to Leonard Bernstein. I was inspired by him
|
||||
(https://www.youtube.com/watch?feature=player_detailpage&v=R9g3Q-qvtss#t=1160)
|
||||
from a Ted talk by Itay Talgam. None of the contributors, myself included, has
|
||||
any interest in making money from this library and so I decided to free up the
|
||||
code as much as possible for any purpose. ...But! You must give credit where
|
||||
credit is due (it's not only a nice idea, it's the law- as in, the license
|
||||
terms)!
|
||||
|
||||
"If you love something, give it away."
|
||||
|
||||
If apologize if I have forgotten anyone here. Please let me know if so.
|
||||
436
libraries/PinChangeInt/RELEASE_NOTES
Normal file
436
libraries/PinChangeInt/RELEASE_NOTES
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
******************************************************************************
|
||||
|
||||
PinChangeInt
|
||||
---- RELEASE NOTES ---
|
||||
Version 2.40-rc2 Mon Jan 12 07:37:22 CST 2015
|
||||
Happy New Year!
|
||||
|
||||
Cleaned up some code, and added the following #define's for ease-of-use:
|
||||
|
||||
#define detachPinChangeInterrupt(pin) PCintPort::detachInterrupt(pin)
|
||||
#define attachPinChangeInterrupt(pin,userFunc,mode) PCintPort::attachInterrupt(pin, &userFunc,mode)
|
||||
#define getInterruptedPin() PCintPort::getArduinoPin()
|
||||
|
||||
Cleaned up the README for better display on GitHub.
|
||||
|
||||
Version 2.40-rc1 Fri Nov 7 07:26:36 CST 2014
|
||||
I'm going to the "-rcX" numbering format like the Linux kernel. That is, 2.40-rc1 is the first "release
|
||||
candidate" on the way to a stable 2.40 release.
|
||||
|
||||
Beginning with this release, only Arduino >= 1.00 is supported. The older Arduinos are left to the
|
||||
dustbin of history...
|
||||
|
||||
I have BIG news: Jan Baeyens ("jantje") has graciously DONATED an Arduino Mega ADK
|
||||
to the PinChangeInt project!!! Wow, thanks Jan! This makes the 2560-based Arduino Mega
|
||||
a first class supported platform- I will be able to test it and verify that it works.
|
||||
I have done so in this release.
|
||||
|
||||
To that end, The PinChangeIntExample has been modified to work properly with the Arduino Mega.
|
||||
Thanks, Jan!
|
||||
|
||||
And the BIG BIG BIG news: The library is now licensed under the Apache 2.0 License. I wanted to
|
||||
free the code up for any use, and Chris J. Kiick and Lex Talionis graciously agreed.
|
||||
|
||||
Version 2.32 Fri Oct 31 05:16:34 CDT 2014
|
||||
Argh! I should have done a "git status" prior to to tagging 2.31. Well, this makes 2.32.
|
||||
|
||||
I had added an additional method to putString, so as to allow for a different signature and stop
|
||||
the compiler from complaining:
|
||||
|
||||
uint8_t ByteBuffer::putString(const char *in) {
|
||||
return(putString((char *) in));
|
||||
}
|
||||
|
||||
No other changes over 2.32
|
||||
|
||||
Version 2.31 Fri Oct 31 05:11:41 CDT 2014
|
||||
I forgot to update these release notes for version 2.30. And I didn't tag it. This is merely a
|
||||
some housekeeping from 2.30. Here is what changed from version 2.21:
|
||||
|
||||
In Examples/PinChangeIntTest/PinChangeIntTest.ino:
|
||||
Whacked a nasty little bug in setup(), where my 'i' variable in the for
|
||||
loop went until 'i < 7'. Should have been 'i < 6' all along. Grrr.
|
||||
|
||||
In PinChangeInt.h:
|
||||
Most significantly: Many thanks to JRHelbert for fixing the PJ0 and PJ1
|
||||
interrupt PCMSK1 issue on the Arduino Mega! This was a great coup, in my
|
||||
humble opinion. Mega interrupt users are indebted to you, jrhelbert.
|
||||
|
||||
Added PinChangeIntDebug.ino, which is a simplified PinChangeIntTest. My
|
||||
head was spinning in PinChangeIntTest due to a nasty bug that I whacked,
|
||||
so I wanted a simplified test file.
|
||||
|
||||
|
||||
Version 2.21 (beta) Mon Apr 8 22:06:13 CDT 2013
|
||||
Fixed Examples/ByteBuffer/ByteBuffer.cpp. Bug in the PutString() method. Does not affect the behavior
|
||||
of the library at all whatsoever, this was only used in the example code.
|
||||
|
||||
Version 2.19 (beta) Tue Nov 20 07:33:37 CST 2012
|
||||
SANGUINO SUPPORT! ...And Mioduino!
|
||||
...The ATmega644 chip is so cool, how can I not? 4 full ports of Pin Change Interrupt bliss! 32 i/o pins! 64k Flash! 4k RAM! Well I wish I had one. That said, Sanguino users, PLEASE send in your bug or bliss reports! Your interrupt-loving brethren and sistren are depending on you, so I can assure everyone that my changes work on that platform. Thanks.
|
||||
|
||||
Modified the addPin() method to save 12 bytes; thanks again robtilllart!
|
||||
if (firstPin != NULL) {
|
||||
tmp=firstPin;
|
||||
do {
|
||||
if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); }
|
||||
if (tmp->next == NULL) break;
|
||||
tmp=tmp->next;
|
||||
} while (true);
|
||||
}
|
||||
Also changed the goto in the PCint() loop to be a while/break combination. No change to
|
||||
code speed, but it looks better and passes the cleanliness "gut check".
|
||||
|
||||
Includes PinChangeIntTest 1.5 sketch.
|
||||
|
||||
...Ooops! Forgot the GetPSTR library, needed for the PinChangeIntTest code! Now it's included.
|
||||
******************************************************************************
|
||||
Version 2.17 (beta) Sat Nov 17 09:46:50 CST 2012
|
||||
Another bugfix in the PCINT_MULTI_SERVICE section. I was using sbi(PCIFR, PCICRbit);
|
||||
I didn't realize that was for I/O ports, and not ATmega registers.
|
||||
But according to "deprecated.h",
|
||||
"These macros became obsolete, as reading and writing IO ports can
|
||||
be done by simply using the IO port name in an expression, and all
|
||||
bit manipulation (including those on IO ports) can be done using
|
||||
generic C bit manipulation operators."
|
||||
So now I do:
|
||||
PCIFR |= PCICRbit;
|
||||
******************************************************************************
|
||||
Version 2.15 (beta) Sat Nov 17 01:17:44 CST 2012
|
||||
Fixed it so that attachInterrupt() will now follow your changes to the user function,
|
||||
as well as the mode. detachInterrupt() still does not delete the PCintPin object but
|
||||
at least you can detach and reattach at will, using different modes (RISING, FALLING,
|
||||
CHANGE) and different functions as you wish.
|
||||
|
||||
******************************************************************************
|
||||
Version 2.13 (beta) Mon Nov 12 09:33:06 CST 2012
|
||||
SIGNIFICANT BUGFIX release! Significant changes:
|
||||
1. PCintPort::curr bug. Interrupts that occur rapidly will likely not get serviced properly by PCint().
|
||||
2. PCint() interrupt handler optimization.
|
||||
3. PCIFR port bit set bug fix.
|
||||
4. Many static variables added for debugging; used only when #define PINMODE is on.
|
||||
5. detachInterrupt() no longer does a delete(), since that wasn't working anyway. When you detachInterrupt(), the PORT just disables interrupts for that pin; the PCintPin object remains in memory and in the linked list of pins (possibly slowing down your interrupts a couple of micros). You can reenable a detached interrupt- but you must do it within the PinChangeInt library (would anyone ever enable an interrupt on a pin, then disable it, then have need to reenable it but not using the library?).
|
||||
6. attachInterrupt() now returns a uint8_t value: 1 on successful attach, 0 on successful attach but using an already-enabled pin, and -1 if the new() operator failed to create a PCintPin object.
|
||||
Also, modified these release notes.
|
||||
|
||||
Details:
|
||||
|
||||
Uncovered a nasty bug, thanks to robtillaart on the Arduino Forums and Andre' Franken who posted to the PinChangeInt groups. This bug was introduced by me when I assigned PCintPort::curr early in the interrupt handler:
|
||||
ISR(PCINT0_vect) {
|
||||
PCintPort::curr = portB.portInputReg;
|
||||
portB.PCint();
|
||||
}
|
||||
Later, in the interrupt handler PCint(), we loop as long as PCIFR indicates a new interrupt wants to be triggered, provided DISABLE_PCINT_MULTI_SERVICE is not defined (it is not by default):
|
||||
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
||||
pcifr = PCIFR & PCICRbit;
|
||||
PCIFR = pcifr; // clear the interrupt if we will process it (no effect if bit is zero)
|
||||
} while(pcifr);
|
||||
#endif
|
||||
...Well. Problem is, if a pin pops up and causes the PCIFR to change, we have to reread the port and look at how it is now! I wasn't doing that before, so if a new interrupt appeared while I was still servicing the old one, odd behavior would take place. For example, an interrupt would register but then the userFunc would not be called upon to service it. The code needs to be:
|
||||
pcifr = PCIFR & PCICRbit;
|
||||
PCIFR = pcifr; // clear the interrupt if we will process it (no effect if bit is zero)
|
||||
PCintPort::curr=portInputReg; // ...Fixed in 2.11beta.
|
||||
} while(pcifr);
|
||||
|
||||
Also, made the interrupt handler even faster with an optimization from robtillaart to take out the checks for changed pins from the while() loop that steps through the pins:
|
||||
uint8_t changedPins = (PCintPort::curr ^ lastPinView) &
|
||||
((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr ));
|
||||
|
||||
...This speedup is offset by more changes in the PCint() handler, which now looks like the following; there are two bug fixes:
|
||||
----------------------------
|
||||
FIX 1: sbi(PCIFR, PCICRbit);
|
||||
FIX 2: ...the aforementioned PCintPort::curr=portInputReg;
|
||||
Here's the new code:
|
||||
----------------------------
|
||||
#ifndef DISABLE_PCINT_MULTI_SERVICE
|
||||
pcifr = PCIFR & PCICRbit;
|
||||
if (pcifr) {
|
||||
//if (PCIFR & PCICRbit) { // believe it or not, this adds .6 micros
|
||||
sbi(PCIFR, PCICRbit); // This was a BUG: PCIFR = pcifr ...And here is the fix.
|
||||
#ifdef PINMODE
|
||||
PCintPort::pcint_multi++;
|
||||
if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1; // PCIFR & PCICRbit should ALWAYS be 0 here!
|
||||
#endif
|
||||
PCintPort::curr=portInputReg; // ...Fixed in 2.11beta.
|
||||
goto loop; // A goto!!! Don't want to look at the portInputReg gratuitously, so the while() will not do.
|
||||
}
|
||||
#endif
|
||||
|
||||
Also I added a lot of variables for debugging when PINMODE is defined, for routing out nasty bugs. I may need them in the future... :-(
|
||||
|
||||
Finally, I am not putting newlines in this commentary so I can make it easier to paste online.
|
||||
|
||||
******************************************************************************
|
||||
Version 2.11 (beta) Mon Nov 12 09:33:06 CST 2012
|
||||
See version 2.13 (beta) above. No change other than tidying up the release notes.
|
||||
******************************************************************************
|
||||
Version 2.01 (beta) Thu Jun 28 12:35:48 CDT 2012
|
||||
...Wow, Version 2! What? Why?
|
||||
Modified the way that the pin is tested inside the interrupt subroutine (ISR) PCintPort::PCint(),
|
||||
to make the interrupt quicker and slightly reduce the memory footprint. The interrupt's time is
|
||||
reduced by 2 microseconds or about 7%. Instead of using the mode variable, two bitmasks are maintained
|
||||
for each port. One bitmask contains all the pins that are configured to work on RISING signals, the other
|
||||
on FALLING signals. A pin configured to work on CHANGE signals will appear in both bitmasks of the port.
|
||||
Then, the test for a change goes like this:
|
||||
if (thisChangedPin) {
|
||||
if ((thisChangedPin & portRisingPins & PCintPort::curr ) ||
|
||||
(thisChangedPin & portFallingPins & ~PCintPort::curr )) {
|
||||
where portRisingPins is the bitmask for the pins configured to interrupt on RISING signals, and
|
||||
portFallingPins is the bitmask for the pins configured to interrupt on FALLING signals. Each port includes
|
||||
these two bitmask variables.
|
||||
|
||||
This is a significant change to some core functionality to the library, and it saves an appreciable amount
|
||||
of time (2 out of 36 or so micros). Hence, the 2.00 designation.
|
||||
|
||||
Tue Jun 26 12:42:20 CDT 2012
|
||||
I was officially given permission to use the PCint library:
|
||||
|
||||
Re: PCint library
|
||||
« Sent to: GreyGnome on: Today at 08:10:33 AM »
|
||||
« You have forwarded or responded to this message. »
|
||||
Quote Reply Remove
|
||||
HI,
|
||||
Yeah, I wrote the original PCint library. It was a bit of a hack and the new one has better features.
|
||||
I intended the code to be freely usable. Didn't really think about a license. Feel free to use it in
|
||||
your code: I hereby grant you permission.
|
||||
|
||||
I'll investigate the MIT license, and see if it is appropriate.
|
||||
Chris J. Kiick
|
||||
Robot builder and all around geek.
|
||||
|
||||
Version 1.81 (beta) Tue Jun 19 07:29:08 CDT 2012
|
||||
Created the getPCIntVersion function, and its associated GET_PCINT_VERSION preprocessor macro. The version
|
||||
is a 16-bit int, therefore versions are represented as a 4-digit integer. 1810, then, is the first beta
|
||||
release of 1.81x series. 1811 would be a bugfix of 1.810. 1820 would be the production release.
|
||||
|
||||
Reversed the order of this list, so the most recent notes come first.
|
||||
|
||||
Made some variables "volatile", because they are changed in the interrupt code. Thanks, Tony Cappellini!
|
||||
|
||||
Added support for the Arduino Mega! Thanks to cserveny...@gmail.com!
|
||||
NOTE: I don't have a Mega, so I rely on you to give me error (or working) reports!
|
||||
To sum it up for the Mega: No Port C, no Port D. Instead, you get Port J and Port K. Port B remains.
|
||||
Port J, however, is practically useless because there is only 1 pin available for interrupts.
|
||||
Most of the Port J pins are not even connected to a header connector. Caveat Programmer.
|
||||
|
||||
Created a function to report the version of this code. Put this #define ahead of the #include of this file,
|
||||
in your sketch:
|
||||
#define GET_PCINT_VERSION
|
||||
Then you can call
|
||||
uint16_t getPCIntVersion ();
|
||||
and it will return a 16-bit integer representation of the version of this library. That is, version 1.73beta
|
||||
will be reported as "1730". 1.74, then, will return "1740". And so on, for whatever version of the library
|
||||
this happens to be. The odd number in the 10's position will indicate a beta version, as per usual, and the
|
||||
number in the 1s place will indicate the beta revision (bugs may necessitate a 1.731, 1.732, etc.).
|
||||
|
||||
Here are some of his notes based on his changes:
|
||||
Mega and friends are using port B, J and K for interrupts. B is working without any modifications.
|
||||
|
||||
J is mostly useless, because of the hardware UART. I was not able to get pin change notifications from
|
||||
the TX pin (14), so only 15 left. All other (PORT J) pins are not connected on the Arduino boards.
|
||||
|
||||
K controls Arduino pin A8-A15, working fine.
|
||||
|
||||
328/168 boards use C and D. So in case the lib is compiled with Mega target, the C and D will be
|
||||
disabled. Also you cannot see port J/K with other targets. For J and K new flags introduced:
|
||||
NO_PORTJ_PINCHANGES and NO_PORTK_PINCHANGES.
|
||||
Maybe we should have PORTJ_PINCHANGES to enable PJ, because they will be most likely unused.
|
||||
|
||||
Enjoy!
|
||||
|
||||
Note: To remain consistent, I have not included PORTJ_PINCHANGES. All ports behave the same,
|
||||
no matter how trivial those ports may seem... no surprises...
|
||||
|
||||
Version 1.72 Wed Mar 14 18:57:55 CDT 2012
|
||||
Release.
|
||||
|
||||
Version 1.71beta Sat Mar 10 12:57:05 CST 2012
|
||||
Code reordering: Starting in version 1.3 of this library, I put the code that enables
|
||||
interrupts for the given pin, and the code that enables Pin Change Interrupts, ahead of actually
|
||||
setting the user's function for the pin. Thus in the small interval between turning on the
|
||||
interrupts and actually creating a valid link to an interrupt handler, it is possible to get an
|
||||
interrupt. At that point the value of the pointer is 0, so this means that the Arduino
|
||||
will start over again from memory location 0- just as if you'd pressed the reset button. Oops!
|
||||
|
||||
I corrected it so the code now operates in the proper order.
|
||||
(EDITORIAL NOTE: If you want to really learn something, teach it!)
|
||||
|
||||
Minor code clean-up: All references to PCintPort::curr are now explicit. This changes the compiled
|
||||
hex code not one whit. I just sleep better at night.
|
||||
|
||||
Numbering: Changed the numbering scheme. Beta versions will end with an odd number in the hundredths
|
||||
place- because they may be odd- and continue to be marked "beta". I'll just sleep better at night. :-)
|
||||
|
||||
Version 1.70beta Mon Feb 27 07:20:42 CST 2012
|
||||
Happy Birthday to me! Happy Birthday tooooo meee! Happy Birthday, Dear Meeeeee-eeeee!
|
||||
Happy Birthday to me!
|
||||
|
||||
Yes, it is on this auspicious occasion of mine (and Elizabeth Taylor's [R.I.P.]) birthday that I
|
||||
humbly submit to you, gracious Arduino PinChangeInt user, version 1.70beta of the PinChangeInt
|
||||
library. I hope you enjoy it.
|
||||
|
||||
New in this release:
|
||||
The PinChangeIntTest sketch was created, which can be found in the Examples directory. It exercises:
|
||||
* Two interrupting pins, one on each of the Arduino's PORTs.
|
||||
* detachInterrupt() (and subsequent attachInterrupt()s).
|
||||
Hopefully this will help avoid the embarrassing bugs that I have heretofore missed.
|
||||
|
||||
As well, it has come to this author's (GreyGnome) attention that the Serial class in Arduino 1.0
|
||||
uses an interrupt that, if you attempt to print from an interrupt (which is what I was doing in my
|
||||
tests) can easily lock up the Arduino. So I have taken SigurðurOrn's excellent ByteBuffer library
|
||||
and modified it for my own nefarious purposes. (see http://siggiorn.com/?p=460). The zipfile
|
||||
comes complete with the ByteBuffer library; see the ByteBuffer/ByteBuffer.h file for a list of
|
||||
changes, and see the PinChangeIntTest sketch for a usage scenario. Now the (interrupt-less and)
|
||||
relatively fast operation of filling a circular buffer is used in the interrupt routines. The buffer
|
||||
is then printed from loop().
|
||||
|
||||
The library has been modified so it can be used in other libraries, such as my AdaEncoder library
|
||||
(http://code.google.com/p/adaencoder/). When #include'd by another library you should #define
|
||||
the LIBCALL_PINCHANGEINT macro. For example:
|
||||
#ifndef PinChangeInt_h
|
||||
#define LIBCALL_PINCHANGEINT
|
||||
#include "../PinChangeInt/PinChangeInt.h"
|
||||
#endif
|
||||
This is necessary because the IDE compiles both your sketch and the .cpp file of your library, and
|
||||
the .h file is included in both places. But since the .h file actually contains the code, any variable
|
||||
or function definitions would occur twice and cause compilation errors- unless #ifdef'ed out.
|
||||
|
||||
Version 1.6beta Fri Feb 10 08:48:35 CST 2012
|
||||
Set the value of the current register settings, first thing in each ISR; e.g.,
|
||||
ISR(PCINT0_vect) {
|
||||
PCintPort::curr = portB.portInputReg; // version 1.6
|
||||
...
|
||||
...instead of at the beginning of the PCintPort::PCint() static method. This means that the port is read
|
||||
closer to the beginning of the interrupt, and may be slightly more accurate- only by a couple of microseconds,
|
||||
really, but it's a cheap win.
|
||||
|
||||
Fixed a bug- a BUG!- in the attachInterrupt() and detachInterrupt() methods. I didn't have breaks in my
|
||||
switch statements! Augh! What am I, a (UNIX) shell programmer? ...Uh, generally, yes...
|
||||
|
||||
Added the PINMODE define and the PCintPort::pinmode variable.
|
||||
|
||||
Version 1.51 Sun Feb 5 23:28:02 CST 2012
|
||||
Crap, a bug! Changed line 392 from this:
|
||||
PCintPort::pinState=curr & changedPins ? HIGH : LOW;
|
||||
to this:
|
||||
PCintPort::pinState=curr & p->mask ? HIGH : LOW;
|
||||
Also added a few lines of (commented-out) debug code.
|
||||
|
||||
Version 1.5 Thu Feb 2 18:09:49 CST 2012
|
||||
Added the PCintPort::pinState static variable to allow the programmer to query the state of the pin
|
||||
at the time of interrupt.
|
||||
Added two new #defines, NO_PIN_STATE and NO_PIN_NUMBER so as to reduce the code size by 20-50 bytes,
|
||||
and to speed up the interrupt routine slightly by declaring that you don't care if the static variables
|
||||
PCintPort::pinState and/or PCintPort::arduinoPin are set and made available to your interrupt routine.
|
||||
// #define NO_PIN_STATE // to indicate that you don't need the pinState
|
||||
// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin
|
||||
|
||||
Version 1.4 Tue Jan 10 09:41:14 CST 2012
|
||||
All the code has been moved into this .h file, so as to allow #define's to work from the user's
|
||||
sketch. Thanks to Paul Stoffregen from pjrc.com for the inspiration! (Check out his website for
|
||||
some nice [lots more memory] Arduino-like boards at really good prices. ...This has been an unsolicited
|
||||
plug. Now back to our regular programming. ...Hehe, "programming", get it?)
|
||||
|
||||
As a result, we no longer use the PinChangeIntConfig.h file. The user must #define things in his/her
|
||||
sketch. Which is better anyway.
|
||||
|
||||
Removed the pcIntPorts[] array, which created all the ports by default no matter what. Now, only
|
||||
those ports (PCintPort objects) that you need will get created if you use the NO_PORTx_PINCHANGES #defines.
|
||||
This saves flash memory, and actually we get a bit of a memory savings anyway even if all the ports are
|
||||
left enabled.
|
||||
|
||||
The attachInterrupt and detachInterrupt routines were modified to handle the new PCintPort objects.
|
||||
|
||||
Version 1.3 Sat Dec 3 22:56:20 CST 2011
|
||||
Significant internal changes:
|
||||
Tested and modified to work with Arduino 1.0.
|
||||
|
||||
Modified to use the new() operator and symbolic links instead of creating a pre-populated
|
||||
PCintPins[]. Renamed some variables to simplify or make their meaning more obvious (IMHO anyway).
|
||||
Modified the PCintPort::PCint() code (ie, the interrupt code) to loop over a linked-list. For
|
||||
those who love arrays, I have left some code in there that should work to loop over an array
|
||||
instead. But it is commented out in the release version.
|
||||
|
||||
For Arduino versions prior to 1.0: The new() operator requires the cppfix.h library, which is
|
||||
included with this package. For Arduino 1.0 and above: new.h comes with the distribution, and
|
||||
that is #included.
|
||||
|
||||
Version 1.2 Sat Dec 3 Sat Dec 3 09:15:52 CST 2011
|
||||
Modified Thu Sep 8 07:33:17 CDT 2011 by GreyGnome. Fixes a bug with the initial port
|
||||
value. Now it sets the initial value to be the state of the port at the time of
|
||||
attachInterrupt(). The line is port.PCintLast=port.portInputReg; in attachInterrupt().
|
||||
See GreyGnome comment, below.
|
||||
|
||||
Added the "arduinoPin" variable, so the user's function will know exactly which pin on
|
||||
the Arduino was triggered.
|
||||
|
||||
Version 1.1 Sat Dec 3 00:06:03 CST 2011
|
||||
...updated to fix the "delPin" function as per "pekka"'s bug report. Thanks!
|
||||
|
||||
---- ^^^ VERSIONS ^^^ (NOTE TO SELF: Update the PCINT_VERSION define, below) -------------
|
||||
|
||||
See google code project for latest, bugs and info http://code.google.com/p/arduino-pinchangeint/
|
||||
For more information Refer to avr-gcc header files, arduino source and atmega datasheet.
|
||||
|
||||
This library was inspired by and derived from "johnboiles" (it seems)
|
||||
PCInt Arduino Playground example here: http://www.arduino.cc/playground/Main/PcInt
|
||||
If you are the original author, please let us know at the google code page
|
||||
|
||||
It provides an extension to the interrupt support for arduino by
|
||||
adding pin change interrupts, giving a way for users to have
|
||||
interrupts drive off of any pin.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
NOTES ================================================================================
|
||||
|
||||
Serial.print()----------------
|
||||
|
||||
Serial.print() does not work well inside interrupts. This is because it uses interrupts,
|
||||
and while you are in an interrupt, interrupts are (by default) turned off.
|
||||
Serial is declared in /usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.h .
|
||||
In the write() method in the .cpp file, for example it says:
|
||||
...
|
||||
// If the output buffer is full, there's nothing for it other than to
|
||||
// wait for the interrupt handler to empty it a bit
|
||||
// ???: return 0 here instead?
|
||||
while (i == _tx_buffer->tail)
|
||||
;
|
||||
...
|
||||
And the ISR is further down in that file (this for the ATmega328 I believe):
|
||||
ISR(USART_RX_vect)
|
||||
...
|
||||
|
||||
If a user wants to try to use Serial.print() inside an ISR, I believe it's possible
|
||||
(by turning on interrupts inside the interrupt)...
|
||||
but it would require them to be aware of any possible contention between the interrupts,
|
||||
and the print ISRs.
|
||||
|
||||
|
||||
Software Serial----------
|
||||
Also, the SoftwareSerial library defines ISRs for Pin Change Interrupt ports:
|
||||
|
||||
ISR(PCINT0_vect)
|
||||
{
|
||||
SoftwareSerial::handle_interrupt();
|
||||
}
|
||||
|
||||
...It defines the interrupt on all ports, whether it's using them or not
|
||||
(the library cannot know ahead of time if the user will be using a set of pins
|
||||
or not).
|
||||
|
||||
To ensure compatibility with the SoftwareSerial library, the user should comment
|
||||
out the ports that they are NOT using with the SoftwareSerial library, in
|
||||
/usr/share/arduino/libraries/SoftwareSerial/SoftwareSerial.cpp
|
||||
and comment out the ports that they ARE using with this library in PinChangeInt.h
|
||||
70
libraries/PinChangeInt/Technical_Notes
Normal file
70
libraries/PinChangeInt/Technical_Notes
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
The purpose of this library is to give the programmer the ability to add interrupts
|
||||
with the easy of attachInterrupt, which looks like this:
|
||||
attachInterrupt(interrupt, &function, MODE)
|
||||
...the interrupt is a number which gets translated to the proper pin on the Arduino. For example,
|
||||
Board int.0 int.1 int.2 int.3 int.4 int.5
|
||||
Uno, Ethernet 2 3
|
||||
Mega2560 2 3 21 20 19 18
|
||||
Leonardo 3 2 0 1 7
|
||||
Due (doesn't use interrupt numbers, it uses the pin numbers directly)
|
||||
|
||||
The MODE is LOW, CHANGE, RISING, or FALLING. On the Due board, you also have HIGH.
|
||||
|
||||
|
||||
The PinChangeInterrupt library does not work on the Due; it is not necessary. It is somewhat easier
|
||||
to use than attachInterrupt() because you don't have to translate from an "Interrupt number" to a
|
||||
pin number- you simply give it the pin that you want to Interrupt on:
|
||||
|
||||
PCintPort::attachInterrupt(interrupt, &function, MODE)
|
||||
|
||||
The MODE is LOW, CHANGE, RISING, or FALLING. On the Due board, you also have HIGH.
|
||||
|
||||
To have an Interrupt:
|
||||
|
||||
Global Interrupt flag must be enabled.
|
||||
Set the I-bit in SREG.
|
||||
In PCICR: bit 2 == PCIE2: set, enable pins PCINT[23:16], enable individual by PCMSK2
|
||||
bit 1 == PCIE1: set, enable PCINT[14:8], enable individual by PCMSK1
|
||||
bit 0 == PCIE0: set, enable PCINT[7:0], enable individual by PCMSK0
|
||||
|
||||
Pin Change Interrupts and Other Libraries ============================================================
|
||||
|
||||
Serial.print()----------------
|
||||
|
||||
Serial.print() does not work well inside interrupts. This is because it uses interrupts,
|
||||
and while you are in an interrupt, interrupts are (by default) turned off.
|
||||
Serial is declared in /usr/share/arduino/hardware/arduino/cores/arduino/HardwareSerial.h .
|
||||
In the write() method in the .cpp file, for example it says:
|
||||
...
|
||||
// If the output buffer is full, there's nothing for it other than to
|
||||
// wait for the interrupt handler to empty it a bit
|
||||
// ???: return 0 here instead?
|
||||
while (i == _tx_buffer->tail)
|
||||
;
|
||||
...
|
||||
And the ISR is further down in that file (this for the ATmega328 I believe):
|
||||
ISR(USART_RX_vect)
|
||||
...
|
||||
|
||||
If a user wants to try to use Serial.print() inside an ISR, I believe it's possible
|
||||
(by turning on interrupts inside the interrupt)...
|
||||
but it would require them to be aware of any possible contention between the interrupts,
|
||||
and the print ISRs.
|
||||
|
||||
|
||||
Software Serial----------
|
||||
The SoftwareSerial library defines ISRs for Pin Change Interrupt ports:
|
||||
|
||||
ISR(PCINT0_vect)
|
||||
{
|
||||
SoftwareSerial::handle_interrupt();
|
||||
}
|
||||
|
||||
...It defines the interrupt on all ports, whether it's using them or not
|
||||
(the library cannot know ahead of time if the user will be using a set of pins
|
||||
or not).
|
||||
|
||||
To ensure compatibility with the SoftwareSerial library, the user should comment
|
||||
out the ports that they are NOT using with the SoftwareSerial library, in
|
||||
/usr/share/arduino/libraries/SoftwareSerial/SoftwareSerial.cpp
|
||||
and comment out the ports that they ARE using with this library in PinChangeInt.h
|
||||
10
libraries/PinChangeInt/keywords.txt
Normal file
10
libraries/PinChangeInt/keywords.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# LITERAL1 specifies constants
|
||||
|
||||
# KEYWORD1 specifies datatypes and C/C++ keywords
|
||||
pinState KEYWORD1 PinState
|
||||
arduinoPin KEYWORD1 ArduinoPin
|
||||
PCintPort KEYWORD1 PCInterruptPort
|
||||
|
||||
# KEYWORD2 specifies methods and functions
|
||||
attachInterrupt KEYWORD2 AttachInterrupt
|
||||
detachInterrupt KEYWORD2 DetachInterrupt
|
||||
Loading…
Add table
Add a link
Reference in a new issue