一.I2C介绍
I2C(Inter-Intergrated Circuit)通信协议是由飞利浦公司开发的一种串行总线,用于连接芯片和其它电路,能够实现简单、低成本的数字通信。51单片机作为一种常用的嵌入式系统芯片,通常采用I2C协议与外部设备通讯。
二.I2C的组成及特点
1.I2C协议使用两条线,即数据线(SDA)和时钟线(SCL),由主机控制总线的时序,从而实现设备之间的数据传输。
2.I2C协议具有以下特点:
(1)双向传输:数据可以在主机和从设备之间双向传输。
(2)多主机共享:多个主机可以共享总线。
(3)从设备寻址:主机可以向多个从设备发送数据,每个设备有一个唯一的地址。
(4)数据传输速率:I2C的数据传输速率通常较慢,最高速率为400kbps。
三、I2C总线传输协议
1.数据位的有效性规定
只有SCL信号为低电平期间,SDA状态才允许变化,当SCL为高电平期间,数据线上的数据必须保持稳定 。
2.起始信号和停止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
3.I2C字节的接收与应答
每传输一个字节,后面跟随一个应答位。通过将 SDA 线拉低,来允许接收端回应发送端。ACK 为 一个低电平信号,当时钟信号为高时, SDA 保持低电平则表明接收端已成功接收到发送端的数据。
当主机作为发送器件时,如果从机上产生无响应信号(NACK) ,主机可以产生停止信号来退出数据传输,或者产生重复起始信号开始新一轮的数据传输。当主机作为接收器件时,发生无响应信号(NACK) ,从机释放 SDA 线,使主机产生停止信号或重复起始信号。
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
4.总线的寻址
I2C协议通过7位的寻址字节。D7-D1位组成从机的地址;D0位是数据传输的方向位,为“0”时表示主机向从机写数据,为“1”时表示由从机读取数据。
I2C总线的7位寻址过程如下:
-
发送起始信号:主设备向总线发送起始信号。
-
发送从设备地址:主设备将7位从设备地址和读/写位发送到总线上,地址格式为“11110XX”,其中“XX”表示从设备的地址。
-
等待从设备响应:主设备等待从设备对地址的响应。
-
发送读/写位:主设备向总线发送读/写位,用于指示数据传输的方向。
-
等待从设备响应:主设备等待从设备对读/写位的响应。
-
发送数据:如果是写操作,主设备向总线发送要写入从设备的数据;如果是读操作,主设备不需要发送数据,而是等待从设备发送数据。
-
结束传输:主设备向总线发送停止信号,结束本次数据传输。
四.I2C程序代码
I2C起始信号代码
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;
void I2C_start(void)//产生I2C起始信号
{
I2C_SDA=1;
delay_10us(1);
I2C_SCL=1;
delay_10us(1);
I2C_SDA=0;
delay_10us(1);//当SCL为高电平时,SDA由高变为低
I2C_SCL=0;
delay_10us(1);//准备发送或接收数据
}
I2C停止信号代码
void I2C_stop(void)//I2C停止信号
{
I2C_SDA=0;
delay_10us(1);
I2C_SCL=1;
delay_10us(1);
I2C_SDA=1;//当SCL为高电平时,SDA由低变为高
delay_10us(1);
}
I2C发送一个字节
void I2C_sendbyte(unsigned char byte)//I2C发送一个字节
{
unsigned char i;
I2C_SCL=0;
for(i=0;i<8;i++) //循环8次
{
I2C_SDA=byte&(0x80>>i);//(高位到低位)依次右移取出每一位放在SDA线上
I2C_SCL=1;
delay_10us(1);
I2C_SCL=0;
delay_10us(1);
}
}
I2C接收一个字节
unsigned char I2C_receivebyte(void)//I2C接收一个字节
{
unsigned char i,byte=0x00;
I2C_SDA=1;
for(i=0;i<8;i++)
{
I2C_SCL=1;
if(I2C_SDA)
{
byte|=(0x80>>i);//把byte最高位置1
}
I2C_SCL=0;
delay_10us(1);
}
return byte;
}
I2C发送应答
void I2C_sendack(unsigned char ack)//I2C发送应答(0为应答,1为非应答)
{
I2C_SDA=ack;
I2C_SCL=1;
delay_10us(1);
I2C_SCL=0;
delay_10us(1);
}
I2C接收应答
unsigned char I2C_receiveack(void)//I2C接收应答(0为应答,1为非应答)
{
unsigned char ack;
I2C_SDA=1;//释放SDA(主机SDA)
delay_10us(1);
I2C_SCL=1;//拉高SCL读取数据位
delay_10us(1);
ack=I2C_SDA;//从机SDA
I2C_SCL=0;
delay_10us(1);
return ack;
}