- I2C总线
- 两线制
- 多主多从
- 双向
- 同步通信
- 半双工
- 串行通信
- I2C通信数据传输流程
- 启动信号
- 地址位和读写位
- 应答信号
- 发送数据
- 停止信号
- 按读和写两种模式来看I2C通信
- I2C通信总结
- 代码实现
- 发送启动信号
- 发送停止信号
- 发送数据
- 接收数据
- 接收应答信号
- 发送应答信号
I2C总线
I2C总线(读作I方C总线),全称Inter-Integrated Circuit,它是由飞利浦公司研发的二线制、多主多从、双向、同步、半双工的串行总线。I2C通信就是利用I2C总线进行数据传输,
两线制
只需要两个引脚进行数据传输
设备间能发送数据,主要是通过SDA这个数据引脚传输,传低电平把SDA拉低,传高电平就是把SDA拉高
用时钟信号SCL引脚控制传输的节拍。
多主多从
多主多从是指在这一个I2C总线上可以有多个主机和多个从机
当然也可以一主一从或者一主多从
主机多为控制芯片(单片机),从机多为显示设备或传感器等
主机是可以发出命令的设备,从机是能接收命令的设备
通信规则:
- 任何时刻,从机只接收一个主机的命令;
- 多主机情况下,从机优先接收最先发送命令的主机的命令;
- 为了区分命令发给谁,每个设备都有自己的地址,即每个设备都有设备ID。
双向
双向是指,主机可以向从机发送数据,也可以接收从机发来的数据,从机可以接收主机发来的数据,也可以向主机发送数据,传输数据的方向是双向的
同步通信
I2C通信通过设备的SCL引脚传递时钟信号,对数据传输进行同步
半双工
数据传送虽然是双向,但是数据线就一根,需要分时传送,即任何时刻只能有一个方向的数据传输
串行通信
传输数据时是一位一位从高位开始从高到底传输,也就是发送一个字节,首先发送的是这个字节对应的最高位二进制,接收一个字节也是同理
I2C通信数据传输流程
一次完整的I2C通信包括:(1)启动信号;(2)发送地址位和读写位(放在一个字节里面发送);(3)接收应答位;(4)发送数据(接收数据);(5)接收(发送)应答位;(6)停止信号
启动信号
每一次I2C通信,先以一个启动信号开始,I2C通信有固定的启动信号,在程序中只要按具体时序图要求发送启动信号。
如上图,也就是SDA下降沿,SCL高电平。
地址位和读写位
靠地址位找到对应的通信设备,也称为寻址,每个从机都有一个固定的器件地址,有7位的,有10位的,下面只介绍7位的地址,每次通信设备的地址要设定准确。
比如olde屏幕,通常是主机对其进行写操作,读写位置0,其他7位记录要通信的设备地址
应答信号
主机在发送为地址位和读写位后,就会等待接收一位数据,根据这个数据判断从机是否正确地应答了,数据0表示接收数据成功,即正确应答,数据1表示未成功接收,即非应答。
主机接收完数据同样要给从机发送应答信号,也是数据0表示接收数据成功,即正确应答,数据1表示未成功接收,即非应答。
发送数据
依次将一个字节8位二进制从高位到低位发送
停止信号
SCL高电平,SDA上升沿,一次I2C通信完成就要以停止信号结束
按读和写两种模式来看I2C通信
按读和写两种不同模式,I2C通信过程也有所不同
写模式:
读模式:
当从机内部也有不同寄存器代表不同功能时,就需要区分,发布的数据是要写入哪个寄存器的,在发送完地址位和读写位并收到应答位后,要先发送内部寄存器的地址,仍然是将地址以一个8位数据发送过去,收到应答后,收到应答后,再继续发送要写入到这个寄存器的数据
这一部分都可以称为是发送数据
I2C通信总结
代码实现
I2C通信的波特率是100K,也就是每秒传送10万个位,取倒数,一位传送实际是10微秒,也就是SCL的时钟周期不能小于10微秒
也就是它的高电平和低电平的总时长不能小于10微秒
所以平均一下就是高电平和低电平的时间都不要小于5微秒
我这个板子的晶振是11.0592Mhz,一个机器周期是正好的1微秒,Delay函数中四个空语句,恰好是4个机器周期,也就是4微秒,在程序中利用这一语句实现传输速率的调整
//I2C通信专用延时程序
void delayI2C()
{_nop_();_nop_();_nop_();_nop_();
}
发送启动信号
//初始化I2C通信
void initI2C()
{//先都拉高成高电平SCL = 1;SDA = 1;//下降沿delayI2C();SDA = 0;delayI2C();SCL = 0;
}
【注】REGX52.H并没有包含SCL SDA位,要看对应的通信的模块的引脚和单片机引脚的连接
发送停止信号
SCL先高电平,SDA上升沿
//关闭I2C通信
void closeI2C()
{//先都拉低SCL = 0;SDA = 0;delayI2C();SCL = 1; //先拉高SCLdelayI2C();SDA = 1; //SCL高电平期间,再拉高SDA,这样就产生了一个上升沿delayI2C();}
发送数据
发送数据的规则就是,在SCL低电平期间,将要传送的数据位放到SDA线上,然后拉高SCL,从机在SCL高电平期间,读取SDA线上的数据依次循环8次就可以将一个字节的数据传送出去,
//I2C写入一个字节,I2C_Byte是待传送的数据
void writeByteI2C(unsigned char I2C_Byte)
{unsigned char i = 0;for(i = 0; i<8; i++){//I2C_Byte & 0x80(1000 0000)//获取最高位,看是1还是0if(I2C_Byte & 0x80){SDA = 1;}else{SDA = 0;}delayI2C();SCL = 1;delayI2C();SCL = 0;I2C_Byte <<= 1; //左移,循环读取每一位,让每一位都成为首位}
}
接收数据
// I2C读一个字节
unsigned char readByteI2C()
{unsigned char i, Byte = 0x00;for(i = 0; i<8; i++){SDA = 1; //拉高SDA,释放I2C总线//读总线之前一定要将SDA拉高SCL = 1; //然后将SCL拉高,准备接收SDA状态delayI2C();if(SDA){Byte |= (0x80>>i); //依次循环右移,得到一个字节(0x00分别或每一位得到,如果是低电平,不需要操作,该位就是0)}SCL = 0;}return Byte;
}
接收应答信号
//读取I2C总线应答信号
bit readAckI2C()
{bit Ack_bit; //应答信号SDA = 1; //拉高SDA,释放I2CdelayI2C();SCL = 1; // 把SCL拉高,第9个时钟信号delayI2C();Ack_bit = SDA; //读取应答信号delayI2C();SCL = 0; //拉低SCL,结束接收应答return Ack_bit;
}
发送应答信号
主机在接收完数据后,会给从机发送应答信号,主机成功接收,会在数据线SDA发送0,接收失败会发送1
//I2C发送应答位
void writeAckI2C(bit Ack_bit)
{//根据应答状态变量来确定SDA是1还是0if(Ack_bit){SDA = 1;}else{SDA = 0;}//第9个时钟周期//拉高SCL,再拉低SCL,完成一次发送应答信号SCL = 1; SCL = 0;
}