如今,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_TYPE>AT24C16)
{
IIC_Send_Byte(0XA0); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr>>8);//发送高地址
}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|time_out_sym)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
)|time_out_sym)))
)|time_out_sym)));
文章评论(0条评论)
登录后参与讨论