Arduino graph software

Arduino graph using Processing

Update: Here is a link to my source code. Some very simple examples, without the buttons, saving data etc. When I get time I’ll start a new post explaining it all properly.

This code is for those that want to draw fancy graphs with processing, and use the fasted method to communicate with the Arduino.

Arduino side:

  • Serially sending arrays for different graphs from the chip
       void PlottArray(int Cmd,int Array1[],int Array2[])
           Cmd  -> which graph is this data for?
       Array1[] -> The real time array. Measured micro-seconds
       Array2[] -> Array of measured voltages
  • Serially sending updates for different graphs from the chip

Processing side:

  • A graph class that makes graphing simple with Processing. Drawing bar graphs, smooth  line graphs etc can be quite a mission..

You just have to declare a graph object:  Graph VoltageAndCurrent;

        VoltageAndCurrent.xMax=int(max(timeArray1));
        VoltageAndCurrent.yMax=int(max(voltageArray));

        VoltageAndCurrent.DrawAxis();
        VoltageAndCurrent.smoothLine(timeArray1,voltageArray,currentArray);
  • Saving and loading data to a text file
  • Efficient serial link to the Arduino (Error checking etc)

Arduino + Processing : Analogue bar graph

So far Processing is the easiest language I’ve used to make win apps. The example code that comes with the compiler (similar to the sample code that comes with the Arduino) lets you get away without doing tutorials, if you know the basics of C++.
.
Here is a pic of the bar graph I made to display the Arduino’s analogue inputs.
.
Arduino analogue graph
An app made using Processing, to display the Arduino’s analogue inputs A0-A5

.

If you copy, paste and run the code you’ll notice the backgound will be plain. I’ve commented out the line where it loads the background image.  The title, axis labels, subdivisions and all variables that you con feel free to play with have been put at the top of the code.Copy the code below into Processing and edit the highlighted code. Whatever com port is used must be entered into the line I’ve highlighted yellow. For some reason I had to enter a 2 to tell it I’m using com port 4, and a 1 for com port 3.

zipped code (1MB – Arduino & Processing)

Processing Code

// Feel Free to edit these variables ///////////////////////////
String  xLabel = "Analogue Inputs";
String  yLabel = "Voltage (V)";
String  Heading = "The Graph Sketch";
String  URL = "01/02/2010";
float Vcc = 5.0;    // the measured voltage of your usb
int NumOfVertDivisions=5;      // dark gray
int NumOfVertSubDivisions=10;  // light gray

int NumOfBars=6;    // you can choose the number of bars, but it can cause issues
                    // since you should change what the arduino sends

// if these are changed, background image has problems
// a plain background solves the problem
int ScreenWidth = 600, ScreenHeight=400;
/////////////////////////////////////////////////////////

//  Serial port stuff ///////////////////////
import processing.serial.*;
Serial myPort;
boolean firstContact = false;
int[] serialInArray = new int[6];
int serialCount = 0;
///////////////////////////////////////////////

int LeftMargin=100;
int RightMArgin=80;
int TextGap=50;
int GraphYposition=80;
float BarPercent = 0.4;

int value;

PFont font;
PImage bg;

int temp;
float yRatio = 0.58;
int BarGap, BarWidth, DivisounsWidth;
int[] bars = new int[NumOfBars];

void setup(){

 // bg = loadImage("BG.jpg"); 

  /// NB SETTINGS ////////////////////////////////////////////////////////
  myPort = new Serial(this, Serial.list()[1], 9600);
  ////////////////////////////////////////////////////////////////////////

  DivisounsWidth = (ScreenWidth-LeftMargin-RightMArgin)/(NumOfBars);
  BarWidth = int(BarPercent*float(DivisounsWidth));
  BarGap = DivisounsWidth - BarWidth;

  size(ScreenWidth,ScreenHeight);
  font = createFont("Arial",12);

  textAlign(CENTER);
  textFont(font);
}

void draw(){

//  background(bg);     // My one used a background image, I've
  background(250);      // commented it out and put a plain colour 

  //  Headings();           // Displays bar width, Bar gap or any variable.
  Axis();
  Labels();
  PrintBars();
}

// Send Recieve data //
void serialEvent(Serial myPort) {

  // read a byte from the serial port:
  int inByte = myPort.read();

  if (firstContact == false) {
    if (inByte == 'A') {
      myPort.clear();          // clear the serial port buffer
      firstContact = true;     // you've had first contact from the microcontroller
      myPort.write('A');       // ask for more
    }
  }
  else {
    // Add the latest byte from the serial port to array:
    serialInArray[serialCount] = inByte;
    serialCount++;

    // If we have 6 bytes:
    if (serialCount > 5 ) {

for (int x=0;x<6;x++){

  bars[x] = int (yRatio*(ScreenHeight)*(serialInArray[x]/256.0));

}

      // Send a capital A to request new sensor readings:
      myPort.write('A');
      // Reset serialCount:
      serialCount = 0;
    }
  }
}

/////// Display any variables for testing here//////////////
void Headings(){
  fill(0 );
  text("BarWidth",50,TextGap );
  text("BarGap",250,TextGap );
  text("DivisounsWidth",450,TextGap );
  text(BarWidth,100,TextGap );
  text(BarGap,300,TextGap );
  text(DivisounsWidth,520,TextGap );
}

void PrintBars(){ 

  int c=0;
  for (int i=0;i<NumOfBars;i++){

    fill((0xe4+c),(255-bars[i]+c),(0x1a+c));
    stroke(90);
    rect(i*DivisounsWidth+LeftMargin,   ScreenHeight-GraphYposition,   BarWidth,   -bars[i]);
    fill(0x2e,0x2a,0x2a);
    text(float(bars[i])/(yRatio*(ScreenHeight))*Vcc,   i*DivisounsWidth+LeftMargin+BarWidth/2,   ScreenHeight-bars[i]-5-GraphYposition );
    text("A",   i*DivisounsWidth+LeftMargin+BarWidth/2 -5,   ScreenHeight-GraphYposition+20 );
    text(i,   i*DivisounsWidth+LeftMargin+BarWidth/2 +5,   ScreenHeight-GraphYposition+20 );
  }
}

void Axis(){

  strokeWeight(1);
  stroke(220);
  for(float x=0;x<=NumOfVertSubDivisions;x++){

    int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertSubDivisions));
    line(LeftMargin-15,bars,ScreenWidth-RightMArgin-DivisounsWidth+50,bars);
  }
  strokeWeight(1);
  stroke(180);
  for(float x=0;x<=NumOfVertDivisions;x++){

    int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));
    line(LeftMargin-15,bars,ScreenWidth-RightMArgin-DivisounsWidth+50,bars);
  }
  strokeWeight(2);
  stroke(90);
  line(LeftMargin-15, ScreenHeight-GraphYposition+2, ScreenWidth-RightMArgin-DivisounsWidth+50, ScreenHeight-GraphYposition+2);
  line(LeftMargin-15,ScreenHeight-GraphYposition+2,LeftMargin-15,GraphYposition);
  strokeWeight(1);
}

void Labels(){
  textFont(font,18);
  fill(50);
  rotate(radians(-90));
  text(yLabel,-ScreenHeight/2,LeftMargin-45);
  textFont(font,16);
  for(float x=0;x<=NumOfVertDivisions;x++){

    int bars=(ScreenHeight-GraphYposition)-int(yRatio*(ScreenHeight)*(x/NumOfVertDivisions));
    text(round(x),-bars,LeftMargin-20);
  }

  textFont(font,18);
  rotate(radians(90));
  text(xLabel,LeftMargin+(ScreenWidth-LeftMargin-RightMArgin-50)/2,ScreenHeight-GraphYposition+40);
  textFont(font,24);
  fill(50);
  text(Heading,LeftMargin+(ScreenWidth-LeftMargin-RightMArgin-50)/2,70);
  textFont(font);

  fill(150);
  text(URL,ScreenWidth-RightMArgin-40,ScreenHeight-15);
  textFont(font);

}


Arduino Code

//Sending 8 bit reading (256) so analogue 
//reading can be sent in 1 byte 

int Analogue0 = 0;    // first analog sensor
int Analogue1 = 0;   // second analog sensor
int Analogue2 = 0;    // digital sensor
int Analogue3 = 0;   // second analog sensor
int Analogue4 = 0;   // second analog sensor
int Analogue5 = 0;   // second analog sensor
int inByte = 0;         // incoming serial byte

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);

  establishContact();  // send a byte to establish contact until Processing responds 
}

void loop()
{
  // if we get a valid byte, read analog ins:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    // read first analog input, divide by 4 to make the range 0-255:
    Analogue0 = analogRead(0)/4;
    // delay 10ms to let the ADC recover:
    delay(10);
    // read second analog input, divide by 4 to make the range 0-255:
    Analogue1 = analogRead(1)/4;
    // read  switch, multiply by 155 and add 100
    // so that you're sending 100 or 255:
    delay(10);
    Analogue2 = analogRead(2)/4;
    delay(10);
    Analogue3 = analogRead(3)/4;
    delay(10);
    Analogue4 = analogRead(4)/4;
    delay(10);
    Analogue5 = analogRead(5)/4;
    delay(10);

    // send sensor values:
    Serial.print(Analogue0 , BYTE);
    Serial.print(Analogue1 , BYTE);
    Serial.print(Analogue2 , BYTE);
    Serial.print(Analogue3 , BYTE);
    Serial.print(Analogue4 , BYTE);
    Serial.print(Analogue5 , BYTE);
  }
}

void establishContact() {
 while (Serial.available() <= 0) {
      Serial.print('A', BYTE);   // send a capital A
      delay(300);
  }
}

Gobetwino: Arduino talking to Excel

Gobetwino is pretty easy use. The Arduino can now send words to the serial port and Gobetwino takes them as commands and does handy stuff like create csv’s send email etc. I’ve tested out this program by making the Arduino log the voltage of a discharging capacitor and send the details to Gobetwino to make a csv for Excel.

Circuitry

 

Log discharging capacitor, use FET's instead of BJT's if you want to avoid 0.6V drop


Arduino Code


//    Arduino code
//    Arduino to Excel using Gobetino

//      - Arduino logs 100 values
//      - Gobetwino takes these values and puts them in data.txt

//      - Excel Imports this file as a csv and draws the graph
// ==========< option 1 >==========
//      FIRST logs data to chip's sram,  THEN sends to pc using Gobetwino
//      - 1028 bytes can be stored

//      - readings are taken fast this way

// ==========< option 2 >==========
//      log straight to .txt with Gobetwino
//      - approximately a max of 37 readings/sec , depending on the serial speed you choose

//      - this way is safe (unlimited with the chips 1024 bytes of SRAM)
// ============< variables >==========

//  A0   -   Vcap
//  D3   -   button/switch    (trigger)

//  D4   -   transisters to charge & discharge cap
//  D5   -   LED 1

//  D6   -   LED 2 const int size = 100;
// number of readings (size of array must be constant)
// don't make it too big, arduino has limited memory const float Vss = 5.0;
// if you want to be more accurate measure arduino's Vss int arrayms[size];
// an arary to store time

int
arrayA0[size];
// an arary store voltage
int
a;
// counter
long startTime;

void setup() {
pinMode
(2, INPUT); // button
pinMode
(3, OUTPUT); // pin connected to transistor bases
pinMode(4, OUTPUT); // LED 1
pinMode(5, OUTPUT); // LED 2 LED's are used to show what stage the chip is in
pinMode(6, OUTPUT); // LED 3

Serial.begin(9600);
}

void loop() {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* test stuff
while(digitalRead(3)){}              // wait until I press pin 3 (trigger button)

while(!digitalRead(3)){}

Serial.println("#S|CPTEST|[]#");     // Use the CPTEST copy file command to make a copy of a new empty logfile

while(digitalRead(3)){}              //wait until I press pin 3 (trigger button)

while(!digitalRead(3)){}

digitalWrite(3, HIGH); // start charging capacitor
delay
(500); // wait 500 ms for the capacitor to charge
while
(digitalRead(2)){ digitalWrite(6, HIGH);   }
digitalWrite(6, LOW);
digitalWrite
(4, HIGH); // LED 1 tells you the capacitor should be charged

wait_until_pin_3_is_pressed(); // ------------------------------
a=0;
startTime =
millis();
digitalWrite
(3, LOW); // discharge capacitor
while
(a <= size )   {
arrayms[a]=
millis()-startTime; // record time
arrayA0[a]=
analogRead(0); // record Vcap
a++;
delay(1); // wait however ms before taking the next reading }
digitalWrite(4, LOW); // If LED 1 doesn't switch off, there is a problem in stage 1
digitalWrite(5, HIGH); // LED 2 tells you that Stage 2 is ready to start
wait_until_pin_3_is_pressed();

// ----------------------

a=0;

while
(a <size){
Serial.print("#S|LOGTEST|[");
// #S -> tells gobetwino to listen

// |LOGTEST|[ -> Gobetwino runs the LOGTEST command I made,
// which opens data.txt in this app's folder

// NOTE: there must already be a data.txt in the folder

printDouble(
double(arrayms[a])/1023*Vss, 3);
Serial
.print(";");
printDouble(
double(arrayA0[a])/1023*Vss, 3);
Serial.println("]#");
// # tells Gobetwino to stop paying attention
a++;
}
digitalWrite(5, LOW); // if LED2 doesn't switch off you're stuck in Stage 2
}
// end of void loop()
// somebody elses function I found to print doubles
void printDouble( double val, byte precision){

// prints val with number of decimal places determine by precision

// precision is a number from 0 to 6 indicating the desired decimial places

// example: printDouble( 3.1415, 2);

// prints 3.14 (two decimal places) Serial.print (int(val));

//prints the int part if( precision > 0) { Serial.print(".");

// print the decimal point

unsigned long frac; unsigned long mult = 1;

byte padding = precision -1; while(precision--)       mult *=10;

if(val >= 0)

frac = (val - int(val)) * mult;

else frac = (int(val)- val ) * mult;

unsigned long frac1 = frac;

while( frac1 /= 10 )       padding--;

while( padding--) Serial.print("0");

Serial.print(frac,DEC) ;   } }

void wait_until_pin_3_is_pressed() {

while( !digitalRead(2) ){   }

while( digitalRead(2) ){   }

}

How Gobetwino works

Before trying to use this program you should read the Gobetwino pdf. You basically have to open Gobetwino and create a command to handle .txt files. I did this by opening Gobetwino and creating a LOGTEST command to open log.txt

  1. Click on the Commands menu
  2. Selecting LGFIL (Log File command)
  3. Select the file location of an existing .txt file (data.txt in this case)

Now when the Arduino serially prints LOGTEST a .txt file is opened.

   Serial.print("#S|LOGTEST|[A,B,C]#");
  • #s tells Gobetwino to pay attention
  • |LOGTEST| is the command I created with Gobetwino to open data.txt
  • [A,B,C] are variables printed to the file
  • # tells Gobetwino to stop paying attention


Summary

  1. Upload the code to the Arduino
  2. Create the LOGTEST command with Gobetwino
  3. Press the button on your circuit (capacitor discharges)

I then import the .txt with excel and create the following graph

The voltage of the discharging capacitor

Notice the capacitor doesn’t fully discharging because I used BJT’s instead of FET’s.

Is this a joke?

I decide to look up the Arduino and see if it’s for sale in SA yet. This is what I found:

RIP OFF!

I’ve blurred out the company name to be safe. I ordered mine from china, and it added up to R300, including shipping! If it was R100 more that would be OK, but R700 more is unacceptable.

Memristor

Resistance, capacitance and inductance are no longer the only basic circuit elements. There is now a fourth one: the memristor. This was predicted about 40 years ago, but only recently discovered by HP Labs.

The symbol of a memristor

Basically it’s a resistor with a resistance that depends on the number of electrons that have passed through it. BIG discovery. This is like adding new plans to the foundations of electronics.

Here is the New Scientist Article with all the details about the memristor.