|
#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();
}
}
|
评分
-
查看全部评分
|