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