The following code accompanies the O'Reilly Biocoder article, A Simple Data Acquisition and Plotting System for Low Cost Experimentation. The source code is a Processing.org sketch.
// Source code for Simple Chart Recorder Application example, // UBW Microcontroller Analog Data Acquisition example ; // Runs in Processing.Org environment. // // Copyright 2013 Jonathan Cline jcline@ieee.org All Rights Reserved // // jcline@ieee.org 2009-03 Initial version // jcline@ieee.org 2013-06-10 Branch for Enhancements. Used with // UV Illuminator/Detector from Amersham Biosciences. // jcline@ieee.org 2013-06-13 Add averaging line with data points. // Compatible with UBW Firmware version "D" // Note, a useful exercise would be to rewrite this application // in Python and Qt. Another useful exercise: write timestamped data // as a .csv file. // About Processing: // Processing is an application programming system developed // originally for artists or non-computer scientists to create // digital interactive artwork and to control mechatronic // animation, without spending excessive effort to learn // programming skills (refer to Processing.org). Processing // is a fast way to develop applications which display graphical // results. The programming language is reduced and simplified // and is well documented with a large archive of examples. The // application system includes a scratch pad to rapidly prototype // programs as they are written. Processing uses Java to allow // software applications to either run on a computer as a native // application, or as a web application within a web browser. // Software applications are immediately compatible with different // operating systems (Apple, Microsoft, GNU/Linux, Unix). // Processing is also used as the basis for the Arduino // programming system; however, the UBW is a better fit to most // requirements so using Arduino hardware is not recommended (see // the UBW web site). // The USB microcontroller communication is a simple serial device import processing.serial.*; Serial ubw; int loops = 0; int[] xvals; void setup() { String ubwVersion; boolean found; float tdelay; found = false; size(1000,500); background(0); // black // Frame rate sets draw rate. Should correspond to UBW's sample timer period. frameRate(10); stroke(255); // white xvals = new int[width]; try { println(Serial.list()); // Important: Change the index [2] below to correspond to the serial // device in the device list of the computer. On OS/X and Linux systems, // this is easily done; on Microsoft systems, it is more difficult. // Serial rate doesnt matter (it's USB), so it is listed as 9600 below. ubw = new Serial(this, Serial.list()[2], 9600); tdelay=millis() + 5000; // Read firmware version from connected UBW Microcontroller; jcline 2009-03 for (int i=0; millis() < tdelay ; i++) { // Get+Verify UBW version string, print to console ubw.write("v\n"); delay(100); ubwVersion = ubw.readStringUntil('\n'); if (ubwVersion != null) { if (ubwVersion.startsWith("UBW", 0)) { println("Found UBW attached to USB:\n"); println(ubwVersion); found = true; break; } } } } catch (Exception e) { println("device access error\n"); } if (found != true) { println("No UBW found, exit\n"); exit(); } else { ubw.write("C,255,255,255,1\n"); ubw.write("CU,1,0\n"); ubw.write("T,200,1\n"); // set timered update in millisec, A=1 ubw.clear(); // flush } } // UBW's firmware uses %4u output for values of analog data // Convert "0023" string to Int 23 Integer string4uToInt(String s) { char a[] = s.toCharArray(); Integer i = 0; Integer v; // char array into positional math based on ASCII value v = byte(a[0]) - 48; i += v * 1000; v = byte(a[1]) - 48; i += v * 100; v = byte(a[2]) - 48; i += v * 10; v = byte(a[3]) - 48; i += v; return (i); } // Read analog data depending on framerate & draw graphical level indicator void draw() { String cmd; String data; Integer val; loops++; // Important: Stop the plot after beaker is dry (20000 iterations) if (loops > 20000) { noLoop(); ubw.write("T,0,1\n"); // Turn off timered updates println("done\n"); ubw.stop(); } data = ubw.readStringUntil('\n'); // read timered update if (data == null) { return; // no periodic data yet } if (data.startsWith("A,", 0) == false) { println("bad input: "+data+"\n"); return; } val = string4uToInt(data.substring(2, data.length())); println(val); val = val/5; for(int i=1; i<width; i++) { xvals[i-1] = xvals[i]; } stroke(255, 0, 0); xvals[width-1] = height - val; background(248, 248, 248); for (int i=4, sum = 0, sumLast = 0; i<width; i++) { //point(i, xvals[i]); // See processing.org's example "mouse signals" //point(i, xvals[i]-1); // Calculate Moving average from raw data history sum = xvals[i]; sum += xvals[i-1]; sum += xvals[i-2]; sum += xvals[i-3]; sum += xvals[i-4]; sum /= 5; // If a bold connecting line of raw data is desired, include the below. //line(i, xvals[i], i, xvals[(i-1)]); point(i, xvals[i]); line(i, sum, i, sumLast); line(i, sum+1, i, sumLast+1); sumLast = sum; } } // End of source |