ESP32通过UART组帧收发多字节数据控制触摸传感器LED咨询
ESP32 UART触摸传感器通信实现方案
以下实现基于ESP-IDF官方UART驱动,所有代码可直接在GCC环境下编译运行。
1. UART多字节数据发送实现
ESP-IDF内置了完整的UART驱动,无需手动实现时序,按以下步骤操作即可发送多字节数据:
- 第一步:配置UART参数(波特率、数据位、停止位、奇偶校验),绑定收发引脚
- 第二步:安装UART驱动,分配内部缓存
- 第三步:调用
uart_write_bytes接口直接发送任意长度的字节数组
初始化代码示例
#include "driver/uart.h" #include "esp_err.h" // 定义UART参数 #define UART_PORT_NUM UART_NUM_2 #define UART_BAUD_RATE 9600 // 按触摸传感器实际要求修改 #define UART_TX_PIN 17 // 按实际硬件连接修改 #define UART_RX_PIN 16 // 按实际硬件连接修改 #define UART_BUF_SIZE 1024 void uart_init(void) { const uart_config_t uart_config = { .baud_rate = UART_BAUD_RATE, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = UART_SCLK_APB, }; // 配置UART参数 uart_param_config(UART_PORT_NUM, &uart_config); // 绑定引脚 uart_set_pin(UART_PORT_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); // 安装驱动,分配收发缓存 uart_driver_install(UART_PORT_NUM, UART_BUF_SIZE * 2, UART_BUF_SIZE * 2, 0, NULL, 0); }
发送多字节数据直接调用:
// 示例:发送长度为len的字节数组data uint8_t data[] = {0x7B, 0x05, 0x03, 0x01, 0x02, 0x06, 0x7D}; int len = sizeof(data); uart_write_bytes(UART_PORT_NUM, (const char*)data, len);
2. 数据包帧组装实现
必须严格按照协议规则组装帧,否则传感器无法识别指令,组装逻辑如下:
- 确定数据域的长度N,整帧总长度L = 1(起始码) + 1(命令) + 1(长度) + N(数据) + 1(校验和) + 1(结束码) = N + 5
- 长度字段值为
L - 4,即等于N + 1 - 校验和计算规则:将长度字段和所有数据域的字节累加,取结果的低8位
- 按顺序填充帧字节:
起始码0x7B -> 命令字节 -> 长度字段 -> 数据域 -> 校验和 -> 结束码0x7D
通用组帧函数示例
/** * @brief 组装符合协议的UART帧 * @param cmd 命令字节 * @param data 数据域指针 * @param data_len 数据域长度 * @param frame_buf 输出的帧缓存,需保证大小足够(至少data_len+5字节) * @return 组装完成的帧总长度 */ int build_uart_frame(uint8_t cmd, uint8_t *data, int data_len, uint8_t *frame_buf) { int total_len = data_len + 5; // 填充起始码、命令、长度 frame_buf[0] = 0x7B; frame_buf[1] = cmd; frame_buf[2] = total_len - 4; // 协议要求长度为L-4 // 填充数据域 for (int i = 0; i < data_len; i++) { frame_buf[3 + i] = data[i]; } // 计算校验和 uint8_t checksum = frame_buf[2]; // 先加长度字段 for (int i = 0; i < data_len; i++) { checksum += data[i]; } frame_buf[3 + data_len] = checksum; // 填充结束码 frame_buf[3 + data_len + 1] = 0x7D; return total_len; }
LED控制调用示例
// 启动LED闪烁,周期200ms(对应参数0x02) uint8_t start_data[] = {0x01, 0x02}; uint8_t start_frame[10] = {0}; int start_frame_len = build_uart_frame(0x05, start_data, sizeof(start_data), start_frame); uart_write_bytes(UART_PORT_NUM, (const char*)start_frame, start_frame_len); // 停止LED闪烁 uint8_t stop_data[] = {0x00, 0x00}; uint8_t stop_frame[10] = {0}; int stop_frame_len = build_uart_frame(0x05, stop_data, sizeof(stop_data), stop_frame); uart_write_bytes(UART_PORT_NUM, (const char*)stop_frame, stop_frame_len);
3. UART响应数据读取实现
使用uart_read_bytes接口即可读取传感器返回的数据,建议设置超时时间避免阻塞,读取后可按协议规则校验帧合法性。
读取响应代码示例
/** * @brief 读取UART响应帧 * @param resp_buf 响应缓存 * @param buf_size 缓存大小 * @param timeout_ms 超时时间,单位ms * @return 读取到的帧长度,小于0为读取失败 */ int read_uart_response(uint8_t *resp_buf, int buf_size, int timeout_ms) { // 先读取起始码 uint8_t start_code = 0; int len = uart_read_bytes(UART_PORT_NUM, &start_code, 1, pdMS_TO_TICKS(timeout_ms)); if (len != 1 || start_code != 0x7B) { return -1; // 无效起始码 } resp_buf[0] = start_code; // 读取到结束码0x7D为止 int pos = 1; while (pos < buf_size) { len = uart_read_bytes(UART_PORT_NUM, &resp_buf[pos], 1, pdMS_TO_TICKS(timeout_ms)); if (len != 1) { return -2; // 读取超时 } if (resp_buf[pos] == 0x7D) { pos++; break; } pos++; } // 可选:校验校验和合法性 uint8_t checksum = resp_buf[2]; for (int i = 3; i < pos - 2; i++) { checksum += resp_buf[i]; } if (checksum != resp_buf[pos - 2]) { return -3; // 校验和错误 } return pos; }
调用示例
uint8_t resp_buf[32] = {0}; int resp_len = read_uart_response(resp_buf, sizeof(resp_buf), 1000); if (resp_len > 0) { // LED控制成功的响应为 0x7B 0x55 0x01 0x01 0x7D if (resp_buf[1] == 0x55) { // 命令执行成功 } }
内容的提问来源于stack exchange,提问作者horsemann07
相关产品推荐
相关产品推荐

