;	PIC16F84A
;	clock:32.768KHz
;
;	時計
;
;	ＬＣＤを４ビットで制御
;	クロックが遅いのでＬＣＤのＢＦはチェックしない
;
;	ＰＩＣのピン接続
;		RB0	LCD DB4
;		RB1	LCD DB5
;		RB2	LCD DB6
;		RB3	LCD DB7
;		RB7	LED （デバッグ用）
;
;		RA1	LCD E	(5:Enable Signal)
;		RA2	LCD RS	(4:Register Select)
;
;	使用タイマ（プログラムループ）
;		 15mS	ＬＣＤパワーオンリセット待ち
;		  5mS	ＬＣＤ初期化ルーチン
;		  1.7mS	ＬＣＤ初期化ルーチン
;		  1mS	ＬＣＤ初期化ルーチン
;


       LIST    P=PIC16F84A
       INCLUDE P16F84A.INC
       __CONFIG _LP_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF


	CBLOCK	00Ch
	save_st		;STATUSのセーブ
	save_w		;W-regのセーブ
	timer
	CNT1S		;1Ｓカウンタ
	CNT15mS		;15ｍＳカウンタ
	CNT5mS		;5ｍＳカウンタ
	CNT2mS		;1.7ｍＳカウンタ
	CNT310mS	;310ｍＳカウンタ
	CNT620mS	;620ｍＳカウンタ
	char		;LCD表示データ
	dyy		;年（西暦下２桁）
	dmm		;月
	ddd		;日
	thh		;時
	tmm		;分
	tss		;秒
	CNTdtime	;日付時刻のカウンタ（+1 or -1）
	workW
	work1
	work10
	adj_timer1
	adj_timer2
	adj_timer3
	adj_val		;時刻補正値
	adj_timerW1
	adj_timerW2
	adj_timerW3

	sw_stat	;スイッチの状態（ON/OFF状態）
;		;bit7:sw1
;		;bit6:sw2
;		;bit5:sw3

	sw_mode		;スイッチの状態（機能動作中）
;		;bit0: 0:通常モード，1:設定モード

	sw_wait		;スイッチ長押し待ち状態
;		;bit0:スイッチ１　０．６Ｓ長押し待ち
;		;bit1:スイッチ２　０．６Ｓ長押し待ち
;		;bit2:スイッチ３　０．６Ｓ長押し待ち
;		;bit3:
;		;bit4:スイッチ２　０．３Ｓ長押し待ち
;		;bit5:スイッチ３　０．３Ｓ長押し待ち
;		;bit6:
;		;bit7:

	lpush_stat	;スイッチ長押し状態(0:310mS,1:620mS)
	setIX		;設定モードの設定項目インデックス
	EE_addr		;EEPROM書き込みアドレス
	EE_data		;EEPROM書き込みデータ
	ENDC

E	EQU	01h		;LCD Enable
RS	EQU	02h		;LCD Register Select
BUSY	EQU	03h		;BUSY FLAG (PORTB,3)

T31ms	EQU	00h		;31.25mS経過フラグ
T1s	EQU	01h		;1S経過フラグ

adj_max	EQU	d'20'		;時刻補正最大値

sw1	EQU	07h		;switch#1 (PORTB,7)
sw2	EQU	06h		;switch#1 (PORTB,6)
sw3	EQU	05h		;switch#1 (PORTB,5)

lpush03	EQU	00h		;長押し０．３秒
lpush06	EQU	01h		;長押し０．６秒


; EEPROM
	ORG	0x2100		;EEPROM
	DE	0,0,0
		;時刻補正値，年，月


	ORG	0
	GOTO	init

; ==================== 割込み処理 =====================
	ORG	4
intr
	BCF	INTCON,T0IF	;割込みフラグクリア
	MOVWF	save_w		;W-regセーブ
	SWAPF	STATUS,W
	MOVWF	save_st		;STATUSレジスタセーブ

	BSF	timer,T31ms	;31.25mS経過フラグセット

	DECFSZ	CNT1S,F
	GOTO	intr90
	BSF	timer,T1s	;1S経過フラグセット
	MOVLW	d'32'
	MOVWF	CNT1S

intr90
	SWAPF	save_st,W
	MOVWF	STATUS		;STATUSレジスタロード
	SWAPF	save_w,F
	SWAPF	save_w,W	;W-regロード
	RETFIE			;割込み許可リターン

; ==================== 初期処理 =====================
init
	CALL	wait15ms	;15mS待つ
	BSF	STATUS,RP0	;■バンク１に切替え
	MOVLW	0F8h
	MOVWF	TRISA		;RA0-2は出力
	MOVLW	0F0h
	MOVWF	TRISB		;RB0-3は出力
	MOVLW	088h		;プリスケーラ:使用しない（WDTに割り当て）
	MOVWF	OPTION_REG
	BCF	STATUS,RP0	;■バンク０に切替え

	CLRF	PORTA
	CLRF	PORTB

			;スイッチ状態クリア
	CLRF	sw_stat
	CLRF	sw_mode
	CLRF	sw_wait
	CLRF	lpush_stat
	MOVLW	d'10'
	MOVWF	CNT310mS
	MOVLW	d'20'
	MOVWF	CNT620mS

			;年月日初期化（2008.1.1）
	MOVLW	d'8'
	MOVWF	dyy
	MOVLW	d'1'
	MOVWF	dmm
	MOVWF	ddd
			;時刻初期化（00:00:00）
	CLRF	thh
	CLRF	tmm
	CLRF	tss

	CALL	adj_set		;時刻補正間隔タイマセット（EEPROMより）

	CALL	LCD_init	;LCD 初期化
	CALL	LCD_disp_init	;LCD 初期表示
	CALL	LCD_ymd		;LCDに年月日を表示

	MOVLW	d'32'
	MOVWF	CNT1S		;1秒カウンタセット
	CLRF	TMR0		;TMR0クリア
	MOVLW	0A0h		;TMR0割り込みを使用する
	MOVWF	INTCON

; ==================== メイン処理 =====================
main
	BTFSS	timer,T1s	;1S経過?
	GOTO	main2		; No
	BCF	timer,T1s	;1S経過フラグクリア
	BTFSC	sw_mode,0	;設定モードならカウント停止
	GOTO	main2		; Yes
	CALL	timer_up	;時分秒をカウントアップ
	CALL	LCD_hms		;LCDに時分秒を表示

main2
	BTFSS	timer,T31ms	;31mS経過?
	GOTO	main3		; No
	BCF	timer,T31ms	;31mS経過フラグクリア
	CALL	lpush_chk	;スイッチ長押し時間判定
	CALL	time_adj	;時刻補正

main3
	BTFSS	PORTB,sw1	;スイッチ１ＯＮ？
	CALL	sw1_on		; Yes
	BTFSS	PORTB,sw2	;スイッチ２ＯＮ？
	CALL	sw2_on		; Yes
	BTFSS	PORTB,sw3	;スイッチ３ＯＮ？
	CALL	sw3_on		; Yes
	BTFSC	PORTB,sw1	;スイッチ１ＯＦＦ？
	CALL	sw1_off		; Yes
	BTFSC	PORTB,sw2	;スイッチ２ＯＦＦ？
	CALL	sw2_off		; Yes
	BTFSC	PORTB,sw3	;スイッチ３ＯＦＦ？
	CALL	sw3_off		; Yes

	GOTO	main


;================= 時刻補正タイマ設定 ====================
;　EEPROMの0番地の内容から時刻補正間隔タイマ３バイトセット
adj_set
	MOVLW	00h
	CALL	EE_read		;補正値をEEPROMから読み込む
	MOVWF	adj_val
	MOVWF	workW
	BTFSS	workW,7		;補正値はマイナス？
	GOTO	adj_set_2	; No
	COMF	workW,F		;プラスに変換
	INCF	workW,F
adj_set_2
	MOVF	workW,W
	CALL	adj_set1	;補正タイマ下位１バイトセット
	MOVWF	adj_timer1
	MOVF	workW,W
	CALL	adj_set2	;補正タイマ２バイト目セット
	MOVWF	adj_timer2
	MOVF	workW,W
	CALL	adj_set3	;補正タイマ上位３バイト目セット
	MOVWF	adj_timer3

;		;　時刻補正タイマ初期化
	MOVF	adj_timer1,W
	MOVWF	adj_timerW1
	MOVF	adj_timer2,W
	MOVWF	adj_timerW2
	MOVF	adj_timer3,W
	MOVWF	adj_timerW3

	RETURN

;================= 時刻補正タイマ１設定 ====================
;　時刻補正間隔タイマ３バイトの下位１バイトセット
adj_set1
	ADDWF	PCL,F
	RETLW	0FFh	;補正０
	RETLW	000h	; 1  2A300
	RETLW	080h	; 2  15180
	RETLW	000h	; 3   E100
	RETLW	0C0h	; 4   A8C0
	RETLW	000h	; 5   8700
	RETLW	080h	; 6   7080
	RETLW	06Dh	; 7   606D
	RETLW	060h	; 8   5460
	RETLW	000h	; 9   4B00
	RETLW	080h	;10   4380
	RETLW	05Dh	;11   3D5D
	RETLW	040h	;12   3840
	RETLW	0ECh	;13   33EC
	RETLW	036h	;14   3036
	RETLW	000h	;15   2D00
	RETLW	030h	;16   2A30
	RETLW	0B4h	;17   27B4
	RETLW	080h	;18   2580
	RETLW	086h	;19   2386
	RETLW	0C0h	;20   21C0

;================= 時刻補正タイマ２設定 ====================
;　時刻補正間隔タイマ３バイトの２バイト目セット
adj_set2
	ADDWF	PCL,F
	RETLW	0FFh	;補正０
	RETLW	0A3h	; 1  2A300
	RETLW	051h	; 2  15180
	RETLW	0E1h	; 3   E100
	RETLW	0A8h	; 4   A8C0
	RETLW	087h	; 5   8700
	RETLW	070h	; 6   7080
	RETLW	060h	; 7   606D
	RETLW	054h	; 8   5460
	RETLW	04Bh	; 9   4B00
	RETLW	043h	;10   4380
	RETLW	03Dh	;11   3D5D
	RETLW	038h	;12   3840
	RETLW	033h	;13   33EC
	RETLW	030h	;14   3036
	RETLW	02Dh	;15   2D00
	RETLW	02Ah	;16   2A30
	RETLW	027h	;17   27B4
	RETLW	025h	;18   2580
	RETLW	023h	;19   2386
	RETLW	021h	;20   21C0

;================= 時刻補正タイマ３設定 ====================
;　時刻補正間隔タイマ３バイトの上位１バイトセット
adj_set3
	ADDWF	PCL,F
	RETLW	0FFh	;補正０
	RETLW	002h	; 1  2A300
	RETLW	001h	; 2  15180
	RETLW	000h	; 3   E100
	RETLW	000h	; 4   A8C0
	RETLW	000h	; 5   8700
	RETLW	000h	; 6   7080
	RETLW	000h	; 7   606D
	RETLW	000h	; 8   5460
	RETLW	000h	; 9   4B00
	RETLW	000h	;10   4380
	RETLW	000h	;11   3D5D
	RETLW	000h	;12   3840
	RETLW	000h	;13   33EC
	RETLW	000h	;14   3036
	RETLW	000h	;15   2D00
	RETLW	000h	;16   2A30
	RETLW	000h	;17   27B4
	RETLW	000h	;18   2580
	RETLW	000h	;19   2386
	RETLW	000h	;20   21C0


;================= 月毎の日数 ==============================
days
	ADDWF	PCL,F
	NOP
	RETLW	d'31'	;1月
	RETLW	d'28'	;2月
	RETLW	d'31'	;3月
	RETLW	d'30'	;4月
	RETLW	d'31'	;5月
	RETLW	d'30'	;6月
	RETLW	d'31'	;7月
	RETLW	d'31'	;8月
	RETLW	d'30'	;9月
	RETLW	d'31'	;10月
	RETLW	d'30'	;11月
	RETLW	d'31'	;12月


;================= 設定モードの項目にＬＣＤのアドレス設定 ===================
set_LCDaddr
	ADDWF	PCL,F
	NOP
	RETLW	084h	;年
	RETLW	087h	;月
	RETLW	08Ah	;日
	RETLW	0C0h	;am/pm
	RETLW	0C4h	;時
	RETLW	0C7h	;分
	RETLW	0CAh	;秒
	RETLW	0CFh	;補正値


;================= 年月日時分秒の設定（振り分け） ===========
dtime_adj
	MOVF	setIX,W
	ADDWF	PCL,F
	NOP
	GOTO	adj_dyy
	GOTO	adj_dmm
	GOTO	adj_ddd
	GOTO	adj_ampm
	GOTO	adj_thh
	GOTO	adj_tmm
	GOTO	adj_tss
	GOTO	adj_tadj


;================= 年の設定 ==================================
adj_dyy
	MOVF	CNTdtime,W	;加減算値(+1/-1)
	ADDWF	dyy,F		;年に±１する

	BTFSC	dyy,7		;-1?
	GOTO	adj_dyy1	; yes

	MOVF	dyy,W
	SUBLW	d'99'
	BTFSC	STATUS,C	;dyy＞99?
	GOTO	adj_dyy5	; No

	;　９９を超えたら０に戻す
	MOVLW	d'0'
	MOVWF	dyy
	GOTO	adj_dyy5

adj_dyy1
	;　－１になったら９９に戻す
	MOVLW	d'99'
	MOVWF	dyy

adj_dyy5
	;　年をＬＣＤに表示する
	MOVLW	083h		;1行3文字
	CALL	LCD_command
	MOVF	dyy,W
	CALL	bin2bcd
	CALL	disp_W
	MOVLW	084h		;1行4文字にカーソルを戻す
	CALL	LCD_command

	RETURN


;================= 月の設定 ==================================
adj_dmm
	MOVF	CNTdtime,W	;加減算値(+1/-1)
	ADDWF	dmm,F		;月に±１する

	BTFSC	STATUS,Z	;0?
	GOTO	adj_dmm1	; yes

	MOVF	dmm,W
	SUBLW	d'12'
	BTFSC	STATUS,C	;dmm＞12?
	GOTO	adj_dmm5	; No

	;　１２を超えたら１に戻す
	MOVLW	d'1'
	MOVWF	dmm
	GOTO	adj_dmm5

adj_dmm1
	;　０になったら１２に戻す
	MOVLW	d'12'
	MOVWF	dmm

adj_dmm5
	;　月をＬＣＤに表示する
	MOVLW	086h		;1行6文字
	CALL	LCD_command
	MOVF	dmm,W
	CALL	bin2bcd
	CALL	disp_W
	MOVLW	087h		;1行7文字にカーソルを戻す
	CALL	LCD_command

	RETURN


;================= 日の設定 ==================================
adj_ddd
	MOVF	CNTdtime,W	;加減算値(+1/-1)
	ADDWF	ddd,F		;日に±１する

	BTFSC	STATUS,Z	;0?
	GOTO	adj_ddd1	; yes

	MOVF	ddd,W
	SUBLW	d'31'
	BTFSC	STATUS,C	;ddd＞31?
	GOTO	adj_ddd5	; No

	;　３１を超えたら１に戻す
	MOVLW	d'1'
	MOVWF	ddd
	GOTO	adj_ddd5

adj_ddd1
	;　０になったら３１に戻す
	MOVLW	d'31'
	MOVWF	ddd

adj_ddd5
	;　日をＬＣＤに表示する
	MOVLW	089h		;1行9文字
	CALL	LCD_command
	MOVF	ddd,W
	CALL	bin2bcd
	CALL	disp_W
	MOVLW	08Ah		;1行10文字にカーソルを戻す
	CALL	LCD_command

	RETURN


;================= AM/PM表示の設定 ===========================
adj_ampm
	RETURN


;================= 時の設定 ==================================
adj_thh
	MOVF	CNTdtime,W	;加減算値(+1/-1)
	ADDWF	thh,F		;時に±１する

	BTFSC	thh,7		;-1?
	GOTO	adj_thh1	; yes

	MOVF	thh,W
	SUBLW	d'23'
	BTFSC	STATUS,C	;ddd＞23?
	GOTO	adj_thh5	; No

	;　２３を超えたら０に戻す
	MOVLW	d'0'
	MOVWF	thh
	GOTO	adj_thh5

adj_thh1
	;　－１になったら２３に戻す
	MOVLW	d'23'
	MOVWF	thh

adj_thh5
	;　時をＬＣＤに表示する
	MOVLW	0C3h		;2行3文字
	CALL	LCD_command
	MOVF	thh,W
	CALL	bin2bcd
	CALL	disp_W
	MOVLW	0C4h		;2行4文字にカーソルを戻す
	CALL	LCD_command

	RETURN


;================= 分の設定 ==================================
adj_tmm
	MOVF	CNTdtime,W	;加減算値(+1/-1)
	ADDWF	tmm,F		;分に±１する

	BTFSC	tmm,7		;-1?
	GOTO	adj_tmm1	; yes

	MOVF	tmm,W
	SUBLW	d'59'
	BTFSC	STATUS,C	;tmm＞59?
	GOTO	adj_tmm5	; No

	;　５９を超えたら０に戻す
	MOVLW	d'0'
	MOVWF	tmm
	GOTO	adj_tmm5

adj_tmm1
	;　－１になったら５９に戻す
	MOVLW	d'59'
	MOVWF	tmm

adj_tmm5
	;　分をＬＣＤに表示する
	MOVLW	0C6h		;2行6文字
	CALL	LCD_command
	MOVF	tmm,W
	CALL	bin2bcd
	CALL	disp_W
	MOVLW	0C7h		;2行7文字にカーソルを戻す
	CALL	LCD_command

	RETURN


;================= 秒の設定 ==================================
adj_tss
	MOVF	CNTdtime,W	;加減算値(+1/-1)
	ADDWF	tss,F		;秒に±１する

	BTFSC	tss,7		;-1?
	GOTO	adj_tss1	; yes

	MOVF	tss,W
	SUBLW	d'59'
	BTFSC	STATUS,C	;tss＞59?
	GOTO	adj_tss5	; No

	;　５９を超えたら０に戻す
	MOVLW	d'0'
	MOVWF	tss
	GOTO	adj_tss5

adj_tss1
	;　－１になったら５９に戻す
	MOVLW	d'59'
	MOVWF	tss

adj_tss5
	;　秒をＬＣＤに表示する
	MOVLW	0C9h		;2行9文字
	CALL	LCD_command
	MOVF	tss,W
	CALL	bin2bcd
	CALL	disp_W
	MOVLW	0CAh		;2行10文字にカーソルを戻す
	CALL	LCD_command

	RETURN


;================= 補正値の設定 ==============================
adj_tadj
	; 補正値が+-２０なら抜ける
	MOVF	adj_val,W
	BTFSS	adj_val,7	;マイナス？
	GOTO	adj_tadj2	; No
	COMF	adj_val,W
	ADDLW	01h
adj_tadj2
	SUBLW	d'20'		;補正値は
	BTFSS	STATUS,Z	;+-２０？
	GOTO	adj_tadj7	; No

	MOVF	adj_val,W
	MOVWF	workW
	MOVF	CNTdtime,W
	XORWF	workW,F
	BTFSS	workW,7		;補正値と加減算値の符号が異なる？
	GOTO	adj_tadj9	; No

adj_tadj7
	; ここから補正値加減算処理
	MOVF	CNTdtime,W	;加減算値(+1/-1)
	ADDWF	adj_val,F	;秒に±１する

	CALL	LCD_adj

	MOVLW	0CFh		;2行15文字
	CALL	LCD_command

adj_tadj9
	RETURN


;================= 時分秒をカウントアップする ===============
timer_up
	INCF	tss,F		;秒＋１
	MOVLW	d'60'		;
	SUBWF	tss,W		;秒＝６０？
	BTFSS	STATUS,Z	;
	GOTO	timer_up_exit	; No
	CLRF	tss

	INCF	tmm,F		;分＋１
	MOVLW	d'60'		;
	SUBWF	tmm,W		;分＝６０？
	BTFSS	STATUS,Z	;
	GOTO	timer_up_exit	; No
	CLRF	tmm

	INCF	thh,F		;時＋１
	MOVLW	d'24'		;
	SUBWF	thh,W		;時＝２４？
	BTFSS	STATUS,Z	;
	GOTO	timer_up_exit	; No
	CLRF	thh

	CALL	date_up		;日付＋１

timer_up_exit
	RETURN


;================= 年月日をカウントアップする ===============
date_up
	MOVF	dmm,W
	CALL	days		;月の日数取得

	INCF	ddd,F		;日＋１
	SUBWF	ddd,W		;日が月の最終日を超えた？
	BTFSC	STATUS,C	;
	BTFSC	STATUS,Z	;
	GOTO	date_up7	; No

;　２月ならうるう年対応
	MOVF	dmm,W
	SUBLW	d'2'
	BTFSS	STATUS,Z	;２月？
	GOTO	date_up2	; No

	BTFSS	dyy,0
	BTFSC	dyy,1		;うるう年？
	GOTO	date_up2	; No
	BTFSC	ddd,0		;２月２９日？
	GOTO	date_up7	; Yes

;　翌月にする
date_up2
	MOVLW	d'1'		;日を１に戻す
	MOVWF	ddd

	INCF	dmm,F		;月＋１
	MOVLW	d'13'
	SUBWF	dmm,W
	BTFSS	STATUS,C	;月＜１３？
	GOTO	date_up7	; Yes

;　翌年にする
	MOVLW	d'1'		;月を１に戻す
	MOVWF	dmm

	INCF	dyy,F		;年＋１

date_up7
	CALL	LCD_ymd		;ＬＣＤに年月日を表示

	RETURN


;================= 時刻補正 ============================
time_adj
	MOVF	adj_val,F	;補正値は
	BTFSC	STATUS,Z	;０？
	GOTO	time_adj_9	; Yes

; １　時刻補正時間経過判定
	MOVF	adj_timerW1,F	;下位１バイトは
	BTFSC	STATUS,Z	;０？
	GOTO	time_adj_1	; Yes
	DECF	adj_timerW1,F
	GOTO	time_adj_9
time_adj_1
	MOVF	adj_timerW2,F	;２バイト目は
	BTFSC	STATUS,Z	;０？
	GOTO	time_adj_2	; Yes
	DECF	adj_timerW1,F
	DECF	adj_timerW2,F
	GOTO	time_adj_9
time_adj_2
	MOVF	adj_timerW3,F	;上位１バイトは
	BTFSC	STATUS,Z	;０？
	GOTO	time_adj_3	; Yes
	DECF	adj_timerW1,F
	DECF	adj_timerW2,F
	DECF	adj_timerW3,F
	GOTO	time_adj_9
time_adj_3

; ２　時刻補正
	BTFSC	adj_val,7	;補正値はプラス？
	GOTO	time_adj_4	; No
	DECFSZ	CNT1S,F		; Yes 時刻を進める
	GOTO	time_adj_5
	BSF	timer,T1s	;1S経過フラグセット
	MOVLW	d'32'
	MOVWF	CNT1S
	GOTO	time_adj_5
time_adj_4
	INCF	CNT1S,F		; 時刻を遅らせる
time_adj_5

; ３　時刻補正タイマ初期化
	MOVF	adj_timer1,W
	MOVWF	adj_timerW1
	MOVF	adj_timer2,W
	MOVWF	adj_timerW2
	MOVF	adj_timer3,W
	MOVWF	adj_timerW3

time_adj_9
	RETURN


;================= LCDに時分秒を表示する ===============
LCD_hms
	MOVLW	0C3h		;2行3文字
	CALL	LCD_command
	MOVF	thh,W
	CALL	bin2bcd
	CALL	disp_W

	MOVLW	0C6h		;2行6文字
	CALL	LCD_command
	MOVF	tmm,W
	CALL	bin2bcd
	CALL	disp_W

	MOVLW	0C9h		;2行9文字
	CALL	LCD_command
	MOVF	tss,W
	CALL	bin2bcd
	CALL	disp_W

	RETURN


;================= LCDに年月日を表示する ===============
LCD_ymd
	MOVLW	083h		;1行3文字
	CALL	LCD_command
	MOVF	dyy,W
	CALL	bin2bcd
	CALL	disp_W

	MOVLW	086h		;1行6文字
	CALL	LCD_command
	MOVF	dmm,W
	CALL	bin2bcd
	CALL	disp_W

	MOVLW	089h		;1行9文字
	CALL	LCD_command
	MOVF	ddd,W
	CALL	bin2bcd
	CALL	disp_W

	RETURN


;================= LCDに補正値を表示する ===============
LCD_adj
	MOVLW	0CDh		;2行13文字
	CALL	LCD_command
	MOVF	adj_val,W
	MOVWF	workW
	BTFSS	adj_val,7	;補正値はマイナス？
	GOTO	LCD_adj1	; No
	MOVLW	'-'
	CALL	LCD_write
	COMF	workW,F		;プラスに変換
	INCF	workW,F
	GOTO	LCD_adj2
LCD_adj1
	MOVLW	'+'
	CALL	LCD_write
LCD_adj2
	MOVF	workW,W
	CALL	bin2bcd
	CALL	disp_W		;補正値をＬＣＤに表示
	RETURN


;================= ＬＣＤ初期表示 ===================
LCD_disp_init
	MOVLW	081h		;1行1文字
	CALL	LCD_command
	MOVLW	'2'
	CALL	LCD_write
	MOVLW	'0'
	CALL	LCD_write
	MOVLW	085h		;1行5文字
	CALL	LCD_command
	MOVLW	'/'
	CALL	LCD_write
	MOVLW	088h		;1行8文字
	CALL	LCD_command
	MOVLW	'/'
	CALL	LCD_write
	MOVLW	0C5h		;2行5文字
	CALL	LCD_command
	MOVLW	':'
	CALL	LCD_write
	MOVLW	0C8h		;2行8文字
	CALL	LCD_command
	MOVLW	':'
	CALL	LCD_write
	RETURN


;================= BCD変換（１０で割った商と余りを求める） =============
bin2bcd
	MOVWF	work1
	CLRF	work10
	MOVLW	d'10'
bin2bcd_loop
	SUBWF	work1,F		;work1-10
	BTFSS	STATUS,C	;work1 < 10
	GOTO	bin2bcd_end	; Yes
	INCF	work10,F	; No
	GOTO	bin2bcd_loop
bin2bcd_end
	ADDWF	work1,F
	SWAPF	work10,W
	IORWF	work1,W
	RETURN


;================= ＷレジスタのＢＣＤ２桁をＬＣＤに表示 =====
disp_W
	MOVWF	workW
	SWAPF	workW,W
	ANDLW	0fh
	IORLW	30h
	CALL	LCD_write	;１０の桁をＬＣＤに表示

	MOVF	workW,W
	ANDLW	0fh
	IORLW	30h
	CALL	LCD_write	;１の桁をＬＣＤに表示

	RETURN


;================= スイッチ１ＯＮ時の処理 ===================
sw1_on
	BTFSC	sw_stat,sw1	;既にＯＮ？
	GOTO	sw1_on3		; Yes
	CALL	wait15ms	;チャタリングキャンセル
	BTFSC	PORTB,sw1	;sw1 ON?
	GOTO	sw1_on9		; No
	BSF	sw_stat,sw1	;sw1 ON確定

	BTFSC	sw_mode,0	;設定モード？
	GOTO	sw1_on0		; Yes
	MOVLW	08Dh		;1行13文字
	CALL	LCD_command
	MOVLW	'1'
	CALL	LCD_write

sw1_on0
;　長押し設定
	MOVF	sw_wait,F	;既に
	BTFSS	STATUS,Z	; 長押し待ちあり？
	GOTO	sw1_on3		; Yes
	MOVLW	d'20'
	MOVWF	CNT620mS	;長押し0.6Sカウンタセット
	BCF	lpush_stat,lpush06	;長押し0.6Sフラグクリア
	BSF	sw_wait,0	;sw1長押し0.6S待ち
	GOTO	sw1_on9

;　長押し判定とその時の処理
sw1_on3
	BTFSC	sw_wait,0	;sw1長押し0.6S待ち？
	BTFSS	lpush_stat,lpush06	;長押し0.6S経過？
	GOTO	sw1_on9		; No
	MOVLW	0CDh		;2行13文字
	CALL	LCD_command
	BTFSS	sw_mode,0	;通常モード？（次は設定モード）
	GOTO	sw1_on4		; No
	MOVLW	00Ch		;カーソル非表示
	CALL	LCD_command
	MOVLW	' '
	CALL	LCD_write
	MOVLW	' '
	CALL	LCD_write
	MOVLW	' '
	CALL	LCD_write

	MOVF	adj_val,W	;補正値をEEPROMに保存
	MOVWF	EE_data
	CLRF	EE_addr
	CALL	EE_write
	CALL	adj_set		;補正値設定
	GOTO	sw1_on9
sw1_on4				;設定モード
	CALL	LCD_adj		;補正値をＬＣＤに表示
sw1_on9
	RETURN


;================= スイッチ１ＯＦＦ時の処理 ===================
sw1_off
	BTFSS	sw_stat,sw1	;既にＯＦＦ？
	GOTO	sw1_off99	; Yes
	CALL	wait15ms	;チャタリングキャンセル
	BTFSS	PORTB,sw1	;sw1 OFF?
	GOTO	sw1_off99	; No
	BCF	sw_stat,sw1	;sw1 OFF確定

sw1_off0
;　長押し判定とその時の処理
	BTFSS	sw_wait,0	;sw1長押し0.6S待ち？
	GOTO	sw1_off2	; No
	BTFSS	lpush_stat,lpush06	;長押し0.6S経過？
	GOTO	sw1_off2		; No
	BCF	sw_wait,0	;sw1長押し0.6S待ちクリア
	BTFSS	sw_mode,0	;通常／設定モード切り替え
	GOTO	sw1_off1
	BCF	sw_mode,0	;通常モードに切り替え
	GOTO	sw1_off9
sw1_off1
	BSF	sw_mode,0	;設定モードに切り替え
	MOVLW	0CFh		;2行15文字
	CALL	LCD_command
	MOVLW	00Eh		;カーソル表示
	CALL	LCD_command
	MOVLW	08h
	MOVWF	setIX		;設定項目インデックス初期化
	GOTO	sw1_off99

;　設定モードでＯＦＦになった（長押しでは無く）
sw1_off2
	BCF	sw_wait,0	;sw1長押し0.6S待ちクリア
	BTFSS	sw_mode,0	;設定モード？
	GOTO	sw1_off9	; No
	MOVF	sw_wait,F	;他で長押し待ち
	BTFSC	STATUS,Z	;　あり？
	CALL	set_datetime	; No （次の項目にカーソル移動）
	GOTO	sw1_off99	; Yes
;
sw1_off9
	MOVLW	08Dh		;1行13文字
	CALL	LCD_command
	MOVLW	' '
	CALL	LCD_write
sw1_off99
	RETURN


;================= 設定モードでの項目設定 ===================
set_datetime
	DECFSZ	setIX,F		;次の設定項目へ
	GOTO	set_datetime5
	MOVLW	08h
	MOVWF	setIX		;設定項目インデックス初期化

set_datetime5
	MOVF	setIX,W
	CALL	set_LCDaddr
	CALL	LCD_command	;設定項目にカーソル移動

set_datetime9
	RETURN


;================= スイッチ２ＯＮ時の処理 ===================
sw2_on
	BTFSC	sw_stat,sw2	;既にＯＮ？
	GOTO	sw2_on9		; Yes
	CALL	wait15ms
	BTFSC	PORTB,sw2	;sw2 ON?
	GOTO	sw2_on9		; No
	BSF	sw_stat,sw2	;sw2 ON確定

	BTFSC	sw_mode,0	;設定モード？
	GOTO	sw2_on1		; Yes
	MOVLW	08Eh		;1行14文字
	CALL	LCD_command
	MOVLW	'2'
	CALL	LCD_write
	GOTO	sw2_on9

;　時刻設定（カウントアップ）
sw2_on1
	MOVLW	01h
	MOVWF	CNTdtime	;カウントアップ
	CALL	dtime_adj	;年月日時分秒補正

sw2_on9
	RETURN


;================= スイッチ３ＯＮ時の処理 ===================
sw3_on
	BTFSC	sw_stat,sw3	;既にＯＮ？
	GOTO	sw3_on9		; Yes
	CALL	wait15ms
	BTFSC	PORTB,sw3	;sw3 ON?
	GOTO	sw3_on9		; No
	BSF	sw_stat,sw3	;sw3 ON確定

	BTFSC	sw_mode,0	;設定モード？
	GOTO	sw3_on1		; Yes
	MOVLW	08Fh		;1行15文字
	CALL	LCD_command
	MOVLW	'3'
	CALL	LCD_write
	GOTO	sw3_on9

;　時刻設定（カウントダウン）
sw3_on1
	MOVLW	0FFh
	MOVWF	CNTdtime	;カウントダウン
	CALL	dtime_adj	;年月日時分秒補正

sw3_on9
	RETURN


;================= スイッチ２ＯＦＦ時の処理 ===================
sw2_off
	BTFSS	sw_stat,sw2	;既にＯＦＦ？
	GOTO	sw2_off9	; Yes
	CALL	wait15ms
	BTFSS	PORTB,sw2	;sw2 OFF?
	GOTO	sw2_off9	; No
	BCF	sw_stat,sw2	;sw2 OFF確定

	BTFSC	sw_mode,0	;設定モード？
	GOTO	sw2_off9	; Yes
	MOVLW	08Eh		;1行14文字
	CALL	LCD_command
	MOVLW	' '
	CALL	LCD_write
sw2_off9
	RETURN


;================= スイッチ３ＯＦＦ時の処理 ===================
sw3_off
	BTFSS	sw_stat,sw3	;既にＯＦＦ？
	GOTO	sw3_off9	; Yes
	CALL	wait15ms
	BTFSS	PORTB,sw3	;sw3 OFF?
	GOTO	sw3_off9	; No
	BCF	sw_stat,sw3	;sw3 OFF確定

	BTFSC	sw_mode,0	;設定モード？
	GOTO	sw3_off9	; Yes
	MOVLW	08Fh		;1行15文字
	CALL	LCD_command
	MOVLW	' '
	CALL	LCD_write
sw3_off9
	RETURN


;================= 31m秒毎の処理（スイッチ長押し判定） ==========
lpush_chk
	DECFSZ	CNT310mS,F	;スイッチ長押し　0.3秒
	GOTO	lpush_chk1
	BSF	lpush_stat,lpush03
lpush_chk1
	DECFSZ	CNT620mS,F	;スイッチ長押し　0.6秒
	GOTO	lpush_chk9
	BSF	lpush_stat,lpush06
lpush_chk9
	RETURN


;================= ＬＣＤ表示をクリアする ===================
LCD_clear
	MOVLW	01h
	CALL	LCD_command
	CALL	wait2ms		;LCDのBFをチェックしないので1.64mS以上待つ
	RETURN

;================= ＬＣＤのカーソル位置を先頭に戻す =========
LCD_home
	MOVLW	02h
	CALL	LCD_command
	CALL	wait2ms		;LCDのBFをチェックしないので1.64mS以上待つ
	RETURN

;================= ＬＣＤのカーソル位置を２行目の先頭に =====
LCD_2line
	MOVLW	0C0h
	CALL	LCD_command
	RETURN

;================= ＬＣＤのディスプレイをＯＮにする =========
LCD_on
	MOVLW	0Ch
	CALL	LCD_command
	RETURN

;================= ＬＣＤのディスプレイとカーソルをＯＮにする ==
LCD_on_cur
	MOVLW	0Eh
	CALL	LCD_command
	RETURN

;================= ＬＣＤのディスプレイをＯＦＦにする =======
LCD_off
	MOVLW	08h
	CALL	LCD_command
	RETURN

;================= ＬＣＤにデータを送る =====================
LCD_write
	MOVWF	char

	BSF	PORTA,RS	;RS=1(Data)

	MOVLW	0F0h		;PORTBの下位４ビットを
	ANDWF	PORTB,F		;　クリア
	SWAPF	char,W		;上位
	ANDLW	0Fh		;４ビットを
	IORWF	PORTB,F		;PORTB(3-0)にセット（PORTB(7-4)はそのまま）
	BSF	PORTA,E		;ＬＣＤにデータ書き込み
	BCF	PORTA,E

	MOVLW	0F0h		;PORTBの下位４ビットを
	ANDWF	PORTB,F		;　クリア
	MOVF	char,W		;下位
	ANDLW	0Fh		;４ビットを
	IORWF	PORTB,F		;PORTB(3-0)にセット（PORTB(7-4)はそのまま）
	BSF	PORTA,E		;ＬＣＤにデータ書き込み
	BCF	PORTA,E

;	MOVLW	0F0h
;	ANDWF	PORTB,F
	MOVLW	0Fh
	IORWF	PORTB,F
	BCF	PORTA,RS	;RS=0

	RETURN

;================= ＬＣＤにコマンドを送る ===================
LCD_command
	MOVWF	char

	BCF	PORTA,RS	;RS=0(Command)

	MOVLW	0F0h		;PORTBの下位４ビットを
	ANDWF	PORTB,F		;　クリア
	SWAPF	char,W		;上位
	ANDLW	0Fh		;４ビットを
	IORWF	PORTB,F		;PORTB(3-0)にセット（PORTB(7-4)はそのまま）
	BSF	PORTA,E		;ＬＣＤにデータ書き込み
	BCF	PORTA,E

	MOVLW	0F0h		;PORTBの下位４ビットを
	ANDWF	PORTB,F		;　クリア
	MOVF	char,W		;下位
	ANDLW	0Fh		;４ビットを
	IORWF	PORTB,F		;PORTB(3-0)にセット（PORTB(7-4)はそのまま）
	BSF	PORTA,E		;ＬＣＤにデータ書き込み
	BCF	PORTA,E

;	MOVLW	0F0h
;	ANDWF	PORTB,F
	MOVLW	0Fh
	IORWF	PORTB,F

	RETURN

;================= LCD初期化 ================================
LCD_init
	BCF	PORTA,RS	;RS=0
	BCF	PORTA,E		;E=0

	MOVLW	03h		;下位４ビットに'３'をセット
	MOVWF	PORTB
	BSF	PORTA,E		;ファンクションセット（１回目）
	BCF	PORTA,E
	CALL	wait5ms		;5mS待つ

	BSF	PORTA,E		;ファンクションセット（２回目）
	BCF	PORTA,E
	CALL	wait5ms		;5mS待つ

	BSF	PORTA,E		;ファンクションセット（３回目）
	BCF	PORTA,E
	CALL	wait5ms		;5mS待つ

	MOVLW	02h		;４ビットモード
	MOVWF	PORTB		;に
	BSF	PORTA,E		;設定
	BCF	PORTA,E
	CALL	wait1ms		;1mS待つ

	MOVLW	028h		;４ビットモード，２行表示，７ドット
	CALL	LCD_command
	CALL	LCD_off		;ディスプレイＯＦＦ
	CALL	LCD_clear	;ＬＣＤクリア
	MOVLW	06h		;
	CALL	LCD_command	;カーソルモードセット (Increment)
	CALL	LCD_on		;ディスプレイＯＮ，カーソルＯＦＦ

	RETURN

;================= EE read ================================
EE_read
	MOVWF	EEADR		;アドレスをEEADRへセット
	BSF	STATUS,RP0	;■バンク１に切替え
	BSF	EECON1,RD	;読み出し開始
	BCF	STATUS,RP0	;■バンク０に切替え
	MOVF	EEDATA,W	;Ｗレジスタにデータ取り出し
	RETURN

;================= EE write ================================
EE_write
	MOVF	EE_addr,W	;データエリアのアドレス指定
	MOVWF	EEADR		;アドレスをEEADRへセット
	MOVF	EE_data,W	;書き込みデータの内容を
	MOVWF	EEDATA		; EEDATAにセット
	BSF	STATUS,RP0	;■バンク１に切替え
	BSF	EECON1,WREN	;EEPROM書き込み許可
	MOVLW	55H		;
	MOVWF	EECON2		;
	MOVLW	0AAH
	MOVWF	EECON2
	BSF	EECON1,WR	;EEPROM書き込み開始
EE_write_LP
	BTFSC	EECON1,WR	;EEPROM書き込み完了？
	GOTO	EE_write_LP
	BCF	STATUS,RP0	;■バンク０に切替え
	RETURN

;================= 15mS WAIT ================================
;123命令
wait15ms
	MOVLW	d'39'
	MOVWF	CNT15mS
wait15ms_loop
	DECFSZ	CNT15mS,F
	GOTO	wait15ms_loop
	RETURN

;================= 5mS WAIT =================================
;41命令
wait5ms
	MOVLW	d'11'
	MOVWF	CNT5mS
wait5ms_loop
	DECFSZ	CNT5mS,F
	GOTO	wait5ms_loop
	RETURN

;================= 1.7mS WAIT =================================
;14命令
wait2ms
	MOVLW	d'3'
	MOVWF	CNT2mS
wait2ms_loop
	DECFSZ	CNT2mS,F
	GOTO	wait2ms_loop
	RETURN

;================= 1mS WAIT =================================
;8命令
wait1ms
	NOP
	NOP
	NOP
	NOP
	RETURN

	END
