目录
你知道内存是怎么读取数据的吗?
内存的读写永远是从低地址开始读写,从低到高。
大小端模式:
大小端指的是字节序。
大端:高位字节存放在低地址中,低位字节存放在高地址中。
小端: 高位字节存放在高地址中,低位字节存放在低地址中。最符合人的思维的字节序,KEIL MDK中,变量是小端模式的。
以unsigned int value = 0x12345678
为例,分别按照大端模式和小端模式存放在芯片中。
内存地址 | 0x00000001 | 0x00000002 | 0x00000003 | 0x00000004 |
---|---|---|---|---|
大端模式 | 0x12 | 0x34 | 0x56 | 0x78 |
小端模式 | 0x78 | 0x56 | 0x34 | 0x12 |
ARM平台是小端的,x86平台是小端的,PowerPC平台是大端的。
不管是大端还是小端模式,我们在读取和存储数据的时候一定都是从内存的低地址依次向高地址读取或写入。
字节高低位:
一般左边为高位,右边为低位。(按照阅读习惯,数字从左往右,表示由大到小)
LSB和MSB:
最低有效位、最高有效位。
eg:0x12345678,LSB = 0x78,MSB = 0x12。
高位先行msb、低位先行lsb:
高位先行:在传输一个字节时先传输高位msb;
低位先行:在传输一个字节时先传输低位lsb。
高位先行和低位先行是针对串行数据传输方式来说的。
常见的串行传输方式有串口、I2C、SPI等。
串口传输是低位先行
标准的串口传输方式是低位先行,芯片在通过TX引脚发送数据时,依次发送位0、位1......位7。
IIC传输是高位先行
IIC的数据和地址均以8位字节传输,MSB在前。
这一点也反映在代码中,看下边IIC的读字节和写字节的函数:
//IIC 发送一个字节 //返回从机有无应答 //1,有应答 //0,无应答 void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); IIC_SCL=0; //拉低时钟开始数据传输 for(t=0;t<8;t++) { IIC_SDA=(txd&0x80)>>7; txd<<=1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } } //读 1 个字节:ack=1 时,发送 ACK;ack=0,发送nACK u8 IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; SDA_IN(); //SDA 设置为输入 for(i=0;i<8;i++ ) { IIC_SCL=0; delay_us(2); IIC_SCL=1; receive<<=1; if(READ_SDA) { receive++; } delay_us(1); } if (!ack) IIC_NAck(); //发送 nACK else IIC_Ack(); //发送 ACK return receive; }
从发送字节的函数中可以看出,首先要将发送的字节与0x80进行与运算,取出最高位,然后循环左移8次就可以将一个字节数据发送出去了。这是因为:IIC规定了在数据传输时必须是高位先行。所以要发送一个字节的数据必须先取出最高位,然后循环左移将数据发出。
同样,接收一个字节时,接收到的第一位认为是最高位。
字节序、比特序
字节序就是串行发送多字节时发送的顺序。
eg:
value = 0x12345678;按字节序发送就是0x12、0x34、0x56、0x78顺序还是0x78、0x56、0x34、0x12顺序。
同理,按比特序就是在bit层面进行排序。eg:如果是一个字节,指先发bit0还是bit7。
串口是lsb优先,I2C是msb优先。这里的msb、lsb指的是比特序,二进制位的位置。区别于“字节序”通信中,先发送低字节还是高字节,那是字节序的MSB还是LSB。