【STM32H743模拟SMBUS获取BQ40Z50-R1电池信息】

SMBUS协议

SMBUS协议与IIC协议的区别并不是特别大,只是需要注意在设置时保证其通信速度不超过100khz就好。其它会遇到的问题TI有篇文档详细的介绍了,可以参考这篇文档,文档我放在末尾。

BQ40Z50-R1

这个网上其它博客也有详细介绍,非常感谢这些代码给的一些思路,遇到问题时参考这些文章还是给我很多调试思路的,相关的文章放在文末。

遇到的问题

无法与BQ40Z50-R1通讯成功

这个问题我觉得主要还是模拟SMBUS的时序问题,可以参考下成功的案例代码里的延时。基本我设置的延时在10us左右,通讯非常稳定,没有再出现过无法通讯的问题。

读到的高位数据为0XFF

我这里主要还是犯蠢了,在接收完数据,发送ACK信号时,没有先将SCK置低,导致SCK的高电平与接收最后一个字节的高电平连到一起了,可能把通信搞呆了,于是就一直发送0XFF。在我解决这个问题的时候,我还看到了还有人遇到这个问题的原因是SMBUS通讯速率不够,会拉低SCK电平,直到准备好之后才能置高。这个问题叫做Clock stretching,解决方案就是在拉高SCK电平值后,检测是否此时SCK电平是否为高,只有高之后再进行后面的操作,保证读取数据的正确。还有一种可能是IIC的问题,因为IIC有两种写法,如果按照其中一种写法来实现的话,是需要进行RESTART的,否则也会导致这种问题。建议遇到这个问题,看一下自己的波形,看到底是哪里出现了问题。

通信成功的波形

分别发送0X16, 0X0D,0X17查询电量信息。
电量信息波形
分别发送0X16, 0X09,0X17查询电压信息。
电压信息波形
分别发送0X16, 0X21,0X17查询模块名称。
模块信息查询

核心代码

给BQ40Z50-R1发送指令进行查询

uint8_t bq40z50_Get_Data(uint8_t address,char* buff)
{
    I2CStart();  
    I2CSendByte(0x16);//发送地址
    if(I2CWaitAck() == 1)//若设备正常,BQ40Z50此时会将SDA拉低
    {
        //未应答
        return 1;
    }
    I2CSendByte(address);    //根据不同的address读取不同的数据,例如电压、电流、剩余电量
    HAL_Delay_us(100);
    if(I2CWaitAck() == 1)//若设备正常,BQ40Z50此时会将SDA拉低
    {
        //未应答
        return 1;
    }
    I2CStart();
    
    I2CSendByte(0x17);
    if(I2CWaitAck() == 1)//若设备正常,BQ40Z50此时会将SDA拉低
    {
        //未应答
        return 1;
    }
    HAL_Delay_us(100);
    
    *(buff+0) = I2CReceiveByte();
    HAL_Delay_us(10);
    
    *(buff+1) = I2CReceiveByte();
    HAL_Delay_us(10);
    
    I2CStop();
    return 0;
}

写在最后

这个模拟的SMBUS一开始以为还是挺好调的,结果搞了两天,都是一些时序的问题,还是要细心一点调通讯协议的时候,并且调通讯协议一定要看自己的波形,不然我就很难发现一直发送0XFF的问题到底出在那里,最后希望如果大家调这个的话,能够顺利。

参考文献
[1]: https://www.cnblogs.com/ramlife/p/8319897.html
[2]: https://www.cnblogs.com/jiuliblog-2016/p/15894156.html
[3]: https://blog.csdn.net/huizzz6/article/details/108600968
[4]: https://www.ti.com.cn/cn/lit/an/slua475/slua475.pdf?ts=1603002370120&ref_url=https%253A%252F%252Fwww.ti.com.cn%252Fsitesearch%252Fcn%252Fdocs%252Funiversalsearch.tsp%253FsearchTerm%253Dsmbus

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
首先,你需要在代码中包含hal库和BQ40Z50的驱动程序。然后,你需要初始化I2C总线和BQ40Z50芯片。 在初始化BQ40Z50之前,你需要设置I2C总线的速度和地址。在初始化BQ40Z50之后,你需要设置BQ40Z50的寄存器地址和读取/写入操作。 以下是使用hal库硬件SMBus读取BQ40Z50数据的示例代码: ```c #include "stm32f4xx_hal.h" #include "bq40z50.h" I2C_HandleTypeDef hi2c1; int main(void) { /* Initialize HAL Library */ HAL_Init(); /* Initialize I2C Bus */ hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&hi2c1); /* Initialize BQ40Z50 */ bq40z50_init(&hi2c1); /* Read Battery Voltage */ float voltage = bq40z50_read_voltage(); /* Read Battery Current */ float current = bq40z50_read_current(); /* Read Battery Temperature */ float temperature = bq40z50_read_temperature(); /* Read Battery Capacity */ float capacity = bq40z50_read_capacity(); /* Read Battery Status */ uint16_t status = bq40z50_read_status(); /* Read Battery Flags */ uint16_t flags = bq40z50_read_flags(); /* Read Battery Cycle Count */ uint16_t cycle_count = bq40z50_read_cycle_count(); /* Read Battery Design Capacity */ uint16_t design_capacity = bq40z50_read_design_capacity(); /* Read Battery Full Charge Capacity */ uint16_t full_charge_capacity = bq40z50_read_full_charge_capacity(); /* Read Battery Remaining Capacity */ uint16_t remaining_capacity = bq40z50_read_remaining_capacity(); /* Read Battery Average Current */ uint16_t average_current = bq40z50_read_average_current(); /* Read Battery Time to Empty */ uint16_t time_to_empty = bq40z50_read_time_to_empty(); /* Read Battery Time to Full */ uint16_t time_to_full = bq40z50_read_time_to_full(); /* Read Battery Charging Current */ uint16_t charging_current = bq40z50_read_charging_current(); /* Read Battery Charging Voltage */ uint16_t charging_voltage = bq40z50_read_charging_voltage(); /* Read Battery Manufacturer Name */ char manufacturer_name[16] = {0}; bq40z50_read_manufacturer_name(manufacturer_name); /* Read Battery Device Name */ char device_name[16] = {0}; bq40z50_read_device_name(device_name); /* Read Battery Firmware Version */ uint16_t firmware_version = bq40z50_read_firmware_version(); /* Read Battery Serial Number */ uint16_t serial_number = bq40z50_read_serial_number(); /* Read Battery State of Charge */ uint16_t state_of_charge = bq40z50_read_state_of_charge(); /* Read Battery State of Health */ uint16_t state_of_health = bq40z50_read_state_of_health(); while (1) { /* Do Something */ } } ``` 请注意,这只是一个示例代码,你需要根据你的具体情况作出修改。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值