系列文章目录
1.元件基础
2.电路设计
3.PCB设计
4.元件焊接
5.板子调试
6.程序设计
7.算法学习
8.编写exe
9.检测标准
10.项目举例
11.职业规划
文章目录
- 前言
- 一、模拟IIC
- 二、BQ27441初始化配置程序
- 三、学习资料
前言
送给大学毕业后找不到奋斗方向的你(每周不定时更新)
中国计算机技术职业资格网
上海市工程系列计算机专业中级专业技术职务任职资格评审
BQ27441采用I2C进行设置。 寄存器地址为0xAA(补齐八位后)。
初始化配置至少需要配置:电池容量、电池能量、截至电压、锥度率。一般的应用配置这四个参数就可以了,需要注意在库仑计上电后,需要延时才能配置成功,延时时间不够,配置不成功。
初始化配置完成后,即可进行电压、SOC、Current的读取。
当电流低于sleep电流后,芯片的默认设置会自动进入sleep模式。
该程序已经在项目验证,采集精度很高。使用下面两个函数即可
一、模拟IIC
可使用模拟也可使用硬件IIC,代码自行移植
#ifndef __MY_IIC_H
#define __MY_IIC_H
#include "main.h"
/* IO操作 */
#define IIC_SCL(x) do{ x ? \
HAL_GPIO_WritePin(My_IIC_SCL_GPIO_Port,My_IIC_SCL_Pin, GPIO_PIN_SET):\
HAL_GPIO_WritePin(My_IIC_SCL_GPIO_Port,My_IIC_SCL_Pin, GPIO_PIN_RESET);\
}while(0) /* SCL */
#define IIC_SDA(x) do{ x ? \
HAL_GPIO_WritePin(My_IIC_SDA_GPIO_Port, My_IIC_SDA_Pin, GPIO_PIN_SET):\
HAL_GPIO_WritePin(My_IIC_SDA_GPIO_Port, My_IIC_SDA_Pin, GPIO_PIN_RESET);\
}while(0) /* SDA */
/* 读取SDA */
#define IIC_READ_SDA HAL_GPIO_ReadPin(My_IIC_SDA_GPIO_Port, My_IIC_SDA_Pin)
/* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1),
也可以读取外部信号的高低电平,SDA外部必须接上拉电阻 */
void iic_init(void);
static void iic_delay(void);
void iic_start(void);
void iic_stop(void);
void iic_send_byte(uint8_t data);
uint8_t iic_read_byte(uint8_t ack);
uint8_t iic_wait_ack(void);
void iic_ack(void);
void iic_nack(void);
int16_t i2c_mt6701_get_value(void);
#endif
#include "MY_IIC.h"
/**
* @brief 初始化IIC
* @param 无
* @retval 无
*/
void iic_init(void)
{
iic_stop(); /* 停止总线上所有设备 */
}
/**
* @brief IIC延时函数,用于控制IIC读写速度
* @param 无
* @retval 无
*/
static void iic_delay(void)
{
for(int i=0;i<100;i++)
{
for(int j=0;j<100;j++)
{
}
}
}
/**
* @brief 产生IIC起始信号
* @param 无
* @retval 无
*/
void iic_start(void)
{
IIC_SDA(1);
IIC_SCL(1);
iic_delay();
IIC_SDA(0); /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
iic_delay();
IIC_SCL(0); /* 钳住I2C总线,准备发送或接收数据 */
iic_delay();
}
/**
* @brief 产生IIC停止信号
* @param 无
* @retval 无
*/
void iic_stop(void)
{
IIC_SDA(0); /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
iic_delay();
IIC_SCL(1);
iic_delay();
IIC_SDA(1); /* 发送I2C总线结束信号 */
iic_delay();
}
/**
* @brief IIC发送一个字节
* @param data: 要发送的数据
* @retval 无
*/
void iic_send_byte(uint8_t data)
{
uint8_t t;
for (t = 0; t < 8; t++)
{
IIC_SDA((data & 0x80) >> 7); /* 高位先发送 */
iic_delay();
IIC_SCL(1);
iic_delay();
IIC_SCL(0);
data <<= 1; /* 左移1位,用于下一次发送 */
}
IIC_SDA(1); /* 发送完成, 主机释放SDA线 */
}
/**
* @brief IIC读取一个字节
* @param ack: ack=1时,发送ack; ack=0时,发送nack
* @retval 接收到的数据
*/
uint8_t iic_read_byte(uint8_t ack)
{
uint8_t i, receive = 0;
for (i = 0; i < 8; i++ ) /* 接收1个字节数据 */
{
receive <<= 1; /* 高位先输出,所以先收到的数据位要左移 */
IIC_SCL(1);
iic_delay();
if (IIC_READ_SDA)
{
receive++;
}
IIC_SCL(0);
iic_delay();
}
if (!ack)
{
iic_nack(); /* 发送nACK */
}
else
{
iic_ack(); /* 发送ACK */
}
return receive;
}
/**
* @brief 等待应答信号到来
* @param 无
* @retval 1,接收应答失败
* 0,接收应答成功
*/
uint8_t iic_wait_ack(void)
{
uint8_t waittime = 0;
uint8_t rack = 0;
IIC_SDA(1); /* 主机释放SDA线(此时外部器件可以拉低SDA线) */
iic_delay();
IIC_SCL(1); /* SCL=1, 此时从机可以返回ACK */
iic_delay();
while (IIC_READ_SDA) /* 等待应答 */
{
waittime++;
if (waittime > 250)
{
iic_stop();
rack = 1;
break;
}
}
IIC_SCL(0); /* SCL=0, 结束ACK检查 */
iic_delay();
return rack;
}
/**
* @brief 产生ACK应答
* @param 无
* @retval 无
*/
void iic_ack(void)
{
IIC_SDA(0); /* SCL 0 -> 1 时 SDA = 0,表示应答 */
iic_delay();
IIC_SCL(1); /* 产生一个时钟 */
iic_delay();
IIC_SCL(0);
iic_delay();
IIC_SDA(1); /* 主机释放SDA线 */
iic_delay();
}
/**
* @brief 不产生ACK应答
* @param 无
* @retval 无
*/
void iic_nack(void)
{
IIC_SDA(1); /* SCL 0 -> 1 时 SDA = 1,表示不应答 */
iic_delay();
IIC_SCL(1); /* 产生一个时钟 */
iic_delay();
IIC_SCL(0);
iic_delay();
}
int16_t i2c_mt6701_get_value(void)
{
uint8_t temp[2];
int16_t VALUE=0;
iic_start();//产生IIC起始信号
iic_send_byte(0x0C);//MT6701 的I2C从机地址(写)
iic_wait_ack();//等待应答信号到来
iic_send_byte(0x03);//MT6701 的03寄存器
iic_wait_ack();//等待应答信号到来
iic_start();//产生IIC起始信号
iic_send_byte(0x0D);//MT6701 的I2C从机地址(读)
iic_wait_ack();//等待应答信号到来
temp[0] = iic_read_byte(0);//IIC读取一个字节h,NACK
iic_stop();//产生IIC停止信号
iic_start();//产生IIC起始信号
iic_send_byte(0x0C);//MT6701 的I2C从机地址(写)
iic_wait_ack();//等待应答信号到来
iic_send_byte(0x04);//MT6701 的04寄存器
iic_wait_ack();//等待应答信号到来
iic_start();//产生IIC起始信号
iic_send_byte(0x0D);//MT6701 的I2C从机地址(读)
iic_wait_ack();//等待应答信号到来
temp[1] = iic_read_byte(0);//IIC读取一个字节h,NACK
iic_stop();//产生IIC停止信号
VALUE = ((int16_t)temp[0] << 6) | (temp[1] >> 2);
return VALUE;
}
二、BQ27441初始化配置程序
bq27441_driver.c
#include "bq27441_driver.h"
#include "common.h"
#include "i2c.h"
const uint16_t terminatevoltage ={0x0C80}; //terminate voltage=3000mV,system shutdown voltage , 系统的正常工作电压
//
const uint16_t loadselect ={0x81}; //load select/load loadselectmode; 0x81 power-mode 0x01 current mode, normally use 0x81 ,if design capacity > 8500mAh change to 0x01
#define BATTERY_3200MAH
uint32_t Frack_Num;
/**************************************************************************************
**************************************************************************************/
#ifdef BATTERY_3200MAH
//3200mAH
unsigned short const Designcapacity={0x0C80}; //Design capacity=2500mAh 这个值随着电池的使用会变化
unsigned short const DesignEnergy={0x2E40}; //Design Energy=2500*3.8mWh; Design Energy=Design capacity*3.7 for 4.2V battery,Design Energy=Design capacity*3.8 for 4.35V battery,
#define FCC_SIZE 950
//220 充电
const uint16_t Taperrate ={0x0140}; //Taper rate=250,taper rate=Design Capacity*10/taper current mA;(2500*10/220 = 125) a little higher than charger taper current(~>20mA)
//Taperrate 是一个充电截止判定的量
//subclass 81
//放电电流 大于62mA 2500*10 / 62.5ma = 400
const uint16_t Dsgcurrentthreshold ={0x190}; // 50000/167=299mA, Dsg current threshold(num)=500, Dsg current threshold(mAh)=Design capacity*10/Dsg current threshold(num)=80mA
//充电电流一定大于这个电流 100mA 2500*10/100 = 250
const uint16_t Chgcurrentthreshold ={0xfa}; //Chg current threshold(num)=500, Chg current threshold(mAh)=Design capacity*10/Chg current threshold(num)=80mA,must smaller than charger taper current
//进入低功耗电流 2500 * 10 / 50ma = 500
const uint16_t Quitcurrent ={0x01f4}; //{0x03E8}; //Quit current threshold(num)=1000,Quit current threshold(mAh)=Design capacity*10/Quit current threshold(num)=40mA
#endif
/**************************************************************************************
**************************************************************************************/
#ifdef BATTERY_3200MAH
const uint16_t Qmax ={0x4000};
const uint16_t Ra[] ={0x66, 0x66, 0x63, 0x6b, 0x48, 0x3b, 0x3e, 0x3f, 0x35, 0x2f, 0x3c, 0x46, 0x8c, 0x171, 0x24c};
//const uint16_t Ra[] ={0x34, 0x34, 0x32, 0x36, 0x2d, 0x32, 0x47, 0x52, 0x50, 0x4b, 0x57, 0x52, 0x72, 0x108, 0x1a4};
#endif
#ifdef BATTERY_2000MAH
uint16_t volt,soc,fcc ;
int16_t avgCur;
/**************************************************************************************
**************************************************************************************/
static uint32_t bq_cmdWrite(uint8_t subaddr, uint8_t cmd);
static uint32_t bq_read(uint8_t *pBuf, uint8_t addr, uint8_t len);
static uint32_t bq_MemoryWrite(uint8_t subaddr, uint16_t data );
static uint8_t GetCheckSum(uint8_t addr);
static void bq_Read_Ta_and_Qmax(void);
static void bq_fullReset(void);
static void bq_CONFIG_subclass82(void);
static void bq_CONFIG_subclass81(void);
static void bq_CONFIG_subclass89(void);
static uint32_t bq_ConfigRead(void);
static uint32_t bq_Rdarg(uint16_t *volt, int16_t *avgCur, uint16_t *soc, uint16_t *fcc);
uint16_t bq_ITPOR(void);
/**************************************************************************************
**************************************************************************************/
/**************************************************************************************
**************************************************************************************/
/********************************************************
向subaddr 这个地址写入cmd这个指令(写单个指令)
********************************************************/
uint32_t bq_cmdWrite(uint8_t subaddr, uint8_t cmd)
{
return HAL_I2C_Mem_Write(&hi2c1,BQ2744_ADDRESS,subaddr,I2C_MEMADD_SIZE_8BIT,&cmd,1,0xff);
}
/*************************************
*************************************/
uint32_t bq_read(uint8_t *pBuf, uint8_t addr, uint8_t len)
{
return HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, addr, len, pBuf, len, 0xfff);
}
/********************************************************
*********************************************************/
uint32_t bq_MemoryWrite(uint8_t subaddr, uint16_t data )
{
uint8_t Mdata=(data>>8);
uint8_t Ldata=(data&0xFF);
HAL_I2C_Mem_Write(&hi2c1,BQ2744_ADDRESS,subaddr,I2C_MEMADD_SIZE_8BIT,&Mdata,1,0xff);
return HAL_I2C_Mem_Write(&hi2c1,BQ2744_ADDRESS,subaddr+1,I2C_MEMADD_SIZE_8BIT,&Ldata,1,0xff);
}
/********************************************************
*********************************************************/
uint8_t GetCheckSum(uint8_t addr)
{
uint8_t checksum = 0, i;
uint8_t rtBuf[2];
for (i = 0; i < 32; i++)
{
rtBuf[0] = 0;
bq_read(rtBuf, addr, 1);
checksum = checksum + rtBuf[0];
addr++;
}
checksum = 0xFF - checksum;
return checksum;
}
/********************************************************
*********************************************************/
void bq_Read_Ta_and_Qmax(void)
{
unsigned short qmax=0x00;
uint8_t Ra_table[32]= {0x0A};
unsigned short cap=0x00;
uint8_t buf[1];
uint8_t tbuf[2];
uint8_t i;
tbuf[0]=0;
tbuf[1]=0;
Ra_table[31]='\r';
Ra_table[30]='\n';
bq_cmdWrite(0x00,0x00); //Places the device in UNSEALED access mode.
bq_cmdWrite(0x01,0x80);
bq_cmdWrite(0x00,0x00);
bq_cmdWrite(0x01,0x80);
bq_cmdWrite(0x61,0x00); // enables BlockData() to access to RAM.
bq_cmdWrite(0x3e,0x52); //选择0x52区域 //access the state subclass (decimal 82, 0x52 hex)
bq_cmdWrite(0x3f,0x00); //use offset 0x00 for offsets 0 to 31
bq_read(buf, 0x40, 2);
qmax = (buf[0] << 8) | buf[1]; //高低位交换
bq_read(buf, 0x4A, 2);
cap = (buf[0] << 8) | buf[1]; //高低位交换
bq_cmdWrite(0x3e,0x59);//选择0x59区域
bq_cmdWrite(0x3f,0x00);
for(i=0; i<30; i++)
{
bq_read(buf, 0x40+i, 1);
Ra_table[i] = buf[0]; //高低位交换
}
HAL_UART_Transmit(&huart2,Ra_table,32,0xff);
Frack_Num++;
tbuf[0]=Frack_Num>>24;
HAL_UART_Transmit(&huart2,tbuf,1,0xff);
tbuf[0]=((Frack_Num>>16)&0xFF);
HAL_UART_Transmit(&huart2,tbuf,1,0xff);
tbuf[0]=((Frack_Num>>8)&0xFF);
HAL_UART_Transmit(&huart2,tbuf,1,0xff);
tbuf[0]=(Frack_Num&0xFF);
HAL_UART_Transmit(&huart2,tbuf,1,0xff);
// bq_cmdWrite(0x3e,0x40);//选择0x59区域
// bq_cmdWrite(0x3f,0x00);
//
//
// bq_read(buf, 0x40, 1);
// HAL_UART_Transmit(&huart2,buf,1,0xff);
// bq_read(tbuf, 0x41, 1);
// HAL_UART_Transmit(&huart2,tbuf,1,0xff);
}
/********************************************************
*********************************************************/
void bq_fullReset(void)
{
if (bq_cmdWrite(0x00,0x00) || bq_cmdWrite(0x01,0x80)) //Places the device in UNSEALED access mode.
{
return ;
}
if (bq_cmdWrite(0x00,0x00) || bq_cmdWrite(0x01,0x80))
{
return ;
}
if (bq_cmdWrite(0x00,0x41) || bq_cmdWrite(0x01,0x00)) //Performs a full device reset.
{
return;
}
}
/********************************************************
*********************************************************/
void bq_CONFIG_subclass82(void)
{
uint8_t checksum = 0;
bq_cmdWrite(0x3e, 0x52); //选择0x52区域 //access the state subclass (decimal 82, 0x52 hex)
bq_cmdWrite(0x3f, 0x00); //use offset 0x00 for offsets 0 to 31
bq_MemoryWrite(0x40, Qmax);
bq_MemoryWrite(0x50, terminatevoltage); //terminatevoltage 截止电压(系统能够正常运行的最低电压)
bq_cmdWrite(0x45, loadselect);
bq_MemoryWrite(0x4A, Designcapacity); //电池容量 mAh
bq_MemoryWrite(0x4C, DesignEnergy); //mWh
bq_MemoryWrite(0x5B, Taperrate);
checksum = GetCheckSum(0x40);
bq_cmdWrite(0x60, checksum); //0xba checksum
}
void bq_CONFIG_subclass81(void) //充放电阈值设置
{
uint8_t checksum = 0;
bq_cmdWrite(0x3e, 0x51); //选择0x51区域
bq_cmdWrite(0x3f, 0x00);
bq_MemoryWrite(0x40, Dsgcurrentthreshold); //放电电流
bq_MemoryWrite(0x42, Chgcurrentthreshold); //充电电流,充电电流的判断标准
bq_MemoryWrite(0x44, Quitcurrent); //静态电源
checksum = GetCheckSum(0x40);
bq_cmdWrite(0x60, checksum); //0x5e
}
void bq_CONFIG_subclass89(void)//内阻表设置
{
uint8_t checksum = 0, i = 0;
bq_cmdWrite(0x3e, 0x59); //选择0x59区域
bq_cmdWrite(0x3f, 0x00);
for (i = 0; i < 15; i++) {
bq_MemoryWrite(0x40 + i * 2, Ra[i]);
}
checksum = GetCheckSum(0x40);
bq_cmdWrite(0x60, checksum);
}
/********************************************************
返回0, 进入配置模式并退出成功, 返回1, 进入配置失败, 返回0xFE, 超时
*********************************************************/
uint32_t bq_Config(void)
{
uint8_t rtBuf[2];
uint16_t value;
uint32_t result;
static uint32_t m_tryCnt = 0;
if (m_tryCnt++ > 10)
{
m_tryCnt = 0;
return 0xFE;
}
if (bq_cmdWrite(0x00, 0x00) || bq_cmdWrite(0x01, 0x80)) //Places the device in UNSEALED access mode.
{
cmsLog_error("entry unsealed err\n");
return 1;
}
if (bq_cmdWrite(0x00, 0x00) || bq_cmdWrite(0x01, 0x80))
{
cmsLog_error("entry unsealed err1\n");
return 1;
}
if (bq_cmdWrite(0x00, 0x13) || bq_cmdWrite(0x01, 0x00))
{
cmsLog_error("entry config mode err\n");
return 1;
}
HAL_Delay(1);
result = bq_read(rtBuf, bq27421CMD_FLAG_LSB, 2);
if (result == 0)
{
value = (rtBuf[1] << 8) | rtBuf[0];
if (!(value & 0x10))
{
cmsLog_error("upmode=0\n");
bq_cmdWrite(0x61,0x00); // enables BlockData() to access to RAM.
bq_CONFIG_subclass82();
// bq_CONFIG_subclass81();
//
// bq_CONFIG_subclass89();
bq_cmdWrite(0x00,0x42); //软复位 退出配置模式
bq_cmdWrite(0x01,0x00);
bq_cmdWrite(0x00,0x00);
bq_cmdWrite(0x01,0x00);
m_tryCnt = 0;
}
else
{
cmsLog_error("upmode=1\n");
bq_cmdWrite(0x61,0x00); // enables BlockData() to access to RAM.
bq_CONFIG_subclass82();
// bq_CONFIG_subclass81();
//
// bq_CONFIG_subclass89();
bq_cmdWrite(0x00,0x42); //软复位 退出配置模式
bq_cmdWrite(0x01,0x00);
bq_cmdWrite(0x00,0x00);
bq_cmdWrite(0x01,0x00);
result = 1;
cmsLog_error("value=0x%x\n", value);
}
}
cmsLog_debug(" %s\n", result == 0 ? "Ok" : "Fail");
return result;
}
/********************************************************
返回0, 配置成功, 返回1, 配置失败 返回其他, 配置超时
*********************************************************/
uint32_t bq_ConfigRead(void)
{
uint8_t rtBuf[2] = {0};
uint16_t value;
uint32_t result;
result = bq_read(rtBuf, bq27421CMD_FLAG_LSB, 2);
if (result != 0)
{
return 0xFF;
}
if (result == 0)
{
value = (rtBuf[1] << 8) | rtBuf[0];
if (value & 0x10)
{
result = 1;
}
else
{
bq_cmdWrite(0x00,0x20);
bq_cmdWrite(0x01,0x00);
}
}
return result;
}
/********************************************************
读参数
********************************************************/
uint32_t bq_Rdarg(uint16_t *volt, int16_t *avgCur, uint16_t *soc, uint16_t *fcc)
{
uint8_t lrtBuf[1];
uint8_t mrtBuf[1];
uint16_t value;
uint16_t ret1;
uint16_t ret2;
ret1=HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, bq27421CMD_VOLT_LSB, 1, lrtBuf, 1, 0xfff); //volt 为电压
ret2=HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, bq27421CMD_VOLT_MSB, 1, mrtBuf, 1, 0xfff);
if(0 == ret1 && ret2 == 0)
{
value = (mrtBuf[0] << 8) |lrtBuf[0];
*volt = value;
}
else
{
return 0xF1;
}
ret1=HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, bq27421CMD_AI_LSB, 1, lrtBuf, 1, 0xfff); //avgCur 为平均电流
ret2=HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, bq27421CMD_AI_MSB, 1, mrtBuf, 1, 0xfff);
if(0 == ret1 && ret2 == 0)
{
value = (mrtBuf[0] << 8) |lrtBuf[0];
*avgCur = value;
}
else
{
return 0xF1;
}
ret1=HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, bq27421CMD_SOC_LSB, 1, lrtBuf, 1, 0xfff); //soc 为电量百份比
ret2=HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, bq27421CMD_SOC_MSB, 1, mrtBuf, 1, 0xfff);
if(0 == ret1 && ret2 == 0)
{
value = (mrtBuf[0] << 8) |lrtBuf[0];
*soc = value;
}
else
{
return 0xF1;
}
ret1=HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, bq27421CMD_FCC_LSB, 1, lrtBuf, 1, 0xfff); //FCC为充电电量
ret2=HAL_I2C_Mem_Read(&hi2c1, BQ2744_ADDRESS, bq27421CMD_FCC_MSB, 1, mrtBuf, 1, 0xfff);
if(0 == ret1 && ret2 == 0)
{
value = (mrtBuf[0] << 8) |lrtBuf[0];
*fcc = value;
}
else
{
return 0xF1;
}
return ret1;
}
/********************************************************
返回1 需要配置 返回0 已配置过 返回其他值出错
********************************************************/
uint16_t bq_ITPOR(void)
{
uint8_t rtBuf[2] = {0};
uint32_t ret;
ret = bq_read(rtBuf, bq27421CMD_FLAG_LSB, 1);
if (ret != 0)
{
return 0xFF;
}
if (rtBuf[0] & 0x20)
{
return 1;
}
return 0xAA;
}
uint8_t BQ25895_STATE(){
bq_Rdarg(&volt, &avgCur, &soc, &fcc);
if((avgCur >20)&&HAL_GPIO_ReadPin(TYPEC_DEC_GPIO_Port,TYPEC_DEC_Pin)&&soc<91){
return BQ_Charging;
}else if(soc>90){
return BQ_Charge_Done;
}else if(avgCur<(-150)){
return Rod_Charging;
}
return 1;
}
uint8_t getBoxBattery(void)
{
uint16_t volt,soc,fcc ;
int16_t avgCur;
if(bq_ITPOR() !=0xAA )
{
HAL_Delay(500);
bq_Config();
if(bq_ConfigRead() != 0)
return 0xFE;
}
bq_Rdarg(&volt, &avgCur, &soc, &fcc);
return soc&0xFF;
}
uint8_t Batter_Gauge_Test(){
uint8_t data;
uint16_t volt,soc,fcc ;
int16_t avgCur;
volt=bq_ITPOR();
if(volt == 1 )
{
bq_Config();
if(bq_ConfigRead() != 0)
return 2;
}
bq_Read_Ta_and_Qmax();
bq_Rdarg(&volt, &avgCur, &soc, &fcc);
return 1;
}
/********************************************************
返回0, 进入配置模式并退出成功, 返回1, 进入配置失败, 返回0xFE, 超时
*********************************************************/
uint32_t bq_Config_nww(void)
{
uint8_t rtBuf[2];
uint16_t value;
uint32_t result;
static uint8_t m_tryCnt = 0;
if (m_tryCnt++ > 10)
{
m_tryCnt = 0;
return 0xFE;
}
if (bq_cmdWrite(0x00, 0x00) || bq_cmdWrite(0x01, 0x80)) //Places the device in UNSEALED access mode.
{
return 1;
}
if (bq_cmdWrite(0x00, 0x00) || bq_cmdWrite(0x01, 0x80))
{
return 2;
}
if (bq_cmdWrite(0x00, 0x13) || bq_cmdWrite(0x01, 0x00))
{
return 3;
}
HAL_Delay(1);
result=1;
while(result){
result = bq_read(rtBuf, bq27421CMD_FLAG_LSB, 2);
if (result == 0)
{
value = (rtBuf[1] << 8) | rtBuf[0];
result=(value & 0x10);
}
}
bq_cmdWrite(0x61,0x00); // enables BlockData() to access to RAM.
bq_CONFIG_subclass52();
return result;
}
void bq27441_init(void){
if(bq_ITPOR() == 1){
cmsLog_error("need_config\n");
HAL_Delay(1100);
bq_Config();
HAL_Delay(10);
bq_ConfigRead();
// bq_fullReset();
}
else
cmsLog_error("noconfig=0\n");
}
bq27441_driver.h
#ifndef __BQ27441_DRIVER_H
#define __BQ27441_DRIVER_H
#include "stm32f0xx.h"
#include <stdio.h>
/***********************************************/
#define COLUMB_FLAG_VOLT (1 << 0)
#define COLUMB_FLAG_CURR (1 << 1)
#define COLUMB_FLAG_SOC (1 << 2)
#define COLUMB_FLAG_FCC (1 << 3)
/***********************************************/
#define SLAVE_I2C_GENERIC_RETRY_MAX 5
//#define BQ2744_ADDRESS 0x55
#define BQ2744_ADDRESS 0xAA
/***********************************************/
#define bq27421CMD_CNTL_LSB 0x00
#define bq27421CMD_CNTL_MSB 0x01
#define bq27421CMD_TEMP_LSB 0x02
#define bq27421CMD_TEMP_MSB 0x03
#define bq27421CMD_VOLT_LSB 0x04
#define bq27421CMD_VOLT_MSB 0x05
#define bq27421CMD_FLAG_LSB 0x06
#define bq27421CMD_FLAG_MSB 0x07
#define bq27421CMD_NAC_LSB 0x08
#define bq27421CMD_NAC_MSB 0x09
#define bq27421CMD_FAC_LSB 0x0a
#define bq27421CMD_FAC_MSB 0x0b
#define bq27421CMD_RM_LSB 0x0c
#define bq27421CMD_RM_MSB 0x0d
#define bq27421CMD_FCC_LSB 0x0e
#define bq27421CMD_FCC_MSB 0x0f
#define bq27421CMD_AI_LSB 0x10
#define bq27421CMD_AI_MSB 0x11
#define bq27421CMD_SI_LSB 0x12
#define bq27421CMD_SI_MSB 0x13
#define bq27421CMD_MLI_LSB 0x14
#define bq27421CMD_MLI_MSB 0x15
#define bq27421CMD_AP_LSB 0x18
#define bq27421CMD_AP_MSB 0x19
#define bq27421CMD_SOC_LSB 0x1c
#define bq27421CMD_SOC_MSB 0x1d
#define bq27421CMD_ITEMP_LSB 0x1e
#define bq27421CMD_ITEMP_MSB 0x1f
#define bq27421CMD_SOH_LSB 0x20
#define bq27421CMD_SOH_MSB 0x21
/**************************************************************************************
**************************************************************************************/
typedef struct __BQ27XX_Drive{
void (*init)(void);
void (*uninit)(void);
uint32_t (*itpor)(void);
void (*fullreset)(void);
uint32_t (*updategauge)(uint16_t *volt, uint16_t *avgCur, uint16_t *soc, uint16_t *fcc);
uint32_t (*config)(void);
uint32_t (*confirmconfig)(void);
void (*showtaandmax)(void);
}BQ27XX_INTERFACE_T;
enum{
Rod_Charging=1,
BQ_Charge_Done,
BQ_Charging,
};
extern const BQ27XX_INTERFACE_T g_pfBQ27xxFunction[];
uint32_t bq_Config(void);
uint8_t BQ25895_STATE();
uint8_t Batter_Gauge_Test();
uint8_t getBoxBattery(void);
void bq27441_init(void);
#endif
common.c
#include "common.h"
#include "timer_driver.h"
static uint32_t m_EnterCnt = 0;
/**************************************************************************************
* FunctionName : Task_EnterCritical()
* Description :
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
void Task_EnterCritical(void)
{
m_EnterCnt++;
__set_PRIMASK(1);
}
/**************************************************************************************
* FunctionName : Task_ExitCritical()
* Description :
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
void Task_ExitCritical(void)
{
m_EnterCnt--;
if (m_EnterCnt == 0)
{
__set_PRIMASK(0);
}
}
/**************************************************************************************
* FunctionName : Task_GetCurrentTime()
* Description :
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
uint32_t Task_GetCurrentTime(void)
{
uint32_t value;
Task_EnterCritical();
/*10ms 增加1*/
value = TIM2_GetClock();
Task_ExitCritical();
return value;
}
common.h
#ifndef __COMMON_H__
#define __COMMON_H__
#include "stm32f0xx.h"
#include "stm32f0xx_hal.h"
//#include "SysTick.h"
#include <stdio.h>
#include "main.h"
//#include "dwtdelay.h"
/***********************************************
***********************************************/
#define cmsLog_error(format,...) printf("%s(%d)|" format"\r",__FUNCTION__,__LINE__,##__VA_ARGS__)
#if 01
#define cmsLog_debug(format,...) printf("%s|" format"\r",__FUNCTION__,##__VA_ARGS__)
#else
#define cmsLog_debug(format,...)
#endif
#define SYSTEM_TICK_HZ 5 /*5ms*/
/***********************************************
***********************************************/
#define PROCESS_TIME_SYNC(nowT, sysT, nextT) \
do{\
if ((int32_t)((int32_t)(sysT) - (int32_t)(nowT)) < 0 )\
{\
return;\
}\
(nowT) = (sysT) + (nextT)/SYSTEM_TICK_HZ;\
}while(0)
/***********************************************
***********************************************/
enum
{
SYS_IDLE = 0, /*系统停机状态*/
SYS_METER , /*配置库仑计*/
SYS_STAR , /*系统启动,准备显示开机画面*/
SYS_CHARG , /*系统充电启动,准备显示开机画面*/
SYS_VOLTLOW , /*系统电压低5%*/
SYS_CLOSE ,
SYS_MAX,
};
/***********************************************
***********************************************/
void Task_EnterCritical(void);
void Task_ExitCritical(void);
void Task_EnterSleep(void);
uint32_t Task_GetCurrentTime(void);
void DelayFunction_Init(void);
void Delay_us(__IO uint32_t nTime);
/***********************************************
***********************************************/
#endif
三、学习资料
1、TI单节电量计基本介绍及常见问题解答
2、TI电量计应用指导
3、TI电量计应用培训视频
4、从零开始快速让电量计工作起来
5、TI电量计–配置及训练流程
6、TI电量计–循环学习产生量产文件及易错分析
7、关于Qmax cell 的填写