2009-10-19

Arduino Oscilloscope

I have some testing I'd like to do that would benefit from an oscilliscope.  Unfortunately, I don't have an oscilloscope, and there's no room in the budget to buy one at the moment.  So I thought I'd see what kind of oscilloscope I can make out of an Arduino microprocessor.

I know an Arduino oscilloscope has been done any number of times before.  This is just my version of the concept.

I originally thought I'd have to do some moderately complex programming to make the Arduino act as an oscilloscope.  I figured I'd have to buffer readings, and have a communication protocol to transfer the data, set up trigger conditions, etc.  Luckily, I decided to run some tests before I started the serious coding.

A quick test app reveals that the analogRead() function 112 or 116 microseconds to execute (the micros() function has a resolution of 4us, so the actual time is somewhere between those two values.)  Serial.write() of a single byte takes only 8 microseconds.

The slow analog conversion time and the fast time to send a single byte gave me an idea: instead of having a complicated Arduino program to act as an oscilloscope, I could use an extremely simple program that just constantly streams measurements from an analog input pin.  For my purpose, I doubt I need the full 10 bits of A2D resolution; 8 bits should be enough.  This means that I don't even have to worry about synchronizing with the data stream from the microcontroller, since every byte is an valid independent reading.  A sample rate of 5000 Hz (200 us between samples) would only be 40kbps, which should be easily handled by a 115200 baud rate.

Unfortunately, further testing revealed that a 5000 Hz sample rate caused the serial data to arrive in large chunks about once a second.  I guess that some part of the serial line was being overwhelmed.  I don't know if it was in the microcontroller, the PC, or in the FTDI USB to serial chip.  Wherever the problem lies, a sample rate of 4000 Hz (250 us between samples) seems to cure the problem.

The resulting Arduino application is so simple that I'm going to post the whole thing here:
void setup()
{
  // need fast serial rate to keep up with 1 byte data every 250 us
  Serial.begin(115200);
}
 
void loop()
{
  static uint16_t analogVal;
  static uint32_t nextReadTime;
  static uint32_t nowTime;
  
  // start by calculating time that next read will take place
  nextReadTime = micros() + 250;
  
  // read analog value
  analogVal = analogRead(0);  

  // send analog value (as single byte)
  Serial.print((uint8_t)(analogVal >> 2), BYTE);
  
  // wait for right amount of time to do next read
  nowTime = micros();
  if(nowTime < nextReadTime)
    delayMicroseconds(nextReadTime - nowTime);
}

Pretty simple, isn't it?

Of course, now all the oscilloscope logic has to go in a program on the PC side.

I started trying to write an application in Python, pySerial, and pygame.  It was going a little slowly though, so I ended up throwing togeather a quick program in C# instead.  Here's what it looks like after a few hours of messing around:




In the first two pictures, the signal is just whatever is picked up with the analog input pin of the Arduino disconnected.  It makes a nice sine wave for testing the display application.

The third picture is the output of a pin set to output PWM with a 25% duty cycle.  The 4000 Hz sample rate of the scope is just barely enough to see the 500 Hz PWM waveform: each cycle gets 4 samples.

I don't know if this will actually be useful for anything, but it was fun to do.  I got to play with microcontrollers and computer graphics at the same time!

5 comments:

wDPware said...

Hello,
I like the simplicity of your project.
May you publish your C# code ?
Best regards,
wDPware

James Wilkins said...

Sure, I can share the C# source code. You can download the project here: http://notzero.net/misc/OscilloscopeApp.zip.

Just keep in mind that this is prototype quality code, not intended to be used as anything other than a proof of concept.

Seb said...

Would it be possible to add the functionality of saving the incoming data in a txt file as comma separated values? That would enable later review of the recorded data, I guess it would be useful.

NelsonMax said...

hi, this is a nice project, that impressed me.

I don't know C#

By problem is, the C# application is not detecting my cop port to which my arduino board is connected. I am using FTDI USB-Serial interface for my boeard. pls help, as soon possible. thanks in advance

James Wilkins said...

Hi Nelson,

I'm not sure sure that I can help you much here. When the program is started it scans for all serial ports and adds them to the "Config" menu. It should detect all serial ports on your computer.

Have you verified that you do have a working serial connection to the Arduino board? You can user the serial monitor in the Arduino software along with some of the communication example sketches to check this.

Since my test application enumerates the list of available serial ports when it is first started, you'll have to be sure to start the software after the Arduino is connected and the serial port is active.

Other than those two suggestions, I can't think if anything I can do to help.