短文标题3.5T静默分帧CRC16校验Modbus-RTU帧结构解析你有没有想过一个问题Modbus-RTU数据帧没有固定的帧头接收方怎么知道一帧从哪里开始、到哪里结束靠“沉默”来分帧。协议规定两个字节之间的间隔超过3.5个字符时间就认为上一帧结束下一帧开始。3.5T3.5字符时间怎么算以9600bps、8N110位/字符1起始8数据1停止为例1位时间 1/9600 ≈ 104µs1字符时间 10 × 104µs ≈ 1.04ms3.5T 3.5 × 1.04ms ≈ 3.64msIDLE中断检测帧结束USART的IDLE标志在总线空闲超过1字符时间时置1可配合软件定时器测量更精确的3.5T或直接用IDLE中断触发帧结束标志工程实践中通常足够。void USART2_IRQHandler(void){if (__HAL_UART_GET_FLAG(huart2, UART_FLAG_IDLE)) {__HAL_UART_CLEAR_IDLEFLAG(huart2);// 帧接收完成frame_received 1;}}Modbus-RTU帧结构地址从机地址1~2470为广播地址功能码03读保持寄存器、06写单个寄存器、05写线圈数据寄存器地址、数量、写入值CRC16从地址到数据区末尾低字节在前常用功能码DMAIDLE接收变长帧// 配置DMA接收HAL_UART_Receive_DMA(huart2, rx_buffer, BUFFER_SIZE);// IDLE中断中处理void USART2_IRQHandler(void){if (__HAL_UART_GET_FLAG(huart2, UART_FLAG_IDLE)) {__HAL_UART_CLEAR_IDLEFLAG(huart2);HAL_UART_DMAStop(huart2);uint16_t len BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart2.hdmarx);// len就是这一帧的长度处理数据HAL_UART_Receive_DMA(huart2, rx_buffer, BUFFER_SIZE);}}这个故事的启示Modbus-RTU没有帧头用“静默”分帧——3.5T就是它的“句号”。CRC16保数据完整一个bit错都不同。学会解析帧结构Modbus通信不再神秘。写在最后Modbus-RTU帧结构就四部分地址区分设备功能码定操作数据传内容CRC保安全。本文灵感源于于振南《新概念ARM32单片机》教程第4.16节、第4.17节。觉得有用点赞、转发让更多人看懂Modbus-RTU的帧结构。