Código fuente de ejemplo para un Arduino basado en registrador de datos de tiempo transcurrido el evento. Muestra interrupciones, registro asincrónico y contacto de rebotan. Destinados a un interruptor de posición de rueda, registra tiempo en el que se dedica a interruptor.
Estamos utilizando un interruptor reed que rebota cuando tanto cuando dis participan. Esto produce múltiples interrupciones. Ring buffer entrada comprueba si el período de evento es mucho más corto que el tiempo previamente registrado el evento. Si es así, gatillo corto se rechaza como rebote de contacto. Eventos rechazados se almacenan, y si muchos rechazos se presentan en una fila, todos registran, suponiendo que algo sucedió y pueden ser eventos significativos. La motivación es que es mejor conectarse unos rebotes que to te pierdas un evento para esta aplicación. Los datos pueden limpiar más en el proceso de post, pero no queremos desorden nuestros registros con todos los eventos del rebote de contacto.
/* $URL: svn+ssh://aaron $ $Id: vLogger.ino 62 2012-06-03 20:11:13Z aaron $ Log the times when a wheel position sensor triggers, as an indirect method of logging time and distance, which can be used to estimate velocity and acceleration in a coast-down wind resistance experiment. User flips switch to record to a ring buffer. Main loop prints ring buffer contents to serial port, asynch. Each time the record operation cycles, the time is reset to start at zero. Sensor switch must be on pin 2, since this pin uses standard external interrupt 0 */ #define PIN_RECORD 4 // record on/off switch #define PIN_LED_RECORD 8 // on when recording #define PIN_LED_SENSOR 13 // toggles as sensor turns #define BUF_LEN 256 // samples in data ring buffer #define MAX_SHORT 10 // max "short" events before assuming they are NOT contact bounce typedef long DATATYPE; #include // sprintf // Diagnostic output logger. Call log from ISR, print outside ISR #define MAX_LOG_LEN 40 #define LOG_BUF_LEN 8 class Logger { protected: volatile int nIn; int nOut; char buf[LOG_BUF_LEN][MAX_LOG_LEN]; public: char msgBuf[MAX_LOG_LEN]; Logger() { nIn=nOut=0; } void print() { if (nOut >= nIn) return; int i = nOut % LOG_BUF_LEN; nOut++; Serial.println(buf[i]);Serial.flush(); } void log(const char *msg) { int i,k; k = nIn % LOG_BUF_LEN; for (i=0; (msg[i]!=0) && (i < MAX_LOG_LEN-1); i++) buf[k][i]=msg[i]; buf[k][i]=0; nIn++; } void log() { log(msgBuf); } // for using provided msgBuf } Log; class RingBuffer { protected: volatile int nIn; int nOut; volatile DATATYPE buf[BUF_LEN]; public: void reset() { nIn=nOut=0; } RingBuffer() { reset(); } volatile void push(DATATYPE x) { if (nOut <= nIn - BUF_LEN) { sprintf(Log.msgBuf,"RingBuffer Overflow %d",x);Log.log(); //Serial.println("RingBuffer Overflow ");Serial.println(x);//Serial.flush(); return; } int i = nIn % BUF_LEN; buf[i]=x; nIn++; } inline bool empty() const { return(nOut >= nIn); } DATATYPE pop() { if (nOut >= nIn) return(0xffff); int i = nOut % BUF_LEN; nOut++; return(buf[i]); } DATATYPE peek() // peek at last OUTPUT { int i = nOut % BUF_LEN; return(buf[i]); } DATATYPE peek(const int nBack) // peak at indicated prev INPUT, 0 is most recent { int i=nIn-1-nBack; if (i < 0) return 0; return(buf[i]); } inline int nPush() const { return(nIn); } inline int nPop() const { return(nOut);} inline int depth() const { return(nIn-nOut); } inline int maxDepth() const { return(BUF_LEN); } }; class TimeEventRingBuffer : public RingBuffer { protected: unsigned long t0; volatile int nShort; volatile DATATYPE shortBuf[MAX_SHORT]; public: void reset() { setZero(); nShort=0; RingBuffer::reset(); } TimeEventRingBuffer() { nShort=t0=0; } void push() { unsigned long tt = millis(); DATATYPE tNow = (DATATYPE)(tt-t0); // check for contact bounce DATATYPE t1 = peek(0); // prev recorded input DATATYPE t2 = peek(1); if ( tNow-t1 < 0.1 * (t1-t2) ) { // short trigger, likely contact bounce if (nShort < MAX_SHORT) { shortBuf[nShort++]=tNow; return; } // Too many short triggers in a row, dump them for (int i=0; i < MAX_SHORT; i++) RingBuffer::push(shortBuf[i]); } // record the time of this event RingBuffer::push(tNow); nShort=0; // this event was good. reset short-trigger counter } void setZero() { t0 = millis(); } }; TimeEventRingBuffer Data; bool RecordingOn; // ISR when wheel sensor event is detected void wheelSense() { if (RecordingOn) { Data.push(); } digitalWrite(PIN_LED_SENSOR,digitalRead(PIN_LED_SENSOR)?LOW:HIGH); } void setup() { pinMode(2,INPUT); // hard-coded to pin 2, since using standard ext. interrupt 0 pinMode(PIN_RECORD,INPUT); digitalWrite(PIN_RECORD,HIGH); // enable pull-up resistor digitalWrite(2,HIGH); pinMode(PIN_LED_RECORD, OUTPUT); pinMode(PIN_LED_SENSOR, OUTPUT); digitalWrite(PIN_LED_RECORD,HIGH); digitalWrite(PIN_LED_SENSOR,HIGH); RecordingOn = true;//false; attachInterrupt(0,wheelSense,RISING); // INT0 is on pin 2 (INT1 on pin 3) Serial.begin(9600); // may want a different serial monitor, which can be faster } void loop() { Log.print(); // check if any log messages need to be printed if (!Data.empty()) { Serial.print(Data.nPop()); Serial.print("\t"); Serial.println(Data.pop()); Serial.flush(); } // check if recording is currently enabled bool rec = (digitalRead(PIN_RECORD)==LOW)?true:false; //rec=true;// always record for testing if (RecordingOn) { if (!rec) { // turn recording OFF digitalWrite(PIN_LED_RECORD,LOW); RecordingOn = false; delay(2); // avoid contact bounce } } else { // recording is off if (rec) { // transition from off to on, start recording digitalWrite(PIN_LED_RECORD,HIGH); Data.setZero(); if (Data.empty()) Data.reset(); RecordingOn = true; delay(2); // avoid contact bounce } } }
Aquí es un script LINUX conveniente a mostrar y registrar los datos de una conexión en serie. Este código se establece para una conexión de puerto USB/serie, pero si cambia el dispositivo busca algo como /dev/rfcomm0 puede configurarse para trabajar en un dispositivo de Bluetooth/SPP.
#!/usr/bin/perl -w # Logs output from an arduino at typical 9600 8-n-1 # assume most recently created tty is the Arduino. # for most users, this should usually work $devName = `ls -t /dev/tty* | head -1`; chomp($devName); print "Listening on $devName\n"; # set up port for typical Arduino (SerialMonitor-like) settings system("stty -F $devName cs8 9600 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts"); $logFileName = ($#ARGV>=0) ? $ARGV[0] : "/tmp/serial.log"; print "Logging to $logFileName\n"; $pid = fork(); if ($pid==0) { # this is the child. local $cmd = "tail -f $devName > $logFileName"; # for some reason, the above did not work on a netbook, but this did: #local $cmd = "cat $devName > $logFileName"; print "$cmd\n"; exec($cmd); } else { # this is the parent, display log. # hopefully when this is ^C'ed or killed, it will kill child too sleep 2; local $cmd = "tail -f $logFileName"; print "$cmd\n"; exec($cmd); }