i2c 总线的时序和读写 i2c 总线的时序和读写 i2c 总线的时序和读写 i2c 总线的时序和读写 i2c 总线的时序和读写

源代码在线查看: i2c 总线的时序和读写.txt

软件大小: 4 K
上传用户: lilacky
关键词: i2c 总线 时序 读写
下载地址: 免注册下载 普通下载 VIP

相关代码

				i2c 总线的时序和读写
				#include 
				#include 
				#define I2c_Control 0xa0        //I2C器件控制字节高四位为0x0a
				#define Wr2_Address 0xa000
				
				extern bdata byte Yo2_Buf;
				extern idata byte TimerOf1ms;
				
				sbit SDA=P1^6;
				sbit SCL=P1^7;
				
				//以下是对I2C器件的操作
				//SDA及SCL空闲状态均保持高电平
				//允许写入24LC01
				byte idata I2c_Address;
				void Wrcs01_Protect_On(void)
				{
				  byte xdata *px;
				  px=Wr2_Address;
				  Yo2_Buf&=0xf3;       //允许写入24LC01
				  *px=Yo2_Buf;
				}
				//禁止写入24LC01
				void Wrcs01_Protect_Off(void)
				{
				  byte xdata *px;
				  px=Wr2_Address;
				  Yo2_Buf&=0xf3;
				  Yo2_Buf|=0x04;       //禁止写入24LC01
				  *px=Yo2_Buf;
				}
				//允许写入24LC02
				void Wrcs02_Protect_On(void)
				{
				  byte xdata *px;
				  px=Wr2_Address;
				  Yo2_Buf|=0x0c;       //允许写入24LC02
				  *px=Yo2_Buf;
				}
				//禁止写入24LC02
				void Wrcs02_Protect_Off(void)
				{
				  byte xdata *px;
				  px=Wr2_Address;
				  Yo2_Buf&=0xf3;
				  Yo2_Buf|=0x04;       //禁止写入24LC02
				  *px=Yo2_Buf;
				}
				void delay(void)
				{
				  byte i,j;
				  for (i=0;i				    j++;
				}
				//启动I2C器件的读写
				void I2c_Start(void)
				{
				  SCL=0;
				  delay();
				  SDA=1;
				  delay();
				  delay();
				  SCL=1;
				  delay();
				  delay();
				  SDA=0;
				  delay();
				  delay();
				}
				//停止I2C器件的读写
				void I2c_Stop(void)
				{
				  SCL=0;
				  delay();
				  SDA=0;
				  delay();
				  delay();
				  SCL=1;
				  delay();
				  delay();
				  SDA=1;
				  delay();
				}
				//在SCL的上升沿向I2C总线上发送一位数据
				void I2c_Send_Bit(bit b_data)
				{
				  SCL=0;
				  delay();
				  SDA=b_data;
				  delay();
				  delay();
				  SCL=1;
				  delay();
				}
				//从I2C总线上接收ACK应答信号
				//接收到ACK 则返回true,否则返回false
				byte I2c_Receive_ACK(void)
				{
				  bit i;
				  SCL=0;
				  delay();
				  SDA=1;                //准备接收ACK 应答
				  delay();
				  delay();
				  i=SDA;
				  SCL=1;
				  delay();
				  if (i==0)
				    return (1);
				  return (0);
				}
				//在SCL的下降沿向I2C总线上发送一字节数据,并接收ACK 应答信号
				//接收到ACK 则返回1,否则返回0
				byte I2c_Send_Byte(byte i)
				{
				  byte j;
				  for (j=0;j				  {
				    if ((i&0x80)==0)
				      I2c_Send_Bit(0);  //发送0
				    else
				      I2c_Send_Bit(1);  //发送1
				    i				  }
				  if (I2c_Receive_ACK()==0)
				    return (0);            //收不到应答信号
				  return (1);
				}
				//在SCL的下降沿从I2C总线上接收一字节数据
				byte I2c_Receive_Byte(void)
				{
				  byte i,j;
				  SCL=0;
				  delay();
				  SDA=1;
				  for (i=0,j=0;i				  {
				    SCL=0;
				    delay();
				    j				    delay();
				    if (SDA==1)
				      j++;
				    SCL=1;
				    delay();
				  }
				  return (j);
				}
				//在SCL的下降沿从I2C总线上接收一字节数据,并发送ACK
				byte I2c_Receive_Byte1(void)
				{
				  byte i;
				  i=I2c_Receive_Byte();         //接收一字节数据
				  I2c_Send_Bit(0);              //发送ACK
				  return (i);
				}
				//在SCL的下降沿从I2C总线上接收一字节数据,但不发送ACK
				byte I2c_Receive_Byte2(void)
				{
				  byte i;
				  i=I2c_Receive_Byte();         //接收一字节数据
				  I2c_Send_Bit(1);              //不发送ACK
				  return (i);
				}
				//启动I2C器件写操作模式
				//Device_Add--I2C器件地址
				//address--数据要写入的地址
				//成功返回1,否则返回0
				byte I2c_Start_Write(byte Device_Add,byte address)
				{
				  byte i,j;
				  for (j=0;j				  {
				    I2c_Start();                  //启动I2C
				    i=Device_Add				    i|=I2c_Control;               //加入控制码
				    i&=0xfe;                      //写操作
				    if (I2c_Send_Byte(i)==1)
				    {                             //发送控制字节后有正确应答
				      if (I2c_Send_Byte(address)==1)
				        return (1);               //发送写地址后有应答
				    }
				    I2c_Stop();                   //结束I2C器件的读写
				    TimerOf1ms=4;
				    for (;;)
				      if (TimerOf1ms==0) break;   //延时4 毫秒后再次重试
				  }
				  switch (I2c_Address)
				  {
				    case 0: Lcd_Display(38);break;
				    case 1: Lcd_Display(39);break;
				    case 2: Lcd_Display(40);
				  }
				  return (0);
				}
				//启动I2C器件读操作模式
				//Device_Add--I2C器件地址
				//成功返回1,否则返回0
				byte I2c_Start_Read(byte Device_Add)
				{
				  byte i;
				  I2c_Start();                  //再次启动I2C
				  i=Device_Add				  i|=I2c_Control;               //加入控制码
				  i|=0x01;                      //读操作
				  if (I2c_Send_Byte(i)==0)
				    return (0);                 //发送控制字节后没有应答
				  return (1);
				}
				//从I2C器件中读取数据
				//device_add--器件地址(0-24LC01,1-8583,2-24LC02)
				//read_add--读数据的起始地址
				//save_add--读出的数据的存储地址
				//block_size--要读取的数据的长度
				//数据全部读出则返回1,否则返回0
				byte I2c_Read(byte Device_Add,byte Read_Add,byte *Save_Add,byte Block_Size)
				{
				  byte i;
				  if (I2c_Start_Write(Device_Add,Read_Add)==0)
				    return (0);                 //启动写模式失败
				  if (I2c_Start_Read(Device_Add)==0)
				    return (0);                 //启动读模式失败
				  if (--Block_Size!=0)
				  {                             //要读取的数据长度不为1
				    for (i=0;i				      *Save_Add++=I2c_Receive_Byte1();
				  }
				  *Save_Add++=I2c_Receive_Byte2();
				  I2c_Stop();
				  return (1);
				}
				
				//向I2C 器件中某一页面写入数据
				byte I2c_Write_Page(byte Device_Add,byte Write_Add,byte *Read_Add,byte Size)
				{
				  byte i,j;
				  byte xdata temp[8];
				  for (i=0;i				  {
				    if (I2c_Start_Write(Device_Add,Write_Add)==0)
				      return (0);                                       //启动写模式失败
				    for (j=0;j				    {
				      if (I2c_Send_Byte(Read_Add[j])==0)
				        return (0);                                     //发送写入数据后没有回应
				    }
				    I2c_Stop();
				    if (I2c_Read(Device_Add,Write_Add,temp,Size)==1)    //将刚刚写入的一页读出
				    {
				      for (j=0;j				        if (Read_Add[j]!=temp[j]) break;                //读出的数据与写入的不同
				      if (j==Size)
				        break;                  //数据已经被正确写入则退出循环,否则再次写入
				    }
				    else
				      return (0);
				  }
				  if (i==3)
				    return (0);                 //三次写入不正确
				  return (1);
				}
				
				//向I2C器件中写入数据
				//device_add--器件地址(0-24LC01、1-8583、2-24LC02)
				//Save_add--要写入数据的起始地址
				//Read_add--读出的数据的存储地址
				//block_size--要写入的数据的长度
				//数据全部读出则返回1,否则返回0
				byte I2c_Write(byte Device_Add,byte Write_Add,byte *Read_Add,byte Block_Size)
				{
				  byte i,j;
				  j=Write_Add&0x07;
				  if (j!=0)
				  {
				    j=8-j;                      //本页面还可写入的数据长度
				    if (Block_Size				      j=Block_Size;             //要写入的数据总长度小于本页面还可写入的数据长度
				    if (I2c_Write_Page(Device_Add,Write_Add,Read_Add,j)==0)
				      return (0);
				    Write_Add+=j;
				    Read_Add+=j;
				    Block_Size-=j;              //还需读出的数据的长度
				  }
				  if (Block_Size!=0)
				  {                             //还有数据需要读出
				    j=Block_Size/8;
				    if (j!=0)
				    {
				      for (i=0;i				      {
				        if (I2c_Write_Page(Device_Add,Write_Add,Read_Add,8)==0)
				          return (0);
				        Write_Add+=8;
				        Read_Add+=8;
				      }
				    }
				    j=Block_Size%8;
				    if (j!=0)
				    {
				      if (I2c_Write_Page(Device_Add,Write_Add,Read_Add,j)==0)
				        return (0);
				    }
				  }
				  I2c_Stop();
				  return (1);
				}
				
				//从24LC01中读取数据
				//Read_Add--要读取数据的首地址
				//Save_Add--读出数据的存储地址
				//Block_Size--要读数据的长度
				//数据不能全部读出则死循环
				byte Cs01_Read(byte Read_Add,byte *Save_Add,byte Block_Size)
				{
				  I2c_Address=0;
				  if (I2c_Read(0,Read_Add,Save_Add,Block_Size)==0)
				  {
				    Lcd_Display(41);
				    return (0);
				  }
				  return (1);
				}
				
				//向24LC01中写入数据
				//Write_Add--要写入的首地址
				//Read_Add--要写入数据的读取地址的首地址
				//Block_Size--要写入数据的长度
				//数据不能全部写入则死循环
				byte Cs01_Write(byte Write_Add,byte *Read_Add,byte Block_Size)
				{
				  Wrcs01_Protect_On();
				  I2c_Address=0;
				  if (I2c_Write(0,Write_Add,Read_Add,Block_Size)==0)
				  {
				    Lcd_Display(42);
				    return (0);
				  }
				  Wrcs01_Protect_Off();
				  return (1);
				}
				
				//从24LC02中读取数据
				byte Cs02_Read(byte Read_Add,byte *Save_Add,byte Block_Size)
				{
				  I2c_Address=2;
				  if (I2c_Read(2,Read_Add,Save_Add,Block_Size)==0)
				  {
				    Lcd_Display(43);
				    return (0);
				  }
				  return (1);
				}
				
				//向24LC02中写入数据
				byte Cs02_Write(byte Write_Add,byte *Read_Add,byte Block_Size)
				{
				  Wrcs02_Protect_On();
				  I2c_Address=2;
				  if (I2c_Write(2,Write_Add,Read_Add,Block_Size)==0)
				  {
				    Lcd_Display(44);
				    return (0);
				  }
				  Wrcs02_Protect_Off();
				  return (1);
				}
				
				//从时钟芯片8583中读取数据
				//数据不能全部读出则返回0
				byte Read_8583(byte Read_Add,byte *Save_Add,byte Block_Size)
				{
				  byte i;
				  I2c_Address=1;
				  if (I2c_Start_Write(1,Read_Add)==0)
				    return (0);                 //启动8583写模式失败
				  if (I2c_Start_Read(1)==0)
				    return (0);                 //启动8583读模式失败
				  if (--Block_Size!=0)
				  {                             //要读取的数据长度不为1
				    for (i=0;i				      *Save_Add++=I2c_Receive_Byte1();
				  }
				  *Save_Add++=I2c_Receive_Byte2();
				  I2c_Stop();
				  return (1);
				}
				
				//向时钟芯片8583中写入数据
				//数据全部写入返回1,否则返回0
				byte Write_8583(byte Write_Add,byte *Read_Add,byte Block_Size)
				{
				  byte i;
				  I2c_Address=1;
				  if (I2c_Start_Write(1,Write_Add)==0)
				    return (0);
				  for (i=0;i				  {
				    if (I2c_Send_Byte(*Read_Add++)==0)
				      return (0);               //发送写入数据后没有回应
				  }
				  I2c_Stop();
				  return (1);
				}
				
				//启动8583走时
				byte Start_8583_Run(void)
				{
				  byte xdata *px;
				  *px=0;                        //32.768kHz
				  return (Write_8583(0,px,1));
				}
				
				//停止8583走时
				byte Stop_8583_Run(void)
				{
				  byte xdata *px;
				  *px=0x80;
				  return (Write_8583(0,px,1));
				}
				
				byte xdata buffer_8583[8];     //用于暂存8583时间数据
				
				//BCD 数转化为二进制数
				byte BCD_To_Bin(byte i)
				{
				  byte j;
				  j=i>>4;
				  j&=0x0f;
				  j*=10;
				  j+=i&0x0f;
				  return (j);
				}
				//二进制数转化为BCD 数
				byte Bin_To_BCD(byte i)
				{
				  byte j;
				  j=i/10;
				  j				  j&=0xf0;
				  j|=i%10;
				  return (j);
				}
				
				//设置8583时间
				//8583的16-17单元暂存年的低位及高位字节(以二进制方式)
				//设置时间不成功则死循环
				void Set_8583_Clock(struct RTC_CLOCK *pclock)
				{
				  byte i,j;
				  Stop_8583_Run();                      //停止8583走时
				  buffer_8583[0]=0x80;                  //控制字节
				  buffer_8583[1]=0x55;
				  buffer_8583[2]=pclock->seconds;       //暂存秒
				  buffer_8583[3]=pclock->minutes;       //暂存分
				  buffer_8583[4]=pclock->hours;         //24小时模式
				  j=BCD_To_Bin(pclock->year_l);         //以二进制方式暂存年的低位字节
				  i=j				  i&=0xc0;
				  buffer_8583[5]=i|pclock->day_of_the_month;    //年的最低两位+日期
				  i=pclock->day_of_the_week;
				  i				  i&=0xe0;
				  buffer_8583[6]=i|pclock->months;      //星期+月份
				  if (Write_8583(0,buffer_8583,7)==0)
				    Lcd_Display(45);
				  buffer_8583[0]=j;
				  buffer_8583[1]=BCD_To_Bin(pclock->year_h);
				  Write_8583(16,buffer_8583,2);         //年数据暂存在8583的16-17地址单元内
				  Start_8583_Run();
				}
				
				//读取8583时间
				//读取时间不成功则死循环
				void Get_8583_Clock(struct RTC_CLOCK *pclock)
				{
				  byte i,j,k;
				  for (;;)
				    if (Stop_8583_Run()==1) break;
				  for (;;)
				    if (Read_8583(0,buffer_8583,8)==1) break;    //从8583地址0 处读出8 字节数据
				  for (;;)
				    if (Start_8583_Run()==1) break;
				  pclock->seconds=buffer_8583[2];       //得到秒
				  pclock->minutes=buffer_8583[3];       //得到分
				  pclock->hours=buffer_8583[4];         //得到小时
				  i=buffer_8583[6];
				  pclock->months=i&0x1f;                //得到月份
				  i>>=5;
				  pclock->day_of_the_week=i&0x07;       //得到星期
				  i=buffer_8583[5];
				  pclock->day_of_the_month=i&0x3f;      //得到日期
				  i=i>>6;
				  i&=0x03;                              //得到年的低两位
				  Read_8583(16,buffer_8583,2);          //读取前次存储的年数据
				  j=buffer_8583[0];                     //年的低位字节
				  k=j&0x03;
				  if (i!=k)
				  {                                     //年值已经改变
				    if (i>k)
				      i-=k;
				    else
				      i+=4-k;
				    j+=i;                               //得到新的年值
				    if (j>99)
				    {
				      j-=100;
				      buffer_8583[1]++;
				    }
				    buffer_8583[0]=j;
				    Write_8583(16,buffer_8583,2);       //年数据暂存在8583的16-17地址单元内
				  }
				  pclock->year_l=Bin_To_BCD(j);
				  pclock->year_h=Bin_To_BCD(buffer_8583[1]);
				}
							

相关资源