目录
一、IIC(Inter-Integrated Circuit)总线介绍
二、IIC协议
(一)IIC通信过程
(二)起始信号和停止信号
程序
(三)应答信号和非应答信号
程序
(四)数据有效性
1.读一个字节程序
2.写一个字节程序
1.用于连接微控制器及其外围设备,多用与主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机。在CPU与被控IC之间,IC与IC之间进行双向传送,高速IIC总线可达400kbps以上。
2.IIC总线上的每个设备都有自己的一个唯一的地址,来确保不同设备之间访问的准确性。
3.IIC总线上一共只有两个总线,一条是双向的串行数据线SDA,一条是串行时钟线SCL;
4.传输数据的设备间是简单的主/从关系(即数据传输是从主机发起,从机接收,从机不可能主动引起数据传输)
5.串行的8位双向数据传输。
6.IIC的高阻态:用于输入/输出,可独立输入/输出低电平和高阻状态,若需要产生高电平,则需使用外部上拉电阻。高阻状态是是三态门电路的一种状态。逻辑门的输出除了有高,低电平两种状态外,还有第三种状态—高阻状态的门电路,电路分析时可看做开路理解。为了避免总线信号的混乱,IIC的空闲状态有外部上拉,而此时空闲设备被拉到了高祖态,相当于断路,整个IIC总线只有开启了的设备才会正常进行通信,而不会干扰到其他设备。
首先由主机产生一个起始信号(START),此时连接到IIC总线上的所有从机都会接收这个信号,所有从机开始等待主机接下来发送的第一个命令字节(共8位,高7位表示从机地址,最低位表示读、写),在总线上,每个设备的地址都是唯一的,当主机发送了命令字节后,所有从机会开始进行地址匹配,当某设备地址与主机发送的地址相同时,这个设备就被选中了,没有选中的设备会忽略之后的所有信息,继续保持高阻态连接。当从机匹配到地址后,从机会向主机发送一个应答信号(ACK),只有主机接收到应答信号之后,主机才能继续发送或接收信号。
当读写位配置为0时,表示由主机向从机写数据。当主机接收到从机的应答信号之后,主机开始正式向从机发送数据,数据以字节为单位传输,主机每发送完一个字节数据,都要等待从机的应答信号(ACK),重复这个过程,主机可以向从机传输N个数据,传输字节数量没有限制。当数据传输结束时,主机向从机发送一个停止传输信息(STOP),表示不再传输数据。
当读写位配置为1时,表示由主机向从机读数据。当主机接收到从机的应答信号之后,主机开始正式从从机读取数据,数据也是以字节为单位传输,从机每发送完一个字节数据,都会等待主机发送应答信号(ACK),重复这个过程,主机可以从从机读取N个数据,传输字节数量没有限制。当传输结束时,主机向从机发送一个非应答信号(NACK),则从机停止发送数据。
当 SCL 线是高电平时 SDA 线从高电平向低电平切换,这个情况表示通讯的起始。当 SCL 是高电平时 SDA线由低电平向高电平切换,表示通讯的停止。起始和停止信号一般由主机产生。
/*
*********************************************************************************************************
* 函 数 名: IIC_Start
* 功能说明: CPU发起IIC总线启动信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void IIC_Start(void)
{
/* 当SCL高电平时,SDA出现一个下跳沿表示IIC总线启动信号 */
IIC_SDA_1();
IIC_SCL_1();
IIC_Delay();
IIC_SDA_0();
IIC_Delay();
IIC_SCL_0();
IIC_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: IIC_Start
* 功能说明: CPU发起IIC总线停止信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void IIC_Stop(void)
{
/* 当SCL高电平时,SDA出现一个上跳沿表示OLED_IIC总线停止信号 */
IIC_SDA_0();
IIC_SCL_1();
IIC_Delay();
IIC_SDA_1();
}
若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号,发送方会继续发送下
一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号,发送方接
收到该信号后会产生一个停止信号,结束信号传输,等待应答期间,SDA为高电平表示非应答信号,为低电平表示应答信号。
/*
*********************************************************************************************************
* 函 数 名: IIC_Ack
* 功能说明: CPU产生一个ACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void IIC_Ack(void)
{
IIC_SDA_0(); /* CPU驱动SDA = 0 */
IIC_Delay();
IIC_SCL_1(); /* CPU产生1个时钟 */
IIC_Delay();
IIC_SCL_0();
IIC_Delay();
IIC_SDA_1(); /* CPU释放SDA总线 */
}
/*
*********************************************************************************************************
* 函 数 名: IIC_NAck
* 功能说明: CPU产生1个NACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void IIC_NAck(void)
{
IIC_SDA_1(); /* CPU驱动SDA = 1 */
IIC_Delay();
IIC_SCL_1(); /* CPU产生1个时钟 */
IIC_Delay();
IIC_SCL_0();
IIC_Delay();
}
在时钟的高电平周期内,SDA线上的数据必须保持稳定,数据线仅可以在时钟SCL为低电平时改变,如下图。
/*
*********************************************************************************************************
* 函 数 名: IIC_ReadByte
* 功能说明: CPU从IIC总线设备读取8bit数据
* 形 参:无
* 返 回 值: 读到的数据
*********************************************************************************************************
*/
static uint8_t IIC_ReadByte(void)
{
uint8_t i;
uint8_t value;
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
IIC_SCL_1();
IIC_Delay();
if (IIC_SDA_READ())
{
value++;
}
IIC_SCL_0();
IIC_Delay();
}
return value;
}
/*
*********************************************************************************************************
* 函 数 名: IIC_SendByte
* 功能说明: CPU向IIC总线设备发送8bit数据
* 形 参:_ucByte : 等待发送的字节
* 返 回 值: 无
*********************************************************************************************************
*/
static void IIC_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
IIC_SDA_1();
}
else
{
IIC_SDA_0();
}
IIC_Delay();
IIC_SCL_1();
IIC_Delay();
IIC_SCL_0();
if (i == 7)
{
IIC_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
IIC_Delay();
}
}
至此,相信读者已经对IIC总线有了初步认识,具体的IIC如何应用可能还是一脸懵逼的,但是不要慌,下一期我们使用IIC通信协议对24C32(EEPROM存储器)进行读写操作,安排!