系列文章目录
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,NACKiic_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,NACKiic_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_2000MAHuint16_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 31bq_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 31bq_MemoryWrite(0x40, Qmax);bq_MemoryWrite(0x50, terminatevoltage); //terminatevoltage 截止电压(系统能够正常运行的最低电压) bq_cmdWrite(0x45, loadselect);bq_MemoryWrite(0x4A, Designcapacity); //电池容量 mAhbq_MemoryWrite(0x4C, DesignEnergy); //mWhbq_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(); }elsecmsLog_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 的填写