Arduino - Improved Poor Man's Oscilloscope

Published

Introduction: Arduino - Improved Poor Man's Oscilloscope

This Instructable continues the work presented here.  It provided a quick and easy way to turn your Arduino into an oscilloscope, though I found that usability was lacking.  I revamped the software this morning to allow for much better functionality and usability and have provided the new software here.  I haven't fully tested it out yet, so please post bugs in the comments.  Also, this is still a fairly limited scope, so don't expect too much in terms of performance.  To reiterate the other Instructable:

First, download Processing (free).
Second, download both the Arduino and Processing code I've provided here.
Third, upload the Arduino code and run the Processing code.

If you examine the Processing software, you will notice that a number of hot keys have been defined.  I won't repeat them here, but please take a look so you know the basic functionality.  These hot keys can quickly be edited to your liking.  Also, if you're having a hard time getting Processing to select the right com port there is a variable for that (note that this variable is the index in the list of available ports).

Lastly, I've added the ability to output a 2Hz square wave on the Arduino.  Connect this pin to your analog input to test the scope.  Enjoy!

10 People Made This Project!

Recommendations

  • Oil Contest

    Oil Contest
  • Woodworking Contest

    Woodworking Contest
  • Make it Move Contest

    Make it Move Contest
user

We have a be nice policy.
Please be positive and constructive.

Tips

Questions

21 Comments

Does this oscilloscope display sine wave; triangular wave also??

This is a great tool for my occasional hobbyist use. I use the free Soundcard Oscilloscope from zeitnitz.eu for signals above 20 Hz. I want to monitor an opto-coupled signal from the relatively slow rotations of the disk on my Electric meter for my current project, an Arduino based house power meter, so this DC coupled Arduino scope is perfect.

I'm thinking about building a scope with this and a RPI + LCD.

Would I be able with some code modification to do multichannel?

Great Project, also used the pull-down resistor to clean up the noise, works really well!

Nice project and thank you. Haven't been able to get my hands on a real scope...yet! so this is perfect for my BB projects.. thanks! i used your code and it works great! i'm on linux 64bit (ubuntu16)
the processin script i had to change Line 77 to

port = new Serial(this, "/dev/ttyACM0");

so it would detect my com.

i have a uno r3.

could you tell me the max frequency this thing can read please?

also, anything up to 5v is ok for A0 but anything above 5v needs a voltage divider and a buffer circuit? is that right?

Little update to get it to work well what i had to do on windows 10 and process 3.0.2
Had to change the word [com_port] to [0]
If you try and run the program and it freezes it will show an error the line with this command

1 reply

Awesome project....this will help greatly. Do you think its possible to have it output to a ascii file?

Is it possible to modify this for -ve and +ve voltages?

1 reply

Great job!

The scope is working perfect here. I've been testing some other arduino/processing scopes but yours seems to be the one!

Tks.

Help! I also have the problem on line 77, but how do i specify the port on Linux? I tried putting in /dev/ttyUSB0 a bunch of different ways, but nothing works. Anybody made it?

1 reply

Ok, I made it work.It was looking for the Arduino on /dev/ttyS1, but it was on /dev/ttyUSB0 so I just made a symlink!

#sudo su

#rm /dev/ttyS1

#ln -n /dev/ttyUSB0 /dev/ttyS1

also, it'll maybe better if there is dual channel option

This is very useful thank you.

when i try to run the processing code i get and error

ArrayIndexOutOfBoundsException: 0

1 reply

i think 0 indicates the port number , i changed it to 5 ( the one iam using for the arduino) yet the error is the same (with 5 instead of 0)

What a great project. I was looking for a simple oscope to test a circuit for another arduino project. I am just learning and I found that playing around with this project helped me to learn a lot. With the help of my brother who is an electrical engineer, we were able to make some efficiency changes to the code.

The first idea was to attempt to send the sync byte only once in order to increase the overall efficiency. That only worked partially. Due to an oddity in the way the serial port starts up, we were only able to achieve sync about 20% of the time. We would have to start processing first and then repeatedly reset the Arduino. So my brother got an idea. The implementation is quite a ways over my head but I will attempt to explain the basics and post the code changes.

In the original code, the arduino sends a sync byte, and two data bytes to encompass the 10bit analog stream. This amounts to three bytes sent for every 10 bits of needed data which could be encompassed inside two bytes. So what my brother did was use the upper few bits of the upper byte to place a sync flag and then read that back in each cycle of data transmission. So instead of using a full byte to achieve a data sync, only two are used. The improvement is about 30%. I was able to see signals of around 6Hz clearly on the oscope.

I hope this works. I'll be interested in hearing what others get for results.

-Scott

So here is the code for the Arduino side and then Processing below that.

Arduino Code - Replace the loop() with this...

==========

void loop() {

int loval;

int hival;

int val = analogRead(ANALOG_IN);

hival = ( (val >> 8) | ( val & 0x80) >> 3) | 0x80;

loval = (val & 0x7f);

Serial.write( hival & 0xff );

Serial.write( loval & 0xff );

}

Processing Code - Replace all of getValue() with this...

=============

// Read value from serial stream

int getValue() {

int value = -1;

int loval;

int hival;

while (port.available () >= 2)

{

hival = port.read();

if((hival & 0x80) == 0x80) { // found hival flag, now read loval

loval = port.read();

if((loval & 0x80) == 0) { // loval flag = 0, as expected

value = ((hival & 0x03) << 8) | ((hival & 0x10) << 3) | loval;

}

else

{

// error - low byte flag <> 0 as expected

value = -1;

}

}

else

{

// error - high byte flag missing

value = -1;

}

}

return value;

}

very nice...

This bit of processing code might help some one else determine the index of their serial port;
------

import processing.serial.*;
// List all the available serial ports and its index:
for (int i = 0; i < Serial.list().length; i++) {
println(i,Serial.list()[i]);
}


------

Hey JP..!!!
Really cool and usefull, many Thanx..!!