ซอฟต์แวร์ที่ใช้
ใช้ VS Code + PlatformIO กับ ESP32
- VS Code = โปรแกรมเขียนโค้ด
- PlatformIO = ส่วนเสริม (Extension) สำหรับพัฒนาไมโครคอนโทรลเลอร์

ต่อจาก VS Code + PlatformIO → ใช้ SquareLine Studio + ATD-S3 Driver + ESP32-S3 (จอ 7 นิ้ว)

บทบาทของแต่ละตัว
- SquareLine Studio 🧩
= โปรแกรมออกแบบ UI แบบลากวาง (LVGL)
→ ออกแบบปุ่ม, หน้าจอ, ตัวอักษร, Layout ได้ง่าย
→ Export เป็นโค้ด C สำหรับ LVGL

- ATD-S3 Driver Board (ESP32-S3) ⚙️
= บอร์ดควบคุมจอทัช 7 นิ้ว
→ มี Driver จอ + Touch + LVGL พร้อมใช้
→ เหมาะกับงาน HMI, Control Panel, ระบบแข่งขัน, จับเวลา - PlatformIO + VS Code 🧠
= เอาโค้ดจาก SquareLine มารวมเป็นโปรเจคจริง
→ เขียน logic ควบคุมปุ่ม, sensor, relay, timer

Flow การทำงาน
SquareLine Studio (ออกแบบ UI)
↓ Export
LVGL
↓
VSCode+ PlatformIO
↓
ATD-S3 Driver (ESP32-S3)
↓
จอ7นิ้ว + Touch Screen
โค้ดที่ใช้ main.cpp
#include <Arduino.h>
#include <lvgl.h>
#include <ATD-S3_Driver.h>
#include "gui/ui.h"
#define RELAY_PIN 10
// ===============================
// HC-SR04P CONFIG
// ===============================
#define TRIG_PIN 11
#define ECHO_PIN 12
#define STOP_DISTANCE_MIN 5
#define STOP_DISTANCE_MAX 100
unsigned long lastUltrasonicRead = 0;
float distanceCM = -1;
float readDistanceCM()
{
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) return -1;
return duration * 0.034 / 2.0;
}
// ===============================
// TIMER + COUNTDOWN VARIABLES
// ===============================
unsigned long startTime = 0;
unsigned long tick = 0;
int mode = 0; // 0=idle, 1=countdown, 2=timer
int countDown = 3;
// ===============================
// LVGL BUTTON EVENT
// ===============================
void setupLVGLEvents() {
lv_obj_add_event_cb(ui_ButStart, [](lv_event_t * e) {
if (mode == 0) {
mode = 1;
countDown = 3;
tick = millis();
lv_label_set_text(ui_LabTime, "START");
Serial.println("Start Countdown");
// Disable START button
lv_obj_add_state(ui_ButStart, LV_STATE_DISABLED);
}
}, LV_EVENT_CLICKED, NULL);
}
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
// HC-SR04P GPIO INIT
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
digitalWrite(TRIG_PIN, LOW);
// Display & Touch
Display.begin(LCD_SIZE_800x480, 1);
Touch.begin();
Display.useLVGL();
Touch.useLVGL();
Display.enableAutoSleep(120);
ui_init();
setupLVGLEvents();
lv_label_set_text(ui_LabTime, "Waiting...");
}
void readSenser() {
static unsigned long timer = 0;
if ((timer == 0) || (millis() < timer) || (millis() - timer >= 500)) {
timer = millis();
lv_label_set_text_fmt(ui_LabLV53, "%.1f", distanceCM);
}
}
void loop() {
// ===============================
// Read Ultrasonic every 200 ms
// ===============================
if (millis() - lastUltrasonicRead > 200) {
lastUltrasonicRead = millis();
distanceCM = readDistanceCM();
}
// ===============================
// COUNTDOWN 3..2..1
// ===============================
static bool beepOn = false;
static unsigned long beepTick = 0;
static unsigned long beepDuration = 0;
if (mode == 1) {
if (millis() - tick >= 1000) {
tick = millis();
if (countDown > 0) {
lv_label_set_text_fmt(ui_LabTime, "%d", countDown);
digitalWrite(RELAY_PIN, HIGH);
beepOn = true;
beepTick = millis();
beepDuration = 150;
countDown--;
} else {
lv_label_set_text(ui_LabTime, "GO!");
digitalWrite(RELAY_PIN, HIGH);
beepOn = true;
beepTick = millis();
beepDuration = 800;
mode = 2;
startTime = millis();
Serial.println("GO! Timer Started");
}
}
}
// ปิดรีเลย์ตามเวลาที่กำหนด
if (beepOn && millis() - beepTick >= beepDuration) {
digitalWrite(RELAY_PIN, LOW);
beepOn = false;
}
// ===============================
// TIMER HH:MM:SS
// ===============================
if (mode == 2) {
unsigned long t = (millis() - startTime) / 1000;
uint8_t s = t % 60;
uint8_t m = (t / 60) % 60;
uint16_t h = t / 3600;
lv_label_set_text_fmt(ui_LabTime, "%02d:%02d:%02d", h, m, s);
// ===============================
// STOP WHEN 5 < distance < 30 cm
// ===============================
if (distanceCM > STOP_DISTANCE_MIN &&
distanceCM < STOP_DISTANCE_MAX) {
mode = 0;
Serial.println("Finish! Timer Stopped");
// Enable START button again
lv_obj_clear_state(ui_ButStart, LV_STATE_DISABLED);
}
}
readSenser();
lv_timer_handler();
Display.loop();
delay(5);
}
🔧 หลักการทำงานของระบบ
ระบบจับเวลาอัตโนมัติด้วย ESP32-S3 + จอทัชสกรีน + Ultrasonic + รีเลย์ + ไซเรน
ระบบนี้เป็นระบบ Start–Timer–Stop อัตโนมัติ สำหรับงานแข่งขัน เช่น
- ปล่อยตัววิ่ง
- แข่งจักรยาน
- แข่งรถบังคับ
- จับเวลาเข้าเส้นชัย
- ระบบทดสอบความเร็ว / การเคลื่อนที่
โดยควบคุมผ่าน หน้าจอทัชสกรีน 7 นิ้ว และตรวจจับการเข้าเส้นชัยด้วย Ultrasonic Sensor
🧠 โครงสร้างระบบ (System Architecture)
[ Touch Screen 7″ ]
│
│ (LVGL GUI)
▼
[ ESP32-S3 ATD-S3 Driver ]
│ │ │
│ │ │
Relay Ultrasonic Display
(ไซเรน) (HC-SR04P) (LVGL UI)

🧩 อธิบายอุปกรณ์แต่ละตัว
1️⃣ ATD-S3 Driver ESP32-S3 + จอ 7 นิ้ว
หน้าที่:
- เป็น สมองหลักของระบบ
- ประมวลผลโค้ดทั้งหมด
- แสดงผล UI ด้วย LVGL
- รับคำสั่งจากจอทัช
- ควบคุมรีเลย์
- อ่านค่าจาก Ultrasonic Sensor
📌 ใช้ไลบรารี:
#include <lvgl.h>
#include <ATD-S3_Driver.h>
#include “gui/ui.h”
2️⃣ HC-SR04P Ultrasonic Sensor
หน้าที่:
- วัดระยะทางวัตถุด้านหน้า
- ใช้เป็น เส้นชัย (Finish Line Detection)
#define TRIG_PIN 11
#define ECHO_PIN 12
หลักการ:
- TRIG ส่งคลื่นเสียง
- ECHO รับคลื่นสะท้อน
- คำนวณระยะเป็น cm
return duration * 0.034 / 2.0;
3️⃣ Relay 5V 1 Channel
หน้าที่:
- ควบคุมไฟ 12V ให้ไซเรน
- แยกวงจรแรงดันต่ำ (ESP32) ออกจากแรงดันสูง (12V)
#define RELAY_PIN 10
4️⃣ ไซเรน 12V (ฮอร์น 4 เสียง)
หน้าที่:
- ให้สัญญาณเสียง:
- ตอนนับถอยหลัง 3..2..1
- ตอน GO!
- ใช้เป็นสัญญาณปล่อยตัว
5️⃣ ระบบไฟ
- Adapter 12V 2A → ไซเรน
- Step-down 12V → 5V → ESP32 / Relay / Sensor
- สวิตซ์ ON/OFF → เปิด-ปิดระบบทั้งชุด
⚙️ หลักการทำงานของโค้ด (Logic Flow)
🔹 โหมดการทำงาน (mode)
int mode = 0; // 0=idle, 1=countdown, 2=timer
| mode | ความหมาย |
| 0 | Idle (รอเริ่ม) |
| 1 | Countdown (3..2..1) |
| 2 | Timer (จับเวลา) |
▶️ ลำดับการทำงานของระบบ
1️⃣ Idle Mode (โหมดรอ)
- หน้าจอแสดง “Waiting…”
- ปุ่ม START ใช้งานได้
- ระบบรอคำสั่งจากผู้ใช้
2️⃣ กดปุ่ม START บนจอ
lv_obj_add_event_cb(ui_ButStart, …
สิ่งที่เกิดขึ้น:
- mode = 1
- เริ่ม Countdown
- ปิดปุ่ม START (กันกดซ้ำ)
- แสดง “START”
3️⃣ Countdown 3..2..1
ทุก 1 วินาที:
3 → 2 → 1
การทำงานร่วมกับอุปกรณ์:
- รีเลย์เปิด → ไซเรนดังสั้นๆ
- แสดงเลขบนจอ
- เสียงเตือนเป็นสัญญาณเตรียมตัว
digitalWrite(RELAY_PIN, HIGH); // เปิดไซเรน
beepDuration = 150; // เสียงสั้น
4️⃣ GO! (ปล่อยตัว)
เมื่อ Countdown = 0:
- แสดง “GO!”
- รีเลย์เปิด → ไซเรนดังยาว
- เริ่มจับเวลา
mode = 2;
startTime = millis();
5️⃣ Timer Mode (จับเวลา)
ระบบเริ่มนับเวลาแบบ:
HH:MM:SS
แสดงบนจอ:
lv_label_set_text_fmt(ui_LabTime, “%02d:%02d:%02d”, h, m, s);
6️⃣ Ultrasonic ตรวจจับเส้นชัย
อ่านค่าระยะทุก 200 ms:
distanceCM = readDistanceCM();
เงื่อนไขหยุดเวลา:
if (distanceCM > 5 && distanceCM < 100)
หมายความว่า:
เมื่อมีวัตถุเข้าใกล้เซนเซอร์ในระยะ 5–100 cm
→ ถือว่า “เข้าเส้นชัย”
7️⃣ Stop Timer (หยุดจับเวลา)
เมื่อเข้าเงื่อนไข:
- mode = 0
- หยุดเวลา
- แสดงเวลาสุดท้าย
- เปิดปุ่ม START ใหม่
lv_obj_clear_state(ui_ButStart, LV_STATE_DISABLED);
🔄 Flow Diagram
[Waiting]
│
│ กด START
▼
[Countdown 3..2..1]
│
│ GO!
▼
[Timer Running]
│
│ Ultrasonic ตรวจจับวัตถุ
▼
[Stop Timer]
│
└── กลับไป Waiting

🎯 ภาพรวมการทำงาน
| อุปกรณ์ | หน้าที่ |
| จอ 7 นิ้ว | ควบคุมระบบ + แสดงเวลา |
| ESP32-S3 | ประมวลผลทั้งหมด |
| Ultrasonic | ตรวจจับเข้าเส้นชัย |
| Relay | เปิด-ปิดไซเรน |
| ไซเรน | สัญญาณเริ่มแข่ง |
| Step-down | ลดไฟ 12V → 5V |
| Adapter 12V | แหล่งจ่ายไฟหลัก |
🏁 สรุปแนวคิดระบบ (Concept)
เป็นระบบ Smart Race Timer
- ปล่อยตัวอัตโนมัติ
- จับเวลาอัตโนมัติ
- หยุดเวลาอัตโนมัติ
- ควบคุมด้วยจอทัช
- ไม่ต้องใช้กรรมการกดจับเวลา
- ลด Human Error
- ใช้เซนเซอร์แทนคน
อุปกรณ์ที่ใช้
1-บอร์ด ESP32-S3 + จอทัชสกรีน 7 นิ้ว
2- HC-SR04P Ultrasonic Ranging Sensor 3-5.5V
3-Jumper (F2F) cable 20cm Female to Female
4-ฮอร์นไซเรน ลำโพง 4เสียง มอเตอร์ไซค์ และรถยนต์ 12V
5-Relay 1 Channel DC 5V High Level Trigger
6-Adapter DC 12V 2A Power Supply
7-สายไฟแดงดำ ขนาด 22AWG
8-เพาเวอร์สวิตซ์สำหรับเปิดปิด (ON / OFF Rocker Switch)
9-กล่องกันน้ำพลาสติก Leetech
10- DC 5V Step-down Power Supply Module