您的代码片段是在将一个16位值()拆分为高字节和低字节:IR_RF_Signal.length
temp_low = IR_RF_Signal.length & 0xFF;
temp_high = IR_RF_Signal.length >> 8;
虽然我在 PX4-Autopilot 仓库中没有找到这段确切的代码,但这是嵌入式系统中的常见做法,特别是在处理通信协议时。这么做的原因主要有以下几点:
1. 通信协议的数据包格式
在大多数低级通信协议中(如UART、SPI、I2C等),数据是按字节一个一个传输的。当需要传输一个多字节的值(如16位的长度值)时,必须将其拆分成单个字节进行传输。拆分成高低字节是标准做法。
2. 字节序(Endianness)考虑
不同的系统可能使用不同的字节序(大端序或小端序)。通过明确地将值拆分为高字节和低字节,可以确保通信双方以相同的方式解释数据,避免字节序差异导致的问题。
3. 内存效率
在资源受限的嵌入式系统中,明确控制每个字节如何存储和传输可以提高内存和带宽效率。
4. 协议兼容性
很多通信协议有特定的数据包格式要求,必须按照固定的格式构造数据包。拆分高低字节是遵循这些格式要求的一种方式。
为什么不直接用数组?
您问为什么不能直接将值存入数组。技术上来说,可以这样做:
uint8_t length_bytes[2];
length_bytes[0] = IR_RF_Signal.length & 0xFF; // 低字节
length_bytes[1] = IR_RF_Signal.length >> 8; // 高字节
或者使用联合体(union)或结构体指针转换。但是,明确地拆分为独立变量有几个优势:
- 代码可读性更高,明确表示这是长度值的高字节和低字节
- 避免可能的内存对齐问题
- 在某些情况下可能需要单独处理这些字节,如添加到不同的数据包位置
注意事项
这种拆分方式实际上是在实现小端序(little-endian)的字节序,即低字节在前,高字节在后。如果接收方期望大端序(big-endian),则应该调整存储顺序。
为什么需要将IR_RF_Signal.length拆分成高低字节
在嵌入式系统中,经常需要将多字节数据拆分成单字节进行存储或传输,这段代码就是这样的一个例子。
原因是是一个16位的无符号整数(),而是一个8位字节()的数组:IR_RF_Signal.length
uint16_t
W25Q64_Buffer
uint8_t
volatile uint8_t W25Q64_Buffer[4096] = {0};
在函数中,需要将16位的值存储到这个8位的缓冲区中:Module_IR_RF_Copy_To_Buffer
length
temp_low = IR_RF_Signal.length & 0xFF; temp_high = IR_RF_Signal.length >> 8; W25Q64_Buffer[0] = temp_low; W25Q64_Buffer[1] = temp_high;
这样做的原因是:
- W25Q64闪存芯片的接口是基于字节操作的,每次只能读写8位数据
- 必须将16位的值分解成两个8位字节才能存储
length
- 使用获取低8位,使用获取高8位
& 0xFF
>> 8
同样地,程序也对数组中的每个16位值进行了类似的拆分:duration
for (i = 0; i < IR_RF_Signal.length; i++) {
temp_low = IR_RF_Signal.duration[i] & 0xFF;
temp_high = IR_RF_Signal.duration[i] >> 8;
W25Q64_Buffer[i * 2 + 2] = temp_low;
W25Q64_Buffer[i * 2 + 3] = temp_high;
}
反过来,当从闪存读取数据时,也需要将两个字节重新组合成一个16位值:
temp_low = W25Q64_Buffer[0];
temp_high = W25Q64_Buffer[1];
IR_RF_Signal.length = (temp_high << 8) | temp_low;
这种拆分和重组16位值的方法在嵌入式系统和通信协议中非常常见,特别是在处理跨字节边界的多字节数据时。
注意
如果想直接存储在数组中而不拆分,那么需要使用uint16_t类型的缓冲区,但W25Q64闪存的接口是基于字节(8位)作的,所以最终在与硬件交互时仍然需要进行字节拆分。