Breadboard
docs
Example project · ESP32

Internet stock ticker (64×8 matrix)

A finance ticker on the big 8-in-1 MAX7219 bar: the ESP32 fetches quotes from the sandbox internet’s mock exchange — prices tick on a deterministic walk every 5 seconds — and scrolls symbol, price, and change across 64×8 LEDs over bit-banged SPI. The scroll re-fetches at every wrap, so watch the numbers move; the serial monitor prints each refresh.

The Internet stock ticker (64×8 matrix) circuit as rendered by the simulator

How it works

Eight cascaded MAX7219 blocks make a 64×8 LED bar, driven exactly like real hardware: the ESP32 bit-bangs SPI words (register in the high byte, row data in the low byte) through all eight chips per load pulse. The script joins Wi-Fi, fetches JSON quotes from the sandbox internet's mock exchange at api.stocks.test, and formats them into one long ticker string — symbol, price, and signed change for four tickers. A 64×8 framebuffer scrolls the message one column per frame; when the scroll wraps, the script re-fetches. The mock prices walk deterministically, stepping every 5 seconds of virtual time, so successive laps show the market moving while staying fully reproducible.

What's on the bench

  • Battery
  • ESP32-C3
  • LED Matrix 64×8 (8-in-1)

How it's wired

  • Battery · posESP32-C3 · vin
  • Battery · negESP32-C3 · gnd
  • ESP32-C3 · 3v3LED Matrix 64×8 (8-in-1) · vcc
  • ESP32-C3 · gnd2LED Matrix 64×8 (8-in-1) · gnd
  • ESP32-C3 · g4LED Matrix 64×8 (8-in-1) · din
  • ESP32-C3 · g3LED Matrix 64×8 (8-in-1) · cs
  • ESP32-C3 · g6LED Matrix 64×8 (8-in-1) · clk

The code

This MicroPython script runs on the emulated board every boot; edit it in the Code tab.

from machine import Pin, SoftSPI
import framebuf, time, network, socket, json
spi = SoftSPI(baudrate=1000000, sck=Pin(6), mosi=Pin(4), miso=Pin(5))
cs = Pin(3, Pin.OUT, value=1)
NUM = 8  # eight cascaded MAX7219 blocks: 64x8
buf = bytearray(NUM * 8)
fb = framebuf.FrameBuffer(buf, NUM * 8, 8, framebuf.MONO_HLSB)
def all8(a, d):
    cs(0); spi.write(bytes([a, d]) * NUM); cs(1)
for a, d in ((0x0f, 0), (0x0b, 7), (0x09, 0), (0x0a, 3), (0x0c, 1)):
    all8(a, d)
def show():
    for y in range(8):
        cs(0)
        for m in range(NUM):
            spi.write(bytes([y + 1, buf[y * NUM + m]]))
        cs(1)
w = network.WLAN(network.STA_IF)
w.active(True)
w.connect('BreadboardNet')
fb.text('WiFi...', 0, 0); show()
while not w.isconnected():
    time.sleep_ms(100)
def quotes():
    addr = socket.getaddrinfo('api.stocks.test', 80)[0][-1]
    s = socket.socket()
    s.connect(addr)
    s.send(b'GET /stocks HTTP/1.0\r\nHost: api.stocks.test\r\n\r\n')
    r = b''
    while True:
        c = s.recv(256)
        if not c:
            break
        r += c
    s.close()
    q = json.loads(r.split(b'\r\n\r\n', 1)[1])['quotes']
    out = ''
    for it in q:
        out += '%s %s %s%s    ' % (it['symbol'], it['price'], '+' if it['change'] >= 0 else '-', abs(it['change']))
    return out
msg = quotes()
print('ticker:', msg)
x = NUM * 8
while True:
    fb.fill(0)
    fb.text(msg, x, 0)
    show()
    x -= 1
    if x < -len(msg) * 8:
        x = NUM * 8
        msg = quotes()
        print('ticker:', msg)
    time.sleep_ms(60)

Try this

  • Let the ticker complete a lap — the re-fetch at the wrap picks up new prices; compare the change figures.
  • Open the serial monitor: every refresh prints the full quote line.
  • Slow the scroll (raise sleep_ms) or change the message format in the Code tab and run it again.
  • Open the 📡 Sniffer to watch each re-fetch as a real DNS + TCP exchange.

Related projects