IIC模拟协议华大单片机移植

IIC模拟协议华大单片机移植

本文所用为 HC32L136K8TA
使用Gpio10== SDA GpioC11==SCL
先把关键性 宏定义说明

//引脚声明 
#define SCL_PORT   GpioPortC
#define SCL_PIN    GpioPin11

#define SDA_PORT   GpioPortC
#define SDA_PIN    GpioPin10

//IO方向设置
#define PC1out(n)   Gpio_WriteOutputIO( GpioPortC,  n, 1)  //输出 
#define PC0out(n)   Gpio_WriteOutputIO( GpioPortC,  n, 0)  //输出 
#define PCin(n)     Gpio_GetInputIO(GpioPortC,n)  //输入 		
			 
//IO操作函数	置地
#define MPU_IIC_SCL_0    PC0out(GpioPin11) //SCL 
#define MPU_IIC_SDA_0    PC0out(GpioPin10) //SDA	 
//IO操作函数	 拉高 
#define MPU_IIC_SCL_1     PC1out(GpioPin11) //SCL
#define MPU_IIC_SDA_1     PC1out(GpioPin10) //SDA
//IO读
#define MPU_READ_SDA     PCin(10)  //输入SDA 


//IIC所有操作函数
void MPU_IIC_Delay(void);				//MPU IIC延时函数
void MPU_IIC_Init(void);                //初始化IIC的IO口				 
void MPU_IIC_Start(void);				//发送IIC开始信号
void MPU_IIC_Stop(void);	  			//发送IIC停止信号
void 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信号

void IMPU_IC_Write_One_Byte(uint8_t daddr,uint8_t addr,uint8_t data);
uint8_t MPU_IIC_Read_One_Byte(uint8_t daddr,uint8_t addr);	  

先初始化SCL SDA 引脚

//初始化IIC
void MPU_IIC_Init(void)
{					     
    stc_gpio_cfg_t stcGpioCfg;
    
    ///< 打开GPIO外设时钟门控
    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
    
    ///< 端口方向配置->输入
    stcGpioCfg.enDir = GpioDirOut;
    stcGpioCfg.enPu = GpioPuEnable;
    stcGpioCfg.enPd = GpioPdDisable;	
		Gpio_Init(SDA_PORT, SDA_PIN, &stcGpioCfg);
	
    ///< 端口方向配置->输出
    stcGpioCfg.enDir = GpioDirOut;
    stcGpioCfg.enPu = GpioPuEnable;
    stcGpioCfg.enPd = GpioPdDisable;		
		Gpio_Init(SCL_PORT, SCL_PIN, &stcGpioCfg);
		
		IIC_SET_SDA;
		IIC_SET_SCL;
}

延时函数

  //MPU IIC 延时函数
void MPU_IIC_Delay(void)
{
		__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();			
		__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();		
}

IIC起始信号 停止信号

//产生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();							   	
}

主动应答和非应答

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
uint8_t MPU_IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	MPU_SDA_IN();      //SDA设置为输入  
	MPU_IIC_SDA_1;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;
}					 				     

发送一个字节 读取一个字节

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void MPU_IIC_Send_Byte(uint8_t txd)
{                        
	uint8_t t;   
	MPU_SDA_OUT(); 	    
	MPU_IIC_SDA_0;
	MPU_IIC_Delay(); 
	for(t=0;t<8;t++)
	{              
			if((txd&0x80)>>7)
				MPU_IIC_SDA_1;
			else
				MPU_IIC_SDA_0;
			txd<<=1;

			MPU_IIC_Delay(); 	
			MPU_IIC_SCL_1;
			MPU_IIC_Delay();
			MPU_IIC_SCL_0;	
			MPU_IIC_Delay();
	}	 
			MPU_IIC_SCL_0;	
			MPU_IIC_Delay();	
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
uint8_t MPU_IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	MPU_SDA_IN();//SDA设置为输入
	MPU_IIC_Delay();
    for(i=0;i<8;i++ )
	{
		receive<<=1;

		MPU_IIC_SCL_1;
		MPU_IIC_Delay();

		if(READ_SDA)
		receive|=0x01;
		
		MPU_IIC_SCL_0; 
		MPU_IIC_Delay(); 
    }					 
    if (!ack)
        MPU_IIC_NAck();//发送nACK
    else
        MPU_IIC_Ack(); //发送ACK   
    return receive;
}
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
I2C总线(Inter-Integrated Circuit,IIC)是一种串行通信总线,由Philips公司在20世纪80年代开发,现在已经成为了一种通用的总线标准。I2C总线可以连接多个设备,每个设备都有一个唯一的地址,可以在同一个总线上进行通信。 I2C总线由两条线组成:串行数据线(SDA)和串行时钟线(SCL)。SDA线用于数据传输,SCL线用于同步传输数据。I2C总线支持两种通信模式:主模式和从模式。在主模式下,主设备控制总线并发起数据传输;在从模式下,从设备等待主设备的控制,并响应主设备的请求。 I2C总线协议规定了通信时序、数据格式和错误处理等方面的规则。在I2C总线上进行通信需要遵循以下步骤: 1. 主设备发送起始信号; 2. 主设备发送设备地址和读写标志; 3. 从设备响应主设备的请求; 4. 主设备发送数据或请求数据; 5. 从设备响应主设备的请求; 6. 主设备发送停止信号。 以下是一个简单的通过I2C总线读取温度传感器数据的C语言程序,以Atmel公司的ATmega16单片机为例: ```c #include <avr/io.h> #include <util/delay.h> #define SCL_PIN 0 // 串行时钟线连接的引脚号,这里假设是PD0口 #define SDA_PIN 1 // 串行数据线连接的引脚号,这里假设是PD1口 #define DEVICE_ADDR 0x90 // 温度传感器的地址 void i2c_start(void) { PORTD |= (1 << SCL_PIN) | (1 << SDA_PIN); _delay_us(5); PORTD &= ~(1 << SDA_PIN); _delay_us(5); PORTD &= ~(1 << SCL_PIN); _delay_us(5); } void i2c_stop(void) { PORTD &= ~(1 << SDA_PIN); _delay_us(5); PORTD |= (1 << SCL_PIN) | (1 << SDA_PIN); _delay_us(5); } void i2c_write(unsigned char data) { unsigned char i; for(i = 0; i < 8; i++) { if(data & 0x80) PORTD |= (1 << SDA_PIN); else PORTD &= ~(1 << SDA_PIN); data <<= 1; PORTD |= (1 << SCL_PIN); _delay_us(5); PORTD &= ~(1 << SCL_PIN); _delay_us(5); } // 接收应答信号 PORTD |= (1 << SDA_PIN); PORTD |= (1 << SCL_PIN); _delay_us(5); if(PIND & (1 << SDA_PIN)) // 应答失败 PORTD &= ~(1 << SCL_PIN); _delay_us(5); } unsigned char i2c_read(unsigned char ack) { unsigned char i, data = 0; for(i = 0; i < 8; i++) { PORTD |= (1 << SCL_PIN); _delay_us(5); data <<= 1; if(PIND & (1 << SDA_PIN)) data |= 0x01; PORTD &= ~(1 << SCL_PIN); _delay_us(5); } // 发送应答信号 if(ack) PORTD &= ~(1 << SDA_PIN); else PORTD |= (1 << SDA_PIN); PORTD |= (1 << SCL_PIN); _delay_us(5); PORTD &= ~(1 << SCL_PIN); _delay_us(5); return data; } int main() { unsigned char temp_l, temp_h, temp; DDRC = 0xFF; DDRD = (1 << SCL_PIN) | (1 << SDA_PIN); i2c_start(); i2c_write(DEVICE_ADDR | 0x01); // 读取温度传感器数据 temp_h = i2c_read(1); temp_l = i2c_read(0); i2c_stop(); temp = (temp_h << 8) | temp_l; temp = temp >> 5; temp = temp * 0.0625; PORTC = temp; // 将温度值输出到LED灯 return 0; } ``` 在这个程序中,我们假设串行时钟线连接在PD0口,串行数据线连接在PD1口。程序的逻辑如下: 1. 配置PD0和PD1为输出引脚; 2. 发送起始信号; 3. 发送温度传感器的地址,并指定读取数据; 4. 接收温度值的高8位,并发送应答信号; 5. 接收温度值的低8位,并发送非应答信号; 6. 发送停止信号; 7. 计算温度值,并输出到LED灯上。 在程序中,我们定义了三个函数:`i2c_start`,`i2c_stop`和`i2c_write`,用于发送起始信号、停止信号和写入数据。我们还定义了一个函数`i2c_read`,用于读取数据,并发送应答信号或非应答信号。 需要注意的是,I2C总线上的数据传输需要遵循具体设备的通信协议和时序要求,不同设备之间可能存在差异。因此,在实际应用中需要根据具体设备的要求进行通信协议的编写。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值