C语言实现Modbus ASCII LRC校验生成相关问题咨询
Modbus ASCII从站LRC校验计算说明
1. LRC计算前的格式转换要求
必须先将接收到的ASCII字符转换为对应的十六进制数值,再进行LRC计算。
Modbus ASCII帧中,除开头的冒号:和结尾的CRLF结束符外,所有业务字段(从站地址、功能码、数据域)均采用2个ASCII字符表示1个字节的十六进制值,LRC校验的计算对象是这些原始字节值,而非ASCII字符本身的编码值。
2. ASCII字符转十六进制的实现逻辑
转换规则如下:
- 09的ASCII字符(编码范围`0x30`
0x39):直接减0x30得到对应数值0~9 - AF的大写ASCII字符(编码范围`0x41`
0x46):减0x37得到对应数值10~15 - af的小写ASCII字符(编码范围`0x61`
0x66):减0x57得到对应数值10~15,也可先转大写再按大写规则处理
注意Modbus ASCII采用2个ASCII字符拼接为1个字节,高4位在前、低4位在后,需要按顺序两两组合转换。
参考实现代码(C语言)
单个ASCII字符转十六进制数值:
uint8_t ascii_to_hex(uint8_t ascii_char) { if (ascii_char >= '0' && ascii_char <= '9') { return ascii_char - '0'; } else if (ascii_char >= 'A' && ascii_char <= 'F') { return ascii_char - 'A' + 10; } else if (ascii_char >= 'a' && ascii_char <= 'f') { return ascii_char - 'a' + 10; } // 非法字符可自行补充错误处理逻辑 return 0xFF; }
两个ASCII字符拼接为1个字节:
// ascii_buf为存储主站发送数据的uint8_t数组,跳过索引0的开头冒号 uint8_t high_nibble = ascii_to_hex(ascii_buf[i]); uint8_t low_nibble = ascii_to_hex(ascii_buf[i+1]); uint8_t hex_byte = (high_nibble << 4) | low_nibble;
3. 后续LRC校验计算流程
LRC计算规则:将转换得到的所有业务字节(从站地址、功能码、全部数据域字节)依次累加,忽略进位,最终对累加结果取反加1,得到的8位值就是本地计算的LRC校验值,和帧末尾2个ASCII字符转换得到的校验字节对比,一致则校验通过。
LRC计算参考代码:
uint8_t calculate_lrc(uint8_t *hex_data_buf, uint8_t data_len) { uint16_t lrc_sum = 0; for (uint8_t idx = 0; idx < data_len; idx++) { lrc_sum += hex_data_buf[idx]; } lrc_sum = ~lrc_sum + 1; return (uint8_t)lrc_sum; }
内容的提问来源于stack exchange,提问作者Vuko
相关产品推荐
相关产品推荐

