检测AT24CXX的自写入周期结束

关于AT24CXX的“自写入周期”,请看:

https://rationmcu.com/elecjc/1480.html

AT24CXX的自写入周期是“小于5ms”,所以可以用延时函数延时5ms解决。

痛点:写延时函数可以用软件延时和定时器延时。软件延时,时间是多少,需要借助示波器才能看出来精确时间,没有示波器,或者用示波器看,都是很麻烦,而且如果单片机主频一改变,软件延时的值又需要改变。定时器延时占用一个定时器,浪费单片机资源。还有,万一由于AT24CXX由于自身问题,突然延长了本次的写入时间,再加上写程序的时候没有考虑到这一点,整个系统就完蛋了。

解决办法:看写入时序,单片机向AT24CXX发送起始信号,再发送一个地址数据后,AT24CXX会返回一个ACK信号,如果自写入周期没有结束,就不会返回一个ACK信号,所以,我们可以观察有没有这个ACK来判断自写入周期是否结束。这样的话,不管24CXX的自写入周期是多长时间,都可以立即进行再写入一个数据或者进行读操作,提高程序的效率。

下面是用STM32库函数写的程序,实现步骤就是上面解决办法所讲的。

void WaitWriteCycleOver(void)
{
 do
 {
 /* 发送开始信号 */
 I2C_GenerateSTART(I2C1, ENABLE);
 /* 读SR1寄存器,用于清除开始标志 */
 I2C_ReadRegister(I2C1, I2C_Register_SR1);
 /* 发送器件地址 */
 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter);
 /* 检测是否成功发送器件地址 */
 }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & I2C_FLAG_ADDR));
 
 /* 清除ACK标志 */
 I2C_ClearFlag(I2C1, I2C_FLAG_AF);
 /* 发送停止信号 */ 
 I2C_GenerateSTOP(I2C1, ENABLE); 
}

看完后,你会对程序有若干疑问:

疑问1:为什么不检测ACK而检测ADDR?

因为我们用的是硬件I2C,检测ACK的事情,就由硬件完成了,SR1中的ADDR置位,就说明硬件检测到了ACK,否则,就没有检测到ACK。

疑问2:为什么要单独清除ACK,不清除其它标志位?

因为ACK位需要软件清除,其它位读一下,就自动清除了。

stm32_i2c时序图部分