自己写的i2c驱动

对于从事嵌入式开发的朋友来说,I2C协议实在是再熟悉不过了,许多芯片都是采用的I2C来进行相应的配置。今天,我们就随便聊聊这个I2C协议,并且自己通过普通GPIO口实现一个i2c驱动。
i2c的通信除了GND之外,主要是SDA和SCL两根线完成,外部芯片可接到这两根线上来实现通信;

#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正常写序列;
在这里插入图描述
使用上述代码实现的写序列
在这里插入图片描述
i2C正常读序列;
在这里插入图片描述
使用上述代码实现的读序列
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43704402/article/details/106005682