学会IIC的原理及应用,这一篇文章就够了

1.IIC基础知识

        1.1什么是IIC?

        IIC(Inter-Integrated Circuit)是 IIC Bus 简称,中文叫集成电路总线。它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。自2006年10月1日起,使用I²C协议已经不需要支付专利费,但制造商仍然需要付费以获取I²C从属设备地址。
  IIC使用两根信号线进行通信:一根时钟线SCL,一根数据线SDA。IIC将SCL处于高时SDA拉低的动作作为开始信号,SCL处于高时SDA拉高的动作作为结束信号;传输数据时,SDA在SCL低电平时改变数据,在SCL高电平时保持数据,每个SCL脉冲的高电平传递1位数据

        IIC是同步半双工的通信方式,带数据应答,支持总线挂载多设备(一主多从,多主多从)。

        1.2IIC总线物理拓扑图

        接线: 所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每个设备都自己一个唯一的地址,来确保不同设备之间访问的准确性。如图为 IIC总线物理拓扑图。

SDA: 双向串行数据线,数据既可以从主机发送到从机,也可以从从机发送到主机。
SCL: 串行时钟线,驱动数据线的信号由 SCL 产生。
主机 : 主机产生串行时钟( SCL )控制总线的传输方向,并产生起始条件(占用总线)和停止条件(释放总线)。
从机 :从机不会控制 SCL 线,从机可以发送数据给主机,但是从机永远不可能 主动 发送数据给主机。
发送器 :发送数据的一方
接收器 :接受数据的一方
仲裁器 :解决多主机模式下竞争总线的问题。(通常情况下我们遇到的都是单主机模式,一主多从)
总线的空闲状态 SDA 和 SCL 都是高电平
注意:①所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。②设备的SCL和SDA均要配置成开漏输出模式。③SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右。

        1.3IIC主从设备通信

        主机如何才能找到想要通信的从机并与它通信呢?

        在 IIC 总线上,所有的从设备都有其唯一的一个器件地址,作为在总线唯一的标识。 器件地址可以为 7 位或者 10 位,器件地址包含固定地址(由厂家决定)和可编程地址(由使用者决定) 器件地址的位数和固定地址的位数、可编程地址的位数、固定地址的内容都是由厂家决定。

        例如7位的器件地址,一般前四位为固定地址,后三位为可编程地址:

        主设备通过从设备的器件地址找到该从设备,与其通信。
        从设备的器件地址具体的内容要通过其数据手册查看,不同厂家是不一样的。
          

2.IIC时序

        2.1IIC数据帧的格式

        IIC 数据帧格式:起始条件(占用总线)+数据位(8 位,发送方发出)+应答位(1 位,接收到 1 个字节数据的一方要回一个应答,0 有应答,1 非应答)+停止条件(释放总线)

IIC 总线上主从设备通信过程:

1. 主机发送起始条件(占用总线)
2. 主机发送器件地址(寻找从机)
3. 在当前总线上的从机会将此器件地址跟自己对比,匹配成功就会回一个应答给主机。其他从机继续休眠。
4. 主机和从机就可以建立通信,在这个过程中,接收方每成功接收到一个字节数据必须要给发送方一个应
答,如果发送方等不到应答则标志通信失败。
5. 主机发送停止条件(释放总线)

        2.2IIC标准时序

        要想使用IIC通信,最重要的还是要了解IIC的标准时序。

        2.2.1起始条件

        起始条件:SCL保持高电平,SDA由高电平变为低电平后,延时(>4.7us),SCL变为低电平。

​
//1.先拉高SDA,再拉高SCL,空闲状态
//2.拉低SDA,产生起始条件
void IIC_Start()         //启动信号

{
       SDA=1; //确保SDA线为高电平
       SCL=1;  //确保SCL高电平
       delay_us(5);//延时--起始条件建立时间
       SDA=0; //在SCL为高时拉低SDA线,即为起始信号
       delay_us(5); //延时--起始条件保持时间
       SCL=0;   //钳住I2C总线,准备发送或接收数据 
    
}

​

        2.2.2停止条件

        停止条件:SCL保持高电平。SDA由低电平变为高电平。

void IIC_Stop(void)   //终止条件:SCL高电平期间,SDA从低拉高
{
	SDA=0;
	SCL=1;
	Delay_us(6);//延时---停止条件的建立时间
	SDA=1; //---产生了停止条件
	Delay_us(6);//延时---本次通信结束到下次通信开始的时间
}

        2.2.3应答信号

        在 IIC 通信过程中,发送方每发送完一个字节数据给接收方,接收方收到后都必须回一个应答给发送方   应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答,

主机如何接收从机的一个应答?
1. 主机拉低 SCL
从机根据自己接受数据的情况,给不给应答主机
2. 主机拉高 SCL
3. 主机读取 SDA 上的应答(如果读到的是 0 ,说明有应答,如果读到的是 1 ,说明没有应答)
uint8_t IIC1_Revice_Ack(void)    //主机接收应答信号
{
	uint8_t ack=0;
	IIC1_SCL=0;//(从机准备数据)
	IIC1_SDA_OUT=1;//读模式-----让输出电路与管脚断开!!!!!!!!!!
	Delay_us(6);//延时(给时间从机准备数据并且数据稳定在数据线上)
	IIC1_SCL=1;
	Delay_us(6);//延时 (给时间主机读取数据)
	if(IIC1_SDA_IN)//主机读取SDA线上的数据
		ack=1;
	
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	return ack;
}
主机如何发送应答给从机?
1. 主机拉低 SCL
2. 主机根据自己的情况决定要不要给应答从机(发送 0 代表有应答, 1 代表非应答)
3. 主机拉高 SCL (从机在 SCL 上升沿读取应答)
void IIC1_Send_Ack(uint8_t ack)    //主机发送应答信号 (SCL低电平时,往SDA放数据;SCL上升沿,从机从SDA读数据)
{

	IIC1_SCL=0;               //拉低SCL 主机放数据   0表示应答 1表示无应答
	if(ack)//(主机准备数据)
		IIC1_SDA_OUT=1;
	else
		IIC1_SDA_OUT=0;
	Delay_us(6);//延时(数据稳定在数据线上)
	IIC1_SCL=1;//(从机在时钟线上升沿从SDA上采集数据)   此时从机自动读取SDA_OUT的数据
	Delay_us(6);//延时(给时间从机读取数据)
	
//	IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
}

        2.2.4IIC的寻址方式

     

器件地址:从设备地址位( 7 位) + 方向位( 1 位)
从设备地址位:固定地址 + 可编程地址
方向位:决定主机发送数据还是读取数据(0写1读)
举例:器件地址 (8 )--- XXXX XXX R/W
1. 主机发送起始条件(主机占用总线,唤醒总线上所有的从设备)
2. 主机发送器件地址(总线上的从设备会拿这个地址跟自身作比较,如果匹配,就回发一个应答给主机)
3. 主机和从机进行数据交流
( 根据器件地址上的方向位来决定是主机发送数据给从机还是主机读取从机的数据 )
4. 主机发送停止条件(主机释放总线)

        2.2.5IIC的三种通信过程

发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。

uint8_t IIC1_Send_Byte(uint8_t data)
{
	uint8_t i=0;
	for(i=0;i<8;i++)
	{
		IIC1_SCL=0;
		if((data<<i)&0x80)//(主机准备数据)    依次左移 判断最高位是0还是1 然后将值放在IIC1_SDA_OUT上
			IIC1_SDA_OUT=1;              
		else
			IIC1_SDA_OUT=0;
		Delay_us(6);//延时(数据稳定在数据线上)
		IIC1_SCL=1;//(从机在时钟线上升沿从SDA上采集数据)
		Delay_us(6);//延时(给时间从机读取数据)
	}
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	return IIC1_Revice_Ack( );  //接收应答信号
}

读取一个字节:SCL低电平期间,从机将数据位依次放到SDA线上然后释放SCL,主机将在SCL高电平期间读取数据位(高位先行),所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次即可接收一个字节(主机在接收之前,需要释放SDA)

uint8_t IIC1_Revice_Byte(uint8_t ack)
{
	uint8_t i=0;
	uint8_t data=0;
	
	for(i=0;i<8;i++)
	{
		IIC1_SCL=0;//(从机准备数据)
		IIC1_SDA_OUT=1;//读模式-----让输出电路与管脚断开!!!!!!!!!!
		Delay_us(6);//延时(给时间从机准备数据并且数据稳定在数据线上)
		IIC1_SCL=1;
		data = (data<<1) | (IIC1_SDA_IN);     //data每次左移一位 空出最低位来存储当前数据
		Delay_us(6);//延时 (给时间主机读取数据)
		
	}
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	IIC1_Send_Ack(ack);
	
	return data;
}

边读边写:边读边写基本时序同上面一样,只不过需要发送重复的起始条件

        3.软件IIC与硬件IIC

        由于 IIC 控制器存在缺陷,一般都不会采用芯片内部的 IIC 控制器。所以要想采用 IIC 通信跟外设进行数据交流,常常使用 IO 口模拟 IIC 时序。
        IIC 总线是两线制通信协议,所以只需要采用两个 IO 口即可,一个 IO 口作为 SCL ,另一个作为 SDA。
        作为 SCL IO 口: SCL 只能由主机发出,把这个 IO 配置成输出模式,推挽输出和开漏输出均可
        作为 SDA IO 口: SDA 是双向数据线,既能从主机发出数据,主机也能在 SDA 读取数据。刚好在 IO 口 配置成输出模式时,输入电路并没有被关闭。但是,在采用输入的时候,不能让输出 电路影响到输入电路,必须配置成开漏输出,在读取数据前,输出“1 ”把输出电路 从 IO 口断开。
 以上内容均为本人学习时的总结,如有错误,希望大家批评指正!
  • 34
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值