第一章 LSB和MSB
1.1 最低有效位(Least Significant Bit, LSB)
红外接收器接收了0x45(0100 0101)之后,怎么将这个数据发送给MCU;
LSB(least significant bit):最低有效位优先,例如红外通信是以最低有效位发送和接收的
LSB发送的比特顺序: 1010 0010
当接收到按键数据时,红外接收头将数据按照从低到高,一个bit一个bit的将数据发生转发给MCU的GPIO口;
1.1.1 MCU的接收示例
1.1.2 MUC接收表示
1.2 最高有效位(Most Significant Bit, MSB)
DHT11温湿度传感器一次完备的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据 + 8bit校验和。
数据传送正确时校验和数据等于“8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据”所得效果的末8位。
温湿度传感器产生了一个字节的数据0xF4(1111 0100)之后,怎么将这个数据发送给MCU;
MSB(Most Significant Bit):最高有效位优先,例如获取温湿度比特流数据的时间是以最高有效位接收的。
MSB发送的比特顺序: 1111 0100
当传感器产生数据时,DHT11将数据按照从高到低,一个bit一个bit的将数据发生转发给MCU的GPIO口;
1.2.1 MCU的接收示例
1.2.2 MUC接收表示
第二章 大端模式和小端模式
2.1 大端模式
在大端模式下,多字节数据的高字节存储在低所在,低字节存储在高所在。也就是说,数据的高位在内存中存放得较前。
举个例子,如果要存储 32 位的十六进制数 0x12345678,在大端模式下,它会被按以下顺序存储在内存中:
所在: ... 0x01 0x02 0x03 0x04
数据: ... 0x12 0x34 0x56 0x78
在内存中的存储顺序是从高位到低位,先存储 0x12(最高字节),再存储 0x34,依此类推。
2.1.1 Modbus通讯协议
Modbus协议使用的是大端模式来表示16位和32位的数据类型。
例如,Modbus中读取的16位数据 0x1234 将会按以下方式传输:
- 高字节(MSB):0x12
- 低字节(LSB):0x34
因此,数据将会被按以下顺序传输:0x12 0x34(大端模式)。
- 32位数据----4byte (表示2个寄存器数据)
如果Modbus必要传输32位数据,协议也会将其按照大端模式进行存储,即先发送高字节,再发送低字节。例如,32位数据 0x12345678 会按以下顺序传输:
- 高字节:0x12
- 次高字节:0x34
- 次低字节:0x56
- 低字节:0x78
传输顺序为:0x12 0x34 0x56 0x78(大端模式)。
2.1.1.1 ModbusRTU主机
- #include <stdio.h>
- #include <stdint.h>
- // 定义宏 MAKEWORD 来组合两个字节
- #define MAKEWORD(a, b) ((uint16_t)(((uint8_t)(a)) | ((uint16_t)((uint8_t)(b))) << 8))
- // CRC计算函数(标准的 CRC-16-IBM 算法)
- uint16_t crc16(const uint8_t *data, uint16_t length) {
- uint16_t crc = 0xFFFF;
- for (uint16_t i = 0; i < length; ++i) {
- crc ^= data[i];
- for (uint8_t j = 0; j < 8; ++j) {
- if (crc & 0x0001) {
- crc = (crc >> 1) ^ 0xA001;
- } else {
- crc >>= 1;
- }
- }
- }
- return crc;
- }
- int main() {
- // 1. 从站地址:0x01
- // 2. 功能码:0x03
- // 3. 起始寄存器地址:MAKEWORD(0x00, 0x01) => 0x0001
- // 4. 寄存器数量:MAKEWORD(0x00, 0x02) => 0x0002
- // 定义一个足够大的数组来存放 Modbus RTU 请求帧
- uint8_t request_frame[8];
- // 填充请求帧数据
- request_frame[0] = 0x01; // 从站地址
- request_frame[1] = 0x03; // 功能码
- request_frame[2] = (uint8_t)(MAKEWORD(0x00, 0x01) >> 8); // 起始寄存器地址高字节
- request_frame[3] = (uint8_t)(MAKEWORD(0x00, 0x01) & 0xFF); // 起始寄存器地址低字节
- request_frame[4] = (uint8_t)(MAKEWORD(0x00, 0x02) >> 8); // 寄存器数量高字节
- request_frame[5] = (uint8_t)(MAKEWORD(0x00, 0x02) & 0xFF); // 寄存器数量低字节
- // 计算 CRC 校验码
- uint16_t crc = crc16(request_frame, 6); // CRC计算不包含 CRC 字节
- request_frame[6] = (uint8_t)(crc & 0xFF); // CRC 低字节
- request_frame[7] = (uint8_t)((crc >> 8) & 0xFF); // CRC 高字节
- // 输出 Modbus RTU 请求帧
- printf("Modbus RTU Request Frame: ");
- for (int i = 0; i < 8; i++) {
- printf("%02X ", request_frame[i]);
- }
- printf("\n");
- // 发送数据(在实际应用中可以通过串口发送)
- // send_data(request_frame, 8); // 伪代码,实际发送数据的函数
- return 0;
- }
复制代码 Modbus RTU Request Frame: 01 03 00 01 00 02 F7 D4
2.1.1.2 ModbusRTU从机
- #define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
复制代码 假设你调用 MAKEWORD(0x12, 0x34),那么:
- a = 0x12(低字节)
- b = 0x34(高字节)
过程如下:
- 低字节: (BYTE)(a) 效果是 0x12。
- 高字节: (WORD)((BYTE)(b)) << 8 效果是 0x34 << 8 = 0x3400。
效果是:0x34 12
使用上述宏界说剖析主机发送来的帧;
- typedef struct TModbusProtocol
- {
- /* 缓冲区 */
- BYTE pRxd[256]; /* 接受帧缓冲地址 */
- BYTE pTxd[256]; /* 发送帧缓冲地址 */
- BYTE byAddress; /* 装置地址 */
- /* 浏览结构 */
- DWORD dwEventSend; /* 动作报告浏览指针 */
- /* 计数器 */
- WORD wErrorCount; /* 异常报文计数,CPT3 */
- WORD wSuccessCount; /* 成功报文计数,CPT4 */
- DWORD dwNetStateCount; /* 网络状态 */
- }TModbusProtocol;
- static TModbusProtocol me;
- static BYTE* s_pRxd; /* 接受帧缓冲地址 */
- static BYTE s_byWritePtr; /* 发送缓冲区写指针 */
- /* modbus归约处理 */
- BOOL ManageModbusProtocol(void){
- .........
- /* 读取接收帧数据 */
- dwLen = hw485_read(me.pRxd, 256);
- s_pRxd = me.pRxd;
- .........
- }
- /* 读取多个Hold Register */
- static BYTE _Frame_03_ReadHoldRegisters(TModbusProtocol* me)
- WORD wStartAddr = MAKEWORD(s_pRxd[3], s_pRxd[2]); // 0x00 01
- WORD wCount = MAKEWORD(s_pRxd[5], s_pRxd[4]); // 0x00 01
- /* 个数判断 */
- if (wCount < 1 || wCount > MAX_HOLDING_REGISTER_COUNT)
- return ExeptionCode_3_ValidateDataValue;
- /* 准备工作 */
- me->pTxd[s_byWritePtr++] = wCount * 2; /* BYTE Count */
- }
复制代码
2.2 小端模式
在小端模式模式下,多字节数据的**低字节(LSB)**存储在低所在,**高字节(MSB)**存储在高所在。即数据的低位存放得较前。
同样以 0x12345678 为例,在小端模式下,它会被按以下顺序存储:
内存存储顺序:
所在: ... 0x01 0x02 0x03 0x04
数据: ... 0x78 0x56 0x34 0x12
2.3 总结
网络字节序、Modbus协议都是大端模式;
主机字节序是小端模式;
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |