⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c 总线的时序和读写.txt

📁 i2c 总线的时序和读写 i2c 总线的时序和读写 i2c 总线的时序和读写 i2c 总线的时序和读写 i2c 总线的时序和读写
💻 TXT
字号:
i2c 总线的时序和读写
#include <w77e58.h>
#include <file.h>
#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<2;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<8;j++)
  {
    if ((i&0x80)==0)
      I2c_Send_Bit(0);  //发送0
    else
      I2c_Send_Bit(1);  //发送1
    i<<=1;
  }
  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<8;i++)
  {
    SCL=0;
    delay();
    j<<=1;
    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<3;j++)
  {
    I2c_Start();                  //启动I2C
    i=Device_Add<<1;
    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<<1;
  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<Block_Size;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<3;i++)
  {
    if (I2c_Start_Write(Device_Add,Write_Add)==0)
      return (0);                                       //启动写模式失败
    for (j=0;j<Size;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<Size;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)
      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<j;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<Block_Size;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<Block_Size;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<<=4;
  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<<6;
  i&=0xc0;
  buffer_8583[5]=i|pclock->day_of_the_month;    //年的最低两位+日期
  i=pclock->day_of_the_week;
  i<<=5;
  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]);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -