;***** Counter_WonderCore.asm *********************************************
;
;	Wonder Core 用 カウンター
;
;	Copyright (C) 2018   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2018/01/20  by M.Yamamoto )
;	coding:  Ver. 1.00   2018/01/27  初期バージョン
;	bugfix:  Ver. 1.10   2018/02/25  センサ変更に伴う変更
;	update:  Ver. x.xx
;
;******************************************************* PicAsm 0243 ******

;	Device: PIC16F628A	Clock: 4MHz (セラロック)

#ifdef comment

 <機能概要>

・本機は、Wonder Core で「クランチ」運動等をしたときの、その回数をカウントするのを目的とする。

・まず、本機の電源をＯＮにすると、開始音としての "ドミソド" ブザー音が出力される。その後、CURRENT（現在）LED の点灯とともに、本機内
　に記憶されている現在のカウント数が４桁の７セグ LED に表示され、新たなセンサからのカウント信号や各種スイッチの入力を待つ。

・初めに各 LED の点灯の意味とスイッチの機能を説明しておくと、この CURRENT（現在）LED の点灯時は、現在のカウント数が４桁の７セグ LED 
　に表示されていることを意味し、センサからのカウント信号によって、"ピポッ" ブザー音とともに１つカウントアップされる。内部的には現在
　カウント数、および合計カウント数の両者がカウントアップされている。

・この CURRENT（現在）LED の点灯時に、ENABLE スイッチを押しながら RESET スイッチが押されると、内部の現在カウント数だけが "0000" クリ
　アされ、"ブー" ブザー音とともに４桁の７セグ LED の表示も "0000" クリアされる。（この CURRENT（現在）LED の点灯時に RESET スイッチ
　だけを押しても何も起こらない。）

・また、TOTAL（合計）LED の点灯時は、今までの合計カウント数が４桁の７セグ LED に表示されていることを意味し、センサからのカウント信号
　によって、CURRENT（現在）LED の点灯時と同様に、"ピポッ" ブザー音とともに１つカウントアップされる。内部的には現在カウント数、および
　合計カウント数の両者がカウントアップされているのは、CURRENT（現在）LED の点灯時と同様である。

・この TOTAL（合計）LED の点灯時に、ENABLE スイッチを押しながら RESET スイッチを押し、なおかつ、この状態を５秒間以上続けることによっ
　て、内部の合計カウント数、および現在カウント数が "0000" クリアされ、"ブッブー" ブザー音とともに４桁の７セグ LED の表示も "0000" ク
　リアされる。（この TOTAL（合計）LED の点灯時に RESET スイッチだけを押したり、ENABLE スイッチを押しながらでも５秒間未満の場合には、
　何も起こらない。）

・これらの CURRENT（現在）LED と TOTAL（合計）LED の点灯を切り替えるには、SELECT スイッチを押すことによって行われ、押す毎に交互に切
　り替わるトグルスイッチとして動作する。

・CORRECT. スイッチの機能は、本機を運用上で何らかの理由により、表示されているカウント数を減算したい場合に用いる。このスイッチの場合
　も ENABLE スイッチと併用して用い、ENABLE スイッチを押しながら CORRECT. スイッチを押すと、本機内に記憶されている現在カウント数、お
　よび合計カウント数の両者が -1 減算され、"ブッ" ブザー音とともに現在表示されている４桁の７セグ LED の表示が、１つカウントダウンされ
　る。ただし、現在カウント数、および合計カウント数はともに "0000" が最低値で、マイナス値になることはない。また、本機にはスイッチによ
　る加算機能は持たせておらず、センサからのカウント信号のみがカウントアップする唯一の方法となる。

 <本機を運用する上での参考>

・上に述べたように、本機には７セグ LED に現在カウント数と合計カウント数の両者を、SELECT スイッチで切り替えて表示することができる。ま
　た、それぞれのカウント数は常に本機内部でバックアップが取られている。したがって、使用しないときには本機の電源をＯＦＦにして、電池の
　消耗を防ぐことが可能である。再開したいときには、いつでも電源をＯＮにすれば前回の各カウント数はそのまま引き継がれ、電源をＯＦＦする
　前の状態に戻すことができる。

・私が本機を使用する場合、現在カウント数は例えば朝昼夜と同一日の累計をカウントするために用い、次の日の朝に使用する前に "0000" クリア
　して、またその日の一日の累計をカウントする。

・そして、合計カウント数は１か月分の累計をカウントするために用いることを想定している。１か月が経ったら次に、同様に使用する前に "0000" 
　クリアして、また次の１か月分のために備える。私の場合、各カウント数とも４桁の７セグ LED の表示があれば十分で、そのように本機を設計し
　たが、Wonder Core のヘビーユーザーには、ひょっとしたら４桁では足りないかもしれない。（そのような方には申し訳ない。）

・ただし、これは４桁の７セグ LED での表示上の問題であり、本機内部でのカウンタは、現在カウント数、合計カウント数とも最大 65,535 までカ
　ウントすることができる。したがって、４桁の LED 表示では最大 "9999" までしか表示することができないので、次には "0000" に戻ってしまう
　が、本来は "10000" と表示されるべきところだが ５桁目が存在しないために、下４桁の "0000" だけが表示されることになる。

#endif

;==========================================================================

;	PIC16F628A のピンと用途

;	 (1) RA2: 7セグLED 3 桁目出力		(18) RA1: 7セグLED 2 桁目出力
;	 (2) RA3: 7セグLED 4 桁目出力		(17) RA0: 7セグLED 1 桁目出力
;	 (3) RA4: LED C/T 出力			(16) RA7: オシレータ水晶入力
;	 (4) RA5: センサ入力			(15) RA6: オシレータ水晶入力
;	 (5) VSS: 電源 GND			(14) VDD: 電源 +5V DC
;	 (6) RB0: a 出力 / SELECTスイッチ入力	(13) RB7: ブザー 出力
;	 (7) RB1: b 出力 / RESETスイッチ入力	(12) RB6: g 出力
;	 (8) RB2: c 出力 / CORRECT.スイッチ入力	(11) RB5: f 出力
;	 (9) RB3: d 出力 / ENABLEスイッチ入力	(10) RB4: e 出力

;	*注.  RA4 の出力はオープンドレインのため、外部抵抗でプルアップしないと、High が出力されない。
;	      RA5 は入力専用で、出力ポートには使えない。

;==========================================================================

	list		p=pic16f628a		;デバイス情報
	include		p16f628a.inc		;インクルードファイル
	errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションの設定
;==========================================================================

	__config  _CP_OFF & _CPD_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC

;==========================================================================
;		変数、定数の定義とレジスタ割付け
;==========================================================================

;#define 	_debug				;TMR0 基準時間の調整中

		radix	dec

xx		equ	15			;補正値-1
tm0_h_val	equ	256 - 200 + xx		;ハードタイマー０カウント値 (4 / 4MHz * 200 = 200μS)
tm0_s_val	equ	2500			;ソフトタイマー０のカウント値 (200 * 2500 = 500mS)

selsw		equ	0			;RB0: SELECT スイッチ
ressw		equ	1			;RB1: RESET スイッチ
corsw		equ	2			;RB2: CORRECT. スイッチ
ensw		equ	3			;RB3: ENABLE スイッチ
buzzer		equ	7			;RB7: ブザー音 出力
ra0		equ	0			;RA0: 7セグLED 1 桁目
ra1		equ	1			;RA1: 7セグLED 2 桁目
ra2		equ	2			;RA2: 7セグLED 3 桁目
ra3		equ	3			;RA3: 7セグLED 4 桁目
ra4		equ	4			;RA4: CURRENT / TOTAL LED
countin		equ	5			;RA5: センサ入力信号

f_doh		equ	65536 -  956		;ド (523.26 Hz)  at 4MHz
f_so		equ	65536 - 1276		;ソ (392.00 Hz)
f_mi		equ	65536 - 1517		;ミ (329.63 Hz)
f_do		equ	65536 - 1911		;ド (261.63 Hz)
po_tim		equ	100			;音長(ms)
pi_tim		equ	100			;音長
bu_tim		equ	100			;音長
buu_tim		equ	250			;音長
dms_tim		equ	200			;音長

seg7_0		equ     b'11000000'		;-gfedcba Pattern 0
seg7_1		equ     b'11111001'		;         Pattern 1
seg7_2		equ     b'10100100'		;         Pattern 2
seg7_3		equ     b'10110000'		;         Pattern 3
seg7_4		equ     b'10011001'		;         Pattern 4
seg7_5		equ     b'10010010'		;         Pattern 5
seg7_6		equ     b'10000010'		;         Pattern 6
seg7_7		equ     b'11111000'		;         Pattern 7
seg7_8		equ     b'10000000'		;         Pattern 8
seg7_9		equ     b'10010000'		;         Pattern 9
seg7_e		equ     b'11101111'		;         e-seg (TOTAL)
seg7_f		equ     b'11011111'		;         f-seg (CURRENT)
seg7_off	equ     b'11111111'		;         LED off

		cblock	h'40'
bin1					;周波数入力カウンタ（最上位）
bin0					;周波数入力カウンタ（最下位）
dec4					;BIN → DEC 変換の出力エリア（最上位）
dec3					;
dec2					;
dec1					;
dec0					;BIN → DEC 変換の出力エリア（最下位）
dv10cnt					;bindec16サブルーチンで使用
dv10wk					;bindec16サブルーチンで使用

differ					;DIFFERENCE（差分）
upd_bin1				;UPDATE（更新）カウンタ（上位）
upd_bin0				;UPDATE（更新）カウンタ（下位）
cur_bin1				;CURRENT（現在）カウンタ（上位）
cur_bin0				;CURRENT（現在）カウンタ（下位）
tot_bin1				;TOTAL（合計）カウンタ（上位）
tot_bin0				;TOTAL（合計）カウンタ（下位）

sw_stat					;全スイッチの入力状態を一時保存
sel_flg					;選択フラグ: 0:CURRENT, 1:TOTAL
monitor_on				;センサ入力ON監視フラグ
monitor_off				;センサ入力OFF監視フラグ
monitor_sw				;スイッチ監視フラグ
monitor_tot				;TOTAL RESET監視フラグ

tm0_cnt_h				;ソフトタイマー０の high カウンタ
tm0_cnt_l				;ソフトタイマー０の low  カウンタ
const_high				;音階用分周定数 high の保存
const_low				;音階用分周定数 low の保存
dsplc					;時間表示ループカウンタ
eep_cnt					;記録データ数
wt1cnt					;ウェイト用ループカウンタ
wt2cnt					;ウェイト用ループカウンタ
wt3cnt					;ウェイト用ループカウンタ
temp					;
		endc

		cblock	h'70'
w_save					;W レジスタの退避用
s_save					;STATUS レジスタの退避用
		endc

;==========================================================================
;		マクロ命令定義
;==========================================================================

;		Sound_M マクロ

Sound_M		macro	@scale,@time
		movlw	high @scale	;出力音階
		movwf	const_high
		movlw	low @scale
		movwf	const_low
		movlw	@time		;出力時間(ms)
		call	buzzer_control	;ブザー音出力コントロール
		endm

;==========================================================================
;		プログラム開始
;==========================================================================

		org	h'0000'		;リセットベクタ
		goto	start

		org	h'0004'		;割り込みベクタ
		goto	interrupt

;==========================================================================
;		W に指定された "0"～"9" の数字を 表示パターンに変換
;	（PCL を操作する場合はプログラムを配置する位置に配慮すること）
;==========================================================================

ptn_set
;		andlw	h'0f'
		addwf	PCL,F		;プログラム・カウンタに加算

		retlw	seg7_0		;0
		retlw	seg7_1		;1
		retlw	seg7_2		;2
		retlw	seg7_3		;3
		retlw	seg7_4		;4
		retlw	seg7_5		;5
		retlw	seg7_6		;6
		retlw	seg7_7		;7
		retlw	seg7_8		;8
		retlw	seg7_9		;9

;==========================================================================
;		初期化処理
;==========================================================================

start
		bcf	STATUS,RP1
		bcf	STATUS,RP0	;バンク 0
		clrf	PORTA		;
		movlw	b'00000111'	;RA3-0 を Digital I/O
		movwf	CMCON		;CMCON に設定

		bsf	STATUS,RP0	;バンク 1
		movlw	b'00100000'	;RA5: 入力, RA4-0: 出力
		movwf	TRISA		;ポートA の I/0 設定
		movlw	b'00000000'	;RB7-0: 出力
		movwf	TRISB		;ポートB の I/0 設定

		movlw	b'10001000'	;bit7=1: PORTB は PULL-UP しない
					;bit6=0: GP2 の割込みは立下りエッジ
					;bit5=0: TMR0 クロックは内部供給
					;bit4=0: TMR0 L から H でカウント
					;bit3=1: TMR0 にプリスケーラを使用しない
					;bit2-0=000: プリスケーラ比
		movwf	OPTION_REG	;OPTION_REG に設定

		bcf	PIE1,TMR1IE	;TMR1IE: タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0
		bcf	INTCON,T0IE	;T0IE: タイマー０割り込みを禁止

		movlw	b'00000001'	;bit7-6: 未使用
					;bit5-4=00: プリスケーラのスケール値 1:1
					;bit3=0: 専用の発振器を使う場合に指定
					;bit2=0: 外部入力クロック指定時に有効
					;bit1=0: 内部クロックを使う
					;bit0=1: タイマー１を動作
		movwf	T1CON		;T1CON に設定

		movlw	b'00011111'	;
		movwf	PORTA		;ポートA をすべて OFF("H") にしておく
#ifdef _debug
		bsf	PORTB,buzzer	;;;
#endif

		bsf	INTCON,PEIE	;PEIE: 周辺機器割り込みを許可
		bsf	INTCON,GIE	;GIE: グローバル割り込み許可

		; 各変数の初期設定等

		clrf	sel_flg		;選択フラグ (0:CURRENT, 1:TOTAL) の初期設定
		clrf	monitor_on	;センサ入力ON監視フラグの初期設定
		clrf	monitor_off	;センサ入力OFF監視フラグの初期設定
		clrf	monitor_tot	;TOTAL RESET監視フラグの初期設定
		clrf	monitor_sw	;スイッチ監視フラグの初期設定
		call	eep_rd		;EEPROM データの読み出し

		call	dl_mi_so_dh	;"ドミソド" ブザー音出力

;==========================================================================
;		メイン・ルーチン
;==========================================================================

main		call	count_disp	;カウンタ値(CURRENT/TOTAL)のＬＥＤ表示（ＸＸＸＸ）
		btfsc	monitor_sw,0	;スイッチ監視フラグ(0) = ON か？
		goto	m13		;Yes

		; センサ入力信号の監視

;		　　　　　on　　　　　　　　　　　off
;		─────┐　　　　　　　　　　　┌─────────
;		　　　　　└──────┤├───┘
;		　　　　　│ 500mS │　　　　　　 │ 500mS │
;			　on0    on1,on2         off0     off1
;		　　　　　　　　　　　　　　　　　　　　　 ↑（カウンタを +1更新） 

		btfsc	monitor_on,0	;センサ入力ON監視フラグ(0) = ON か？
		goto	m01		;Yes

		btfsc	monitor_on,2	;センサ入力ON監視フラグ(2) = ON か？
		goto	m02		;Yes

		btfsc	monitor_off,0	;センサ入力OFF監視フラグ(0) = ON か？
		goto	m03		;Yes

		btfsc	PORTA,countin	;RA5: センサ入力信号 = ON("L") か？
		goto	m04		;No

		bsf	monitor_on,0	;センサ入力ON監視フラグ(0) = ON
		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定
		movlw	high tm0_s_val	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	low tm0_s_val	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		bsf	INTCON,T0IE	;タイマー０割り込みを許可
		goto	main		;センサ入力信号の監視中はスイッチ入力を受け付けない（以下同）

m01		btfss	monitor_on,1	;センサ入力ON監視フラグ(1) = ON（500mS経過）か？
		goto	main		;No

		clrf	monitor_on	;センサ入力ON監視フラグの初期設定
		btfsc	PORTA,countin	;RA5: センサ入力信号 = ON("L") か？
		goto	main		;No. 無効にする
					;（500mS経過直後はまだON("L")であること）
		bsf	monitor_on,2	;センサ入力ON監視フラグ(2) = ON
		call	buzzer_po	;"ポッ" ブザー音出力 (100 mS)
		goto	main

m02		btfss	PORTA,countin	;RA5: センサ入力信号 = OFF("H") か？
		goto	main		;No

		clrf	monitor_on	;センサ入力ON監視フラグの初期設定
		bsf	monitor_off,0	;センサ入力OFF監視フラグ(0) = ON
		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定
		movlw	high tm0_s_val	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	low tm0_s_val	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		bsf	INTCON,T0IE	;タイマー０割り込みを許可
		goto	main

m03		btfss	monitor_off,1	;センサ入力OFF監視フラグ(1) = ON（500mS経過）か？
		goto	main		;No

		btfss	PORTA,countin	;RA5: センサ入力信号 = OFF("H") か？
		goto	main		;No

		clrf	monitor_off	;センサ入力OFF監視フラグの初期設定
		incf	cur_bin0,F	;CURRENT カウンタ（下位）を +1 更新
		btfsc	STATUS,Z	;CURRENT カウンタ（下位）= 0 か？
		incf	cur_bin1,F	;Yes. CURRENT カウンタ（上位）を +1 更新
		incf	tot_bin0,F	;TOTAL カウンタ（下位）を +1 更新
		btfsc	STATUS,Z	;TOTAL カウンタ（下位）= 0 か？
		incf	tot_bin1,F	;Yes. TOTAL カウンタ（上位）を +1 更新
		call	eep_wr		;EEPROM データの書き込み
		call	count_disp	;カウンタ値(CURRENT/TOTAL)のＬＥＤ表示を即更新
		call	buzzer_pipo	;"ピポッ" ブザー音出力 (230mS)
		goto	main

		; スイッチの入力状態の読み取り

m04		call	sw_read		;スイッチの入力状態の読み取り
		movlw	b'00000111'
		andwf	sw_stat,W	;ENABLE スイッチ以外の
		btfsc	STATUS,Z	;入力があるか？
		goto	main		;No

		; RESET + ENABLE スイッチ = ON (CURRENT) の判定とその処理

		btfss	sw_stat,ressw	;RESET スイッチ = ON か？
		goto	m09		;No

		btfss	sw_stat,ensw	;ENABLE スイッチ = ON か？
		goto	main		;No. （無視する）

		btfsc	sel_flg,0	;選択フラグ = 0:CURRENT か？
		goto	m05		;No

		clrf	cur_bin1	;CURRENT カウンタ（上位）を 0クリア
		clrf	cur_bin0	;CURRENT カウンタ（下位）を 0クリア
		call	eep_wr		;EEPROM データの書き込み
		call	count_disp	;カウンタ値(CURRENT/TOTAL)のＬＥＤ表示を即更新
		call	buzzer_buu	;"ブー" ブザー音出力 (250mS)
		goto	m12

		; RESET + ENABLE スイッチ = ON (TOTAL) の判定とその処理

m05		bsf	monitor_tot,0	;TOTAL RESET監視フラグ(0) = ON
		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定
		movlw	high (tm0_s_val * 10)	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	low (tm0_s_val * 10)	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		bsf	INTCON,T0IE	;タイマー０割り込みを許可

#ifdef _debug
		bcf	PORTB,buzzer	;;;
#endif
m06		call	count_disp	;カウンタ値(CURRENT/TOTAL)のＬＥＤ表示
		btfss	monitor_tot,1	;TOTAL RESET監視フラグ(1) = ON（5秒経過） か？
		goto	m06		;No
#ifdef _debug
		bsf	PORTB,buzzer	;;;
#endif

m07		call	sw_read		;スイッチの入力状態の読み取り
		btfss	sw_stat,ressw	;RESET スイッチ = ON か？
		goto	m08		;No

		btfss	sw_stat,ensw	;ENABLE スイッチ = ON か？
		goto	m08		;No.（5秒経過直後OFFの場合は無効となる）
					;（5秒経過直後は両スイッチがまだONであること）
		call	count_disp	;カウンタ値(CURRENT/TOTAL)のＬＥＤ表示
		btfsc	monitor_tot,2	;TOTAL RESET監視フラグ(2) = ON か？
		goto	m07		;Yes

		bsf	monitor_tot,2	;TOTAL RESET監視フラグ(2) = ON
		clrf	tot_bin1	;TOTAL カウンタ（上位）を 0クリア
		clrf	tot_bin0	;TOTAL カウンタ（下位）を 0クリア
		clrf	cur_bin1	;CURRENT カウンタ（上位）を 0クリア
		clrf	cur_bin0	;CURRENT カウンタ（下位）を 0クリア
		call	eep_wr		;EEPROM データの書き込み
		call	count_disp	;カウンタ値(CURRENT/TOTAL)のＬＥＤ表示を即更新
		call	buzzer_bubuu	;"ブッブー" ブザー音出力 (450mS)
		goto	m07

m08		clrf	monitor_tot	;TOTAL RESET監視フラグの初期設定
		goto	m12

		; CORRECT. + ENABLE スイッチ = ON の判定とその処理

m09		btfss	sw_stat,corsw	;CORRECT. スイッチ = ON か？
		goto	m11		;No

		btfss	sw_stat,ensw	;ENABLE スイッチ = ON か？
		goto	main		;No. （無視する）

		movf	tot_bin0,W
		iorwf	tot_bin1,W
		btfsc	STATUS,Z	;TOTAL カウンタ = 0 か？
		goto	main		;Yes

		movlw	1
		subwf	tot_bin0,F	;TOTAL カウンタ（下位）を -1 更新
		btfss	STATUS,C	;TOTAL カウンタ（下位）< 0 か？
		decf	tot_bin1,F	;Yes. TOTAL カウンタ（上位）を -1 更新

		movf	cur_bin0,W
		iorwf	cur_bin1,W
		btfsc	STATUS,Z	;CURRENT カウンタ = 0 か？
		goto	m10		;Yes

		movlw	1
		subwf	cur_bin0,F	;CURRENT カウンタ（下位）を -1 更新
		btfss	STATUS,C	;CURRENT カウンタ（下位）< 0 か？
		decf	cur_bin1,F	;Yes. CURRENT カウンタ（上位）を -1 更新

m10		call	eep_wr		;EEPROM データの書き込み
		call	count_disp	;カウンタ値(CURRENT/TOTAL)のＬＥＤ表示を即更新
		call	buzzer_bu	;"ブッ" ブザー音出力 (100 mS)
		goto	m12

		; SELECT スイッチ = ON の判定とその処理

m11		btfss	sw_stat,selsw	;SELECT スイッチ = ON か？
		goto	main		;No. (Illegal)

		movlw	b'00000001'
		xorwf	sel_flg,F	;"CURRENT / TOTALフラグの切り替え
		call	count_disp	;カウンタ値(CURRENT/TOTAL)のＬＥＤ表示を即更新
		call	buzzer_pi	;"ピッ" ブザー音出力 (100 mS)

		; スイッチの重複検出防止時間の確保

m12		bsf	monitor_sw,0	;スイッチ監視フラグ(0) = ON
		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定
		movlw	high (tm0_s_val / 2)	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_h	;ソフトタイマー０の high カウンタの設定
		movlw	low (tm0_s_val / 2)	;ソフトタイマー０のカウント値
		movwf	tm0_cnt_l	;ソフトタイマー０の low  カウンタの設定
		bsf	INTCON,T0IE	;タイマー０割り込みを許可
		goto	main

m13		btfss	monitor_sw,1	;スイッチ監視フラグ(1) = ON（250mS経過） か？
		goto	main		;No

		clrf	monitor_sw	;スイッチ監視フラグの初期設定
		goto	main

;==========================================================================

		; スイッチの入力状態の読み取り

sw_read		bsf	STATUS,RP0	;バンク 1
		movlw	b'00001111'
		movwf	TRISB		;ポートB の I/0 設定: RB0～RB3入力
		bcf	STATUS,RP0	;バンク 0

		movf	PORTB,W		;全スイッチの入力状態を
		andlw	b'00001111'	;一度に読み取り
		xorlw	b'00001111'	;'0'→'1'に反転して
		movwf	sw_stat		;一時保存する

		bsf	STATUS,RP0	;バンク 1
		clrf	TRISB		;ポートB の I/0 設定: すべて出力
		bcf	STATUS,RP0	;バンク 0
		return

;==========================================================================
;		EEPROM データの読み出しと書き込み
;==========================================================================

;		de	h'00'		;差分 DIFFERENCE	─┐ 記録位置
;		de	h'00',h'00'	;更新 UPDATE1,UPDATE0	─┘ の管理用
;		de	h'00',h'00'	;現在 CURRENT1,CURRENT0
;		de	h'00',h'00'	;合計 TOTAL1,TOTAL0
;		de	h'00',h'00'	;更新 UPDATE1,UPDATE0	─┐
;		de	h'00',h'00'	;現在 CURRENT1,CURRENT0	　│ 次の記録位置
;		de	h'00',h'00'	;合計 TOTAL1,TOTAL0	─┘
;		de	:
;		de	:
;		de	:

		; EEPROM データの読み出し

eep_rd		bsf	STATUS,RP0	;バンク1
		clrf	EEADR		;EEPROM の先頭アドレスを設定
		bsf	EECON1,RD	;読み出し制御 = ON
		movf	EEDATA,W	;DIFFERENCE（差分）データの読み出し
		addwf	EEADR,F		;EEPROM の記録アドレスを更新
		bcf	STATUS,RP0	;バンク0

		movwf	differ		;差分データを退避
		movlw	upd_bin1	;UPDATE（更新）カウンタ（上位）のアドレスを
		movwf	FSR		;間接アドレスに設定

		movlw	6
		movwf	eep_cnt		;記録（カウンタ）データ数

epr01		bsf	STATUS,RP0	;バンク1
		incf	EEADR,F		;EEPROM の記録アドレスを更新
		bsf	EECON1,RD	;読み出し制御 = ON
		movf	EEDATA,W	;データの読み出し
		bcf	STATUS,RP0	;バンク0

		movwf	INDF		;各カウンタへ書き込み
		incf	FSR,F		;間接アドレスの更新
		decfsz	eep_cnt,F	;記録データ数 - 1 = 0 か？
		goto	epr01		;No

		return

;==========================================================================

		; EEPROM データの書き込み

; EEPROMへの書き込み回数が 65,535（2バイトカウンタの最大値）+1回ごとに、
; 各カウンタデータ（2 x 3 = 6バイト分）の書き込み位置を更新する。
; EEPROMへの書き込み回数は、最低10万回が保証されているらしいが、余裕をみる
; ことと、プログラムを簡単にするために、2バイトカウンタの最大値で管理した。

eep_wr
		bsf	STATUS,RP0	;バンク1
		clrf	EEADR		;EEPROM の先頭アドレスを設定
		bcf	STATUS,RP0	;バンク0

		incf	upd_bin0,F	;UPDATE（更新）カウンタ（下位）を +1 更新
		btfss	STATUS,Z	;カウンタ（下位）= 0 か？
		goto	epw01		;No

		incf	upd_bin1,F	;Yes. UPDATE（更新）カウンタ（上位）を +1 更新
		btfss	STATUS,Z	;カウンタ（上位）= 0 か？
		goto	epw01		;No

;		差分 DIFFERENCE データ の書き込み

		movlw	6
		addwf	differ,F	;差分データを更新
		movf	differ,W

		bsf	STATUS,RP0	;バンク1
		movwf	EEDATA		;書き込みデータ（差分データ）を設定
		bsf	EECON1,WREN	;書き込みイネーブル = ON
		movlw	h'55'
		movwf	EECON2		;h'55' を EECON2 に書き込む
		movlw	h'aa'
		movwf	EECON2		;h'aa' を EECON2 に書き込む
		bsf	EECON1,WR	;書き込み開始
		btfsc	EECON1,WR	;書き込み 終了か?
		goto	$-1		;No

		bcf	STATUS,RP0	;バンク0

;		カウンタ データ の書き込み

epw01		movf	differ,W	;差分データ

		bsf	STATUS,RP0	;バンク1
		addwf	EEADR,F		;EEPROM の記録アドレスを更新
		bcf	STATUS,RP0	;バンク0

		movlw	upd_bin1	;UPDATE（更新）カウンタ（上位）のアドレスを
		movwf	FSR		;間接アドレスに設定

		movlw	6
		movwf	eep_cnt		;記録（カウンタ）データ数

epw02		movf	INDF,W		;各カウンタデータの読み出し

		bsf	STATUS,RP0	;バンク1
		incf	EEADR,F		;EEPROM の記録アドレスを更新
		movwf	EEDATA		;書き込みデータを設定
		bsf	EECON1,WREN	;書き込みイネーブル = ON
		movlw	h'55'
		movwf	EECON2		;h'55' を EECON2 に書き込む
		movlw	h'aa'
		movwf	EECON2		;h'aa' を EECON2 に書き込む
		bsf	EECON1,WR	;書き込み開始
		btfsc	EECON1,WR	;書き込み 終了か?
		goto	$-1		;No

		bcf	STATUS,RP0	;バンク0

		incf	FSR,F		;間接アドレスの更新
		decfsz	eep_cnt,F	;記録データ数 - 1 = 0 か？
		goto	epw02		;No

		return

;==========================================================================
;		カウンタ値(CURRENT/TOTAL)のＬＥＤ表示（ＸＸＸＸ）
;==========================================================================

#ifndef _debug
count_disp
;		movwf	dsplc		;カウンタ値表示ループカウンタの設定

		; 16ビット数値を10進数5桁の文字列に変換

		movf	tot_bin1,W
		btfss	sel_flg,0	;選択フラグ ( 0:CURRENT, 1:TOTAL ) = 1 か？
		movf	cur_bin1,W	;No
		movwf	bin1		;BIN（上位）

		movf	tot_bin0,W
		btfss	sel_flg,0	;選択フラグ ( 0:CURRENT, 1:TOTAL ) = 1 か？
		movf	cur_bin0,W	;No
		movwf	bin0		;BIN（下位）

		call	bindec16	;16ビット数値を10進数5桁の文字列に変換

		; CURRENT/TOTAL LEDの表示

cdsp01		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra0	;7セグLED 1 桁目を消灯

		movlw	seg7_e		;e-seg (TOTAL)
		btfss	sel_flg,0	;選択フラグ ( 0:CURRENT, 1:TOTAL ) = 1 か？
		movlw	seg7_f		;No. f-seg (CURRENT)

		movwf	PORTB
		bcf	PORTA,ra4	;CURRENT/TOTAL LEDを点灯
		call	wait_300us	;１桁の表示時間

		; 7セグLED 4 桁目の表示

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra4	;CURRENT/TOTAL LEDを消灯

		movf	dec3,W
		call	ptn_set		;dec3を表示パターンに変換
		movwf	PORTB
		bcf	PORTA,ra3	;7セグLED 4 桁目を点灯
		call	wait_300us	;１桁の表示時間

		; 7セグLED 3 桁目の表示

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra3	;7セグLED 4 桁目を消灯

		movf	dec2,W
		call	ptn_set		;dec2を表示パターンに変換
		movwf	PORTB
		bcf	PORTA,ra2	;7セグLED 3 桁目を点灯
		call	wait_300us	;１桁の表示時間

		; 7セグLED 2 桁目の表示

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra2	;7セグLED 3 桁目を消灯

		movf	dec1,W
		call	ptn_set		;dec1を表示パターンに変換
		movwf	PORTB
		bcf	PORTA,ra1	;7セグLED 2 桁目を点灯
		call	wait_300us	;１桁の表示時間

		; 7セグLED 1 桁目の表示

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra1	;7セグLED 2 桁目を消灯

		movf	dec0,W
		call	ptn_set		;dec0を表示パターンに変換
		movwf	PORTB
		bcf	PORTA,ra0	;7セグLED 1 桁目を点灯
		call	wait_300us	;１桁の表示時間

;		decfsz	dsplc,F		;カウンタ値表示ループカウンタ - 1 = 0 か？
;		goto	cdsp01		;No

		movlw	seg7_off
		movwf	PORTB
		bsf	PORTA,ra0	;7セグLED 1 桁目を消灯

		return

#else
count_disp
;		movwf	dsplc		;カウンタ値表示ループカウンタの設定

		; 16ビット数値を10進数5桁の文字列に変換

		movf	tot_bin1,W
		btfss	sel_flg,0	;選択フラグ ( 0:CURRENT, 1:TOTAL ) = 1 か？
		movf	cur_bin1,W	;No
		movwf	bin1		;BIN（上位）

		movf	tot_bin0,W
		btfss	sel_flg,0	;選択フラグ ( 0:CURRENT, 1:TOTAL ) = 1 か？
		movf	cur_bin0,W	;No
		movwf	bin0		;BIN（下位）

		call	bindec16	;16ビット数値を10進数5桁の文字列に変換

		; CURRENT/TOTAL LEDの表示

cdsp01		movlw	seg7_off
		call	substitute
		bsf	PORTA,ra0	;7セグLED 1 桁目を消灯

		movlw	seg7_e		;e-seg (TOTAL)
		btfss	sel_flg,0	;選択フラグ ( 0:CURRENT, 1:TOTAL ) = 1 か？
		movlw	seg7_f		;No. f-seg (CURRENT)

		call	substitute
		bcf	PORTA,ra4	;CURRENT/TOTAL LEDを点灯
		call	wait_300us	;１桁の表示時間

		; 7セグLED 4 桁目の表示

		movlw	seg7_off
		call	substitute
		bsf	PORTA,ra4	;CURRENT/TOTAL LEDを消灯

		movf	dec3,W
		call	ptn_set		;dec3を表示パターンに変換
		call	substitute
		bcf	PORTA,ra3	;7セグLED 4 桁目を点灯
		call	wait_300us	;１桁の表示時間

		; 7セグLED 3 桁目の表示

		movlw	seg7_off
		call	substitute
		bsf	PORTA,ra3	;7セグLED 4 桁目を消灯

		movf	dec2,W
		call	ptn_set		;dec2を表示パターンに変換
		call	substitute
		bcf	PORTA,ra2	;7セグLED 3 桁目を点灯
		call	wait_300us	;１桁の表示時間

		; 7セグLED 2 桁目の表示

		movlw	seg7_off
		call	substitute
		bsf	PORTA,ra2	;7セグLED 3 桁目を消灯

		movf	dec1,W
		call	ptn_set		;dec1を表示パターンに変換
		call	substitute
		bcf	PORTA,ra1	;7セグLED 2 桁目を点灯
		call	wait_300us	;１桁の表示時間

		; 7セグLED 1 桁目の表示

		movlw	seg7_off
		call	substitute
		bsf	PORTA,ra1	;7セグLED 2 桁目を消灯

		movf	dec0,W
		call	ptn_set		;dec0を表示パターンに変換
		call	substitute
		bcf	PORTA,ra0	;7セグLED 1 桁目を点灯
		call	wait_300us	;１桁の表示時間

;		decfsz	dsplc,F		;カウンタ値表示ループカウンタ - 1 = 0 か？
;		goto	cdsp01		;No

		movlw	seg7_off
		call	substitute
		bsf	PORTA,ra0	;7セグLED 1 桁目を消灯

		return

substitute	andlw	b'01111111'
		movwf	temp
		movlw	b'10000000'
		andwf	PORTB,W
		iorwf	temp,W
		movwf	PORTB
		return
#endif

;==========================================================================
;		アラーム（ブザー）音出力ルーチン
;==========================================================================

		; "ピッ" ブザー音出力
buzzer_pi
		Sound_M		f_so, pi_tim
		return

		; "ポッ" ブザー音出力
buzzer_po
		Sound_M		f_doh, po_tim
		return

		; "ピポッ" ブザー音出力 (230 mS)
buzzer_pipo
		call	buzzer_pi	;"ピッ" ブザー音出力
		call	wait_30ms
		call	buzzer_po	;"ポッ" ブザー音出力
		return

		; "ブッ" ブザー音出力
buzzer_bu
		Sound_M		f_do, bu_tim
		return

		; "ブー" ブザー音出力
buzzer_buu
		Sound_M		f_do, buu_tim
		return

		; "ブッブー" ブザー音出力 (450 mS)
buzzer_bubuu
		call	buzzer_bu	;"ブッ" ブザー音出力
		call	wait_100ms
		call	buzzer_buu	;"ブー" ブザー音出力
		return

		; "ドミソド" ブザー音出力 (1,150 mS)
dl_mi_so_dh
		Sound_M		f_do, dms_tim
		call	wait_50ms

		Sound_M		f_mi, dms_tim
		call	wait_50ms

		Sound_M		f_so, dms_tim
		call	wait_50ms

		Sound_M		f_doh, dms_tim
		Sound_M		f_doh, dms_tim
		return

		; ブザー音出力コントロール
buzzer_control
		bsf	STATUS,RP0	;バンク 1
		bsf	PIE1,TMR1IE	;タイマー１割り込みを許可
		bcf	STATUS,RP0	;バンク 0

		call	wait_w1ms	;入力 W: 音長（ループカウンタ）

		bsf	STATUS,RP0	;バンク 1
		bcf	PIE1,TMR1IE	;タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0
		return

;==========================================================================
;		ウェイト・ルーチン (at 4 MHz)
;==========================================================================

		; 7セグ LED１桁の表示時間
wait_300us
		movlw	100		;1
		movwf	wt3cnt		;1

w3u01		decfsz	wt3cnt,F	;1,2
		goto	w3u01		;2,0	1+1+(1+2)*99+(2+0)=301

		return			;2	301+2=303
					;Total	303/4MHz*4 = 303 μS

		; 1m 秒 x W ウェイトルーチン
wait_w1ms
		movwf	wt2cnt		;1

w1m01		movlw	110		;1
		movwf	wt1cnt		;1

w1m02		goto	$ + 1		;2
		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt1cnt,F	;1,2
		goto	w1m02		;2,0	(2+2+2+1+2)*109+(2+2+2+2+0)=989

		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt2cnt,F	;1,2
		goto	w1m01		;2,0	(1+1+989+2+2+1+2)*(W-1)+(1+1+989+2+2+2+0)=998*W-1

		return			;2	1+(998*W-1)+2=998*W+2
					;Total	(998*W+2)/4MHz*4 = (998*W + 2) μS

		; 30m 秒 ウェイトルーチン
wait_30ms
		movlw	30		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*30+5)/4MHz*4 = 29.945 mS

		; 50m 秒 ウェイトルーチン
wait_50ms
		movlw	50		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*50+5)/4MHz*4 = 49.905 mS

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100		;1
		goto	wait_w1ms	;2	1+2+1+(998*W-1)+2=998*W+5
					;Total	(998*100+5)/4MHz*4 = 99.805 mS

;==========================================================================
;		割り込み処理
;==========================================================================

interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		movf	STATUS,W
		movwf	s_save		;STATUS レジスタの保存

		bcf	STATUS,RP0	;バンク 0
		btfsc	INTCON,T0IF	;タイマー０割り込み か？
		goto	int_t0		;Yes

		btfsc	PIR1,TMR1IF	;タイマー１割り込み か？
		goto	int_t1		;Yes
		goto	int_end		;(Illegal interrupt)

		; タイマー０割り込み処理

int_t0		bcf	INTCON,T0IF	;タイマー０割込みフラグをクリア

		movlw	tm0_h_val	;ハードタイマー０カウント値
		movwf	TMR0		;タイマー０ TMR0 の設定

		movlw	1
		subwf	tm0_cnt_l,F	;ソフトタイマー０の low  カウンタ - 1
		btfsc	STATUS,Z	;ソフトタイマー０の low  カウンタ = 0 か？
		goto	int01		;Yes

		btfsc	STATUS,C	;ソフトタイマー０の low  カウンタ > 0 か？
		goto	int_end		;Yes

		subwf	tm0_cnt_h,F	;ソフトタイマー０の high カウンタ - 1
		goto	int_end	

int01		movf	tm0_cnt_h,F
		btfss	STATUS,Z	;ソフトタイマー０の high カウンタ = 0 か？
		goto	int_end		;No

		; tm0_cnt_h = 0 & tm0_cnt_l = 0

		btfss	monitor_on,0	;センサ入力ON監視フラグ(0) = ON か？
		goto	int02		;No

		bsf	monitor_on,1	;センサ入力ON監視フラグ(1) = ON（500mS経過）
		goto	int05	

int02		btfss	monitor_off,0	;センサ入力OFF監視フラグ(0) = ON か？
		goto	int03		;No

		bsf	monitor_off,1	;センサ入力OFF監視フラグ(1) = ON（500mS経過）
		goto	int05	

int03		btfss	monitor_sw,0	;スイッチ監視フラグ(0) = ON か？
		goto	int04		;No

		bsf	monitor_sw,1	;スイッチ監視フラグ(1) = ON（250mS経過）
		goto	int05	

int04		;btfss	monitor_tot,0	;TOTAL RESET監視フラグ(0) = ON か？
		;goto	int0x		;No

		bsf	monitor_tot,1	;TOTAL RESET監視フラグ(1) = ON（5秒経過）

int05		bcf	INTCON,T0IE	;タイマー０割り込みを禁止
		goto	int_end

		; タイマー１割り込み処理

int_t1		bcf	PIR1,TMR1IF	;タイマー１割込みフラグをクリア

		movf	const_high,W	;音階用分周定数 high を
		movwf	TMR1H		;TMR1H に設定
		movf	const_low,W	;音階用分周定数 low を
		movwf	TMR1L		;TMR1L に設定

#ifndef _debug
		movlw	1 << buzzer	;対象ビットをセット
		xorwf	PORTB,F		;出力をビット反転
#endif
;		goto	int_end

		; レジスタの復帰

int_end		movf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie

;==========================================================================
;		16ビット数値を10進数5桁の文字列に変換
;
;	入力:	bin1,bin0
;	出力:	dec4,dec3,dec2,dec1,dec0
;
;	     （ サイト "ELECTRONICS SHELVES" の "サブルーチン集" から
;		hxdec16c_mp.txt を拝借して編集し直したもの 
;		http://orange.zero.jp/electronics/pic/pic.html ）
;==========================================================================

bindec16
		movlw	dec0 + 1	;格納場所初期値
		movwf	FSR		;
		call	dev16		;最下位変換
		call	dev16
		call	dev16
		call	dev16
		call	dev16		;最上位変換

		return

		; ÷10（10で除算）
dev16
		movlw	16		;16ビット繰り返し
		movwf	dv10cnt
		clrf	dv10wk

dev161		bcf	STATUS,C	;キャリフラグのクリア
		rlf	bin0,F
		rlf	bin1,F
		rlf	dv10wk,F
		movlw	h'f6'
		addwf	dv10wk,W
		btfsc	STATUS,W
		movwf	dv10wk
		btfsc	STATUS,W
		incf	bin0,F
		decfsz	dv10cnt,F
		goto	dev161

		decf	FSR,F
		movf	dv10wk,W
		movwf	INDF		;余り
	;	movlw	h'30'		;文字コードに変換
	;	addwf	INDF,F

		return

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'2100'

		de	h'00'		;差分 DIFFERENCE	─┐ 記録位置
		de	h'00',h'00'	;更新 UPDATE1,UPDATE0	─┘ の管理用
		de	h'00',h'00'	;現在 CURRENT1,CURRENT0
		de	h'00',h'00'	;合計 TOTAL1,TOTAL0

		org	h'2100' + 128 - 32

		de	"Copyright (C) 2018 by M.Yamamoto"

;==========================================================================

		end			;プログラムの終了
