一、为什么要学iic
很多面试官喜欢问IIC通信协议怎么实现,当时我只有在开发板用过IIC来向存储芯片(WQ25128系列)存数据,觉得在设计中没有很大的作用,为什么相比起串口(USART)更喜欢问IIC,当听我说“之前学过一遍,已经总结在word里了,如果需要用到,再去看就行了”,结果面试官不是很满意我的回答。在百度帖吧,看别人也有问过这个问题,大多解释是面试官要看一下应试者的基础。面试前重新看一下背一下就行。同时有的人说IIC在实际应用在很多地方。
二、怎么理解IIC
2.1 概要
IIC(IIC,inter-Integrated circuit),两线式串行总线,用于MCU和外设间的通信。 IIC只需两根线:数据线SDA和时钟线SCL。以半双工方式实现MCU和外设之间数据传输,速度可达400kbps。
多主机I2C总线结构
注意SDA和SCL两根总线需要上拉,使总线处于空闲状态。
2.2 IIC协议
a.空闲状态
协议规定,SDA和SCL同时为高电平时,总线处于空闲状态。上拉电阻保证电平处于高电平。
起始信号和停止信号
起始信号:SCL为高电平时,SDA电平发生高到低的跳变
停止信号:SCL为高电平时,SDA电平发生低到高的跳变
发送0xa0数据:有应答的,速度100khz
周期10us:
b.应答信号
发送器每发送完一个字节(8个脉冲),在第9个脉冲间释放总线,接收器返回一个ACK信号,协议规定,低电平为有效应答,高电平为无效应答。
c.数据有效性
协议对有效数据进行了规定:即时钟信号为高电平期间,数据必须保持稳定,时钟信号低电平期间,数据线上的电平才允许变化。也就是说,数据在时钟信号到来前必须准备好,并保持到时钟信号的下降沿之后。
d.数据传输
I2C为同步传输,时钟控制数据位的传输,边沿触发。
驱动程序
直接引用实验中的代码。测试没问题。
起始信号
1. //产生IIC起始信号
2. void IIC_Start(void)
3. {
4. SDA_OUT(); //sda线输出
5. IIC_SDA=1;
6. IIC_SCL=1;
7. delay_us(4);
8. IIC_SDA=0;//START:when CLK is high,DATA change form high to low
9. delay_us(4);
10. IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
11. }
停止信号
1. //产生IIC停止信号
2. void IIC_Stop(void)
3. {
4. SDA_OUT();//sda线输出
5. IIC_SCL=0;
6. IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
7. delay_us(4);
8. IIC_SCL=1;
9. IIC_SDA=1;//发送I2C总线结束信号
10. delay_us(4);
11. }
有效应答
1. //产生ACK应答
2. void IIC_Ack(void)
3. {
4. IIC_SCL=0;
5. SDA_OUT();
6. IIC_SDA=0;
7. delay_us(2);
8. IIC_SCL=1;
9. delay_us(2);
10. IIC_SCL=0;
11. }
无效应答
1. //不产生ACK应答
2. void IIC_NAck(void)
3. {
4. IIC_SCL=0;
5. SDA_OUT();
6. IIC_SDA=1;
7. delay_us(2);
8. IIC_SCL=1;
9. delay_us(2);
10. IIC_SCL=0;
11. }
发送单字节
1. //IIC发送一个字节
2. //返回从机有无应答
3. //1,有应答
4. //0,无应答
5. void IIC_Send_Byte(u8 txd)
6. {
7. u8 t;
8. SDA_OUT();
9. IIC_SCL=0;//拉低时钟开始数据传输
10. for(t=0;t<8;t++)
11. {
12. IIC_SDA=(txd&0x80)>>7;
13. txd<<=1;
14. delay_us(2); //对TEA5767这三个延时都是必须的
15. IIC_SCL=1;
16. delay_us(2);
17. IIC_SCL=0;
18. delay_us(2);
19. }
20. }
接收单字节
1. //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
2. u8 IIC_Read_Byte(unsigned char ack)
3. {
4. unsigned char i,receive=0;
5. SDA_IN();//SDA设置为输入
6. for(i=0;i<8;i++ )
7. {
8. IIC_SCL=0;
9. delay_us(2);
10. IIC_SCL=1;
11. receive<<=1;
12. if(READ_SDA)receive++;
13. delay_us(1);
14. }
15. if (!ack)
16. IIC_NAck();//发送nACK
17. else
18. IIC_Ack(); //发送ACK
19. return receive;
20. }
三、怎么背IIC
上面的程序亲身验证过,可以用的(第二节非原创,摘录一个牛人,很久之前找到了,不知道原创的链接了)。
1.IIC由SCL和SDA组成。
2.根据IIC的时序要求,要实现六个功能子函数,包括启动函数,停止函数,应答函数,非应答函数,字节发送函数,字节接受函数。
3.再深入就是背时序了。启动,停止,应答,非应答是主动发送的过程相对来说比较简单,
启动就是先将SCL,SDA拉高,延时一下,然后将SDA拉低,延时一下;
停止也是先将SCL拉高,SDA拉低,延时一下,不过接下来将SDA拉高,延时一下;
应答是将SCL拉高,在拉高期间将SDA保持低电平,非应答则是将SDA拉高。
发送和接收字节都是从高位开始的,先将SCL拉高,延时一下,然后发送或者接收。