MCU GPIO模似I2C(代码完整版)

在硬件资源不够的情况下,通常需要使用GPIO口模似I2C。

1:初始化硬件GPIO口,不同硬件方法在同小异常

void SW_I2C_Init(void)
{			
  GPIO_InitTypeDef GPIO_InitStructure;
	
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     
  GPIO_Init(GPIOB, &GPIO_InitStructure);					       
}

2:根据I2C协议写:Start,Stop,Wait_Ack函数

//起始位:SCL为高时,SDA产生下降沿

static int I2C_Start(void)
{
	//1:确保SDA为输出模式
	SET_SDA_OUT();     	

	//2:拉高SDA,SCL
	I2C_SDA_H();
	if(!READ_SDA_PIN) return 0;	
	I2C_SCL_H();
	delay_us(SW_I2C_DELAY);
	
	//3:拉低SDA
 	I2C_SDA_L(); 
	if(READ_SDA_PIN) return 0;	
	delay_us(SW_I2C_DELAY);
	
	//4:拉低SCL,钳住I2C总线,准备发送数据
	I2C_SCL_L();	
	
	return 1;
}
//停止位:SCL为高时,SDA产生上升沿
static void I2C_Stop(void)
{
	//1:确保SDA为输出模式
	SET_SDA_OUT();
	
	//2: 拉低SCL,SDA
	I2C_SCL_L(); 	
	I2C_SDA_L(); 	
 	delay_us(SW_I2C_DELAY);
	
	//3:拉高SCL,SDA
	I2C_SCL_H();
	I2C_SDA_H(); 	
	delay_us(SW_I2C_DELAY);
}
//应答信号:0:Ack,1:NoAck
static u8 I2C_Wait_Ack(void)
{
	u8 timeout = 0;
	
	//1:SDA设为输入,拉高SCL
	SET_SDA_IN();   
	I2C_SDA_H();
	delay_us(SW_I2C_DELAY);
	I2C_SCL_H();
	delay_us(SW_I2C_DELAY);	 
	
	//2:读SDA
	while(READ_SDA_PIN)
	{
		timeout++;
		if(timeout > 50)
		{
			I2C_Stop();
			printf("[%s]:[Error]: there is no Ack!!!\r\n",__func__);
			return 0;
		}
	  delay_us(SW_I2C_DELAY);
	}
	
	//3:拉低SCL
	I2C_SCL_L();
	
	return 1;
}

3:I2C读字节

// I2C_Addr:从设置地址,Reg_Addr:寄存器地址,res:读取的数据
u8 I2C_Read_OneByte(u8 I2C_Addr,u8 Reg_Addr)
{
	u8 res = 0;
	
	//1:I2C开始
	I2C_Start();	
	
	//2:发送设备地址
	I2C_Send_Byte(I2C_Addr);	   						  
	I2C_Wait_Ack();
	
	//3:发送寄存器地址
	I2C_Send_Byte(Reg_Addr);   					 				
	I2C_Wait_Ack();	  
	I2C_Stop();															 	 
	
	//4:接入接收模式
	I2C_Start();
	I2C_Send_Byte(I2C_Addr+1);           			   
	I2C_Wait_Ack();
	
	//5:接收数据
	res = I2C_Receive_Byte(0);	   
  I2C_Stop();																

	return res;
}
static u8 I2C_Receive_Byte(u8 ack)
{
	u8 i,receive = 0;
	
	SET_SDA_IN();
	
	for(i=0;i<8;i++ )
	{
		I2C_SCL_L();
		delay_us(SW_I2C_DELAY);
		
		I2C_SCL_H();
		receive <<= 1;
		if(READ_SDA_PIN)
		{
			receive++;  
		}			
		delay_us(SW_I2C_DELAY);
  }			
	
	if (ack)
		I2C_Ack(); 
	else
		I2C_NAck();
	
	return receive;
}

4:I2C写字节

static void I2C_Send_Byte(u8 Byte)
{
	u8 i;   
	
	//1:确保SDA为输出状态
	SET_SDA_OUT(); 	

	//2: SCL拉低
	I2C_SCL_L();	

	//3: SDA准备数据
	for(i=0;i<8;i++)
  {   
		if((Byte & 0x80) == 0)
		{
			I2C_SDA_L();   //输出:0
		}
		else
		{
			I2C_SDA_H();   //输出:1
		}
		Byte <<= 1; 	  
		delay_us(SW_I2C_DELAY);  
		
		//4:SCL拉高,锁定SDA数据
		I2C_SCL_H();
		delay_us(SW_I2C_DELAY);
		
		//5:SCL拉低,准备下一个数据
		I2C_SCL_L();
		delay_us(SW_I2C_DELAY);
   }	 
}

#define SW_I2C_DELAY            1

所有延时用的都是1us。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DevinLGT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值