一、I2C的时序流程图
![](https://i-blog.csdnimg.cn/blog_migrate/59dbb206f6d4e22be36909c0bd3e185e.png)
二、代码分析
*以下延时,需要头文件 “ #include<intrins.h> ”
#define I2CDelay() {_nop_();_nop_();_nop_();_nop_();}
1、I2C总线_起始信号[ void I2CStart() ]
*起始条件:在SCL线是高电平时,SDA线从高电平向低电平切换,这个情况表示起始条件。
第一步,确保SDA总线与SCL总线为高电平。
I2C_SDA = 1; //确保SDA总线与SCL总线为高电平
I2C_SCl = 1;
第二步,延时,确保总线稳定后,将SDA线从高电平向低电平切换。
I2CDelay(); //延时
I2C_SDA = 0; //先拉低SDA
第三步,延时,确保总线稳定后,将SCL线从高电平向低电平切换(SCL拉低,准备接收信号)。
I2CDelay(); //延时
I2C_SCL = 0; //拉低SCL
2、I2C总线_停止信号[ void I2CStop() ]
*当SCL线是高电平时,SDA线由低电平向高电平切换,这个情况表示停止条件
第一步,确保SDA总线与SCL总线为低电平。
I2C_SDA = 0; //确保SDA与SCL总线为低电平
I2C_SCL = 0;
第二步,延时,确保总线稳定后,将SCL线由低电平向高电平切换。
I2CDelay(); //延时
I2C_SCL = 1; //先拉高SCL
第三步,延时,确保总线稳定,将SDA线由低电平向高电平切换,再延时。
I2CDelay(); //延时
I2C_SCL = 1; //拉高SDA
I2CDelay();
3、I2C总线_写数据 [ bit I2CWrite(unsigned char dat) ]
bit ack; //用于暂存应答位的值
unsigned char mask; //用于探测字节内某一个值的掩码变量
第一步 ,将数据的值输出到SDA上。
for(mask = 0x80; mask != 0; mask >>= 1) //mask用于探测字节内某一位值的掩码变量,从高到低进行
{
if((mask & dat) == 0) //dat传入的字节,该位的值输出到SDA上
I2C_SDA = 0;
else
I2C_SDA = 1;
I2CDelay(); //延时
I2C_SCL = 1; //拉高SCL,等待该位的值传输
I2CDelay(); //延时
I2C_SCL = 0; //拉低SCL,完成一个位周期
}
第二步,主机释放SDA,以检测从机应答。
· * 有响应的时钟脉冲期间,发送器释放SDA线(高电平) ——I2C总线规范基础(二、响应)
I2C_SDA = 1; //主机释放SDA
·第三步,读取从机的应答值。
I2CDelay(); //延时
I2C_SCL = 1; //拉高SCL
ack = I2C_SDA; //读取此时的SDA值,即为从机的应答值
I2CDelay(); //延时
I2C_SCL = 0; //再拉低SCL完成应答,并保持信总线
第四步,返回从机应答值(从机回复应答,ack为‘0’)。
return ask; //返回从机应答值
4、I2C总线_读操作
unsigned char mask; //用于探测字节内某一位值的掩码变量
unsigned char dat; //用于暂存读到的字节
第一步,确保主机释放SDA。
I2C_SDA = 1; //确保主机释放SDA
第二步,读取SDA的值。
for(mask = 0x80; mask != 0; mask >>= 1) //mask用于探测字节内某一位值的掩码变量,从高到低进行
{
I2CDelay(); //延时
I2C_SCL = 1; //拉高SCL,准备读此时SDA的值
if(I2C_SDA == 0) //读取SDA的值
dat &= ~mask; //SDA的值为0时,dat中对应位清零
else
dat |= mask; //SDA的值为1时,dat中对应位置1
I2CDelay(); //延时
I2C_SCL = 0; //再拉低SCL,以使从机发送出下一位
}
第三步,应答信号处理
4.1、并发送非应答信号,返回值为读到的字节[ unsigned char I2CReadNAK() ]。
*8位数据发送完成后,拉高SDA,发送非应答信号,并保持住总线。
I2C_SDA = 1; //8位数据发送完成后,拉高SDA,发送非应答信号
I2CDelay(); //延时
I2C_SCL = 1; //拉高SCL
I2CDelay(); //延时
I2C_SCL = 0; //再拉低SCL完成非应答位,并保持住总线
4.2、并发送应答信号,返回值为读到的字节[ unsigned char I2CReadACK() ]。
* 8位数据发送完成后,拉低SDA,发送应答信号,并保持住总线。
I2C_SDA = 0; //8位数据发送完成后,拉低SDA,发送应答信号
I2CDelay(); //延时
I2C_SCL = 1; //拉高SCL
I2CDelay(); //延时
I2C_SCL = 0; //再拉低SCL完成非应答位,并保持住总线
第四步,返回读到的字节
return dat; //返回读到的字节
5、I2C寻址[ bit I2CAddressing(unsigned char addr) ]
bit I2CAddressing(unsigned char addr)
{
bit ack; //用于暂存应答位的值
I2CStart(); //产生起始信号,即启动一次总线操作
ack = I2CWrite(addr << 1); //器件地址需左移一位,因寻址命令的最低位为读写位
I2CStop(); //不需要进行后续读写,而直接停止本次总线操作
return ack;
}