In the development of several projects we had the need of an easy, versatile and low cost data acquisition system for monitoring important variables like pressure, temperature and other meters.
For this reason we developed a very simple data acquisition system based on Arduino platform and Processing programming language, naming it liber 1.
Liber 1 is based on opensource hardware and software, and was developed in an interpreted language for keeping it available for different platforms (linux, mac os and even windows).
The two basic concepts are rather simple:
- having a minimum control on the instantaneous values , which are written into a simple window, for immediate intervention
- storing the data into a text file on a pc.
The code is divided into 2 parts, one (the firmware) has to be uploaded on the arduino microcontroller and is responsible for the channels reading and averaging the data into a certain time period, while the other (the software) runs on a pc connected to the Arduino card and is responsible for the collection, conversion and storage of the data.
Screenshot - click on the image for larger view
A txt file gets created with the time and the data collected, that can be easily imported in your favourite data processing software (spreadseet:libreoffice, openoffice, excel. Matlab, Scilab, Octave or similar).
Everything, including the font to be used by processing, is included in the downloadable file here.
The code is also included in the following. In case this is going to be used (and not the link above), remember to create the font file (named "mono.vlw") with the processing tool menu.
The firmware (to be uploaded on the Arduino board):
/*
Liber 1
Liber 1 is an easy set up for the Arduino Mega board fro realizing
a cheap Data Acquisition.
The circuit:
Attach all the sensor with Tension signals to the pins of the board.
The ones that are not used would better be ground connected.
*/
void setup() {
// initialize the serial communication:
Serial.begin(9600);
}
void loop() {
Serial.println('P');
int nMedie=10; //numeri da mediare ogni lettura
//Setting empty array for getting data
int canale[15]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//starting average
for (int j=0; j <= nMedie; j++){
for (int i=0; i <= 15; i++){
canale[i] = analogRead(i) + canale[i];
}
}
for (int j=0; j <= nMedie; j++){
canale[j]=canale[j]/nMedie;
// send the value of analog input 0:
Serial.println(canale[j]);
}
// wait a bit for the analog-to-digital converter
// to stabilize after the last reading:
delay(1000);
}
The Software (to be executed in processing sw):
//************************************************************************
// Graphing sketch
// This program takes ASCII-encoded strings
// from the serial port at 9600 baud and graphs them. It expects values in the
// range 0 to 1023, followed by a newline, or newline and carriage return
// Calling the Processing serial library
import processing.serial.*;
/*****************************************Definitions***************************************/
//************************************************
//Here are the values that have to be set up by the user
//************************************************
int nSerial=0; //Serial Port number
int nCanali = 8; //Number of channels
float nPres=7; //Pressure probe channel, if absent, set to 30
float nFumi=6; //Flow gases Temp probe, if absent, set to 30
float rP=.215; //Known Resistance on the Pressure channel
float rNotaNTC=10000; //Known resistance for the NTC circuit, in Ohm
float rNotaPT100=99.5; //Known resistance for the Pt100 circuit, in Ohm
float aliment=5; //Voltage for feeding the Temp probe circuits
//************************************************
//End of the settings part
//************************************************
/*********Other Variables************/
float rMis=0; //Measured resistance at the channel
float tensMis=0; //Measured voltage
Serial myPort; // The serial port
int xPos = 1; // horizontal position of the graphics
int count = 0;
int scrivi = 0;
float[] data = new float[nCanali];
PrintWriter output; //Output filename
float dataOut;
/*********End of Other Variables************/
/**************************************End of Definitions************************************/
/*********Setup function, happens only once*********/
void setup () {
// set the window size:
size(300, nCanali*25+35);
// List all the available serial ports
println(Serial.list());
// Open whatever port is the one you're using.
myPort = new Serial(this, Serial.list()[nSerial], 9600);
// don't generate a serialEvent() unless you get a newline character:
myPort.bufferUntil('\n');
// set inital background:
background(255);
//Output Filename
output = createWriter("data.txt");
}
/*********End of Setup**********/
void draw () {
// everything happens in the serialEvent()
}
void serialEvent (Serial myPort) {
// get the ASCII string:
String inString = myPort.readStringUntil('\n');
if (inString != null) {
// trim off any whitespace:
inString = trim(inString);
if(inString.equals("P")){
count=0;
if (second()==10||second()==40)
scrivi=1; //scrivi is a flag activated at the tenth second of each minute for writing to the ouput file
if (scrivi==1){
output.println("");
output.print(day()+""+TAB+""+hour()+""+TAB+""+minute()+""+TAB);
}
PFont font;
font = loadFont("mono.vlw");
textFont(font);
fill(0);
text("Push <b> to stop",20,nCanali*25+25);
fill(255);
}
else {
if(count<nCanali) {
//Calibrazione canali
/*Trovata curva di calibrazione per NTC con curveexpert
Harris Model: y=1/(a+bx^c)
Coefficient Data:
a= -6.25116347002E-003
b= 7.44960639190E-003
c= 2.75523042335E-002
*/
tensMis=float(inString)*5/1024; //Tens rilevata dal canale
if (count==nFumi) { //caratteristica del canale della pt100
//rMis=tensMis*rNotaPT100/(aliment-float(inString)*5/1024);
dataOut=263.05*tensMis-675.68;
}
else if (count==nPres) { //caratteristica del canale del sensore di pressione
dataOut=-63.047+15.11*(tensMis/rP);
}
else { //si suppongono i rimanenti canali aventi caratteristica NTC
rMis=tensMis*rNotaNTC/(aliment-float(inString)*5/1024);
dataOut=1/(-6.25116347002E-003+7.44960639190E-003*pow(rMis,
2.75523042335E-002))-273;
}
//inizitialize the font
PFont font;
font = loadFont("mono.vlw");
textFont(font);
//draw a rectangle and write the value
rect(15, 25*count, 240,25 );
fill(0);
String s="Can "+(count+1)+" - "+dataOut;
text(s, 20, 22+25*count);
fill(255);
count++;
//data[count]=float(inString);
if (scrivi==1){
output.print(dataOut+""+TAB);
if (count==nCanali)
scrivi=0;
}
}
}
}
}
//************************************************************************
//Function for terminating and storing the data
void keyPressed() {
if (key == 'b' || key == 'B') {
//output.flush(); // Write the remaining data
output.close(); // Finish the file
exit(); // Stop the program
}
}