stm32软件模拟I2C
扫描二维码
随时随地手机看文章
一 概述
很多人都知道stm32的硬件I2C存在BUG,现在我们通过软件模拟时序的办法来实现I2C。
使用软件模拟I2C主要是方便程序的移植,只需要更改一下相应的IO端口即可。
二 软件模拟实现
1 起始信号
voidi2c_Start(void)
{
macI2C_SDA_1();//首先确保SDA和SCL都是高电平
macI2C_SCL_1();
i2c_Delay();
macI2C_SDA_0();//先拉低SDA
i2c_Delay();
macI2C_SCL_0();//在拉低SCL
i2c_Delay();
}
2 总线产生停止信号
voidi2c_Stop(void)
{
macI2C_SDA_0();//首先确保SDA是低电平
macI2C_SCL_1();//先拉高SCL
i2c_Delay();
macI2C_SDA_1();//在拉高SDA
}
3 CPU向I2C总线设备发送8bits的数据
voidi2c_SendByte(uint8_t_ucByte)
{
uint8_ti;
for(i=0;i<8;i++)
{
if(_ucByte&0x80)
{
macI2C_SDA_1();
}
else
{
macI2C_SDA_0();
}
i2c_Delay();
macI2C_SCL_1();
i2c_Delay();
macI2C_SCL_0();
if(i==7)
{
macI2C_SDA_1();//8位数据发送完毕后,主机释放SDA,以检测从机应答
}
_ucByte<<=1;//左移1个bit
i2c_Delay();
}
}
4 CPU从I2C总线读取8个bits的数据
uint8_ti2c_ReadByte(void)
{
uint8_ti;
uint8_tvalue;
/*读取到的第一个bit为bit7*/
value=0;
for(i=0;i<8;i++)
{
value<<=1;
macI2C_SCL_1();
i2c_Delay();
if(macI2C_SDA_READ())
{
value++;
}
macI2C_SCL_0();
i2c_Delay();
}
returnvalue;
}
5 CPU产生一个时钟,并且读取器件的ACK应答信号
uint8_ti2c_WaitAck(void)
{
uint8_tre;
macI2C_SDA_1();//CPU释放SDA总线
i2c_Delay();
macI2C_SCL_1();//CPU驱动SCL=1,此时器件会返回ACK应答
i2c_Delay();
if(macI2C_SDA_READ())//CPU读取SDA口线状态
{
re=1;
}
else
{
re=0;
}
macI2C_SCL_0();
i2c_Delay();
returnre;
}
6 CPU产生一个ACK信号
voidi2c_Ack(void)
{
macI2C_SDA_0();
i2c_Delay();
macI2C_SCL_1();
i2c_Delay();
macI2C_SCL_0();
i2c_Delay();
macI2C_SDA_1();
}
7 CPU产生一个NACK信号(NACK即无应答信号)
voidi2c_NAck(void)
{
macI2C_SDA_1();//CPU驱动SDA产生1
i2c_Delay();
macI2C_SCL_1();//CPU驱动SCL产生1
i2c_Delay();
macI2C_SCL_0();
i2c_Delay();
}
8 I2C总线位延时
staticvoidi2c_Delay(void)
{
uint8_ti;
for(i=0;i<10;i++);
}
对于I2C总线延时来说,不同的单片机写法是不相同的,参考野火的程序,当CPU主频为72MHz时,在内部Flash运行,同时MDK不做优化的情况下
循环次数为10时,SCL频率为205KHz
循环次数为7时,SCL频率为347KHz,SCL高电平时间为1.5us,SCL低电平时间为2.87us
后记:关于I2C通信,我还是有几处地方没有搞明白,这里的程序只是写好了具体的底层封装,对于不同的外设,如AT24C02,MPU6050,应用起来肯定是不相同的,等搞明白其他的一些问题后,我会继续补充这篇文章。
参考资料
1http://blog.csdn.net/subkiller/article/details/6854910 《I2C总线协议》
2 《手把手教你学51单片机》
3 野火stm32指南者开发板程序