zoukankan      html  css  js  c++  java
  • 读取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
    ", 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
    ",voltage_l | voltage_h << 8);

        使用spin_lock_irqsave是由于读取过程必须严格遵循时序,不能被中断或进程调度打断。一但打断将不能正确从电池中读出数据。由于使用了spin_lock所以期间的睡眠也仅仅能是忙等,不能使用sleep这类的系统调度的睡眠函数。


  • 相关阅读:
    hdu 4521 小明系列问题——小明序列(线段树 or DP)
    hdu 1115 Lifting the Stone
    hdu 5476 Explore Track of Point(2015上海网络赛)
    Codeforces 527C Glass Carving
    hdu 4414 Finding crosses
    LA 5135 Mining Your Own Business
    uva 11324 The Largest Clique
    hdu 4288 Coder
    PowerShell随笔3 ---别名
    PowerShell随笔2---初始命令
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/7287270.html
Copyright © 2011-2022 走看看