找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1368|回复: 0
收起左侧

单片机读BQ2040电池电量程序 原理图

[复制链接]
ID:41347 发表于 2022-9-16 15:10 | 显示全部楼层 |阅读模式
#include <AT89X51.H>
#include <absacc.h>
#include <intrins.h>

sbit  SMBC=P1^6;//sbit  SMBC=P1^4;          //bq2040中SMbus的时钟端
sbit  SMBD=P1^7;//sbit  SMBD=P1^5;          //bq2040中SMbus的数据端
sbit  led3=P1^3;          //LED指示灯的最高位,4位中的第3位,0表示指示灯亮,1表示指示灯灭,即对读出数据取反
sbit  led2=P1^2;          //LED指示灯4位中的第2位
sbit  led1=P1^1;          //LED指示灯4位中的第1位
sbit  led0=P1^0;          //LED指示灯的最低位,4位中的第0位
sbit  power_led=P1^4;//sbit  power_led=P1^7;
sbit  speaker=P1^5;//sbit  speaker=P1^6;

unsigned char bq2040_Command_RC=0x0f;     //读剩余电量的指令
signed char bq2040_Command_C=0x0a;     //读电流的指令
unsigned char bq2040_Command_BS=0x16;     //读电池状态
unsigned char ReceiveData_L,ReceiveData_H,Current_H_7,BatteryStatus_L_6,BatteryStatus_L_5;
      //从BQ2040接收数据的低位,高位,电流正负位(正表示充电,负表示放电),电池状态充放电判断(0表示充电,0x40表示放电),电池状态满充判断(0表示未充满,0x20表示充满)
unsigned char ack;      //用于判断接收确认是否超时,超时为1,未超时为0

unsigned char ADAPTER=0,ERROR; //用于判断仪器采用电池供电或者采用电源适配器供电

void Delay(void)   //延时子程序
{
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
}

//以下函数详见SMbus原理
void Star(void)  //开始子程序      当SMBC为高电平时,SMBD上出现一个下降沿。该条件启动一次传输过程
{
  SMBC=0;
  Delay();
  SMBD=1;
  Delay();
  SMBC=1;
  Delay();
  SMBD=0;
  Delay();
}


void Stop(void)  //停止子程序      当SMBC为高电平时,SMBD上出现一个上升沿。该条件停止一次传输过程
{
  SMBC=0;
  Delay();
  SMBD=0;
  Delay();
  SMBC=1;
  Delay();
  SMBD=1;
  Delay();
}


void Ackw(void)  //ACKNOWLEDGE写子程序     SMBC为高时,采样到SMBD为低电平
{
  unsigned char a=0;
  ack=0;
  SMBC=0;
  Delay();
  SMBD=1;
  Delay();
  SMBC=1;
  Delay();
  while(SMBD)
  {
    a++;
        ack=0;
    if(a==250)     //   向串口发送EE,表示发送出错,未收到确认。利用串口助手可以看到
    {
      ADAPTER++;
          if(ADAPTER==20)
          {
        ERROR=0xEE;
                ADAPTER=0;
      }
      else
            ERROR=0;
          ack=1;
      SBUF=0xEE;
      while(!TI);
      TI=0;
      break;
    }
  }
}

void Ackr(void) //ACKNOWLEDGE读子程序     SMBC为高时,采样到SMBD为低电平
{
  SMBC=0;
  Delay();
  SMBD=0;
  Delay();
  SMBC=1;
  Delay();
}


void Nack(void)  //NOT ACKNOWLEDGE子程序    SMBC为高电平时,采样到SMBD为高电平
{
  SMBC=0;
  Delay();
  SMBD=1;
  Delay();
  SMBC=1;
  Delay();
}


void Send(unsigned char b)  //发送子程序      将b按从最高位到最低位的顺序,逐位的发送给bq2040
{
  unsigned char i,x,y,z;
  z=0x80;
  for(i=1;i<9;i++)
  {
    x=b&z;
    if(x==0)
      y=0;
    else
      y=1;
    SMBC=0;
    Delay();
    SMBD=y;
    Delay();
    SMBC=1;
    Delay();
    z>>=1;
  }
}

unsigned char Receive(void)  //接收子程序     将bq2040中的数据逐位的读出
{
  unsigned char i,g=0x00;
  for(i=1;i<9;i++)
  {
    SMBC=0;
    _nop_();
    _nop_();
    SMBD=1;
    Delay();
    SMBC=1;
    Delay();
    g<<=1;
    if(SMBD)
      g++;
    Delay();
  }
  return g;
}




void Read(unsigned char Command)   //读剩余电量子程序
{
  unsigned int a;
  Star();      //开始
  a=0x16;
  Send(a);    //发送器件地址0x16
  Ackw();     //发送确认
  if(ack)     //未确认则重新发送
    return;
  Send(Command);  //发送读剩余电量指令
  Ackw();     //发送确认
  if(ack)     //未确认则重新发送
    return;
  Star();
  a=0x17;    //发送器件地址0x17
  Send(a);
  Ackw();    //发送确认
  if(ack)    //未确认则重新发送
    return;
  ReceiveData_L=Receive();  //接收剩余电量低8位数据
  Ackr();    //接收确认
  ReceiveData_H=Receive();  //接收剩余电量高8位数据
  Nack();    //非确认
  Stop();    //结束
}




void Delay2(void)   //4s显示延时
{
  unsigned char i,j,k;
  for(i=0;i<255;i++)
   for(j=0;j<255;j++)
    for(k=0;k<20;k++);
}


void Delay3(void)   //power_led快闪延时
{
  unsigned char i,j,k;
  for(i=0;i<100;i++)
   for(j=0;j<150;j++)
    for(k=0;k<5;k++);
}

void Delay4(void)   //power_led特快闪延时,speaker响延时
{
  unsigned char i,j,k;
  for(i=0;i<100;i++)
   for(j=0;j<150;j++)
    for(k=0;k<1;k++);
}

void Delay5(void)   //power_led慢闪延时
{
  unsigned char i,j,k;
  for(i=0;i<100;i++)
   for(j=0;j<150;j++)
    for(k=0;k<12;k++);
}

void LedDisplay_Battery(unsigned char h,unsigned char l)
{
  unsigned char i;
  if(BatteryStatus_L_5==0x20&&BatteryStatus_L_6==0)  //充电充满时,指示灯显示0 1 0 0=11
  {
    power_led=0;
    speaker=1;
    led0=0;
    led1=0;
    led2=1;
    led3=0;
    Delay2();
  }
  else if(Current_H_7==0&&BatteryStatus_L_6==0)  //充电时,指示灯显示0 1 0 1=10
  {     
    power_led=0;
    speaker=1;
    led0=1;
    led1=0;
    led2=1;
    led3=0;
    Delay2();
  }
             //放电时,指示灯指示电量0-9共10份
  else
  {
    if(h>0x22)     //超出电量范围(当读出的剩余电量16位的高8位大于0x22,即电量大于8960mah时1,表示错误,所有灯不亮)
    {
      power_led=0;
      speaker=1;
      led0=1;
      led1=1;
      led2=1;
      led3=1;
    }

    if(h<=0x22&&h>=0x17)  //显示09(当剩余电量在5888mah~8960mah之间时,指示灯表示 0 1 1 0=9)
    {
      power_led=0;
      speaker=1;
      led0=0;
      led1=1;
      led2=1;
      led3=0;
      Delay2();
    }

    if(h<0x17&&h>=0x15)  //显示08(当剩余电量在5376mah~5888mah之间时,指示灯表示 0 1 1 1=8)
    {
      power_led=0;
      speaker=1;
      led0=1;
      led1=1;
      led2=1;
      led3=0;
      Delay2();
    }

    if(h<0x15&&h>=0x12)  //显示07(当剩余电量在4608mah~5376mah之间时,指示灯表示 1 0 0 0=7)
    {
      power_led=0;
      speaker=1;
      led0=0;
      led1=0;
      led2=0;
      led3=1;
      Delay2();
    }

    if(h<0x12&&h>=0x0f)  //显示06(当剩余电量在3840mah~4608mah之间时,指示灯表示 1 0 0 1=6)
    {
      power_led=0;
      speaker=1;
      led0=1;
      led1=0;
      led2=0;
      led3=1;
      Delay2();
    }

    if(h<0x0f&&h>=0x0d)  //显示05(当剩余电量在3328mah~3840mah之间时,指示灯表示 1 0 1 0=5)
    {
      power_led=0;
      speaker=1;
      led0=0;
      led1=1;
      led2=0;
      led3=1;
      Delay2();
    }
    if(h<0x0d&&h>=0x0a)  //显示04(当剩余电量在2560mah~3328mah之间时,指示灯表示 1 0 1 1=4)
    {
      power_led=0;
      speaker=1;
      led0=1;
      led1=1;
      led2=0;
      led3=1;
      Delay2();
    }

    if(h<0x0a&&h>=0x08)  //显示03(当剩余电量在2048mah~2560mah之间时,指示灯表示 1 1 0 0=3)
    {
      power_led=0;
      speaker=1;
      led0=0;
      led1=0;
      led2=1;
      led3=1;
      Delay2();
    }  

    if(h<0x08&&h>=0x05)  //显示02(当剩余电量在1280mah~2048mah之间时,指示灯表示 1 1 0 1=2)
    {
      power_led=0;
      speaker=1;
      led0=1;
      led1=0;
      led2=1;
      led3=1;
      Delay2();
    }

    if(h<0x05&&h>=0x01)  //显示01(当剩余电量在256mah~1280mah之间时,指示灯表示 1 1 1 0=1)
    {
      power_led=0;
      speaker=1;
      led0=0;
      led1=1;
      led2=1;
      led3=1;
      Delay2();
    }

    if(h<0x01)  //显示01在闪烁(当剩余电量在0mah~256mah之间时,指示灯表示 1 1 1 0=0)
    {
      //led0=0;
      led1=1;
      led2=1;
      led3=1;
          if(l>=0x40&&l<0xa0)
          {
            speaker=1;
                for(i=0;i<15;i++)
        {
                  led0=!led0;
          power_led=!power_led;
          Delay3();
                }
      }
          else if(l<0x40)
          {                  
                speaker=0;
                for(i=0;i<15;i++)
        {
          led0=!led0;
                  power_led=!power_led;
                  Delay4();
                }
          }
          else
          {
            speaker=1;
                for(i=0;i<10;i++)
        {
          led0=!led0;
                  power_led=!power_led;
                  Delay5();
                }
      }   
        }  
   }
}

void LedDisplay_Adapter()  //灯全亮,表示采用电源适配器供电
{
  power_led=0;
  speaker=1;
  led0=0;
  led1=0;
  led2=0;
  led3=0;
  Delay2();
}

main()
{
  unsigned char RemainingCapacity_H,RemainingCapacity_L,Current_H,BatteryStatus_L;
  TMOD=0x20;   //串口波特率9600bps,方式3,无校验,数据位8,停止位1.
  TH1=0xFD;
  TL1=0xFD;
  PCON=0x00;
  TR1=1;
  SCON=0xD8;

  power_led=0;
  while(1)
  {
   Read(bq2040_Command_C);
   //   向串口发送当前电流,利用串口助手可以看到

   if(ack==0)   //读数据成功,则执行赋值
     Current_H=ReceiveData_H;

   SBUF=bq2040_Command_C;
   while(!TI);
   TI=0;

   SBUF=Current_H;
   while(!TI);
   TI=0;
   SBUF=ReceiveData_L;
   while(!TI);
   TI=0;

      Current_H_7=Current_H&0x80;


   Read(bq2040_Command_BS);
   //   向串口发送电池状态,利用串口助手可以看到

   if(ack==0)   //读数据成功,则执行赋值
     BatteryStatus_L=ReceiveData_L;

   SBUF=bq2040_Command_BS;
   while(!TI);
   TI=0;

   SBUF=ReceiveData_H;
   while(!TI);
   TI=0;
   SBUF=BatteryStatus_L;
   while(!TI);
   TI=0;

    BatteryStatus_L_6=BatteryStatus_L&0x40;
    BatteryStatus_L_5=BatteryStatus_L&0x20;

    Read(bq2040_Command_RC);
    //   向串口发送剩余电量,利用串口助手可以看到

        if(ack==0)   //读数据成功,则执行赋值
    {
      RemainingCapacity_H=ReceiveData_H;
      RemainingCapacity_L=ReceiveData_L;
    }   

   SBUF=bq2040_Command_RC;
   while(!TI);
   TI=0;

   SBUF=RemainingCapacity_H;
   while(!TI);
   TI=0;
   SBUF=RemainingCapacity_L;
   while(!TI);
   TI=0;

   if(ack==0)
    LedDisplay_Battery(RemainingCapacity_H,RemainingCapacity_L);
   else if(ERROR==0xEE)
    LedDisplay_Adapter();
  }
}


1663311839329.jpg

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表