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, ®_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, ®_val);
if(ret)
{
return 1;
}
}
/* readback & check */
for(i = 0; i < SIZE_BATINFO; i++)
{
ret = cw_read(REG_BATINFO+i, ®_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, ®_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, ®_val);
if(ret)
{
return 1;
}
/* reset */
reset_val = MODE_NORMAL;
reg_val = MODE_RESTART;
ret = cw_write(REG_MODE, ®_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, ®_val);
if(ret)
{
return 1;
}
/* check ATHD if not right */
ret = cw_read(REG_CONFIG, ®_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, ®_val);
if(ret)
{
return 1;
}
}
/* check config_update_flag if not right */
ret = cw_read(REG_CONFIG, ®_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, ®_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, ®_val);
if (ret)
return 1;
else if (reg_val <= 100)
break;
}
if (i >=30){
reg_val = MODE_SLEEP;
ret = cw_write(REG_MODE, ®_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, ®_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, ®_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();
}
}