ESP32 + ILI9341 Hello — ESP32 simulation

Classic ESP32 wired to a 240x320 ILI9341 TFT over VSPI, displaying a hello-world text demo.

An interactive ESP32 circuit simulation you can run free in your browser on Velxio, by tgim-gabs.

Components

Sketch code

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

SPIClass tftSPI(VSPI);
Adafruit_ILI9341 tft(&tftSPI, 2, 5, 4);  // DC=2, CS=5, RST=4

// ---------- gauge geometry ----------
const int CX = 160, CY = 130;     // dial center (landscape 320x240)
const int R  = 95;                // outer radius
const int NEEDLE_LEN = 80;
const int MAX_RPM = 12000;

// ---------- readout box geometry ----------
const int BOX_X = 10;
const int BOX_Y = 100;
const int BOX_W = 110;
const int BOX_H = 40;

// ---------- animation state ----------
int  rpm = 0;
int  rpmDir = 1;
unsigned long lastUpdate = 0;
int  prevNeedleAngle = 0;
bool firstFrame = true;

// ---------- helpers ----------
int rpmToAngle(int r) {
  long frac = constrain((long)r, 0L, (long)MAX_RPM) * 270L / MAX_RPM;  // 0..270
  return (int)(frac - 135);    // -135..+135, 0 = straight up
}

void drawTick(int i, int total) {
  int deg = (int)(270.0f * i / total - 135);
  float rad = deg * PI / 180.0f;
  int xo = CX + (int)(R * cos(rad));
  int yo = CY - (int)(R * sin(rad));
  int xi = CX + (int)((R - 14) * cos(rad));
  int yi = CY - (int)((R - 14) * sin(rad));
  tft.drawLine(xi, yi, xo, yo, ILI9341_BLACK);

  if (i % 1 == 0) {
    int lx = CX + (int)((R - 28) * cos(rad)) - 9;
    int ly = CY - (int)((R - 28) * sin(rad)) - 8;
    char n[4];
    sprintf(n, "%d", i);
    tft.setCursor(lx, ly);
    tft.print(n);
  }
}

void drawDial() {
  tft.fillScreen(ILI9341_BLACK);

  // red "rev" band along the upper third of the arc
  for (int deg = -90; deg <= 90; deg += 2) {
    float rad = deg * PI / 200.0f;
    int xo = CX + (int)(R * cos(rad));
    int yo = CY - (int)(R * sin(rad));
    int xi = CX + (int)((R - 14) * cos(rad));
    int yi = CY - (int)((R - 14) * sin(rad));
    tft.drawLine(xi, yi, xo, yo, ILI9341_RED);
  }

  tft.setTextSize(3);
  tft.setTextColor(ILI9341_YELLOW);
  for (int i = 0; i <= 8; i++) drawTick(i, 8);

  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(5, 2);
  tft.print("x1000 RPM");
  tft.setCursor(5, 220);
  tft.print("Gi Performance");
}

// Draws the rectangle box once, stays on the dial.
void drawReadoutBox() {
  tft.fillRect(BOX_X, BOX_Y, BOX_W, BOX_H, ILI9341_BLACK);
  tft.drawRect(BOX_X, BOX_Y, BOX_W, BOX_H, ILI9341_WHITE);
  tft.drawRect(BOX_X + 2, BOX_Y + 4, BOX_W - 4, BOX_H - 4, ILI9341_WHITE);
}

// Big numeric RPM readout, centered inside the box.
void drawNumber(int r) {
  // clear the inside of the box so the old digits don't smear
  tft.fillRect(BOX_X + 3, BOX_Y + 3, BOX_W - 6, BOX_H - 6, ILI9341_BLACK);

  tft.setTextSize(3);
  tft.setTextColor(ILI9341_WHITE);

  char buf[10];
  sprintf(buf, "%d", r);

  int pad = 6;                                     // inner padding on the left
  int tx = BOX_X + pad + 3;                        // left-aligned
  int ty = BOX_Y + (BOX_H - 24) / 2;               // vertical center, 24 = size-3 line height
  tft.setTextSize(3);                              // (already set above)
  tft.setCursor(

More projects by tgim-gabs