Build a Portable Arduino Oscilloscope for Under $30 – Step‑by‑Step Guide

You ever wish you could peek at a signal on the go without hauling a bulky bench‑top scope? I’ve been there—sitting on a coffee break, trying to debug a noisy sensor, and the only oscilloscope in the lab is a 20‑year‑old monster that needs a power outlet and a forklift. The good news? With a little Arduino magic and a few cheap parts, you can put a decent, pocket‑size scope in your tool belt for less than the cost of a decent lunch.

Below is the exact list of parts, the wiring plan, and the software tweaks I used to turn an Arduino Nano into a 2‑channel, 10‑Msps (mega‑samples per second) little eye. The whole build stays under $30, even after accounting for a small OLED screen and a battery pack. Let’s dive in.

What You’ll Need

Core electronics

  • Arduino Nano (or any ATmega328 board) – $5
  • 2.4 inch 128×64 OLED display (SSD1306 driver) – $4
  • MCP3008 8‑channel 10‑bit ADC – $2
  • 2 × 10 kΩ resistors (for voltage divider) – $0.10
  • Breadboard and jumper wires – $3

Power & enclosure

  • Li‑ion 18650 cell + holder – $4
  • TP4056 charging module – $1.5
  • Mini project box (≈ 10 × 6 × 3 cm) – $3
  • On/off switch – $0.50

Optional extras (still under budget)

  • Push‑button for trigger – $0.20
  • Mini speaker or buzzer for audio cue – $0.30

All together you should stay comfortably below $30, even if you buy a few parts from different suppliers.

Why an Arduino‑Based Scope Works

The Arduino’s ATmega328 runs at 16 MHz, which means it can sample a few hundred thousand points per second if you bypass the built‑in ADC. The MCP3008 is a cheap external ADC that can handle up to 200 ksps (kilo‑samples per second) in single‑ended mode, which is plenty for hobby‑level debugging of PWM signals, sensor outputs, or simple audio waveforms. Pair that with a tiny OLED and you have a self‑contained display that fits in the palm of your hand.

Wiring the Circuit

1. Power rail

  • Connect the 18650 holder’s + to the Vin pin on the Nano (the Nano’s regulator will drop it to 5 V).
  • Ground of the holder goes to the Nano’s GND and the OLED’s GND.

2. OLED hookup

  • VCC → Nano 5V
  • GND → Nano GND
  • SCL → Nano A5 (I2C clock)
  • SDA → Nano A4 (I2C data)

3. MCP3008 connection

MCP3008 PinConnection
VDDNano 5V
VREFNano 5V
AGNDGND
DGNDGND
CLKNano D13
DOUTNano D12
DINNano D11
CS/SHDNNano D10

4. Input channels

  • CH0 and CH1 are the two inputs you’ll watch.
  • For safety, each input goes through a simple voltage divider (two 10 kΩ resistors) to keep the voltage under 5 V.
  • The divider’s midpoint connects to the MCP3008 channel pin, the top to the signal source, and the bottom to GND.

5. Trigger button (optional)

  • One side of the push‑button to Nano D2, the other side to GND. Enable internal pull‑up in code.

That’s it for the hardware. A quick photo of the assembled board inside the project box helps, but the wiring is straightforward enough that a sketch on paper does the trick.

Programming the Nano

I built the firmware using the Arduino IDE and the Adafruit_SSD1306 library for the OLED. The core loop does three things:

  1. Read the two ADC channels at the highest possible rate (about 100 ksps).
  2. Store a short buffer (256 samples) for each channel.
  3. Draw the waveform on the OLED, scaling the Y‑axis to fit the 64‑pixel height.

Below is a trimmed version of the sketch. You can copy‑paste it, compile, and upload.

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET -1
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);

const int CS_PIN = 10;
const int CLK_PIN = 13;
const int DIN_PIN = 11;
const int DOUT_PIN = 12;

const int CH0 = 0;
const int CH1 = 1;
const int SAMPLE_COUNT = 256;
uint16_t buf0[SAMPLE_COUNT];
uint16_t buf1[SAMPLE_COUNT];

void setup() {
  pinMode(CS_PIN, OUTPUT);
  digitalWrite(CS_PIN, HIGH);
  SPI.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
}

uint16_t readADC(byte channel) {
  digitalWrite(CS_PIN, LOW);
  byte command = 0b11000000 | ((channel & 0x07) << 3);
  SPI.transfer(command);
  uint16_t result = SPI.transfer(0) & 0x03;
  result <<= 8;
  result |= SPI.transfer(0);
  digitalWrite(CS_PIN, HIGH);
  return result;
}

void loop() {
  // Sample both channels
  for (int i = 0; i < SAMPLE_COUNT; i++) {
    buf0[i] = readADC(CH0);
    buf1[i] = readADC(CH1);
  }

  // Draw waveforms
  display.clearDisplay();
  for (int i = 0; i < SAMPLE_COUNT - 1; i++) {
    int x0 = map(i, 0, SAMPLE_COUNT - 1, 0, 127);
    int x1 = map(i + 1, 0, SAMPLE_COUNT - 1, 0, 127);
    int y0 = map(buf0[i], 0, 1023, 63, 0);
    int y1 = map(buf0[i + 1], 0, 1023, 63, 0);
    display.drawLine(x0, y0, x1, y1, SSD1306_WHITE);
    // Channel 1 in a different color (if you have a color OLED) or offset
    int y0b = map(buf1[i], 0, 1023, 63, 0);
    int y1b = map(buf1[i + 1], 0, 1023, 63, 0);
    display.drawPixel(x0, y0b, SSD1306_WHITE);
  }
  display.display();
}

A few notes:

  • The readADC function talks to the MCP3008 over SPI. It’s fast enough for our 100 ksps target.
  • The map calls scale the 10‑bit ADC value (0‑1023) to the OLED’s 0‑63 pixel range.
  • If you want a trigger, just add a simple check on the button pin before drawing.

Calibration and Tips

  1. Check the voltage divider – Use a multimeter to verify that a 5 V input really reads about 2.5 V after the divider. This protects the ADC from over‑voltage.
  2. Add a small capacitor (0.1 µF) across the MCP3008 VDD and GND pins to smooth out power spikes from the Li‑ion cell.
  3. Adjust the sample count – 256 points give a smooth line on a 128‑pixel wide screen. If you need more detail, increase the buffer size, but remember the OLED can only draw so fast.
  4. Battery life – The Nano draws ~30 mA at idle, the OLED another 10 mA when active. A 2600 mAh 18650 will keep you running for 30‑40 hours of light use.

Using Your New Scope

  • Measure PWM – Hook the signal to CH0, watch the duty cycle change as you turn a potentiometer.
  • Debug a sensor – Connect a temperature sensor’s analog output and see the voltage drift in real time.
  • Audio sniffing – Clip a cheap microphone pre‑amp to the input and you’ll see a rough waveform of speech or music. Not hi‑fi, but enough to spot clipping.

I’ve taken this little rig to a maker fair, a friend’s garage, and even a backyard garden to monitor a solar‑panel charger. Each time it saved me from pulling out a pricey bench scope or guessing what a stray voltage was doing.

Wrap‑Up

Building a portable Arduino oscilloscope is a perfect weekend project for anyone who likes to see the invisible. You get a functional tool, a deeper understanding of ADCs, and a tidy gadget that fits in a pocket. The parts are cheap, the code is short, and the satisfaction of watching a live waveform on a tiny OLED is priceless.

Give it a try, tweak the code to add a second trigger level, or swap the OLED for a tiny TFT if you want color. The sky’s the limit, and the cost stays under $30 – a small price for a big boost in your debugging arsenal.

#electronics #arduino #diy

Reactions
Do you have any feedback or ideas on how we can improve this page?