AN137 [SILICON]

LITHIUM ION BATTERY CHARGER USING C8051F300; 锂离子电池充电器使用C8051F300
AN137
型号: AN137
厂家: SILICON    SILICON
描述:

LITHIUM ION BATTERY CHARGER USING C8051F300
锂离子电池充电器使用C8051F300

电池
文件: 总36页 (文件大小:381K)
中文:  中文翻译
下载:  下载PDF数据表文档文件
AN137  
LITHIUM ION BATTERY CHARGER USING C8051F300  
Relevant Devices  
Key Points  
On-chip high-speed, 8-bit ADC provides supe-  
rior accuracy in monitoring charge voltage  
(critical to prevent overcharging in Li-Ion  
applications), maximizing charge effectiveness  
and battery life.  
This application note applies to the following devices:  
C8051F300  
Introduction  
Driven by the need for untethered mobility and  
ease of use, many systems rely on rechargable bat-  
teries as their primary power source. The battery  
charging circuitry for these systems is typically  
implemented using a fixed-function IC to control  
the charging current/voltage profile.  
On-chip PWM provides means to implement  
buck converter with a very small external  
inductor.  
On-chip Temp sensor provides an accurate and  
stable drive voltage for determining battery  
temperature. An external RTD (resistive tem-  
perature device) can also be used via the flexi-  
ble analog input AMUX.  
The C8051F30x family provides a flexible alterna-  
tive to fixed-function battery chargers. This appli-  
cation note discusses how to use the C8051F30x  
family in Li-Ion battery charger applications. The  
Li-Ion charging algorithms can be easily adapted to  
other battery chemistries, but an understanding of  
other battery chemistries is required to ensure  
proper charging for those chemistries.  
A single C8051F30x platform provides full  
product range for multi-chemistry chargers,  
expediting time to market and reducing inven-  
tory.  
Figure 1. Lithium Ion Battery Charge Block Diagram.  
V Pos (+)  
LDO  
Buck  
Converter  
PWM Out  
8051F30x  
AIN  
Resistor  
Divider  
LED  
Li-Ion  
Cells  
Cygnal  
Integrated  
Products  
8k FLASH, PWM,  
Temp Sensor,  
Precision Time Base  
V Neg (-)  
Sense Resistor  
Rev. 1.2 12/03  
Copyright © 2003 by Silicon Laboratories  
AN137-DS12  
AN137  
batteries use a rate of change in voltage or tempera-  
ture to determine when to terminate.  
Charging Basics  
Batteries are exhaustively characterized to deter-  
mine safe yet time-efficient charging profiles. The  
optimum charging method for a battery is depen-  
dent on the battery’s chemistry (Li-Ion, NiMH,  
NiCd, SLA, etc.). However, most charging strate-  
gies implement a 3-phase scheme:  
Note that while charging a battery, most of the elec-  
trical energy is stored in a chemical process, but not  
all as no system is 100 percent efficient. Some of  
the electrical energy is converter to thermal energy,  
heating up the battery. This is fine until the battery  
reaches full charge at which time all the electrical  
energy is converted to thermal energy. In this case,  
if charging isn’t terminated, the battery can be  
damaged or destroyed. Fast chargers (chargers that  
charge batteries fully in less than a couple hours)  
compound this issue, as these chargers use a high  
charge current to minimize charge time. As one can  
see, monitoring a battery’s temperature is critical  
(especially for Li-Ion as they explode if over-  
charged). Therefore, the temperature is monitored  
during all phases. Charge is terminated immedi-  
ately if the temperature rises out of range.  
1. Low-current conditioning phase  
2. Constant-current phase  
3. Constant-voltage phase/charge termination  
All batteries are charged by transferring electrical  
energy into them (refer to the references at the end  
of this note for a battery primer). The maximum  
charge current for a battery is dependent on the bat-  
tery’s rated capacity (C). For example, a battery  
with a cell capacity of 1000mAh is referred to as  
being charged at 1C (1 times the battery capacity) if  
the charge current is 1000mA. A battery can be  
charged at 1/50C (20 mA) or lower if desired.  
However, this is a common trickle-charge rate and  
is not practical in fast charge schemes where short  
charge-time is desired.  
Li-Ion Battery Charger -  
Hardware  
Currently, Li-Ion batteries are the battery chemistry  
of choice for most applications due to their high  
energy/space and energy/weight characteristics  
when compared to other chemistries. Most modern  
Li-Ion chargers use the tapered charge termination,  
minimum current (see Figure 2), method to ensure  
the battery is fully charged as does the example  
code provided at the end of this note.  
Most modern chargers utilize both trickle-charge  
and rated charge (also referred to as bulk charge)  
while charging a battery. The trickle-charge current  
is usually used in the initial phases of charging to  
minimize early self heating which can lead to pre-  
mature charge termination. The bulk charge is usu-  
ally used in the middle phase where the most of the  
battery’s energy is restored.  
Buck Converter  
The most economical way to create a tapered ter-  
mination charger is to use a buck converter. A buck  
converter is a switching regulator that uses an  
inductor and/or a transformer (if isolation is  
desired), as an energy storage element to transfer  
energy from the input to the output in discrete  
packets (for our example we use an inductor; the  
capacitor in Figure 3 is used for ripple reduction).  
Feedback circuitry regulates the energy transfer via  
the transistor, also referred to as the pass switch, to  
maintain a constant voltage or constant current  
During the final phase of battery charge, which  
generally takes the majority of the charge time,  
either the current or voltage or a combination of  
both are monitored to determine when charging is  
complete. Again, the termination scheme depends  
on the battery’s chemistry. For instance, most Lith-  
ium Ion battery chargers hold the battery voltage  
constant, and monitor for minimum current. NiCd  
2
Rev. 1.2  
AN137  
Figure 2. Lithium Ion Charge Profile.  
Charge Voltage  
Charge Current  
Conditioning  
Phase  
Current regulation  
Voltage regulation  
Time  
within the load limits of the circuit. See Figure 3 voltage decreases and vice versa. Therefore, con-  
for details.  
trolling the duty cycles allows one to regulate the  
voltage or the current to within desired limits.  
Tapered Charger Using the F30x  
Figure 3 illustrates an example buck converter  
Selecting the Buck Converter Inductor  
using the ‘F30x. The pass switch is controlled via To size the inductor in the buck converter, one first  
the on-chip 8-bit PWM (Pulse Width Modulator) assumes a 50 percent duty cycle, as this is where  
output of the PCA. When the switch is on, current the converter operates most efficiently.  
will flow like in Figure 3A. The capacitor is  
charged from the input through the inductor. The Duty cycle is given by Equation 1, where T is the  
inductor is also charged. When the switch is period of the PWM (in our example T = 10.5µS).  
opened (Figure 3B), the inductor will try to main-  
ton  
tain its current flow by inducing a voltage as the  
current through an inductor can’t change instanta-  
neously. The current then flows through the diode  
and the inductor charges the capacitor. Then the  
cycle repeats itself. On a larger scale, if the duty  
cycle is decreased (shorter “on” time), the average  
DutyCycle = --------  
T
Equation 1. Duty Cycle.  
Figure 3. Buck Converter.  
(A)  
(B)  
Inductor  
Inductor  
Pass Switch On  
Pass Switch Off  
Shottky  
Diode  
Power  
Source  
Power  
Shottky  
Diode  
Capacitor  
Capacitor  
Battery  
Battery  
Source  
Rev. 1.2  
3
AN137  
With this established, select a PWM switching fre- To ensure accurate voltage and current measure-  
quency. As Equation 2  
ments, the algorithms use a two-point system cali-  
bration scheme. In this scheme, the user is expected  
to apply two known voltages and two known cur-  
rents, preferable, one point near ground and the  
other point near full-scale. The algorithm then  
takes these two points, calculates a slope and an  
offset for both the current and voltage channels,  
and stores the results in FLASH. All future conver-  
sions are scaled relative to these slope and offset  
calculations. Note that if an external amplifier is  
used for the current channel, it will need to be cali-  
brated with a similar two-point calibration scheme  
to ensure maximum accuracy.  
(Vi Vsat Vo)ton  
L = ----------------------------------------------------  
2Iomax  
Equation 2. Inductor Size.  
shows, the larger the PWM switching frequency,  
the smaller (and more cost effective) the inductor.  
Our example code configures the ‘F30x’s 8-bit  
hardware PWM to use the internal master clock of  
24.5MHz divided by 256 to generate a 95.7kHz  
switch rate.  
Temperature  
Now we can calculate the inductor’s size. Assum-  
ing V , the charging voltage, is 15V, V , the satu-  
i
sat  
To monitor the temperature, the algorithms use the  
on-chip temperature sensor. The sensor is left  
uncalibrated, but still provides a sufficiently accu-  
rate temperature measurement. For more accurate  
temperature measurement, one or two-point tem-  
perature calibration is required.  
ration voltage, is 0.5V, the desired output voltage,  
V is 4.2V, and I  
, the maximum output cur-  
0MAX  
o,  
rent, is 1500 mA, the inductor should be at least  
18µH.  
Note that the capacitor in this circuit is simply a  
ripple reducer. The larger it is the better as ripple is  
inversely proportional to the size of the cap. For  
more details on buck converters, refer to the refer-  
ences listed at the end of this note.  
An external temperature sensor can be used if  
desired. The AMUX can to be reconfigured to  
accommodate this additional input voltage.  
Current  
Li-Ion Battery Charger -  
Software  
The charge-current to the battery cells is monitored  
by taking a differential voltage reading across a  
The software example that follows demonstrates a small but accurate sense resistor. The current is  
Li-Ion battery charger using the C8051F300. The amplified through the on-chip PGA, digitized by  
F300 is designed for high-level languages like “C” the on-chip 8-bit ADC, and scaled accordingly via  
and includes an 8-bit 8051 based micro-controller, the slope and offset calibration coefficients. An  
an 8-bit 500 ksps ADC, 8k FLASH, an 8-bit and external gain stage may be necessary if more reso-  
16-bit PWM, and a 2% accurate oscillator all on- lution is desired for the current measurement.  
chip. The algorithms discussed are written entirely  
in “C” making them easily portable. Refer to the Voltage  
F300’s datasheet for a full description of the  
device.  
The battery’s voltages are divided down and moni-  
tored via external resistors. Note that this example  
uses the supply voltage as the ADC voltage refer-  
ence. Any monitored voltage above the reference  
voltage must be divided down for accurate moni-  
Calibration  
4
Rev. 1.2  
AN137  
toring. If a more accurate reference is required, an battery’s current condition and starts charging from  
external voltage reference can be used. Adjustment that point.  
to the divide resistors must be made accordingly.  
Conclusion  
Charging - Phase1  
The C8051F300’s high level of analog integration,  
small form-factor, integrated FLASH memory, and  
In phase 1, (for description purposes, we assume  
low power consumption makes it ideal for flexible  
the battery is initially discharged), the ‘F30x regu-  
next generation battery charging applications. This  
lates the battery’s current to I  
(typi-  
LOWCURRENT  
application note discussed how to use the  
C8051F30x family in Lithium Ion battery charger  
applications. Example code is provided as well.  
cally 1/50 C) until the battery’s voltage reaches  
V
. Note that the battery’s charge cur-  
MINVOLTBULK  
rent is current limited to I  
to ensure  
LOWCURRENT  
safe initial charge and to minimize battery self-  
heating. If at any time the temperature increases out  
of limit, charging is halted.  
References  
Maxim Integrated Product, “DC-DC Converter  
Tutorial”.  
Charging - Phase 2  
Martinez, Carlos and Drori, Yossi and Ciancio,  
Joe, “AN126 Smart Battery Primer”, Xicor, Octo-  
ber 1999.  
Once the battery reaches V  
the  
MINVOLTBULK  
charger enters phase 2, where the battery’s algo-  
rithm controls the PWM pass switch to ensure the  
output voltage provides a constant charge-current  
I
to the battery (rate or bulk current is usually  
BULK  
1C and is definable in the header file as is  
I
and V ).  
LOWCURRENT  
MINVOLTBULK  
Charging - Phase 3  
After the battery reaches V  
(typically 4.2 V in  
Top  
single cell charger), the charger algorithm enters  
phase 3, where the PWM feeds back and regulates  
the battery’s voltage. In phase 3, the battery contin-  
ues to charge until the battery’s charge current  
reaches I  
, after which, the battery is  
MINIBULKl  
charged for an additional 30 minutes and then  
charge terminates. Phase 3 typically takes the  
majority of the charging time.  
Note that in most practical applications, such as a  
portable PC, the batteries may be in any of the three  
phases when charging is activated. This doesn’t  
really affect the charger as it simply monitor’s the  
Rev. 1.2  
5
AN137  
Appendix  
Figure 4. 1 Cell Battery Charger Schematic.  
6
Rev. 1.2  
AN137  
Figure 5. 1 Cell Buck Converter Schematic.  
Rev. 1.2  
7
AN137  
Figure 6. main() Flow Chart.  
main()  
Config_F300()  
CalibrateADCfor  
Measurement()  
Enable Interrupts  
Infinite  
Loop  
Yes/No  
Clear Termination Flags  
Clear Charge Status Flags  
No  
SW0  
Pressed?  
?
Yes  
Yes  
No  
Error  
Detected  
?
No  
Status = BULK  
?
Error  
Detected  
?
Yes  
Turn on LED0  
Turn off LED0, Error  
BULK_charge()  
Infinite Loop  
Yes/No  
No  
Status =  
LOWCURRENT  
?
Yes  
LOWCURRENT_charge()  
8
Rev. 1.2  
AN137  
Figure 7. CalibrateADCforMeasurement() Flow Chart.  
CalibrateADCforMearurement()  
SW0  
No  
No  
Pushed  
?
Yes  
SW0  
Pushed  
?
Setup ADC0's AMUX,  
Throughput, Gain, for near  
zero-scale voltage cal point  
Yes  
Setup ADC0's AMUX,  
Throughput, Gain, for near  
zero-scale Current cal point  
Acquire 16-bit  
Measurement  
Setup ADC0's AMUX,  
Throughput, Gain, for near  
full-scale voltage cal point  
Acquire 16-bit  
Measurement  
Setup ADC0's AMUX,  
Throughput, Gain, for near  
full-scale Current cal point  
Acquire16-bit  
Measurement  
Calculate Voltage Slope  
Coefficient  
Acquire16-bit  
Measurement  
Calculate Voltage Offset  
Coefficient  
Calculate Current Slope  
Coefficient  
Erase Memory Page  
0x1A00  
Calculate Current Offset  
Coefficient  
Store Voltage Offset and  
Slope Coefficients in  
FLASH Memory  
Store Current Offset and  
Slope Coefficients in  
FLASH Memory  
END  
Rev. 1.2  
9
AN137  
Figure 8. Monitor_Battery() Flow Chart.  
Monitor_Battery()  
Measurement  
Type  
?
Temperature  
Stop PWM  
Current  
Charge Voltage  
AMUX = Volt  
Battery Voltage  
Stop PWM  
AMUX = Current  
AMUX = Temperature  
AMUX = Volt  
AV = 0  
I = 0  
No  
I≤10  
?
Voltage w/ or w/out PWM  
Current  
Temperature  
Calculate Voltage w/  
Calculate Current w/  
Calibration Coefficients  
Calculate Temperature w/  
Calibration Coefficients  
Yes  
Calibration Coefficients  
Start ADC0  
No  
ADC0 Done?  
Yes  
AV = AV + ADC0  
Turn PWM on  
Return Desired Parameter  
END  
AV = AV/10  
10  
Rev. 1.2  
AN137  
Figure 9. Bulk_Charge() Flow Chart (Part 1).  
Bulk_Charge()  
Start PWM w/ Zero Output  
Status = const_C  
T
No  
No  
Within Limits  
?
Yes  
V
<max_V &  
> min_Bulk  
?
Yes  
Set Appropriate Flags  
Calculate bulk_finish_time  
Green LED On  
Status =  
BULK & No  
Error?  
No  
No  
Yes  
Status =  
const_c  
?
Yes  
Regulate Battery Current  
Read Charge Voltage  
Charge  
Yes  
Voltage Within  
Limits  
?
Change Status from  
const_C to const_V  
No  
B
C
A
D
Rev. 1.2  
11  
AN137  
Figure 10. BULKCurrent() Flow Chart (Part 2).  
B
C
A
D
No  
Status =  
const_V  
?
Yes  
Regulate Voltage()  
Time  
Overflow  
?
Yes  
Stop PWM  
& Flag Error  
No  
Yes  
Temp.  
Overflow  
?
Stop PWM  
No  
& Flag Error  
No  
60 Sec.  
Over  
?
Yes  
const_V,  
NOT Delay & Current  
Below Threshold  
?
No  
Yes  
Calculate bulk_finish_time  
Status = Delay  
Delay  
No  
Time  
Over  
?
Yes  
Stop PWM  
Status = const_C  
Status = LOWCURRENT  
Green LED Off  
END  
12  
Rev. 1.2  
AN137  
Figure 11. LowCurrent_Charge() Flow Chart.  
LOWCURRENT_charge()  
No  
V
<BulkThreshold  
?
ResetTimeBase()  
Yes  
Prepare Flags to enter  
Bulk Mode  
Calculate Finish_time  
No  
Charge  
Voltage  
Within Limits  
?
No ERROR &  
LOWCURRENT =1  
?
Yes  
Change Status  
from const_C to  
const_V  
Yes  
No  
No  
Temp  
within Limits  
?
Regulate Current  
Yes  
No  
No  
V
<max_V  
?
Status = const_V  
Yes  
Yes  
Green LED Blinking  
Regulate Voltage  
Status = Delay  
Lowcurrent  
Finish Time  
reached?  
Yes  
Green LED Off  
END  
Stop PWM  
No  
and flag error  
Rev. 1.2  
13  
AN137  
Figure 12. Turn_PWM_Off() Flow Chart.  
Turn_PWM_Off()  
CEX0  
Counter  
<0x0F?  
No  
Yes  
Increment CEX0  
Counter  
CEX0  
Counter  
<0x0F?  
Yes  
No  
Disable PWM Mode  
END  
14  
Rev. 1.2  
AN137  
Figure 13. Measure() Flow Chart.  
measure()  
Set accumulator and  
counter i variables to zero  
Clear End of Conversion  
Flag  
Start New Conversion  
Conversion  
Complete  
?
No  
Yes  
accumulator =  
accumulator + ADC0  
Increment i  
No  
i = 0  
?
Yes  
Return 16-bit  
Measurement  
END  
Rev. 1.2  
15  
AN137  
Figure 14. Regulate_Voltage() Flow Chart.  
Regulate_Voltage()  
Measure Battery's  
voltage  
Voltage <  
VOLT_BULK &  
PCA not max  
?
No  
Yes  
No  
Voltage >  
VOLT_BULK &  
PCA not 0  
Make Duty Cycle Larger  
Yes  
Make Duty Cycle Smaller  
Voltage  
< VOLT_BULK + Tolerence  
& > VOLT_BULK  
?
No  
Yes  
END  
16  
Rev. 1.2  
AN137  
Figure 15. Regulate_Current() Flow Chart.  
Regulate_Current()  
Measure Current  
Current <  
No  
passed current &  
PCA not max  
?
Yes  
No  
Current >  
passed current &  
PCA not 0  
Make Duty Cycle Larger  
Yes  
Make Duty Cycle Smaller  
No  
Current =  
passed value  
?
Yes  
Monitor Voltage  
w/ PWM off  
No  
Voltage <  
VOLT_LOWCURRENT  
± Tolerence  
?
Yes  
CHARGE_STATUS =  
const_V  
END  
Rev. 1.2  
17  
AN137  
Figure 16. PCA_OVERFLOW_ISR() Flow Chart.  
PCA_OVERFLOW_ISR()  
Reset PCA Counter and  
PCA Interrupts  
Decrement time.count  
No  
0 = time.count  
Yes  
Reset time.count to  
overflow value  
Increment time.sec  
No  
60 = time.sec  
?
Yes  
Reset time.sec  
Increment time.min  
LOW  
CURRENT  
charge &  
no errors  
?
No  
No  
60 = time.min  
?
Yes  
Increment time.hour  
Yes  
odd  
second  
?
No  
Reset time.min  
24 = time.hour  
Yes  
No  
Turn on LED  
Yes  
Turn Off LED  
Reset time.hour  
END  
18  
Rev. 1.2  
AN137  
//-----------------------------------------------------------------------------  
//  
// Copyright 2002 Cygnal Integrated Products, Inc.  
//  
// Filename:  
LIION_BC_MAIN.h  
// Target Device: 8051F300  
// Created:  
// Created By:  
11 SEP 2002  
DKC  
// Tool chain: KEIL Eval C51  
//  
// This header file is used to define all preprocessor directives, prototypes,  
// and global variable for LIION_BC_MAIN.c.  
//  
// The user should modify this header file before proceeding as key  
//  
//  
battery parameter limits are set here.  
//-----------------------------------------------------------------------------  
// Function Prototypes  
//-----------------------------------------------------------------------------  
void Config_F300(void);  
void Reset_Time_Base(void);  
void CalibrateADCforMeasurement(void);  
void Regulate_Current(int);  
void Regulate_Voltage(void);  
void Turn_PWM_Off(void);  
int Monitor_Battery(unsigned char);  
void Bulk_Charge(void);  
void Lowcurrent_Charge(void);  
unsigned int Measure(void);  
void Delay_Loop(void);  
//-----------------------------------------------------------------------------  
// UNIONs, STRUCTUREs, and ENUMs  
//-----------------------------------------------------------------------------  
typedef union LONG {  
long l;  
// byte-addressable LONG  
unsigned char b[4];  
} LONG;  
typedef union INT {  
int i;  
// byte-addressable INT  
unsigned char b[2];  
} INT;  
typedef struct  
{
unsigned long int t_count;  
int sec;  
int min;  
// global seconds  
// global minutes  
// global hour  
int hour;  
}time_struct;  
//-----------------------------------------------------------------------------  
// Global Variable Definitions  
Rev. 1.2  
19  
AN137  
//-----------------------------------------------------------------------------  
time_struct TIME;  
// Global Struct to Track Time  
// Global Variable to Track Termination  
// Global Variable to Track Charging  
// 0x0A0A Default value, for later use  
// Volt Slope Register  
char bdata TERMINATION;  
char bdata CHARGE_STATUS;  
INT code CHECK_BYTE  
LONG code VOLT_SLOPE  
LONG code VOLT_OFFSET  
_at_ 0x1A00;  
_at_ 0x1A60;  
_at_ 0x1A64;  
// Volt Offset Register  
LONG code I_NOAMP_SLOPE _at_ 0x1A70;  
LONG code I_NOAMP_OFFSET _at_ 0x1A74;  
LONG temp_LONG_1,temp_LONG_2;  
// Current Slope Register,ext. amp off  
// Current Offset Register,ext. amp.off  
// Temporary Storage Variables  
// Temporary Storage Variables  
INT temp_INT_1,temp_INT_2;  
//-----------------------------------------------------------------------------  
// Bit maskable CHARGE STATUS Register Definition  
//-----------------------------------------------------------------------------  
sbit BULK  
= CHARGE_STATUS^0;  
// bit 0 : BULK charge status bit  
sbit LOWCURRENT = CHARGE_STATUS^1;  
// bit 1 : LOWCURRENT charge status bit  
// bit 2 : ERROR before/during charging  
// bit 3 : charged w/ constant VOLTAGE  
// bit 4 : charged w/ constant CURRENT  
// bit 5 : BULK charge DELAY for LiIon  
sbit ERROR  
sbit CONST_V  
sbit CONST_C  
sbit DELAY  
= CHARGE_STATUS^2;  
= CHARGE_STATUS^3;  
= CHARGE_STATUS^4;  
= CHARGE_STATUS^5;  
//  
// bit 6 : Lowcurrent charge is  
// terminated; battery is charged  
// bit 7 : Not Currently used  
after CURRENT threshold detection  
sbit READY  
sbit FREE1  
= CHARGE_STATUS^6;  
= CHARGE_STATUS^7;  
//-----------------------------------------------------------------------------  
// Bit Maskable TERMINATION Register Definition  
//-----------------------------------------------------------------------------  
sbit TEMP_MIN = TERMINATION^0;  
sbit TEMP_MAX = TERMINATION^1;  
// bit 0 : minimum TEMPERATURE overflow  
// bit 1 : maximum TEMPERATURE overflow  
// bit 2 : minimum CURRENT overflow  
// bit 3 : maximum CURRENT overflow  
// bit 4 : maximum time overflow  
// bit 5 : maximum VOLTAGE overflow  
// bit 6 : minimum VOLTAGE overflow  
// bit 7 : Not Currently used  
sbit I_MIN  
sbit I_MAX  
= TERMINATION^2;  
= TERMINATION^3;  
sbit TIME_MAX = TERMINATION^4;  
sbit VOLT_MAX = TERMINATION^5;  
sbit VOLT_MIN = TERMINATION^6;  
sbit FREE2  
= TERMINATION^7;  
//-----------------------------------------------------------------------------  
// Bit maskable PORT Definitions  
//-----------------------------------------------------------------------------  
sbit SDA  
sbit SCL  
sbit CEX0  
sbit LED0  
sbit SW0  
= P0 ^ 0;  
= P0 ^ 1;  
= P0 ^ 2;  
= P0 ^ 3;  
= P0 ^ 7;  
// bit 0 : SDA In/Output, Pin P0.  
// bit 1 : SCL Output, Pin P1.  
// bit 2 : PWM Output, Pin P2.  
// bit 3 : LED0, Pin P0.3  
// bit 7 : Switch0, Pin P0.7  
// AMUX Selections; Analog Inputs  
#define TBAT  
#define IBAT  
#define VBAT  
0xF8;  
0x65;  
0xF6;  
// bit 4 : Temp.  
// bit 5 : Current Ch.; Analog In  
// bit 6 : Voltage Ch.; Analog In  
Ch.; Analog In  
//-----------------------------------------------------------------------------  
// 8051F300 PARAMETERS  
//-----------------------------------------------------------------------------  
#define SYSCLK  
24500000  
// System clock frequency  
20  
Rev. 1.2  
AN137  
#define TEMP_SENSOR_GAIN  
#define TEMP_GAIN  
#define CURRENT_GAIN  
#define VREF  
#define SCRATCH_PAGE  
#define PWM_CLOCK  
3300  
2
4
3200  
0x1C00  
SYSCLK/255  
// Temp Sensor Gain in (uV / degC)  
// PGA gain setting  
// PGA gain setting  
// ADC Voltage Reference (mV)  
// FLASH page used for temp storage  
// PWM frequency is 96 kHz  
//-----------------------------------------------------------------------------  
// Calibration/Calculation PARAMETERS  
//-----------------------------------------------------------------------------  
#define V1_CAL  
#define V2_CAL  
#define I1_CAL  
#define I2_CAL  
#define RSENSE  
#define RESB  
67  
2800  
67  
133  
1
20  
// 1st cal point for 2 point cal.  
// 2nd cal point for 2 point cal.  
// 1st cal point for 2 point cal.  
// 2nd cal point for 2 point cal.  
// RSENSE is assumed to be 1/2 ohm  
// 10k Ohms, Voltage Divide Resistor  
// 20k Ohms, Voltage Divide Resistor  
#define RESAB  
30  
#define TEMP_SLOPE ((long) TEMP_GAIN * TEMP_SENSOR_GAIN * 65536 / 100 / VREF)  
// An estimate of the Temperature<SLOPE>  
// in [tenth codes / K]  
// The temperature measurement is  
// within 3 degrees of accuracy.  
//-----------------------------------------------------------------------------  
// Monitor_Battyer Switch PARAMETERS  
//-----------------------------------------------------------------------------  
#define TEMPERATURE  
#define VOLTAGE  
#define VOLTAGE_PWM_OFF  
#define CURRENT  
7
5
3
1
// Value for Switch Statement  
// Value for Switch Statement  
// Value for Switch Statement  
// Value for Switch Statement  
//-----------------------------------------------------------------------------  
// Battery/Pack Parameters  
//-----------------------------------------------------------------------------  
#define CELLS  
1
150  
4200  
// Number of cells in the battery pack  
// mAh, Battery Capacity (LiIon)  
// mV, Nominal Charge Voltage  
#define CAPACITY  
#define LiIon_CELL_VOLT  
#define I_BULK  
(unsigned int)(CAPACITY)  
#define I_LOWCURRENT  
#define VOLT_BULK  
(unsigned int)(CAPACITY/4)  
(unsigned int)(LiIon_CELL_VOLT)  
#define VOLT_LOWCURRENT  
#define VOLT_TOLERANCE  
(unsigned int)(LiIon_CELL_VOLT)  
(unsigned int)(LiIon_CELL_VOLT/100)// 1 Percent Acc  
#define CURRENT_TOLERENCE (unsigned int)(CAPACITY/10)  
// 10 Percent Acc  
//-----------------------------------------------------------------------------  
// Battery Characteristics: Charge TERMINATION Limits  
//-----------------------------------------------------------------------------  
#define MIN_TEMP_ABS  
#define MAX_TEMP_ABS  
26300  
32300  
// Abs. min. TEMPERATURE = -10 C, 263K  
// Abs. max. TEMPERATURE = 50C, 323K:  
Rev. 1.2  
21  
AN137  
#define MIN_VOLT_BULK  
#define MAX_VOLT_ABS  
#define MIN_I_BULK  
3000  
// Minimum BULK Voltage  
(unsigned int)(CELLS * LiIon_CELL_VOLT)  
(unsigned int)(CAPACITY/4)  
#define MAX_TIME_LOWCURRENT 30  
// Max Lowcurrent Charge Time = 90min  
// Maximum BULK Charge Time = 90 min  
#define MAX_TIME_BULK  
#define BULK_TIME_DELAY  
// END OF FILE  
90  
//  
at 1C CURRENT  
30  
// DELAY = 30min after “MIN_I_BULK”  
22  
Rev. 1.2  
AN137  
//-----------------------------------------------------------------------------  
//  
// Copyright 2002 Cygnal Integrated Products, Inc.  
//  
// Filename:  
LIION_BC_MAIN.c  
// Target Device: 8051F300  
// Created:  
// Created By:  
// Tool chain:  
//  
11 SEP 2002  
DKC  
KEIL Eval C51  
// This is a stand alone battery charger for a Lithium ION battery.  
// It utilizes a buck converter, controlled by the on-chip 8-bit PWM,  
// to provide constant current followed by constant voltage battery charge.  
//  
//-----------------------------------------------------------------------------  
// Includes  
//-----------------------------------------------------------------------------  
#include <c8051f300.h>  
#include “LIION_BC_MAIN.h”  
// Battery Hearder File  
//-----------------------------------------------------------------------------  
// Functions  
//-----------------------------------------------------------------------------  
void Config_F300(void)  
{ RSTSRC  
XBR0  
= 0x02;  
= 0x70;  
= 0x44;  
= 0x40;  
// Enable VDD Monitor  
// Skip P0.4,5,6; they’re analog In  
// Enable SMBus on P0.0, P0.1, and CEX0  
// as PWM at P0.2  
XBR1  
XBR2  
// Enable crossbar and weak pull-ups  
P0MDOUT = 0x0C;  
// Set P0.2 & P0.3 output to push-pull  
// Configure P0.4,5,6 as Analog Inputs  
P0MDIN  
OSCICN  
ADC0CN  
= 0x8F;  
= 0x07;  
= 0xC0;  
// Set SYSCLK to 24.5MHz, internal osc.  
// Turn on the ADC Module;  
//  
enable low power mode for settling  
REF0CN  
= 0x0C;  
// Configure ADC’s to use VDD for  
//  
//  
Voltage Reference,  
Enable On-chip Temperature Sensor  
//-----------------------------------------------------------------------------  
// PCA Configuration  
//-----------------------------------------------------------------------------  
PCA0MD  
PCA0MD  
= 0x00;  
= 0x08;  
// Disable WDT  
// Set PWM Time base = SYSCLK  
PCA0L  
PCA0H  
= 0x00;  
= 0x00;  
// Initialize PCA Counter to Zero  
PCA0CN  
= 0x40;  
// Enable PCA Counter  
// Clear PCA Counter Overflow flag  
//Module 0  
PCA0CPM0 = 0x00;  
PCA0CPL0 = 0xF0;  
PCA0CPH0 = 0xF0;  
// Configure CCM0 to 8-bit PWM mode  
// Initialize PCA PWM to small duty cycle  
// 0xF0 Ensures a Soft Initial Charge  
Rev. 1.2  
23  
AN137  
//Module 1  
PCA0CPM1 = 0x49;  
PCA0CPL1 = 0xFF;  
// Configure Module 1 as software timer  
// Initialize to 255 so that Interrupt  
//  
is generated when PCA ends  
// 8-bit PWM Cycle  
PCA0CPH1 = 0x00;  
// PCA0CPH is the high byte of the  
//  
Output Compare Module  
EIE1  
= 0x08;  
// Enable PCA Overflow Interrupt  
}
//-----------------------------------------------------------------------------  
// Reset_Time_Base - Resets all Time Counting Values  
//-----------------------------------------------------------------------------  
void Reset_Time_Base()  
{
TIME.sec  
TIME.min  
TIME.hour  
= 0x00;  
= 0x00;  
= 0x00;  
TIME.t_count = PWM_CLOCK;  
}
//-----------------------------------------------------------------------------  
// Delay - This is a Delay to permit time for Switches to Debounce  
//-----------------------------------------------------------------------------  
void Delay_Loop (void)  
{
long i=0;  
for (i=0;i<100000;i++);  
}
//-----------------------------------------------------------------------------  
// Initialize CalibrateADCforVoltageMeasurement  
//-----------------------------------------------------------------------------  
// This function calibrates the voltage channel and stores the calibration  
// coefficients in the parameters volt_slope and volt_offset.  
//  
void CalibrateADCforMeasurement()  
// This calibration routine uses a 2 point cal.  
{ unsigned char xdata *pwrite;  
EA = 0;  
// FLASH write pointer  
// Disable All Interrupts  
// Wait until 1st calibration voltage is ready for cal  
while (SW0 == 1);  
Delay_Loop();  
// Wait until SW0 pushed  
// Wait for Switch Bounce  
// Once ready, Get the first calibration voltage  
AMX0SL = VBAT;  
// Select appropriate input for AMUX  
ADC0CF = (SYSCLK/5000000) << 3;  
ADC0CF &=0xF8;  
ADC0CF |= 0x01;  
// ADC conversion clock = 5.0MHz  
// Clear any Previous Gain Settings  
// PGA gain = 1  
temp_INT_1.i = Measure();  
// Wait until 2nd calibration voltage is ready for cal  
while (SW0 == 1);  
Delay_Loop();  
// Wait until SW0 pushed  
// Wait for Switch Bounce  
24  
Rev. 1.2  
AN137  
// Once ready, Get the 2nd calibration voltage  
AMX0SL = VBAT;  
//  
Change Mux for second point  
temp_INT_2.i = Measure();  
// Calculate the SLOPE  
// V1 and V2 are in tenth of a degree  
temp_LONG_1.l = (unsigned)(temp_INT_2.i-temp_INT_1.i);  
temp_LONG_1.l *= (unsigned)100;  
// Account for Math Truncation Error  
temp_LONG_1.l /= (unsigned)(V2_CAL - V1_CAL);  
// Calculate the OFFSET  
temp_LONG_2.l = (unsigned)temp_INT_1.i;  
temp_LONG_2.l -= (signed)(temp_LONG_1.l * V1_CAL/100);  
temp_LONG_1.l = 2050;  
temp_LONG_2.l = 0;  
// If no cal. use these  
// as default values  
// Erased memory at page 0x1A00  
pwrite = (char xdata *)&(CHECK_BYTE.b[0]);  
PSCTL = 0x03;  
// MOVX writes target FLASH memory;  
// FLASH erase operations enabled  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
*pwrite = 0x00;  
// FLASH key sequence #1  
// FLASH key sequence #2  
// initiate PAGE erase  
// Write the Volt SLOPE and OFFSET to Flash  
PSCTL = 1;  
// MOVX writes to Flash  
pwrite = (char xdata *)&(VOLT_SLOPE.b[0]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_1.b[0];  
pwrite = (char xdata *)&(VOLT_SLOPE.b[1]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_1.b[1];  
pwrite = (char xdata *)&(VOLT_SLOPE.b[2]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_1.b[2];  
pwrite = (char xdata *)&(VOLT_SLOPE.b[3]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_1.b[3];  
pwrite = (char xdata *)&(VOLT_OFFSET.b[0]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_2.b[0];  
pwrite = (char xdata *)&(VOLT_OFFSET.b[1]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_2.b[1];  
pwrite = (char xdata *)&(VOLT_OFFSET.b[2]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_2.b[2];  
Rev. 1.2  
25  
AN137  
pwrite = (char xdata *)&(VOLT_OFFSET.b[3]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_2.b[3];  
PSCTL = 0;  
// MOVX writes target XRAM  
//-----------------------------------------------------------------------------  
// Initialize CalibrateADCforCurrentMeasurement_NOAMP  
//-----------------------------------------------------------------------------  
// This function calibrates the current channel with no external amp  
// and stores the calibration coefficients in the  
// parameters i_noamp_slope and i_noamp__offset.  
//  
// This calibration routine uses a 2 point cal.  
// Wait until calibration voltage is ready for cal  
while (SW0 == 1);  
Delay_Loop();  
// Wait until SW0 pushed  
// Wait for Switch Bounce  
// Once ready, Get the first calibration voltage  
AMX0SL = IBAT;  
// Select appropriate input for AMUX  
ADC0CF = (SYSCLK/5000000) << 3;  
ADC0CF &=0xF8;  
ADC0CF |= 0x03;  
// ADC conversion clock = 5.0MHz  
// Clear any Previous Gain Settings  
// Set PGA gain = 4  
temp_INT_1.i = Measure();  
temp_INT_1.i *= 2;  
// Acquire 16-bit Conversion  
// Account for Differential Mode  
// Wait until 2nd calibration voltage is ready for cal  
while (SW0 == 1);  
Delay_Loop();  
// Wait until SW0 pushed  
// Wait for Switch Bounce  
// Once ready, Get the 2nd calibration voltage  
temp_INT_2.i = Measure();  
temp_INT_2.i *=2;  
// Acquire 16-bit Conversion  
// Account for Differential Mode  
// Calculate the SLOPE  
temp_LONG_1.l = (unsigned)(temp_INT_2.i - temp_INT_1.i);  
temp_LONG_1.l *= (unsigned)100;  
// Account for Math Truncation Error  
temp_LONG_1.l /= (unsigned)(I2_CAL - I1_CAL);  
temp_LONG_1.l /= (unsigned)CURRENT_GAIN;// Account for Gain  
// Calculate the OFFSET  
temp_LONG_2.l = (signed)(temp_INT_1.i/CURRENT_GAIN);  
temp_LONG_2.l -= (signed)(temp_LONG_1.l * V1_CAL/100);  
temp_LONG_1.l = 2050;  
temp_LONG_2.l = 0;  
// If no cal. use these  
// as default values  
// Memory at 0x1A00 is already erased  
// Write the Volt SLOPE and OFFSET to Flash  
PSCTL = 1;  
// MOVX writes to Flash  
pwrite = (char xdata *)&(I_NOAMP_SLOPE.b[0]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_1.b[0];  
pwrite = (char xdata *)&(I_NOAMP_SLOPE.b[1]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_1.b[1];  
pwrite = (char xdata *)&(I_NOAMP_SLOPE.b[2]);  
26  
Rev. 1.2  
AN137  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_1.b[2];  
pwrite = (char xdata *)&(I_NOAMP_SLOPE.b[3]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_1.b[3];  
pwrite = (char xdata *)&(I_NOAMP_OFFSET.b[0]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_2.b[0];  
pwrite = (char xdata *)&(I_NOAMP_OFFSET.b[1]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_2.b[1];  
pwrite = (char xdata *)&(I_NOAMP_OFFSET.b[2]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_2.b[2];  
pwrite = (char xdata *)&(I_NOAMP_OFFSET.b[3]);  
FLKEY = 0xA5;  
FLKEY = 0xF1;  
// enable flash write  
*pwrite = temp_LONG_2.b[3];  
PSCTL = 0;  
// MOVX writes target XRAM  
}
//-----------------------------------------------------------------------------  
// Measure  
//-----------------------------------------------------------------------------  
//  
// This routine averages 65536 ADC samples and returns a 16-bit unsigned  
// result.  
//  
unsigned int Measure (void)  
{
unsigned i;  
// sample counter  
unsigned long accumulator=0L;  
// here’s where we integrate the  
// ADC samples  
// read the ADC value and add to running total  
i = 0;  
do {  
AD0INT = 0;  
// clear end-of-conversion indicator  
AD0BUSY = 1;  
// initiate conversion  
while(!AD0INT);  
accumulator += ADC0;  
i++;  
// wait for conversion to complete  
// read adc value and accumulate  
// update counter  
} while (i != 0x0000);  
// the accumulator now contains 16 added bits of which 8 are usable  
return (unsigned int) (accumulator >> 8);  
}
//-----------------------------------------------------------------------------  
// Regulate_Current  
//-----------------------------------------------------------------------------  
// This routine monitors the battery’s current and adjusts  
// the PWM (i.e. duty cycle) to keep the current at a known value  
Rev. 1.2  
27  
AN137  
//  
void Regulate_Current(int passed_current)  
{ unsigned int temp = 0;  
do{  
temp = Monitor_Battery(CURRENT);  
// Measure Current  
if (temp < passed_current)  
PCA0CPH0--;  
if (temp > passed_current)  
PCA0CPH0++;  
}while ((temp < (passed_current - CURRENT_TOLERENCE)) ||  
(temp > (passed_current + CURRENT_TOLERENCE)));  
// I_BULK or I_LOWCURRENT is set now  
temp = Monitor_Battery(VOLTAGE_PWM_OFF);  
// If VOLTAGE within range,  
// change from constant CURRENT charge  
// mode to constant VOLTAGE charge mode  
if ((temp >= (VOLT_LOWCURRENT - VOLT_TOLERANCE)) &&  
(temp <= (VOLT_LOWCURRENT + VOLT_TOLERANCE)))  
{
CONST_C = 0;  
CONST_V = 1;  
}
}
//-----------------------------------------------------------------------------  
// Regulate_Voltage  
//-----------------------------------------------------------------------------  
// This routine monitors the battery’s voltage and adjusts  
// the PWM (i.e. duty cycle) to keep the voltage at a known value  
//  
void Regulate_Voltage(void)  
{ unsigned int temp = 0;  
// set VOLT_BULK (with “soft start”)  
do{  
temp = Monitor_Battery(VOLTAGE);  
if (temp < VOLT_BULK)  
PCA0CPH0--;  
if (temp > VOLT_BULK)  
PCA0CPH0++;  
}while ((temp < (VOLT_BULK - VOLT_TOLERANCE)) ||  
(temp > (VOLT_BULK + VOLT_TOLERANCE)));  
// VOLTAGE is set now  
}
//-----------------------------------------------------------------------------  
// Turn_PWM_Off  
//-----------------------------------------------------------------------------  
// This routine peforms a soft charge turn off by taking the PWM’s  
// duty cycle slowly to zero.  
//  
void Turn_PWM_Off(void)  
{
28  
Rev. 1.2  
AN137  
do{  
if (PCA0CPH0 < 0xF0)  
PCA0CPH0++;  
}while (PCA0CPH0 < 0xF0);  
// Duty Cycle is now small and safe to turn off.  
PCA0CPM0 = 0x00;  
// Disable PWM  
}
//-----------------------------------------------------------------------------  
// Monitor_Battery  
//-----------------------------------------------------------------------------  
// This routine acts as a switch when gathering different conversion types.  
// It adjusts the throughput, adjust the AMUX and returns the current in mA,  
// voltage in mV, and temperature in C, 2% accurate.  
//  
int Monitor_Battery(unsigned char value)  
{
char i;  
unsigned long av =0;  
long signed result;  
ADC0CF = (SYSCLK/5000000) << 3;  
ADC0CF &= 0xF8;  
// ADC conversion clock = 5.0MHz  
// Clear any Previous Gain Settings  
switch (value)  
{
case TEMPERATURE:  
Turn_PWM_Off();  
AMX0SL = TBAT;  
ADC0CF |= 0x02;  
break;  
// Turn PWM Off  
// Select appropriate input for AMUX  
// Set PGA gain = 2  
case VOLTAGE:  
AMX0SL = VBAT;  
ADC0CF |= 0x01;  
break;  
// Select appropriate input for AMUX  
// Set PGA gain = 1  
case VOLTAGE_PWM_OFF:  
Turn_PWM_Off();  
AMX0SL = VBAT;  
ADC0CF |= 0x01;  
break;  
// Turn PWM Off  
// Select appropriate input for AMUX  
// Set PGA gain = 1  
case CURRENT:  
AMX0SL = IBAT;  
ADC0CF |= 0x03;  
break;  
// Select appropriate input for AMUX  
// Set PGA gain = 4  
}
//Compute average of next 10 A/D conversions  
for(av=0,i=10;i;--i){  
AD0INT = 0;  
// clear end-of-conversion indicator  
AD0BUSY = 1;  
while(!AD0INT);  
av = av+ADC0;  
// initiate conversion  
// wait for conversion to complete  
}
Rev. 1.2  
29  
AN137  
av = av/10;  
av = av<<8;  
// Compute the average  
// Convert to 16-bit conversion  
// ...to account for 16-bit cal.  
//  
coefficients  
PCA0CPM0 = 0x42;  
// Turn on PWM  
switch (value)  
{ case TEMPERATURE:  
result = (long) av * 1000/TEMP_SLOPE;  
break;  
case VOLTAGE:  
case VOLTAGE_PWM_OFF:  
result = (av - VOLT_OFFSET.l);  
result /= VOLT_SLOPE.l;  
result *= 100;  
result *= RESAB;  
result /= RESB;  
// Account for System Errors  
// Convert to Voltage in Millivolts  
// Account for Math Truncation Error  
// Account for Divide Resistors  
break;  
case CURRENT:  
result = av*2;  
// Account for Differential Mode  
// Account for System Errors  
// Convert to Milliamps  
// Account for Math Truncation Error  
// Account for Sense Resistor  
// Account for Divide Resistors  
result -= I_NOAMP_OFFSET.l;  
result /= I_NOAMP_SLOPE.l;  
result *= 100;  
result /= RSENSE;  
result *= RESAB;  
result /= RESB;  
result /= CURRENT_GAIN;  
break;  
}
return (int) result;  
}
//-----------------------------------------------------------------------------  
// Bulk_Charge Function  
//-----------------------------------------------------------------------------  
void Bulk_Charge(void)  
{
unsigned int temp = 0;  
unsigned int bulk_finish_hour = 0;  
unsigned int bulk_finish_min = 0;  
unsigned int delay_hour = 0;  
unsigned int delay_min = 0;  
unsigned int last_min = 0;  
Reset_Time_Base();  
// Reset Time Base to zero  
// Calculate BULK charge finish time  
bulk_finish_min = (TIME.min + MAX_TIME_BULK);  
bulk_finish_hour = TIME.hour;  
while (bulk_finish_min > 60)  
{
bulk_finish_min = bulk_finish_min - 60;  
bulk_finish_hour++;  
}
30  
Rev. 1.2  
AN137  
CONST_C = 1;  
DELAY = 0;  
// Start in constant current charge mode  
// Reset timer DELAY  
temp = Monitor_Battery(TEMPERATURE); // Monitor Temperature  
// Is temperature within range?  
if ((temp > MIN_TEMP_ABS) && (temp < MAX_TEMP_ABS))  
{
temp = Monitor_Battery(VOLTAGE);  
// Monitor Voltage  
// Is Voltage within range?  
if ((temp <= (MAX_VOLT_ABS + VOLT_TOLERANCE)) && temp > MIN_VOLT_BULK)  
{
PCA0CPM0 = 0x42;  
// Configure CCM0 to 8-bit PWM mode  
// Enter main loop in Bulk_Charge()  
while ((BULK == 1) && (ERROR == 0))  
{
if (CONST_C == 1)  
Regulate_Current(I_BULK);  
// Charge with Constant Current  
// Charge with Constant Voltage  
else if (CONST_V == 1)  
Regulate_Voltage();  
// Now, Check for error and charge termination conditions  
// If above max charge time, flag error  
// Test for BULK Charge Time Out  
// Monitor Time  
if ((TIME.hour == bulk_finish_hour) && (TIME.min == bulk_finish_min)  
&& (DELAY == 0))  
{
Turn_PWM_Off();  
TIME_MAX = 1;  
// Turn Off PWM  
// Set Time max error flag  
// Set general error flag  
ERROR  
= 1;  
}
// Monitor Temperature  
temp = Monitor_Battery(TEMPERATURE);  
if ((temp < MIN_TEMP_ABS) && (temp > MAX_TEMP_ABS))  
{
Turn_PWM_Off();  
// Turn Off PWM  
if (temp < MIN_TEMP_ABS)  
TEMP_MIN = 1;  
else  
// Set Temperature below minimum flag  
// Set Temperature exceeds maximum flag  
// Set general error flag  
TEMP_MAX = 1;  
ERROR  
= 1;  
}
// Minute elapsed?  
// Check for minimum current  
// if reached, enter last DELAY charge  
if (TIME.min != last_min)  
{
last_min = TIME.min;  
if ((CONST_V == 1) && (DELAY == 0) && (Monitor_Battery(CURRENT)  
<= MIN_I_BULK))  
Rev. 1.2  
31  
AN137  
{
// Calculate TOP OFF Battery Time finish time  
delay_min = (TIME.min + BULK_TIME_DELAY);  
delay_hour = TIME.hour;  
while (delay_min > 60)  
{
delay_min = delay_min - 60;  
delay_hour++;  
}
DELAY = 1;  
// Set Delay Flag  
}
// Monitor Delay time, time up?  
if ((TIME.hour == delay_hour)&&(TIME.min == delay_min) &&  
(DELAY == 1))  
{
Turn_PWM_Off();  
CONST_V = 0;  
CONST_C = 1;  
BULK = 0;  
// Turn Off PWM  
// Exit CONST_V  
// Prepare to enter CONST_C  
// Prepare to exit BULK mode  
// Prepare to enter LOWCURRENT Mode  
LOWCURRENT = 1;  
}
}
}
// End Main While loop  
}
else if(ERROR == 0)  
{
if (temp > (MAX_VOLT_ABS + VOLT_TOLERANCE))  
{ VOLT_MAX = 1; // Set Max Voltage error flag  
ERROR = 1;  
// Set general error flag  
}
else if(temp < MIN_VOLT_BULK)  
{ VOLT_MIN = 1;  
LOWCURRENT = 1;  
BULK = 0;  
// Set Minimum bulk voltage error flag  
// Switch to LOWCURRENT mode  
// Exit Bulk Charge mode  
}
// battery’s voltage very low  
}
}
else if(ERROR == 0)  
{
// Absolute temperature out of range?  
if (temp < MIN_TEMP_ABS)  
TEMP_MIN = 1;  
else  
// Set Temperature below minimum flag  
// Set Temperature exceeds maximum flag  
// Set general error flag  
TEMP_MAX = 1;  
ERROR = 1;  
}
}
//-----------------------------------------------------------------------------  
// Lowcurrent_Charge  
//-----------------------------------------------------------------------------  
void Lowcurrent_Charge(void)  
{
unsigned int temp = 0;  
unsigned int lowcurrent_finish_min = 0;  
32  
Rev. 1.2  
AN137  
unsigned int lowcurrent_finish_hour = 0;  
Reset_Time_Base(); // Reset Time base to zero  
// Calculate LOWCURRENT finish time  
lowcurrent_finish_min = (TIME.min + MAX_TIME_LOWCURRENT);  
lowcurrent_finish_hour = TIME.hour;  
while (lowcurrent_finish_min > 60)  
{
lowcurrent_finish_min = lowcurrent_finish_min - 60;  
lowcurrent_finish_hour++;  
}
// Enter Main Lowcurrent Loop.  
// Only exits are upon error and full charge  
while ((LOWCURRENT == 1) && (ERROR == 0))  
{
temp = Monitor_Battery(TEMPERATURE);// Get Temperature Reading  
// Is TEMPERATURE within limits  
if ((temp > MIN_TEMP_ABS) && (temp < MAX_TEMP_ABS))  
{
// Is Battery’s Charge Voltage below max charge voltage  
temp = Monitor_Battery(VOLTAGE); // Get Voltage Reading  
if (temp <= (VOLT_LOWCURRENT + VOLT_TOLERANCE))  
{
if (CONST_C == 1)  
// CONST_C ?, charge w/ constant current  
Regulate_Current(I_LOWCURRENT);  
if (CONST_V == 1)  
// CONST_V?, charge w/ constant voltage  
Regulate_Voltage();  
if ((temp >= MIN_VOLT_BULK) && (DELAY == 0))// Bulk Threshold voltage met?  
{ LOWCURRENT = 0;  
// Exit LOWCURRENT mode  
BULK = 1;  
}
// Switch to Bulk Charge mode  
// Check elapsed time  
if ((TIME.hour == lowcurrent_finish_hour) &&  
( TIME.min == lowcurrent_finish_min))  
{
TIME_MAX = 1;  
ERROR = 1;  
// Set Time MAX error flag  
// Set general error flag  
}
}
else if(ERROR == 0)  
// Voltage to high?  
{
VOLT_MAX = 1;  
// Set Max voltage error flag  
// Set general error flag  
ERROR  
= 1;  
}
}
else if(ERROR == 0)  
{
// Absolute temperature out of range?  
if (temp < MIN_TEMP_ABS)  
TEMP_MIN = 1;  
else  
// Set Temperature below minimum flag  
// Set Temperature exceeds maximum flag  
// Set general error flag  
TEMP_MAX = 1;  
ERROR = 1;  
}
}
Rev. 1.2  
33  
AN137  
}
//-----------------------------------------------------------------------------  
// Main Function  
//-----------------------------------------------------------------------------  
void main(void)  
{
EA = 0;  
// Disable All Interrupts  
Reset_Time_Base();  
Config_F300();  
// Config F300  
CalibrateADCforMeasurement();  
// Calibrate F300  
EA = 1;  
// Enable All Active Interrupts  
// Turn LED0 off  
while(1)  
{
LED0 = 0;  
TERMINATION = 0x00;  
CHARGE_STATUS = 0x00;  
BULK = 1;  
// Reset Termination Flags  
// Reset Charge Status Flags  
// Start in LOWCURRENT Charge mode  
CONST_C = 1;  
while (SW0 == 1);  
Delay_Loop();  
// Wait until SW0 pushed  
// Wait for Switch Bounce  
while (ERROR == 0)  
{
if (BULK == 1)  
{
LED0 = 1;  
Bulk_Charge();  
}
// Turn LED0,indicates Bulk Mode  
// Enter Bulk Charge Mode  
if (LOWCURRENT == 1)  
Lowcurrent_Charge();  
// Enter Lowcurrent_Charge function  
// Toggle LED0 at 1 Hz rate via ISR  
}
if (ERROR == 1)  
{
Turn_PWM_Off();;  
LED0 = 0;  
EA = 0;  
// Turn PWM Off  
// Turn OFF LED0 to indicate “ERROR”.  
// Disable All Interrupts  
// Enter a eternal loop  
while (1);  
// No recovery except “reset-button”  
}
}
}
//-----------------------------------------------------------------------------  
// PCA_ISR  
//-----------------------------------------------------------------------------  
// This routine counts the elapsed time in seconds, minutes, hours.  
// It also toggles LED0 every second when in Lowcurrent Charge Mode.  
// This routine interrupts every time the PCA counter overflows, every 256  
// SYSCLK cycles. After SYSCLK/256 interrupts, one second has elapsed.  
//  
void PCA_OVERFLOW_ISR (void) interrupt 9  
{
34  
Rev. 1.2  
AN137  
PCA0CN = 0x40;  
PCA0H = 0x00;  
// Reset all PCA Interrupt Flags  
// Reset High Byte of PCA Counter  
//  
of 8-bit PWM we are using Module1  
if (0x0000 == --TIME.t_count)  
{
TIME.t_count = PWM_CLOCK;  
// Reset 1 Second Clock  
if ( 60 == ++TIME.sec )  
{
// Account for elapsed seconds  
// Reset second counter every minute  
TIME.sec = 0x00;  
if ( 60 == ++TIME.min )  
// Account for elapsed minutes  
{
// Reset minute counter every hour  
TIME.min = 0x00;  
if ( 24 == ++TIME.hour )  
// Account for elapsed hours  
TIME.hour = 0x00;  
// Reset hour counter every day  
}
}
if ((LOWCURRENT == 1) && (ERROR == 0))  
{
// Blink LED0 at 1 Hz if in Lowcurrent  
if (TIME.sec % 2)  
LED0 = 0;  
else  
// Turn on LED every odd second  
// Turn on LED every even second  
LED0 = 1;  
}
}
}
// END OF FILE  
Rev. 1.2  
35  
AN137  
Contact Information  
Silicon Laboratories Inc.  
4635 Boston Lane  
Austin, TX 78735  
Tel: 1+(512) 416-8500  
Fax: 1+(512) 416-9669  
Toll Free: 1+(877) 444-3032  
Email: productinfo@silabs.com  
Internet: www.silabs.com  
The information in this document is believed to be accurate in all respects at the time of publication but is subject to change without notice.  
Silicon Laboratories assumes no responsibility for errors and omissions, and disclaims responsibility for any consequences resulting from  
the use of information included herein. Additionally, Silicon Laboratories assumes no responsibility for the functioning of undescribed features  
or parameters. Silicon Laboratories reserves the right to make changes without further notice. Silicon Laboratories makes no warranty, rep-  
resentation or guarantee regarding the suitability of its products for any particular purpose, nor does Silicon Laboratories assume any liability  
arising out of the application or use of any product or circuit, and specifically disclaims any and all liability, including without limitation conse-  
quential or incidental damages. Silicon Laboratories products are not designed, intended, or authorized for use in applications intended to  
support or sustain life, or for any other application in which the failure of the Silicon Laboratories product could create a situation where per-  
sonal injury or death may occur. Should Buyer purchase or use Silicon Laboratories products for any such unintended or unauthorized ap-  
plication, Buyer shall indemnify and hold Silicon Laboratories harmless against all claims and damages.  
Silicon Laboratories and Silicon Labs are trademarks of Silicon Laboratories Inc.  
Other products or brandnames mentioned herein are trademarks or registered trademarks of their respective holders.  
36  
Rev. 1.2  

相关型号:

AN1375-521P

AN0625-521P
ETC

AN1393

Dual Comparators
PANASONIC

AN1393(AN6914)

Dual Comparators
PANASONIC

AN1393S

Dual Comparators
PANASONIC

AN1393S(AN6914S)

Dual Comparators
PANASONIC

AN13CC0101F24

CECC 32101 MLCC
KYOCERA AVX

AN13CC0101F2K

CECC 32101 MLCC
KYOCERA AVX

AN13CC0101F2L

CECC 32101 MLCC
KYOCERA AVX

AN13CC0101F2Y

CECC 32101 MLCC
KYOCERA AVX

AN13CC0101F9Y

CECC 32101 MLCC
KYOCERA AVX

AN13CC0101FT2

CECC 32101 MLCC
KYOCERA AVX

AN13CC0101FT3

CECC 32101 MLCC
KYOCERA AVX