一、什么是IIC协议?
在学习嵌入式的时候,学习了最基本的外设和串口通信,在上手传感器的时候,会发现出了简单的开关量传感器,很多模拟量传感器都是使用了其他的通信协议与单片机进行数据和指令的通信,而IIC也是其中最经典的有线通信协议,它也是嵌入式等方向的必备专业核心技术。下面,就来学习IIC
IIC(Inter-Integrated Circuit)协议是一种串行通信协议,用于连接集成电路之间的通信。它由飞利浦公司(现在的恩智浦半导体)开发,是一种双向、同步、串行通信协议。IIC协议通常用于连接微控制器、传感器、存储器和其他集成电路之间的通信。在IIC总线上,可以同时连接多个设备,并且通过地址寻址来识别和访问每个设备。
IIC协议的基本工作原理是通过两根线(一根为数据线SDA,一根为时钟线SCL)进行数据传输。设备之间通过时钟信号同步数据传输,数据线上的数据传输由起始信号、地址、数据和停止信号组成。IIC协议支持主从模式,其中主设备负责发起通信和控制总线,而从设备则响应主设备的指令。
二、优缺点及适用范围
在认识一种通信协议之前,肯定是要先清楚它的优缺点,知道它的使用范围和特点,在有这些前置认识后,对后面的原理和实验才能了解的更深入和透彻
1、优点
简单易用:IIC协议使用两根线进行通信,实现起来比较简单,适合连接少量设备进行通信。
可靠性高:通过时钟同步传输数据,数据传输稳定可靠,不易受干扰。
支持多设备:IIC总线可以连接多个设备,通过地址寻址来选择通信对象。
节省引脚:相比于并行通信,IIC协议只需要两根线,节省了设备的引脚资源。
2、缺点
速度较慢:由于是串行通信,相比于并行通信,IIC协议的数据传输速度较慢;但是在有线通信协议里面传输速度:UART<IIC<SPI
通信距离短:IIC协议的通信距离受限,适合连接设备之间距离较近的场景。
冲突问题:当多个设备同时发送数据时,可能会出现冲突,需要通过软件或硬件解决。
3、使用场景
IIC是为了单片机与低速设备通信而发明的通信设备,多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。
三、物理层
物理层就是协议的总线介绍以及电路连接图
1、总线介绍
IIC总线就是SDA和SCL。
数据线SDA(Serial Data Line,串行数据线),用于数据传输(传输方式:大端传输(MSB),一次8bit,即1字节)
时钟线SCL(Serial Clock Line,串行时钟线),用于控制数据同步收发的时序。
2、电路连接图
看下图,SDA和SCL总线通过上拉电阻(一般在4.7k~10k之间)与电源相连接。所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。总线空闲,各设备开漏输出,上拉电阻组总使SDA和SCL保持高电平(这也是控制时序的空闲状态)。
其中的内部结构:
四、协议层
每个接到I2C总线上的元器件都有唯一的地址addr(系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份(可编程部分决定了某类元器件可接入总线的最大数目),细节视芯片而定,看相关的数据手册),共7个bit,广播地址全0。根据元器件的能力,作为发送器或接收器工作。
在协议体系中,传输数据时都会带上目的器件的设备地址,因此可以实现设备组网
1、帧格式
起始信号 | 寻址字节 | 应答信号 | 数据位 | 应答信号 | 终止信号 |
S | 7位地址位+1位读写位 | 1位 | 8位 | 1位 | P |
其中变颜色的为可重复的部分
2、时序
根据上述的帧格式,我们可以结合时序来看一下
除了图中标示的“起始条件”和“终止条件”外,帧中的其他部分均在图中的数据变化中。这也是IIC通信的时序图,这幅图很重要,需要大家记住它,它也是我们编写代码的逻辑体现。
其中数据传输中,有很重要的一点,就是主机在传输一位数据时,那一刻SDA和SCL的的状态,因为主机在传送或者接收的数据时候,必须稳定两条总线的状态(高电平或者低电平),下图讲的就是两条总线的状态。也就是:SCL为高电平时,SDA线必须保持稳定,这样发送或接收的数据才不会出错,才会稳定。(数据线仅可以在时钟SCL为低电平时改变)。这两点就是易忽视和记错的点!(见四、3的“数据有效性”一节)
2.1、空闲状态
PS:代码除特殊标注之外,都是主机的时序逻辑代码
SDA和SCL两条线高电平,这也是上述我说的空闲状态。
void IIC_init() //IIC初始化
{
SCL=1; //首先把时钟线拉高
delay_us(4); //延时函数
SDA=1; //在SCL为高的情况下把SDA拉高
delay_us(4); //延时函数
}
2.2起始信号
SCL=高电平期间,SDA由高电平-->低电平后,延时(>4.7us)
//起始信号
void IIC_Start(void)
{
SDA_OUT(); //SDA线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(5);
IIC_SDA=0; //START:when CLK is high,DATA change form high to low
delay_us(5);//是因为数据线要在时钟线拉高的前提下,高电平保持4us,才能拉低
IIC_SCL=0; //钳住IIC总线,准备发送/接收数据
}
2.3终止信号
SCL=高电平期间,SDA=低电平—>高电平
//停止信号
void IIC_Stop(void)
{
SDA_OUT(); //SDA线输出
IIC_SCL=0;
IIC_SDA=0; //STOP;当SCL高时,数据由低变高
delay_us(4);
IIC_SCL=1;
IIC_SDA=1; //发送IIC总线结束信号
delay_us(4);
}
2.4应答信号
发送器每发送一个字节(8位)就在时钟脉冲9期间释放数据线;接收器反馈一个应答信号(下面两个)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
应答信号=低电平,有效应答位(ACK简称应答位)表示接收器成功接收了该字节
应答信号=高电平,非应答位(NACK)接收器接受该字节没有成功
反馈有效应答位ACK要求:接收器在第9个时钟脉冲之前的低电平期间将SDA拉低,并确保该时钟线SCL高电平期间为稳定的低电平(如下图)
产生应答:在第9个时钟脉冲之前,SCL拉高,并且SDA一直是低电平
//1.先拉低SCL,再拉低SDA
//2.拉高SCL
//3.拉低SCL
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
未产生应答:在第9个时钟脉冲之前,SCL拉高,并且SDA一直是高电平
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
主机数据发送完一个八位之后,释放SDA,此时SDA变成高电平。此时处于等待ACK应答状态。SCL再给一个时钟脉冲,如果有应答信号,SDA会变低 。
//等待应答信号
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
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;//时钟为0
return 0;
}
2.5发送数据/接收数据
发送数据
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟,开始信号传输
for(t=0;t<8;t++)
{
//IIC_SDA=txd&0x80; //获取最高位
//获取数据的最高位,然后右移7位,假设为 1000 0000 右移7位为 0000 0001
// 假设为 0000 0000 右移7位为 0000 0000
//如果某位为1,则SDA为1,否则相反
//IIC_SDA=((txd&0x80)>>7);
//txd<<=1;
//IIC_SDA=txd&0x80; //获取最高位
//获取数据的最高位,然后数据左移一位
//如果某位为1,则SDA为1,否则相反
if(txd&0x80)
IIC_SDA=1;
else
IIC_SDA=0;
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();//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;
}
3、数据有效性
IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
好处:数据不会丢失,不会失真
五、数据传输
传输每一位数据都有一个时钟脉冲相对应(SCL串行时钟的配合下,SDA上逐位串行传送每一位数据)数据位的传输是边沿触发
输出到SDA线上的每个字节必须是8位,数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成 ,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
主机要向从机写数据时:
1、主机首先产生START信号
2、然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方 向位(R/W),0表示主机发送数据(写),1表示主机接收数据(读)
3、主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为发送器和接收器
4、这时候主机等待从机的应答信号(A)
5、当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号
6、当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号,
7、主机产生停止信号,结束传送过程。
主机要从从机读数据时:
1、主机首先产生START信号
2、然后紧跟着发送一个从机地址,注意此时该地址的第8位为0,表明是向从机写命令,
3、这时候主机等待从机的应答信号(ACK)
4、当主机收到应答信号时,发送要访问的地址,继续等待从机的应答信号,
5、当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接收变为发送)所以主机重新发送一个开始start信号,然后紧跟着发送一个从机地址,注意此时该地址的第8位为1,表明将主机设置成接收模式开始读取数据,
6、这时候主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不在接收数据
7、主机进而产生停止信号,结束传送过程。
六、小结
本篇文章介绍了IIC的基础知识,下篇文章《一文弄懂IIC--(进阶篇)》,介绍IIC在具体传感器和芯片中的应用!敬请期待!!!