一、IIC简介

IIC
(
Inter-Integrated Circuit
,又称为
I2C
或
I²C
)是一种串行同步传输通信协议,用于连接微控制器和外部设备,例如传感 器、存储器、显示器等。它是一种简单而灵活的通信协议,由飞利浦公司(现在的恩智浦半导体)在1982
年开发。
IIC通讯协议包括两根线,一根是串行数据线(SDA),另一根是串行时钟线(SCL)。在通讯过程中,数据通过SDA线传输,而SCL线则用来同步数据传输速度。由于只有一根串行数据线(SDA)用来传输数据,在同一时间内只能进行单向的数据传输,即发送或接收不能同时进行,但可以在不同时间交替进行。所以I2C是半双工通信。
主从结构: I2C通信中,设备分为主设备(通常是微控制器)和从设备(例如传感器或存储器)。主设备负责发起通信和控制通信的时序,而从设备响应主设备的指令,可以有多个从设备。
地址寻址: 每个
I2C
设备都有一个唯一的
7位
或10位地址,主设备通过发送目标设备的地址来选择通信对象,我们通常使用的是7位地址
二、IIC通讯协议示意图:

主机发送开始通信信号后,首先发送7位从机地址,选择与哪一个从机进行通信,然后从机发送应答响应,才开始传输数据,最后一次数据传输完成后,主机等不到应答信号,通信结束
三、IIC通信要点:
1、I2C通信设备为什么通常配置为开漏输出:
1、I2C通信设备为什么通常配置为开漏输出:
I2C
总线上的信号(SCL)是开漏输出的,这意味着每个
I2C
设备的输出引脚都是一个开漏输出,可
以通过外部上拉电阻拉高。这种设计允许多个设备共享同一根总线,而不会出现信号冲突和短路。
(当
I2C
设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。)
2、IIC通信逻辑
IIC通讯默认状态下SDA(数据线)SCL(信号线)都为高电平,我们一次IIC通信中,SDA(数据线)的高低电平总是在SCL(信号线)为低电平时转换的;SCL(信号线)为高电平时,读取SDA(数据线)的电平状态(低电平代表接收到0,高电平代表接收到1)。因为SCL(信号线)为高电平时,SDA(数据线)从高电平转换为低电平,代表着一次IIC通信的开始,而SCL(信号线)为高电平时,SDA(数据线)从低电平转换为高电平,则代表着一次IIC通信的结束。
四、IIC协议代码实现:
开始信号:
当SCL保持高电平的时候,SDA从高电平变为低电平,这标志着一个IIC传输的开始。这种电平的变化被IIC主设备用来通知所有连接到IIC总线上的从设备,即将开始一次数据传输。
//IIC开始信号
void IIC_Start(void)
{
IIC_SDA_OUT();
IIC_SDA_H;
IIC_SCL_H;
Delay_us(4); //让高电平保持稳定
IIC_SDA_L; //在SCL高电平时,将SDA拉低
Delay_us(4);
IIC_SCL_L; //钳住IIC总线,准备发送数据
}
应答信号(结束信号不需要应答。一旦发出结束信号,从设备会自动释放总线,允许其他设备进行通信):
在每个字节传输后,发送方会释放SDA线,允许接收方发送应答信号。接收方会在第9个时钟周期(SCL为高电平期间)将SDA拉低以发出ACK(应答)信号,或者保持SDA高电平以发出NACK(非应答)信号。
//IIC应答信号
void IIC_ACK(void)
{
IIC_SDA_OUT();
IIC_SCL_L; //在SCL低电平时候,SDA可以进行数据切换的(0/1)
IIC_SDA_L; //SDA低电平表示应答
Delay_us(1); //让电平稳定
IIC_SCL_H; //SCL拉高,表示此刻SDA数据有效,读出来SDA是低电平,表示应答。
Delay_us(1); //读取稳定时间
IIC_SCL_L; //拉低SCL,表示一个SCL周期结束,为下次读取做准备。
}
//IIC非应答信号
void IIC_NACK(void)
{
IIC_SDA_OUT();
IIC_SCL_L;
IIC_SDA_H;//SDA低电平表示非应答
Delay_us(1);
IIC_SCL_H;
Delay_us(1);
IIC_SCL_L;
}
等待应答;STM32单片机发送完一个字节之后,等待从设备回复应答信号
//IIC等待应答,返回0表示应答了,1表示非应答
uint8_t IIC_WaitACK(void)
{
IIC_SDA_IN();
IIC_SDA_H; //先让SDA默认为高电平,如果后面发现变低了,说明从机应答了
Delay_us(1); //电平平稳
uint8_t temp=0;
IIC_SCL_H; //SCL高,SDA数据有效
Delay_us(1); //电平平稳
//设置一个超时应答时间
while(READ_SDA)
{
temp++;
if(temp>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL_L;
return 0;
}
结束信号:
当SCL保持高电平的时候,SDA从低电平变为高电平,这标志着一个IIC传输的结束。
//IIC结束信号
void IIC_Stop(void)
{
IIC_SDA_OUT();
IIC_SCL_H;
IIC_SDA_L;
Delay_us(4);
IIC_SDA_H;
}
读取一个字节:通过传参的形式,设置第九个时钟周期是高电平(非应答)还是低电平(应答),将应答信号反馈给从设备
//IIC读取一个字节
uint8_t IIC_ReadByte(uint8_t ack) //ack 0应答 ,1非应答
{
IIC_SDA_IN();
uint8_t i , receive=0;
for(i=0;i<8;i++)
{
IIC_SCL_L;
Delay_us(1);
IIC_SCL_H; //SDA数据有效
receive <<=1;
if(READ_SDA)
{
receive++; //读多了高电平
}
Delay_us(1); //电平平稳
}
if(ack)
IIC_NACK();
else
IIC_ACK();
return receive;
}
发送一个字节:STM32单片机向从设备发送一个字节的数据,发送一个字节之后要判断等待一下从设备的应答或非应答信号
//IIC发送一个字节
void IIC_SendByte(uint8_t data)
{
IIC_SDA_OUT();
IIC_SCL_L; //在SCL低电平时候,SDA可以进行数据切换的(0/1)
uint8_t i=0;
for(i=0;i<8;i++)
{
if(data&0x80) //0x80 1000 0000
{
IIC_SDA_H; //高电平,1
}
else
{
IIC_SDA_L;
}
IIC_SCL_H; //SCL拉高,数据有效
Delay_us(1);//延时,将数据发出去
IIC_SCL_L; //SCL拉低,为下一次SDA变化做准备
Delay_us(1); //低电平处于稳定的状态
data<<=1; //左移
}
}