Added some more projects and libraries.

This commit is contained in:
Johannes Findeisen 2022-11-27 16:14:05 +01:00
commit 1e1459fa50
94 changed files with 11904 additions and 0 deletions

View 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 *)&in;
putInFront(pointer[0]);
putInFront(pointer[1]);
}
void ByteBuffer::putInt(int in){
byte *pointer = (byte *)&in;
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 *)&in;
putInFront(pointer[0]);
putInFront(pointer[1]);
putInFront(pointer[2]);
putInFront(pointer[3]);
}
void ByteBuffer::putLong(long in){
byte *pointer = (byte *)&in;
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 *)&in;
putInFront(pointer[0]);
putInFront(pointer[1]);
putInFront(pointer[2]);
putInFront(pointer[3]);
}
void ByteBuffer::putFloat(float in){
byte *pointer = (byte *)&in;
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;
}

View 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

View 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

View file

@ -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;
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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.");
}