STM32 Modbus RTU USART发送场景下int变量转高低字节实现方法问询
问题原因
你用sprintf实现达不到预期是因为sprintf的%x是将数值转换为ASCII编码的十六进制字符串,例如455转义后得到的是字符数组{'1','c','7','\0'},对应ASCII值为0x31、0x63、0x37、0x00,和你需要的数值本身的高低字节完全是两个概念。
正确实现方式
方法1:位运算拆分(推荐,跨平台通用)
直接通过位运算提取16位数值的高低字节,该方法不受CPU大小端模式影响,完全符合Modbus RTU要求的大端序(高字节在前、低字节在后)规范:
#include <stdint.h> int freq = 455; // 先转换为Modbus要求的16位无符号类型,避免int溢出或符号位干扰 uint16_t modbus_val = (uint16_t)freq; // 提取高低字节 uint8_t high_byte = (modbus_val >> 8) & 0xFF; uint8_t low_byte = modbus_val & 0xFF;
你示例中的455对应十六进制为0x01C7,拆分后high_byte为0x01,low_byte为0xC7,完全符合你的需求。
报文填充示例
uint8_t pBuffer[8] = {0}; // 填充固定字段 pBuffer[0] = 0x02; // 从站地址 pBuffer[1] = 0x06; // 功能码:写单个保持寄存器 pBuffer[2] = 0x0C; // 寄存器地址高字节 pBuffer[3] = 0x21; // 寄存器地址低字节 // 填充数值字段 pBuffer[4] = high_byte; pBuffer[5] = low_byte; // 后续计算CRC16填充到pBuffer[6]、pBuffer[7]后即可发送 HAL_UART_Transmit(&huart2, pBuffer, 8, 0xFFFF);
可选方法:联合体拆分
如果你习惯用联合体也可以实现,原理是利用共用内存空间的特性直接读取高低字节:
union ModbusVal { uint16_t val; uint8_t byte[2]; }; union ModbusVal mval; mval.val = (uint16_t)freq; // 注意:STM32是小端模式,所以byte[0]是低字节,byte[1]是高字节 uint8_t high_byte = mval.byte[1]; uint8_t low_byte = mval.byte[0];
该方法仅适用于已知CPU大小端的场景,通用性不如位运算方法。
内容的提问来源于stack exchange,提问作者desarrollo1
相关产品推荐
相关产品推荐

