德州仪器BQ27220电量计驱动

最近在调试BQ27220电量计,记录一下,供大家参考。

一、先上图

图一图二为在“Battery Management Studio”上进行调试,也为后续驱动的顺序做准备。小白可以对比驱动手册,理解上面的意思,下文会详细描述。

图三图四图五自己用单片机成功驱动的读写例子。

下面是代码说明:

        注意:如果确定硬件没问题,调不通的,用逻辑分析仪去抓,大概率是时序的问题,后面代码需要注意的地方也会标注出来,供大家参考

 //补上自己控制io口的相关代码  最好是直接操作寄存器的方式

#define SDA_OUT()   //配置sda为输出
#define IIC_SDA_H() //配置sda为输出高
#define IIC_SDA_L() //配置sda为输出低
#define IIC_SDA_IN() //配置sda为输入
#define IIC_SCL_H() //配置scl为输出高
#define IIC_SCL_L() //配置scl为输出低
#define READ_SDA()  //sda为输入时 读取sda的状态

//产生IIC起始信号
static void IIC_Start(void)
{
    SDA_OUT();     //sda线输出
    IIC_SDA_H();
    IIC_SCL_H();
    delay1us(5);//注意这里的延时 一般情况下,这里不需要修改
     IIC_SDA_L();//START:when CLK is high,DATA change form high to low
    delay1us(5);
    IIC_SCL_L();//钳住I2C总线,准备发送或接收数据
}

//产生IIC停止信号
static void IIC_Stop(void)
{
    SDA_OUT();//sda线输出
    IIC_SCL_L();
    IIC_SDA_L();//STOP:when CLK is high DATA change form low to high
     delay1us(5);//注意这里的延时 一般情况下,这里不需要修改
    IIC_SCL_H();
    delay1us(3);//注意这里的延时 一般情况下,这里不需要修改
    IIC_SDA_H();//发送I2C总线结束信号
    delay1us(5);//注意这里的延时 一般情况下,这里不需要修改
}

//等待应答信号 这个函数一定要注意

static uint8_t IIC_Wait_Ack(void)
{
    uint8_t ucErrTime=0;
    IIC_SDA_IN();      //SDA设置为输入
    delay1us(3);
    IIC_SCL_H();
    delay1us(3);
    while(READ_SDA())
    {
        ucErrTime++;
        //delay(1);
        if(ucErrTime>250)
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL_L();//时钟输出0
    return 0;
}

//产生ACK应答
static  void IIC_Ack(void)
{
    IIC_SCL_L();
    SDA_OUT();
    IIC_SDA_L();
    delay1us(3);//注意这里的延时 一般情况下,这里不需要修改
    IIC_SCL_H();
    delay1us(5);//注意这里的延时 一般情况下,这里不需要修改
    IIC_SCL_L();
}
//不产生ACK应答
static void IIC_NAck(void)
{
    IIC_SCL_L();
    SDA_OUT();
    IIC_SDA_H();
    delay1us(3);//注意这里的延时 一般情况下,这里不需要修改
    IIC_SCL_H();
    delay1us(3);//注意这里的延时 一般情况下,这里不需要修改
    IIC_SCL_L();
}

//IIC发送一个字节
//注意这里的延时 一般情况下,这里不需要修改
static void IIC_Send_Byte(uint8_t txd)
{
    uint8_t t;
    SDA_OUT();
    IIC_SCL_L();//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {
        if((txd&0x80)>>7)
            IIC_SDA_H();
        else
          IIC_SDA_L();
        //hal_gpio_write(IIC_SDA,((txd&0x80)>>7));
        txd<<=1;
        delay1us(5);   //对TEA5767这三个延时都是必须的
        IIC_SCL_H();
        delay1us(5);
        IIC_SCL_L();
        delay1us(5);
    }
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK

//注意这里的延时 一般情况下,这里不需要修改
static uint8_t IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    IIC_SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL_L();
        delay1us(5);
        IIC_SCL_H();
        receive<<=1;
        if(READ_SDA())receive++;
        delay1us(5);
    }
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK
    return receive;
}

//向BQ27220的寄存器发送字节 这里后续这里的len一直为2字节 
//这个函数必须注意延时函数的延时时间和是否需要延时  不同的平台,可能都不一样

static uint8_t BQ27220_Write(uint8_t addr,uint8_t reg,uint8_t *data,uint8_t len)
{
    IIC_Start();
    IIC_Send_Byte(addr);//发送器件地址+写命令
    if(IIC_Wait_Ack())    //等待应答
    {
        IIC_Stop();
        return 0;
    }
    IIC_Send_Byte(reg);    //写寄存器地址
    delay1us(30);//用过两款单片机驱动,一款这里需要延时 一款不需要,请注意
    if(IIC_Wait_Ack())    //等待应答
    {
        IIC_Stop();
        return 0;
    }
    IIC_Send_Byte(data[0]);//发送数据
    delay1us(30);//用过两款单片机驱动,一款这里需要延时 一款不需要,请注意
    if(IIC_Wait_Ack())    //等待ACK
    {
        IIC_Stop();
        return 0;
    }
    IIC_Send_Byte(data[1]);//发送数据
    delay1us(30);//用过两款单片机驱动,一款这里需要延时 一款不需要,请注意
    if(IIC_Wait_Ack())    //等待ACK
    {
        IIC_Stop();
        return 0;
    }
    delay1us(20);//用过两款单片机驱动,一款这里需要延时 一款不需要,请注意
    IIC_Stop();
    mdelay(2);//这里最好加上延时,因为BQ27220手册里说了,结尾要加66uS的延时
    return 1;
}

//读取BQ27220的寄存器字节 这里后续这里的len一直为2字节 
//这个函数必须注意延时函数的延时时间和是否需要延时  不同的平台,可能都不一样

static uint8_t BQ27220_Read(uint8_t addr, uint8_t reg,uint8_t cmd,uint8_t *date,uint8_t len)
{
    //uint8_t res;
    IIC_Start();
    IIC_Send_Byte(addr);//发送器件地址+写命令
    if(IIC_Wait_Ack())    //等待ACK
    {
        IIC_Stop();
        return 0;
    }
    IIC_Send_Byte(reg);    //写寄存器地址
    delay1us(30);//用过两款单片机驱动,一款这里需要延时 一款不需要,请注意
    if(IIC_Wait_Ack())    //等待ACK
    {
        IIC_Stop();
        return 0;
    }
    delay1us(10);//用过两款单片机驱动,一款这里需要延时 一款不需要,请注意
    IIC_Start();
    IIC_Send_Byte(addr|0x01);//发送器件地址+读命令
    if(IIC_Wait_Ack())    //等待ACK
    {
        IIC_Stop();
        return 0;
    }
    delay1us(50);//用过两款单片机驱动,两款需要延时的大小都不一样,建议是以150uA为延时
    date[0]=IIC_Read_Byte(1);//读取数据,发送nACK
    delay1us(50);/用过两款单片机驱动,两款需要延时的大小都不一样,建议是以150uA为延时
    date[1]=IIC_Read_Byte(0);//读取数据,发送nACK
    IIC_Stop();            //产生一个停止条件
    return 1;

}

接下来是步骤说明,根据图一图二的步骤来的,本人也是按照这个步骤来的,实测基本上问题不大了。注意 注意 注意 一定要按照图一图二的顺序来。

(1):上电先判断电量计的容量配置是否为自己要的配置(举例而已(0x3C,因为我有改容量所以读取容量寄存器,判断是否需要修改),具体看自己,图一图二没有该步骤),如果需要修改,则开始进行图一图二的步骤,反之则执行读取电量等操作。

(2):执行图一图二的操作。有些说明地方可能不对,请结合配置手册来看,W表示写,R表示读。

  我是写了一个定时器,每50ms发送一条配置指令,可以通过下面的方式,通过加延时去实现

W 0x00 0x1404   这里只说明一次 W +0x00,0x1404表示在寄存器00写入0x1404

delayms(50);

W 0x00  0x7236//这两个指令需要配置时都需要先发送

delayms(50);

说明:我的方法是通过一个标志位和一个定时器来实现的,如下,每个配置的指令的定时都大同小异,后面会按照延时的方式去写,这样方便大家理解。

               

W 0x4100  //重启操作,这里最好加上重启操作,因为有时候万一出了问题,导致配置丢失 ,这里重启,恢复初始状态

delayms(4000);//重启需要4秒钟 4秒后在操作27220

W 0x00  0xFFFF

  delayms(50);

W 0x00  0xFFFF//两次发送FFFF让27220进入FULL ACCESS 模式

  delayms(50);

W 0x00  0x9000//进入CFGUPDATE模式

  delayms(1100);

R 0x3B //读取两字节 通过第一节判断是否成功进入CFGUPDATE模式  没有进入的话 需要重新开始,不可以往下进行 判断的依据为 第一字节&0x04==1表示进入成功.

W 0x3E  0x9B92  //通过3E寄存器配置接下来要操作的地址 这个寄存器很重要

  delayms(50);

上面的0x9B92 其实是0x929B,但程序必须写成9B92,这个操作的是下面这个寄存器,也是很重要的一个寄存器  默认值为0x102A 没啥要求的话,就按照我的配置来吧 我测试过,确实能用。

W 0x40  0x0021  //上面的0x3E告诉27220要配置的地址,这里的0x40是告诉27220 要配置的值 这里说一下,0021表示启动平滑处理 就是电量可以从100 99.....往下掉 不会跳变,21表示使用FIXED_EDV0(即用自己配置的东西),请对照手册去理解

delayms(50);

W 0x60 0xCC24  // 上面的0x3E告诉27220要配置的地址,0x40是告诉27220 要配置的值,这里的0x60是告诉27220  配置好了 请根据这个值进行校验,非常注意 这里的校验很奇怪,请不要按照官方的文档进行配置,按照我这里的描述来,按照官方的文档很容易出错,只需要用到官方提供的两个公式即可,不要问为什么,我也很奇怪。
校验值说明:
         公式如下:
                Temp = mod(255 – Old_Chksum – OLD_DC_MSB – OLD_DC_LSB, 256);
                New_Chksum = 255 – mod(temp + 0x04 + 0Xb0, 256);

开始说明:

(1)通过大量的实验表明,27220第一次读取“Old_Chksum,OLD_DC_MSB,OLD_DC_LSB”都是一样的,意思就是假如 上电进入配置模式,配置要操作的地址为0x9D92,读取0x40(就是这个地址原来的值)都为0x0BB8(记住就行,可能例子的0bb8写反了),读取0x60的值都为0x3D24(3D表示Old_Chksum,24表是长度)不要管3D24怎么来的 记住这两个值就行,记住只需要你读一次值记下来就行,千万不要第二次读取,因为第二次读取出来的值跟第一次读取出来的值不一样,这样会导致后续的配置不成功。

(2)通过步骤一读取到的“Old_Chksum,OLD_DC_MSB,OLD_DC_LSB”用带入上面的公式进行计算,得到新的校验值,上例子解析, Temp=(255-0x3D-0x0B-0xB8)%256=255(结果为负的话就用补码来实现,(这里建议在网页收搜一下mod的计算器,直接填数字就行)这里假设要配置的值为0x2710(10000mAh)

New_Chksum = 255 – (0x27+0x10+0x3D)%256=0xC9;记住这个(0xC924就行),把这两个值写入到0x60寄存器就行,同理,修改别的地址的值也是一样的。

delayms(50);

W 0x3E  0x9D92  //这个是配置电池可以的容量的 跟0x9F92是配合使用的 

delayms(50);

W 0x40  0x2710 //配置的电池容量为10000mAh 

delayms(50);

W 0x60  0xC924  //校验值按照上面的方法进行

delayms(50);

W 0x3E  0x9F92  //这个是配置电池可以的容量的 跟0x9F92是配合使用的 

delayms(50);

W 0x40  0x2710 //配置的电池容量为10000mAh 

delayms(50);

W 0x60  0x2D24  //校验值按照上面的方法进行

delayms(50);

W 0x3E  0x0692  //这个操作是进制27220进入休眠的  进入休眠后 所有数据都会丢失,所以禁止它休眠 

delayms(50);

W 0x40  0x0084 //

delayms(50);

W 0x60  0x1524  //校验值按照上面的方法进行

delayms(50);

W 0x3E  0x7192  //这个操作是让27220平滑处理  尽量加上吧  每试过不加上会不会有影响

delayms(50);

W 0x40  0x0F0E //

delayms(50);

W 0x60  0xCF92  //校验值按照上面的方法进行

delayms(50);

W 0x3E  0xB792  //因为是用自己设定的值,所以这里配的3%的电压为3.100V 这个可以自己定,别定太高,免得出现电量跳变

delayms(50);

W 0x40  0x0C1C //

delayms(50);

W 0x60  0x2821  //校验值按照上面的方法进行  这里的21 不是24  因为通过上面的校验方法 读出来的长度就为0x21

delayms(50);

W 0x3E  0xBA92  //因为是用自己设定的值,所以这里配的7%的电压为3.200V 这个可以自己定,别定太高,免得出现电量跳变

delayms(50);

W 0x40  0x0C80 //

delayms(50);

W 0x60  0x7C1E  //校验值按照上面的方法进行  这里的1E 不是24  因为通过上面的校验方法 读出来的长度就为0x1E

delayms(50);

//到此,已经把电池容量的3000mA配置到了10000mA  去掉休眠,加上平滑处理,自定义电量百分之七的电压(防止跳变,别定太高)接下来就是最后两条指令,重置计量。

W 0x00  0x9100//退出配置模式  重启计量器  开始生效配置

  delayms(50);

W 0x00  0x3000//进入CFGUPDATE模式

对了  图一图二配置的是5000mAh的

Nginx是一个高性能的HTTP和反向代理服务器,用于管理和转发网络流量。配置`nginx.conf`是设置Nginx基本运行环境和行为的关键步骤。`nginx.conf`文件通常位于服务器的`/etc/nginx`目录下(取决于操作系统和安装位置),这是一个主配置文件,包含了全局的配置选项。 配置`nginx.conf`主要包括以下几个部分: 1. **Server Block**(服务器块):每个包含`http`或`stream`关键字的部分定义了一个独立的监听端口和相关的配置,如域名、路径、SSL证书等。例如: ```nginx server { listen 80; server_name example.com; # 更多配置项... } ``` 2. **监听和端口**:`listen`指令指定Nginx监听的地址和端口,如`listen 443 ssl;`。 3. **访问控制**:通过`access_log`定义日志记录,`root`指定了静态资源文件的根目录,`index`指定了默认的首页文件。 4. **路由和URL处理**:`location`指令用于匹配URL并决定如何处理请求,可以包括文件服务、动态内容处理、反向代理等。 5. **HTTPS配置**:如果需要HTTPS,需要添加SSL/TLS证书和密钥,并启用`ssl`参数。 6. **错误页面**:设置自定义的404、500等错误页面。 7. **缓存和性能优化**:`gzip`模块可以压缩传输数据,`proxy_cache`用于缓存代理请求。 8. **日志和监控**:`log_format`定义日志格式,`error_log`指定错误日志的位置和级别。 9. **守护进程**:`worker_processes`和`worker_connections`设置Nginx的工作进程数和连接数。 相关问题: 1. Nginx的配置文件通常存储在哪里? 2. 什么是`server_name`指令在配置中的作用? 3. 如何在Nginx中启用HTTPS功能? 4. Nginx的`location`指令有哪些常见的用途? 5. 什么是Nginx的日志轮换机制? 如果你需要深入了解某个具体的配置选项,可以详细描述一下你的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值