ESP32-S3 Lab · Day 21 of 30

Turn one byte
into a digit

Today the shift register earns its keep. You wire its eight outputs to a 7-segment display and upload a sketch that sends one byte per character, and the display counts 0 through F. Each byte is an encoding: eight bits that say which of the seven bars to light. Choosing a character is choosing the right byte, and the sketch keeps a table of them so it only has to look each up — the same three wires you ran on Day 20.

About 30 minutesArduino firstMicroPython optionalSame three wires as Day 20
Agent assist code TSK-DAY21-SEVENSEG

Hand this to an agent so it can pull the lesson packet and coach you step by step.

01 First, know the pieces

What you need

Six things, and two of them are old friends from Day 20. Tap Define on any part you haven't met — the answer opens as a field note you can read and dismiss without losing your place.

Official manual photo of the ESP32-S3 development board.
Manual photo

ESP32-S3 board

The brain that runs your uploaded sketch.

Official manual image of the ESP32-S3 GPIO extension board.
Manual photo

GPIO extension board

Spreads the pins into rows you can reach and label.

Official manual photo of the 74HC595 shift register chip with its pins labelled.
Manual photo

74HC595 shift register

Day 20's chip — takes a byte in on three wires and holds it on eight outputs.

Official manual photo of a one-digit seven-segment display module with its pins numbered 10, 6, 1, and 5 at the corners.
Manual photo

7-segment display

Eight lit bars arranged as a figure — together they draw one character.

Official manual photo of a resistor with coloured value bands.
Manual photo

8 × 220 Ω resistors

One per segment, each keeping its own current gentle.

Official manual image of a jumper wire.
Manual photo

Jumper wires

Temporary, solder-free connections.

02 Make the physical circuit

Chart the circuit

The official Freenove diagram is your chart — schematic on top, the same circuit built on a breadboard below. Click it to enlarge. The three control wires are exactly where Day 20 left them; today's work is the eight resistor paths from the chip's outputs to the display's segments.

Official Freenove circuit — C Tutorial, Chapter 15 (74HC595 & 7-Segment Display), page 140.
GPIO 12 74HC595 DS (pin 14) Carries each bit of the pattern byte into the chip.
GPIO 13 74HC595 ST_CP (pin 12) The latch — a low-high pulse shows the finished byte on all eight outputs at once.
GPIO 14 74HC595 SH_CP (pin 11) The clock tick that moves each bit one place along.
74HC595 Q0-Q7 segments A-G and DP via 220 Ω each Each output drives one segment through its own resistor.
Display common pins (3 and 8) positive rail (3.3V/5V) Feeds the shared anode so a 0 bit can light its segment.

Mind the chip and the display's orientation. Seat the 74HC595 with its notch matching the diagram, and place the display the way the breadboard photo shows — its segments only line up with the right Q pins one way round. Unplug USB before you move any wire.

03 One action at a time

Build it

This is the main path — you can finish the day without opening a single field note. Tap each step as you go to keep your place.

0 / 9 done
  1. Seat the ESP32-S3 on the GPIO extension board and keep USB unplugged while you wire.

  2. Straddle the 74HC595 across the breadboard's centre gap with its notch matching the diagram — the same seat as Day 20.

  3. Place the 7-segment display nearby the way the breadboard photo shows, and find its two common pins (3 and 8).

  4. Run the three control wires — GPIO 12 to DS, GPIO 13 to ST_CP, GPIO 14 to SH_CP.

  5. Wire each chip output Q0 through Q7 to its segment through its own 220 Ω resistor, following the diagram one row at a time.

  6. Wire the display's common pins (3 and 8) to the positive rail so the shared anode has power.

  7. Compare every wire to the chart before you plug in USB.

  8. Open Sketch_15.1_1_Digit_7-Segment_Display.ino in Arduino IDE and upload it.

  9. Watch the display count 0 through F, one character per second.

A digit you can read.

The board is drawing characters now, one byte each. Head to Test & debug to confirm the full count.

04 Read just enough code

Read the code

The sketch keeps Day 20's writeData() helper word for word. The new piece is a table of sixteen bytes — one ready-made segment pattern per character — and a loop that sends them one per second. Switch to MicroPython if you'd rather see the same idea in Python — the wiring never changes.

Sketch_15.1_1_Digit_7-Segment_Display.ino
int dataPin  = 12;          // Pin connected to DS of 74HC595(Pin14)
int latchPin = 13;          // Pin connected to ST_CP of 74HC595(Pin12)
int clockPin = 14;          // Pin connected to SH_CP of 74HC595(Pin11)

// Define the encoding of characters 0-F for the common-anode 7-Segment Display
byte num[] = {
  0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
  0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e
};

void setup() {
  // set pins to output
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
  // display 0-F on digital tube
  for (int i = 0; i < 16; i++) {
    writeData(num[i]);// Send data to 74HC595
    delay(1000);      // delay 1 second
    writeData(0xff);  // Clear the display content
  }
}

void writeData(int value) {
  // Make latchPin output low level
  digitalWrite(latchPin, LOW);
  // Send serial data to 74HC595
  shiftOut(dataPin, clockPin, LSBFIRST, value);
  // Make latchPin output high level, then 74HC595 will update the data to parallel output
  digitalWrite(latchPin, HIGH);
}
byte num[]The lookup table of segment patterns — sixteen bytes, one per character 0 through F, so num[i] is the ready-made encoding for character i.
shiftOut(dataPin, clockPin, LSBFIRST, value)Clocks the byte into the chip one bit at a time — the same move as Day 20.
writeData(0xff)All eight bits set to 1 means every segment off — this line blanks the display.
delay(1000)Holds each character on the display for one full second.

05 Understand, don't memorise

A digit is a pattern, and a byte is that pattern

A seven-segment display doesn't understand the number 3. It only knows which of its bars are lit. Turning "3" into something it can show means deciding which segments to switch on, packing that decision into a byte, and handing that byte to Day 20's shift register. That translation from a numeral to a pattern of bits is the whole idea today, and a small lookup table carries it.

1

Seven named bars

A single digit is drawn by seven bars, labelled a to g, plus a decimal point. Any numeral is a particular set of those bars switched on: a 7 lights three of them, an 8 lights all seven.

2

One bit per segment

Give each segment its own bit and the whole on-off pattern fits in eight bits. On this display the bit order from the top down is DP G F E D C B A, so each bit owns exactly one bar.

3

A 0 bit lights the bar

The display is common anode: every segment shares the positive rail, so a bar lights when its bit is pulled LOW. A 0 turns a segment on and a 1 leaves it dark, which is why 0xff is a blank display.

4

Look it up, don't compute it

There is no tidy formula from the numeral 3 to its segments, so the sketch stores the answer once. num[3] is the ready-made byte for a 3, and choosing which digit to show becomes choosing an entry from the table.

5

Day 20 delivers it

The 74HC595 sends whatever byte you hand it out onto its eight pins. Show a 3 by looking up num[3] and shifting that byte out — the same three wires as yesterday.

The model digit → index the table → one byte → eight segments → a shape you can read

How a byte becomes a shape

Read 0xb0 as bits, 1011 0000, in segment order DP G F E D C B A. The 0 bits — G, D, C, B, A — are the lit bars, and A B C D G drawn together is a 3. Every entry in the table is one of these patterns worked out in advance.

Why a table, not arithmetic

Which bars a numeral lights follows no equation — a 2 and a 5 share almost nothing. Ten patterns cover 0 to 9 (this sketch keeps sixteen, adding A to F for hex counting), each stored once so the loop only has to index them.

Why 0 means on

Common anode ties every segment's positive side to the rail, so an output must sit LOW to let current flow and light its bar. That inverts the intuition: 0 is on, 1 is off, and all ones (0xff) shows nothing.

06 Know it worked

Test & debug

Nothing prints to the screen today — the proof is the count running on the display in front of you.

What you should see
Display
  • The display counts 0 1 2 3 4 5 6 7 8 9 then A b C d E F — one character per second.
  • After F it wraps back to 0 and the count runs again.
  • Each character sits steady for its full second.

Lowercase b and d are deliberate — with all seven segments a capital B would read as 8 and a capital D as 0.

If it doesn't
  • Every segment lit, all the time? The patterns aren't reaching the chip — check the latch wire on GPIO 13.
  • One segment never lights? Trace that segment's 220 Ω wire back to its Q pin on the chip.
  • Shapes are nonsense? Segment wires are on the wrong Q pins — re-check them against the diagram one row at a time.
  • Display completely dark? Run Day 20's chip power and orientation checklist, then confirm the common pins (3 and 8) reach the positive rail.

07 Make the idea yours

Try this: decode a byte, then bend the count

The table is the whole trick, so take it apart. Read one byte back into a shape, shorten the count to change the sequence, then hand-build a character the table never had — all on the working circuit, inside today's 30 minutes.

Decode a byte back into a shape

Take num[3] from the table — the byte 0xb0 — and write it out as bits, 1011 0000, in segment order DP G F E D C B A. The 0 bits are the lit bars, so mark them and you get G D C B A, which draws a 3. Watch the count reach 3 and confirm your reading matches the display.

Count only 0-9

Change the loop's for (int i = 0; i < 16; i++) to i < 10 and upload. The display now counts 0 through 9 and wraps, skipping A to F — you have changed the sequence by changing which table entries the loop walks.

Build your own character

Segments B C E F G draw an H, and in bit order DP G F E D C B A that pattern is the byte 0x89. Empty out loop(), add writeData(0x89) to the end of setup(), and check that the H holds steady from power-on.

08 Learn it with a hand on the tiller

Coach me through it

Every lesson ships with a code and a machine-readable packet, so an agent can guide you with full context.

Lesson code

TSK-DAY21-SEVENSEG

How the agent should behave: guide one physical connection at a time, then teach the encoding underneath: how a numeral becomes a set of lit segments, how that set packs into one byte, and why a lookup table is the clean way to keep them. Explain terms on request, and always check wiring, board, port, and USB before changing code.

Keep your place

Finished Day 21?

Mark it complete — it shows on your course map, and your place is saved on this device.

Field note

Shortcut

Prompt copied