As a brief experiment into rapid logging of sensor data and equally fast transmission of that data to a PC I have written a couple sketches for the Arduino and Processing to do just this. The goal is to read from an analog sensor on the Arduino (which will eventually consist of some sort of biometric sensor like a PPG sensor) at a rate of close to 1kHz, log the data to a data logger, and transmit the data wirelessly to a computer running Processing. The simple Arduino sketch attempts to use its built-in timers to read the sensor at 1kHz as well as log and transmit the data.
/*
This example shows how to read and write data to and from an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 10
*/
#include <SD.h>
#define CS 10
#define BUTTON 15
File myFile;
int PPG = 0;
void setup()
{
Serial.begin(57600);
Serial.println("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(CS, OUTPUT);
analogReference(EXTERNAL);
// if (!SD.begin(CS)) {
// Serial.println("initialization failed!");
// return;
// }
// Serial.println("initialization done.");
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
//myFile = SD.open("logTest.txt", FILE_WRITE);
int analogVal = 0;
// if the file opened okay, write to it:
//if (myFile) {
//Serial.println("Writing to logTest.txt...");
//**********//
long period = micros();
long startTime = millis();
long number = 0;
// A LED on pin 2 indicates when the system is running
pinMode(2, OUTPUT);
digitalWrite(2, HIGH);
Serial.println("$$$");
// While the button is not pressed (1) read the sensor
while(digitalRead(BUTTON) == 1) {
int i = 0;
while(i < 1000) {
if((micros() - period) >= 830) {
analogVal = analogRead(PPG);
period = micros();
//myFile.println(analogVal);
Serial.println(number);
i++;
number++;
}
}
}
long endTime = millis();
digitalWrite(2, LOW);
//**********//
//myFile.close(); // close the file:
//Serial.println("\ndone writing to logTest.txt");
Serial.print("It took ");
Serial.print(endTime - startTime);
Serial.print(" mSec to write ");
Serial.print(number);
Serial.println(" integers to the SD card%");
//} else {
// if the file didn't open, print an error:
// Serial.println("error opening logTest.txt");
//}
}
void loop()
{
// nothing happens after setup
}
The Processing sketch is written to use the serial library to connect to an Xbee through a virtual serial port. It looks for a transmission starting character, in the Arduino sketch this is “$$$” and then logs all the remaining data to a file named “log.txt” until it sees the end of transmission character which has been arbitrary selected as “%” for this test.
import processing.serial.*;
Serial myPort;
PrintWriter out_f;
void setup() {
size(200, 200);
println(Serial.list());
String portName = Serial.list()[1];
myPort = new Serial(this, portName, 57600);
out_f = createWriter("log.txt");
}
void draw()
{
while ( myPort.available() > 0) { // If data is available,
char c = char(myPort.read());
if (c == '\r' || c == '$') {
int h = hour();
int m = minute();
int s = second();
int mill = millis();
println("\t"+h+":"+m+":"+s+"."+mill%1000);
out_f.print("\t"+h+":"+m+":"+s+"."+mill%1000);
out_f.flush();
}
else if(c == '%') {
out_f.close();
}
else {
print(c);
out_f.print(c);
out_f.flush();
}
}
}
In addition to logging the transmitted sensor data, the Processing sketch also adds a time-stamp to the data as well which consists of the hour, minute, second, and thousands of a second when each data-point was received. Each character is written to the file separately and the time-stamp is only added when a new data-point is detected (as a newline character ‘\r’).