Introduction: Arduino - Improved Poor Man's Oscilloscope

Picture of 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!


usevimli made it! (author)2017-08-27

It works on linux. By the way hotkeys;

'w'; // Translate waveform up

's'; // down

'a'; // left

'd'; // right

'c'; // Horizontal zoom in
'z'; // out

'e'; // Vertical scale in

'f'; // out

'r'; // Minor grid lines increase

'f'; // decrease

'p'; // Toggle pause (unpause resets waveform)

' '; // Reset axis settings

'x'; // Adds and/or highlights vertical bars (time measurement)

','; // Move highlighted vertical bar left (can also mouse click)

'.'; // right

You should change line 77 according to your com port here is mine:
port = new Serial(this, "/dev/ttyUSB0", 9600);

Thank you very much.

Anirban pal (author)2017-04-07

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

MikeFromMA (author)2017-04-02

This is a great tool for my occasional hobbyist use. I use the free Soundcard Oscilloscope from 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.

ScholliY (author)2016-10-18

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

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

AraY18 (author)2016-09-18

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

JamesS59 made it! (author)2015-07-02

You need to add a 1M Ohm pull-down resistor (from GND of course) to A0 to remove majority of the noise. Works though!! I'd like to add features later. Do you have a link to the original GitHub repo?

AlissonD (author)JamesS592016-08-26

Thank you man! The noise problem was driving me crazy!

colzilla090 (author)2016-05-19

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?

DavidH520 (author)2016-05-03

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

DavidH520 (author)DavidH5202016-05-03

On line 77

difranc3 (author)2016-03-09

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

TheGoodLife (author)2015-10-03

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

bigredlevy (author)TheGoodLife2016-03-01

you will have to add an opamp summing mixer

The input voltage range of (0 to +5V) will be changed to (-2.5 to +2.5V).

If a greater range is needed (eg. +/-15V), you will need to use a voltage divider on your circuit input.

Kepp27 made it! (author)2016-02-22

A lot of noise when no input choosen. Didn't what to bother with a pulldown resistor. Works perfect when connected to pin 13!

rbalani (author)2016-02-13

Great job!

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


LukaM5 (author)2016-01-30

Also, it doesn't really seem to work propperly for me. Instead of the test square wave it shows me kind of a sawtooth or a trangle wave. Do i have to connect REF or VIN to a stable voltage like 3v3 or 5v? Sorry I've had an arduino for like a week :)

LukaM5 made it! (author)LukaM52016-01-31

Here you can see first the wannabe square wave from pin 13, then me unplugging the wire from pin 13 and connecting it to 5V. I think it needs a little calibration... Can anybody help me?

LukaM5 (author)2016-01-30

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?

LukaM5 (author)LukaM52016-01-30

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

clovisf made it! (author)2016-01-28

I made it using +Kevin Mitchell's tip of changing line 77 of processing to "port = new Serial(this, "COM3");"

nickaris1 (author)2015-11-22

in line 77 i get an error "ArrayIndexOutOfBoundsException:1"

please HELP ME

Kevin Mitchell made it! (author)nickaris12015-11-26

Same happened with me. But I also had to use the 32 bit version of Processing to run a script.

Here's how I got it to work;

To find the port name run the Arduino IDE and check out the label on the bottom right of the form. Mine reads "Arduino/Genuino Uno on COM3". COM3 is the default port in my case - if not all cases. You can change this through the device manager properties. On line 77 replace that list array to your port name. "port = new Serial(this, "COM3");" When you run the script hopefully the port is found and the form starts up properly.

Now the next problem I had... The original script didn't work as is for me. I was about to give up before I tried what the user scottgriz has shared. Though I don't think the test wave off the digital output is working as it should. Scoping an LFO I have breadboarded I can see the rest of the arduino script running and communication with Processing seems to be going strong.

Hope this helps you - it was a well worth headache for myself. I'm new to micro controllers and haven't programmed in ages.

DCBURG3R (author)2015-11-04


What kind of bandwidth is this capable of measuring ? id like to check the gate drive for my tesla coil :)

Borowik made it! (author)DCBURG3R2015-11-16

Rising edge lasts about 8ms, so the program is able to check signal once for 8ms. So I think that max freq is only about 125Hz.

Thats what I got after setting 100Hz square signal. I would really love to make it run faster ;)


Borowik made it! (author)2015-11-16

Made it! Really nice and easy project! Thanks!

I saw that rising edge in case of putting 3,3V by hand lasts about 8ms, what means the frequency isn't very good if our oscilloscope checks the values every 8ms. I tried to increase baud rate, but I think this problem coud be connected with operations needed to expose the signal for Processing.
I'll try to increase the frequency and I will let you know.
Greetings, thanks for the project :)

ptabone made it! (author)2015-08-28

Worked for me too, not at first thou as I needed to change the serial port number in the processing code. (To find your port use sysop code in the comment below)

DoğanK1 (author)2015-06-18

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

DoğanK1 made it! (author)2015-06-18

wow, such handy and useful project, many thanks

FrostyG1 (author)2015-04-17

This is very useful thank you.

bersham (author)2015-03-24

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

ArrayIndexOutOfBoundsException: 0

bersham (author)bersham2015-03-24

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)

scottgriz (author)2015-01-29

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.


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 =;

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

loval =;

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

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




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

value = -1;





// error - high byte flag missing

value = -1;



return value;


sysop (author)2014-12-24

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++) {


pleekMan (author)2014-11-27

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

homayounmh (author)2014-06-04

It was fun.

About This Instructable




Add instructable to: