一:使用串口中断功能回传数据
实现ESP32的串口数据“回传”,最直接的理解就是 “回声” (Echo) 功能:将ESP32从串口收到的任何数据,原样发回去。这在调试设备或验证通信链路时非常常用。
实现这个功能的核心逻辑非常简单,在Arduino框架下的标准写法如下:
void setup() {
// 初始化串口通信,波特率设为115200
Serial.begin(115200);
}
void loop() {
// 检查串口缓冲区是否有数据可读
if (Serial.available() > 0) {
// 读取一个字节的数据
char incomingChar = Serial.read();
// 将收到的这个字节原样发送回去,实现“回传”
Serial.print(incomingChar);
}
}这段代码的逻辑是:当ESP32从USB串口(连接到电脑的Serial Monitor)收到数据时,就会立即把同样的数据发送回去。你可以打开Arduino IDE的串口监视器,发送任意字符,都会看到它被立即返回。
监听:通过available();检查是否有数据。
读取:使用Serial.read()等方法获取数据。
回写:通过Serial.print();方法将数据发送回去
二:串口空闲中断回传数据
ESP32在Arduino环境下,虽然没有和STM32完全一样的“空闲中断”硬件机制,但通过较新版本的HardwareSerial库,可以使用 onReceive() 回调函数达到非常相似的效果。
这个功能允许你设置一个回调函数,当串口在指定时间内没有收到新数据时被触发,这正是处理不定长数据帧的理想时机
#include <HardwareSerial.h>
// 自定义 Serial1 的 RX 和 TX 引脚
// 推荐使用开发板上不冲突的引脚,例如:
#define SERIAL1_RX 18 // 接收引脚
#define SERIAL1_TX 19 // 发送引脚
// 数据接收缓冲区
uint8_t rxBuffer[512];
uint8_t rxLength = 0;
void setup() {
// 初始化 USB 串口用于调试输出
Serial.begin(115200);
// 初始化 Serial1,配置波特率、数据位、停止位、奇偶校验
// 格式:begin(波特率, 配置模式, RX引脚, TX引脚)
// SERIAL_8N1 表示 8数据位、无校验、1停止位(最常用)
Serial1.begin(115200, SERIAL_8N1, SERIAL1_RX, SERIAL1_TX);
// 设置空闲超时时间为 10ms
// 即:当 Serial1 在 10ms 内没有收到新数据时,触发回调
Serial1.setRxTimeout(10);
// 注册回调函数,第二个参数 'true' 表示仅在超时时触发
// 这等同于"空闲中断"的效果
Serial1.onReceive(onSerial1Receive, true);
Serial.println("=== Serial1 空闲中断式回传已启动 ===");
Serial.printf("RX 引脚: %d, TX 引脚: %d\n", SERIAL1_RX, SERIAL1_TX);
}
void loop() {
// 主循环中可以执行其他任务
// 例如:每秒打印一次心跳信息
static unsigned long lastPrint = 0;
if (millis() - lastPrint > 5000) {
lastPrint = millis();
Serial.println("系统运行中...");
}
}
// ========================================
// Serial1 空闲中断回调函数
// 这个函数在每帧数据接收完毕后被自动调用
// 注意:此函数运行在中断上下文中,应尽量简短
// ========================================
void onSerial1Receive() {
// 获取当前可读的字节数(即这一帧的数据长度)
rxLength = Serial1.available();
if (rxLength > 0) {
// 从串口读取全部数据到缓冲区
Serial1.readBytes(rxBuffer, rxLength);
// ===== 数据处理 =====
// 1. 将收到的数据通过 USB 串口打印出来(用于调试)
Serial.print("[收到数据帧] 长度: ");
Serial.print(rxLength);
Serial.print(" 字节, 内容: ");
Serial.write(rxBuffer, rxLength); // 使用 write 以支持二进制数据
Serial.println(); // 换行
Serial1.write(rxBuffer, rxLength);
// }
}
}注意事项;
回调函数的执行环境:onSerial1Receive在中断上下文中执行,因此:避免使用delay
尽量保持代码简短快速
不要在回调中做复杂计算或阻塞操作
超时时间的选取:
如果超时时间太短(如1ms),在数据流传输时可能因短暂间隙而误触发如果超时时间太长(如100ms),则帧处理的实时性会下降
对于115200波特率,10ms是比较通用的值
缓冲区大小:uint8_t rxBuffer[512];可以根据需要调整,确保能容纳最大的一帧数据。
如果不需要回传:只需要将Serial1.write(rxBuffer, rxLength);这一行注释掉或删除即可。
我要赚赏金
