IIC总线学习

一、IIC总线连接图

IIC总线简单来说就是一根线来控制时钟和一个线来发送数据。时钟线为SCL,数据线为SDA,两个线按照一定的传输协议来进行传输数据。由于只有一根线来传输数据,也就意味着同一时间只能有一个发送设备。按现在的传输机制来说,IIC的传输数据的速率并不是很快,现主要用于外扩存储上。(这里我们将CPU方定为主控设备,存储方定为受控设备)


二、IIC的信号类型

IIC总共有4中信号类型:起始信号、停止信号、应答信号和非应答信号。

1、IIC传输的基本规则

SCL=1时,如果是传输数据,SDA电平应保持不变,这样才可以将数据发送出去。如果SDA电平发生了变化,则是启停信号。

SCL=0时,SDA上的电平允许变化,变化好了,等SCL=1,SDA电平一直保持到SCL=0,这样就可以将数据传送出去。


2、IIC的四种信号(这四种信号都是在SCL=1时定义的)

可以这样理解,SCL=1,SDA的变化是变换数据类型和判断数据高低电平的;SCL=0时,仅是用于SDA的安全变化。

  • 起始信号

SCL=1,SDA由高电平变低电平(1→0),定义为起始信号,在发起传输时,主控设备发送起始信号用于告知对方从这开始就是要传输的内容了。


  • 停止信号

SCL=1,SDA由低电平变高电平(0→1),定义为停止信号,传输内容传输完毕后,主控设备用于告知对方本次传输结束。


  • 应答信号

IIC传输规定每传输完一个字节的数据后,到了第9个位时,主控设备要释放SDA(SDA不能被主控设备使用),SDA先暂由受控设备使用,受控设备必须输出低电平做为应答信号,主控设备接收SDA信号来判断受控设备是否应答。


  • 非应答信号

这个信号用于主控设备接收数据时,在接收到最后一个数据后面,主控设备发送一个SDA=1,通知受控设备结束发送数据并释放数据线,以便主控设备产生一个停止信号来终止总线的数据传送。


总结:我感觉应答信号是由接收字节数据的那一方(不论主控还是受控)发起的,其他信号都是主控设备发起的呀。

三、IIC总线的传输协议


总体规则来说就是起始信号+地址+寄存器地址+数据+应答............+应答(非应答)+停止信号

1、IIC总线写格式(主控设备写数据到受控设备)


交互过程:

(1)主控设备对总线发起起始信号

(2)主控设备发送的第一个字节数据是受控设备的地址,高7位表征受控设备地址,最低位表征是读(1)还是写操作(0)。从这里可以看出IIC总线的传输是高位先传输,低位后传输。

(3)当主控设备发送完一个字节数据后,主控设备要等待受控设备的应答信号,也就说每发送了8位二进数,第9位就是根据SDA线的电平来判断受控设备是否发送了应答信号。

(4)应答信号之后,就是第二个字节了,这个字节多半是受控设备寄存器地址,受控设备收到字节数据后也要进行应答。

(5)发送完寄存器地址后,就要发送数据,每发送一个字节数据,受控设备都要做出应答,传输的字节数没有限制,数据传输完毕后由主控设备发出停止信号来停止总线。

2、IIC总线读数据格式(主控设备从受控设备中读取数据)


交互过程:

(1)由主控设备发起起始信号,前面两个字节是主控设备写受控设备地址和寄存器地址(数据方向为写,即"0"),所以过程和写操作相同。

(2)第二个字节之后,主控设备要重新启动总线,重传控设备地址,并且数据方向为读,即"1",这表明后续数据就是读操作了。

(3)从上图可以看出,应答信号有两种,一种是主控设备发送的,一种是受控设备发送的。前三个字节的数据方向是主控设备写到受控设备,固应答信号是由受控设备发送的;后面是受控设备发送数据到主控设备,固应答信号是由主控设备发送的,当主控设备接收到最后一个字节数据后,主控设备发送一个非应答信号,通知受控设备不用再发送数据了。

(4)最后,主控设备还要发送一个停止信号来停止总线。

四、示例(采用正点原子代码)

//IO·方向设置
#define SDA_IN()  {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=0<<5*2;}
#define SDA_OUT() {GPIOH->MODER&=~(3<<(5*2));GPIOH->MODER|=1<<5*2;} 
//IO操作
#define IIC_SCL(n)  (n?HAL_GPIO_WritePin(GPIOH,GPIO_PIN_4,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOH,GPIO_PIN_4,GPIO_PIN_RESET)) //SCL
#define IIC_SDA(n)  (n?HAL_GPIO_WritePin(GPIOH,GPIO_PIN_5,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOH,GPIO_PIN_5,GPIO_PIN_RESET)) //SDA

#define READ_SDA    HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_5)  



//产生起始信号
void IIC_Start(void)
{
SDA_OUT();  
IIC_SDA(1);    
IIC_SCL(1);
delay_us(4);
  IIC_SDA(0);
delay_us(4);
IIC_SCL(0);

}

//产生停止信号

void IIC_Stop(void)
{
SDA_OUT();
IIC_SCL(0);
IIC_SDA(0);
  delay_us(4);
IIC_SCL(1); 
IIC_SDA(1);
delay_us(4);  

}

//主控设备产生应答信号
void IIC_Ack(void)
{
IIC_SCL(0);
SDA_OUT();
IIC_SDA(0);
delay_us(2);
IIC_SCL(1);
delay_us(2);
IIC_SCL(0);

}

//主控设备产生非应答信号    
void IIC_NAck(void)
{
IIC_SCL(0);
SDA_OUT();//SDAÏßΪÊä³öģʽ
IIC_SDA(1);
delay_us(2);
IIC_SCL(1);
delay_us(2);
IIC_SCL(0);

}

//主控设备等待应答信号

//返回值=1,没有收到应答信号

//返回值=0,收到应答信号

u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN();  
IIC_SDA(1);delay_us(1);   
IIC_SCL(1);delay_us(1);  
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL(0);
return 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);
    }  

//主控设备读取一个字节数据

u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();
  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();
    else
        IIC_Ack(); 
    return receive;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值