本教程是的一部分: ESP32-S3 RGB LED 点阵
这是一个很棒的项目,可以使用 ESP32-S3 RGB 矩阵模块进行创作,兼具趣味性和实用性。本文下方有其他相关视频的链接。
ESP32-S3 RGB LED矩阵项目4 - 倾斜点
项目4 - 倾斜点(通过倾斜ESP32-S3 RGB LED矩阵移动点)
项目 4 引入了内置于 ESP32-S3 RGB LED 矩阵模块中的运动传感器。与自动移动点(如项目 1)或滚动文字(项目 2 和 3)不同,该项目允许您通过倾斜电路板来控制点的位置。点根据模块背面的 QMI8658C 加速度计的实时读取,平稳移动于 8×8 RGB 显示屏上。
该系列中的所有六个项目都在一个YouTube视频中演示。视频嵌入在此页面上,因此您可以看到当板子倾斜时,点如何实时移动。该项目的完整代码会自动加载在文章下方,模块的联属购买链接出现在代码部分下方。


ESP32-S3 RGB LED矩阵模块概述
该项目使用ESP32-S3 RGB LED矩阵模块,包括:

- ESP32-S3 微控制器带有Wi-Fi和蓝牙
- 8×8 RGB LED 矩阵(64个可单独控制的LED灯)
- QMI8658C 加速度计用于倾斜和运动检测的背面
- USB接口用于编程和电力
- 启动 / 重置按钮
- 可用的 GPIO 引脚用于未来扩展
QMI8658C传感器读取X,Y,和Z加速度和方向值,允许点根据板子的倾斜程度向上/下/左/右移动。:contentReference[oaicite:0]{index=0}

视频中涵盖的项目(时间戳)
- 00:00- 介绍
- 02:01- 安装ESP32板
- 03:32- 安装库
- 05:32- 项目 1:移动点
- 11:11- 项目 2:文本滚动
- 12:59- 项目 3:HTTP 文本
- 16:41-项目 4:倾斜点 (此项目)
- 18:55- 项目 5:向上箭头
- 20:02- 项目6:目标游戏
强烈推荐观看视频中的倾斜演示,因为您可以看到点如何平滑地响应板的方向。:contentReference[oaicite:1]{index=1}

在Arduino IDE中安装ESP32开发板
如果您已经完成了任何早期项目,板载支持已安装。否则,请按照以下步骤进行操作:
- 打开
File > Preferences→ 添加ESP32开发板的URL。 - 去
Tools > Board > Boards Manager…并安装ESP32. - 在下方选择您的ESP32-S3开发板
Tools > Board. - 在下面选择正确的COM端口
Tools > Port.
安装所需库
该项目需要以下库:
Adafruit NeoMatrixAdafruit NeoPixelAdafruit GFX LibraryQMI8658(运动传感器)
在库管理器中安装它们:
- 打开
Sketch > Include Library > Manage Libraries…. - 搜索Adafruit NeoMatrix→ 安装。
- 允许自动安装Adafruit GFX和Adafruit 彩灯.
- 搜索QMI8658由其列出的作者 → 安装.:contentReference[oaicite:2]{index=2}
项目4的工作原理
QMI8658C传感器持续提供沿X、Y和Z轴的加速度数据。在这个项目中,我们仅使用X和Y轴来决定:
- 点在左右(X轴)移动多远
- 将点向上或向下移动多少 (Y 轴)
传感器值被映射到从 0 到 7 的坐标范围(适用于 8×8 LED 矩阵)。点的位置每秒更新多次,随着模块的倾斜,产生平滑的滑动效果。:contentReference[oaicite:3]{index=3}
项目 4 - 代码设置(倾斜点)
以下是项目代码顶部附近的用户可编辑设置。完整的草图会在文章下方自动显示。
矩阵销和尺寸
// 8×8 RGB matrix configuration
const int MATRIX_PIN = 14; // fixed pin for this board
const int MATRIX_WIDTH = 8;
const int MATRIX_HEIGHT = 8;
离开MATRIX_PIN在14它与机载矩阵直接连接。
亮度
// Overall brightness (0–255)
uint8_t matrixBrightness = 40;
如有必要,可以增加亮度,但在近距离观看时避免极端的亮度。
点颜色
// Dot color (R, G, B)
uint8_t dotRed = 0;
uint8_t dotGreen = 200; // light green (default)
uint8_t dotBlue = 0;
更改这些值以创建任意颜色。例如:
- 红色:
(255, 0, 0) - 黄色:
(255, 255, 0) - 白色
(255, 255, 255)
运动敏感度
为了防止极端的跳变,加速度计的值通常会被限制或缩放。典型的设置如下:
// How aggressively tilt affects movement
float sensitivity = 4.0f; // larger = faster movement across screen
如果点移动得太慢 → 增加值。如果点移动得太突然 → 减少值。
更新速度(刷新率)
您可以在更新之间添加小的延迟,以平滑运动:
// Delay between position updates (ms)
int refreshDelayMs = 20; // lower = smoother and faster response
10-30毫秒之间的数值感觉非常灵敏。
摘要
项目4通过让您用物理动作控制LED矩阵,赋予ESP32-S3内置的QMI8658C加速度计生命。电路板的小幅倾斜使点在相同方向移动,使这个项目成为更高级的“箭头向上”和“靶子游戏”项目的完美跳板。
本文下方自动加载了完整的Tilt Dot草图。为了更好地理解,请观看视频中的倾斜演示,您可以看到点在旋转板子时移动得多么顺畅。在代码部分下方包含了购买ESP32-S3 RGB LED矩阵模块的链接。
本教程是……的一部分: ESP32-S3 RGB LED 点阵
- ESP32-S3 RGB LED矩阵项目 1- 基本点阵
- ESP32-S3 RGB LED矩阵项目2 - 滚动文字
- ESP32-S3 RGB LED矩阵项目3 - 手机文本
- ESP32-S3 RGB LED矩阵项目5 - 箭头始终向上
- ESP32-S3 RGB LED矩阵项目6 - Cible游戏
- ESP32-S3 RGB LED 矩阵 Wi-Fi + NTP 时钟项目 - 1 基本时钟
- ESP32-S3 RGB LED矩阵网络时钟项目 - 2个时钟多彩时间和日期显示
- ESP32-S3 RGB LED矩阵互联网时钟项目 - 带日期的3种夜间颜色
- ESP32-S3 RGB LED 矩阵网络时钟项目 - 5 种彩虹色
- ESP32-S3 RGB LED矩阵互联网时钟项目 - 4种随机颜色
- ESP32-S3 RGB LED矩阵测试,RGB,GRB设置
/*
* 项目 4:Tilt Dot - ESP32-S3 RGB LED 矩阵(Waveshare)
*
* 该示例从 QMI8658C IMU 读取倾斜数据,并根据板子方向平滑移动 8×8 RGB LED 矩阵上的点。
*
* ▶️ 视频教程:
* https://youtu.be/JKLuYrRcLMI
*
* 📚⬇️ 资源与代码页面:
* 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> // 拉哈夫·加哈利
// -------- LED 矩阵设置 --------
#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 设置 --------
QMI8658 imu;
QMI8658_Data imuData;
// -------- 用户设置 --------
// 真正 -> 对面上的点: USB↔OUSB, 34↔15
// 假 -> 点与上方在同一侧
bool useOppositeMapping = false;
// 点颜色(每个 0-255)
uint8_t dotRed = 0;
uint8_t dotGreen = 100;
uint8_t dotBlue = 0;
// 侧板
enum Side {
SIDE_CENTER = 0,
SIDE_USB,
SIDE_OUSB,
SIDE_15,
SIDE_34
};
// 平滑点位置(以像素坐标表示,但保持为浮点数以便于缓动)
float dotPosX = 3.0f; // 从中心开始
float dotPosY = 3.0f;
// 平滑因子:更小=更慢的移动(0.1 非常慢,0.5 较快)
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 "?";
}
}
// 使用校准轴检测哪个面是上面:
// +X = USB,-X = OUSB,+Y = 34,-Y = 15
Side detectSideUp(float ax_g, float ay_g, float az_g) {
// 平面检测
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;
// 说“这个轴真的倾斜”的阈值
const float tiltThreshY = 0.5f;
const float tiltThreshX = 0.5f;
// 如果明显倾斜,优先选择 15 / 34 的 Y 轴。
if (fabs(ay_g) >= tiltThreshY) {
if (ay_g > 0) {
return SIDE_15; // +Y = 34 向上
} else {
return SIDE_34; // -Y = 15 向上
}
}
// 2) 否则,检查 X 轴上的 USB / OUSB
if (fabs(ax_g) >= tiltThreshX) {
if (ax_g > 0) {
return SIDE_USB; // +X = USB 向上
} else {
return SIDE_OUSB; // -X = OUSB 向上
}
}
// 3) 如果没有明显倾斜,就称之为中心。
return SIDE_CENTER;
}
// 从UP侧到点应该去的地方的地图
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;
}
}
// 将点侧转换为矩阵坐标
void getDotPixel(Side dotSide, int &px, int &py) {
// 矩阵 (0,0) = 左上角
// 顶部中心: (3,0) → USB
// 底部中心: (3,7) → OUSB
// 左中心: (0,3) → 15
// 右中: (7,3) → 34
// 中心: (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 适用于 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);
// --- 向目标的平滑移动 ---
dotPosX += (targetX - dotPosX) * dotSmooth;
dotPosY += (targetY - dotPosY) * dotSmooth;
// 转换为整数像素坐标
int px = (int)round(dotPosX);
int py = (int)round(dotPosY);
// 以防万一夹紧
if (px < 0) px = 0;
if (px > 7) px = 7;
if (py < 0) py = 0;
if (py > 7) py = 7;
// --- 绘制点 ---
matrix.fillScreen(0);
uint16_t color = matrix.Color(dotRed, dotGreen, dotBlue);
matrix.drawPixel(px, py, color);
matrix.show();
// 调试
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);
}
|||您可能需要的东西
-
亚马逊从亚马逊购买ESP32-S3 RGB矩阵amzn.to
-
易趣从eBay购买ESP32-S3 RGB矩阵ebay.us
-
全球速卖通从AliExpress购买ESP32-S3 RGB矩阵 (2)s.click.aliexpress.com
-
全球速卖通在AliExpress上购买ESP32-S3 RGB矩阵s.click.aliexpress.com
资源与参考
-
内部颜色选择器工具robojax.com
文件📁
Fritzing 文件
-
esp32-S3-supermini-tht Fritzing 部件
esp32-S3-supermini-tht.fzpz0.02 MB