IIC模拟代码

这段代码展示了如何使用STM32的GPIO引脚模拟IIC通信协议,包括开始信号、停止信号、发送数据和读取数据的函数,以及相应的IO操作宏定义。主要用于与IIC设备如传感器的交互。
摘要由CSDN通过智能技术生成

IIC模拟代码

#define SCL_PORT   GPIOC
#define SCL_PIN    GPIO_Pin_6

#define SDA_PORT   GPIOC
#define SDA_PIN    GPIO_Pin_5


#define SCL_OUT_1(n)   GPIO_SetBits( SCL_PORT,  n )  //Êä³ö 
#define SCL_OUT_0(n)   GPIO_ResetBits( SCL_PORT,  n )  //Êä³ö 

#define SDA_OUT_1(n)   GPIO_SetBits( SDA_PORT,  n )  //Êä³ö 
#define SDA_OUT_0(n)   GPIO_ResetBits( SDA_PORT,  n)  //Êä³ö 

#define SDA_IN(n)      GPIO_ReadInputDataBit(SDA_PORT ,n)  //ÊäÈë 					 
					 
//IO·½ÏòÉèÖÃ
//#define MPU_SDA_IN()  {SetBit(((uint32_t)&M0P_GPIO->PADIR + SDA_PORT), SDA_PIN, (boolean_t)GpioDirIn);}
//#define MPU_SDA_OUT() {SetBit(((uint32_t)&M0P_GPIO->PADIR + SDA_PORT), SDA_PIN, (boolean_t)GpioDirOut);}

//IO²Ù×÷º¯Êý	 
#define MPU_IIC_SCL_0    SCL_OUT_0(SCL_PIN)   //SCL  0
#define MPU_IIC_SDA_0    SDA_OUT_0(SDA_PIN)   //SDA  0 
#define MPU_READ_SDA     SDA_IN(GPIO_Pin_5)   //ÊäÈëSDA 

//IO²Ù×÷º¯Êý	 
#define MPU_IIC_SCL_1     SCL_OUT_1(SCL_PIN)  //SCL 1
#define MPU_IIC_SDA_1     SDA_OUT_1(SDA_PIN)  //SDA 1
 

#define MPU_ADDR				0x12

//IICËùÓвÙ×÷º¯Êý
void MPU_IIC_Delay(void);				//MPU IICÑÓʱº¯Êý
void hal_IIC_Init(void);                //³õʼ»¯IICµÄIO¿Ú				 
void MPU_IIC_Start(void);				//·¢ËÍIIC¿ªÊ¼ÐźÅ
void MPU_IIC_Stop(void);	  			//·¢ËÍIICÍ£Ö¹ÐźÅ
uint8_t MPU_IIC_Send_Byte(uint8_t txd);			//IIC·¢ËÍÒ»¸ö×Ö½Ú
uint8_t MPU_IIC_Read_Byte(unsigned char ack);//IIC¶ÁÈ¡Ò»¸ö×Ö½Ú
uint8_t MPU_IIC_Wait_Ack(void); 				//IICµÈ´ýACKÐźÅ
void MPU_IIC_Ack(void);					//IIC·¢ËÍACKÐźÅ
void MPU_IIC_NAck(void);				//IIC²»·¢ËÍACKÐźÅ

extern uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data);				//IICдһ¸ö×Ö½Ú
extern uint8_t MPU_Read_Byte(uint8_t reg);						//IIC¶ÁÒ»¸ö×Ö½Ú

void hal_IIC_Proc(void);

//ÅäÖÃÒý½ÅΪÊäÈë
void MPU_SDA_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	//¶¨ÒåÒ»¸öGPIO_InitTypeDefÀàÐ͵ĽṹÌå
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;		//ÉèÖÃÒý½ÅģʽΪÊäÈë
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	//ÎÞÆ«ÖÃ
	///< ¶Ë¿Ú·½ÏòÅäÖÃ->ÊäÈë
	GPIO_InitStructure.GPIO_Pin = SDA_PIN;	//Ñ¡ÔñÒª¿ØÖƵÄGPIOÒý½Å
	GPIO_Init(SDA_PORT, &GPIO_InitStructure);	//µ÷Óÿ⺯Êý£¬³õʼ»¯GPIO
//	SDA_PORT->OES =SDA_PIN;
//	SDA_PORT->ODS = SDA_PIN;

}
//ÅäÖÃÒý½ÅΪÊä³ö
void MPU_SDA_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	//¶¨ÒåÒ»¸öGPIO_InitTypeDefÀàÐ͵ĽṹÌå

	GPIO_InitStructure.GPIO_Mode = GPIO_OType_OD;		//ÉèÖÃÒý½ÅģʽΪͨÓÃÍÆÍìÊä³ö
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	//ÎÞÆ«ÖÃ

	///< ¶Ë¿Ú·½ÏòÅäÖÃ->ÊäÈë
	GPIO_InitStructure.GPIO_Pin = SDA_PIN;	//Ñ¡ÔñÒª¿ØÖƵÄGPIOÒý½Å
	GPIO_Init(SDA_PORT, &GPIO_InitStructure);	//µ÷Óÿ⺯Êý£¬³õʼ»¯GPIO
//	SDA_PORT->OES = SDA_PIN;
//	SDA_PORT->PDC = SDA_PIN;	
//	SDA_PORT->PUC = SDA_PIN;
}


 //MPU IIC ÑÓʱº¯Êý
void MPU_IIC_Delay(void)
{
		__nop();__nop();__nop();__nop();__nop();__nop();

}

//³õʼ»¯IIC
void hal_IIC_Init(void)
{					     
	GPIO_InitTypeDef GPIO_InitStructure;	//¶¨ÒåÒ»¸öGPIO_InitTypeDefÀàÐ͵ĽṹÌå

	GPIO_InitStructure.GPIO_Mode = GPIO_OType_OD;		//ÉèÖÃÒý½ÅģʽΪ¿ªÂ©
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	//ÎÞÆ«ÖÃ

	///< ¶Ë¿Ú·½ÏòÅäÖÃ->ÊäÈë
	GPIO_InitStructure.GPIO_Pin = SDA_PIN;	//Ñ¡ÔñÒª¿ØÖƵÄGPIOÒý½Å
	GPIO_Init(SDA_PORT, &GPIO_InitStructure);	//µ÷Óÿ⺯Êý£¬³õʼ»¯GPIO
	GPIO_SetBits(SDA_PORT, SDA_PIN);
	///< ¶Ë¿Ú·½ÏòÅäÖÃ->Êä³ö
	GPIO_InitStructure.GPIO_Pin = SCL_PIN;	//Ñ¡ÔñÒª¿ØÖƵÄGPIOÒý½Å
	GPIO_Init(SCL_PORT, &GPIO_InitStructure);	//µ÷Óÿ⺯Êý£¬³õʼ»¯GPIO
	GPIO_SetBits(SCL_PORT, SCL_PIN);

	MPU_IIC_SDA_1;
	MPU_IIC_SCL_1;
	
	MPU_IIC_Delay();

}
//²úÉúIICÆðʼÐźÅ
void MPU_IIC_Start(void)
{
	MPU_SDA_OUT();     //sdaÏßÊä³ö
	MPU_IIC_SDA_1;	  	  
	MPU_IIC_SCL_1;
	MPU_IIC_Delay();
 	MPU_IIC_SDA_0;//START:when CLK is high,DATA change form high to low 
	MPU_IIC_Delay();
	MPU_IIC_SCL_0;//ǯסI2C×ÜÏߣ¬×¼±¸·¢ËÍ»ò½ÓÊÕÊý¾Ý 
	MPU_IIC_Delay();
}	  
//²úÉúIICÍ£Ö¹ÐźÅ
void MPU_IIC_Stop(void)
{
	MPU_SDA_OUT();//sdaÏßÊä³ö
	MPU_IIC_SCL_0;
	MPU_IIC_SDA_0;//STOP:when CLK is high DATA change form low to high
 	MPU_IIC_Delay();
	MPU_IIC_SCL_1;  
	MPU_IIC_SDA_1;//·¢ËÍI2C×ÜÏß½áÊøÐźÅ
	MPU_IIC_Delay();							   	
}

uint8_t MPU_IIC_Wait_Ack(void)
{
	uint16_t ucErrTime=0;
	MPU_SDA_IN(); MPU_IIC_Delay();  
	MPU_IIC_SCL_1;MPU_IIC_Delay();

	while(MPU_READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			MPU_IIC_Stop();
			return 1;  
		}
	}

	MPU_IIC_SCL_0;//????0 	   
	return 0;  
} 
//??ACK??
void MPU_IIC_Ack(void)
{
	MPU_IIC_SCL_0;
	MPU_SDA_OUT();
	MPU_IIC_SDA_0;
	MPU_IIC_Delay();
	MPU_IIC_SCL_1;
	MPU_IIC_Delay();
	MPU_IIC_SCL_0;
}
//???ACK??		    
void MPU_IIC_NAck(void)
{
	MPU_IIC_SCL_0;
	MPU_SDA_OUT();
	MPU_IIC_SDA_1;
	MPU_IIC_Delay();
	MPU_IIC_SCL_1;
	MPU_IIC_Delay();
	MPU_IIC_SCL_0;
}					 				     



uint8_t MPU_IIC_Send_Byte(uint8_t txd)
{                        
	uint8_t t;   

  MPU_SDA_OUT();
	MPU_IIC_SCL_0;	
	for(t=0;t<8;t++)
	{     
			if((txd<<t)&0x80)
				MPU_IIC_SDA_1;
			else
				MPU_IIC_SDA_0;
			
			MPU_IIC_Delay(); 	
			MPU_IIC_SCL_1;
			
			MPU_IIC_Delay();	
			MPU_IIC_SCL_0;	
			
			MPU_IIC_Delay();			
	}	 

} 	    
 
uint8_t MPU_IIC_Read_Byte(unsigned char ack)
{
	uint8_t i,receive=0;
	uint16_t ucErrTime=0;
	MPU_SDA_IN();//SDA

	for(i=0;i<8;i++ )
	{
			
			MPU_IIC_SCL_0; 
			MPU_IIC_Delay(); 
		
			MPU_IIC_SCL_1;
			receive<<=1;

			if(MPU_READ_SDA)
			receive++;
			
			MPU_IIC_Delay();

  }					 
	return receive;
}



uint8_t MPU_Write_Str(uint8_t reg,uint8_t *s,uint8_t xn) 				 
{ 
	uint8_t i=0;
  MPU_IIC_Start(); 
	MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//
	if(MPU_IIC_Wait_Ack())	return 0;		
	MPU_IIC_Send_Byte(reg);	//
	if(MPU_IIC_Wait_Ack())	return 0;		 
	
	for(i=0;i<xn;i++)
	{
		MPU_IIC_Send_Byte(*s);
		if(MPU_IIC_Wait_Ack())	return 0;		
		s++;		
	}

  MPU_IIC_Stop();	 
	return 1;
}

uint8_t MPU_Read_Byte(uint8_t reg)
{
	uint8_t res;
	MPU_IIC_Start(); 
	MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//
	if(MPU_IIC_Wait_Ack())	return 0;		
	MPU_IIC_Send_Byte(reg);	
	if(MPU_IIC_Wait_Ack())	return 0;		

	MPU_IIC_Start();
	MPU_IIC_Send_Byte((MPU_ADDR<<1)|1);//
	if(MPU_IIC_Wait_Ack())	return 0;		
	res=MPU_IIC_Read_Byte(0);//
	MPU_IIC_NAck();
	MPU_IIC_Stop();			//

	return res;		
}
uint8_t MPU_Read_Str(uint8_t reg,uint8_t *s,uint8_t xn) 				 
{ 
	uint8_t i=0;
	MPU_IIC_Start(); 
	MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//
	if(MPU_IIC_Wait_Ack())	return 0;		
	MPU_IIC_Send_Byte(reg);	
	if(MPU_IIC_Wait_Ack())	return 0;		

	MPU_IIC_Start();
	MPU_IIC_Send_Byte((MPU_ADDR<<1)|1);//
	if(MPU_IIC_Wait_Ack())	return 0;		
	
	for(i=0;i<xn;i++)
	{
		*s=MPU_IIC_Read_Byte(0);//
		MPU_IIC_Ack();
		s++;		
	}
	*s=MPU_IIC_Read_Byte(0);//
	
	MPU_IIC_NAck();
	MPU_IIC_Stop();			//
	return 1;		
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,GPIO (General Purpose Input Output) 模拟 IIC 可能是指通过 GPIO 端口来实现 I2C 总线通信的一种做法。通常,微控制器硬件上自带了专门用于 I2C 的模块,但在某些情况下,开发者可能会选择只利用 GPIO 来实现基本的 I2C 功能,这需要自定义驱动和协议处理。 ### C语言实现IIC的基本步骤 1. **初始化IIC**: - 配置GPIO作为I2C总线的SCL和SDA信号线。 - 设置定时器或中断机制来处理数据的发送和接收时间。 2. **生成起始和停止条件**: - 发送起始条件(0x00)来开始传输。 - 发送设备地址加上读写标志(读写命令),并等待应答。 3. **发送和接收数据**: - 使用循环结构来轮流发送和接收数据字节。 - 对于每个数据字节,先发送或接收开始位(0),然后是8位数据位。 4. **终止交易**: - 发送结束条件(0xFF)来结束交易。 ### 示例代码结构 假设我们有一个简单的函数 `send_i2c_message` 来实现这个过程: ```c #include <avr/io.h> // 引入AVR寄存器操作库 void send_i2c_message(unsigned char device_address, unsigned char read_write_bit, unsigned char data[], int length) { unsigned char i; // 初始化SCL和SDA GPIO端口 DDRD |= (1 << PD6); // SCL为输出 PORTD &= ~(1 << PD6); DDRE |= (1 << PE2); // SDA为输出 PORTE &= ~(1 << PE2); // 生成起始条件 SCL = HIGH; // 将SCL设置高电平 delayMicroseconds(100); // 给器件一些初始化时间 SDA = LOW; // 将SDA拉低,发送起始条件 SCL = LOW; delayMicroseconds(1); // 停留片刻以便接收方准备好 SCL = HIGH; // 写入设备地址和读写标志 for(i=7; i>=0; i--) { if((device_address >> i) & 0x01) { // 判断地址的每一位是否为1 SDA ^= 1; // 如果为1,则将SDA拉高表示1;如果为0,则保持SDA的状态 delayMicroseconds(1); // 等待 } SCL = LOW; delayMicroseconds(1); SCL = HIGH; delayMicroseconds(1); } // 添加读写标志 if(read_write_bit == READ) { SDA ^= 1; // 读操作标志 } else { SDA = 0; // 写操作标志 } SCL = LOW; delayMicroseconds(1); SCL = HIGH; // 发送数据 for(i=0; i<length; i++) { while(!bit_is_set(SDA)); // 等待SDA为低电平 SCL = LOW; // 开始位 for(int j=7; j>=0; j--) { SDA ^= 1; // 根据data[i]的第j位值改变SDA状态 SCL = HIGH; delayMicroseconds(1); SCL = LOW; delayMicroseconds(1); } SCL = HIGH; // 数据发送完成,进入下一个位 while(bit_is_set(SDA)); // 等待SDA回到低电平 } // 释放资源 PORTD |= (1 << PD6); // SCL变为输入 PORTE |= (1 << PE2); // SDA变为输入 // 结束条件 SCL = HIGH; delayMicroseconds(100); SDA = HIGH; delayMicroseconds(500); } // 定义一个辅助函数来判断GPIO引脚状态 int bit_is_set(unsigned char pin) { return (PIND & (1 << pin)) != 0; // 返回非零值,说明引脚为高电平 } ``` ### 注意事项和潜在改进点 - 这是一个非常基础的示例,实际应用中可能需要添加更多的错误检查、时序调整以及更复杂的控制逻辑。 - 对于不同的微控制器平台,GPIO配置和操作细节会有所不同。 - 实际编码时需考虑时钟同步、数据冲突等问题,并可能需要用到定时器中断或其他高级功能来优化性能。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值