IIC概述
IIC总线是一种串行半双工两线总线。一根是双向的数据线SDA,另一根是时钟线SCL。所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。硬件拓扑如下图所示,且每个器件都有唯一的设备地址来确定每个器件,地址位通常为7bit。
IIC总线是一种多主机总线,连接在IIC总线上的器件可分为主机和从机。其中每个器件都可以作为主机也可以作为从机。(但同一时刻只能有一个主机)。主机有权发起和结束一次通讯。而从机只能被主机呼叫。并且,IIC总线的时钟信号是由主控器件(主机)产生。在传输速率上,串行的8位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s。
IIC总线上的器件增加和删除不会影响其他器件正常工作,并且IIC总线在通讯时总线上发送数据的器件称为发送器,接收数据的器件称为接收器。
- 对于硬件IIC和软件IIC各有优劣,考虑实际情况具体使用。为更好理解IIC,文章下描述的是采用软件IIC。
IIC协议
IIC的通信过程由开始、结束、发送、响应、接收五个部分构成。并且在通讯过程中,IIC的SCL线和SDA线遵循以下原则:
- 当SCL高电平时采样SDA电平状态,此时SDA电平状态不允许改变。
- 当SCL低电平时不采样SDA电平状态,此时SDA电平状态允许改变。
- IIC在总线空闲状态时,这两根线通常是被外部上拉电阻拉高,保持着高电平。
IIC总线通讯过程
- 主机发送起始信号启用总线
- 主机发送一个字节数据,指明从机地址和后续字节的传输方向(7bit地址加1bit读写(0-主机写/1-主机读))
- 被寻址的从机发送应答信号回应主机
- 发送器发送一个字节数据
- 接收器发送应答信号回应发送机
- (…循环4.5)
- 通讯完成后,主机发送停止信号释放总线
典型的IIC时序
下面是拆分通讯过程的描述和代码实现。
开始信号与停止信号
- 开始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平。
- 停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
- 此时的起始信号和停止信号都是由主机发出的,起始信号产生后,总线处于占用,停止信号产生后,总线处于空闲状态(MSB)。
void IIC_Start(void)
{
SDA_OUT();
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;
delay_us(4);
IIC_SCL=0;
}
void IIC_Stop(void)
{
SDA_OUT();
IIC_SCL=0;
IIC_SDA=0;
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;
delay_us(4);
}
应答信号
发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
- 当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,从机应答主机所需要的时钟仍是主机提供的。应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答。
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN();
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;
return 0;
}
- 当从机向主机发送完一个字节的数据,从机也是需要等待主机给出一个应答信号。
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
发送数据
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;
for(t=0;t<8;t++)
{
if((txd&0x80)>>7)
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();
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();
else
IIC_Ack();
return receive;
}
参考文章
[1]: IIC通信详解
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)