ESP32通过UART读取DSMR5电表数据出现乱码问题求助
看起来你在ESP32读取DSMR5电表P1口数据时碰到了乱码的棘手问题,我结合你的代码和DSMR5的特性,整理几个关键排查方向和修复建议:
1. 移除手动配置RX引脚的GPIO代码
你在app_main里手动把GPIO16(RX2)配置成了上拉输入,但UART驱动在调用uart_set_pin和uart_driver_install后,会自动将引脚切换为UART功能模式,手动的GPIO配置很可能和驱动设置冲突,导致信号接收异常。直接删掉这段代码试试:
// 删掉以下这段冗余配置 gpio_config_t io_conf = { .intr_type = GPIO_INTR_DISABLE, .mode = GPIO_MODE_INPUT, .pin_bit_mask = (1ULL << 16), .pull_down_en = GPIO_PULLDOWN_DISABLE, .pull_up_en = GPIO_PULLUP_ENABLE, }; gpio_config(&io_conf);
2. 确认DSMR5的通信参数是否匹配
虽然你设置了115200波特率、8N1参数,但部分DSMR5电表的P1口默认参数是9600波特率、偶校验(不同厂商的电表可能有差异)。可以先修改UART配置测试,同时把时钟源换成参考时钟提升波特率精度:
uart_config_t uart_config = { .baud_rate = 9600, // 先尝试9600波特率 .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_EVEN, // 尝试偶校验 .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = UART_SCLK_REF_TICK, // 用1MHz参考时钟减少波特率误差 };
另外,你不需要给电表发送数据,UART的TX引脚可以直接设为无变化,避免占用GPIO17:
ESP_ERROR_CHECK(uart_set_pin(2, UART_PIN_NO_CHANGE, 16, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
3. 检查电平匹配问题(最常见的根源)
很多DSMR电表的P1口输出的是RS232电平(正负12V左右),而ESP32的UART只支持TTL电平(0-3.3V),直接接线会导致信号被严重扭曲,必然产生乱码。你需要在电表TXD和ESP32 RX之间加一个RS232转TTL模块(比如MAX3232芯片),把RS232信号转换成ESP32能识别的TTL信号。
4. 优化UART接收超时设置
你当前的uart_read_bytes超时是20ms,而DSMR5每秒钟发送一整帧数据,单帧接收时间可能超过20ms,导致数据被拆分接收(虽然不会直接导致乱码,但会影响数据完整性)。可以把超时时间改长到1000ms,确保能接收到完整的一帧:
int len = uart_read_bytes(2, data, (BUF_SIZE - 1), 1000 / portTICK_PERIOD_MS);
5. 硬件接线稳定性排查
- 确保ESP32和电表的GND完全共地,共地不良会引入大量信号噪声;
- 电表TXD到ESP32 RX的接线尽量短,最好用屏蔽线,减少电磁干扰;
- 确认RTS引脚的3.3V供电稳定,DSMR5的RTS是有源高电平,只有RTS保持高电平时电表才会持续发送数据。
如果以上方法都试过还是有问题,建议用示波器或逻辑分析仪抓取电表TXD的信号波形,确认电平、波特率是否和你设置的参数一致,这样能快速定位是硬件还是软件的问题。
内容来源于stack exchange




