Cortex M在keil中的数据端结构及其应用

关于CPU的端结构的文章并不少见,我主要讲一讲在实际产品中的应用及其注意事项。
下面的所以代码和实例基于Keil MDK5.26演示,CPU为STM32F103VCT6.
一. 定义
Little-Endian:小端
就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
Big-Endian:大端
就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

比如一个 int类型的变量 little = 0x12345678,在不同的端模式的CPU上起存储的结果如下:
小端模式:
低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
大端模式:
低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78

二. 测试验证
我们定义了一个uinion类型的变量来验证数据的存放,如下图所示。
在这里插入图片描述
union类型的变量占用的存储空间是最大的那个变量需要的的存储空间,所以该变量总的占用存储器4个字节。我们给其中的32bit的变量u32赋值过后,可以看到另外两个变量的数值和存储顺序,在这里插入图片描述其存储顺序符合我们小端的定义。所以,我们证明了ARM的cortex M的端结构是小端模式。
同时,我们看到了字符串的存放顺序也是按照从低地址到高地址的顺序存储的。
延伸一下:
x86的CPU端结构是小端结构
51内核的CPU的大端结构
cortex M内核的CPU是小端结构

网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序
三. 应用
端结构对我们的编程有哪些影响呢?
如果我们的数据只是发生在CPU内部变量之间进行运算(硬件寄存器位置除外),我们不需要去关心端结构对数据存取的影响,因为这符合如何去如何来的原则,数据不会发生任何变化。
但是当我们要和外设进行数据交换的时候,那么你就要特别小心了。
例子1:从spi flash读写数据
大多数小容量的eeprom类型的flash的数据读写都是按照字节为单位进行的。如果我们是把一个8bit的char型数据或者以该类型数据保存的buffer的数据或者数组的数据保存到flash去,我们不需要做任何变化。如下面例子所示,因为它符合如何去就如何来的原则。

//flash的读写函数分别如下:
void sFLASH_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void sFLASH_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
//写设备地址
void WriteDeviceAddress(unsigned int devaddr)
{
	sFLASH_WriteBuffer((uint8_t*)&devaddr,0x00004000,4);
}
//读设备地址
unsigned int  ReadDeviceAddress(void)
{
	unsigned int u32;
	sFLASH_ReadBuffer((uint8_t*)&u32,0x00004000,4);
	return u32;
}

如果我们的设备地址本身是从比如卡片等设备读取进来的并且保持到如下buffer中:
Unsigned char addr[4];
那么我们在写入的时候直接传递该buffer进去,而读取的时候读到32bit的地址变量,就需要特别的小心了。
例子二:网络接收和发送数据
由于网络的数据采用网络字节序,所以,非字节的数据从网络传输过来的时候,就需要进行符合你所使用的CPU结构的端结构的数据转换。
我们可以用如下的方式转换为小端模式或者将小端模式的数据转换为网络字节序:
//转换网络传输字节序为32位的int类型,此转换与CPU的存储结构相关

UINT32 NetByteToInt32(UINT8* bytes)
{
	return ((UINT32)((((UINT32)(bytes[0])) << 24) | (((UINT32)(bytes[1])) << 16) | (((UINT32)(bytes[2])) << 8) | (((UINT32)(bytes[3])) << 0)));
}
//转换32位的int类型为网络传输字节序,此转换与CPU的存储结构相关
void Int32ToNetByte(UINT8* bytes,UINT32 iint)
{
	bytes[0] = (UINT8)(iint >> 24);
	bytes[1] = (UINT8)(iint >> 16);
	bytes[2] = (UINT8)(iint >> 8);
	bytes[3] = (UINT8)(iint >> 0);
}
//转换网络传输字节序为16位的int类型,此转换与CPU的存储结构相关
UINT16 NetByteToInt16(UINT8* bytes)
{
	return ((UINT16)(((UINT16)(bytes[0])) << 8) | (((UINT16)(bytes[1])) << 0));
}
//转换16位的int类型为网络传输字节序,此转换与CPU的存储结构相关
void Int16ToNetByte(UINT8* bytes,UINT16 iint)
{
	bytes[0] = (UINT8)(iint >> 8);
	bytes[1] = (UINT8)(iint >> 0);
}

原创文章,欢迎转载,请注明来源,未经书面允许,请勿用于商业用途。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值