读取bq26500电池电量 Driver
Posted cynchanpin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了读取bq26500电池电量 Driver相关的知识,希望对你有一定的参考价值。
bq26500是用于锂离子电池、锂聚合物电池充电、放电控制和监控的集成电路芯片。利用它能够准确提供电池充电、放电、电池温度、充放电电压、电池电量等相关数据。不须要外接微处理器參与电池充电、放电等相关数据的计算。
本文简单的读取了电池的电量百分比和电压。如要读取其它參数依照datasheet给出的寄存器一一读取就可以。
连接示意图:
引脚pack+ 和 pack-分别连接正极和负极用来冲放电,HDQ是数据交互引脚,用来读取电池的參数,一般用一个gpio连接就能够。
时序图:
看图可知。逻辑1和0并非简单的高低电平,而是依据高低电平占空比来推断是逻辑1还是0的。
基本通信过程:先发break 进入通信, 然后主机发送地址,电池返回数据。
寄存器列表:
读取电量百分比为0x0b寄存器。读取电压为0x09和0x08寄存器的值拼接的。
依据上诉信息编写读取电量的代码:
#define ADDR_PERCENT 0x0b void bat_set_gpio(int en) { if (en) { mt_set_gpio_mode(GPIO155, GPIO_MODE_00); mt_set_gpio_dir(GPIO155, GPIO_DIR_OUT); mt_set_gpio_out(GPIO155, GPIO_OUT_ONE); } else { mt_set_gpio_mode(GPIO155, GPIO_MODE_00); mt_set_gpio_dir(GPIO155, GPIO_DIR_OUT); mt_set_gpio_out(GPIO155, GPIO_OUT_ZERO); } return; } int bat_get_gpio(void) { int ret = 0; mt_set_gpio_mode(GPIO155, GPIO_MODE_00); mt_set_gpio_dir(GPIO155, GPIO_DIR_IN); ret = mt_get_gpio_in(GPIO155); return ret; } static int send_addr_to_bq26500(unsigned int addr,int rw) { int i; unsigned int cmd = 0; cmd = addr | rw << 7; // break and break recovery timing bat_set_gpio(1); udelay(100); bat_set_gpio(0); udelay(190);//190us bat_set_gpio(1); udelay(40); //40us for (i=0;i<8;i++) { if(cmd >> i & 0x01) { //hw1 bat_set_gpio(0); udelay(40); //40us bat_set_gpio(1); udelay(150); //150 } else { //hw0 bat_set_gpio(0); udelay(125); //125 bat_set_gpio(1); udelay(65); //65 } } bat_get_gpio(); return 0; } static unsigned char data_from_bq26500(void) { volatile unsigned char value = 0, low=0, temp = 0, temp_old = 0; int i, j; //wait response time for(i=0; i < 32; i++) { //320us udelay(10); temp = bat_get_gpio(); if (temp == 0) break; } //read data //依据占空比推断是逻辑1还是逻辑0 for (i=0; i < 8; i++) { for (j=0, low = 0; j < 26; j++) {//260us udelay(10); temp = bat_get_gpio(); if (temp == 0) { low++; } if ((temp == 1) && (temp_old == 0)){ break; } temp_old = temp; } if (low < 6 && low != 0){ value = value | 1<< i; } temp = 1; temp_old = 1; } return value; } static DEFINE_SPINLOCK(bq26500_spinlock); // transmit address to bq26500 static unsigned char read_data_bq26500(unsigned int addr) { volatile unsigned char value = 0, temp[3] = {0}; unsigned long flags; int i, j; //读取三次取中间值上报,假设平台频率低仅仅读取一次就可以。 for (i=0; i < 3; i++) { spin_lock_irqsave(&bq26500_spinlock, flags); value = send_addr_to_bq26500(addr,0); temp[i] = data_from_bq26500(); spin_unlock_irqrestore(&bq26500_spinlock, flags); usleep_range(10, 20); } for (i=0; i < 3; i++) { for (j=i; j < 3; j++) { if (temp[i] > temp[j]) { value = temp[i]; temp[i] = temp[j]; temp[j] = value; } } } value = temp[1]; return value; }
printk("Battery percent: %d\n", read_data_bq26500(0x0b))
我实现的平台是MTK 平台,操作GPIO的函数跟标准的kernel有些出入,但不影响理解代码。
上诉代码是读取电量百分的,读取电压的方法例如以下:
voltage_h = read_data_bq26500(0x09/*BATTERYH_VOLTAGE*/); voltage_l = read_data_bq26500(0x08/*BATTERYL_VOLTAGE*/); printk("Battery Vol:%d\n",voltage_l | voltage_h << 8);
使用spin_lock_irqsave是由于读取过程必须严格遵循时序,不能被中断或进程调度打断。一但打断将不能正确从电池中读出数据。由于使用了spin_lock所以期间的睡眠也仅仅能是忙等,不能使用sleep这类的系统调度的睡眠函数。
以上是关于读取bq26500电池电量 Driver的主要内容,如果未能解决你的问题,请参考以下文章