以你的代碼為例
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器件硬件電氣性能很好,它的反應比單片機還快,它可能壓根就不需要應答
|