---

Wednesday, December 28, 2011

Arduino Oscilloscope Update

Project 18 in my book 30 Arduino Evil Genius Projects for the Evil Genius, is a very crude Arduino-based Oscilloscope - well more of an experiment really.



It just reads data from A0, divides it by 4 so it would fit in a byte and then sent it over USB to a receiving program that I wrote in Ruby and Tk.


// Project 18 - Oscilloscope

#define CHANNEL_A_PIN 0

void setup()                 
{
 Serial.begin(115200);
//Serial.begin(9600);

}

void loop()                   
{
  int value = analogRead(CHANNEL_A_PIN);
  value = (value >> 2) & 0xFF;
  Serial.print(value, BYTE);
  delayMicroseconds(100);
}


Here is the schematic - it just creates a 2.5V reference and AC coupling.

Note that there is no overvoltage protection, so understand what you try and measure with it, or you could damage or destroy your Arduino.




A few people have been having trouble using Tk and Ruby, so I decided to redo the sketch in Processing.


 As I said, very crude, but feel free to improve it and make something of it.



If you haven't had a play then do so, its great! If you are used to Arduino, then the IDE will be very familiar to you. Instead of 'setup' and 'loop' you have 'setup' and 'draw'.

The full processing sketch is listed below and if you just want an executable (mac, Linux and Windows), you can download this from the 'downloads' page on the book's website.


import processing.serial.*;

final int dt = 5;
final int width = 800;
final int height = 600;
final int messageHeight = 30;

Serial myPort;
int reading;
int t = 0;
int a_ = 128;

void setup() 
{
  size(width, height);
  background(255, 255, 255);
  makeConnection();  
}


void draw()
{
  if (t == 0)
  {
    while (getNextReading() != 128) {}; // wait for zero crossing
  }
  int a = (256 - getNextReading()) * 2 + messageHeight;
  // clear a vertical strip just infront of waveform
  fill(255, 255, 255);
  noStroke();
  rect(t, messageHeight+1, dt, height-messageHeight);
  // draw 0V line
  fill(0, 255, 0);
  stroke(1);
  line(t, 256 + messageHeight, t+dt, 256 + messageHeight);  
  // draw the waveform line
  fill(255, 0, 0);
  stroke(2);
  line(t, a_, t+dt, a);
  t += dt;
  a_ = a;
  if (t > width) t = 0; // flyback to start
}

int getNextReading()
{
  try
  {
    int readAttempts = 0;
    while ( myPort.available() <  0 && readAttempts < 10000) 
    {
      readAttempts ++;
    } 
    return myPort.read();  
  }
  catch (Exception e)
  {
    makeConnection();
  }
  return 128;
}  

void makeConnection()
{
    // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  // Open whatever port is the one you're using.
  String portName = "None";
  try
  {
    portName = Serial.list()[0];
    myPort = new Serial(this, portName, 115200);
    notify("Port: " + portName);
  }
  catch (Exception e)
  {
    warn("Not Connected: " + portName);
  }
}

void notify(String message)
{
  fill(255, 255, 255);
  stroke(0);
  rect(0, 0, width, messageHeight);
  fill(0, 0, 255);
  text(message, 0, 20); 
}

void warn(String message)
{
  fill(255, 0, 0);
  stroke(0);
  rect(0, 0, width, messageHeight);
  fill(0, 0, 0);
  text(message, 0, 20); 
}


About the Author
These are my books. Click on the image below to find out more about them.




1 comment:

Ytai said...

I once made a similar project with a PIC. There's a nice trick I used (and that you can use too) to dramatically boost the sample rate:
You don't need to send each individual sample form the Arduino to the host. Just trigger a "frame", say, 25 times a second, that in turn should wait for a trigger (e.g. zero crossing), then sample a fixed number of samples (say 1000, or as many you want to fit on the screen) and send them to the host. This decouples your sample rate from your connection speed, and unless you want to record the samples for offline viewing, you don't really need to send all of them.