;--------------------------------------------------------------------------------
;	18V 太陽電池、12鉛電池用 充電専用コントローラー
;	Programmed by GRANADA
;	Since 					2007/09/11-
;	Pulse Charge version	2007/10/17
;	充電専用バージョン 		2008/1/9 - 1/13
;	微修正					2008/11/20
;--------------------------------------------------------------------------------

	LIST		P=12F675
	INCLUDE		P12F675.INC
	ERRORLEVEL	-302

CB = _CPD_OFF
CB &= _CP_OFF
CB &= _BODEN_ON				; ブラウンアウトリセット (2.0V) ON
CB &= _MCLRE_ON				; 外部リセット許可
CB &= _PWRTE_ON
CB &= _WDT_OFF
CB &= _INTRC_OSC_NOCLKOUT	; 4MHz 内部発振モード、Port 4 も使用可能に

	__CONFIG	CB
	__IDLOCS	H'0100'

;--------------------------------------------------------------------------------
;	ファイルアドレス定義
;--------------------------------------------------------------------------------

VOLTAGE		EQU		H'20'	; バッテリー電圧ストア用
EMPTY_FLAG	EQU		H'21'	; 過放電フラグ
FULL_FLAG	EQU		H'22'	; 満充電検出フラグ
PULSE_COUNT	EQU		H'23'	; パルス充電用カウンタ
FIRST_FULL	EQU		H'24'	; 満充電に達したのが初回かのフラグ

W_WORK		EQU		H'30'	; 割り込み時の W レジスタ退避用（未使用）
ST_WORK		EQU		H'31'	; 割り込み時のステータスレジスタ退避用（未使用）

COUNTER1	EQU		H'40'	; 時間待ち用ワーク
COUNTER2	EQU		H'41'	; 時間待ち用ワーク
COUNTER3	EQU		H'42'	; 時間待ち用ワーク

;--------------------------------------------------------------------------------
;	定数定義
;--------------------------------------------------------------------------------

FULL_V		EQU		D'148'	; 満充電値       (14.3V) の 8bit A/D 変換値 = (14.3+0.2)/5 * 256/5
RECHARGE_V	EQU		D'145'	; 再充電許可値   (14.0V) の 8bit A/D 変換値 = (14.0+0.2)/5 * 256/5
EMPTY_V		EQU		D'121'	; 通常状態下限値（11.7V）の 8bit A/D 変換値 = (11.7+0.2)/5 * 256/5
							; （いずれも SBD Vf 0.2V ぶんを上乗せ）

ANALOG_IN	EQU		D'0'	; 電池電圧検出（アナログ入力）ポート
CHARGE_PORT	EQU		D'1'	; 充電制御 FET ポート, 充電 = H, 充電停止 = L
CHARGE_LED	EQU		D'2'	; 充電中 LED ポート
RESET_PORT	EQU		D'3'	; 外部リセット入力ポート（固定値）
ALERT_LED	EQU		D'4'	; 過放電警告 LED ポート
FULL_LED	EQU		D'5'	; 満充電 LED ポート

;--------------------------------------------------------------------------------
;	プログラム先頭
;--------------------------------------------------------------------------------

	ORG		H'0'
	GOTO	INITIALIZE

;--------------------------------------------------------------------------------
;	割り込み処理（現状未使用）
;--------------------------------------------------------------------------------

	ORG		H'4'			; 割り込み処理先頭アドレス

PUSH_REG:

	MOVWF	W_WORK			; レジスタ待避
	SWAPF	STATUS,W		; Z フラグが影響しないよう、MOVF ではなく SWAPF を使用
	MOVWF	ST_WORK

;
;	ここに何らかの割り込み処理を記述
;

POP_REG:

	SWAPF	ST_WORK,W        ;レジスタ復帰
	MOVWF	STATUS
	SWAPF	W_WORK,F
	SWAPF	W_WORK,W
;	BCF		INTCON,***		; 処理が終了した割込み対象のフラグをクリアしておく
							; フラグをクリアしておかないと次回の割り込みがかからないので注意

	RETFIE					; 割り込み処理終了

;--------------------------------------------------------------------------------
;	初期化
;--------------------------------------------------------------------------------

INITIALIZE:

	BANKSEL	OSCCAL				; Bank 1

	CALL	H'3FF'      		; 内部発振器をキャリブレーション
	MOVWF   OSCCAL

	CLRF	TRISIO				; ひとまず全ポートを出力に指定
	BSF		TRISIO,ANALOG_IN	; 入力に再指定
	BSF		TRISIO,RESET_PORT	; RESET ポートは入力に再指定

	MOVLW	B'00110000'			; A/D 変換クロック -> FRC、全ポートをデジタル指定
	MOVWF	ANSEL
	BSF		ANSEL,ANALOG_IN		; アナログポートのみ再指定、他はデジタルポートのまま

	CLRF	PIE1
	BSF		PIE1,ADIE			; ADIE ビットを 1 にして AD 割り込み許可

	BANKSEL	GPIO				; Bank 0

	CLRF	GPIO				; 全ポートを L に -> 充電不許可、全 LED 消灯

	MOVLW	B'00000111'			; コンパレータ未使用、これを設定しないと Port 0 の挙動が怪しい
	MOVWF	CMCON

	BSF		INTCON,PEIE			; PEIE ビットを 1 にして周辺割り込みを許可
								; ただし SLEEP からの起動のみなので GIE は立てない

	MOVLW	B'00000001'			; 左詰、内部 REF、AD コンバータ電源 ON
	MOVWF	ADCON0
	BSF		ADCON0,1			; AN0 でアナログ変換（アナログポート変更時はここを変更すること）

	CLRF	EMPTY_FLAG			; 過放電フラグをクリアしておく
	CLRF	FULL_FLAG			; 満充電フラグをクリアしておく
	CLRF	FIRST_FULL			; 満充電にまだ一度も達していない

	CALL	CHARGE_FET_ON		; 充電許可状態にして電池電圧を測定できる状態に
	CALL	WAIT_200ms			; しばらく待つ

;--------------------------------------------------------------------------------
;	メインループ開始
;--------------------------------------------------------------------------------

MAIN_LOOP:

	CALL	CHARGE_FET_ON		; 一時的に充電許可状態にして電池電圧を測定できる状態に
	CALL	WAIT_1ms			; 次のサンプリングまで 2TAD 以上待つ
	CALL	READ_VOLTAGE		; 電圧を読んでメモリにストア

;--------------------------------------------------------------------------------
;	電圧比較、満充電か ?
;--------------------------------------------------------------------------------

	MOVF	VOLTAGE,W			; 測定電圧値を読み出す
	SUBLW	FULL_V				; FULL_V - VOLTAGE -> W
	BTFSC	STATUS,C			; 満充電時は借り入れが発生するので C=0 となり、次の命令がスキップされる
	GOTO	CHECK_RECHARGE		; 満充電ではない

;--------------------------------------------------------------------------------
;	満充電
;--------------------------------------------------------------------------------

	CALL	FULL_LED_ON			; 満充電 LED 点灯
	CALL	CHARGE_OFF			; 充電停止

	MOVLW	D'1'
	MOVWF	FULL_FLAG			; 満充電フラグセット
	MOVLW	D'1'
	MOVWF	FIRST_FULL			; 満充電に一度でも達した

	CLRF	EMPTY_FLAG			; 過放電フラグをクリア
	CALL	ALERT_LED_OFF		; 過放電 LED 警告を停止

	CALL	WAIT_200ms			; 少し待つ

	GOTO	MAIN_LOOP			; メイン処理再開

;--------------------------------------------------------------------------------
;	再充電許可電圧か ?
;--------------------------------------------------------------------------------

CHECK_RECHARGE:

	MOVF	VOLTAGE,W			; 測定電圧値を読み出す
	SUBLW	RECHARGE_V			; RECHARGE_V - VOLTAGE -> W

	BTFSC	STATUS,C			; 再充電許可電圧より電圧が高ければキャリーが発生して C=0 となり次の命令がスキップされる
	GOTO	CHECK_NORMAL_MIN	; 通常状態下限電圧チェックへ

;--------------------------------------------------------------------------------
;	再充電許可電圧以上の場合
;--------------------------------------------------------------------------------

	CLRF	EMPTY_FLAG			; 過放電フラグをクリア
	CALL	ALERT_LED_OFF		; 過放電 LED 警告を停止

	MOVF	FULL_FLAG,F			; 満充電フラグをチェック。満充電に達していたら 1 になる
	BTFSS	STATUS,Z			; Z フラグが 1（満充電に達していない）なら次の命令をスキップ
	GOTO	COOL_DOWN			; 満充電フラグが立っていたら（Z=0）電圧が下がるまで充電停止

;--------------------------------------------------------------------------------
;	電源投入後、一度でも満充電に達したか
;--------------------------------------------------------------------------------

	MOVF	FIRST_FULL,F	; 一度も満充電に達していないかのフラグをチェック
	BTFSC	STATUS,Z		; Z フラグが 0（既に一度でも満充電に達した）なら次の命令をスキップ
	GOTO	MAIN_LOOP		; まだ一度も満充電に達していから通常充電

;--------------------------------------------------------------------------------
;	既に一度満充電に達しているのでパルス充電モードにする
;--------------------------------------------------------------------------------

	CALL	FULL_LED_ON		; 満充電 LED を点灯する
	CALL	PULSE_CHARGE	; パルス充電する
	GOTO	MAIN_LOOP		; メイン処理再開

;--------------------------------------------------------------------------------
;	満充電経過後、再充電許可電圧以上の場合
;--------------------------------------------------------------------------------

COOL_DOWN:

	CALL	CHARGE_OFF		; 一旦充電を停止
	CALL	WAIT_200ms		; 少し待ってから
	GOTO	MAIN_LOOP		; メイン処理再開

;--------------------------------------------------------------------------------
;	通常状態下限値以上か ?（過放電チェック）
;--------------------------------------------------------------------------------

CHECK_NORMAL_MIN:

	CLRF	FULL_FLAG		; 満充電フラグをクリア
	CALL	FULL_LED_OFF	; 満充電 LED 消灯
	CALL	CHARGE_ON		; 電圧が十分下がっているので電池を接続

	MOVF	VOLTAGE,W		; 測定電圧値を読み出す
	SUBLW	EMPTY_V			; EMPTY_V - VOLTAGE -> W
	BTFSC	STATUS,C		; 通常電圧以上なら借り入れが発生するので C=0 となり、次の命令がスキップされる
	GOTO	EMPTY			; 過放電処理へ

;--------------------------------------------------------------------------------
;	通常状態下限値以上の場合
;--------------------------------------------------------------------------------

	CLRF	EMPTY_FLAG		; 過放電フラグをクリア
	CALL	ALERT_LED_OFF	; 過放電 LED 警告を停止
	GOTO	MAIN_LOOP		; メイン処理再開

;--------------------------------------------------------------------------------
;	過放電処理
;--------------------------------------------------------------------------------

EMPTY:

	CLRF	FIRST_FULL		; 満充電にまだ一度も達していない状態に戻してパルス充電をしないようにする
	MOVLW	D'1'
	MOVWF	EMPTY_FLAG		; 過放電フラグを立てる

	CALL	ALERT_LED_ON	; LED 警告開始

	GOTO	MAIN_LOOP		; メイン処理再開

;--------------------------------------------------------------------------------
;	A/D 変換を実行し、値をメモリにストアする
;--------------------------------------------------------------------------------

READ_VOLTAGE:

	BCF		PIR1,ADIF		; ADIF を 0 に（A/D 変換終了時このビットが 1 になる）
	BSF		ADCON0,GO		; GO (start) bit を立てて A/D 変換開始

;EXEC_AD:					; 通常の A/D 変換
;	BTFSC	ADCON0,GO		; A/D 変換終了したか? 0 なら次をスキップ
;	GOTO	EXEC_AD			; まだ変換中

	SLEEP					; A/D 変換しながら SLEEP モードへ
	NOP						; A/D 変換が終了したら自動的に再開

	MOVF	ADRESH,W		; A/D 変換値を読み出して
	MOVWF	VOLTAGE			; ひとまず汎用メモリに保存

	RETURN

;--------------------------------------------------------------------------------
;	充電を許可する
;--------------------------------------------------------------------------------

CHARGE_ON:

	CALL	CHARGE_LED_ON		; 充電中 LED 点灯

CHARGE_FET_ON:

	BSF		GPIO,CHARGE_PORT	; 充電制御 FET ON -> 充電可

	RETURN

;--------------------------------------------------------------------------------
;	充電を止める
;--------------------------------------------------------------------------------

CHARGE_OFF:

	BCF		GPIO,CHARGE_PORT	; 充電制御 FET OFF -> 充電停止
	CALL	CHARGE_LED_OFF		; 充電中 LED 消灯
	CALL	WAIT_1sec			; ばたつきを防ぐため１秒待つ

	RETURN

;--------------------------------------------------------------------------------
;	一定時間パルス充電
;--------------------------------------------------------------------------------

PULSE_CHARGE:

	MOVLW	D'5'				; 充電パルス回数
	MOVWF	PULSE_COUNT

PULSE_LOOP:

	CALL	CHARGE_ON			; 充電制御 FET ON
	CALL	WAIT_200ms
	CALL	WAIT_200ms
	CALL	CHARGE_OFF			; 充電制御 FET OFF
	CALL	WAIT_200ms
	CALL	WAIT_200ms

	DECFSZ	PULSE_COUNT,F
	GOTO	PULSE_LOOP			; in case DECFSZ false

	RETURN

;--------------------------------------------------------------------------------
;	警告（LED）表示点灯
;--------------------------------------------------------------------------------

ALERT_LED_ON:

	BSF		GPIO,ALERT_LED	; 警告 LED 点灯

	RETURN

;--------------------------------------------------------------------------------
;	警告（LED）表示停止
;--------------------------------------------------------------------------------

ALERT_LED_OFF:

	BCF		GPIO,ALERT_LED	; 警告 LED 消灯

	RETURN

;--------------------------------------------------------------------------------
;	満充電 LED 点灯
;--------------------------------------------------------------------------------

FULL_LED_ON:

	BSF		GPIO,FULL_LED	; 満充電 LED 点灯

	RETURN

;--------------------------------------------------------------------------------
;	満充電 LED 消灯
;--------------------------------------------------------------------------------

FULL_LED_OFF:

	BCF		GPIO,FULL_LED	; 満充電 LED 消灯

	RETURN

;--------------------------------------------------------------------------------
;	充電中 LED 点灯
;--------------------------------------------------------------------------------

CHARGE_LED_ON:

	BSF		GPIO,CHARGE_LED	; 充電中 LED 点灯

	RETURN

;--------------------------------------------------------------------------------
;	充電中 LED 消灯
;--------------------------------------------------------------------------------

CHARGE_LED_OFF:

	BCF		GPIO,CHARGE_LED	; 充電中 LED 消灯

	RETURN

;--------------------------------------------------------------------------------
;	時間待ちサブルーチン
;--------------------------------------------------------------------------------

WAIT_1ms:

	MOVLW	D'1'
	GOTO	SET_COUNTER

WAIT_20ms:

	MOVLW	D'20'
	GOTO	SET_COUNTER

WAIT_200ms:

	MOVLW	D'200'

;--------------------------------------------------------------------------------
;	時間待ちサブルーチン・コア部分、1ms ループ
;	（クロック 4MHz 時 1 step = 1/4000000 x 4 (sec) = 1μs）
;--------------------------------------------------------------------------------

SET_COUNTER:

	MOVWF	COUNTER1

WAIT_LOOP1:

	MOVLW	H'F9'		; 4MHz 時 F9H で 1ms のループになる
	MOVWF	COUNTER2

WAIT_LOOP2:

	NOP
	DECFSZ	COUNTER2,F
	GOTO	WAIT_LOOP2

	DECFSZ	COUNTER1,F
	GOTO	WAIT_LOOP1

	RETURN

;--------------------------------------------------------------------------------
;	時間待ちサブルーチン、だいたい 1 秒
;--------------------------------------------------------------------------------

WAIT_1sec:

	MOVLW	D'5'
	MOVWF	COUNTER3

WAIT_LOOP3:

	CALL	WAIT_200ms

	DECFSZ	COUNTER3,F
	GOTO	WAIT_LOOP3

	RETURN

;--------------------------------------------------------------------------------
;	プログラム終了
;--------------------------------------------------------------------------------

	END
