FluxBench.AIShared project · read-only

AMOLED Market Ticker

LilyGO T-Display-S3 AMOLED·Arduino C++·Updated Jul 27, 2026·by FluxBench TeamIncludes Lab + Schematic

A stock ticker for the LilyGo T-Display S3 AMOLED (536×240): big color-coded price, change line and a live sparkline, all drawn with the flicker-free full-screen sprite pattern and pushed in one shot with pushColors(). Cycles QQQ → SPY → BTC-USD every 6 seconds — or on the GPIO 21 button: the bench has a push button wired to GPIO 21, so click it in the Lab to skip ahead (it works the same as the side button on the real board). Prices are a simulated random walk so the whole screen runs live in the Lab simulator — the comments show exactly how to swap in a real Yahoo Finance fetch on hardware.

sketch.ino
// AMOLED Market Ticker — LilyGo T-Display S3 AMOLED (536x240)
//
// Three symbols (QQQ / SPY / BTC-USD) rendered with the flicker-free
// full-screen sprite pattern: draw everything into a 536x240 sprite,
// then push it to the panel in one shot with amoled.pushColors().
//
// The onboard side button (GPIO 21) cycles symbols, and the page also
// auto-advances every 6 seconds. Prices here are a simulated random walk
// so the demo runs anywhere — including the FluxBench Lab simulator.
// On real hardware, swap simulateTick() for a Yahoo Finance fetch:
//   https://query1.finance.yahoo.com/v8/finance/chart/QQQ?interval=1d&range=1d
//   (send one header: http.addHeader("User-Agent", "Mozilla/5.0"))

#include <LilyGo_AMOLED.h>
#include <TFT_eSPI.h>

#define BTN_PIN 21          // onboard button
#define W 536
#define H 240

LilyGo_Class amoled;
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr = TFT_eSprite(&tft);

const int NHIST = 60;       // sparkline points
float hist[60];
int histLen = 0;

int sym = 0;                // 0=QQQ 1=SPY 2=BTC-USD
String symName = "QQQ";
float price = 529.14;
float prevClose = 527.90;

unsigned long lastTick = 0;
unsigned long lastPage = 0;
int lastBtn = HIGH;

void selectSymbol(int s) {
  sym = s;
  if (sym == 0) { symName = "QQQ";     price = 529.14;   prevClose = 527.90; }
  if (sym == 1) { symName = "SPY";     price = 623.50;   prevClose = 625.10; }
  if (sym == 2) { symName = "BTC-USD"; price = 118250.0; prevClose = 116900.0; }
  histLen = 0;
}

void simulateTick() {
  // random walk: +/-0.15% per tick — replace with the Yahoo fetch on hardware
  float step = (random(-100, 101) / 100.0) * price * 0.0015;
  price = price + step;
  if (histLen < NHIST) {
    hist[histLen] = price;
    histLen = histLen + 1;
  } else {
    for (int i = 0; i < NHIST - 1; i++) hist[i] = hist[i + 1];
    hist[NHIST - 1] = price;
  }
}

void drawScreen() {
  spr.fillSprite(TFT_BLACK);

  // header
  spr.setTextDatum(TL_DATUM);
  spr.setTextFont(4);
  spr.setTextColor(TFT_CYAN, TFT_BLACK);
  spr.drawString(symName, 16, 12);
  spr.setTextDatum(TR_DATUM);
  spr.setTextColor(TFT_DARKGREY, TFT_BLACK);
  spr.drawString("FluxBench Ticker", W - 16, 12);

  // big price, centered
  float change = price - prevClose;
  uint16_t upDown = TFT_GREEN;
  if (change < 0) upDown = TFT_RED;
  spr.setTextDatum(MC_DATUM);
  spr.setTextFont(8);
  spr.setTextColor(upDown, TFT_BLACK);
  spr.drawString(String("$") + String(price, 2), W / 2, 92);

  // change line
  float pct = 100.0 * change / prevClose;
  String sign = "+";
  if (change < 0) sign = "";
  spr.setTextFont(4);
  spr.drawString(sign + String(change, 2) + "  (" + sign + String(pct, 2) + "%)", W / 2, 150);

  // sparkline of the recent walk
  if (histLen >= 2) {
    float lo = hist[0];
    float hi = hist[0];
    for (int i = 1; i < histLen; i++) {
      if (hist[i] < lo) lo = hist[i];
      if (hist[i] > hi) hi = hist[i];
    }
    if (hi - lo < 0.01) hi = lo + 0.01;
    int x0 = 20, x1 = W - 20, y0 = 176, y1 = 228;
    spr.drawRect(x0 - 4, y0 - 4, (x1 - x0) + 8, (y1 - y0) + 8, TFT_DARKGREY);
    for (int i = 1; i < histLen; i++) {
      int xa = x0 + (i - 1) * (x1 - x0) / (NHIST - 1);
      int xb = x0 + i * (x1 - x0) / (NHIST - 1);
      int ya = y1 - (int)((hist[i - 1] - lo) / (hi - lo) * (y1 - y0));
      int yb = y1 - (int)((hist[i] - lo) / (hi - lo) * (y1 - y0));
      spr.drawLine(xa, ya, xb, yb, upDown);
    }
  }

  amoled.pushColors(0, 0, W, H, (uint16_t *)spr.getPointer());
}

void setup() {
  Serial.begin(115200);
  pinMode(BTN_PIN, INPUT_PULLUP);
  if (!amoled.beginAMOLED_191()) {
    Serial.println("Panel init failed");
  }
  spr.createSprite(W, H);
  spr.setSwapBytes(true);
  selectSymbol(0);
  Serial.println("AMOLED Market Ticker ready");
}

void loop() {
  // button cycles symbols (falling edge)
  int b = digitalRead(BTN_PIN);
  if (b == LOW && lastBtn == HIGH) {
    selectSymbol((sym + 1) % 3);
    lastPage = millis();
  }
  lastBtn = b;

  // auto-advance pages every 6 s
  if (millis() - lastPage >= 6000) {
    lastPage = millis();
    selectSymbol((sym + 1) % 3);
  }

  // new "quote" twice a second
  if (millis() - lastTick >= 500) {
    lastTick = millis();
    simulateTick();
    drawScreen();
    Serial.print(symName);
    Serial.print(" $");
    Serial.println(price, 2);
  }

  delay(20);
}

Built with FluxBench.AI — the AI workbench for embedded projects.