How to Display Numbers on 4-Digit 7-Segment Display with Raspberry Pi Pico in Wokwi - Complete Step-by-Step Tutorial

4-Digit 7-Segment Display with Raspberry Pi Pico | MakeMindz
🔧 Free Wokwi Simulation Included — No Hardware Needed!  |  ▶ Run Now
🔴 Raspberry Pi Pico  ·  Wokwi Simulator

4-Digit 7-Segment Display
with Raspberry Pi Pico

Master multiplexing and PIO control to drive a 4-digit display — simulate it instantly in your browser, no hardware required.

⏱ 15 min read 🎯 Beginner–Intermediate 🔧 Arduino Core / C++ 🖥 Wokwi Simulator 📌 PIO · GPIO · Multiplexing

Project Overview

This tutorial shows you how to connect and program a 4-digit 7-segment display (Common Cathode) with the Raspberry Pi Pico using the Wokwi online simulator. You'll use the PIO (Programmable I/O) hardware to drive all four digits efficiently with minimal CPU involvement.

🔢

Multiplexing

Drive 4 digits with just 12 GPIO pins using time-division multiplexing

PIO Control

Hardware state machine keeps display refreshed without blocking the CPU

🖥

Wokwi Sim

Simulate everything online — no breadboard or components needed

Counter Demo

Watch an incrementing counter from 0000–9999 update every 200ms

How 7-Segment Displays Work

A 7-segment display contains 7 LED segments (A–G) plus a decimal point (DP). By turning specific segments on or off, you can display digits 0–9 and many letters.

A B C D E F G DP Displaying 8

Segment layout: A=Top, B=Top-Right, C=Bottom-Right, D=Bottom, E=Bottom-Left, F=Top-Left, G=Middle, DP=Decimal Point

Common Cathode vs Common Anode

TypeCommon PinSegment ON when GPIO =Used in this tutorial?
Common CathodeGNDHIGH✅ Yes
Common AnodeVCC (3.3V)LOW❌ No
💡

Common Cathode displays are simpler to control — a HIGH GPIO signal turns a segment ON. This is what the Wokwi wokwi-7segment component uses by default.

Understanding Multiplexing

A 4-digit display has 8 segment pins (A–G, DP) and 4 digit-select pins (D1–D4). Only one digit is active at a time, but switching happens faster than 50 Hz — so all four digits appear lit simultaneously to the human eye.

1

Enable Digit 1

Pull D1 HIGH, set segment pins to show the thousands digit, then disable.

2

Enable Digit 2

Pull D2 HIGH, set segment pins to show the hundreds digit, then disable.

3

Enable Digit 3

Pull D3 HIGH, set segment pins to show the tens digit, then disable.

4

Enable Digit 4

Pull D4 HIGH, set segment pins to show the units digit, then disable.

Repeat Continuously

The PIO state machine loops this at 2000 Hz — no CPU intervention needed.

⚠️

Multiplexing below 50 Hz causes visible flickering. The PIO clock runs at 2000 Hz, giving each digit 500 Hz — well above the flicker threshold.

GPIO Pin Assignment

Connect your 4-digit 7-segment display to the Raspberry Pi Pico using the following pin mapping:

🟢 Segment Pins (GP2 – GP9)

SegmentPositionPico GPIO
ATopGP2
BTop RightGP3
CBottom RightGP4
DBottomGP5
EBottom LeftGP6
FTop LeftGP7
GMiddleGP8
DPDecimal PointGP9

🔵 Digit Select Pins (GP10 – GP13)

DigitPositionPico GPIO
D1Leftmost digitGP10
D2Second digitGP11
D3Third digitGP12
D4Rightmost digitGP13
🔌

In Wokwi simulation, resistors are optional. For real hardware, add 220Ω–330Ω resistors in series with each segment pin to protect the LEDs.

diagram.json

Paste this into your diagram.json file in the Wokwi editor. It places the Pico and 4-digit display, then wires all 12 connections automatically.

JSON — diagram.json
{
  "version": 1,
  "author": "Uri Shaked",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-pi-pico",
      "id": "pico",
      "top": 65.16,
      "left": -27.77,
      "rotate": 90,
      "hide": false,
      "attrs": { "env": "arduino-community" }
    },
    {
      "type": "wokwi-7segment",
      "id": "sevseg1",
      "top": -21.97,
      "left": -85.69,
      "rotate": 0,
      "hide": false,
      "attrs": { "digits": "4" }
    }
  ],
  "connections": [
    [ "pico:GP0", "$serialMonitor:RX", "", [] ],
    [ "pico:GP1", "$serialMonitor:TX", "", [] ],
    [ "sevseg1:A",   "pico:GP2",  "green", [ "v-21", "h145", "v115", "h-68" ] ],
    [ "sevseg1:B",   "pico:GP3",  "green", [ "v-15", "h100", "v103", "h-65" ] ],
    [ "sevseg1:C",   "pico:GP4",  "green", [ "v16",  "h37"  ] ],
    [ "sevseg1:D",   "pico:GP5",  "green", [ "v22",  "h53"  ] ],
    [ "sevseg1:E",   "pico:GP6",  "green", [ "v32",  "h42"  ] ],
    [ "sevseg1:F",   "pico:GP7",  "green", [ "v-13", "h-96", "v116", "h104" ] ],
    [ "sevseg1:G",   "pico:GP8",  "green", [ "v11",  "h1"   ] ],
    [ "sevseg1:DP",  "pico:GP9",  "green", [ "v7",   "h-3"  ] ],
    [ "sevseg1:DIG1","pico:GP10", "blue",  [ "v-19", "h-84", "v128", "h81"  ] ],
    [ "sevseg1:DIG2","pico:GP11", "blue",  [ "v-28", "h-121","v144", "h80"  ] ],
    [ "sevseg1:DIG3","pico:GP12", "blue",  [ "v-39", "h-139","v162", "h79"  ] ],
    [ "sevseg1:DIG4","pico:GP13", "blue",  [ "v66",  "h-82" ] ]
  ]
}

segment.pio.h

This auto-generated PIO header file contains the state machine program that drives all four digits via hardware — freeing up the CPU for other tasks.

C — segment.pio.h
// -------------------------------------------------- //
// This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- //

#pragma once

#if !PICO_NO_HARDWARE
#include "hardware/pio.h"
#endif

#define segment_wrap_target 0
#define segment_wrap 5

static const uint16_t segment_program_instructions[] = {
    // .wrap_target
    0x8080, // 0: pull   noblock       side 0
    0xa027, // 1: mov    x, osr        side 0
    0x6208, // 2: out    pins, 8       side 1
    0x6408, // 3: out    pins, 8       side 2
    0x6808, // 4: out    pins, 8       side 4
    0x7008, // 5: out    pins, 8       side 8
    // .wrap
};

#if !PICO_NO_HARDWARE
static const struct pio_program segment_program = {
    .instructions = segment_program_instructions,
    .length = 6,
    .origin = -1,
};

static inline pio_sm_config segment_program_get_default_config(uint offset) {
    pio_sm_config c = pio_get_default_sm_config();
    sm_config_set_wrap(&c, offset + segment_wrap_target, offset + segment_wrap);
    sm_config_set_sideset(&c, 4, false, false);
    return c;
}

#include "hardware/clocks.h"
static inline void segment_program_init(PIO pio, uint sm, uint offset,
                                          uint first_segment_pin, uint first_digit_pin) {
    const int segment_pins = 8;
    const int digit_pins   = 4;

    pio_sm_config c = segment_program_get_default_config(offset);
    sm_config_set_out_pins(&c, first_segment_pin, segment_pins);
    sm_config_set_sideset_pins(&c, first_digit_pin);
    sm_config_set_out_shift(&c, false, false, 32); // Shift left

    // Attach all segment pins to PIO
    for (int pin = first_segment_pin; pin < first_segment_pin + segment_pins; pin++)
        pio_gpio_init(pio, pin);

    // Attach all digit select pins to PIO
    for (int pin = first_digit_pin; pin < first_digit_pin + digit_pins; pin++)
        pio_gpio_init(pio, pin);

    // Set all as outputs
    pio_sm_set_consecutive_pindirs(pio, sm, first_segment_pin, segment_pins, true);
    pio_sm_set_consecutive_pindirs(pio, sm, first_digit_pin,   digit_pins,   true);

    // Run at 2000 Hz
    float div = (float)clock_get_hz(clk_sys) / 2000;
    sm_config_set_clkdiv(&c, div);

    pio_sm_init(pio, sm, offset, &c);
    pio_sm_set_enabled(pio, sm, true);
}
#endif

Full C++ Code

This is the main Arduino sketch. It initialises the PIO state machine and increments a counter displayed on all four digits every 200 ms.

C++ — sketch.ino
/**
 * Pi Pico PIO driving a 4-digit seven segment display example.
 * Copyright (C) 2021, Uri Shaked
 */

#include "segment.pio.h"

// Segment bit patterns for digits 0–9 (Common Anode encoding)
uint8_t digits[] = {
  0b11000000, // 0
  0b11111001, // 1
  0b10100100, // 2
  0b10110000, // 3
  0b10011001, // 4
  0b10010010, // 5
  0b10000010, // 6
  0b11111000, // 7
  0b10000000, // 8
  0b10011000, // 9
};

const uint8_t first_segment_pin = 2;   // GP2 = Segment A
const uint8_t first_digit_pin   = 10;  // GP10 = Digit 1

void setup() {
  Serial1.begin(115200);
  Serial1.println("Raspberry Pi Pico PIO 7-Segment Example");

  // Load the PIO program and start the state machine
  auto offset = pio_add_program(pio0, &segment_program);
  segment_program_init(pio0, 0, offset, first_segment_pin, first_digit_pin);
}

/**
 * Display any 0–9999 value across all four digits.
 * Packs each digit's segment byte into a single 32-bit word for the PIO FIFO.
 */
void displayNumber(uint value) {
  pio_sm_put(pio0, 0,
    digits[value / 1000 % 10] << 24 |   // Thousands
    digits[value /  100 % 10] << 16 |   // Hundreds
    digits[value /   10 % 10] <<  8 |   // Tens
    digits[value        % 10]           // Units
  );
}

int i = 0;

void loop() {
  displayNumber(i++);
  delay(200);
}

Step-by-Step Instructions

Follow these steps to get the simulation running in under 5 minutes:

1

Open Wokwi

Go to wokwi.com and create a new project. Select Raspberry Pi Pico as your board with the Arduino Community environment.

2

Add the 7-Segment Display

Click the "+" button in the parts panel and search for wokwi-7segment. Add it to the canvas and set its digits attribute to 4.

3

Paste diagram.json

Click on the diagram.json tab in Wokwi and replace its content with the JSON from Section 5 above. This auto-wires all 12 connections.

4

Add segment.pio.h

Create a new file named segment.pio.h in your project and paste in the full PIO header from Section 6. This is required for the C++ sketch to compile.

5

Paste the Main Sketch

In the main sketch.ino editor, paste the C++ code from Section 7. Ensure the #include "segment.pio.h" line is at the top.

6

Run the Simulation

Click the green ▶ Play button. You should see the display counting up from 0000, updating every 200 ms with zero flickering.

🖥

Try It in Your Browser — Free

No hardware, no installation. The full simulation runs on Wokwi with the correct wiring and code pre-loaded.

▶ Open Wokwi Simulation

Expected Output

The display counts from 0000 → 0001 → 0002 → … → 9999, updating every 200 ms. No flickering should be visible thanks to the 2000 Hz PIO refresh rate.

Demo ModeDisplay Output
Incrementing Counter0000 → 0001 → 0002 …
Decimal Display00.0 → 01.0 …
Countdown Timer0010 → 0009 → … → 0000
Static Number1234 (fixed)

Applications

Once you've mastered this technique, you can apply it to a wide range of embedded projects:

🕐
Digital Clocks
🌡
Temperature Displays
Stopwatches
🏆
Scoreboards
📡
Frequency Counters
🌐
IoT Dashboards
🏭
Industrial Panels

Embedded systems tutorials, simulations, and project guides.

makemindz.com  ·  Tutorial by MakeMindz Team

Comments

try for free