I2c driver written by myself

For friends who are engaged in embedded development, the I2C protocol is really familiar. Many chips use I2C for corresponding configuration. Today, we will just talk about this I2C protocol, and implement an i2c driver through the ordinary GPIO port.
In addition to GND, the communication of i2c is mainly completed by two wires, SDA and SCL, and the external chip can be connected to these two wires to realize communication;

#define	SETSCL1()	GPIO_OutputCtr(GPIO_Pin_3,SET)   //拉高SCL管脚
#define	CLRSCL1()	GPIO_OutputCtr(GPIO_Pin_3,RESET) //拉低SCL管脚

#define	SETSDA1()	GPIO_OutputCtr(GPIO_Pin_4,SET)  //拉高SDA管脚
#define	CLRSDA1()	GPIO_OutputCtr(GPIO_Pin_4,RESET) //拉低SDA管脚

#define	GET_SDA1_STATUAS()	GPIO_GetInputLevel(GPIO_Pin_4) //获取SDA管脚的高低电平
#define	GET_SCL1_STATUAS()	GPIO_GetInputLevel(GPIO_Pin_3)  //获取SCL管脚的高低电平
static unsigned char F1;

void myIIC1_Init(void)
{
	/*将SDA和SCl配置成输入。因为平台不一致,就不具体写了*/
}
/**将SDA设置为输入功能*/
void sda1_in_set(void)
{
}
/**将SDA设置为输出功能,并且根据之前的输入状态来判断是否要拉高,还是拉低*/
void sda1_out_set(void)
{
}
/**将SCL设置为输出功能,并且拉高*/
void scl1_out_set(void)
{
}
/**将SCL设置为输入功能*/
void scl1_in_set(void)
{
}
/**起始条件:当SCL高电平时,SDA由高电平向低电平转换;*/
void iic1_start(void)
{
	uint8_t temp=5;
	SETSDA1();  //sda 1
	SETSCL1();  //sck 1
	sda1_out_set();
	scl1_out_set();		
	CLRSDA1();  //sda 0
	while(temp--);
	CLRSCL1();  //sck 0
}
/**停止条件:当SCL高电平时,SDA由低电平向高电平转换。*/
void iic1_stop(void)
{
	uint16_t i;
	CLRSDA1();  //sda 0
	SETSCL1();  //sck 1
	SETSCL1();  //sck 1
	SETSDA1();  //sda 1
	if(F1 == 1)          
	{
		for(i=0;i<100;i++);
	}
	myIIC1_Init();
}

/*数据接收方收到传输的一个字节数据后,需要给出响应,此时处在第九个时钟,发送端释放SDA线控制权,将SDA电平拉高,
由接收方控制。若希望继续,则给出“应答(ACK)”信号,即SDA为低电平;反之给出“非应答(NACK)”信号,
即SDA为高电平。*/
void check_ACK1(void)  
{   
	uint16_t i;
	
	sda1_in_set();   //sda in
	scl1_in_set();		//scl in
	
	F1 = 0;
	i = 0;
	while((GET_SDA1_STATUAS() != RESET)&&(i<200))
	{
		i++;
	}
	if(i>= 200)
	{
		F1 = 1;
	}

	CLRSCL1();  //sck 0
	sda1_out_set();   //sda out
	scl1_out_set();
	CLRSCL1();  //sck 1
    for(int j = 0; j< 160; j++); //这地方加个延时是因为实际测试过程中,有个外部芯片,会将SCL拉高;
} 

void send_ACK1(void)
{
	uint16_t i;
	
	sda1_out_set();   //sda out
	CLRSDA1();
	SETSCL1();  //sck 1
	for(i=2;i>0;i--);   //short delay	
	CLRSCL1();  //sck 0
	sda1_in_set();   //sda in
}

void send_NOACK1(void)  
{ 
	SETSDA1();   //sda 1   
	SETSCL1();  //sck 1
	CLRSCL1();  //sck 0
}
/*发送data数据*/
void IIC1SendByte(unsigned char ch)  
{   
	unsigned char n=8;     
	while(n--)  
	{   
		if((ch&0x80) == 0x80)    // 
	   {  
			SETSDA1();  //sda 1
			SETSCL1();  //sck 1  
			SETSCL1();
			CLRSCL1();  //sck 0
	   }  
	   else  
	   {   
			CLRSDA1();  //sda 0   //
			SETSCL1();  //sck 1 
			SETSCL1(); 
			CLRSCL1();  //sck 0  
	   }  
	    ch = ch<<1;    //
	} 	
}
/*接收数据*/
unsigned char IIC1receiveByte(void)  
{  
	unsigned char n=8;    
	unsigned char tdata=0;
	sda1_in_set();   //sda in
	while(n--)  
	{   
	  SETSCL1();  //sck 1 
	  tdata = tdata<<1;    //
	  if(GET_SDA1_STATUAS() != RESET)
		{
			tdata = tdata|0x01;    
	  }
		else   
		{
			tdata = tdata&0xfe;    
	  } 
	  CLRSCL1();  //sck 0  
	} 
	sda1_out_set();   //sda out
	return(tdata);  
} 

unsigned char IIC1_write_Nbytes(unsigned char devAddr,unsigned char reg_add,unsigned char *buf,unsigned char len)  
{
	uint8_t i;
	
	iic1_start();                // 
	IIC1SendByte(devAddr);     //
	check_ACK1();
    if(F1 == 1)
    {
        for(i=0;i<100;i++);
        myIIC1_Init();
        return 1;
    }
	IIC1SendByte(reg_add);       // 
	check_ACK1();                // 
    if(F1 == 1)
    {
        for(i=0;i<100;i++);
        myIIC1_Init();
        return 1;
    }
	for(i=0;i<len;i++)
	{
		IIC1SendByte(buf[i]);       //  
		check_ACK1();                // 
        if(F1 == 1)
        {
            for(i=0;i<100;i++);
            myIIC1_Init();
            return 1;
        }
    }
	iic1_stop();         
	myIIC1_Init();		
    if(F1 == 1)
    {
        return 1;
    }
	return 0;
}
unsigned char IIC1_receive_Nbytes(unsigned char devAddr,unsigned char reg_add,unsigned char *buf,unsigned char len)  
{   
	unsigned char i;
	uint16_t temp=0;
	iic1_start();  
	IIC1SendByte(devAddr); //
	check_ACK1();
    if(F1 == 1)
    {
        for(i=0;i<100;i++);
        myIIC1_Init();
        return 1;
    }
	IIC1SendByte(reg_add); 
	check_ACK1();
    if(F1 == 1)
    {
        iic1_stop();
        myIIC1_Init();
        return 1;
    }    
	iic1_start();  
	IIC1SendByte(devAddr+1); 
	check_ACK1();
    if(F1 == 1)
    {
        iic1_stop();
        myIIC1_Init();
        return 1;
    }
	for(i=0;i<len;i++)
	{
		temp=150;
		while(temp--);
		buf[i]=IIC1receiveByte();
		if(i!=(len-1))
		{
			send_ACK1();		
		}
	}
	send_NOACK1();      
	iic1_stop(); 
	myIIC1_Init();		
    if(F1 == 1)
    {
        for(i=0;i<100;i++);
        return 1;
    }
	return 0;
}

i2C normal writing sequence;
Insert figure description here
the writing sequence realized by the above code
Insert picture description here
i2C normal reading sequence;
Insert picture description here
the reading sequence realized by the above code
Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_43704402/article/details/106005682