Controlador I2c escrito por mí mismo

Para los amigos que se dedican al desarrollo integrado, el protocolo I2C es realmente familiar.Muchos chips utilizan I2C para la configuración correspondiente. Hoy, solo hablaremos de este protocolo I2C e implementaremos un controlador i2c a través de un puerto GPIO común.
Además de GND, la comunicación de i2c se completa principalmente con dos cables, SDA y SCL, y el chip externo se puede conectar a estos dos cables para realizar la comunicación;

#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;
}

Secuencia de escritura normal i2C;
Inserte la descripción de la figura aquí
la secuencia de escritura realizada por el código anterior
Inserte la descripción de la imagen aquí
Secuencia de lectura normal i2C;
Inserte la descripción de la imagen aquí
la secuencia de lectura realizada por el código anterior
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_43704402/article/details/106005682
Recomendado
Clasificación