实际我给的例程是PC的并口模拟I2C协议,用什么语言并不重要.
楼主的类似以下的程序全部有问题~~~ while(i--) { I2CStart(); I2CSendByte(ControlByte&0xfe);//指定芯片,此次必定为写 if(!WaitAck()) //涵数返回一个1为成功 continue; //结束写操作,并i-1后,再来一次 //... if(errorflag==error) //经过写完后,如果最后errorflag标志为1,则表示有错误 continue; //结束写操作,并i-1后,再来一次
等等都有问题. I2C的通讯状态很规矩,每个状态都有详细的定义. gccavr中的定义很规范(atmel称I2C为TWI) enum enum_TWIState { /* Master */ TW_START = 0x08, TW_REP_START= 0x10, /* Master Transmitter */ TW_MT_SLA_ACK= 0x18, TW_MT_SLA_NACK= 0x20, TW_MT_DATA_ACK= 0x28, TW_MT_DATA_NACK= 0x30, TW_MT_ARB_LOST= 0x38, /* Master Receiver */ TW_MR_ARB_LOST= 0x38, TW_MR_SLA_ACK= 0x40, TW_MR_SLA_NACK= 0x48, TW_MR_DATA_ACK= 0x50, TW_MR_DATA_NACK= 0x58, /* Slave Transmitter */ TW_ST_SLA_ACK= 0xA8, TW_ST_ARB_LOST_SLA_ACK= 0xB0, TW_ST_DATA_ACK= 0xB8, TW_ST_DATA_NACK= 0xC0, TW_ST_LAST_DATA= 0xC8, /* Slave Receiver */ TW_SR_SLA_ACK= 0x60, TW_SR_ARB_LOST_SLA_ACK= 0x68, TW_SR_GCALL_ACK= 0x70, TW_SR_ARB_LOST_GCALL_ACK= 0x78, TW_SR_DATA_ACK= 0x80, TW_SR_DATA_NACK= 0x88, TW_SR_GCALL_DATA_ACK= 0x90, TW_SR_GCALL_DATA_NACK= 0x98, TW_SR_STOP= 0xA0, /* Misc */ TW_NO_INFO= 0xF8, TW_BUS_ERROR= 0x00, TW_READ= 1, TW_WRITE= 0 };
不管I2C出现的任何错误,主机都应该发送I2CStop(),而不应该像楼主用continue重试.
因为从机是根据主机的节拍即时钟进行工作即状态转移的,主机发现的错误从机并不知晓.
所以正确地容错应该是主机发送I2CStop()停止从机的工作后,使从机的状态归零. 然后再I2CStart()重新通讯.
再者I2C的调试实际很简单,应该在发送I2CStart()和从地址后,在接收应答处 设置个断点. 若裸奔应该在此处加个LedOn()或LedOff()看看到底收到从机的应答信号ACK否.
若收不到就应该检查时序,否则一切都白搭~~~
建议I2C用状态机,虽然在模拟I2C上很少使用,但它能使通讯更可靠~~~ 相关链接:https://bbs.21ic.com/club/bbs/showEssence.asp?id=9000&page=1 |