提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
一、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);
总结
提示:这里对文章进行总结: