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

📄 i2c.c

📁 单片机代码实现I2c通信协议
💻 C
字号:
/*I2C总线操作函数*/

#include "I2C.H"
#include <reg52.H>

sbit I2C_scl=P1^2;     //I2C时钟信号
sbit I2C_sda=P1^3;     //I2C数据信号

void I2C_Delay(unsigned int item);      //I2C总线延时
void I2C_Init();                        //I2C总线初始化
void I2C_Start();                       //I2C总线启动
void I2C_WriteByte(unsigned char x);    //I2C总线写入1字节数据
unsigned char I2C_ReadByte();           //I2C总线读取1字节数据
bit I2C_SlaveAck();                     //I2C总线从机应答
void I2C_MasterAck(bit ack);            //I2C总线主机应答
void I2C_Stop();                        //I2C总线停止
bit I2C_Puts(unsigned char slave_addr,unsigned int sub_addr,unsigned char sub_mode, char* dat,unsigned char size);
//I2C总线连续发送字节,slave_addr为从机地址,sub_addr为从机内部寄存器地址,sub_mode为寄存器地址类型,"0"表示无地址,
//"1"表示单字节地址,"2"表示双字节地址,dat为发送字节指针,size为字节数
bit I2C_Gets(unsigned char slave_addr,unsigned int sub_addr,unsigned char sub_mode, char* dat,unsigned char size);
//I2C总线连续接收字节,slave_addr为从机地址,sub_addr为从机内部寄存器地址,sub_mode为寄存器地址类型,"0"表示无地址,
//"1"表示单字节地址,"2"表示双字节地址,dat为发送字节指针,size为字节数

/* I2C总线延时*/
void I2C_Delay(unsigned int item)
{
 while(item--);
}

/* I2C初始化子程序 */
void I2C_Init()
{
  I2C_scl=1;
  I2C_Delay(I2C_DELAY_VALUE);
  I2C_sda=1;
  I2C_Delay(I2C_DELAY_VALUE);
}

/* I2C总线启动子程序,时钟线高电平时,数据线下降沿启动总线*/
void I2C_Start()
{

  I2C_sda=1;
  I2C_Delay(I2C_DELAY_VALUE);
  I2C_scl=1;
  I2C_Delay(I2C_DELAY_VALUE);
  I2C_sda=0;
  I2C_Delay(I2C_DELAY_VALUE);
  I2C_scl=0;
  I2C_Delay(I2C_DELAY_VALUE);

}

/* I2C总线字节写入子程序*/
void I2C_WriteByte(unsigned char x)
{
  unsigned char i;
  for(i=8;i>0;i--)
  {
   I2C_sda=(bit)(x&(0x80));
   x=x<<1;
   I2C_scl=1;                  //时钟线高时写入
   I2C_Delay(I2C_DELAY_VALUE);
   I2C_scl=0;
   I2C_Delay(I2C_DELAY_VALUE);
  }
}

/* I2C总线字节读取子程序*/
unsigned char I2C_ReadByte()
{
 unsigned char x,i;               //函数返回字节
 I2C_sda=1;                    //数据线先置高
 x=0;
 for(i=8;i>0;i--)
 {
  I2C_scl=1;
  I2C_Delay(I2C_DELAY_VALUE);
  x=x<<1;
  if(I2C_sda){x=x|(0x01);}      //数据线为1
  I2C_scl=0;
  I2C_Delay(I2C_DELAY_VALUE);
 }
 return(x);                     //字节返回
}

/* I2C总线从机应答,返回值为1时终止传输,为0时表明从机接收完一字节数据*/
bit I2C_SlaveAck()
{
  bit ack;
  I2C_sda=1;
  I2C_Delay(I2C_DELAY_VALUE);
  I2C_scl=1;
  I2C_Delay(I2C_DELAY_VALUE);
  ack=I2C_sda;
  I2C_scl=0;
  I2C_Delay(I2C_DELAY_VALUE);
  return ack;                   //返回状态位
}

/* I2C总线主机应答,"ack"为"1"时终止传输,为"0"时表明接收完一字节数据*/
void I2C_MasterAck(bit ack)
{
 I2C_sda=ack;
 I2C_Delay(I2C_DELAY_VALUE);
 I2C_scl=1;
 I2C_Delay(I2C_DELAY_VALUE);
 I2C_scl=0;
 I2C_Delay(I2C_DELAY_VALUE);
}

/* I2C总线停止*/
void I2C_Stop()
{
  unsigned int delay=I2C_STOP_VALUE;
  I2C_sda=0;
  I2C_Delay(I2C_DELAY_VALUE);
  I2C_scl=1;
  I2C_Delay(I2C_DELAY_VALUE);
  I2C_sda=1;
  I2C_Delay(I2C_DELAY_VALUE);        //上升沿终止I2C总线传输
  while(delay--);
  //{delay--;}              //延时一段时间
}


/* I2C接口器件内部数据写入子程序*/
bit I2C_Puts(unsigned char slave_addr,unsigned int sub_addr,unsigned char sub_mode, char* dat,unsigned char size)
{
  unsigned char i;
  unsigned char num[3];
  bit ack=0;
  if(size==0) {return 0;}       //字节长度为0,返回
  num[0]=slave_addr;            //数组首字节存储从机I2C地址,末位"0"表示写入,"1"表示读出
                                //ZLG7290地址定义为0x70H,默认时为写操作
  if(sub_mode>2) {sub_mode=2;}  //检查内部字节储存方式

  switch(sub_mode)              //存储内部地址
  {
   case 0:
        {break;}
   case 1:
        {num[1]=(char)(sub_addr);
         break;}
   case 2:
        {num[1]=(char)(sub_addr>>8);
         num[2]=(char)(sub_addr&(0x00ff));
         break;}
   default:
        break;
  }

  sub_mode++;                    //配合后面for循环操作
  I2C_Start();                  //启动I2C总线

  for(i=0;i<sub_mode;i++)
  {
   I2C_WriteByte(num[i]);       //写入从机I2C地址
   ack=I2C_SlaveAck();
   if(ack==1)
    {
     I2C_Stop();                //终止I2C总线传输
     return 1;
    }
  }

  for(i=0;i<size;i++)
  {
   I2C_WriteByte(*dat);
   ack=I2C_SlaveAck();
   if(ack==1){break;}           //跳出for循环
   dat++;                       //指针加1
  }

  I2C_Stop();                   //传输停止
  if(ack==0)                    //数据传输正确,返回值"0"。
  {return 0;}
  else
  {return 1;}

}

/* I2C接口器件内部数据读出子程序,只能读取单一地址单元内数据*/
bit I2C_Gets(unsigned char slave_addr,unsigned int sub_addr,unsigned char sub_mode, char* dat,unsigned char size)
{
 bit bdata ack;
 unsigned char i;
 unsigned char num[3];
// unsigned char content;

 if(size==0){return 0;}
 num[0]=slave_addr;             //首先将地址写入(写操作)

 if(sub_mode>2){sub_mode=2;}

 if(sub_mode!=0)                //有内部地址
 {
   switch(sub_mode)
   {
   case 0:
        {break;}
   case 1:
        {num[1]=(char)(sub_addr);
         break;}
   case 2:
        {num[1]=(char)(sub_addr>>8);
         num[2]=(char)(sub_addr&(0x00ff));
         break;}
   default:
        break;
  }
 }
 sub_mode++;
 I2C_Start();                  //启动I2C总线
 for(i=0;i<sub_mode;i++)
  {
   I2C_WriteByte(num[i]);       //写入从机I2C地址
   ack=I2C_SlaveAck();
   if(ack==1)
    {
     I2C_Stop();                //终止I2C总线传输
     return 1;
    }
  }

//开始读操作

  I2C_Start();                  //启动I2C总线
  num[0]=num[0]|(0x01);         //末位置高,读操作
  I2C_WriteByte(num[0]);        //写入读操作地址
  ack=I2C_SlaveAck();
  if(ack==1)
   {
    I2C_Stop();                //终止I2C总线传输
    return (0x01);
   }
  while(1)
  {
    *dat=I2C_ReadByte();
    dat++;
    size--;                   //长度减1
    if(size==0)
    {
     I2C_MasterAck(1);        //接收完毕,终止I2C传输
     break;
    }
    I2C_MasterAck(0);        //继续传输
  }
  I2C_Stop();
  return 0;

}

⌨️ 快捷键说明

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