IIC协议概述
前言
这几天,我的一个朋友告诉我IIC协议的内容在面试的时候经常会被问到,所以今天写了这篇文章,重新复习了下相关协议内容。
提示:以下是本篇文章正文内容,仅供参考,若有错误欢迎指正
一、IIC概述
IIC,英文全称叫做Inter Intergrated Circuit,集成电路总线,是一种同步 串行 半双工通信总线。(半双工即双方可互相通信,但不能同时通信)同步这两个字很关键,这说明它需要一个时钟线(SCL)。
IIC拓扑图如下(图源于网络):
- IIC由两根线组成,一根是SDA(数据线)、另一根是SCL(时钟线)。还有一个上拉电阻:说明在空闲状态是高电平。
- 总线支持多设备连接,允许多主机存在,每个设备都有唯一的地址。
- 连接到总线上的数目受总线的最大电容400pf限制。
- 传输速率:标准模式:100k bit/s,快速模式400k bit/s,高速模式3.4Mbit/s。
二、IIC的三个信号
IIC有三个信号,分别是起始信号、应答信号、停止信号
1.起始信号
需要注意的是,SDA(数据线)和SCL(时钟线)受上拉电阻的影响,所以其默认状态为高电平,而按照逻辑来讲:既然接收到了起始信号,那必然是发生了状态变化才对,所以SDA和SCL必然有一根发生了状态变化,即从高电平跳变为低电平。
开始信号的特点如下:
当时钟线SCL在高电平
时,数据线SDA从高电平跳变为低电平
。
2.应答信号
上拉电阻影响下SDA默认为高电平,而从机拉低SDA就是确认收到数据
(ACK),若还是高电平就表示没有收到数据
(NACK)。
3.停止信号
停止信号与起始信号相反,当时钟线SCL在高电平时
,数据线SDA从低电平跳变为高电平
。
三、模拟IIC
起始信号与停止信号两者相似,便放一起了:
//起始信号
void iic_start(void)
{
//起始信号:SCL在高电平期间,SDA从高电平往低电平跳变
//起始状态,两根总线都为高电平
IIC_SDA(1);
IIC_SCL(1);
//延时
iic_delay();//延时的具体时间根据从机器件决定
//SDA从高电平跳变为低电平
IIC_SDA(0);
iic_delay();
IIC_SCL(0);
iic_delay();//钳住总线,准备发送/接收数据
}
//停止信号
void iic_stop(void)
{
//停止信号:SCL为高电平期间,SDA从低电平往高电平跳变
//先拉低SDA
IIC_SDA(0);
iic_delay();
//拉高SCL
IIC_SCL(1);
iic_delay();
//SDA从低电平跳变到高电平
IIC_SDA(1);
iic_delay();
}
应答信号的:
//检查应答信号
unint_t iic_wait_ack(void)
{
//主机释放SDA
IIC_SDA(1);
iic_delay();
//从机返回ACK
IIC_SCL(1);
iic_delay();
if(IIC_READ_SDA)//SDA为高电平,表示从机没有收到数据
{
iic_stop();
return 1;
}
IIC_SCL(0);//SCL变低电平表示ACK检查结束
iic_delay();
return 0;
}
//发送应答信号
void iic_ack(void)
{
IIC_SCL(0);
iic_delay();
IIC_SDA(0);//SDA为低电平,表示应答
iic_delay();
IIC_SCL(1);
iic_delay();
}
//发送非应答信号
void iic_nack(void)
{
IIC_SCL(0);
iic_delay();
IIC_SDA(1);//SDA为高电平,表示非应答
iic_delay();
IIC_SCL(1);
iic_delay();
}
发送和读取一字节:
//发送一字节数据
void iic_send_byte(uint8_t data)
{
for(uint8_t t=0;t<8;t++)
{
//高位先发
IIC_SDA((data&0x80)>>7);
iic_delay();
IIC_SCL(1);
iic_delay();
IIC_SCL(0);
data<<=1;//左移一位,用于下一次发送
}
IIC_SDA(1);//发送完成,主机释放数据线SDA
}
//读取一字节数据
uint8_t iic_read_byte(uint8_t ack)//1:ack;0:nack
{
unint8_t receive=0;
for(unin8_t t=0;t<8;t++)
{
//高位先输出,先收到的数据要左移
receive<<=1;
IIC_SCL(1);
iic_delay();
if(IIC_READ_SDA)
receive++;
IIC_SCL(0);
iic_delay();
}
if(!ack)
{
iic_nack();
}else
{
iic_ack();
}
return receive;
}
为什么(data&0x80)>>7能取最高位的值:
以data=10011100举个例子,0x80,转换为2进制之后就是1000 0000,与1001 1100想与,得到结果为1000 0000,任何数与0x80相与后,后七位都是0,最高位是1还是0取决于跟0x80相与的数最高位为0或1,相与之后右移一位则去除了后面七个0,得到的就是最高位的数。