        LIST P=12F675,R=HEX
;
;       Monitor for Li-Ion / Li-Poly Battery Packs with cell balance connector
;       SUN, PU-NENG
;       
;	VERSION 2.0  (DEC/12/2005)
;	Add unbalance detector nominal 0.2V, actually 0.1~0.15V 
;
;	VERSION 1.0  (DEC/08/2005)
;	3cell, Cut off at 3.0 V, 
;=============================================	
;  Voltage AN0 = cell 0
;  Voltage AN1 = cell (0+1)/2
;  Voltage AN2 = cell (0+1+2)/3
;  
;  Voltage cell 0 = AN0
;  Voltage cell 1 = (AN1*2)-AN0
;  Voltage cell 2 = (AN2*3)-(AN1*2)
;==============================================
;       
;----  SYSTEM CONFIG  ----
	__CONFIG	H'3FA4' ;_INTRC_OSC_NOCLKOUT,_MCLRE_OFF,WDT OFF,PWRTE ON
;
;-----  SYSTEM  ---------
W       EQU 0           ;d VALUE FOR INCF......
F       EQU 1           ;d VALUE
TMR0	EQU 1		;TIMER 0
PCL     EQU 2           ;PROGRAM COUNTER
STATUS  EQU 3
FSR     EQU 4           ;BUFFER OF INDIRECT ADDR
GPIO	EQU 5
OPTION_reg	EQU 0x81
TRISIO	EQU 0x85
OSCCAL  EQU 0x90	
RP0	EQU 5
CMCON	EQU 0x19	;CMCON REGISTER
ANSEL   EQU 0x9F	;ANALOG SEL
ADCON0	EQU H'1F'
ADRESH	EQU H'1E'
GO	EQU 1
C	EQU 0		;status
Z	EQU 2		;status
;=====================================
;
;----  USER registers DEFINE  ------
;
TEMP0    EQU H'20'   
TEMP1    EQU H'21'       ;
TEMP2    EQU H'22'       ;
TEMP3    EQU H'23'       ; 
SOUND_TEMP1    EQU H'24'       ;
SOUND_TEMP2    EQU H'25'       ;
SOUND_TEMP3    EQU H'26'       ;
FLAG_REG  EQU H'27'	
;   
ACCaLO  equ     2A
ACCaHI  equ     2B
ACCbLO  equ     2C
ACCbHI  equ     2D
ACCcLO  equ     2E
ACCcHI  equ     2F
;
CELL0_V equ    	31
CELL1_V equ     32
CELL2_V equ     33
;
;============================================
;----  VARIABLES DEFINE ----
;
LOW_VOLTAGE   	EQU D'153'       ; (3.0V/5.0V)*255= 153
;LOW_VOLTAGE   	EQU D'158'       ; (3.1V/5.0V)*255= 158	
;LOW_VOLTAGE   	EQU D'163'       ; (3.2V/5.0V)*255= 163
;
UNBAL_VOLTAGE   EQU D'10'       ; (0.2V/5.0V)*255= 10
;				;nominal 0.2V, actually 0.1~0.15V
;----  HARDWARE DEFINE ----
;
AN0		EQU 0
AN1		EQU 1
AN2		EQU 2
SOUND_PIN	 	EQU 4	;INVERSE
LED_PIN		EQU 5	;INVERSE
;
;============================================
;==============   MAIN PROGRAM   ============
;
;--- RESTORE OSC CALIBRATION ---------

	ORG     0
	BSF STATUS,RP0	;;BANK1
	CALL 3FFh
	MOVWF OSCCAL	;RESTORE OSC CALI
;----------------------------------

START	
	CALL 	INIT_SYS
	call	self_test
MAIN	
	call 	output_audio	;CALL 	GET_Votlage	 
	GOTO 	MAIN

;=====================================

INIT_SYS
	bsf 	status,RP0	;bank1
	MOVLW 	H'C0'		;T0CS=0, TO ENABLE GP2
	MOVWF 	OPTION_reg 	

	MOVLW 	B'00000111'     ;GPIO 0~2 =input		
	MOVWF 	TRISIO 
	MOVLW 	B'00100111'
	MOVWF	ANSEL		;T32, GPIO 0~2 ARE ANALOG

	BCF     STATUS,RP0      ; BANK0
	MOVLW 	B'00000001'
	MOVWF	ADCON0		; LEFT JUSTIFIED,VDD,A/D ON
	
	BSF	GPIO,SOUND_PIN	;INVERSE
	BSF	GPIO,LED_PIN
	CLRF	FLAG_REG	
	return
;---------------------------------------------
SELF_TEST	
	BCF	GPIO,LED_PIN
	MOVLW 	D'20'		;20*100uS, 500Hz
	MOVWF   SOUND_TEMP1 
	MOVLW 	D'100'		;100 CYCLO
	MOVWF   SOUND_TEMP2 
	CALL	sound		;
	MOVLW 	D'16'		; 625Hz
	MOVWF   SOUND_TEMP1 
	MOVLW 	D'126'		;126 CYCLO
	MOVWF   SOUND_TEMP2 
	CALL	sound		;
	MOVLW 	D'12'		;833z
	MOVWF   SOUND_TEMP1 
	MOVLW 	D'166'		;166 CYCLO
	MOVWF   SOUND_TEMP2 
	CALL	sound		;
	MOVLW 	D'10'		;1000z
	MOVWF   SOUND_TEMP1 
	MOVLW 	D'200'		;200 CYCLO
	MOVWF   SOUND_TEMP2 
	CALL	sound		;
	BSF	GPIO,LED_PIN
	return
;---------------------------------------------
sound	
	BCF	STATUS,C
	RRF	SOUND_TEMP1,F	;DURATION/2, 50% DUTY RATE 
SOUND_1
	BCF	GPIO,SOUND_PIN
	MOVF    SOUND_TEMP1,W 
	CALL	LOOP_S		;100uS LOOP
	BSF	GPIO,SOUND_PIN
	MOVF    SOUND_TEMP1,W 
	CALL	LOOP_S		;100uS LOOP
	DECFSZ  SOUND_TEMP2,F
	GOTO 	SOUND_1
	return

;---------------------------------------------

GET_Votlage

B0	BCF     STATUS,RP0      ; BANK0
	MOVLW 	B'00000001'	; AN0
	MOVWF	ADCON0		; LEFT JUSTIFIED,VDD,A/D ON
	CALL 	START_ADC
COMPARE0
	MOVF	ADRESH,W
	MOVWF	CELL0_V		;SAVE CELL 0 VOLTAGE	
	MOVWF	ACCcLO		;SAVE (AN0) TO ACCc
	MOVWF	ACCbLO
	CLRF	ACCbHI
	MOVLW 	LOW_VOLTAGE
	MOVwF	ACCaLO
	CLRF	ACCaHI
	CALL	D_SUB		; B - A
        SKPNC            	;IF f < w, C= 0,SKIP ;SKIP IF LOW VOLTAGE
	GOTO 	B1
B1_1	
	BSF	FLAG_REG,0	;AN0 < LOW_voltage
	BSF	FLAG_REG,7	; LOW CELL FLAG
	BCF	GPIO,LED_PIN

B1	BCF     STATUS,RP0      ; BANK0
	MOVLW 	B'00000101'	; AN1
	MOVWF	ADCON0		; LEFT JUSTIFIED,VDD,A/D ON
	CALL 	START_ADC
COMPARE1
	MOVF	ADRESH,W
		
	MOVWF	ACCbLO
	CLRF	ACCbHI
	CALL	D_DOUBLE	;AN1*2
	MOVF	ACCcLO,W
	MOVWF	ACCaLO
	CLRF	ACCaHI		; RESTORE AN0 FROM ACCc
	MOVF	ACCbLO,W
	MOVWF	ACCcLO
	MOVF	ACCbHI,W
	MOVWF	ACCcHI		;SAVE (AN1*2) TO ACCc
	CALL	D_sub		;(AN1*2)-AN0  B-A
	MOVF	ACCbLO,W
	MOVWF	CELL1_V		;SAVE CELL 1 VOLTAGE	
	SKPC    
	GOTO	B2_1		;;((AN1*2)-AN0)<0
	MOVLW 	LOW_VOLTAGE
	MOVwF	ACCaLO
	CLRF	ACCaHI
	CALL	D_SUB		; B - A
	SKPNC            	;IF f < w, C= 0,SKIP ;SKIP IF LOW VOLTAGE
	GOTO 	B2
B2_1	
	BSF	FLAG_REG,1
	BSF	FLAG_REG,7	; LOW CELL FLAG
	BCF	GPIO,LED_PIN

B2	
	BCF     STATUS,RP0      ; BANK0
	MOVLW 	B'00001001'	; AN2
	MOVWF	ADCON0		; LEFT JUSTIFIED,VDD,A/D ON
	CALL 	START_ADC
COMPARE2	
	MOVF	ADRESH,W
		
	MOVWF	ACCbLO
	CLRF	ACCbHI
	CALL	D_DOUBLE
	CALL	D_DOUBLE	;AN2*4
	MOVF	ADRESH,W
	MOVWF	ACCaLO
	CLRF	ACCaHI
	CALL	D_sub		;(AN2*4)-AN2=AN2*3
	MOVF	ACCcLO,W
	MOVWF	ACCaLO
	MOVF	ACCcHI,W
	MOVWF	ACCaHI		;move (AN1*2) from ACCc TO ACCa
	CALL	D_sub		;((AN2*3)-(AN1*2)) 
	MOVF	ACCbLO,W
	MOVWF	CELL2_V		;SAVE CELL 2 VOLTAGE	
	SKPC            	;
	GOTO	B3_1		;((AN2*3)-(AN1*2)) <0
	MOVLW 	LOW_VOLTAGE
	MOVwF	ACCaLO
	CLRF	ACCaHI
	CALL	D_SUB		; B - A
	SKPNC            	;IF f <= w, C= 0,SKIP ;SKIP IF LOW VOLTAGE
	GOTO 	B3
B3_1	
	BSF	FLAG_REG,2
	BSF	FLAG_REG,7	; LOW CELL FLAG
	BCF	GPIO,LED_PIN
B3
	BTFSC	FLAG_REG,7	; IF CELL LOW 7=1, DON'T DETECT UNBALANCE
	GOTO	B4
UNBAL
	MOVF	CELL0_V,W
	SUBWF	CELL1_V,W
	CALL	CHECK_UNBAL
	MOVF	CELL1_V,W
	SUBWF	CELL2_V,W
	CALL	CHECK_UNBAL
	MOVF	CELL2_V,W
	SUBWF	CELL0_V,W
	CALL	CHECK_UNBAL
B4
	return		

;-----------------------------------------
;
CHECK_UNBAL			;IF UNBAL, BSF FLAG_REG,6
	MOVWF	TEMP0	
	BTFSS	STATUS,C
	COMF	TEMP0,F		; NEGATIVE
	MOVLW	UNBAL_VOLTAGE
	SUBWF	TEMP0,W		;F<W, C=0 
	SKPNC
	BSF FLAG_REG,6		;(Vx-Vx) > UNBAL_VOLTAGE
	return
;------------------------------------------
;
START_ADC
	BCF     STATUS,RP0      ; BANK0
	BSF	ADCON0,GO	;START ADC
START_ADC1
	BTFSC	ADCON0,GO		
	GOTO 	START_ADC1
	return
;------------------------------------------
;
output_audio
	MOVLW 	D'40'		;
	CALL	LOOP_L		;	
	CALL 	GET_Votlage	 
	BTFSS	FLAG_REG,0
	GOTO	OA_1
	MOVLW 	D'10'		;1000z
	MOVWF   SOUND_TEMP1 
	MOVLW 	D'200'		;200 CYCLO
	MOVWF   SOUND_TEMP2 
	CALL	sound		;	
OA_1	
	MOVLW 	D'40'		;
	CALL	LOOP_L		;	
	CALL 	GET_Votlage	
	BTFSS	FLAG_REG,1
	GOTO	OA_3 
	MOVLW	2
	MOVWF   TEMP0
OA_2		
	MOVLW 	D'10'		;1000z
	MOVWF   SOUND_TEMP1 
	MOVLW 	D'200'		;200 CYCLO
	MOVWF   SOUND_TEMP2 
	CALL	sound		;
	MOVLW 	D'10'		;100 mS
	CALL	LOOP_L		;		
	DECFSZ  TEMP0,F
        GOTO    OA_2
     
OA_3	
	MOVLW 	D'40'		;
	CALL	LOOP_L		;	
	CALL 	GET_Votlage	
	BTFSS	FLAG_REG,2
	GOTO	OA_5 
	MOVLW	3
	MOVWF   TEMP0
OA_4	
	MOVLW 	D'10'		;1000z
	MOVWF   SOUND_TEMP1 
	MOVLW 	D'200'		;200 CYCLO
	MOVWF   SOUND_TEMP2 
	CALL	sound		;
	MOVLW 	D'10'		;100 mS
	CALL	LOOP_L		;		
	DECFSZ  TEMP0,F
        GOTO    OA_4
OA_5
	MOVLW 	D'40'		;
	CALL	LOOP_L		;	
	CALL 	GET_Votlage	 
	BTFSS	FLAG_REG,6	; IF UNBAL 6=1, FLASH LED AND BEEP 5
	GOTO	OA_9		; RETURN
	BTFSC	FLAG_REG,7
	GOTO 	OA_51
	BCF	GPIO,LED_PIN
	GOTO 	OA_53
OA_51
	BSF	GPIO,LED_PIN
OA_53	
	MOVLW	5		;5 BEEP
	MOVWF   TEMP0
OA_6
	MOVLW 	D'16'		;625Hz
	MOVWF   SOUND_TEMP1 
	MOVLW 	D'126'		;
	MOVWF   SOUND_TEMP2 
	CALL	sound		;
	MOVLW 	D'10'		;100 mS
	CALL	LOOP_L		;		
	DECFSZ  TEMP0,F
        GOTO    OA_6
        
	BTFSC	FLAG_REG,7
	GOTO 	OA_55
	BSF	GPIO,LED_PIN
	GOTO 	OA_57
OA_55
	BCF	GPIO,LED_PIN
OA_57	
	
OA_9
	return

;=========================================


LOOP_S				;100 uS LOOP *W
	MOVWF   TEMP1	
LOOP_S1	
	MOVLW	D'24'		;(24*4)=96 
	MOVWF   TEMP2
LOOP_S2
        NOP
	DECFSZ  TEMP2,1
        GOTO    LOOP_S2
	DECFSZ  TEMP1,1
        GOTO    LOOP_S1
	return

;=========================================


LOOP_L				;10 mS LOOP *W
	MOVWF   TEMP1	
LOOP_L1 
	MOVLW	D'10'		;10 mS
	MOVWF   TEMP2
LOOP_L2	
	MOVLW	D'249'		;(249*4)+5=1001 
	MOVWF   TEMP3
LOOP_L3
        NOP
	DECFSZ  TEMP3,1
        GOTO    LOOP_L3
	DECFSZ  TEMP2,1
        GOTO    LOOP_L2
	DECFSZ  TEMP1,1
        GOTO	LOOP_L1
	RETURN
;==============================================
;
;*******************************************************************
;                 Double Precision Double
;
;   Double : ACCb(16 bits)*2 -> ACCb(16 bits)
;      (a) Load the 1st operand in location ACCb( 16 bits )
;      (b) CALL D_Double
;      (c) The result is in location ACCbLO & ACCbHI ( 16 bits )
;     
;     
;       Revision Date:    2005-12-09     
;       By:               Philip Sun (aka: iLuFa)  
;*******************************************************************;
D_Double
	bcf	status,c	;3,0
	rlf     ACCbLO,F       
	rlf     ACCbHI,F  
	retlw   0

;****************************************************************



;*******************************************************************
;                 Double Precision Subtraction
;
;   Subtraction : ACCb(16 bits) - ACCa(16 bits) -> ACCb(16 bits)
;      (a) Load the 1st operand in location ACCaLO & ACCaHI ( 16 bits )
;      (b) Load the 2nd operand in location ACCbLO & ACCbHI ( 16 bits )
;      (c) CALL D_sub
;      (d) The result is in location ACCbLO & ACCbHI ( 16 bits )
;      (e) If ACCa > ACCb, Carry =0 (Status,C)  
;   
;       Revision Date:    2005-12-12     
;       By:               Philip Sun (aka: iLuFa)  
;*******************************************************************;

D_sub   movf    ACCaLO,W
	subwf   ACCbLO,F	;lsd
	SKPC			;f<w, c=0
	GOTO	D_SUB_1
	movf    ACCaHI,W
	subwf   ACCbHI,F       	;msb
	return
D_SUB_1
	MOVF	ACCbHI,F
	SKPNZ			;IF ACCbHI=0, ACCa > ACCb 
	GOTO	D_SUB_2
	decf    ACCbHI,F
	movf    ACCaHI,W
	subwf   ACCbHI,F       	;msb
	return			;IF ACCa > ACCb C=0
D_SUB_2
	decf    ACCbHI,F
	movf    ACCaHI,W
	subwf   ACCbHI,F       	;msb
	BCF	STATUS,C	;ACCa > ACCb 
	return
	
;****************************************************************

	END
