【嵌入式工程师面试高频问题】你知道IIC吗(附程序说明)

在嵌入式面试中,需要能够熟悉IIC的工作原理使用场景,并且需要能够手撕IIC的时序图和写一个IIC读写程序

IIC的一些工作原理、时序图在《沧小海详解面试的必答题——I2C协议》这篇博客介绍已经很全面了,我这里主要就是补充IIC的代码部分。顺便补充一下IIC和SPI以及UART的一些区别。

IIC读写特点

IIC最大的特点就是只使用两根线进行通讯,支持多个主服务器和多个从服务器。

IIC只有两根线,而且又不像SPI一样有片选线,那怎么区分地址呢?其实IIC总线上每个设备都有自己的地址,有的是芯片里面定死的,如果自己用GPIO模拟则可以自己定一个地址。
在这里插入图片描述

IIC、SPI、UART区别

SPI:4根线,全双工同步,速率最大可10Mbps,
I2C:2根线,半双工同步,速率一般是1Mbps,
UART:2根线,全双工异步,速率一般不超过20Kbps

UART和SPI、I2C两者最大的区别在于后面两者是同步的,要有统一的时钟线,而UART不需要,接线方便,但收发双方都需要配置相同的波特率,即设备要有自己的时钟源;

I2C协议中是有地址规则的,因此在一对多通信的时候更有优势。常用来连接传感器;

SPI编程简单,在设备不多,端口充足,对通信速度要求不高的场合可以应用,较常用来连接EEPROM、FLASH或液晶显示器。

SPI优点:支持全双工操作;操作简单;数据传输速率较高。SPI没有定义速度限制,一般的实现通常能达到甚至超过10 Mbps。

SPI缺点:需要占用主机较多的口线(每个从机都需要一根片选线);只支持单个主机;没有指定的流控制,没有应答机制确认是否接收到数据。

I2C优点:只使用两根电线,支持多个主服务器和多个从服务器,ACK / NACK位确认每个帧都已成功传输,硬件没有UART那么复杂。

I2C缺点:数据传输速率比SPI慢(IIC 最高的速度也就快速+模式(1 Mbps)和高速模式(3.4 Mbps)),数据帧的大小限制为8位,实现比SPI更复杂的硬件。

UART优点:只使用两根电线,不需要时钟信号,有一个奇偶校验位,只要双方设置后,就可以改变数据包的结构。

UART缺点:数据帧的大小限制为最多9位,不支持多个从属或多个主系统,速度最慢。

IIC八种状态和对应代码

其实IIC的通信就是通过两根线的八种状态完成的。**两根线怎么会有八种状态?**其实一根线有高电平、低电平、上升沿、下降沿四种状态。
在这里插入图片描述
数据线和时钟线组成的8种状态。
在这里插入图片描述
下面的代码就是用IO口去模拟IIC。实验是在STM32F103芯片做的,是能够跑通的。
在这里插入图片描述
在这里插入图片描述

//产生IIC起始信号  
void IIC_Start(void)  
{  
    SDA_OUT();     //sda输出  
    IIC_SDA=1;          
    IIC_SCL=1;  
    delay_us(4);  
    IIC_SDA=0;//START:when CLK is high,DATA change form high to low   
   	delay_us(4);  
    IIC_SCL=0;//铅住I2C总线,准备发送或接收数据  
}   

在这里插入图片描述

//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;  //往SDA上放数据,放txd最高位
       txd<<=1;      
       delay_us(2);   //对TEA5767这三个延时都是必须的  
       IIC_SCL=1;  
       delay_us(2);   
       IIC_SCL=0;    
       delay_us(2);  
    }      
}     

在这里插入图片描述

//等待应答信号到来  
//返回值:1,接收应答失败  
//        0,接收应答成功  
u8 IIC_Wait_Ack(void)  
{  
    u8 ucErrTime=0;  
   	SDA_IN();      //SDA设置为输入  
    IIC_SDA=1;delay_us(1);       //SDA设置为1,释放SDA总线
    IIC_SCL=1;delay_us(1);     
    while(READ_SDA)  //读SDA,如果SDA一直为1,则无应答;如果SDA为0,则应答成功
    {  
        ucErrTime++;  
        if(ucErrTime>250)  
       	{  
            IIC_Stop();  
            return 1;  
        }  
    }  
    IIC_SCL=0;//时钟输出0        
    return 0;    
}  

在这里插入图片描述

//产生ACK应答  
void IIC_Ack(void)  
{  
    IIC_SCL=0;  
    SDA_OUT();  
    IIC_SDA=0;  
   	delay_us(2);  
    IIC_SCL=1;  
    delay_us(2);  
    IIC_SCL=0;  
}  

在这里插入图片描述

//读数据
//返回值就是接收到的一个字节
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;  //SCL为高的时候读取数据
        receive<<=1;  //每读一次,receive左移一位
        if(READ_SDA)receive++;     //读取SDA放在receive最低位
        delay_us(1);   
    }                      
    if (!ack)  
        IIC_NAck();//发送nACK  
    else  
        IIC_Ack(); //发送ACK    
     return receive;  
} 

在这里插入图片描述

//产生IIC停止信号  
void IIC_Stop(void)  
{  
    SDA_OUT();//sda输出  
    IIC_SCL=0;  
    IIC_SDA=0;//STOP:when CLK is high DATA change form low to high  
    delay_us(4);  
    IIC_SCL=1;   
    IIC_SDA=1;//发送I2C总线结束信号  
    delay_us(4);                                  
}  

参考资料
[1] https://blog.csdn.net/z123canghai/article/details/83244185

  • 9
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值