大小端与高位先行、低位先行

近期学习嵌入式过程中混淆了大小端和高位先行、低位先行的区别,现总结如下。

首先地址信号的顺序:

一个地址信号是一个16位的二进制数字,最右边的是第1位,最左边的是第16位。低8位指的是第1位到第8位,高8位指的是9-16位。

大小端与高位先行、低位先行_第1张图片

首先解释大端小端模式。大端模式即高位字节存放在低地址中,低位字节存放在高地址中;小端模式相反,高位字节存放在高地址中,低位字节存放在低地址中。用图表示更加容易理解。如下图,我们将数据0x01020304分别按照大端模式和小端模式存放在芯片中。

内存地址 0x00000004 0x00000003 0x00000002 0x00000001
大端 0x04 0x03 0x02 0x01
小端 0x01 0x02 0x03 0x04

注意芯片在取数据时,都是从低地址位开始取数据,这就是为什么要注意大小端的原因。用下面代码作解释:

int main()
{
    int a=0x01020304;
    printf("%x",(int)(*((char*)(&a))));//看输出的是0x01还是0x04
}

由于芯片都从低地址位开始取数据,那么如果上述代码输出0x01,表示高位字节0x01存放在低地址位,则此芯片采用大端模式;如果上述代码输出0x04,表示低位字节0x04存放在低地址位,则此芯片采用小端模式。

大小端模式是一种存储方式,是针对芯片来说的,每一个芯片在出厂时都已经规定好了大小端,用户不可以更改。

然后解释高位先行(MSB)和低位先行(LSB)。高位先行即在传输一个字节的时候先传输高位;低位先行即在传输一个字节的时候先传输低位。高位先行和低位先行是针对串行数据传输方式来说的。常见的串行传输方式有串口(UART)、I2C、SPI等。以串口传输方式为例,标准的串口传输方式是低位先行,如下图所示,芯片在通过TX引脚发送数据时,依次发送位0、位1……位7。

一般的芯片都集成串口外设,大家在使用串口时直接配置就行,可能体会不到高位先行和低位先行。下面以常用的模拟I2C为例,从代码上更加直观的看一下高位先行和低位先行。

I2C在数据传输时,协议规定了数据传输必须是高位先行,以下代码为I2C发送一个字节:

void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
    SDA_OUT(); 	    
    IIC_SCL=0;              //拉低时钟开始传输数据
    for(t=0;t<8;t++)        //循环8次,即发送一个字节
    {              
      IIC_SDA=(txd&0x80)>>7;//每次左移7位,即将最高位移到最低位,发送出去
      txd<<=1; 	  
      delay_us(2);   
      IIC_SCL=1;
      delay_us(2); 
      IIC_SCL=0;	
      delay_us(2);
    }	 
}

 从第8行和第9行代码中可以看到,在发送一个字节时,先将最高位发送出去,然后是第6位……第0位;同样在接收一个字节时,接收到的第1位认为是最高位,接收一个字节代码如下:

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;   //每次左移一位,循环8次后,第1次接收的位移到了最高位,依次类推
    if(READ_SDA)
        receive++;   
    delay_us(1); 
  }					 
    if (!ack)
        IIC_NAck();//发送非应答
    else
        IIC_Ack(); //发送应答 
    return receive;
}

 所有使用I2C的设备必须遵循I2C协议,必须都是高位先行的,这样才能实现通用性。

 

你可能感兴趣的:(嵌入式)