模拟IIC_读写BQ40Z50模块

本文详细介绍了使用32位单片机通过IIC接口与BQ40Z50电池管理模块进行通信的方法。包括GPIO初始化、封装管脚拉高拉低函数、读写IIC模块的具体实现,以及关键的延时计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

读写BQ40Z50模块,我使用的是32单片机
该模拟IIC仅适用于BQ40Z50模块,因为每个模块延时有差异
1.初始化GPIO,根据你所使用的单片机完成初始化

__HAL_RCC_GPIOH_CLK_ENABLE();//初始化时钟
	/*IIC3 Configure GPIO pins : PIPin PIPin */
  GPIO_InitStruct.Pin = IIC3SDA_Pin|IIC3SCL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
//	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
  HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

初始化输入输出模式

#define     SDA_IN()          {GPIOH->MODER&=~(3<<(8*2));GPIOH->MODER|=0<<8*2;}    //PH8
#define     SDA_OUT()         {GPIOH->MODER&=~(3<<(8*2));GPIOH->MODER|=1<<8*2;} //PH8
#define     SDA_OD_OUT()     {GPIOH->OTYPER&=~(1<<8);GPIOH->OTYPER|=1<<8;} //PH8
#define     SDA_PP_OUT()     {GPIOH->OTYPER&=~(1<<8);GPIOH->OTYPER|=0<<8;} //PH8

2.封装管脚拉高拉低函数

//读取数据管脚电平
uint8_t I2C_SDA_READ(GPIO_I2C_ST IICx )
{
	return HAL_GPIO_ReadPin(IICx.Gpio_Sda_Port,IICx.Gpio_Sda_Pin);
}
//读取时钟管脚电平
uint8_t I2C_SCL_READ(GPIO_I2C_ST IICx)
{
	return HAL_GPIO_ReadPin(IICx.Gpio_Scl_Port,IICx.Gpio_Scl_Pin);
}
//将时钟电平拉高
void I2C_SCL_1(GPIO_I2C_ST IICx )
{
	HAL_GPIO_WritePin(IICx.Gpio_Scl_Port,IICx.Gpio_Scl_Pin,GPIO_PIN_SET);
}	
//时钟电平拉低
void I2C_SCL_0(GPIO_I2C_ST IICx )
{
	HAL_GPIO_WritePin(IICx.Gpio_Scl_Port,IICx.Gpio_Scl_Pin,GPIO_PIN_RESET);
}
//数据电平拉高
void I2C_SDA_1(GPIO_I2C_ST IICx ) 
{	
	HAL_GPIO_WritePin(IICx.Gpio_Sda_Port,IICx.Gpio_Sda_Pin,GPIO_PIN_SET);
}
//数据电平拉低
void I2C_SDA_0(GPIO_I2C_ST IICx)
{
	HAL_GPIO_WritePin(IICx.Gpio_Sda_Port,IICx.Gpio_Sda_Pin,GPIO_PIN_RESET);
}

3.读写IIC模块
延时是根据硬件IIC计算出来的

/*
开始
*/
void SMbus_Start(GPIO_I2C_ST IICx)
{
    SDA_PP_OUT();      //  
    SDA_OUT();     //
    I2C_SDA_1(IICx);        
    I2C_SCL_1(IICx);
    delay_us(50);
     I2C_SDA_0(IICx);
    delay_us(50);
    I2C_SCL_0(IICx);//
}   

//结束
void SMbus_Stop(GPIO_I2C_ST IICx)
{
    SDA_PP_OUT();      // 
    SDA_OUT();//
    I2C_SCL_0(IICx);
    I2C_SDA_0(IICx);//
     delay_us(50);
    I2C_SCL_1(IICx);
		delay_us(10);    
    I2C_SDA_1(IICx);//
    delay_us(50);                                   
}
//发送ACK
void SMbus_Ack(GPIO_I2C_ST IICx)
{
    SDA_PP_OUT();
    SDA_OUT();
    I2C_SCL_0(IICx);
		I2C_SDA_0(IICx);	
    delay_us(60);
		I2C_SCL_0(IICx);
		delay_us(5);
    I2C_SCL_1(IICx);
    delay_us(50);
    I2C_SCL_0(IICx);
    delay_us(4);
    //在发送完ACK后严禁数据线电平变化
//    I2C_SDA_1(IICx);
}


// 接收ACK
uint8_t SMbus_Wait_Ack(GPIO_I2C_ST IICx)
{
    uint8_t ucErrTime=0;
    SDA_OD_OUT();      //SDA???????
	I2C_SCL_0(IICx);
    SDA_IN();
		delay_us(100);//等待100US是为了等待高电平,时间太短可能等不到
    I2C_SCL_1(IICx);delay_us(10);     
    while(I2C_SDA_READ(IICx))
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            SMbus_Stop(IICx);
            return 1;
        }
    }    
    return 0; 
}  
//发送一个字节  
void SMbus_Send_Byte(GPIO_I2C_ST IICx,uint8_t txd)
{                        
    uint8_t t;   
    SDA_PP_OUT();      //
    SDA_OUT();         
    I2C_SCL_0(IICx);//
		delay_us(5); 
    for(t=0;t<8;t++){
				if((txd&0x80)>>7 == 1)
				{
					I2C_SDA_1(IICx);
				}
				else
				{
					I2C_SDA_0(IICx);
				}
        txd<<=1;       
        delay_us(50);   
        I2C_SCL_1(IICx);
        delay_us(50); 
        I2C_SCL_0(IICx); 
				delay_us(4);
    } 
		I2C_SCL_0(IICx); 		
    delay_us(10);     
} 
//读取一个字节
uint8_t SMbus_Read_Byte(GPIO_I2C_ST IICx)
{
    unsigned char i,receive=0;
    SDA_OD_OUT();      //
    SDA_IN();//
		I2C_SCL_0(IICx);
	//在读取第一个字节第一位的时候,延时需要超过60US,因为从设备控制数据线有个跳变的过程,这点必须注意
    delay_us(70);
  for(i=0;i<8;i++ )
    {
		I2C_SCL_0(IICx); 
        delay_us(50);
        I2C_SCL_1(IICx);
		delay_us(50);
        receive<<=1;
        if(I2C_SDA_READ(IICx))receive++;          
    }
		I2C_SCL_0(IICx); 
    delay_us(10);
    SMbus_Ack(IICx);

    return receive;
}
//读取寄存器当中的两个字节,单片机做主,BQ40Z50做从
uint8_t bq40z50_Get_Data(GPIO_I2C_ST IICx,uint8_t address,uint8_t* buff)
{
    SMbus_Start(IICx);  //开始
    SMbus_Send_Byte(IICx,0x16);//发送模块地址
    if(SMbus_Wait_Ack(IICx) == 1)//读取ACK
    {        
        return 1;
    }
    
    SMbus_Send_Byte(IICx,address);    //发送寄存器地址
		if(SMbus_Wait_Ack(IICx) == 1)//
    {
        
        return 1;
    }
    SMbus_Start(IICx);
    
    SMbus_Send_Byte(IICx,0x17);
    if(SMbus_Wait_Ack(IICx) == 1)//
    {
        return 1;
    }
    
    *(buff+0) = SMbus_Read_Byte(IICx);//读取一个字节
    *(buff+1) = SMbus_Read_Byte(IICx);
    SMbus_Stop(IICx);
    return 0;
}

如果延时不会初始化点击下面链接
https://blog.youkuaiyun.com/weixin_43879214/article/details/111587924

首先,需要在代码中包含 HAL 库和 CMSIS 库的头文件。然后,需要初始化 I2C 总线和 BQ40Z50 芯片。 以下是一个使用 HAL 库的示例代码: ``` #include "stm32f1xx_hal.h" #include "cmsis_os.h" I2C_HandleTypeDef hi2c1; #define BQ40Z50_ADDR 0x16 void BQ40Z50_Init(void) { uint8_t tx_data[2]; // Set the BQ40Z50's "Control" register to 0x00 tx_data[0] = 0x00; tx_data[1] = 0x00; HAL_I2C_Master_Transmit(&hi2c1, BQ40Z50_ADDR, tx_data, 2, 1000); // Set the BQ40Z50's "Control" register to 0x01 tx_data[0] = 0x00; tx_data[1] = 0x01; HAL_I2C_Master_Transmit(&hi2c1, BQ40Z50_ADDR, tx_data, 2, 1000); } void BQ40Z50_Read(uint8_t reg_addr, uint8_t *data, uint8_t len) { HAL_I2C_Mem_Read(&hi2c1, BQ40Z50_ADDR, reg_addr, 1, data, len, 1000); } void BQ40Z50_Write(uint8_t reg_addr, uint8_t *data, uint8_t len) { uint8_t tx_data[20]; tx_data[0] = reg_addr; memcpy(&tx_data[1], data, len); HAL_I2C_Master_Transmit(&hi2c1, BQ40Z50_ADDR, tx_data, len+1, 1000); } int main(void) { uint8_t data[20]; // Initialize I2C bus and BQ40Z50 HAL_I2C_Init(&hi2c1); BQ40Z50_Init(); // Read data from BQ40Z50's "Manufacturer Name" register BQ40Z50_Read(0x20, data, 20); // Do something with the data... // Write data to BQ40Z50's "Manufacturer Access" register data[0] = 0x01; data[1] = 0x02; BQ40Z50_Write(0x3E, data, 2); while (1) { // Main program loop } } ``` 在这个示例代码中,我们使用了 `HAL_I2C_Master_Transmit()` 和 `HAL_I2C_Mem_Read()` 函数来进行 I2C 通讯。`BQ40Z50_Init()` 函数用于初始化 BQ40Z50 芯片。`BQ40Z50_Read()` 函数用于从 BQ40Z50 芯片中读取数据,`BQ40Z50_Write()` 函数用于向 BQ40Z50 芯片中写入数据。 需要注意的是,以上代码仅供参考。实际使用时,需要根据具体的硬件和软件环境进行相应的修改。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值