BQ27441初始化配置程序,电压、SOC等参数读取程序

news2024/9/22 19:46:30

系列文章目录

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 的填写

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2047080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法打卡 Day23(二叉树)-二叉搜索树的最小绝对差 + 二叉搜索树中的众数 + 二叉树的最近公共祖先

文章目录 Leetcode 530-二叉搜索树的最小绝对差题目描述解题思路 Leetcode 501-二叉搜索树中的众数题目描述解题思路 Leetcode 236-二叉树的最近公共祖先题目描述解题思路 Leetcode 530-二叉搜索树的最小绝对差 题目描述 https://leetcode.cn/problems/minimum-absolute-diff…

萌啦数据使用多久,萌啦数据价格表2024

在数字化浪潮汹涌的今天&#xff0c;数据已成为企业决策与业务增长的核心驱动力。在众多数据分析工具中&#xff0c;萌啦数据凭借其强大的数据处理能力、直观的数据可视化效果以及灵活的数据分析模型&#xff0c;赢得了众多企业和个人的青睐。那么&#xff0c;关于“萌啦数据使…

C++ | Leetcode C++题解之第341题扁平化嵌套列表迭代器

题目&#xff1a; 题解&#xff1a; class NestedIterator { private:vector<int> vals;vector<int>::iterator cur;void dfs(const vector<NestedInteger> &nestedList) {for (auto &nest : nestedList) {if (nest.isInteger()) {vals.push_back(n…

苍穹外卖项目DAY05

苍穹外卖项目DAY05 1、店铺营业状态设置 1.1、Redis入门 Redis简介 Redis是一个基于内存的key-value结构数据库 基于内存存储&#xff0c;读写性能高适合存储热点数据&#xff08;热点商品、咨询、新闻&#xff09;企业应用广泛 中文网&#xff1a;https://www.redis.net…

FSOP,glibc-2.23攻击IO_list_all

文章目录 FSOP介绍&#xff1a;FOSP链执行流程&#xff1a;源码调试过程 FSOP 介绍&#xff1a; FSOP 是 File Stream Oriented Programming 的缩写&#xff0c;根据前面对 FILE 的介绍得知进程内所有的 _ IO_FILE 结构会使用 _ chain 域相互连接形成一个链表&#xff0c;这个…

景联文科技:一文详解如何构建高质量SFT数据

在图像处理和计算机视觉领域中&#xff0c;将一张图像转化为可用于训练机器学习模型的数据是一项复杂而重要的任务。SFT&#xff08;Supervised Fine-Tuning&#xff0c;监督微调&#xff09;是一种常见的深度学习策略&#xff0c;在这一过程中发挥着核心作用。 SFT是指在一个预…

【云备份】服务端模块-热点管理

文章目录 0.回顾extern1.介绍2.实现思想3.代码测试代码 0.回顾extern extern cloudBackup::DataManager *_dataManager extern 关键字用于声明一个全局变量或对象&#xff0c;而不定义它。这意味着 _dataManager 是一个指向 cloudBackup::DataManager 类型的指针&#xff0c;但…

外部接入tensorboard和Jupyter Notebook

本地端打开服务器端jupyter Notebook 1:服务器端在目标文件夹下输入jupyter notebook --no-browser --port8888&#xff08;留意下token&#xff09; 2&#xff1a;本地端打开git 的bash窗口输入ssh -L 8888:localhost:8888 warren10.12.14.187 warren为用户名&#xff0c;10…

get 请求获取不到参数,但是post参数可以获取到

一&#xff1a;测试代码时发现&#xff0c;get请求一直获取不到参数。最终原因如下&#xff0c;nginx配置中需求有下面的配置 $args&#xff1a;代表接受到的参数

MemFire Cloud是否真的可以取代后端

近年来&#xff0c;随着前端技术的迅速发展&#xff0c;前端工程师们越来越多地开始思考一个问题&#xff1a;“我还能不能不依赖后端&#xff1f;” 这种想法并非空穴来风&#xff0c;尤其是随着像MemFire Cloud这样的工具出现&#xff0c;它不仅能让开发者在没有后端的情况下…

2. springboot集成kafka入门使用教程

项目demo地址 : https://mp.weixin.qq.com/s?__bizMzkzODQyNzE3 1. 项目结构 ─src├─main│ ├─java│ │ └─org│ │ └─example│ │ │ KafkaApplication.java│ │ ││ │ └─demo│ │ KafkaConsume…

跟李沐学AI:目标检测、锚框

边缘框 用于表示物体的位置&#xff0c;一个边缘框通过四个数字定义&#xff1a;(坐上x, 左上y, 右下x, 右下y)或&#xff08;左上x, 左上y, 宽, 高&#xff09; 通常物体检测或目标检测的数据集比图片分类的数据集小很多&#xff0c;因为物体检测数据集标注成本高很多。 目…

音视频相关知识

H.264编码格式 音频 PCM就是要把声音从模拟信号转换成数字信号的一种技术&#xff0c;他的原理简单地说就是利用一个固定的频率对模拟信号进行采样。 pcm是无损音频音频文件格式

【Qt】QWidget的font属性

QWidget的font属性 API说明 font() 获取当前 widget 的字体信息. 返回 QFont 对象. setFont(const QFont& font) 设置当前 widget 的字体信息. 关于Qfont 属性说明 family 字体家族. ⽐如 "楷体", "宋体", "微软雅⿊" 等. pointSiz…

“面试通关秘籍:高频题目与算法整理”

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

Postman断言

目录 概述 断言工作原理 常用断言方法 Status code: Code is 200 Status code: Successful POST request Status code: Code name has string Response body: Contains string Response body: JSON value check Response body: ls equal to a string Response headers…

鸿萌数据恢复服务:SQL Server 中的 GAM、SGAM、IAM,及数据库损坏的修复方法

天津鸿萌科贸发展有限公司从事数据安全服务二十余年&#xff0c;致力于为各领域客户提供专业的数据恢复、数据备份、网络及终端数据安全等解决方案与服务。 同时&#xff0c;鸿萌是国际主流数据恢复软件(Stellar、UFS、R-Studio、ReclaiMe Pro 等)的授权代理商&#xff0c;为专…

开源的数据库增量订阅和消费的中间件——Cancl

目录 工作原理 MySQL主备复制原理 Canal 工作原理 主要功能和特点 应用场景 实验准备 安装JDK11 下载MySQL8.0 配置canal.admin 配置canal-deployer 测试数据读取 新增一台主机用做被同步的目标机器测试 官方地址&#xff1a;https://github.com/alibaba/canal?ta…

极狐 GitLab 依赖扫描:助力开发者管理软件供应链

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…

LeetCode.22。括号生成

题目描述&#xff1a; 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组 输入输出实例&#xff1a; 思路&#xff1a;对于这道题目我们可以用回溯法&#xff0c;创建一个函数backtrack(当前字符&#xff0c;左括…