Garage_Display — ESP32 simulation

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

Components

Sketch code

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

// CYD Display Hardware Pins
#define CYD_TFT_CS    15
#define CYD_TFT_DC     2
#define CYD_TFT_MOSI  13
#define CYD_TFT_SCLK  14
#define CYD_TFT_MISO  12
#define CYD_TFT_RST    4
#define CYD_TFT_BL    21

// Ultrasonic Sensor Pins
const int trigPin = 22; // RCWL-1605 Trigger
const int echoPin = 35; // RCWL-1605 Echo

// Exit Pushbutton Pin
const int buttonPin = 27; // Active LOW (internal pull-up)

// Interrupt flag for exit handling
volatile bool isHalted = false;

// Hardware SPI bus for Display
SPIClass hspi = SPIClass(HSPI);
Adafruit_ILI9341 tft = Adafruit_ILI9341(&hspi, CYD_TFT_DC, CYD_TFT_CS, CYD_TFT_RST);

void IRAM_ATTR handleButtonPress() {
  isHalted = true;
}

void setup() {
  Serial.begin(115200);

  // Reset Display Controller
  pinMode(CYD_TFT_RST, OUTPUT);
  digitalWrite(CYD_TFT_RST, LOW);
  delay(10);
  digitalWrite(CYD_TFT_RST, HIGH);
  delay(50);

  // Power Backlight
  pinMode(CYD_TFT_BL, OUTPUT);
  digitalWrite(CYD_TFT_BL, HIGH);

  // Configure Button Input with Hardware Interrupt
  pinMode(buttonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(buttonPin), handleButtonPress, FALLING);

  // Initialize display hardware SPI
  hspi.begin(CYD_TFT_SCLK, CYD_TFT_MISO, CYD_TFT_MOSI, CYD_TFT_CS);
  tft.begin();
  tft.setRotation(1); // Landscape
  tft.fillScreen(ILI9341_BLACK);

  // Configure Ultrasonic Sensor
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

void loop() {
  if (isHalted) {
    stopProgram();
    while (true) {
      delay(100);
    }
  }

  // Trigger sensor pulse
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  // Read echo pulse
  unsigned long duration = pulseIn(echoPin, HIGH, 60000); 

  char displayBuf[16];

  if (duration == 0) {
    snprintf(displayBuf, sizeof(displayBuf), "---      ");
  } else {
    long mm = 0;

    // Velxio piecewise range translation
    if (duration <= 23) {
      // Direct raw lower range
      mm = duration * 10;
    } else if (duration > 23 && duration <= 500) {
      // Scale break range 1 (maps slider values above 23)
      mm = (duration * 58) / 10; 
    } else {
      // Upper microsecond pulse calculation
      mm = (long)((duration * 0.343) / 2.0);
    }

    // Clamp maximum sensor boundary
    if (mm > 4000) {
      snprintf(displayBuf, sizeof(displayBuf), "Out of Range");
    } else {
      snprintf(displayBuf, sizeof(displayBuf), "%ldmm   ", mm);
    }
  }

  // Draw directly to screen
  drawDirectText(displayBuf, 40, 70);

  delay(100); 
}

void stopProgram() {
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.setCursor(70, 110);
  tft.println("Program Stopped");
}

void drawDirectText(const char* txt, int posX, int posY) {
  tft.setCursor(posX, posY);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setTextSize(5);
  tft.print(txt);