1、IIC停止信号产生,感觉与IIC时序不一致
代码如下:
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
2、等待应答信号函数中,将SDA设置为输入,后更改SDA的脚状态,不能够理解。
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
原子例程里的模拟IIC的stop信号是有bug的,论坛里某个帖子做了说明了的。
这是我根据论坛那个帖子改了的stop信号。
[mw_shl_code=c,true]//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
delay_us(4);
IIC_SDA=1;//发送I2C总线结束信号
}[/mw_shl_code]
重新搜索了一下那个帖子,发现以下几个帖子提到了这个问题:
http://openedv.com/forum.php?mod=viewthread&tid=96021&highlight=IIC
http://openedv.com/forum.php?mod=viewthread&tid=87513&highlight=IIC
其中第二个地址讨论比较详细。
具体说来就是原子例程中的stop信号没有严格的执行IIC的stop时序。通常,大部分的IIC协议器件在通讯时使用原子例程是没有问题的,
主要原因是大部分IIC器件速度比较快,有足够速度响应
[mw_shl_code=c,true]
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
[/mw_shl_code]
这样的操作:在SCL拉高后,1us以内(可能只有几十ns)迅速拉高SDA。
当然,对于“大部分”的IIC协议器件,这样的操作是没有问题的。
我就比较惨了,碰到了一个神经病一样的EEPROM,使用原子例程里的stop信号时序通讯就失败了。
器件型号24C021,ST的产品,测试发现该器件速率神经病一样的低,大部分的24Cxx都是100K 400K 1M的速率的,
这个24C021的SCL的周期超过40us,也就是说,这个24C021的频率低于25K。
在这么低的频率下,STM32F4的SDA紧随着SCL拉高后拉高,在24C021方面,可能还没响应完SCL的拉高信号,SDA就已经拉高了。
我们一般的数字电路里,一般说来,一个信号比另外一个信号慢,是能够体现出来的。但是这个24C021是一个包含时序逻辑的器件,很可能它对stop信号的响应是这样的:在某个寄存器为1(或者0)的情况下检测有没有SDA的上升沿信号。
那么24C021用原子例程IIC通讯失败的大概原因也就出来了:
原子例程里,SCL拉高后,没任何延时就直接拉高了SDA,而24C021方面,在收到SCL拉高后,因为这个24C021速度实在太慢,可能还没来得及将某个寄存器置1(或者0)SDA就已经被拉高了,等某个寄存器置1(或者0)完成后,已经等不到SDA上升沿信号了,所以stop信号就失败了。
所以我在SCL拉高之后加入了一个几us的延时,通讯就正常了。
实在抱歉,其实是我把前后几个测试搞混了,最早发现stop通讯失败的器件是24C16,stop修改之后跟24C16通讯就正常了。然而过了不久分析同样一个型号的配件又发现了24C021的低速率问题,在IIC驱动中加入了非常多的delay_us(5);之后,与24C021的通讯才正常。
想起我搞混测试之后,帖子已经编辑了大部分了,就懒得改了,好在对于理解stop问题还不影响。
一周热门 更多>