This tutorial is part of: Ma trận LED RGB ESP32-S3
Đây là một dự án thú vị và hữu ích sử dụng module ma trận RGB ESP32-S3. Các liên kết đến các video khác được cung cấp bên dưới bài viết này.
Dự án Ma trận LED RGB ESP32-S3 4 - Chấm nghiêng
Dự án 4 – Chấm Nghiêng (Di Chuyển Chấm Bằng Cách Nghiêng ESP32-S3 RGB LED Matrix)
Dự án 4 giới thiệu cảm biến chuyển động được tích hợp trong mô-đun ESP32-S3 RGB LED Matrix. Thay vì tự động di chuyển chấm (như Dự án 1) hoặc cuộn chữ (Dự án 2 và 3), dự án này cho phép bạn điều khiển vị trí của chấm chỉ bằng cách nghiêng bo mạch. Chấm di chuyển mượt mà trên màn hình RGB 8×8 dựa trên số liệu trực tiếp từ gia tốc kế QMI8658C ở mặt sau của mô-đun.
Tất cả sáu dự án trong loạt bài này được trình diễn trong một video YouTube. Video tương tự cũng được nhúng trên trang này, để bạn có thể thấy chính xác cách chấm di chuyển trong thời gian thực khi bo mạch nghiêng. Mã hoàn chỉnh cho dự án này được tải tự động bên dưới bài viết, và các liên kết mua hàng liên kết cho mô-đun xuất hiện dưới phần mã.


Tổng Quan Về Mô-đun ESP32-S3 RGB LED Matrix
Dự án này sử dụng mô-đun ESP32-S3 RGB LED Matrix, bao gồm:

- Vi điều khiển ESP32-S3 với Wi-Fi và Bluetooth
- Ma trận LED RGB 8×8 (64 đèn LED có thể định địa chỉ riêng lẻ)
- Gia tốc kế QMI8658C ở mặt sau để phát hiện độ nghiêng và chuyển động
- Cổng USB để lập trình và cấp nguồn
- Các nút Boot / Reset
- Các chân GPIO có thể sử dụng để mở rộng trong tương lai
Cảm biến QMI8658C đọc các giá trị gia tốc và hướng theo trục X, Y và Z, cho phép chấm di chuyển lên/xuống/trái/phải dựa trên cách bo mạch được nghiêng.

Các Dự Án Được Trình Bày Trong Video (Mốc Thời Gian)
- 00:00 – Giới thiệu
- 02:01 – Cài đặt bo mạch ESP32
- 03:32 – Cài đặt thư viện
- 05:32 – Dự án 1: Chấm Di Chuyển
- 11:11 – Dự án 2: Cuộn Chữ
- 12:59 – Dự án 3: Văn Bản HTTP
- 16:41 – Dự án 4: Chấm Nghiêng (dự án này)
- 18:55 – Dự án 5: Mũi Tên Lên
- 20:02 – Dự án 6: Trò Chơi Bắn Mục Tiêu
Xem phần trình diễn độ nghiêng trong video được khuyến khích cao, vì bạn có thể thấy cách chấm phản ứng mượt mà với hướng của bo mạch.

Cài Đặt Bo Mạch ESP32 Trong Arduino IDE
Nếu bạn đã hoàn thành bất kỳ dự án nào trước đó, hỗ trợ bo mạch đã được cài đặt sẵn. Nếu không, hãy làm theo các bước sau:
- Mở
File > Preferences→ Thêm URL ESP32 Boards. - Đi tới
Tools > Board > Boards Manager…và cài đặt ESP32. - Chọn bo mạch ESP32-S3 của bạn trong
Tools > Board. - Chọn đúng cổng COM trong
Tools > Port.
Cài Đặt Các Thư Viện Cần Thiết
Dự án này yêu cầu các thư viện sau:
Adafruit NeoMatrixAdafruit NeoPixelAdafruit GFX LibraryQMI8658(cảm biến chuyển động)
Cài đặt chúng trong Library Manager:
- Mở
Sketch > Include Library > Manage Libraries…. - Tìm kiếm Adafruit NeoMatrix → Cài đặt.
- Cho phép cài đặt tự động Adafruit GFX và Adafruit NeoPixel.
- Tìm kiếm QMI8658 theo tác giả được liệt kê → Cài đặt.
Cách Dự Án 4 Hoạt Động
Cảm biến QMI8658C liên tục cung cấp dữ liệu gia tốc dọc theo các trục X, Y và Z. Đối với dự án này, chúng ta chỉ sử dụng trục X và Y để quyết định:
- Khoảng cách di chuyển của chấm sang trái hoặc phải (trục X)
- Khoảng cách di chuyển của chấm lên hoặc xuống (trục Y)
Các giá trị cảm biến được ánh xạ vào phạm vi tọa độ từ 0 đến 7 (cho ma trận LED 8×8). Vị trí chấm được cập nhật nhiều lần mỗi giây, tạo hiệu ứng trượt mượt mà khi bạn nghiêng mô-đun.
Dự án 4 – Cài Đặt Mã (Chấm Nghiêng)
Dưới đây là các cài đặt người dùng có thể chỉnh sửa được tìm thấy gần đầu mã của dự án. Bản phác thảo đầy đủ xuất hiện tự động bên dưới bài viết.
Chân và Kích Thước Ma Trận
// Cấu hình ma trận RGB 8×8
const int MATRIX_PIN = 14; // chân cố định cho bo mạch này
const int MATRIX_WIDTH = 8;
const int MATRIX_HEIGHT = 8;
Giữ nguyên MATRIX_PIN ở giá trị 14. Nó được nối cứng với ma trận trên bo mạch.
Độ Sáng
// Độ sáng tổng thể (0–255)
uint8_t matrixBrightness = 40;
Tăng nếu cần, nhưng tránh độ sáng quá cao khi nhìn ở khoảng cách gần.
Màu Chấm
// Màu chấm (R, G, B)
uint8_t dotRed = 0;
uint8_t dotGreen = 200; // xanh lá nhạt (mặc định)
uint8_t dotBlue = 0;
Thay đổi các giá trị này để tạo bất kỳ màu nào. Ví dụ:
- Đỏ:
(255, 0, 0) - Vàng:
(255, 255, 0) - Trắng:
(255, 255, 255)
Độ Nhạy Chuyển Động
Để tránh các bước nhảy quá lớn, các giá trị gia tốc kế thường được giới hạn hoặc chia tỷ lệ. Một cài đặt điển hình trông như:
// Mức độ ảnh hưởng của độ nghiêng đến chuyển động
float sensitivity = 4.0f; // lớn hơn = di chuyển nhanh hơn trên màn hình
Nếu chấm di chuyển quá chậm → tăng giá trị. Nếu chấm di chuyển quá đột ngột → giảm giá trị.
Tốc Độ Cập Nhật (Tần Suất Làm Mới)
Bạn có thể thêm một khoảng trễ nhỏ giữa các lần cập nhật để chuyển động mượt mà hơn:
// Độ trễ giữa các lần cập nhật vị trí (ms)
int refreshDelayMs = 20; // thấp hơn = phản hồi mượt và nhanh hơn
Các giá trị từ 10–30 ms sẽ cho cảm giác rất nhạy bén.
Tóm tắt
Dự án 4 đưa cảm biến gia tốc QMI8658C tích hợp trên ESP32-S3 vào hoạt động bằng cách cho phép bạn điều khiển ma trận LED bằng chuyển động vật lý. Một cú nghiêng nhỏ của bo mạch sẽ di chuyển chấm theo cùng hướng, biến dự án này thành bước đệm hoàn hảo cho các dự án nâng cao hơn như “Mũi tên lên” và “Trò chơi bắn mục tiêu”.
Mã nguồn đầy đủ của Tilt Dot được tải bên dưới bài viết này (tự động). Để hiểu rõ nhất, hãy xem phần trình diễn độ nghiêng trong video, nơi bạn có thể thấy chấm di chuyển mượt mà như thế nào khi bo mạch được xoay. Liên kết mua mô-đun ESP32-S3 RGB LED Matrix được bao gồm dưới phần mã nguồn.
This tutorial is part of: Ma trận LED RGB ESP32-S3
- Dự án Ma trận LED RGB ESP32-S3 1- Chấm cơ bản
- Dự án Ma trận LED RGB ESP32-S3 2 - Văn bản cuộn
- Dự án ma trận LED RGB ESP32-S3 3 - Văn bản từ điện thoại di động
- Dự án Ma trận LED RGB ESP32-S3 5 - Mũi tên luôn hướng lên
- Dự án Ma trận LED RGB ESP32-S3 6 - Trò chơi Cible
- Dự án Đồng hồ thời gian Wi-Fi + NTP sử dụng ma trận LED RGB ESP32-S3 - 1 Đồng hồ cơ bản
- Dự án Đồng hồ Internet Ma trận LED RGB ESP32-S3 - Hiển thị Thời gian & Ngày tháng 2 Đồng hồ đa màu sắc
- Dự án Đồng hồ Internet Ma trận LED RGB ESP32-S3 - 3 Màu Ban Đêm kèm Ngày
- Dự án Đồng hồ Internet Ma trận LED RGB ESP32-S3 - 5 Màu cầu vồng
- Dự án Đồng hồ Internet Ma trận LED RGB ESP32-S3 - 4 màu ngẫu nhiên
- ESP32-S3 RGB LED Matrix test for RGB, GRB setting
/*
Project 4: Tilt Dot – ESP32-S3 RGB LED Matrix (Waveshare)
This sketch reads tilt from the QMI8658C IMU and smoothly moves a dot
on the 8×8 RGB LED matrix based on board orientation.
▶️ Video Tutorial:
https://youtu.be/JKLuYrRcLMI
📚⬇️ Resources & Code Page:
https://robojax.com/RJT829
QMI8658_RGB_2
*/
#include <Arduino.h>
#include <math.h>
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#include <QMI8658.h> // by Lahav Gahali
// -------- LED MATRIX SETUP --------
#define MATRIX_PIN 14
#define MATRIX_WIDTH 8
#define MATRIX_HEIGHT 8
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(
MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
NEO_RGB + NEO_KHZ800
);
// -------- QMI8658 IMU SETUP --------
QMI8658 imu;
QMI8658_Data imuData;
// -------- USER SETTINGS --------
// true -> dot on opposite side: USB↔OUSB, 34↔15
// false -> dot on same side as UP
bool useOppositeMapping = false;
// Dot color (0–255 each)
uint8_t dotRed = 0;
uint8_t dotGreen = 100;
uint8_t dotBlue = 0;
// Board sides
enum Side {
SIDE_CENTER = 0,
SIDE_USB,
SIDE_OUSB,
SIDE_15,
SIDE_34
};
// Smooth dot position (in pixel coordinates, but kept as float for easing)
float dotPosX = 3.0f; // start at center
float dotPosY = 3.0f;
// Smoothing factor: smaller = slower movement (0.1 very slow, 0.5 faster)
const float dotSmooth = 0.25f;
bool isFlat = false;
const char* sideName(Side s) {
switch (s) {
case SIDE_CENTER: return "CENTER";
case SIDE_USB: return "USB";
case SIDE_OUSB: return "OUSB";
case SIDE_15: return "15";
case SIDE_34: return "34";
default: return "?";
}
}
// Detect which side is UP using calibrated axes:
// +X = USB, -X = OUSB, +Y = 34, -Y = 15
Side detectSideUp(float ax_g, float ay_g, float az_g) {
// Flat detection
const float flatThreshXY = 0.15f;
const float flatThreshZ = 0.15f;
if (fabs(ax_g) < flatThreshXY &&
fabs(ay_g) < flatThreshXY &&
fabs(az_g - 1.0f) < flatThreshZ) {
isFlat = true;
return SIDE_CENTER;
}
isFlat = false;
// Thresholds to say "this axis is really tilted"
const float tiltThreshY = 0.5f;
const float tiltThreshX = 0.5f;
// 1) Prefer Y axis for 15 / 34 if it's clearly tilted
if (fabs(ay_g) >= tiltThreshY) {
if (ay_g > 0) {
return SIDE_15; // +Y = 34 up
} else {
return SIDE_34; // -Y = 15 up
}
}
// 2) Otherwise, check X axis for USB / OUSB
if (fabs(ax_g) >= tiltThreshX) {
if (ax_g > 0) {
return SIDE_USB; // +X = USB up
} else {
return SIDE_OUSB; // -X = OUSB up
}
}
// 3) If nothing is strongly tilted, just call it CENTER
return SIDE_CENTER;
}
// Map from UP side to where the dot should go
Side dotSideFromUpSide(Side upSide) {
switch (upSide) {
case SIDE_USB:
return useOppositeMapping ? SIDE_OUSB : SIDE_USB;
case SIDE_OUSB:
return useOppositeMapping ? SIDE_USB : SIDE_OUSB;
case SIDE_34:
return useOppositeMapping ? SIDE_15 : SIDE_34;
case SIDE_15:
return useOppositeMapping ? SIDE_34 : SIDE_15;
case SIDE_CENTER:
default:
return SIDE_CENTER;
}
}
// Convert dot side to matrix coordinates
void getDotPixel(Side dotSide, int &px, int &py) {
// Matrix (0,0) = top-left
// top center: (3,0) → USB
// bottom center: (3,7) → OUSB
// left center: (0,3) → 15
// right center: (7,3) → 34
// center: (3,3)
switch (dotSide) {
case SIDE_USB: px = 3; py = 0; break;
case SIDE_OUSB: px = 3; py = 7; break;
case SIDE_15: px = 0; py = 3; break;
case SIDE_34: px = 7; py = 3; break;
case SIDE_CENTER:
default: px = 3; py = 3; break;
}
}
void setup() {
Serial.begin(115200);
delay(500);
matrix.begin();
matrix.setBrightness(20);
matrix.fillScreen(0);
matrix.show();
// IMU: SDA=11, SCL=12 for ESP32-S3-Matrix
if (!imu.begin(11, 12)) {
Serial.println("Failed to initialize QMI8658!");
while (1) { delay(1000); }
}
imu.setAccelUnit_mg(true);
imu.setGyroUnit_dps(true);
imu.setDisplayPrecision(4);
Serial.print("QMI8658 initialized. useOppositeMapping = ");
Serial.println(useOppositeMapping ? "TRUE" : "FALSE");
}
void loop() {
if (!imu.readSensorData(imuData)) {
return;
}
float ax_g = imuData.accelX / 1000.0f;
float ay_g = imuData.accelY / 1000.0f;
float az_g = imuData.accelZ / 1000.0f;
Side upSide = detectSideUp(ax_g, ay_g, az_g);
Side dotSide = dotSideFromUpSide(upSide);
int targetX, targetY;
getDotPixel(dotSide, targetX, targetY);
// --- Smooth movement toward target ---
dotPosX += (targetX - dotPosX) * dotSmooth;
dotPosY += (targetY - dotPosY) * dotSmooth;
// Convert to integer pixel coordinates
int px = (int)round(dotPosX);
int py = (int)round(dotPosY);
// Clamp just in case
if (px < 0) px = 0;
if (px > 7) px = 7;
if (py < 0) py = 0;
if (py > 7) py = 7;
// --- Draw dot ---
matrix.fillScreen(0);
uint16_t color = matrix.Color(dotRed, dotGreen, dotBlue);
matrix.drawPixel(px, py, color);
matrix.show();
// Debug
Serial.print("AX="); Serial.print(ax_g, 3);
Serial.print(" AY="); Serial.print(ay_g, 3);
Serial.print(" AZ="); Serial.print(az_g, 3);
Serial.print(" | UP="); Serial.print(sideName(upSide));
Serial.print(" | DOT="); Serial.print(sideName(dotSide));
Serial.print(" | px="); Serial.print(px);
Serial.print(" py="); Serial.println(py);
delay(80);
}
Nghĩ bạn có thể cần
-
Amazon
-
eBay
-
AliExpressPurchase ESP32-S3 RGB Matrix from AliExpresss.click.aliexpress.com
-
AliExpressPurchase ESP32-S3 RGB Matrix from AliExpress (2)s.click.aliexpress.com
Tài nguyên & tài liệu tham khảo
-
Nội bộ🎨 Color picker Toolrobojax.com
Tập tin📁
Tập tin Fritzing
-
esp32-S3-supermini-tht fritzing part
esp32-S3-supermini-tht.fzpz0.02 MB