锂电池电量检测-CW2015-AT32

 CW2015驱动.c文件:

#include "cw2015.h"

extern i2c_handle_type hi2c1;

unsigned char CHARGE = 0; //用于标识是否正在充电

unsigned char reset_loop =0; //用于记录重置CW2015的尝试次数


STRUCT_CW_BATTERY   cw_bat; //结构体,用于存储电池的各种状态信息

/*单字节读取*/
int cw_read(uint8_t point_reg,uint8_t *r_pdata)
{

    i2c_memory_read(&hi2c1, I2C_MEM_ADDR_WIDIH_8, 0xc5, point_reg, r_pdata, 1, 0xFFFFFFF);

    return 0;
}
/*/*多字节读取*/
int cw_read_word(uint8_t point_reg,uint8_t *r_pdata, uint16_t length)
{

    i2c_memory_read(&hi2c1, I2C_MEM_ADDR_WIDIH_8, 0xc5, point_reg, r_pdata, length, 0xFFFFFFF);
    return 0;
}
/*单字节写入*/
int cw_write(uint8_t point_reg,uint8_t *w_pdata)
{
    i2c_memory_write(&hi2c1, I2C_MEM_ADDR_WIDIH_8, 0xc4, point_reg, w_pdata, 1, 0xFFFFFFF);
    return 0;
}

/*毫秒延时*/
void CW_Delay10ms(unsigned int c)
{
    unsigned char a, b, d;
    for (;c>0;c--)
    {
        for(b=95;b>0;b--)
        {
            for(a=209;a>0;a--) ;
        }
    }
}
/*微秒延时*/
void CW_Delay100us()
{
    unsigned char a, b;
    unsigned char i;
    for(i = 0; i < 10; i++)
    {
        for(b = 1;b > 0;b --)
        {
            for(a = 7;a > 0;a --);
        }
    }
}

/*该函数将新电池的配置写入CW2015,并检查是否写入成功。配置完成后,芯片会被重置,以应用新配置*/
unsigned char cw_update_config_info(void)
{
    int ret = 0;
    unsigned char i;
    unsigned char reset_val;
    unsigned char reg_val;
    const unsigned char cw_bat_config_info[SIZE_BATINFO] = {
    0x14,0xA6,0x70,0x6C,0x6C,0x67,0x64,
    0x62,0x60,0x5C,0x59,0x4E,0x50,0x42,
    0x2E,0x26,0x25,0x24,0x27,0x2E,0x41,
    0x5A,0x6D,0x4C,0x39,0xD7,0x06,0x66,
    0x00,0x01,0x05,0x34,0x61,0x76,0x79,
    0x7D,0x42,0x1E,0xA4,0x00,0x27,0x5A,
    0x52,0x87,0x8F,0x91,0x94,0x52,0x82,
    0x8C,0x92,0x96,0x2B,0x59,0x6E,0xCB,
    0x2F,0x7D,0x72,0xA5,0xB5,0xC1,0x94,
    0x99
    };

    /* 确保IC没有在睡眠状态,make sure no in sleep mode */
    ret = cw_read(REG_MODE, &reg_val);
    if(ret)
    {
        return 1;
    }
    if((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) //如果相等,说明设备当前处于睡眠模式
    {
        return 2;
    }
    /* update new battery info */
    for(i = 0; i < SIZE_BATINFO; i++)
    {
        reg_val = cw_bat_config_info[i];
        ret = cw_write(REG_BATINFO+i, &reg_val);
        if(ret)
        {
            return 1;
        }
    }

    /* readback & check */
    for(i = 0; i < SIZE_BATINFO; i++)
    {
        ret = cw_read(REG_BATINFO+i, &reg_val);
        if(ret)
        {
            return 1;
        }
        if(reg_val != cw_bat_config_info[i])
        {
            return 3;
        }
    }
    /* set cw2015/cw2013 to use new battery info */
    ret = cw_read(REG_CONFIG, &reg_val);
    if(ret)
    {
        return 1;
    }
    reg_val |= CONFIG_UPDATE_FLG;   /* set UPDATE_FLAG */
    reg_val &= 0x07;                /* clear ATHD */
    reg_val |= ATHD;                /* set ATHD */
    ret = cw_write(REG_CONFIG, &reg_val);
    if(ret)
    {
        return 1;
    }
    /* reset */
    reset_val = MODE_NORMAL;
    reg_val = MODE_RESTART;
    ret = cw_write(REG_MODE, &reg_val);
    if(ret)
    {
        return 1;
    }
    CW_Delay100us();  //delay 100us
    ret = cw_write(REG_MODE, &reset_val);
    if(ret)
    {
        return 1;
    }
    return 0;
}

/* 该函数用于初始化CW2015,如果芯片处于睡眠模式,会将其唤醒,并检查配置是否正确。
 * 如果配置不正确,则调用cw_update_config_info更新配置。
 * 最后会反复检查SOC(State of Charge,电池的充电状态)寄存器,以确保初始化成功*/
unsigned char cw_init(void)
{
    unsigned ret;
    unsigned char i;
    unsigned char reg_val = MODE_NORMAL;
    const unsigned char cw_bat_config_info[SIZE_BATINFO] = {
    0x14,0xA6,0x70,0x6C,0x6C,0x67,0x64,
    0x62,0x60,0x5C,0x59,0x4E,0x50,0x42,
    0x2E,0x26,0x25,0x24,0x27,0x2E,0x41,
    0x5A,0x6D,0x4C,0x39,0xD7,0x06,0x66,
    0x00,0x01,0x05,0x34,0x61,0x76,0x79,
    0x7D,0x42,0x1E,0xA4,0x00,0x27,0x5A,
    0x52,0x87,0x8F,0x91,0x94,0x52,0x82,
    0x8C,0x92,0x96,0x2B,0x59,0x6E,0xCB,
    0x2F,0x7D,0x72,0xA5,0xB5,0xC1,0x94,
    0x99
    };

    /* 从睡眠状态唤醒wake up cw2015/13 from sleep mode */
    ret = cw_write(REG_MODE, &reg_val);
    if(ret)
    {
        return 1;
    }

    /* check ATHD if not right */
    ret = cw_read(REG_CONFIG, &reg_val);
    if(ret)
    {
        return 1;
    }
    if((reg_val & 0xf8) != ATHD)
    {
        //"the new ATHD need set"
        reg_val &= 0x07;    /* clear ATHD */
        reg_val |= ATHD;    /* set ATHD */
        ret = cw_write(REG_CONFIG, &reg_val);
        if(ret)
        {
            return 1;
        }
    }

    /* check config_update_flag if not right */
    ret = cw_read(REG_CONFIG, &reg_val);
    if(ret)
    {
        return 1;
    }
    if(!(reg_val & CONFIG_UPDATE_FLG))
    {
        //"update flag for new battery info need set"
        ret = cw_update_config_info();
        if(ret)
        {
            return ret;
        }
    }
    else
    {
        for(i = 0; i < SIZE_BATINFO; i++)
        {
            ret = cw_read(REG_BATINFO +i, &reg_val);
            if(ret)
            {
                return 1;
            }
            if(cw_bat_config_info[i] != reg_val)
            {
                break;
            }
        }
        if(i != SIZE_BATINFO)
        {
            //"update flag for new battery info need set"
            ret = cw_update_config_info();
            if(ret)
            {
                return ret;
            }
        }
    }
    /* check SOC if not eqaul 255 */
    for (i = 0; i < 30; i++) {
        CW_Delay10ms(10);//delay 100ms
        ret = cw_read(REG_SOC, &reg_val);
        if (ret)
            return 1;
        else if (reg_val <= 100)
            break;
    }

    if (i >=30){
        reg_val = MODE_SLEEP;
        ret = cw_write(REG_MODE, &reg_val);
        // "cw2015/cw2013 input unvalid power error_2\n";
        return 4;
    }
    return 0;
}

/* 实现了对电池管理芯片的电源复位操作(Power-On Reset, POR)。
 * 通过将芯片设置为睡眠模式(MODE_SLEEP)再切换回正常模式(MODE_NORMAL),
 * 然后重新初始化芯片,以确保芯片处于正确的工作状态。
 * */
int cw_por(void)
{
    int ret = 0;
    unsigned char reset_val = 0;

    // 将芯片设置为睡眠模式
    reset_val = MODE_SLEEP;
    ret = cw_write(REG_MODE, &reset_val);
    if (ret)
        return -1;
    CW_Delay100us(); //delay 100us

    // 将芯片设置为正常模式
    reset_val = MODE_NORMAL;
    ret = cw_write(REG_MODE, &reset_val);
    if (ret)
        return -1;
    CW_Delay100us(); //delay 100us

    // 重新初始化芯片
    ret = cw_init();
    if (ret)
        return ret;
    return 0;
}

/*读取电池的容量,并进行一些校正,如果读取的容量不正常,会尝试重置CW2015*/
int cw_get_capacity(void)
{
    int ret = 0;
    unsigned char allow_capacity;
    unsigned char reg_val;
    //unsigned char reset_val;
    unsigned char cw_capacity;
    //int charge_time;

    ret = cw_read(REG_SOC, &reg_val);
    if(ret)
    {
        return -1;
    }

    cw_capacity = reg_val;
    /*校验容量值是否在有效范围内*/
    if ((cw_capacity < 0) || (cw_capacity > 100)) {
                // get cw_capacity error
        reset_loop++;
        if (reset_loop >5) {
            ret = cw_por(); //por ic
            if(ret)
                return -1;
            reset_loop =0;
        }
        return cw_bat.capacity;
    }else {
        reset_loop =0;
    }

    return(cw_capacity);
}

/*获取电池的电压值,通过读取多个采样点来得到更精确的电压值*/
//unsigned int cw_get_vol(void)
float cw_get_vol(void)
{
    int ret = 0;
    unsigned char get_ad_times = 0;
    unsigned char reg_val[2] = {0 , 0};
    unsigned long ad_value = 0;
    unsigned int ad_buff = 0;
    unsigned int ad_value_min = 0;
    unsigned int ad_value_max = 0;

    /*循环读取电压值3次*/
    for(get_ad_times = 0; get_ad_times < 3; get_ad_times++)
    {
        ret = cw_read_word(REG_VCELL, &reg_val[0],2); // 从电池管理芯片读取电压值
        if(ret)
        {
            return 1;
        }
        ad_buff = (reg_val[0] << 8) + reg_val[1]; //将两字节数据组合为一个16位的值

        // 初始化最小值和最大值
        if(get_ad_times == 0)
        {
            ad_value_min = ad_buff;
            ad_value_max = ad_buff;
        }
        if(ad_buff < ad_value_min)
        {
            ad_value_min = ad_buff;
        }
        if(ad_buff > ad_value_max)
        {
            ad_value_max = ad_buff;
        }

        // 累加读取到的电压值
        ad_value += ad_buff;
    }

    // 排除最小值和最大值,以减少误差
    ad_value -= ad_value_min;
    ad_value -= ad_value_max;

    // 计算最终的电压值,单位为mV(毫伏)
    ad_value = (ad_value  * 305 + 50000) / 100000;

    float ad_voltage = ad_value / 10.0;

    return(ad_voltage);       //14位ADC
}

/*更新电池的容量信息*/
void update_capacity(void)
{
    int cw_capacity;
    cw_capacity = cw_get_capacity();
    /* 确保 cw_capacity 是一个有效的电池容量值,即在 0 到 100 之间
     * cw_bat.capacity != cw_capacity 用于检查当前的 cw_capacity 是否与 cw_bat 结构体中的 capacity 成员变量不同。
     * 如果不同,表示电池的容量发生了变化,需要更新*/
    if((cw_capacity >= 0) && (cw_capacity <= 100) && (cw_bat.capacity != cw_capacity))
    {
        cw_bat.capacity = cw_capacity;
    }
}

/*更新电池的电压信息*/
void update_vol(void)
{
    float cw_voltage;
    cw_voltage = cw_get_vol();
    if(cw_voltage == 1){
        //read voltage error
        cw_bat.voltage = cw_voltage;
        //cw_bat.voltage = cw_bat.voltage;
    }else if(cw_bat.voltage != cw_voltage)
    {
        cw_bat.voltage = cw_voltage;
    }
}

#ifdef CW2015_GET_RRT
static void update_time_to_empty(void)
{
    unsigned int rrt;
    rrt = (unsigned int)cw_get_time_to_empty();
    if((rrt >= 0) && (cw_bat.time_to_empty != rrt))
    {
        cw_bat.time_to_empty = rrt;
    }
}
#endif
/*
static void update_alt(void)
{
    signed int alt;
    alt = cw_get_alt();
    if ((rrt >= 0) && (cw_bat.alt != alt))
    {
        cw_bat.alt = (unsigned int)alt;
    }
}
*/

void update_usb_online(void)
{
    if(CHARGE == 1)
    {
        cw_bat.usb_online = 1;
    }else{
        cw_bat.usb_online = 0;
    }
}

/*调用了update_usb_online、update_capacity和update_vol,更新电池的状态信息*/
void cw_bat_work(void)
{
    update_usb_online();
    update_capacity();
    update_vol();
    printf("%d%%\r\n",cw_bat.capacity);
    printf("%.1f V\r\n",cw_bat.voltage);


#ifdef CW2015_GET_RRT
    update_time_to_empty();
#endif
}

/*
static void cw_bat_gpio_init(void)
{

     usb_det_pin -- init
     alt_pin  -- init

     return 0;
}
*/

/*初始化电池信息结构体,并调用cw_init函数初始化CW2015,直到初始化成功*/
unsigned char cw_bat_init(void)
{
    unsigned char ret;
    unsigned char loop = 0;
    //cw_bat_gpio_init();

    ret = cw_init(); //初始化成功返回0
    while((loop++ < 200) && (ret != 0))
    {
        ret = cw_init();
    }

    cw_bat.usb_online = 0;
    cw_bat.capacity = 2;
    cw_bat.voltage = 0;

/* 如果 CW2015_GET_RRT 这个宏被定义了,
 * 那么将cw_bat 结构体中的 time_to_empty 成员变量初始化为 0*/
#ifdef CW2015_GET_RRT
    cw_bat.time_to_empty = 0;
#endif
    cw_bat.alt = 0;

    return ret;
}

    void CW_2015_ID(void)
    {
    uint8_t ID=2;
    cw_read(0x00,&ID);
    printf("0x%x\r\n",ID);

    }

CW2015驱动.h文件:

#ifndef __CW2015_H__
#define __CW2015_H__

#include <stdio.h>
#include <string.h>
#include "i2c_application.h"
#include "at32l021_i2c.h"

#define    READ_CW2015                0xc5
#define    WRITE_CW2015            0xc4

#define REG_VERSION             0x0
#define REG_VCELL               0x2
#define REG_SOC                 0x4
#define REG_RRT_ALERT           0x6
#define REG_CONFIG              0x8
#define REG_MODE                0xA
#define REG_BATINFO             0x10


#define MODE_SLEEP_MASK         (0x3<<6)
#define MODE_SLEEP                     (0x3<<6)
#define MODE_NORMAL                  (0x0<<6)
#define MODE_QUICK_START        (0x3<<4)
#define MODE_RESTART                 (0xf<<0)

#define CONFIG_UPDATE_FLG       (0x1<<1)

#define ATHD                    (0x0<<3)        //ATHD = 0%,在此修改低电量报警阈值

#define SIZE_BATINFO        64

#define BATTERY_UP_MAX_CHANGE   720             // the max time allow battery change quantity
#define BATTERY_DOWN_MIN_CHANGE 60             // the min time allow battery change quantity when run
#define BATTERY_DOWN_MIN_CHANGE_SLEEP 1800      // the min time allow battery change quantity when run 30min
//#define BAT_LOW_INTERRUPT    1
//#define CW2015_GET_RRT

//****************************struct*********************************/
typedef struct tagSTRUCT_CW_BATTERY {
    unsigned char usb_online;
    unsigned int capacity;
    float voltage;
#ifdef CW2015_GET_RRT
    unsigned int time_to_empty;
#endif
    unsigned char alt;
}STRUCT_CW_BATTERY;

unsigned char cw_bat_init(void);
void cw_bat_work(void);
void CW_Delay10ms(unsigned int c);

int cw_read(uint8_t point_reg,uint8_t *r_pdata);
int cw_read_word(uint8_t point_reg,uint8_t *r_pdata, uint16_t length);
int cw_write(uint8_t point_reg,uint8_t *w_pdata);
void CW_2015_ID(void);

#endif

main.c:

int main(void)
{
  cw_bat_init();

     while(1)
    {
      cw_bat_work();
    }
}

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值