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

📄 i2c.c

📁 一个用C写的IIC驱动,可用在铁电或EEPROM的片子上
💻 C
字号:

#include "51all.h"
#include <intrins.h>

#define  NOP  _nop_()
#define  Clk_delay();  _nop_();_nop_();_nop_();_nop_();_nop_();   //低时钟时适当减少_nop_()个数


 void I2C_delay(unsigned char );     //I2C_DELAY
 void I2C_START();
 void I2C_STOP();
 unsigned char I2C_CheckAck();       //检验I2C总线应答信号,有应答则返回1,否则返回0,超时值取255
 void I2C_SendAck();                 //主控制器进行应答信号
 void I2C_SendNoAck();               //主控制器进行非应答信号
 void I2C_W_byte(unsigned char );     //写一个BYTE
 unsigned char I2C_R_byte();          //读一个BYTE
 void I2C_Wdat(unsigned int , unsigned char *, unsigned int  );     //写一快数据  起始地址,数据首地址,数据长度
 void I2C_Wbyte(unsigned int , unsigned char  );                  //往一个具体知地址写一个BYTE   起始地址,数据
 void I2C_Wadd(unsigned int );       //写地址
 void I2C_Rdat(unsigned int , unsigned char *, unsigned int );      // 读一快数据   起始地址,数据存放首地址,数据长度
 unsigned char I2C_Rbyte(unsigned int );       // 读一个字节



sbit  SDA = P1^3;    //模拟I2C数据传输位
sbit  SCL = P1^2;    //模拟I2C时钟控制位
bit  I2C_Ack = 1;

/*******************************I2C_START************************************/
//启动I2C总线,即发送I2C初始条件
void I2C_START()
{
	SDA = 1;
	SCL = 1;      //延时>4.7us
    Clk_delay();
    Clk_delay();
	SDA = 0;      //延时>4.7us
    Clk_delay();
    Clk_delay();
	SCL = 0;      
	Clk_delay();
}

/*******************************I2C_STOP************************************/
// 停止I2C总线
void I2C_STOP()
{
	SDA = 0;
	SCL = 1;   //延时>4.7us
    Clk_delay();
    Clk_delay();
	SDA = 1;   //延时>4.7us
    Clk_delay();
}

/*******************************I2C_ACK************************************/
//检验I2C总线应答信号,有应答则返回1,否则返回0,超时值取255

unsigned char I2C_CheckAck()
{
   unsigned char errtime = 255;    // 因故障接收方无 Ack,超时值为255
   SCL = 0;                       // 延时
   Clk_delay();
   SDA = 1;  //读取SDA时,先置1;
   NOP;NOP;
   SCL = 1;
   Clk_delay();
   while(SDA)
    {
     errtime--;
     if(errtime==0)
       {
        I2C_STOP();
        break;
        }
     }
   SCL = 0;
   if(SDA) return(0);
      else return(1);
}

/*******************************I2C_SendAck************************************/
//主控制器进行应答信号
void I2C_SendAck()
{
   SCL = 0;
   Clk_delay();
   SDA = 0;
   Clk_delay();
   SCL = 1;
   Clk_delay();
   SCL = 0;
}

/*******************************I2C_SendNoAck************************************/
//主控制器进行非应答信号
void I2C_SendNoAck()
{
   SCL = 0;
   Clk_delay();
   SDA = 1;
   Clk_delay();
   SCL = 1;
   Clk_delay();
   SCL = 0;
}

/*******************************I2C_Wbyte************************************/
//写一个BYTE
void I2C_W_byte(unsigned char c)
{
	unsigned char i;
	for(i=0; i<8; i++)
	{
		SCL = 0;
        Clk_delay();
		SDA=(bit)((c<<i)&0x80);
		SCL = 1;
        Clk_delay();
	}
        SCL = 0;
        I2C_Ack=I2C_CheckAck();
}



/*******************************I2C_Rbyte************************************/
//读一个BYTE
unsigned char I2C_R_byte()
{
	unsigned char i,Rbyte = 0;
	SDA = 1;                          //在读取SDA的电平时,先给SDA置1;
	for(i=0; i<8; i++)
	{
	   SCL = 0;
       Clk_delay();
	   SCL = 1;
       Clk_delay();
	   Rbyte<<=1;
	   if(SDA)
       Rbyte=Rbyte+0x01;
	}
	SCL = 0;
	return (Rbyte);
}


/*******************************I2C_Wadd************************************/
// 写16bit数据地址

void I2C_Wadd(unsigned int start_add)
{
  I2C_W_byte((char)(start_add>>8));  
  I2C_W_byte((char)start_add);  
}


/*******************************I2C_Wbyte************************************/
//往一个具体知地址写一个BYTE

void I2C_Wbyte(unsigned int start_add, unsigned char dat )
{

	I2C_START();
	I2C_W_byte(0xa0);  //device address
    if(!I2C_Ack)  ;//return (0);
	I2C_Wadd(start_add);         //16位地址
	I2C_W_byte(dat);                   //写数据
    if(!I2C_Ack)  ;//return (0);
	I2C_STOP();
    I2C_delay(5);
}



/*******************************I2C_Rbyte************************************/
// 读一个字节
unsigned char I2C_Rbyte(unsigned int start_add)
{
	unsigned char i;
    I2C_START();
	I2C_W_byte(0xa0);            //device addr
    if(!I2C_Ack)     return (0);        //I2C_Ack==0,没有接受到ACK,退出该函数。
    I2C_Wadd(start_add);        //数据地址
	I2C_START();
	I2C_W_byte(0xa1);
    if(!I2C_Ack)   return 0;
    i=I2C_R_byte();
    I2C_SendNoAck();
	I2C_STOP();
	I2C_delay(5);
	return i;
}


/*******************************I2C_Wdat************************************/
//写一快数据
void I2C_Wdat(unsigned int start_add, unsigned char *dat, unsigned int dat_len )
{
	I2C_START();
	I2C_W_byte(0xa0);  //device address
    if(!I2C_Ack)   ;//return (0);
	I2C_Wadd(start_add);         //16位地址
	for(; dat_len!=0; dat_len--)       //写数据
	{
       I2C_W_byte(*dat);
       if(!I2C_Ack)   ;//return (0);
	   dat++;
	}
	I2C_STOP();
    I2C_delay(5);
}



/*******************************I2C_Rdat************************************/
// 读一快数据
void I2C_Rdat(unsigned int start_add, unsigned char *dat_put, unsigned int len)
{
	unsigned int i=0;
	if(len>0)
    { len--;
      I2C_START();
      I2C_W_byte(0xa0);
      //if(!I2C_Ack)    return (0);       //I2C_Ack==0,没有接受到ACK,退出该函数。
      I2C_Wadd(start_add);              //数据地址
	  I2C_START();                      //再启动  
	  I2C_W_byte(0xa1);                  //开始读
      //if(!I2C_Ack)  ;  return 0;
      while(len--)
      {	
		*(dat_put+i)=I2C_R_byte();        //连续读出1BYTE
        I2C_SendAck();                   //送ACK
        i++;
	   }
      *(dat_put+i)=I2C_R_byte();        //读出1BYTE
        I2C_SendNoAck();               //送无效ACK
	 I2C_STOP();
   }
  I2C_delay(5);
}









/////////////////////////////////////////////////////////////////////////////////////






/*******************************I2C_DELAY************************************/
void I2C_delay(unsigned char i)
{
  unsigned char j;
  while(i--)
  {j=10;
   while(j--) NOP;
  }
}






⌨️ 快捷键说明

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