以你的代码为例
void i2cwritebyte(unsigned char wdat)//写入一字节,加入应答
{
unsigned char i;
P2=wdat;
for(i=0;i<8;i++)
{
i2csda=0x01&wdat>>7;
wdat=wdat<<1;
i2cscl=1;delayus(4);
i2cscl=0;delayus(4);//最后时钟线是低电平,第8个时钟已经结束
}
i2cwack();//应答中时钟线是高电平,这就是第9 个时钟
}
但是,你的应答并不对
应答是要等待SDA出现低电平,而不是简单延时一下
这个SDA的低电平是24C02给出的
理论上应该是:
SCL=1;//时钟高电平,保持从机在第9个时钟
Delay();//延时
SDA=1;//释放SDA
while(SDA) ;等待从机出现应答,重点在这里,延时是不行的,必需得是等待,这是协议规定的
但是,在实际情况中,考虑从机有故障或者什么的,可能不会应答,while(SDA) ;会卡死
所以,可以使用:
while((SDA==1)&(k<1000)) //超时就不再等待应答
{
k++;
Delay();
}
而你的程序,本身就是错误的:
void i2cwack()//写入应答
{
i2csda=1; delayus(4);//执行后数据线状态为低,说明从器件的应答信号已发出
i2cscl=1;delayus(4);//数据线状态为低
i2cscl=0;delayus(4);//数据线状态为高
}
应该是:
void i2cwack()//写入应答
{
i2csda=1; delayus(4);
i2cscl=1;delayus(4); while(i2csda); //这里要等待,不是延时,重点!重点!重点!可以加入超时检测退出,防止卡死
i2cscl=0;delayus(4);
}
而且,IIC停止读取之前要加一定不应答信号,这个信号要由单片机给出,告诉从机,不要再发送数据了
这个信号不是绝对需要,有的器件你直接停止就可以了,但有的不行,你要给出不应答才能正确读取下一次的数据
像你的代码,能正常就是运气好,因为有的IIC器件硬件电气性能很好,它的反应比单片机还快,它可能压根就不需要应答
|