- 机器人等级考试
ESP32 for Arduino 学习笔记教程:点阵屏与 millis() 应用
- 2025-7-23 19:21:56 @
ESP32 for Arduino 学习笔记教程:点阵屏与 millis() 应用
一、课程目标
- 掌握 ESP32 引脚模式配置,实现硬件控制
- 学会使用
millis()
函数实现非阻塞延时,替代delay()
- 理解点阵屏驱动原理,实现图案动态切换显示
- 掌握移位寄存器控制方法(
shiftOut
函数应用 )
二、核心知识点回顾
1. 引脚模式配置
- 函数:
pinMode(引脚编号, 模式)
- 模式包含
INPUT
(输入)、OUTPUT
(输出)等 - 例:
pinMode(13, OUTPUT);
配置引脚 13 为输出模式,用于控制点阵屏锁存信号
- 模式包含
2. millis()
函数
- 功能:获取程序启动后经过的毫秒数,实现非阻塞延时
- 优势:相比
delay()
,不会阻塞程序执行,可同时处理多个任务 - 用法:
unsigned long currentTime = millis();
结合逻辑判断实现延时,如:
if (millis() - oldTime >= 1000) {
// 执行延时 1 秒后的操作
oldTime = millis(); // 更新时间标记
}
3. 点阵屏驱动原理
- 通过移位寄存器(如 74HC595)控制:
- 行数据(
Rowdata
):控制点亮哪一行 - 列数据(
COLdata
):控制该行哪些点点亮
- 行数据(
- 核心函数
shiftOut(数据引脚, 时钟引脚, 数据顺序, 数据)
:将数据逐位移位输出到寄存器
三、代码实战与解析
完整代码(带详细注释)
// 点阵屏控制引脚定义
const int LPin = 13, CPin = 14, DPin = 15;
// LPin: 锁存引脚 | CPin: 时钟引脚 | DPin: 数据引脚
byte Rowdata, COLdata; // 存储行、列数据
// 图案定义(8x8 点阵)
// 小爱心图案
byte small[8] = {0x00, 0x00, 0x00, 0x14, 0x3E, 0x1C, 0x08, 0x00};
// 大爱心图案
byte big[8] = {0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18};
// 全局变量(用于 millis() 非阻塞延时)
// 记录上一次状态切换的时间
long long oldTime = 0;
// 控制图案显示状态(小爱心/大爱心)
boolean ledState = false;
void setup() {
// 配置控制引脚为输出模式
pinMode(LPin, OUTPUT);
pinMode(CPin, OUTPUT);
pinMode(DPin, OUTPUT);
// 初始状态设置
// 锁存引脚低电平,允许数据输入
digitalWrite(LPin, LOW);
// 时钟引脚初始化为低
digitalWrite(CPin, LOW);
// 初始化串口通信(波特率 115200),用于调试输出
Serial.begin(115200);
}
void loop() {
// 非阻塞延时:每隔 1000 毫秒(1 秒)切换状态
if (millis() - oldTime >= 1000) {
oldTime = millis(); // 更新时间标记
ledState = !ledState; // 切换显示状态(小爱心 ↔ 大爱心)
Serial.println(ledState); // 串口打印状态(调试用)
}
// 根据状态显示对应图案
if (ledState == false) {
displayImages(small); // 显示小爱心
} else {
displayImages(big); // 显示大爱心
}
}
// 点阵屏显示函数:逐行输出图案数据
void displayImages(byte imgs[]) {
for (int row = 0; row < 8; row++) { // 遍历 8 行
// 生成行数据:每次只点亮一行(通过位运算 0b1 << row 实现)
Rowdata = 0b1 << row;
// 列数据:对图案数据取反(根据硬件电路决定是否需要取反)
COLdata = ~imgs[row];
matrixDisplay(); // 输出行、列数据到点阵屏
delay(1); // 短暂延时,保证显示稳定
}
}
// 矩阵显示核心函数:通过移位寄存器输出数据
void matrixDisplay() {
// 先发送列数据到移位寄存器
shiftOut(DPin, CPin, MSBFIRST, COLdata);
// 再发送行数据到移位寄存器
shiftOut(DPin, CPin, MSBFIRST, Rowdata);
// 锁存引脚置高,将移位寄存器数据更新到点阵屏(点亮对应点)
digitalWrite(LPin, LOW);
// 锁存引脚置低,准备下一次数据传输
digitalWrite(LPin, HIGH);
}
代码分步解析
1. 引脚与图案定义
const int LPin = 13, CPin = 14, DPin = 15;
byte Rowdata, COLdata;
byte small[8] = {0x00, 0x00, 0x00, 0x14, 0x3E, 0x1C, 0x08, 0x00};
byte big[8] = {0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18};
- 定义点阵屏控制引脚:
LPin
(锁存)、CPin
(时钟)、DPin
(数据) - 定义两个图案数组
small
(小爱心)和big
(大爱心),每个数组存储 8 字节数据,对应 8x8 点阵的一行
2. setup()
函数:初始化配置
void setup() {
pinMode(LPin, OUTPUT);
pinMode(CPin, OUTPUT);
pinMode(DPin, OUTPUT);
digitalWrite(LPin, LOW);
digitalWrite(CPin, LOW);
Serial.begin(115200);
}
- 配置引脚为输出模式,准备控制点阵屏
- 初始化引脚电平:
LPin
和CPin
置低,保证初始状态正确 - 启动串口通信,波特率 115200,用于调试输出
3. loop()
函数:主逻辑循环
void loop() {
if (millis() - oldTime >= 1000) {
oldTime = millis();
ledState = !ledState;
Serial.println(ledState);
}
if (ledState == false) {
displayImages(small);
} else {
displayImages(big);
}
}
- 非阻塞延时:通过
millis() - oldTime >= 1000
判断是否达到 1 秒,达到则切换ledState
状态 - 图案切换:根据
ledState
的值,调用displayImages()
显示对应图案
4. displayImages()
函数:逐行处理图案数据
void displayImages(byte imgs[]) {
for (int row = 0; row < 8; row++) {
Rowdata = 0b1 << row;
COLdata = ~imgs[row];
matrixDisplay();
delay(1);
}
}
- 遍历 8 行,逐行生成行数据(
Rowdata
)和列数据(COLdata
) - 调用
matrixDisplay()
输出数据到点阵屏,delay(1)
保证显示稳定
5. matrixDisplay()
函数:移位寄存器操作
void matrixDisplay() {
shiftOut(DPin, CPin, MSBFIRST, COLdata);
shiftOut(DPin, CPin, MSBFIRST, Rowdata);
digitalWrite(LPin, LOW);
digitalWrite(LPin, HIGH);
}
shiftOut()
函数:按MSBFIRST
(高位先送)的顺序,通过DPin
(数据)和CPin
(时钟)将数据输出到移位寄存器digitalWrite(LPin, LOW/HIGH)
:通过锁存引脚电平变化,将移位寄存器中的数据“锁存”到点阵屏,实现点亮操作
四、硬件连接说明
- 点阵屏与 ESP32 引脚对应:
LPin
(13 脚)→ 点阵屏锁存引脚CPin
(14 脚)→ 点阵屏时钟引脚DPin
(15 脚)→ 点阵屏数据引脚
- 移位寄存器(如 74HC595):若使用外部移位寄存器,需将
DPin
、CPin
连接到移位寄存器对应引脚,再由移位寄存器控制点阵屏
五、常见问题与解决
1. 图案显示异常(如乱码、缺行)
- 检查:
- 图案数组
small
、big
的数据是否正确(可通过字模提取软件重新生成) COLdata = ~imgs[row];
中的取反操作是否必要(根据硬件电路调整,若不需要取反则删除~
)
- 图案数组
- 解决:重新校准图案数据,或调整取反逻辑
2. 延时不精准(millis()
失效)
- 检查:
- 全局变量
oldTime
是否为long long
类型(避免溢出) - 程序中是否有其他长时间阻塞操作(如
delay(1000)
会干扰millis()
判断)
- 全局变量
- 解决:确保
oldTime
类型正确,用millis()
替代所有delay()
3. 串口无输出(Serial.println
失效)
- 检查:
setup()
中是否调用Serial.begin(115200);
- 串口监视器波特率是否为 115200
- 解决:添加
Serial.begin()
,并匹配串口监视器波特率
六、拓展练习
- 添加更多图案:用字模提取软件生成新图案(如笑脸、箭头),实现多图案循环切换
- 优化显示效果:通过
analogWrite()
实现点阵屏亮度调节 - 结合传感器:读取光线传感器数据,根据环境亮度自动切换图案显示频率
通过本节课,你已掌握 ESP32 点阵屏驱动、millis()
非阻塞延时的核心用法。继续拓展练习,可实现更复杂的交互效果!
2 条评论
-
admin SU @ 2025-7-23 19:22:25
// LED矩阵控制引脚定义 const int LPin = 13, CPin = 14, DPin = 15; // LPin:锁存引脚, CPin:时钟引脚, DPin:数据引脚 byte Rowdata, COLdata; // 行数据和列数据存储变量 byte imgs[8] = { /*-- 调入了一幅图像:这是您新建的图像 --*/ /*-- 宽度x高度=8x8 --*/ 0x10, 0x38, 0x7C, 0xFE, 0x38, 0x38, 0x38, 0x38 }; byte small[8] = {//小爱心 /*-- 调入了一幅图像:这是您新建的图像 --*/ /*-- 宽度x高度=8x8 --*/ 0x00, 0x00, 0x00, 0x14, 0x3E, 0x1C, 0x08, 0x00 }; byte big[8] = {//大爱心 /*-- 调入了一幅图像:这是您新建的图像 --*/ /*-- 宽度x高度=8x8 --*/ 0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18 }; void setup() { // 初始化控制引脚为输出模式 pinMode(LPin, OUTPUT); pinMode(CPin, OUTPUT); pinMode(DPin, OUTPUT); // 初始状态设置 digitalWrite(LPin, LOW); // 锁存引脚低电平,允许数据输入 digitalWrite(CPin, LOW); // 时钟引脚初始化为低 // 设置PWM分辨率为10位(0-1023),虽然此处未使用PWM功能 // analogSetWidth(10); Serial.begin(115200); } long long oldTime = 0;//旧的时间 boolean ledState = false;//小灯的状态 void loop() { if (millis() - oldTime >= 1000) { oldTime = millis();//更新旧的时间 ledState = !ledState;//把状态更新一下 Serial.println(ledState); //digitalWrite(25, ledState); } if(ledState == false){ displayImages(small); }else{ displayImages(big); } } void displayImages(byte imges[]) {// 点阵显示函数:把图形数据输出到移位寄存器,控制点阵点亮 for (int row = 0; row < 8; row++) { // 逐行处理 Rowdata = 0b1 << row; COLdata = ~imgs[row]; matrixDisplay(); delay(1); // 短暂延时,让显示稳定 } } // 矩阵显示函数 - 通过移位寄存器发送数据 void matrixDisplay() { // 发送列数据(先发送) shiftOut(DPin, CPin, MSBFIRST, COLdata); // 发送行数据(后发送,级联寄存器) shiftOut(DPin, CPin, MSBFIRST, Rowdata); // 更新显示 - 上升沿锁存数据 digitalWrite(LPin, LOW); // 锁存引脚置高,将移位寄存器数据更新到输出 digitalWrite(LPin, HIGH); // 锁存引脚置低,准备下一次数据传输 }
-
2025-7-23 19:22:14@
const int LPin = 13,CPin = 14,DPin = 15; byte ROWdata,COLdata; int big_heart[8] = {0x00,0x66,0xFF,0xFF,0xFF,0x7E,0x3C,0x18}; void setup() { pinMode(LPin,OUTPUT); pinMode(CPin,OUTPUT); pinMode(DPin,OUTPUT); digitalWrite(LPin,LOW); digitalWrite(CPin,LOW); } void loop() { for(int i=0;i<=7;i++) { ROWdata = 1 << i; COLdata = ~(big_heart[i]); matrixDisplay(); } } void matrixDisplay() { shiftOut(DPin,CPin,MSBFIRST,COLdata); shiftOut(DPin,CPin,MSBFIRST,ROWdata); digitalWrite(LPin,HIGH); digitalWrite(LPin,LOW); }
- 1