1.IIC基础知识
1.1什么是IIC?
IIC(Inter-Integrated Circuit)是 IIC Bus 简称,中文叫集成电路总线。它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。自2006年10月1日起,使用I²C协议已经不需要支付专利费,但制造商仍然需要付费以获取I²C从属设备地址。
IIC使用两根信号线进行通信:一根时钟线SCL,一根数据线SDA。IIC将SCL处于高时SDA拉低的动作作为开始信号,SCL处于高时SDA拉高的动作作为结束信号;传输数据时,SDA在SCL低电平时改变数据,在SCL高电平时保持数据,每个SCL脉冲的高电平传递1位数据
IIC是同步半双工的通信方式,带数据应答,支持总线挂载多设备(一主多从,多主多从)。
1.2IIC总线物理拓扑图
接线: 所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每个设备都自己一个唯一的地址,来确保不同设备之间访问的准确性。如图为 IIC总线物理拓扑图。
1.3IIC主从设备通信
主机如何才能找到想要通信的从机并与它通信呢?
在 IIC 总线上,所有的从设备都有其唯一的一个器件地址,作为在总线唯一的标识。 器件地址可以为 7 位或者 10 位,器件地址包含固定地址(由厂家决定)和可编程地址(由使用者决定) 器件地址的位数和固定地址的位数、可编程地址的位数、固定地址的内容都是由厂家决定。
例如7位的器件地址,一般前四位为固定地址,后三位为可编程地址:
2.IIC时序
2.1IIC数据帧的格式
IIC 数据帧格式:起始条件(占用总线)+数据位(8 位,发送方发出)+应答位(1 位,接收到 1 个字节数据的一方要回一个应答,0 有应答,1 非应答)+停止条件(释放总线)
IIC 总线上主从设备通信过程:
2.2IIC标准时序
要想使用IIC通信,最重要的还是要了解IIC的标准时序。
2.2.1起始条件
起始条件:SCL保持高电平,SDA由高电平变为低电平后,延时(>4.7us),SCL变为低电平。
//1.先拉高SDA,再拉高SCL,空闲状态
//2.拉低SDA,产生起始条件
void IIC_Start() //启动信号
{
SDA=1; //确保SDA线为高电平
SCL=1; //确保SCL高电平
delay_us(5);//延时--起始条件建立时间
SDA=0; //在SCL为高时拉低SDA线,即为起始信号
delay_us(5); //延时--起始条件保持时间
SCL=0; //钳住I2C总线,准备发送或接收数据
}
2.2.2停止条件
停止条件:SCL保持高电平。SDA由低电平变为高电平。
void IIC_Stop(void) //终止条件:SCL高电平期间,SDA从低拉高
{
SDA=0;
SCL=1;
Delay_us(6);//延时---停止条件的建立时间
SDA=1; //---产生了停止条件
Delay_us(6);//延时---本次通信结束到下次通信开始的时间
}
2.2.3应答信号
在 IIC 通信过程中,发送方每发送完一个字节数据给接收方,接收方收到后都必须回一个应答给发送方 应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答,
uint8_t IIC1_Revice_Ack(void) //主机接收应答信号
{
uint8_t ack=0;
IIC1_SCL=0;//(从机准备数据)
IIC1_SDA_OUT=1;//读模式-----让输出电路与管脚断开!!!!!!!!!!
Delay_us(6);//延时(给时间从机准备数据并且数据稳定在数据线上)
IIC1_SCL=1;
Delay_us(6);//延时 (给时间主机读取数据)
if(IIC1_SDA_IN)//主机读取SDA线上的数据
ack=1;
//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
return ack;
}
void IIC1_Send_Ack(uint8_t ack) //主机发送应答信号 (SCL低电平时,往SDA放数据;SCL上升沿,从机从SDA读数据)
{
IIC1_SCL=0; //拉低SCL 主机放数据 0表示应答 1表示无应答
if(ack)//(主机准备数据)
IIC1_SDA_OUT=1;
else
IIC1_SDA_OUT=0;
Delay_us(6);//延时(数据稳定在数据线上)
IIC1_SCL=1;//(从机在时钟线上升沿从SDA上采集数据) 此时从机自动读取SDA_OUT的数据
Delay_us(6);//延时(给时间从机读取数据)
// IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
}
2.2.4IIC的寻址方式
2.2.5IIC的三种通信过程
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。
uint8_t IIC1_Send_Byte(uint8_t data)
{
uint8_t i=0;
for(i=0;i<8;i++)
{
IIC1_SCL=0;
if((data<<i)&0x80)//(主机准备数据) 依次左移 判断最高位是0还是1 然后将值放在IIC1_SDA_OUT上
IIC1_SDA_OUT=1;
else
IIC1_SDA_OUT=0;
Delay_us(6);//延时(数据稳定在数据线上)
IIC1_SCL=1;//(从机在时钟线上升沿从SDA上采集数据)
Delay_us(6);//延时(给时间从机读取数据)
}
//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
return IIC1_Revice_Ack( ); //接收应答信号
}
读取一个字节:SCL低电平期间,从机将数据位依次放到SDA线上然后释放SCL,主机将在SCL高电平期间读取数据位(高位先行),所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次即可接收一个字节(主机在接收之前,需要释放SDA)
uint8_t IIC1_Revice_Byte(uint8_t ack)
{
uint8_t i=0;
uint8_t data=0;
for(i=0;i<8;i++)
{
IIC1_SCL=0;//(从机准备数据)
IIC1_SDA_OUT=1;//读模式-----让输出电路与管脚断开!!!!!!!!!!
Delay_us(6);//延时(给时间从机准备数据并且数据稳定在数据线上)
IIC1_SCL=1;
data = (data<<1) | (IIC1_SDA_IN); //data每次左移一位 空出最低位来存储当前数据
Delay_us(6);//延时 (给时间主机读取数据)
}
//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
IIC1_Send_Ack(ack);
return data;
}
边读边写:边读边写基本时序同上面一样,只不过需要发送重复的起始条件!