热度 23
2013-1-11 19:37
5594 次阅读|
0 个评论
如今,I2C接口用的很多,使用两根线,即使加上地线一共才三根线,传输简单便捷;对于很多传感器和E2PROM都使用这种传输协议。 对于不采用中断功能的I2C数据传输,超时处理时必须;假如没有超时处理,一旦传输出错或者I2C器件损坏,整个程序都停在那儿了。 个人觉着,要解决超时的问题,首先我们要分清使用的是模拟的I2C还是硬件I2C?我们只是从MCU主模式来考虑问题,对于硬件I2C,我们可以用一个定时器设置超时指针,定时器必须采用中断的方式,因为只有中断,才能跳过无休止的等待。这样在I2C即使工作在查询模式,也能进行超时处理,而且不影响程序正常时的效率。 首先看一下,如何写一个字节 /****************************************** I2C总线写一个字节 返回0:写成功 返回非0:写失败 *******************************************/ unsigned char i2c_Write(unsigned char Wdata,unsigned char RomAddress) { Start();//I2C启动 Wait(); if(TestAck()!=START) return 1;//ACK Write8Bit(wr_device_add);//写I2C从器件地址和写方式 Wait(); if(TestAck()!=MT_SLA_ACK) return 1;//ACK Write8Bit(RomAddress);//写24C02的ROM地址 Wait(); if(TestAck()!=MT_DATA_ACK) return 1;//ACK Write8Bit(Wdata);//写数据到24C02的ROM Wait(); if(TestAck()!=MT_DATA_ACK) return 1;//ACK Stop();//I2C停止 // delay_ms(10);//延时等EEPROM写完 return 0; } 我们要做的超时处理,就是在wait()中 加入超时处理,超时标志假设为time_out_sym,初始值为0,在进入wait()时,打开超时计数窗口,有定时器中断处理,在发生超时后对time_out_sym置1,否则对所有相关标志复位。 那么这个函数就相当于 void wait(void) { while(!((TWCR(1 } 如此一来就可以进行简单的超时处理了!这个思路,实际上起源于某MCU官网上的一个关于I2C的例程,个人觉得这样处理很不错,所以写下来和大家分享!实际上我们仔细想想,对于模拟的I2C接口,超时处理也是可以采用这种方式的,只不过处理起来比硬件的相对麻烦一些罢了。 下面是硬件IIC超时处理: //在AT24CXX指定地址写入一个数据 //WriteAddr :写入数据的目的地址 //DataToWrite:要写入的数据 void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite) { IIC_Start(); if(EE_TYPEAT24C16) { IIC_Send_Byte(0XA0); //发送写命令 IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr8);//发送高地址 }else IIC_Send_Byte(0XA0+((WriteAddr/256)1)); //发送器件地址0XA0,写数据 IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr%256); //发送低地址 IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); //发送字节 IIC_Wait_Ack(); IIC_Stop();//产生一个停止条件 delay_ms(10); } 标志处理也是采用中断方式,加在IIC_wait_Ack()上 //等待应答信号到来 //返回值: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|t ime_out_sym ) { ucErrTime++; if(ucErrTime250) { IIC_Stop(); return 1; } } IIC_SCL=0;//时钟输出0 return 0; } )|time_out_sym))) )|time_out_sym)));