IIC通信协议
IIC是同步半双工通信,一个数据线SDA和一个时钟SCL线,可以接受和发送数据。在CPU与被控IC之间、IC与IC之间进行双向传送。
空闲状态
IIC总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。
起始信号
当SCL为高期间,SDA由高到低的跳转
代码实现为:
//产生IIC起始信号void IIC_Start(void){SDA_OUT();//sda线输出模式IIC_SDA=1; IIC_SCL=1;delay_us(4);IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4);IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 }
停止信号
当SCL为高期间,SDA由低到高的跳转
代码实现:
//产生IIC停止信号void IIC_Stop(void){SDA_OUT();//sda线输出IIC_SCL=0;IIC_SDA=0;//STOP:when CLK is high DATA change form low to highdelay_us(4);IIC_SCL=1; delay_us(4);IIC_SDA=1;//发送I2C总线结束信号 }
应答信号
发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位,表示接收器已经成功接收到了该字节。应答信号为高电平时,规定为非应答位,一般表示接收器接收该字节没有成功。
对于反馈有效应答位ACK的要求是,接收器第9个时钟脉冲之前的低电平将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电压。
代码实现为:
//产生ACK应答void IIC_Ack(void){IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;}//不产生ACK应答 void IIC_NAck(void){IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;}//等待应答信号到来//返回值: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){ucErrTime++;if(ucErrTime>250){IIC_Stop();return 1;}}IIC_SCL=0;//时钟输出0 return 0; }
数据的有效性
IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平才允许变化。即数据在SCL的上升沿到来之前就需要准备好,并且在下降沿到来之前必须保持稳定。
数据的传送
在IIC总线上传送的每一位数据都有一个时钟脉冲相对应(同步控制),即在SCL串行时钟的配合下,在SDA上逐位串行传送每一位数据,数据位的传输是边沿触发。
发送一字节代码实现为:
//IIC发送一个字节//返回从机有无应答//1,有应答//0,无应答 void IIC_Send_Byte(u8 txd){u8 t; SDA_OUT();IIC_SCL=0;//拉低时钟开始数据传输for(t=0;t<8;t++){IIC_SDA=(txd&0x80)>>7;txd<<=1; delay_us(2); //对TEA5767这三个延时都是必须的IIC_SCL=1;delay_us(2); IIC_SCL=0;delay_us(2);} }
数据传输之前IIC_SCL必须等于0,即时信号为低电平,然后准备一位数据,准备好之后,IIC_SCL=1,即时钟信号为高电平,数据就传输过去了
对于下面的代码:
IIC_SDA=(txd&0x80)>>7;txd<<=1;
无符号类型左移丢弃最高位,低位补0,无符号类型右移丢弃最低位,低位补0,txd&0x80让txd第8位数据不变,其他为变成0(txd的值不受影响),左移7位,将最高位的数据赋值给IIC_SDA,当IIC_SCL=1时,第八位数据就传输过去了,txd<<=1让第7位数据变成第8位数据,下次循环就传输原来第7位数据了。循环8次将一字节数据传输完毕。
读取数据代码实现:
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK u8 IIC_Read_Byte(unsigned char ack){unsigned char i,receive=0;SDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){IIC_SCL=0; delay_us(2);IIC_SCL=1;receive<<=1;if(READ_SDA)receive++; delay_us(1); } if (!ack)IIC_NAck();//发送nACKelseIIC_Ack(); //发送ACK return receive;}
对于下面的代码:
receive<<=1;if(READ_SDA)receive++;
READ_SDA是获取SDA线上的电压,高电压说明说明传送过来的数据是1,receive++,下一次的时候, receive<<=1,receive先右移一位,然后接受数据,这样循环8次,就能保证接受的数据在原来的位置上了。
与EEPROM通信
硬件连接
EEPROM是一种掉电后数据不丢失的存储芯片,可以在电脑上或专用设备上擦除已有信息,重新编程。
24C02的总容量是256个字节,接口是IIC
模式选择
硬件连接中,A2=A1=A0=0(接地),所以,我们读数据时,只需写入0xA1,表示读模式,写数据时,只需写入0xA0,表示写模式
写时序
下面是写入一个字节数据的过程
一个IIC_START信号写入模式,写入0xA0等待一个ACK发送写入数据的地址(0~255)等待一个ACK发送一个字节等待一个ACK一个STOP信号
具体代码如下
//在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); }
读数据
下面是读一个字节数据的过程
产生一个START信号写入0xA0,表示是写模式等待一个ACK写入读数据的地址等待一个ACK产生一个START信号写入0xA1,表示是读模式等待一个ACK读取数据
实现代码如下:
//在AT24CXX指定地址读出一个数据//ReadAddr:开始读数的地址 //返回值 :读到的数据u8 AT24CXX_ReadOneByte(u16 ReadAddr){u8 temp=0; IIC_Start(); if(EE_TYPE>AT24C16){IIC_Send_Byte(0XA0); //发送写命令IIC_Wait_Ack();IIC_Send_Byte(ReadAddr>>8);//发送高地址 }else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,写数据 IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr%256); //发送低地址IIC_Wait_Ack(); IIC_Start();IIC_Send_Byte(0XA1); //进入接收模式 IIC_Wait_Ack(); temp=IIC_Read_Byte(0); IIC_Stop();//产生一个停止条件 return temp;}