基于stm32 BQ40Z50电池管理芯片

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

 

 

一、bq40z50 是什么?

bq40z50 1 节、2 节、3节和 4 节串联锂离子电池组管理器
1 特性
全集成 1 节、 2 节、 3 节和 4 节串联锂离子或锂聚
bq40z50 器件采用已获专利的 Impedance Track™
合物电池组管理器及保护
术,是一款基于电池组的单芯片全集成解决方案,针对
下一代已获专利的 Impedance Track™ 技术可准确
1 节、 2 节、 3 节和 4 节串联锂离子或锂聚合物电池组
测量锂离子和锂聚合物电池中的可用电量
提供电量监测、保护及认证等一些列丰富的功能。
高侧 N 通道保护场效应晶体管 (FET) 驱动
bq40z50 器件利用其集成的高性能模拟外设,测量锂
充电或者静止状态时集成的电池均衡
离子或锂聚合物电池的可用容量、电压、电流、温度和
可编程保护特性的完全阵列
其他关键参数,保留准确的数据记录,并通过 SMBus
电压
v1.1 兼容接口将这些信息报告给系统主机控制器。
电流
温度
(1)
充电终止时间
bq40z50
VQFN (32)
4.00mm x 4.00mm
– CHG/DSG FET
模拟前端 (AFE)
(1) 如需了解所有可用封装,请见数据表末尾的可订购产品附录。
精密的充电算法
日本电子与信息技术工业协会 (JEITA)
增强型充电
自适应充电
电池均衡
支持 TURBO 升压模式
支持电池跳变点 (BTP)
诊断寿命数据监视器和黑匣子记录器
发光二极管 (LED) 显示
支持 2 线制系统管理总线 (SMBus) v1.1 接口
安全散列算法 (SHA-1) 认证
紧凑封装: 32 导线四方扁平无引线 (QFN) (RSM)

二、使用步骤

1.驱动程序

代码如下(示例):

 bq40z50.c

/********************************************************
*作者:john,.feng
*时间:2023/3/30
*文件描述描述:BQ40Z50驱动程序

*芯片描述:bq40z50 1 节、2 节、3 节和 4 节串联锂离子电池组管理器

*********************************************************/
#include "bq40z50.h"
#include "delay.h"



void BQ40z50_GPIOInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    BQ40Z50_GPIO_CLK();

    GPIO_InitStructure.GPIO_Pin = BQ40Z50_GPIO_SCL_PIN | BQ40Z50_GPIO_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(BQ40Z50_GPIO_SCL_PORT, &GPIO_InitStructure);
    GPIO_Init(BQ40Z50_GPIO_SDA_PORT, &GPIO_InitStructure);

    BQ40Z50_SCL_OUT(1);
    BQ40Z50_SDA_OUT(1);
}


void SMbus_Start()
{
    SET_SDA_OUT();

    BQ40Z50_SDA_OUT(1);
    BQ40Z50_SCL_OUT(1);
    delay_us(4);
    BQ40Z50_SDA_OUT(0);

    delay_us(4);
    BQ40Z50_SCL_OUT(0);
    delay_us(4);
}

//结束
void SMbus_Stop()
{
    SET_SDA_OUT();
    BQ40Z50_SCL_OUT(0);
    BQ40Z50_SDA_OUT(0);
    delay_us(4);
    BQ40Z50_SCL_OUT(1);
    BQ40Z50_SDA_OUT(1);
    delay_us(4);
}

//发送ACK
void SMbus_ack(void)
{

    BQ40Z50_SCL_OUT(0);
    SET_SDA_OUT();
    BQ40Z50_SDA_OUT(0);
    delay_us(2);

    BQ40Z50_SCL_OUT(1);
    delay_us(2);
    BQ40Z50_SCL_OUT(0);
}

/************************************************************************
  * @name:  IIC_NAck
  * @param: none
  * @note:  不产生IIC ARC信号
  * @retval:none
  ******************************************************************************/
void SMbus_NAck(void)
{
    BQ40Z50_SCL_OUT(0);
    SET_SDA_OUT();
    BQ40Z50_SDA_OUT(1);
    delay_us(2);
    BQ40Z50_SCL_OUT(1);
    delay_us(2);
    BQ40Z50_SCL_OUT(0);
}
//发送ACK
void SMbus_Ack(uint8_t Ack)
{
    SET_SDA_OUT();
    if(Ack)
    {
        BQ40Z50_SDA_OUT(0);
    }
    else
    {
        BQ40Z50_SDA_OUT(1);
    }
    BQ40Z50_SCL_OUT(1);
    delay_us(5);
    BQ40Z50_SCL_OUT(0);
    delay_us(80);//此处要加长延时
}


// 接收ACK
uint8_t SMbus_Wait_Ack()
{
    uint16_t ucErrTime = 0;
    SET_SDA_IN();
    while(BQ40Z50_SDA_IN())
    {
        ucErrTime++;
        if(ucErrTime > 350)
        {
            SMbus_Stop();
            return 1;
        }
    }
    BQ40Z50_SCL_OUT(1);
    delay_us(5);
    BQ40Z50_SCL_OUT(0);
    delay_us(80);//此处要加长延时
    return 0;
}

static uint16_t polynomial =  263 ;// represented 1 0000 0111//
uint8_t cal_crc(uint8_t* ptr, uint8_t len)
{
    uint8_t i;
    uint8_t crc = 0;

    while(len-- != 0)
    {
        for(i = 128; i != 0; i /= 2)
        {
            if((crc & 128) != 0)
            {
                crc *= 2;
                crc ^= polynomial;
            }
            else
            {
                crc *= 2;
            }
            if((*ptr & i) != 0)
            {
                crc ^= polynomial;
            }
        }
        ptr++;
    }
    return crc;
}


//发送一个字节
void SMbus_Send_Byte(uint8_t txd)
{
    uint8_t t;
    delay_us(10);
    BQ40Z50_SCL_OUT(0);//
    SET_SDA_OUT();
    for(t = 0; t < 8; t++)
    {
        if(txd & 0x80)
        {
            BQ40Z50_SDA_OUT(1);

        }
        else
        {
            BQ40Z50_SDA_OUT(0);

        }
        txd <<= 1;
        delay_us(2);
        BQ40Z50_SCL_OUT(1);

        delay_us(5);
        BQ40Z50_SCL_OUT(0);
        delay_us(2);
    }

}


//读取一个字节
uint8_t SMbus_Read_Byte(uint8_t Ack)
{
    unsigned char i, receive = 0;

    SET_SDA_IN();
//    BQ40Z50_SCL_OUT(0);
//    I2C_SCL_0(IICx);
    //在读取第一个字节第一位的时候,延时需要超过60US,因为从设备控制数据线有个跳变的过程,这点必须注意
    for(i = 0; i < 8; i++)
    {
        receive <<= 1;
        BQ40Z50_SCL_OUT(1);
        delay_us(5);
        if(BQ40Z50_SDA_IN())receive |=  0x01;

        BQ40Z50_SCL_OUT(0);
        delay_us(7);


    }
    if(Ack)SMbus_Ack(1);//读完数据后要发送应答或者非应答信号
    else SMbus_Ack(0);
    return receive;
}


//读取寄存器当中的两个字节,单片机做主,BQ40Z50做从
uint8_t bq40z50_Get_Data(uint8_t address, uint16_t data)
{
    uint8_t CRC8_BQ40z50_DATA = 0;
//    uint16_t data = 0;
    SMbus_Start();                              //开始
    SMbus_Send_Byte(0x16);                //发送模块地址
    SMbus_Wait_Ack();
    SMbus_Send_Byte(address);    //发送寄存器地址

    SMbus_ack();
    delay_us(80);
    SMbus_Start();

    SMbus_Send_Byte(0x17);
    SMbus_Wait_Ack();

    data = SMbus_Read_Byte(1);
    data =    data | SMbus_Read_Byte(1) << 8;
    CRC8_BQ40z50_DATA = SMbus_Read_Byte(0);
    return CRC8_BQ40z50_DATA;
}



void IIC_SYS_Luminance_SET(uint8_t num)
{
    uint8_t sys_bcc_Check = 0;

    sys_bcc_Check = 0x5e ^ 0x51 ^ 0x84 ^ 0x03 ^ 0x10 ^ 0x00 ^ num;
    delay_ms(2);
    SMbus_Start();
    SMbus_Send_Byte(0x5e);
    SMbus_ack();
    SMbus_Send_Byte(0x51);
    SMbus_ack();
    SMbus_Send_Byte(0x84);
    SMbus_ack();
    SMbus_Send_Byte(0x03);
    SMbus_ack();
    SMbus_Send_Byte(0x10);
    SMbus_ack();
    SMbus_Send_Byte(0x00);
    SMbus_ack();
    SMbus_Send_Byte(num);
    SMbus_ack();
    SMbus_Send_Byte(sys_bcc_Check);
    SMbus_NAck();
    SMbus_Stop();
    delay_ms(5);
}


uint8_t CRC8_BQ40z50_DATA = 0;
static uint8_t CRC8_BQ40z50_DATA111[5] = {0};
uint16_t BQ40z50_ReadData(uint16_t ReadAddr)
{
    uint16_t data = 0, data1 = 0;

    delay_ms(5);
    CRC8_BQ40z50_DATA111[0] = 0x17;
    SMbus_Start();  //开始
    SMbus_Send_Byte(0x16);//发送模块地址
    SMbus_Wait_Ack();
    SMbus_Send_Byte(ReadAddr);    //发送寄存器地址

    SMbus_ack();
    delay_us(80);
    SMbus_Start();

    SMbus_Send_Byte(0x17);
    SMbus_Wait_Ack();

    CRC8_BQ40z50_DATA111[1] = SMbus_Read_Byte(1);
    data =  CRC8_BQ40z50_DATA111[1];

    CRC8_BQ40z50_DATA111[2] = SMbus_Read_Byte(1);
    data1 =  CRC8_BQ40z50_DATA111[2];
    CRC8_BQ40z50_DATA = SMbus_Read_Byte(0);       //读完最后一个字节后发送非应答信号

    SMbus_Stop();

    data = data | (data1 << 8);
    return data;
}

//带校验检测数据
uint16_t BQ40z50_Read_Data(uint16_t ReadAddr)
{
        uint8_t CRC_DA = 0;
    uint8_t CRC_buff[5] = {0};
    uint16_t bq40z50_dafa = 0;

    CRC_buff[0] = 0x17;

    bq40z50_dafa = BQ40z50_ReadData(ReadAddr);
    CRC_buff[1] = bq40z50_dafa;
    CRC_buff[2] = bq40z50_dafa << 8;

    CRC_DA = cal_crc(&CRC_buff[0], 3);
    if(CRC8_BQ40z50_DATA == CRC_DA)
    {
        return bq40z50_dafa;
    }
    else
    {
        SMbus_Stop();
        delay_ms(100);
        //电量
        bq40z50_dafa = BQ40z50_ReadData(ReadAddr);

        CRC_DA = cal_crc(&CRC_buff[0], 3);
        if(CRC8_BQ40z50_DATA == CRC_DA)
        {
            return bq40z50_dafa;
        }

    }
        return 1;
}


unsigned int ReceiveW(unsigned char command)   //接收一个字
{
    unsigned char temph, templ, pec;
    unsigned int b;
    unsigned char dp[5];


    dp[0] = 0x16;
    dp[1] = command;
    dp[2] = 0x17;

    SMbus_Start();
    SMbus_Send_Byte(0x16);
    if(SMbus_Wait_Ack())
    {
        SMbus_Stop();
        return(0);
    }
    else
    {
        SMbus_Send_Byte(command);
        if(SMbus_Wait_Ack())
        {
            SMbus_Stop();
            return(0);
        }
        else
        {
            SMbus_Start();
            SMbus_Send_Byte(0x17);
            if(SMbus_Wait_Ack())
            {
                SMbus_Stop();
                return(0);
            }
            else
            {
                templ = SMbus_Read_Byte(1);
//                ack();
                dp[3] = templ;
                temph = SMbus_Read_Byte(1);
//                ack();
                dp[4] = temph;
                pec = SMbus_Read_Byte(0);
//                notack();
                SMbus_Stop();
                if(pec != cal_crc(dp, 5))return(0);
                else
                {
                    b = temph;
                    b = (b * 256) | templ;
                    return(b);
                }
            }
        }
    }
}
bq40z50.h
#ifndef __BQ40Z50_H
#define __BQ40Z50_H
#include "stdint.h"
#include "stdbool.h"
#include "sys.h"   
#include "stdio.h"

#define BQ40Z50_GPIO_CLK()                                        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
#define BQ40Z50_GPIO_SCL_PORT                        GPIOB
#define BQ40Z50_GPIO_SCL_PIN                  GPIO_Pin_6
#define BQ40Z50_GPIO_SDA_PORT                        GPIOB
#define BQ40Z50_GPIO_SDA_PIN                  GPIO_Pin_7

#define SET_SDA_OUT()   {BQ40Z50_GPIO_SDA_PORT->CRL&=0X0FFFFFFF;BQ40Z50_GPIO_SDA_PORT->CRL|=(uint32_t)3<<(4*7);}  //设置为开漏输出
#define SET_SDA_IN()    {BQ40Z50_GPIO_SDA_PORT->CRL&=0X0FFFFFFF;BQ40Z50_GPIO_SDA_PORT->CRL|=(uint32_t)8<<(4*7);}  //设置为浮空输入

//SCL_OUT
#define BQ40Z50_SCL_OUT(vol)        GPIO_WriteBit(BQ40Z50_GPIO_SCL_PORT, BQ40Z50_GPIO_SCL_PIN,(vol & (1<<0 )) ? Bit_SET : Bit_RESET)         //SCL
//SDA_OUT
#define BQ40Z50_SDA_OUT(vol)        GPIO_WriteBit(BQ40Z50_GPIO_SDA_PORT, BQ40Z50_GPIO_SDA_PIN,(vol & (1<<0 )) ? Bit_SET : Bit_RESET) 
//SDA_IN 
#define BQ40Z50_SDA_IN()                  GPIO_ReadInputDataBit(BQ40Z50_GPIO_SDA_PORT, BQ40Z50_GPIO_SDA_PIN)    //SDA数据读取


#define BQ40Z50_Current_addr        0x0a          //电流                -32767 - 32768 mA
#define BQ40Z50_Voltage_addr        0x09            //电压                0-65535 mV
#define BQ40Z50_Capacity_addr        0x0d            //剩余电量        0 - 100% 
#define BQ40Z50_ARE_Curr_addr        0x0b            //平均电流   -32767 - 32768 mA

void BQ40z50_GPIOInit(void);
uint8_t cal_crc(uint8_t* ptr, uint8_t len);
uint8_t bq40z50_Get_Data(uint8_t address, uint16_t data);
void IIC_SYS_Luminance_SET(uint8_t num);
uint16_t BQ40z50_ReadData(uint16_t ReadAddr);
uint16_t BQ40z50_Read_Data(uint16_t ReadAddr);

unsigned int ReceiveW(unsigned char command) ;  //接收一个字

#endif









2.调用

代码使用如下(示例):

#define BQ40Z50_Current_addr        0x0a          //电流                -32767 - 32768 mA
#define BQ40Z50_Voltage_addr        0x09            //电压                0-65535 mV
#define BQ40Z50_Capacity_addr        0x0d            //剩余电量        0 - 100% 
#define BQ40Z50_ARE_Curr_addr        0x0b            //平均电流   -32767 - 32768 mA





//        uint16_t bq40z50_ccy = BQ40z50_Read_Data(BQ40Z50_Capacity_addr);        //剩余电量
   
//    u2_printf("BQ40Z50_Capacity = %d\r\n", bq40z50_ccy);


总结

提示:这里对文章进行总结:
 

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值