AN137 [SILICON]
LITHIUM ION BATTERY CHARGER USING C8051F300; 锂离子电池充电器使用C8051F300型号: | AN137 |
厂家: | SILICON |
描述: | LITHIUM ION BATTERY CHARGER USING 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
相关型号:
©2020 ICPDF网 联系我们和版权申明