;***** VoiceClock.asm *****************************************************
;
;	音声時計（音声告知クロック）
;
;	origin:  http://www.zea.jp/audio/vck/vck_01.htm (vck_16f877a.asm)
;		電子マスカット:Vクロック ver.1.0 いしづかやすゆき:2008.03.29
;
;     ( coding:  Ver. 0.00   2008/05/12  by M.Yamamoto )
;	coding:  Ver. 1.00   2008/05/22  初期バージョン
;	update:  Ver. 1.01   2019/12/28  見直し
;	bugfix:  Ver. x.xx
;
;******************************************************* PicAsm 0217 ******

;	Device: PIC16F877A	Clock: 20MHz (セラロック)

;	PIC16F877A のピンと用途

;	 (1) MCLR マスター・クリア入力		(40) RB7  出力: 電力増幅IC 電源制御
;	 (2) RA0  出力: 予備			(39) RB6  出力: 予備
;	 (3) RA1  出力: I2C-CLOCK 端子　	(38) RB5  入力: 音声告知スイッチ
;	 (4) RA2  出力: I2C-DATA 端子		(37) RB4  入力: 時刻調整「時」スイッチ
;	 (5) RA3  出力: 予備			(36) RB3  入力: 時刻調整「分」スイッチ
;	 (6) RA4  出力: 予備			(35) RB2  出力: 予備
;	 (7) RA5  出力: 予備			(34) RB1  出力: 予備
;　	 (8) RE0  出力: 予備			(33) RB0  入力: INT 外部割り込み
;	 (9) RE1  出力: 予備			(32) VDD  電源 +5V DC
;	(10) RE2  出力: 予備			(31) VSS  電源 GND
;	(11) VDD  電源 +5V DC			(30) RD7  出力: R-2R ラダー 7
;	(12) VSS  電源 GND			(29) RD6  出力: R-2R ラダー 6
;	(13) OSC1 オシレータ水晶入力		(28) RD5  出力: R-2R ラダー 5
;	(14) OSC2 オシレータ水晶入力		(27) RD4  出力: R-2R ラダー 4
;	(15) T1OSO タイマー１用オシレータ出力	(26) RC7  出力: 予備	
;	(16) T1OSI タイマー１用オシレータ入力	(25) RC6  出力: 予備	
;	(17) RC2  出力: 予備			(24) RC5  出力: 予備	
;	(18) RC3  出力: 予備			(23) RC4  出力: 予備	
;	(19) RD0  出力: R-2R ラダー 0		(22) RD3  出力: R-2R ラダー 3
;	(20) RD1  出力: R-2R ラダー 1		(21) RD2  出力: R-2R ラダー 2

;==========================================================================

	list		p=pic16f877a	;デバイス情報
	include		p16f877a.inc	;インクルードファイル

	errorlevel	-302		;suppress message 302 from list file
	errorlevel	-305		;suppress message 305 from list file

	__config _CP_OFF & _DEBUG_OFF & _WRT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC

;==========================================================================
;		定数の定義とレジスタ割付け
;==========================================================================

		radix	dec

sp_12j_p	equ	h'00'		;「12時」音声データ開始最上位P0ビット
sp_12j_h	equ	h'00'		;「12時」音声データ開始上位アドレス
sp_12j_l	equ	h'00'		;「12時」音声データ開始下位アドレス
sp_01j_p	equ	h'00'		;「1時」音声データ開始最上位P0ビット
sp_01j_h	equ	h'11'		;「1時」音声データ開始上位アドレス
sp_01j_l	equ	h'D0'		;「1時」音声データ開始下位アドレス
sp_02j_p	equ	h'00'		;「2時」音声データ開始最上位P0ビット
sp_02j_h	equ	h'1F'		;「2時」音声データ開始上位アドレス
sp_02j_l	equ	h'F0'		;「2時」音声データ開始下位アドレス
sp_03j_p	equ	h'00'		;「3時」音声データ開始最上位P0ビット
sp_03j_h	equ	h'29'		;「3時」音声データ開始上位アドレス
sp_03j_l	equ	h'70'		;「3時」音声データ開始下位アドレス
sp_04j_p	equ	h'00'		;「4時」音声データ開始最上位P0ビット
sp_04j_h	equ	h'37'		;「4時」音声データ開始上位アドレス
sp_04j_l	equ	h'F0'		;「4時」音声データ開始下位アドレス
sp_05j_p	equ	h'00'		;「5時」音声データ開始最上位P0ビット
sp_05j_h	equ	h'42'		;「5時」音声データ開始上位アドレス
sp_05j_l	equ	h'D0'		;「5時」音声データ開始下位アドレス
sp_06j_p	equ	h'00'		;「6時」音声データ開始最上位P0ビット
sp_06j_h	equ	h'4D'		;「6時」音声データ開始上位アドレス
sp_06j_l	equ	h'10'		;「6時」音声データ開始下位アドレス
sp_07j_p	equ	h'00'		;「7時」音声データ開始最上位P0ビット
sp_07j_h	equ	h'5B'		;「7時」音声データ開始上位アドレス
sp_07j_l	equ	h'A0'		;「7時」音声データ開始下位アドレス
sp_08j_p	equ	h'00'		;「8時」音声データ開始最上位P0ビット
sp_08j_h	equ	h'6A'		;「8時」音声データ開始上位アドレス
sp_08j_l	equ	h'D0'		;「8時」音声データ開始下位アドレス
sp_09j_p	equ	h'00'		;「9時」音声データ開始最上位P0ビット
sp_09j_h	equ	h'7A'		;「9時」音声データ開始上位アドレス
sp_09j_l	equ	h'60'		;「9時」音声データ開始下位アドレス
sp_10j_p	equ	h'00'		;「10時」音声データ開始最上位P0ビット
sp_10j_h	equ	h'83'		;「10時」音声データ開始上位アドレス
sp_10j_l	equ	h'40'		;「10時」音声データ開始下位アドレス
sp_11j_p	equ	h'00'		;「11時」音声データ開始最上位P0ビット
sp_11j_h	equ	h'8F'		;「11時」音声データ開始上位アドレス
sp_11j_l	equ	h'00'		;「11時」音声データ開始下位アドレス
sp_10f_p	equ	h'00'		;「10分」音声データ開始最上位P0ビット
sp_10f_h	equ	h'A5'		;「10分」音声データ開始上位アドレス
sp_10f_l	equ	h'10'		;「10分」音声データ開始下位アドレス
sp_20f_p	equ	h'00'		;「20分」音声データ開始最上位P0ビット
sp_20f_h	equ	h'B5'		;「20分」音声データ開始上位アドレス
sp_20f_l	equ	h'A0'		;「20分」音声データ開始下位アドレス
sp_30f_p	equ	h'00'		;「30分」音声データ開始最上位P0ビット
sp_30f_h	equ	h'C9'		;「30分」音声データ開始上位アドレス
sp_30f_l	equ	h'40'		;「30分」音声データ開始下位アドレス
sp_40f_p	equ	h'00'		;「40分」音声データ開始最上位P0ビット
sp_40f_h	equ	h'E2'		;「40分」音声データ開始上位アドレス
sp_40f_l	equ	h'D0'		;「40分」音声データ開始下位アドレス
sp_50f_p	equ	h'02'		;「50分」音声データ開始最上位P0ビット
sp_50f_h	equ	h'00'		;「50分」音声データ開始上位アドレス
sp_50f_l	equ	h'00'		;「50分」音声データ開始下位アドレス
sp_10t_p	equ	h'02'		;「10…」音声データ開始最上位P0ビット
sp_10t_h	equ	h'11'		;「10…」音声データ開始上位アドレス
sp_10t_l	equ	h'B0'		;「10…」音声データ開始下位アドレス
sp_20t_p	equ	h'02'		;「20…」音声データ開始最上位P0ビット
sp_20t_h	equ	h'18'		;「20…」音声データ開始上位アドレス
sp_20t_l	equ	h'F0'		;「20…」音声データ開始下位アドレス
sp_30t_p	equ	h'02'		;「30…」音声データ開始最上位P0ビット
sp_30t_h	equ	h'25'		;「30…」音声データ開始上位アドレス
sp_30t_l	equ	h'70'		;「30…」音声データ開始下位アドレス
sp_40t_p	equ	h'02'		;「40…」音声データ開始最上位P0ビット
sp_40t_h	equ	h'34'		;「40…」音声データ開始上位アドレス
sp_40t_l	equ	h'90'		;「40…」音声データ開始下位アドレス
sp_50t_p	equ	h'02'		;「50…」音声データ開始最上位P0ビット
sp_50t_h	equ	h'44'		;「50…」音声データ開始上位アドレス
sp_50t_l	equ	h'20'		;「50…」音声データ開始下位アドレス
sp_01f_p	equ	h'02'		;「01分」音声データ開始最上位P0ビット
sp_01f_h	equ	h'4F'		;「01分」音声データ開始上位アドレス
sp_01f_l	equ	h'90'		;「01分」音声データ開始下位アドレス
sp_02f_p	equ	h'02'		;「02分」音声データ開始最上位P0ビット
sp_02f_h	equ	h'60'		;「02分」音声データ開始上位アドレス
sp_02f_l	equ	h'D0'		;「02分」音声データ開始下位アドレス
sp_03f_p	equ	h'02'		;「03分」音声データ開始最上位P0ビット
sp_03f_h	equ	h'6D'		;「03分」音声データ開始上位アドレス
sp_03f_l	equ	h'20'		;「03分」音声データ開始下位アドレス
sp_04f_p	equ	h'02'		;「04分」音声データ開始最上位P0ビット
sp_04f_h	equ	h'81'		;「04分」音声データ開始上位アドレス
sp_04f_l	equ	h'90'		;「04分」音声データ開始下位アドレス
sp_05f_p	equ	h'02'		;「05分」音声データ開始最上位P0ビット
sp_05f_h	equ	h'90'		;「05分」音声データ開始上位アドレス
sp_05f_l	equ	h'80'		;「05分」音声データ開始下位アドレス
sp_06f_p	equ	h'02'		;「06分」音声データ開始最上位P0ビット
sp_06f_h	equ	h'A0'		;「06分」音声データ開始上位アドレス
sp_06f_l	equ	h'50'		;「06分」音声データ開始下位アドレス
sp_07f_p	equ	h'02'		;「07分」音声データ開始最上位P0ビット
sp_07f_h	equ	h'B3'		;「07分」音声データ開始上位アドレス
sp_07f_l	equ	h'50'		;「07分」音声データ開始下位アドレス
sp_08f_p	equ	h'02'		;「08分」音声データ開始最上位P0ビット
sp_08f_h	equ	h'C1'		;「08分」音声データ開始上位アドレス
sp_08f_l	equ	h'30'		;「08分」音声データ開始下位アドレス
sp_09f_p	equ	h'02'		;「09分」音声データ開始最上位P0ビット
sp_09f_h	equ	h'D1'		;「09分」音声データ開始上位アドレス
sp_09f_l	equ	h'00'		;「09分」音声データ開始下位アドレス
sp_des_p	equ	h'02'		;「です」音声データ開始最上位P0ビット
sp_des_h	equ	h'DF'		;「です」音声データ開始上位アドレス
sp_des_l	equ	h'70'		;「です」音声データ開始下位アドレス

auto00		equ	0		;stat_byte 00分オートスピーチフラグ
auto30		equ	1		;stat_byte 30分オートスピーチフラグ
timset		equ	2		;stat_byte 時刻調整中フラグ
swint		equ	3		;stat_byte 外部割り込み(RB0/INT)からの証拠フラグ

amp_cntl	equ	7		;電力増幅IC 制御
voice_sw	equ	5		;音声告知スイッチ
h_adj_sw	equ	4		;時刻調整「時」スイッチ
m_adj_sw	equ	3		;時刻調整「分」スイッチ

scl		equ	1		;I2C-CLOCK 端子
sda		equ	2		;I2C-DATA 端子
do		equ	0		;I2C-BUFFER 内出力ビット
di		equ	1		;I2C-BUFFER 内入力ビット
ack_bit		equ	2		;I2C-ACK ビット

		cblock  h'20'
tim_cnt1				;遅延タイマー用レジスタ
tim_cnt2				;遅延タイマー用レジスタ
beep_cnt				;BEEP 振動回数カウンタ
stat_byte				;状態バイト
s4_cnt					;4秒カウンタ
ml_cnt					;分カウンタ
mh_cnt					;十分カウンタ
ho_cnt					;時カウンタ

cl_da_cnt				;AD出力を00Hにするまでの割り込み回数カウンタ（ポップノイズ防止）

da_data_a				;
da_data_b				;

rom_chip				;I2C-EEPROM デバイスアドレス
rom_add_h				;I2C-EEPROM データアクセスアドレス上位レジスタ
rom_add_l				;I2C-EEPROM データアクセスアドレス下位レジスタ
buffer					;I2C-バッファ
data_in					;I2C-読み出しデータ
data_out				;I2C-送り出しデータ
bit_cnt					;I2C-1バイト8ビットのカウンタレジスタ
		endc

		cblock	h'70'
w_save					;W レジスタの退避用
s_save					;STATUS レジスタの退避用
		endc

;==========================================================================
;		プログラム開始
;==========================================================================

		org	0		;リセットベクタ
		goto	init
		org	4		;割り込みベクタ
		goto	interrupt

;==========================================================================
;		初期化処理
;==========================================================================

init
		bsf	STATUS,RP0	;バンク1
		movlw	h'06'		;ポートA, E を ディジタルモード
		movwf	ADCON1		;ADCON1 の設定
		clrf	TRISA		;ポートA　全て出力設定
		movlw	b'00111001'	;RB5-3,0: 入力, RB7-6,2-1: 出力
		movwf	TRISB		;ポートB　設定
		clrf	TRISC		;ポートC　全て出力設定
		clrf	TRISD		;ポートD　全て出力設定
		clrf	TRISE		;ポートE　全て出力設定
		clrf	OPTION_REG	;プルアップ抵抗有効, INT割込み立下りエッジ
		bsf	PIE1,TMR1IE	;タイマー1 割込み許可
		bcf	STATUS,RP0	;バンク0

		movlw	b'00011111'	;bit5-4=01: プリスケーラ1/2
					;bit3=1:    発振器を使用
					;bit2=1:    外部入力クロックに同期させない
					;bit1=1:    外部入力クロックを使う
					;bit0=1:    タイマー1 動作有効 
		movwf	T1CON		;T1CON (タイマー１制御用レジスタ）の設定

		movlw	b'01010000'	;bit7=0: GIE  全割込み禁止
					;bit6=1: PEIE 周辺割込み許可
					;bit4=1: INTE 外部割り込み(RB0/INT)割込み許可
		movwf	INTCON		;INTCON の設定

		clrf	s4_cnt		;4秒カウンタの初期設定
		clrf	ml_cnt		;分カウンタの初期設定
		clrf	mh_cnt		;十分カウンタの初期設定
		clrf	ho_cnt		;時カウンタの初期設定
		clrf	stat_byte	;状態バイトの初期設定
		clrf	TMR1L
		clrf	TMR1H
		bsf	PORTA,sda	;SDA="H"
		bsf	PORTA,scl	;SCL="H"
		clrf	PORTD		;ポートD 全てに 0 を出力

		call	rom_test	;全てのフレーズを喋るかテスト

		bsf	INTCON,GIE	;GIE 全割り込み許可

;==========================================================================
;		メイン・ルーチン
;==========================================================================

main
		btfss	stat_byte,swint	;外部割り込み(RB0/INT)か?
		goto	main01		;No

		btfss	PORTB,voice_sw	;音声告知スイッチが押されているか?
		goto	main02		;Yes

		btfss	PORTB,h_adj_sw	;時刻調整「時」スイッチが押されているか?
		goto	main03		;Yes

		btfss	PORTB,m_adj_sw	;時刻調整「分」スイッチが押されているか?
		goto	main04		;Yes

main01		btfsc	stat_byte,auto00 ;毎時スピーチか?
		goto	main06		;Yes	

		btfsc	stat_byte,auto30 ;毎30分スピーチか?
		goto	main07		;Yes
		goto	main09		;No

main02		call	tim_sw		;チャタリング監視時間
		btfss	PORTB,voice_sw	;音声告知スイッチが確実に押されているか?
		goto	main07		;Yes
		goto	main09		;No

main03		call	tim_sw		;チャタリング監視時間
		btfsc	PORTB,h_adj_sw	;時刻調整「時」スイッチが確実に押されているか?
		goto	main09		;No

		; 時刻調整「時」スイッチが押された
		call	audio_set	;オーディオ回路の設定
		call	beep

		incf	ho_cnt,F	;時カウンタ + 1
		movlw	12
		subwf	ho_cnt,W
		btfsc	STATUS,Z	;時カウンタ = 12 か?
		clrf	ho_cnt		;Yes. 12回のカウントでレジスタをクリア

		bsf	stat_byte,timset ;時刻調整中フラグのセット
		bcf	INTCON,GIE	;全割込み禁止
		call	sp_hour		;スピーチ順序ルーチン「時」
		bsf	INTCON,GIE	;全割込み許可
		bcf	stat_byte,timset ;時刻調整中フラグのリセット

		call	tim_sw		;チャタリング監視時間
		btfsc	PORTB,h_adj_sw	;時刻調整「時」スイッチがまだ押されているか?
		goto	main09		;No

		call	tim_200ms
		call	tim_200ms
		goto	main03

main04		call	tim_sw		;チャタリング監視時間
		btfsc	PORTB,m_adj_sw	;時刻調整「分」スイッチが確実に押されているか?
		goto	main09		;No

		; 時刻調整「分」スイッチが押された
		call	audio_set	;オーディオ回路の設定
		clrf	TMR1L
		clrf	TMR1H
		clrf	s4_cnt		;「分」調整時のみ秒レベルまでクリア
		call	beep

		incf	ml_cnt,F	;分カウンタ + 1
		movlw	10
		subwf	ml_cnt,W
		btfss	STATUS,Z	;分カウンタ = 10 か?
		goto	main05		;No

		clrf	ml_cnt		;Yes. 10回のカウントでレジスタクリア

		incf	mh_cnt,F	;十分カウンタ + 1
		movlw	6
		subwf	mh_cnt,W
		btfsc	STATUS,Z	;十分カウンタ = 6 か?
		clrf	mh_cnt		;Yes. 6回のカウントでレジスタクリア

main05		bsf	stat_byte,timset ;時刻調整中フラグのセット
		bcf	INTCON,GIE	;全割込み禁止
		call	sp_minute	;スピーチ順序ルーチン「分」
		bsf	INTCON,GIE	;全割込み許可
		bcf	stat_byte,timset ;時刻調整中フラグのリセット

		call	tim_sw		;チャタリング監視時間
		btfsc	PORTB,m_adj_sw	;時刻調整「分」スイッチがまだ押されているか?
		goto	main09		;No

		call	tim_200ms
		goto	main04

		; 毎時スピーチ
main06		call	audio_set	;オーディオ回路の設定
		call	beep		;ビープ音２回
		call	tim_100ms
		call	beep
		goto	main08

		; 毎30分スピーチ ／ 音声告知スイッチが押された
main07		call	audio_set	;オーディオ回路の設定
		call	beep		;ビープ音１回

main08		call	tim_200ms
		call	tim_200ms
		call	tim_200ms
		bcf	INTCON,GIE	;全割込み禁止
		call	sp_hour		;スピーチ順序ルーチン「時」
		call	sp_minute	;スピーチ順序ルーチン「分」
		call	sp_des		;フレーズ「です」読み出し
		bsf	INTCON,GIE	;全割込み許可

		; オーディオ電源 OFF
main09		bsf	PORTB,amp_cntl	;電力増幅IC 電源OFF
		clrf	stat_byte	;状態バイトのクリア
		movf	cl_da_cnt,F
		btfsc	STATUS,Z	;割り込み回数カウンタ = 0 か?
		goto	main10		;Yes

		decf	cl_da_cnt,F	;割り込み回数カウンタ - 1
		btfsc	STATUS,Z	;割り込み回数カウンタ = 0 か?
		clrf	PORTD		;Yes

main10		sleep			;普段はここ
		nop
		goto	main

;--------------------------------------------------------------------------

;		オーディオ回路の設定

audio_set
		movlw	h'80'
		movwf	PORTD		;ノイズ防止のため中立の h'80'をラダー抵抗ポートにスタンバイ
		bcf	PORTB,amp_cntl	;電力増幅IC 電源ON
		movlw	4
		movwf	cl_da_cnt	;音声告知終了後に3回目の割込み突入でラダー抵抗ポートをクリア
		return

;--------------------------------------------------------------------------

;		BEEP 音生成サブルーチン

beep
		movlw	h'60'		;振動回数
		movwf	beep_cnt	;BEEP 振動回数カウンタを設定

beep01		bsf	PORTD,5		;RD5 = 1 
;		call	tim_100us
;		call	tim_100us
		call	tim_100us
		call	tim_100us
		call	tim_100us
		bcf	PORTD,5		;RD5 = 0 
;		call	tim_100us
;		call	tim_100us
		call	tim_100us
		call	tim_100us
		call	tim_100us
		decfsz	beep_cnt	;BEEP 振動回数カウンタ - 1 = 0 か？
		goto	beep01		;No

		return

;==========================================================================
;		スピーチ順序ルーチン「時」
;==========================================================================

sp_hour
		movf	ho_cnt,W
		btfss	STATUS,Z	;時カウンタ = 12 か?
		goto	sph01		;No

		call	sp_12j		;フレーズ「じゅうにじ」読み出し
		goto	sph12

sph01		movf	ho_cnt,W
		sublw	1
		btfss	STATUS,Z	;時カウンタ = 1 か?
		goto	sph02		;No

		call	sp_01j		;フレーズ「いちじ」読み出し
		goto	sph12

sph02		movf	ho_cnt,W
		sublw	2
		btfss	STATUS,Z	;時カウンタ = 2 か?
		goto	sph03		;No

		call	sp_02j		;フレーズ「にじ」読み出し
		goto	sph12

sph03		movf	ho_cnt,W
		sublw	3
		btfss	STATUS,Z	;時カウンタ = 3 か?
		goto	sph04		;No

		call	sp_03j		;フレーズ「さんじ」読み出し
		goto	sph12

sph04		movf	ho_cnt,W
		sublw	4
		btfss	STATUS,Z	;時カウンタ = 4 か?
		goto	sph05		;No

		call	sp_04j		;フレーズ「よじ」読み出し
		goto	sph12

sph05		movf	ho_cnt,W
		sublw	5
		btfss	STATUS,Z	;時カウンタ = 5 か?
		goto	sph06		;No

		call	sp_05j		;フレーズ「ごじ」読み出し
		goto	sph12

sph06		movf	ho_cnt,W
		sublw	6
		btfss	STATUS,Z	;時カウンタ = 6 か?
		goto	sph07		;No

		call	sp_06j		;フレーズ「ろくじ」読み出し
		goto	sph12

sph07		movf	ho_cnt,W
		sublw	7
		btfss	STATUS,Z	;時カウンタ = 7 か?
		goto	sph08		;No

		call	sp_07j		;フレーズ「しちじ」読み出し
		goto	sph12

sph08		movf	ho_cnt,W
		sublw	8
		btfss	STATUS,Z	;時カウンタ = 8 か?
		goto	sph09		;No

		call	sp_08j		;フレーズ「はちじ」読み出し
		goto	sph12

sph09		movf	ho_cnt,W
		sublw	9
		btfss	STATUS,Z	;時カウンタ = 9 か?
		goto	sph10		;No

		call	sp_09j		;フレーズ「くじ」読み出し
		goto	sph12

sph10		movf	ho_cnt,W
		sublw	10
		btfss	STATUS,Z	;時カウンタ = 10 か?
		goto	sph11		;No

		call	sp_10j		;フレーズ「じゅうじ」読み出し
		goto	sph12

sph11		call	sp_11j		;フレーズ「じゅういちじ」読み出し

sph12		return

;==========================================================================
;		スピーチ順序ルーチン「分」
;==========================================================================

sp_minute
		movf	ml_cnt,W
		btfss	STATUS,Z	;分カウンタ = 0 か?
		goto	spm06		;No

		; 下位が「0分」のとき
		movf	mh_cnt,W
		btfss	STATUS,Z	;十分カウンタ = 0 か?
		goto	spm01		;No

		call	sp_00f		;フレーズ「無音」
		goto	spm21

spm01		movf	mh_cnt,W
		sublw	1
		btfss	STATUS,Z	;十分カウンタ = 1 か?
		goto	spm02		;No

		call	sp_10f		;フレーズ「じゅっぷん」読み出し
		goto	spm21

spm02		movf	mh_cnt,W
		sublw	2
		btfss	STATUS,Z	;十分カウンタ = 2 か?
		goto	spm03		;No

		call	sp_20f		;フレーズ「にじゅっぷん」読み出し
		goto	spm21

spm03		movf	mh_cnt,W
		sublw	3
		btfss	STATUS,Z	;十分カウンタ = 3 か?
		goto	spm04		;No

		call	sp_30f		;フレーズ「さんじゅっぷん」読み出し
		goto	spm21

spm04		movf	mh_cnt,W
		sublw	4
		btfss	STATUS,Z	;十分カウンタ = 4 か?
		goto	spm05		;No

		call	sp_40f		;フレーズ「よんじゅっぷん」読み出し
		goto	spm21

spm05		call	sp_50f		;フレーズ「ごじゅっぷん」読み出し
		goto	spm21

		; 下位が「0分」以外の上位分
spm06		movf	mh_cnt,W
		btfss	STATUS,Z	;十分カウンタ = 0 か?
		goto	spm07		;No
		goto	spm12

spm07		movf	mh_cnt,W
		sublw	1
		btfss	STATUS,Z	;十分カウンタ = 1 か?
		goto	spm08		;No

		call	sp_10t		;フレーズ「じゅう」読み出し
		goto	spm12

spm08		movf	mh_cnt,W
		sublw	2
		btfss	STATUS,Z	;十分カウンタ = 2 か?
		goto	spm09		;No

		call	sp_20t		;フレーズ「にじゅう」読み出し
		goto	spm12

spm09		movf	mh_cnt,W
		sublw	3
		btfss	STATUS,Z	;十分カウンタ = 3 か?
		goto	spm10		;No

		call	sp_30t		;フレーズ「さんじゅう」読み出し
		goto	spm12

spm10		movf	mh_cnt,W
		sublw	4
		btfss	STATUS,Z	;十分カウンタ = 4 か?
		goto	spm11		;No

		call	sp_40t		;フレーズ「よんじゅう」読み出し
		goto	spm12

spm11		call	sp_50t		;フレーズ「ごじゅう」読み出し
		goto	spm12

		; 下位が「0分」以外の下位分
spm12		movf	ml_cnt,W
		sublw	1
		btfss	STATUS,Z	;分カウンタ = 1 か?
		goto	spm13		;No

		call	sp_01f		;フレーズ「いっぷん」読み出し
		goto	spm21

spm13		movf	ml_cnt,W
		sublw	2
		btfss	STATUS,Z	;分カウンタ = 2 か?
		goto	spm14		;No

		call	sp_02f		;フレーズ「にふん」読み出し
		goto	spm21

spm14		movf	ml_cnt,W
		sublw	3
		btfss	STATUS,Z	;分カウンタ = 3 か?
		goto	spm15		;No

		call	sp_03f		;フレーズ「さんぷん」読み出し
		goto	spm21

spm15		movf	ml_cnt,W
		sublw	4
		btfss	STATUS,Z	;分カウンタ = 4 か?
		goto	spm16		;No

		call	sp_04f		;フレーズ「よんぷん」読み出し
		goto	spm21

spm16		movf	ml_cnt,W
		sublw	5
		btfss	STATUS,Z	;分カウンタ = 5 か?
		goto	spm17		;No

		call	sp_05f		;フレーズ「ごふん」読み出し
		goto	spm21

spm17		movf	ml_cnt,W
		sublw	6
		btfss	STATUS,Z	;分カウンタ = 6 か?
		goto	spm18		;No

		call	sp_06f		;フレーズ「ろっぷん」読み出し
		goto	spm21

spm18		movf	ml_cnt,W
		sublw	7
		btfss	STATUS,Z	;分カウンタ = 7 か?
		goto	spm19		;No

		call	sp_07f		;フレーズ「ななふん」読み出し
		goto	spm21

spm19		movf	ml_cnt,W
		sublw	8
		btfss	STATUS,Z	;分カウンタ = 8 か?
		goto	spm20		;No

		call	sp_08f		;フレーズ「はっぷん」読み出し
		goto	spm21

spm20		call	sp_09f		;フレーズ「きゅうふん」読み出し

spm21		return

;==========================================================================
;		フレーズサブルーチン
;==========================================================================
; 呼び出されると指定のアドレスから ROMを読み出しラダー抵抗ポートに出力する

		; フレーズ「じゅうにじ」読み出し
sp_12j
		movlw	sp_12j_p	;最上位アドレスP0をデバイスアドレスに指定
		movwf	rom_chip	;rom_chip レジスタにコピー
		movlw	sp_12j_h	;上位アドレスを指定して
		movwf	rom_add_h	;rom_add_h レジスタにコピー
		movlw	sp_12j_l	;下位アドレスを指定して
		movwf	rom_add_l	;rom_add_l レジスタにコピー
		call	rom_read	;上記アドレスから ROM 読み出し
		return

		; フレーズ「いちじ」読み出し
sp_01j
		movlw	sp_01j_p
		movwf	rom_chip
		movlw	sp_01j_h
		movwf	rom_add_h
		movlw	sp_01j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「にじ」読み出し
sp_02j
		movlw	sp_02j_p
		movwf	rom_chip
		movlw	sp_02j_h
		movwf	rom_add_h
		movlw	sp_02j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「さんじ」読み出し
sp_03j
		movlw	sp_03j_p
		movwf	rom_chip
		movlw	sp_03j_h
		movwf	rom_add_h
		movlw	sp_03j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「よじ」読み出し
sp_04j
		movlw	sp_04j_p
		movwf	rom_chip
		movlw	sp_04j_h
		movwf	rom_add_h
		movlw	sp_04j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「ごじ」読み出し
sp_05j
		movlw	sp_05j_p
		movwf	rom_chip
		movlw	sp_05j_h
		movwf	rom_add_h
		movlw	sp_05j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「ろくじ」読み出し
sp_06j
		movlw	sp_06j_p
		movwf	rom_chip
		movlw	sp_06j_h
		movwf	rom_add_h
		movlw	sp_06j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「しちじ」読み出し
sp_07j
		movlw	sp_07j_p
		movwf	rom_chip
		movlw	sp_07j_h
		movwf	rom_add_h
		movlw	sp_07j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「はちじ」読み出し
sp_08j
		movlw	sp_08j_p
		movwf	rom_chip
		movlw	sp_08j_h
		movwf	rom_add_h
		movlw	sp_08j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「くじ」読み出し
sp_09j
		movlw	sp_09j_p
		movwf	rom_chip
		movlw	sp_09j_h
		movwf	rom_add_h
		movlw	sp_09j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「じゅうじ」読み出し
sp_10j
		movlw	sp_10j_p
		movwf	rom_chip
		movlw	sp_10j_h
		movwf	rom_add_h
		movlw	sp_10j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「じゅういちじ」読み出し
sp_11j
		movlw	sp_11j_p
		movwf	rom_chip
		movlw	sp_11j_h
		movwf	rom_add_h
		movlw	sp_11j_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「じゅっぷん」読み出し
sp_10f
		movlw	sp_10f_p
		movwf	rom_chip
		movlw	sp_10f_h
		movwf	rom_add_h
		movlw	sp_10f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「にじゅっぷん」読み出し
sp_20f
		movlw	sp_20f_p
		movwf	rom_chip
		movlw	sp_20f_h
		movwf	rom_add_h
		movlw	sp_20f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「さんじゅっぷん」読み出し
sp_30f
		movlw	sp_30f_p
		movwf	rom_chip
		movlw	sp_30f_h
		movwf	rom_add_h
		movlw	sp_30f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「よんじゅっぷん」読み出し
sp_40f
		movlw	sp_40f_p
		movwf	rom_chip
		movlw	sp_40f_h
		movwf	rom_add_h
		movlw	sp_40f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「ごじゅっぷん」読み出し
sp_50f
		movlw	sp_50f_p
		movwf	rom_chip
		movlw	sp_50f_h
		movwf	rom_add_h
		movlw	sp_50f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「じゅう」読み出し
sp_10t
		movlw	sp_10t_p
		movwf	rom_chip
		movlw	sp_10t_h
		movwf	rom_add_h
		movlw	sp_10t_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「にじゅう」読み出し
sp_20t
		movlw	sp_20t_p
		movwf	rom_chip
		movlw	sp_20t_h
		movwf	rom_add_h
		movlw	sp_20t_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「さんじゅう」読み出し
sp_30t
		movlw	sp_30t_p
		movwf	rom_chip
		movlw	sp_30t_h
		movwf	rom_add_h
		movlw	sp_30t_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「よんじゅう」読み出し
sp_40t
		movlw	sp_40t_p
		movwf	rom_chip
		movlw	sp_40t_h
		movwf	rom_add_h
		movlw	sp_40t_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「ごじゅう」読み出し
sp_50t
		movlw	sp_50t_p
		movwf	rom_chip
		movlw	sp_50t_h
		movwf	rom_add_h
		movlw	sp_50t_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「いっぷん」読み出し
sp_01f
		movlw	sp_01f_p
		movwf	rom_chip
		movlw	sp_01f_h
		movwf	rom_add_h
		movlw	sp_01f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「にふん」読み出し
sp_02f
		movlw	sp_02f_p
		movwf	rom_chip
		movlw	sp_02f_h
		movwf	rom_add_h
		movlw	sp_02f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「さんぷん」読み出し
sp_03f
		movlw	sp_03f_p
		movwf	rom_chip
		movlw	sp_03f_h
		movwf	rom_add_h
		movlw	sp_03f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「よんぷん」読み出し
sp_04f
		movlw	sp_04f_p
		movwf	rom_chip
		movlw	sp_04f_h
		movwf	rom_add_h
		movlw	sp_04f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「ごふん」読み出し
sp_05f
		movlw	sp_05f_p
		movwf	rom_chip
		movlw	sp_05f_h
		movwf	rom_add_h
		movlw	sp_05f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「ろっぷん」読み出し
sp_06f
		movlw	sp_06f_p
		movwf	rom_chip
		movlw	sp_06f_h
		movwf	rom_add_h
		movlw	sp_06f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「ななふん」読み出し
sp_07f
		movlw	sp_07f_p
		movwf	rom_chip
		movlw	sp_07f_h
		movwf	rom_add_h
		movlw	sp_07f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「はっぷん」読み出し
sp_08f
		movlw	sp_08f_p
		movwf	rom_chip
		movlw	sp_08f_h
		movwf	rom_add_h
		movlw	sp_08f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「きゅうふん」読み出し
sp_09f
		movlw	sp_09f_p
		movwf	rom_chip
		movlw	sp_09f_h
		movwf	rom_add_h
		movlw	sp_09f_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; フレーズ「です」読み出し
sp_des
		movlw	sp_des_p
		movwf	rom_chip
		movlw	sp_des_h
		movwf	rom_add_h
		movlw	sp_des_l
		movwf	rom_add_l
		call	rom_read	;ROM 読み出し
		return

		; 時刻調整時のみ 0.8秒間無音とする
sp_00f
		btfss	stat_byte,timset ;時刻調整中か?
		goto	sp00		;No

		call	tim_200ms
		call	tim_200ms
		call	tim_200ms
		call	tim_200ms

sp00		return

;==========================================================================
;		スピーチテスト
;==========================================================================

rom_test
		btfsc	PORTB,voice_sw	;音声告知スイッチ = ON か？
		goto	r_test02	;No

r_test01	btfss	PORTB,voice_sw	;音声告知スイッチ = OFF か？
		goto	r_test01	;No

		call	audio_set	;オーディオ回路の設定
		call	tim_200ms
		call	beep
		call	tim_100ms
		call	beep
		call	tim_200ms
		call	sp_12j		;フレーズ「じゅうにじ」読み出し
		call	sp_01j		;フレーズ「いちじ」読み出し
		call	sp_02j		;フレーズ「にじ」読み出し
		call	sp_03j		;フレーズ「さんじ」読み出し
		call	sp_04j		;フレーズ「よじ」読み出し
		call	sp_05j		;フレーズ「ごじ」読み出し
		call	sp_06j		;フレーズ「ろくじ」読み出し
		call	sp_07j		;フレーズ「しちじ」読み出し
		call	sp_08j		;フレーズ「はちじ」読み出し
		call	sp_09j		;フレーズ「くじ」読み出し
		call	sp_10j		;フレーズ「じゅうじ」読み出し
		call	sp_11j		;フレーズ「じゅういちじ」読み出し
		call	sp_10f		;フレーズ「じゅっぷん」読み出し
		call	sp_20f		;フレーズ「にじゅっぷん」読み出し
		call	sp_30f		;フレーズ「さんじゅっぷん」読み出し
		call	sp_40f		;フレーズ「よんじゅっぷん」読み出し
		call	sp_50f		;フレーズ「ごじゅっぷん」読み出し
		call	sp_10t		;フレーズ「じゅう」読み出し
		call	sp_20t		;フレーズ「にじゅう」読み出し
		call	sp_30t		;フレーズ「さんじゅう」読み出し
		call	sp_40t		;フレーズ「よんじゅう」読み出し
		call	sp_50t		;フレーズ「ごじゅう」読み出し
		call	sp_01f		;フレーズ「いっぷん」読み出し
		call	sp_02f		;フレーズ「にふん」読み出し
		call	sp_03f		;フレーズ「さんぷん」読み出し
		call	sp_04f		;フレーズ「よんぷん」読み出し
		call	sp_05f		;フレーズ「ごふん」読み出し
		call	sp_06f		;フレーズ「ろっぷん」読み出し
		call	sp_07f		;フレーズ「ななふん」読み出し
		call	sp_08f		;フレーズ「はっぷん」読み出し
		call	sp_09f		;フレーズ「きゅうふん」読み出し
		call	sp_des		;フレーズ「です」読み出し
		call	tim_200ms
		call	tim_200ms
		call	beep
		call	tim_100ms
		call	beep

r_test02	return

;==========================================================================
;		I2C EEPROM 読み出し
;==========================================================================

rom_read
		call	sda_in		;初期設定でSDAを入力モードにしたならば必要ない
		call	start_con	;スタートコンディション
		call	rom_tim		;タイミング調整

		movlw	h'a0'		;コントロールバイト + 書き込みビット
		iorwf	rom_chip,W	;デバイスアドレスを加える(24C1024では最上位アドレスP0<BIT:1>を含む)
		movwf	data_out
		call	byte_out	;1バイト送信
		call	rom_tim		;タイミング調整

		movf	rom_add_h,W	;アドレス上位送信
		movwf	data_out
		call	byte_out	;1バイト送信
		call	rom_tim		;タイミング調整

		movf	rom_add_l,W	;アドレス下位送信
		movwf	data_out
		call	byte_out	;1バイト送信
		call	rom_tim		;タイミング調整

		call	start_con	;スタートコンディション
		call	rom_tim		;タイミング調整

		movlw	h'a1'		;コントロールバイト + 読み出しビット
		iorwf	rom_chip,W	;デバイスアドレスを加える(24C1024では最上位アドレスP0<BIT:1>を含む)
		movwf	data_out
		call	byte_out	;1バイト送信
		call	rom_tim		;タイミング調整

seq_read
		bsf	buffer,ack_bit	;ACKビットを送出して連続読み出し
		call	byte_in		;1バイト受信

		;データ処理
		comf	data_in,W	;h'ff' であるか確認
		btfsc	STATUS,Z
		goto	last_read	;h'ff' ならば読み出し終了

		movf	da_data_a,W
		movwf	PORTD		;前回のデータをポート出力
		clrf	da_data_b
		movf	data_in,W
		bcf	STATUS,C
		addwf	da_data_a,F
		btfsc	STATUS,C
		bsf	da_data_b,0
		rrf	da_data_a,F
		btfsc	da_data_b,0
		bsf	da_data_a,7
		call	tim_ad		;音声スピード
		movf	da_data_a,W	;前回と今回のデータの平均値をポート出力
		movwf	PORTD
		movf	data_in,W
		movwf	da_data_a	;今回のデータを保存
		goto	seq_read	;シーケンス読み出し継続
		;
last_read
		bcf	buffer,ack_bit	;ACKビットを送出しないで最終読み出し
		call	byte_in		;1バイト受信
		call	rom_tim		;タイミング調整

		call	stop_con	;ストップコンディション
		return

;--------------------------------------------------------------------------

;		I2C EEPROM スタートシーケンス

start_con
		bsf	PORTA,scl	;SCL="H"
		call	rom_tim		;タイミング調整
		call	sda_out		;SDA端子を出力モードにする："H"レベル出力
		bcf	PORTA,sda	;SDA="L"
		call	rom_tim		;タイミング調整
		bcf	PORTA,scl	;SCL="L"
		call	sda_in		;SDA端子を入力モードにする（SDAはプルアップ抵抗により"H"レベル）
		return

;		I2C EEPROM ストップシーケンス

stop_con
		call	sda_out		;SDA端子を出力モードにする："H"レベル出力
		bcf	PORTA,sda	;SDA="L"
		bsf	PORTA,scl	;SCL="H"
		call	rom_tim		;タイミング調整
		call	sda_in		;SDA端子を入力モードにする（SDAはプルアップ抵抗により"H"レベル）
		return
	
;--------------------------------------------------------------------------

;		I2C EEPROM 1バイト送信

byte_out
		movlw	8
		movwf	bit_cnt		;ループカウンタにセット

byteo01		bsf	buffer,do	;    出力ビット do = 1
		btfss	data_out,7	;送り出しデータの 7ビット目 = 1 か？
		bcf	buffer,do	;No. 出力ビット do = 0
		call	bit_out		;1ビット送信
		rlf	data_out,F	;送り出しデータを 1ビット左にシフト
		decfsz	bit_cnt,F	;8ビット送信した か？
		goto	byteo01		;No

		call	bit_in		;1ビット受信
		return

;		I2C EEPROM 1バイト受信

byte_in
		clrf	data_in		;読み出しデータ（の入れ物）を初期設定
		movlw	8
		movwf	bit_cnt		;ループカウンタにセット
		bcf	STATUS,C

bytei01		rlf	data_in,F	;読み出しデータを 1ビット左にシフト
		call	bit_in		;1ビット受信
		btfsc	buffer,di	;入力ビット di = 0 か？
		bsf	data_in,0	;No. 読み出しデータの 0ビット目 = 1
		decfsz	bit_cnt,F	;8ビット受信した か？
		goto	bytei01		;No

		bsf	buffer,do	;    出力ビット do = 1
		btfsc	buffer,ack_bit	;ACKビット = 0 か？
		bcf	buffer,do	;No. 出力ビット do = 0
		call	bit_out		;1ビット送信
		return

;--------------------------------------------------------------------------

;		I2C EEPROM 1ビット送信

bit_out
		bcf	PORTA,scl	;SCL="L"
		btfsc	buffer,do	;出力ビット do = 0 か？
		goto	bito01		;No

		call	sda_out		;SDA 端子を出力設定
		bcf	PORTA,sda	;SDA="L"

bito01		bsf	PORTA,scl	;SCL="H"
		call	rom_tim		;タイミング調整
		bcf	PORTA,scl	;SCL="L"
		call	sda_in		;SDA 端子を入力設定
		return

;		I2C EEPROM 1ビット受信

bit_in
		bcf	PORTA,scl	;SCL="L"
		call	sda_in		;SDA 端子を入力設定
		bsf	buffer,di	;    入力ビット di = 1
		bsf	PORTA,scl 	;SCL="H"
		call	rom_tim		;タイミング調整
		btfss	PORTA,sda	;SDA="H" か？
		bcf	buffer,di	;No. 入力ビット di = 0
		bcf	PORTA,scl	;SCL="L"
		return

;--------------------------------------------------------------------------

;		I2C EEPROM SDA 入力端子設定

sda_in
		bsf	STATUS,RP0	;バンク1
		bsf	TRISA,sda	;SDA 端子を入力設定
		bcf	STATUS,RP0	;バンク0
		return

;		I2C EEPROM SDA 出力端子設定

sda_out
		bsf	STATUS,RP0	;バンク1
		bcf	TRISA,sda	;SDA 端子を出力設定
		bcf	STATUS,RP0	;バンク0
		bsf	PORTA,sda	;SDA="H"
		return

;--------------------------------------------------------------------------

;		I2C EEPROM タイミング調整用ディレイ
;		（配線により読み出し不良となる場合があるのであまり欲張らない）

rom_tim
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
		goto	$+1		;2サイクル
;		goto	$+1		;2サイクル
;		goto	$+1		;2サイクル
;		goto	$+1		;2サイクル
;		goto	$+1		;2サイクル
;		goto	$+1		;2サイクル
;		goto	$+1		;2サイクル
		return			;2サイクル

;==========================================================================
;		遅延タイマ・ルーチン (20 MHz)
;==========================================================================

		; 100μ秒 ウェイトルーチン

tim_100us
		movlw	166		;1
		movwf	tim_cnt1	;1

t100us01	decfsz	tim_cnt1,F	;1,2
		goto	t100us01	;2,0	1+1+(1+2)*165+(2+0)=499

		return			;2	499+2=501
					;Total	501/20MHz*4 = 0.0001002 S = 100 μS

		; 200m秒, 150m秒, 100m秒, 50m秒 ウェイトルーチン

tim_200ms				;50 mS + 50 mS + 50 mS + 50 mS
		movlw	248
		movwf	tim_cnt2

t200ms01	call	tim_100us
		call	tim_100us
		decfsz	tim_cnt2,F
		goto	t200ms01

tim_150ms				;50 mS + 50 mS + 50 mS
		movlw	248
		movwf	tim_cnt2

t150ms01	call	tim_100us
		call	tim_100us
		decfsz	tim_cnt2,F
		goto	t150ms01

tim_100ms				;50 mS + 50 mS
		movlw	248
		movwf	tim_cnt2

t100ms01	call	tim_100us
		call	tim_100us
		decfsz	tim_cnt2,F
		goto	t100ms01

tim_50ms				;50 mS
		movlw	248		;1
		movwf	tim_cnt2	;1

t50ms01		call	tim_100us	;503	2+501
		call	tim_100us	;503	2+501
		decfsz	tim_cnt2,F	;1,2
		goto	t50ms01		;2,0	1+1+(503+503+1+2)*247+(503+503+2+0)=250233

		return			;2	2+250233=250235
					;Total	250235/20MHz*4 = 0.050047 S = 50 mS

;--------------------------------------------------------------------------

		; 音声スピード

tim_ad
		movlw	h'17'		;h'01'～h'30'程度
		movwf	tim_cnt1

timad01		decfsz	tim_cnt1,F
		goto	timad01

		return

;--------------------------------------------------------------------------

		; チャタリング監視時間 (約20mS)

tim_sw
		movlw	99		;1
		movwf	tim_cnt2	;1

timsw01		call	tim_100us	;503	2+501
		call	tim_100us	;503	2+501
		decfsz	tim_cnt2,F	;1,2
		goto	timsw01		;2,0	1+1+(503+503+1+2)*98+(503+503+2+0)=99892

		return			;2	99892+2=99894
					;Total	99894/20MHz*4 = 0.0199788 S = 20 mS

;==========================================================================
;		割り込み処理
;==========================================================================
; 割込みに入るのは タイマー１オーバーフローとINTピン立下りの2通り
; タイマー１割込みは4秒ごとに発生する

interrupt
		movwf	w_save		;W レジスタの保存
		movf	STATUS,W
		movwf	s_save		;STATUS レジスタの保存

		btfsc	PIR1,TMR1IF	;タイマ１オーバフロー か？
		goto	int_tmr1	;Yes

		; 外部割り込み (RB0/INT)

		bcf	INTCON,INTF	;外部割り込み(RB0/INT)を解除
		bsf	stat_byte,swint	;外部割り込み(RB0/INT)であることを記憶
		goto	int_out

		; タイマー１割り込み

int_tmr1	bcf	PIR1,TMR1IF	;タイマ１オーバフローを解除

		incf	s4_cnt,F	;4秒カウンタ + 1
		movlw	15
		subwf	s4_cnt,W
		btfss	STATUS,Z	;4秒カウンタ = 15 か？
		goto	int_out		;No

		clrf	s4_cnt		;Yes. 15回のカウントでレジスタクリア

		incf	ml_cnt,F	;分カウンタ + 1
		movlw	10
		subwf	ml_cnt,W
		btfss	STATUS,Z	;分カウンタ = 10 か?
		goto	int_out		;No

		clrf	ml_cnt		;Yes. 10回のカウントでレジスタクリア

		incf	mh_cnt,F	;十分カウンタ + 1
		movlw	3
		subwf	mh_cnt,W
		btfsc	STATUS,Z	;十分カウンタ = 3 か?
		bsf	stat_byte,auto30 ;Yes. 30分オートスピーチフラグをセット

		movlw	6
		subwf	mh_cnt,W
		btfss	STATUS,Z	;十分カウンタ = 6 か?
		goto	int_out		;No

		clrf	mh_cnt		;Yes. 6回のカウントでレジスタクリア

		incf	ho_cnt,F	;時カウンタ + 1
		bsf	stat_byte,auto00 ;00分オートスピーチフラグをセット
		movlw	12
		subwf	ho_cnt,W
		btfss	STATUS,Z	;時カウンタ = 12 か?
		goto	int_out		;No

		clrf	ho_cnt		;Yes. 12回のカウントでレジスタクリア

int_out		movf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie

;==========================================================================

		end			;プログラムの終了
