Simplify gateway code (handles interrupts internally) and remove external dependencies. Ledmode is now always "enabled".

Remove unused libraries.
Add default CS/CE pin to Config.h
Add new variebles for voltage and current.
Add new internal command sent to controller when gateway is ready and online
This commit is contained in:
Henrik Ekblad
2014-08-21 09:59:30 +02:00
parent 8a6b092db8
commit dfcd3d44d3
21 changed files with 52 additions and 2496 deletions
@@ -1,272 +0,0 @@
/*
ByteBuffer.cpp - 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.
Also made the capacity, position, length, and fillError variables volatile, for safe use by interrupts.
*/
#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;
}
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(char *in){
uint8_t count=0;
char *inString;
inString=in;
uint8_t oldSREG = SREG; cli();
while(length <= capacity){
if (length == capacity) {
fillError=true;
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;
}
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;
}
//
// 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;
}
@@ -1,104 +0,0 @@
/*
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
@@ -1,21 +0,0 @@
#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
@@ -1,77 +0,0 @@
// PinChangeIntExample, version 1.1 Sun Jan 15 06:24:19 CST 2012
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
//-------- 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.
//#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
// 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 ------------------------------------------------------
#include <PinChangeInt.h>
// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions.
// All interrupts are serviced immediately, but one of the pins (pin 4) will show you immediately
// on the Terminal. The other function connected to 2 pins sets an array member that is queried in loop().
// You can then query the array at your leisure.
// This makes loop timing non-critical.
// Add more Pins at your leisure.
// For the Analog Input pins used as digital input pins, and you can use 14, 15, 16, etc.
// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's
// for the Analog Input pins and will properly recognize e.g., pinMode(A0, INPUT);
#define PIN1 2
#define PIN2 3
#define PIN3 4
uint8_t latest_interrupted_pin;
uint8_t interrupt_count[20]={0}; // 20 possible arduino pins
void quicfunc() {
latest_interrupted_pin=PCintPort::arduinoPin;
interrupt_count[latest_interrupted_pin]++;
};
// You can assign any number of functions to any number of pins.
// How cool is that?
void pin3func() {
Serial.print("Pin "); Serial.print(PIN3, DEC); Serial.println("!");
}
void setup() {
pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH);
PCintPort::attachInterrupt(PIN1, &quicfunc, FALLING); // add more attachInterrupt code as required
pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH);
PCintPort::attachInterrupt(PIN2, &quicfunc, FALLING);
pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH);
PCintPort::attachInterrupt(PIN3, &pin3func, CHANGE);
Serial.begin(115200);
Serial.println("---------------------------------------");
}
uint8_t i;
void loop() {
uint8_t count;
Serial.print(".");
delay(1000);
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);
}
}
}
@@ -1,265 +0,0 @@
// 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);
}
@@ -1,344 +0,0 @@
// PinChangeIntTest
// version 1.0 Wed Feb 15 07:25:09 CST 2012
// Version 1.1 Fri Jun 22 19:10:50 CDT 2012 minor tweaks to eliminate compiler warnings. Also, there were bugfixes in ByteBuffer.
// I had some "cli()" without "sei()" in there.
// 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.
//-------- 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>
// 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
// All pins send interrupts. Arduino pins 2 and A4 (tPIN1,6) interrupt on FALLING.
// Arduino pins 3 and 12 (tPIN2,4) interrupt on RISING.
// Arduino pins 11 and A3 (tPIN5) interrupts on CHANGE.
// quicfunc0 is attached to Arduino pins 2, 3, 11, and 12 (tPIN1-4)
// quicfunc1 is attached to Arduino pin A3 (tPIN5)
// quicfunc2 is attached to Arduino pin A4 (tPIN6).
// 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));
// HOW IT WORKS
// 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 *) "\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((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 *) "\n");
};
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 *) ")\n");
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 *) "\n");
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");
delay(500);
for (i=0; i < 7; i++) {
pinMode(pins[i], INPUT); digitalWrite(pins[i], HIGH);
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:
PCintPort::attachInterrupt(pins[i], &quicfunc2, FALLING);
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();
}
}
@@ -1,275 +0,0 @@
//#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();
}
}