大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
data0 |
Data1 |
Data2 |
Data3 |
Data4 |
Data5 |
Data6 |
Data7 |
Data8 |
Data9 |
帧头 |
指令 |
参数 |
CRC校验码 |
||||||
0xaabb |
0x0001 |
0x01 |
0x02 |
0x1234 |
|
如上指令协议,我在解读时会按照大端模式理解,
即数据发送的顺序为:aabb 0001 0102 1234 crc
为了处理方便,构建如下结构体:
typedef struct
{
u16 frame_head;
u16 module_cmd;
u8 cmd_data4;
u8 cmd_data5;
u16 cmd_data67;
u16 crc_data;
}ProtocolType;
但我用的stm32f4系列为小端模式,这么构建结构体会带来一些问题:
问题1: 不能使用memcpy函数向结构体中复制数据,如果直接复制,frame_head中存储的数据为0xbbaa,这是大小端模式导致的。
问题2:crc码的计算,正如问题1所述,若要为计算crc16建立一个u16的数组,需要将源数据按字节取出,按照小端模式组合,再赋值到数组中:
for(;word_len < (len>>1) ;word_len++)
{
rec_cmd_buff[word_len] = ((u16)p_data[(word_len<<1)]<<8)+p_data[(word_len<<1)+1];
}
问题3:按照问题2的处理方法,我们可以很容易计算数据的crc码,并校验,而且还可以直接把这个数组复制到问题1设想的结构体中,但又会出现新的问题:结构体中的cmd_data4并非是0x01,而是0x02,这是因为单字节数据本身不受大小端存储方式的影响,但在问题2中,我们强行把cmd_data4,cmd_data5合并为了u16类型数据,导致两个数据颠倒了位置,所以要想正常使用ProtocolType结构体,可以把cmd_data4,cmd_data5的定义颠倒一下,或者干脆也定义成u16类型数据,高低字节分别取用就是了。
至于为什么非要定义成一个结构体呢,为了维护方便,提高可读性。。。