I've updated the program a bit.
Added an annoying beeping that doesn't stop until the unit is switched off. I did this because someone left a unit on at work and completely discharged the battery, now being a lithium battery it cannot be recharged without bursting into flames. Bit of an expensive paperweight.
I also had a play at porting it to a PIC12F again if anyone was interested but have had trouble programming it with a PIC-Kit 2.
I did do a circuit design for the PIC12F with PCB-Express, if anyone wants a look at let me know.
Here's the updated code,
Code: Select all
;**************************************************************
; !! Lithium Battery Safety Circuit !!
;**************************************************************
;
; Date: 7 Jan 2009
; Author: S.Long
;
; Description: Messure Battery Voltage for LED indication
; and Shutdown when Min. Voltage reached.
; LED's & buzzer for level indication and
; warning.
;
; Revision History:
; 22/01/09 Added time delay and beep loop at end of shutdown
; 27/01/09 Added test for DC power in beep loop. Program will
; go back to the start if DC power is connected or
; battery is charged.
;
;
; Hardware Notes: PIC16F690
; 10k ohm pot on RA0, var. from 5v to Gnd
; for ADC input - voltage divider network in
; working circuit.
; PortC,0 Power On, transistor.
; PortC,1 Green LED
; PortC,2 Red LED
; PortC,3 Buzzer
;
;*************************************************************
#include <p16F690.inc>
__config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)
cblock 0x20
Batt ; Battery value from ADC
dc1 ; defines Delay counters
dc2
SDV ; define for Shutdown Value
BSDV ; define for Buzzer Shutdown
BLP ; define for Beep loop
endc
; !! This is the maths for the Voltages - Needs adjusting
;
; ResRat = 4700.0 / (4700.0 + 6800.0) ; Res1 / (Res1 + Res2)
; = 4700 / 11500
; = 0.4087
; Resistor divider network ratio
; Resistor divider used to bring input (batt) voltage
; down to compare with 5.0 Volts (Vdd).
;*********************************************************************
; MinimumV = ResRat * 9.0 ; ResRat * Minimum Voltage
; = 0.4087 * 9.0
; = 3.678
; Variable MinV ; MinV = (MinimumV / Vdd) * 255
; [=187]
;*********************************************************************
; Low Voltage = ResRat * 9.5 ; ResRat * Low Voltage
; = 0.4087 * 9.5
; = 3.883
; LowV ; LowV = (Low Voltage / Vdd) * 255
; [=198]
;*********************************************************************
; getting_low Voltage = ResRat * 9.75 ; ResRat * Low Voltage
; = 0.4087 * 9.75
; = 3.985
; getting_lowV ; LowV = (getting_low Voltage / Vdd) * 255
; [=203]
;*********************************************************************
; 8-bit gives approx. 0.05 Volt resolution.
;*********************************************************************
org 0
Start:
bsf STATUS,RP0 ; select Register Page 1
movlw b'11110000'
movwf TRISC ; make C3,2,1,0 output
movlw 0x10 ; A2D Clock Fosc/8
movwf ADCON1
bcf STATUS,RP0 ; back to Register Page 0
bcf STATUS,RP0 ; address Register Page 2
bsf STATUS,RP1
movlw 0xFF ; all Port A pins Analoga
movwf ANSEL
bcf STATUS,RP0 ; address Register Page 0
bcf STATUS,RP1
movlw 0x01
movwf ADCON0 ; configure A2D for Channel 0 (RA0), Left justified, and turn on the A2D module
movlw b'00000110' ; flash LEDs to show "Start"
movwf PORTC
call Delay
clrf PORTC ; initialise output setup
movlw .105 ; load value for shutdown
movwf SDV
movlw .020 ; load value for buzzer shutdown
movwf BSDV
Main:
nop ; wait 5uS for A2D amp to settle and capacitor to charge.
nop ; wait 1uS
nop ; wait 1uS
nop ; wait 1uS
nop ; wait 1uS
bsf ADCON0,GO ; start conversion
btfss ADCON0,GO ; this bit will change to zero when the conversion is complete
goto $-1
; Check Batt above minimum voltage
movf ADRESH,w
movwf Batt ; put ADC in Batt
bcf STATUS,C ; prep for compare
movlw .187 ; load variable for minimum Voltage
subwf Batt,w
btfsc STATUS,C ; skip next if Batt <= Minimum Voltage
goto Power_on ; goto Power_on if Voltage > MinV
goto Shutdown
Power_on:
bsf PORTC,0 ; turn on POWER
movlw .105 ; load value for shutdown
movwf SDV
movlw .020 ; load value for buzzer shutdown
movwf BSDV
; test if batt voltage is above "Low" level.
bcf STATUS,C ; prep for compare
movlw .198 ; load variable for "Low" Voltage
subwf Batt,w
btfsc STATUS,C ; skip next if Batt <= Low Voltage
goto $+2 ; goto $+2 if Voltage > LowV
goto Power_low
nop
; test if batt voltage is above "getting_low" level.
bcf STATUS,C ; prep for compare
movlw .203 ; load variable for "getting_low" Voltage
subwf Batt,w
btfsc STATUS,C ; skip next if Batt <= getting_lowow Voltage
goto Power_good ; goto Power_good if Voltage > getting_lowV
goto Power_getting_low
Power_good:
movlw b'00000011' ; Power ON, green LED ON, red LED OFF
movwf PORTC
goto Main
Power_getting_low
movlw b'00000111' ; Power ON, green LED ON, red LED ON
movwf PORTC
goto Main
Power_low:
movlw b'00000101' ; Power ON, red LED ON, green LED OFF
movwf PORTC
goto Main
Shutdown:
movlw b'00001101' ; turn on Buzzer, Red LED and Power.
movwf PORTC
call Delay
movlw b'00000001' ; Power ON, turn off Buzzer & Red LED.
movwf PORTC
call Delay
call Delay
decfsz BSDV ; test times shutdown has looped
goto Main
NoBuzzer
movlw b'00000101' ; turn off Buzzer. Red LED and Power ON.
movwf PORTC
call Delay
movlw b'00000001' ; Power ON, turn off Buzzer & Red LED.
movwf PORTC
call Delay
call Delay
decfsz SDV ; test times shutdown has looped
goto NoBuzzer
clrf PORTC ; Shutdown ALL!!!!
; Added 22 Jan 2009 - Revision
; Shut all down, wait for time delay, Beep 4 times, then loop round
BeepLoop:
call BuzzOn
call BuzzOff
call BuzzOn
call BuzzOff
call BuzzOn
call BuzzOff
call BuzzOn
call BuzzOff
call Test_Pow ; test if DC power applied
clrf BLP
call Delay
decfsz BLP
goto $-2 ; loop 255 times, approx. 1min delay
goto BeepLoop ; keep looping until unit is switched OFF!!!
BuzzOn
bsf PORTC,3 ; turn buzzer ON
call Delay
return
BuzzOff
bcf PORTC,3 ; turn buzzer OFF
call Delay
return
Test_Pow
; test if DC power has been applied, reset to main loop if it
; is above the required level.
nop ; allow for AD cap. to charge
nop
nop
nop
nop
nop
nop
bsf ADCON0,GO ; start conversion
btfss ADCON0,GO ; this bit will change to zero when the conversion is complete
goto $-1
; Check Batt above required voltage
movf ADRESH,w
movwf Batt ; put ADC in Batt
bcf STATUS,C ; prep for compare
movlw .203 ; load variable for required Voltage
subwf Batt,w
btfsc STATUS,C ; skip next if Batt <= required Voltage
goto Start ; goto Start if Battery Voltage > required
return
Delay
; delay loops
; movlw .xxx value determines delay
movlw .065
movwf dc2 ; puts value in delay2 counter
clrf dc1
delay1 ; loop 1
nop
decfsz dc1,f
goto delay1
delay2 ; loop2
nop
decfsz dc1,f
goto delay2
decfsz dc2,f
goto delay1
return
end
I've also attached a flowchart of the program.