;***** I2Cmod_LCD1602_Clock.asm *******************************************
;
;	I2C IF モジュール使用 LCD 1602 表示時計
;
;	Copyright (C) 2020-2021   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2020/12/10  by M.Yamamoto )
;	coding:  Ver. 1.00   2021/01/30  初期バージョン
;	update:  Ver. x.xx
;	bugfix:  Ver. x.xx
;
;******************************************************* PicAsm 0256 ******

;	Device: PIC16F684	Clock: 8Hz (Internal OSC)

#ifdef comment

 <機能概要>

・本機の電源を投入すると、"ピポッ" と開始ブザー音を出力後、ＬＣＤに次の開始メッセージが３秒間ずつ交互に連続
　２回表示がされる。

			[ LCD 1602 Clock ]			[    Ver.x.xx    ]
			[ (Temp & Humi)  ]			[  by m.yamamoto ]

・その後１秒間の空白を置いた後、RTC（リアルタイムクロック）モジュールの状態がチェックされ、初めて電源を入れ
　たときや、バックアップ用バッテリーが異常なとき等に、次のエラーメッセージがＬＣＤに表示されるとともに、"ブ
　ッブー" ブザー音が出力される。 

			[ DS3231 Error!  ]
			[        Init?_  ]

・なお、このときＬＣＤでは "Init?_" の後がブリンク表示されているが、これは RTC（リアルタイムクロック）モジュ
　ールの初期設定をするかどうかを、ユーザに応答を求めていることを表している。ユーザはバックアップ用バッテリー
　の状態等を確認してその対処を行った後、 この場合には５つのスイッチの内のどれかを押して応答をする。

・すると、RTC（リアルタイムクロック）モジュールの初期設定をした後、再度 RTC（リアルタイムクロック）モジュー
　ルの状態がチェックされ、なおも NG であれば同様にエラーメッセージの表示が繰り返されるが、OK であれば時計機
　能のＬＣＤ表示が開始され、次のように年月日(曜日)、時分秒が刻々と変化をしながら表示が行われる。この状態を 
　NORMAL モード という。 

			[20xx/xx/xx (xxx)]
			[  xx xx:xx:xx   ]

・このように、RTC（リアルタイムクロック）モジュールの初期設定がされると、エラーフラグがクリアされるとともに、
　年月日(曜日)、時分秒が本機をプログラミングしたときの設定値、 "2021/01/01(FRI)"、"00：00：00" にされるため、 
　次のスイッチ操作による手順で現在の年月日、時分秒に設定し直す必要がある。

・その手順の説明の前に、先に本機におけるＬＣＤに表示をする、項目（年月日、時分秒、温度湿度）の組み合わせパタ
　ン（モード）を説明しておく。（このときのモードの意味は上述の NORMAL モードと対比するものではなく、単に組み
　合わせパタンの種類を意味し表している。）

		モード 0          	モード 2		モード 4
		[20xx/xx/xx (xxx)]	[  xx xx:xx:xx   ]	[-xx.xﾟC xxx.x % ]
		[  xx xx:xx:xx   ]	[-xx.xﾟC xxx.x % ]	[20xx/xx/xx (xxx)]

		モード 1          	モード 3          	モード 5
		[20xx/xx/xx (xxx)]	[  xx xx:xx:xx   ]	[-xx.xﾟC xxx.x % ]
		[-xx.xﾟC xxx.x % ]	[20xx/xx/xx (xxx)]	[  xx xx:xx:xx   ]

・以上のように６つの表示パタン（モード）があり、これらは MODE / SET スイッチを押すごとに、ＬＣＤに表示される
　項目の組み合わせパタン（モード）が切り替わり、モード番号が増加して行く。 そして モード 5 の次は再びモード 
　0 に戻る。なお、これらの３つの項目（年月日、時分秒、温度湿度）は刻々とリアルタイムに更新をしながらＬＣＤに
　表示が行われる。

・ここで話を戻すと設定手順としては、このようにどのパタン（モード）がＬＣＤに表示されている場合においても可能
　で、まず、パタン（モード）切り替えのときのように "チョン押し" ではなく、同じ MODE / SETスイッチ を "長押し"
　することによって、スイッチ操作による年月日、時分秒を自由に設定することができる、SET モード に移行をする。 

・すなわち、MODE / SET スイッチを３秒以上 "長押し" をしていると、ＬＣＤに次のメッセージが表示されて、NORMAL 
　モードから SET モードに移行をしたことを知らせる。

			[ ** SET MODE ** ]
			[                ]

・ユーザはそれを確認してスイッチから指を離すと、次には必ずモード 0 の表示パタンで年月日、時分秒が表示される。
　ただし、SET モードに移行後は表示の更新は停止して刻々と変化することはない。そして、この移行直後は "20xx" の
　左の "x" のところがブリンク表示され、"年の下位２桁" が変更の対象項目であることを示している。 
			   v
			[20xx/xx/xx (xxx)]	………  v の位置の文字がブリンク表示
			[  xx xx:xx:xx   ]

・ここで変更が必要であれば、UP スイッチを押すごとに現在値より１づつ増加し、また DOWN スイッチ を押すごとに
　１づつ減少するので、適宜希望する値に変更をする。また、このときの増減幅を大きくしたい場合には、UP スイッチ、
　または DOWN スイッチを押したままにしていると、１秒当たり 4 ～ 5 の増減幅で更新をするようになる。

・"年の下位２桁" の変更が済んだら、再び MODE / SET スイッチを押すと、次には "月の２桁" である "/xx/" の左の 
　"x" のところがブリンク表示され、変更の対象項目が変更されたことを示す。このように各変更の対象項目２桁の内、
　必ず１桁目（左側）がブリンク表示されて、そのときに選択されている対象項目を表現している。
			      v
			[20xx/xx/xx (xxx)]	………  v の位置の文字がブリンク表示
			[  xx xx:xx:xx   ]

・そして同様に変更が必要であれば、UP スイッチ、または DOWN スイッチを押すことによって、適宜希望する値に変更
　をする。

・以降、同様に SET スイッチを押すごとに、日 → 24H/12H → 時 → 分 → 秒 と設定項目を変更することができるの
　で、変更が必要であればその該当項目の選択時に、UP スイッチ、または DOWN スイッチを押すことによって、適宜希
　望する値に変更をする。

・なお、曜日は年月日によって一意的に決まるものであって、曜日だけを勝手に変更をすることは許されないため、曜日
　については変更の対象項目には入っていない。年、月、日のどれかを変更することによって、曜日も自動的に変更表示
　がされる。

・この SET スイッチによって対象項目を選択中に、誤って希望する項目を通り過ぎてしまったような場合には、ZERO / 
　BACK スイッチを押すごとにひとつづつ前の項目に戻ることができる。

・最後の秒の項目選択時に更に SET スイッチを押すと、今まで変更をしてきた設定値の年月日、時分秒が RTC（リアル
　タイムクロック）モジュールに書き込み更新されるとともに、SET モードから再び NORMAL モード に切り替わって、
　ＬＣＤには新たな更新表示が再開される。

・SET モードでの選択項目の推移をまとめると次図のようになる。 

	                                BACK  BACK  BACK       BACK  BACK  BACK
	              MODE               ←    ←    ←         ←    ←    ←
	              /SET              SET   SET   SET        SET   SET   SET   SET
	  NORMALモード ─→ 年(下位２桁) → 月 → 日 → 24H/12H → 時 → 分 → 秒 ─→ NORMALモード
	                         │                                            ↑
	                     BACK└──────────────────────┘

・ここで項目 24H/12H について補足をしておくと、これは時表示を 24 時間表示にするか 12 時間表示にするかの、ど
　ちらかを選択することで、この項目を選択時に UP スイッチ、または DOWN スイッチのどちらかを押すことによって、
　交互に切り替えることができる。

			[20xx/xx/xx (xxx)]			[20xx/xx/xx (xxx)]
			[     xx:xx:xx   ]			[  AM xx:xx:xx   ]

・そして、24 時間表示を選択した場合には、ＬＣＤの該当の位置には何も表示がされないが、12 時間表示を選択した
　場合には、そのときに表示している時の値によって、ＬＣＤの該当の位置には AM または PM が表示される。逆に、
　時の項目が選択時にも時の値を変更すると（12 時間表示が選択のときには）、その値によって AM / PM が更新表示
　される。

・次に、12 時間表示と 24 時間表示の対応を示す。なお、12 時間表示の場合のみ 時 "xx" の先頭の１桁目は、ゼロサ
　プレスを行なって表示をする。

		(24H)  00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
		(12H)  12  1  2  3  4  5  6  7  8  9 10 11 12  1  2  3  4  5  6  7  8  9 10 11
		       am am am am am am am am am am am am pm pm pm pm pm pm pm pm pm pm pm pm

・なお、この 12 時間表示と 24 時間表示の変更操作は、上述の SET モード中だけでなく、NORMAL モードにおいても 
　UP スイッチを押すごとに、いつでも交互に切り替えることができる。

・ZERO／BACK スイッチは、SET モードでは上述のように BACK スイッチとして機能をするが、NORMAL モードでは 毎正
　時プラス・マイナス 5 分以内に押されると、00 分 00 秒に設定するための ZERO スイッチとして機能をする。

・SIGNAL スイッチは、毎時の時報音出力のブザー音を、押すごとに有効／無効に交互に設定をする。 このときの設定
　状態は視覚的な表示がないため、有効になったときには "ピピピッ" 音を、無効になったときには "ブー" 音を、そ
　れぞれ鳴らして知らせる。なお、電源を投入した直後は有効状態に設定がされている。また、有効に設定時には、時
　分秒が表示されない表示パタン（モード）においても、毎時の時報音は有効（鳴る）なので注意が必要である。

・本機では年月日(曜日)、時分秒の他に、温度湿度を表示するパタン（モード）があることは上述の通りであるが、年
　月日(曜日)、時分秒の情報は、上述した RTC（リアルタイムクロック）モジュール（ DS3231 ）と PIC とを、I2C シ
　リアル通信によって情報を得ているのに対して、温度湿度情報は、デジタル温度湿度センサーモジュール（ DHT22（
　AM2302））と PIC との間を、たった１本だけのデータ線によるシリアル通信によって情報を得ている。

・そして、前者の場合には１秒間隔で通信を行うが、後者の場合には４秒間隔（２秒以上が必要）で通信を行っている。
　また、前者の場合には通信を休むことはない（１秒に１度必ず通信を行う）が、後者の場合にはＬＣＤ表示がないパ
　タン（モード）に設定がされているときには、本機ではまったく通信を行わずに休んでいる。

・また、後者のデジタル温度湿度センサーモジュール（ DHT22（AM2302））との通信においては、通信中にエラーが起
　こった場合には、次のようなエラーメッセージがＬＣＤに表示されるとともに、"ブッブー" ブザー音が出力される。
　次の例では、表示パタンがモード 1 に設定されている場合で２行目にエラー表示がされているが、モード x によっ
　て１行目に表示がされる場合もある。

			[20xx/xx/xx (xxx)]			[20xx/xx/xx (xxx)]
			[DHT22 Time Out! ]			[DHT22 CRC Error!]

・左の例では通信中にタイムアウトエラーが起こった場合で、データ線上の "high" または "low" 電圧の続く時間が、
　仕様で決められた時間をオーバーした場合に発生をする。 また、右の例ではチェックサム(CRC)エラーが起こった場
　合で、DHT22（AM2302）からは１度の通信で、湿度情報が 16 ビット、温度情報が 16 ビット、チェックサムが 8 ビ
　ットの、計 40 ビットが送られてくるが、それらの情報でパリティチェックを行った結果、エラーが起こった場合に
　発生をする。

#endif

;==========================================================================

;	PIC16F684 のピンと用途

;		(1) Vdd: 電源 +5V DC		(14) Vss: 電源 GND
;		(2) RA5: MODE/SET SW 入力	(13) RA0: ZERO／BACK SW 入力
;		(3) RA4: UP SW 入力		(12) RA1: DOWN SW 入力
;		(4) RA3: SIGNAL SW 入力		(11) RA2/INT: SQW 入力
;		(5) RC5: DHT22 DATAポート	(10) RC0: I2C SCL 出力
;		(6) RC4: ブザー音 出力		 (9) RC1: I2C SDA 入出力
;		(7) RC3: 予備			 (8) RC2: 予備

;	*注.  RA3 は入力専用で、出力ポートには使えない。

;==========================================================================

		list		p=pic16f684		;デバイス情報
		include		p16f684.inc		;インクルードファイル
		errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションの設定
;==========================================================================

	__config 	_CP_OFF & _CPD_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

;==========================================================================
;		定数の定義と変数のレジスタ割付け
;==========================================================================

#define 	ver_no	"1.00"

		radix	dec

DHT		equ	5		;DHT22 DATAポート	;┐
SCL		equ	0		;I2C SCL		;│PORTC
SDA		equ	1		;I2C SDA		;│
_BZ		equ	4		;アラーム音 出力	;┘

_swZER		equ	0		;ZERO   スイッチ	;┐
_swBAK		equ	0		;BACK   スイッチ	;│
_swDWN		equ	1		;DOWN   スイッチ	;│
_swUP		equ	4		;UP     スイッチ	;│PORTA
_swMOD		equ	5		;MODE   スイッチ	;│
_swSET		equ	5		;SET    スイッチ	;│
_swSIG		equ	3		;SIGNAL スイッチ	;┘

f_rah		equ	65536 - 1136	;ラ (880.00 Hz)
f_doh		equ	65536 - 1911	;ド (523.26 Hz)  at 8MHz
f_ra		equ	65536 - 2273	;ラ (440.00 Hz)
f_so		equ	65536 - 2551	;ソ (392.00 Hz)
f_mi		equ	65536 - 3034	;ミ (329.63 Hz)
f_do		equ	65536 - 3822	;ド (261.63 Hz)
f_do_		equ	65536 - 7644	;ド (130.82 Hz)
po_tim		equ	100		;音長(ms)
pi_tim		equ	100		;音長
bu_tim		equ	100		;音長
buu_tim		equ	250		;音長

		cblock	h'20'
int_flg					;外部(RA2/INT)割り込みフラグ
					;bit0: RTC DS3231 からデータ読み出し要求フラグ
					;bit1: DHT22 からデータ読み出し要求フラグ, （取消変更）*
					;bit1-2: 4 秒カウンタ, （変更）*
					;bit3: DHT22 からデータ読み出し要求フラグ, （変更）*
bcd_yh					;年(上位2桁) BCD カウンタ
bcd_yl					;年(下位2桁) BCD カウンタ
;bcd_yy					;年 BCD カウンタ
bcd_nn					;月 BCD カウンタ
bcd_dd					;日 BCD カウンタ
bcd_hh					;時 BCD カウンタ
bcd_mm					;分 BCD カウンタ
bcd_ss					;秒 BCD カウンタ
bcd_ww					;曜日 BCD カウンタ
temp_hh					;仮の時 BCD カウンタ
time_flg				;時間表示モードフラグ  bit1=0:24H/1:12H, bit0=0:am/1:pm
mod_cnt					;bit0-6: 表示モードカウンタ
mod_flg					;bit7: 表示モード変更フラグ, bit6: エラー表示の記憶フラグ
blk_point				;ブリンク位置ポインタ
chg_flg					;データ変更フラグ, bit0:ブリンク位置だけ, :bit1:ブリンク位置のデータ変更
sig_flg					;時報音出力フラグ, bit0:予報音, :bit1:正報音, bit7:出力許可
uru_flg					;0:平年 / 1:閏年
cur_yh					;年(上位2桁)(変) BCD カウンタ
cur_yl					;年(下位2桁)(変) BCD カウンタ
cur_nn					;月(変) BCD カウンタ
cur_week				;週位置カウンタ（曜日 1～7）
xxx_yh					;ワーク
m_humi_h				;湿度上位 8 bit の記憶
m_humi_l				;湿度下位 8 bit の記憶
m_temp_h				;温度上位 8 bit の記憶
m_temp_l				;温度下位 8 bit の記憶

work1					;ワーク
work2					;ワーク
work3					;ワーク
lp_cnt1					;汎用ループカウンタ
lp_cnt2					;汎用ループカウンタ
buff		;(00)			;変換文字列の格納エリア
buff1		;(01)			;
buff2		;(02)			;
buff3		;(03)			;
buff4		;(04)			;
data_h					;変換する上位バイト
data_l					;変換する下位バイト

const_high				;音階用分周定数 high の保存
const_low				;音階用分周定数 low の保存
wt1cnt					;ウェイト用ループカウンタ
wt2cnt					;ウェイト用ループカウンタ
wt3cnt					;ウェイト用ループカウンタ

; (DHT22.sub で使用)
humidity_h				;湿度上位 8 bit
humidity_l				;湿度下位 8 bit
temperature_h				;温度上位 8 bit
temperature_l				;温度下位 8 bit
time_cnt				;bit0-5: 時間計測カウンタ, 
					;bit6: チェックサム(CRC)エラー, bit7: タイムアウトエラー

; (I2C_RTC.sub で使用)
seconds					;00h: Seconds: 00-59
minutes					;01h: Minutes: 00-59
hours					;02h: Hours:   1-12 + AM/PM, 00-23
day					;03h: Day:     1-7
date					;04h: Date:    01-31
month					;05h: Month/Century: 01-12 + Century
year					;06h: Year:    00-99
alarm1s					;07h: Alarm 1 Seconds: 00-59
alarm1m					;08h: Alarm 1 Minutes: 00-59
alarm1h					;09h: Alarm 1 Hours:   1-12 + AM/PM, 00-23
alarm1dy				;0Ah: Alarm 1 Day:     1-7
alarm1d					;0Bh: Alarm 1 Date:    1-31
alarm2h					;0Ch: Alarm 2 Hours:   1-12 + AM/PM, 00-23
alarm2d					;0Dh: Alarm 2 Day:     1-7, Alarm 2 Date:    1-31
control					;0Eh: Control
cont_stat				;0Fh: Control/Status
aging					;10h: Aging Offset
temp_m					;11h: MSB of Temp
temp_l					;12h: LSB of Temp

rtc_lpcnt				;ループカウンタ
rtc_addr_high				;読み出すデータの high アドレス
rtc_addr_low				;読み出すデータの low アドレス

; (I2C_XS_LCD.sub で使用)
lcdtmp					;LCD への出力データの一時保存
lcdtmp2					;
cntrbuf					;
lcd_addr_high				;書き込みデータの high アドレス
lcd_addr_low				;書き込みデータの low アドレス

; (I2C_XS_100K.sub で使用)
i2ctmp					;送受信データの一時保存
bit_cnt					;ループカウンタ
		endc

		cblock	h'80' - 3
w_save					;W レジスタの退避用
s_save					;STATUS レジスタの退避用
f_save					;FSR レジスタの退避用
		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

;==========================================================================
;		サブルーチンファイルのインクルード
;==========================================================================

#define 	TRISX	TRISC		;PORTC で I2C を行う場合、
#define 	PORTX	PORTC		;

		include		D:\Project\PIC\_sub\I2C_XS_LCD.sub
		include		D:\Project\PIC\_sub\I2C_XS_100K.sub
		include		D:\Project\PIC\_sub\I2C_RTC.sub
		include		D:\Project\PIC\_sub\DHT22.sub

;==========================================================================
;		初期化処理
;==========================================================================

#define 	bcd_yy	bcd_yl		;年(下位2桁) BCD カウンタ ***

start
		bcf	STATUS,RP1
		bcf	STATUS,RP0	;バンク 0

		movlw	h'20'
		movwf	bcd_yh		;年(上位2桁) BCD カウンタ ***

		clrf	STATUS		;STATUS クリア
	 	clrf	INTCON		;INTCON クリア

		; PORTA,PORTC をデジタルI/O に設定

		clrf	PORTA		;
		clrf	PORTC		;
		movlw	b'00000111'	;Digital I/O
		movwf	CMCON0

		bsf	STATUS,RP0	;バンク 1
		clrf	ANSEL		;Digital I/O
		movlw	b'00111111'
		movwf	TRISA		;ポートA の I/0 設定
		movlw	b'00100000'
		movwf	TRISC		;ポートC の I/0 設定
					;RC5: DHT22のDATAポートを入力ポート = 外部プルアップで DHT="H"

		movlw	b'00110111'	;RA5,4,2,1,0 を プルアップ
		movwf	WPUA

		; 内部クロックを 8 MHzに設定

		movlw	h'70'		;CLOCK=8MHz
		movwf	OSCCON

		; OPTION_REG の設定

		movlw	b'00001000'	;bit7=0: プルアップ有効
					;bit6=0: INTピンの立ち下がりエッジで割り込み
					;bit5=0: タイマー０クロックソース選択 = 内部クロック（FOSC / 4）
					;bit4=0: タイマー０エッジ選択 = low-to-high
					;bit3=1: タイマー０でプリスケーラを使用しない
					;bit2-0=000: プリスケーラのスケール値 
		movwf	OPTION_REG

		; 割り込みの設定

		bcf	PIE1,TMR1IE	;TMR1IE: タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0

		movlw	b'00000001'	;bit7-6: 
					;bit5-4=00: プリスケーラのスケール値 1:1
					;bit3=0: 専用の発振器を使う場合に指定
					;bit2=0: 外部入力クロック指定時に有効
					;bit1=0: 内部クロックを使う
					;bit0=1: タイマー１を動作
		movwf	T1CON		;T1CON に設定

	;	bcf	INTCON,T0IE	;T0IE: タイマー０割り込みを禁止
		bcf	INTCON,INTE	;INTE: 外部(RA2/INT)割り込みを禁止
		bsf	INTCON,PEIE	;PEIE: 周辺機器割り込みを許可
		bsf	INTCON,GIE	;GIE:  グローバル割り込みを許可

;--------------------------------------------------------------------------

		; スタートメッセージの表示

		bsf	PORTC,DHT	;DHT="H", DHT22インタフェースの初期設定
		bsf	PORTC,SDA	;SDA="H"
		bsf	PORTC,SCL	;SCL="H"
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	I2CxLcd_Init	;I2C IF モジュール使用 LCD の初期設定
		movlw	h'0c'		;表示オン／オフコントロール
		call	I2CxLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク

		movlw	2
		movwf	lp_cnt1		;メッセージの表示回数
stmsg01
;		[ LCD 1602 Clock ]	;スタートメッセージ
;		[ (Temp & Humi)  ]
		Disp_I2CxLcd	h'80',start_msg,1	;DDRAM のアドレスをセット(１行目先頭)

		Disp_I2CxLcd	h'c0',         ,0	;DDRAM のアドレスをセット(２行目先頭)
		call	wait_1sec
		call	wait_1sec
		call	wait_1sec

;		[    Ver.x.xx    ]
;		[  by m.yamamoto ]
		Disp_I2CxLcd	h'80',         ,0	;DDRAM のアドレスをセット(１行目先頭)
		Disp_I2CxLcd	h'c0',         ,0	;DDRAM のアドレスをセット(２行目先頭)
		call	wait_1sec
		call	wait_1sec
		call	wait_1sec

		decfsz	lp_cnt1,F	;メッセージの表示回数 = 終了 か？
		goto	stmsg01		;No

;--------------------------------------------------------------------------

rtcinit01	movlw	h'01'		;表示クリア
		call	I2CxLcd_Cmd	;I2C LCD へコマンドを出力
		call	wait_1sec

		; I2C RTC（DS3231）モジュールのチェック

		Rtc_Read_M	cont_stat,1	;0Fh: Control/Status 読み出し

		btfss	cont_stat,7	;OSF = 1 か？
		goto	rtcinit03	;No

;		[ DS3231 Error!  ]	;DS3231 RTC エラーメッセージ
;		[        Init?_  ]	;DS3231 初期化メッセージ
		Disp_I2CxLcd	h'80',rtc_err,1		;DDRAM のアドレスをセット(１行目先頭)
		Disp_I2CxLcd	h'c8',       ,0		;DDRAM のアドレスをセット(２行目)

		movlw	h'0d'		;表示オン／オフコントロール
		call	I2CxLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=1: ブリンク
		movlw	h'ce'		;
		call	I2CxLcd_Cmd	;DDRAM のアドレスをセット
		call	buzzer_bubuu	;"ブッブー" ブザー音出力

rtcinit02	movlw	h'3b'		;全スイッチ
		andwf	PORTA,W
		xorlw	h'3b'
		btfsc	STATUS,Z	;どれかのスイッチ = ON か？
		goto	rtcinit02	;No

		movlw	h'0c'		;表示オン／オフコントロール
		call	I2CxLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク

		; I2C RTC（DS3231）モジュールの初期設定

		call	I2cRtc_Init	;I2C RTC（DS3231）モジュールの初期設定
		goto	rtcinit01

		; 各変数の初期設定

rtcinit03	clrf	mod_cnt		;表示モードカウンタの初期設定
		clrf	time_flg	;時間表示モードフラグ bit1=0:24H/1:12H, bit0=0:am/1:pm
		movlw	b'10000000'
		movwf	sig_flg		;時報音出力許可フラグ = ON
		movwf	mod_flg		;表示モード変更フラグ = ON（強制表示）
		Rtc_Read_M  seconds,7	;RTC DS3231 から年月日、時分秒を読み出し
		call	buffer_to_counter

		clrf	int_flg		;外部割り込みフラグの初期設定
		bsf	INTCON,INTE	;INTE: 外部(RA2/INT)割り込みを禁止解除
		goto	main

;==========================================================================
;	    I2C IF モジュール ＋ LCD(1602A) 表示用 メッセージ等
;==========================================================================

		; スタートメッセージ

start_msg	dt	" LCD 1602 Clock ",0
		dt	" (Temp & Humi)  ",0
		;	 0123456789ABCDEF

start_msg2	dt	"    Ver.",ver_no,"    ",0
		dt	"  by m.yamamoto ",0
		;	 0123456789ABCDEF

		; RTC エラーメッセージ, 初期化メッセージ

rtc_err		dt	" DS3231 Error!  ",0
		dt	        "Init?_  ",0
		;	 0123456789ABCDEF

		; 年月日(曜日)のテンプレート

date_temp	dt	"20  /  /   (   )",0
		;	 0123456789ABCDEF
;		dt	"20xx/xx/xx (xxx)",0

		; AM/PM 時分秒のテンプレート

time_temp	dt	"       :  :     ",0
		;	 0123456789ABCDEF
;		dt	"  xx xx:xx:xx   ",0

		; 温度、湿度のテンプレート

tmp_hum_temp	dt	"   . ﾟC    .  % ",0
		;	 0123456789ABCDEF
;		dt	"-xx.xﾟC xxx.x % ",0

		; SET モードメッセージ

set_mode_msg	dt	" ** SET MODE ** ",0
		;	 0123456789ABCDEF

		; タイムアウトエラーメッセージ

timout_err	dt	"DHT22 Time Out! ",0
		;	 0123456789ABCDEF

		; チェックサム(CRC)エラーメッセージ

crc_err		dt	"DHT22 CRC Error!",0
		;	 0123456789ABCDEF

;==========================================================================
;	    表示モードカウンタ mod_cnt 値による LCD 表示の遷移
;==========================================================================

;		mod_cnt = 0		[20xx/xx/xx (xxx)]
;					[  xx xx:xx:xx   ]

;		mod_cnt = 1		[20xx/xx/xx (xxx)]
;					[-xx.xﾟC xxx.x % ]

;		mod_cnt = 2		[  xx xx:xx:xx   ]
;					[-xx.xﾟC xxx.x % ]

;		mod_cnt = 3		[  xx xx:xx:xx   ]
;					[20xx/xx/xx (xxx)]

;		mod_cnt = 4		[-xx.xﾟC xxx.x % ]
;					[20xx/xx/xx (xxx)]

;		mod_cnt = 5		[-xx.xﾟC xxx.x % ]
;					[  xx xx:xx:xx   ]

;==========================================================================
;		メイン・ルーチン
;==========================================================================

main
		btfss	mod_flg,7	;表示モード変更フラグ = ON か？
		goto	main01		;No

;		[20xx/xx/xx (xxx)]	;
;		[  xx xx:xx:xx   ]
		call	date_display	;年月日(曜日)の表示
		call	time_display	;AM/PM 時分秒の表示

;		[-xx.xﾟC xxx.x % ]
		call	tmp_hum_display	;温度、湿度の表示

		bcf	mod_flg,7	;表示モード変更フラグ = OFF
		goto	main03

main01		btfss	int_flg,0	;RTC DS3231 からデータ読み出し要求フラグ = ON（１秒周期） か？
		goto	main03		;No

		Rtc_Read_M  seconds,7	;RTC DS3231 から年月日、時分秒を読み出し
		call	buffer_to_counter
		bcf	int_flg,0	;RTC DS3231 からデータ読み出し要求フラグ = OFF

;		[20xx/xx/xx (xxx)]	;mod_cnt = 0 のとき
;		[  xx xx:xx:xx   ]
		call	date_display	;年月日(曜日)の表示
		call	time_display	;AM/PM 時分秒の表示

	;;	btfss	int_flg,1	;DHT22 からデータ読み出し要求フラグ = ON（２秒周期） か？
		btfss	int_flg,3	;DHT22 からデータ読み出し要求フラグ = ON（４秒周期） か？, （変更）*
		goto	main02		;No

		movf	mod_cnt,W
		btfsc	STATUS,Z	;mod_cnt = 0 か？
		goto	main02		;Yes

		movlw	3
		subwf	mod_cnt,W
		btfsc	STATUS,Z	;mod_cnt = 3 か？
		goto	main02		;Yes

		call	dht22_measure	;DHT22 から温度、湿度を読み出し
		bcf	int_flg,3	;DHT22 からデータ読み出し要求フラグ = OFF, （追加）*

		btfsc	mod_flg,6	;エラー表示の記憶フラグ = ON か？
		bsf	mod_flg,7	;Yes. 表示モード変更フラグ = ON

;		[-xx.xﾟC xxx.x % ]
		call	tmp_hum_display	;温度、湿度の表示

main02		call	time_signal	;時報音出力コントロール	

		; 各スイッチの ON／OFF 状態のチェック

main03		btfss	PORTA,_swMOD	;MODE / SET スイッチ = ON か？
	;;	call	mode_switch	;Yes	;;┐
		goto	mode_switch	;Yes	;;│スタック消費量の改善対策
main04						;;┘
		btfss	PORTA,_swUP	;UP / TIME MODE スイッチ = ON か？
		call	tmode_switch	;Yes

		btfss	PORTA,_swZER	;ZERO スイッチ = ON か？
		call	zero_switch	;Yes

		btfss	PORTA,_swSIG	;SIGNAL スイッチ = ON か？
		call	signal_switch	;Yes
		goto	main

;--------------------------------------------------------------------------

		; バッファからカウンタへコピー

buffer_to_counter
		movf	seconds,W	;Seconds
		movwf	bcd_ss		;秒 BCD カウンタ
		movf	minutes,W	;Minutes
		movwf	bcd_mm		;分 BCD カウンタ
		movf	hours,W		;Hours
		movwf	bcd_hh		;時 BCD カウンタ

		movf	day,W		;Day
		movwf	bcd_ww		;曜日 BCD カウンタ

		movf	date,W		;Date
		movwf	bcd_dd		;日 BCD カウンタ
		movlw	h'1f'		;
		andwf	month,W		;Month
		movwf	bcd_nn		;月 BCD カウンタ
		movf	year,W		;Year
		movwf	bcd_yy		;年 BCD カウンタ
		return

		; カウンタからバッファへコピー

counter_to_buffer
		movf	bcd_ss,W	;秒 BCD カウンタ
		movwf	seconds		;Seconds
		movf	bcd_mm,W	;分 BCD カウンタ
		movwf	minutes		;Minutes
		movf	bcd_hh,W	;時 BCD カウンタ
		movwf	hours		;Hours

		movf	bcd_ww,W	;曜日 BCD カウンタ
		movwf	day		;Day

		movf	bcd_dd,W	;日 BCD カウンタ
		movwf	date		;Date
		movf	bcd_nn,W	;月 BCD カウンタ
		movwf	month		;Month
		movf	bcd_yy,W	;年 BCD カウンタ
		movwf	year		;Year
		return

;--------------------------------------------------------------------------

		; 変更する対象項目の LCD アドレス

;		（PCL を操作する場合はプログラムを配置する位置に配慮すること）

blk_point_table
		movf	blk_point,W
		addwf	PCL,F

		dt	h'82'		;blk_point = 0: YY
		dt	h'85'		;            1: NN
		dt	h'88'		;            2: DD
		dt	h'c2'		;            3: AM/PM
		dt	h'c5'		;            4: HH
		dt	h'c8'		;            5: MM
		dt	h'cb'		;            6: SS

;--------------------------------------------------------------------------
;		MODE / SET スイッチの処理
;--------------------------------------------------------------------------

;	現状では SET モードに移行中は、外部(RA2/INT)割り込みを禁止にするため (interrupt) は起こらないので、
;	スタック消費量の改善対策は不要ではあるが、次のようにスタックが満タンになるため、余裕を持たせるために
;	(1) のところでは、CALL を止めて GOTO で呼び出しを行っている。そのため、本ルーチンの最後のところでは
;	RETURN ではなく、同様に GOTO で呼び出し側に戻るように変更をした。

;	(main) → (mode_switch) → (date_display) → (ww_disp) → (I2CxLcd_Disp) → (I2CxLcd_Data) 
;	       (1)              (2)               (3)          (4)               (5)
;
;	       → (I2CxLcd_Out) → (i2c_byte_send) → (i2c_wait) → (interrupt)
;	       (6)              (7)                (8)          x(9)

mode_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTA,_swMOD	;再度 MODE スイッチ = ON か？
		goto	modsw09		;No

		movlw	60		;50ms x 60 = 3 秒間の監視
		movwf	lp_cnt1		;ループカウンタ

modsw01		call	wait_50ms	;50m 秒 ウエイト

		btfss	int_flg,0	;RTC DS3231 からデータ読み出し要求フラグ = ON か？	;
		goto	modsw02		;No							;
												;これらの命令がないと
		Rtc_Read_M  seconds,7	;RTC DS3231 から年月日、時分秒を読み出し		;表示が停止して違和感
		call	buffer_to_counter							;を感じたので挿入した
		call	time_display	;AM/PM 時分秒の表示					;
		bcf	int_flg,0	;RTC DS3231 からデータ読み出し要求フラグ = OFF		;
modsw02												;

		btfsc	PORTA,_swMOD	;MODEスイッチ = OFF か？
		goto	modsw03		;Yes

		decfsz	lp_cnt1,F	;ループカウンタ - 1 = 0 か？
		goto	modsw01		;No
		goto	modsw04		;Yes

		; 表示モードカウンタの更新

modsw03		incf	mod_cnt,F	;表示モードカウンタの更新
		movlw	6
		subwf	mod_cnt,W
		btfsc	STATUS,Z	;表示モードカウンタ = 6 か？
		clrf	mod_cnt		;Yes. mod_cnt = 0 にクリア
		bsf	mod_flg,7	;表示モード変更フラグ = ON
		goto	modsw09

		; SET モードに移行

modsw04		bcf	INTCON,INTE	;INTE: 外部(RA2/INT)割り込みを禁止

		movlw	h'01'		;表示クリア
		call	I2CxLcd_Cmd	;I2C LCD へコマンドを出力

;		[ ** SET MODE ** ]	;SET モードメッセージ
		Disp_I2CxLcd	h'80',set_mode_msg,1	;(１行目先頭)

		btfss	PORTA,_swSET	;MODE/SET スイッチ = OFF か？
		goto	$ - 1		;No

		call	wait_30ms	;チャッタリング吸収
		movlw	h'0d'		;表示オン／オフコントロール
		call	I2CxLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=1: ブリンク

		clrf	mod_cnt		;表示モードカウンタ = 0
		clrf	blk_point	;ブリンク位置ポインタ = 0

modsw05		bsf	mod_flg,7	;表示モード変更フラグ = ON

;		[20xx/xx/xx (xxx)]	;mod_cnt = 0
;		[  xx xx:xx:xx   ]
		call	date_display	;年月日(曜日)の表示
		call	time_display	;AM/PM 時分秒の表示

modsw06		call	blk_point_table	;変更する対象項目の LCD アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力
		clrf	chg_flg		;データ変更フラグをクリア

		; 各スイッチの入力処理

modsw07		btfss	PORTA,_swSET	;SET スイッチ = ON か？
		call	set_switch	;Yes

		btfss	PORTA,_swUP	;UP スイッチ = ON か？
		call	up_switch	;Yes

		btfss	PORTA,_swDWN	;DOWN スイッチ = ON か？
		call	down_switch	;Yes

		btfss	PORTA,_swBAK	;BACK スイッチ = ON か？
		call	back_switch	;Yes

		movlw	7
		subwf	blk_point,W
		btfsc	STATUS,Z	;終了 blk_point = 7 か？
		goto	modsw08		;Yes

		btfsc	chg_flg,0	;ブリンク位置だけの変更があった か？
		goto	modsw06		;Yes

		btfsc	chg_flg,1	;ブリンク位置のデータ変更があった か？
		goto	modsw05		;Yes
		goto	modsw07		;No

modsw08		btfss	PORTA,_swSET	;SET スイッチ = OFF か？
		goto	$ - 1		;No

		call	counter_to_buffer
		Rtc_Write_M  seconds,7	;RTC DS3231 へ年月日、時分秒を書き込み

		bsf	INTCON,INTE	;INTE: 外部(RA2/INT)割り込みを禁止解除

		movlw	h'0c'		;表示オン／オフコントロール
		call	I2CxLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク

modsw09		btfss	PORTA,_swMOD	;MODE スイッチ = OFF か？
		goto	$ - 1		;No

	;;	return			;;┐
		goto	main04		;;┘スタック消費量の改善対策

;--------------------------------------------------------------------------
;		SET スイッチの処理
;--------------------------------------------------------------------------

set_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTA,_swSET	;再度 SET スイッチ = ON か？
		goto	setsw01		;No

		bsf	chg_flg,0	;ブリンク位置だけの変更フラグ = ON
		incf	blk_point,F	;ブリンク位置ポインタ + 1

setsw01		btfss	PORTA,_swSET	;SET スイッチ = OFF か？
		goto	$ - 1		;No

		call	wait_30ms	;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		UP スイッチの処理
;--------------------------------------------------------------------------

up_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTA,_swUP	;再度 UP スイッチ = ON か？
		goto	upsw08		;No

		bsf	chg_flg,1	;ブリンク位置のデータ変更フラグ = ON
		movf	blk_point,W
		btfss	STATUS,Z	;blk_point = 0 か？
		goto	upsw01		;No

		call	bcd_yl_inc	;年 BCD カウンタのインクリメント
		goto	upsw03

upsw01		movlw	1
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 1 か？
		goto	upsw02		;No

		call	bcd_nn_inc	;月 BCD カウンタのインクリメント
		goto	upsw03

upsw02		movlw	2
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 2 か？
		goto	upsw04		;No

		call	bcd_dd_inc	;日 BCD カウンタのインクリメント

upsw03		call	day_week	;該当日の曜日を取得
		movwf	bcd_ww		;曜日 BCD カウンタ
		goto	upsw08

upsw04		movlw	3
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 3 か？
		goto	upsw05		;No

;時間表示モードフラグ:  bit1=0:24H/1:12H, bit0=0:am/1:pm

;		00: 24H	   ┌─────────────┐
;		01: x	   └→ '00' → '10' → '11' ─┘
;		10: am		'  ' → 'am' → 'pm'
;		11: pm

;		incf	time_flg,F	;
;		movlw	b'00000011'
;		andwf	time_flg,F	;下 2 ビットが有効
;		movlw	b'00000001'
;		xorwf	time_flg,W
;		btfsc	STATUS,Z	;time_flg = b'00000001' か？
;		incf	time_flg,F	;Yes
;		goto	upsw08

		movlw	b'00000010'	;（上ルーチンから変更）
		xorwf	time_flg,F
		goto	upsw08

upsw05		movlw	4
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 4 か？
		goto	upsw06		;No

		call	bcd_hh_inc	;時 BCD カウンタのインクリメント
		goto	upsw08

upsw06		movlw	5
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 5 か？
		goto	upsw07		;No

		call	bcd_mm_inc	;分 BCD カウンタのインクリメント
		goto	upsw08

upsw07	;	movlw	6
	;	subwf	blk_point,W
	;	btfss	STATUS,Z	;blk_point = 6 か？
	;	goto	upsw08		;No

		call	bcd_ss_inc	;秒 BCD カウンタのインクリメント

upsw08	;	btfss	PORTA,_swUP	;UP スイッチ = OFF か？
	;	goto	$ - 1		;No

		call	wait_200ms	;早送りの速度調整
		return

;--------------------------------------------------------------------------
;		DOWN スイッチの処理
;--------------------------------------------------------------------------

down_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTA,_swDWN	;再度 DOWN スイッチ = ON か？
		goto	dwnsw08		;No

		bsf	chg_flg,1	;ブリンク位置のデータ変更フラグ = ON
		movf	blk_point,W
		btfss	STATUS,Z	;blk_point = 0 か？
		goto	dwnsw01		;No

		call	bcd_yl_dec	;年 BCD カウンタのデクリメント
		goto	dwnsw03

dwnsw01		movlw	1
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 1 か？
		goto	dwnsw02		;No

		call	bcd_nn_dec	;月 BCD カウンタのデクリメント
		goto	dwnsw03

dwnsw02		movlw	2
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 2 か？
		goto	dwnsw04		;No

		call	bcd_dd_dec	;日 BCD カウンタのデクリメント

dwnsw03		call	day_week	;該当日の曜日を取得
		movwf	bcd_ww		;曜日 BCD カウンタ
		goto	dwnsw08

dwnsw04		movlw	3
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 3 か？
		goto	dwnsw05		;No

;時間表示モードフラグ:  bit1=0:24H/1:12H, bit0=0:am/1:pm

;		00: 24H	   ┌─────────────┐
;		01: x	   └─ '00' ← '10' ← '11' ←┘
;		10: am		'  ' ← 'am' ← 'pm'
;		11: pm

;		decf	time_flg,F	;
;		movlw	b'00000011'
;		andwf	time_flg,F	;下 2 ビットが有効
;		movlw	b'00000001'
;		xorwf	time_flg,W
;		btfsc	STATUS,Z	;time_flg = b'00000001' か？
;		decf	time_flg,F	;Yes
;		goto	dwnsw08

		movlw	b'00000010'	;（上ルーチンから変更）
		xorwf	time_flg,F
		goto	dwnsw08

dwnsw05		movlw	4
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 4 か？
		goto	dwnsw06		;No

		call	bcd_hh_dec	;時 BCD カウンタのデクリメント
		goto	dwnsw08

dwnsw06		movlw	5
		subwf	blk_point,W
		btfss	STATUS,Z	;blk_point = 5 か？
		goto	dwnsw07		;No

		call	bcd_mm_dec	;分 BCD カウンタのデクリメント
		goto	dwnsw08

dwnsw07	;	movlw	6
	;	subwf	blk_point,W
	;	btfss	STATUS,Z	;blk_point = 6 か？
	;	goto	dwnsw08		;No

		call	bcd_ss_dec	;秒 BCD カウンタのデクリメント

dwnsw08	;	btfss	PORTA,_swDWN	;DWN スイッチ = OFF か？
	;	goto	$ - 1		;No

		call	wait_200ms	;早送りの速度調整
		return

;--------------------------------------------------------------------------
;		BACK スイッチの処理
;--------------------------------------------------------------------------

back_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTA,_swBAK	;再度 BACK スイッチ = ON か？
		goto	baksw01		;No

		bsf	chg_flg,0	;ブリンク位置だけの変更フラグ = ON
		decf	blk_point,F	;ブリンク位置ポインタ - 1
		incf	blk_point,W
		btfss	STATUS,Z	;ブリンク位置ポインタ = 0 か？
		goto	baksw01		;No

		movlw	6
		movwf	blk_point	;最大値 blk_point = 6 に設定

baksw01		btfss	PORTA,_swBAK	;BACK スイッチ = OFF か？
		goto	$ - 1		;No

		call	wait_30ms	;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		UP / TIME MODE スイッチの処理
;--------------------------------------------------------------------------

tmode_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTA,_swUP	;再度 UP スイッチ = ON か？
		goto	tmodsw01	;No

		movlw	b'00000010'
		xorwf	time_flg,F	;時間表示モードフラグ bit1=0:24H/1:12H, bit0=0:am/1:pm
		bsf	mod_flg,7	;表示モード変更フラグ = ON, （強制再表示）

tmodsw01	btfss	PORTA,_swUP	;UP スイッチ = OFF か？
		goto	$ - 1		;No

		call	wait_30ms	;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		ZERO スイッチの処理
;--------------------------------------------------------------------------

zero_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTA,_swZER	;再度 ZERO スイッチ = ON か？
		goto	zersw04		;No

		movlw	h'05'
		subwf	bcd_mm,W
		btfss	STATUS,C	;分 BCD カウンタ < h'05' か？
		goto	zersw02		;Yes

		movlw	h'55'
		subwf	bcd_mm,W
		btfss	STATUS,C	;分 BCD カウンタ >= h'55' か？
		goto	zersw04		;No. 無視

		bcf	INTCON,INTE	;INTE: 外部(RA2/INT)割り込みを禁止
		call	bcd_hh_inc	;時 BCD カウンタのインクリメント
		movf	bcd_hh,W
		btfss	STATUS,Z	;時 BCD カウンタ = h'00' か？
		goto	zersw03		;No

		call	bcd_dd_inc	;日 BCD カウンタのインクリメント
		movlw	h'01'
		subwf	bcd_dd,W
		btfss	STATUS,Z	;日 BCD カウンタ = h'01' か？
		goto	zersw01		;No

		call	bcd_nn_inc	;月 BCD カウンタのインクリメント
		movlw	h'01'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月 BCD カウンタ = h'01' か？
		goto	zersw01		;No

		call	bcd_yl_inc	;年(下位2桁) BCD カウンタのインクリメント

zersw01		call	day_week	;該当日の曜日を取得
		movwf	bcd_ww		;曜日 BCD カウンタ
		goto	zersw03

zersw02		bcf	INTCON,INTE	;INTE: 外部(RA2/INT)割り込みを禁止

zersw03		clrf	bcd_mm		;分 BCD カウンタのクリア
		clrf	bcd_ss		;秒 BCD カウンタのクリア
		call	counter_to_buffer
		Rtc_Write_M  seconds,7	;RTC DS3231 へ年月日、時分秒を書き込み

		bsf	INTCON,INTE	;INTE: 外部(RA2/INT)割り込みを禁止解除
		bsf	mod_flg,7	;表示モード変更フラグ = ON, （強制再表示）

zersw04		btfss	PORTA,_swZER	;ZERO スイッチ = OFF か？
		goto	$ - 1		;No

		call	wait_30ms	;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		SIGNAL スイッチの処理
;--------------------------------------------------------------------------

;出力:		sig_flg: 時報音出力フラグ ( bit0:予報音, bit1:正報音, bit7:出力許可 )
;			 本プログラムでは bit0, bit1 のフラグは使用しない

signal_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTA,_swSIG	;再度 SIGNAL スイッチ = ON か？
		goto	sigsw03		;No

		movlw	b'10000000'
		xorwf	sig_flg,F	;時報音出力許可フラグの更新

		btfss	sig_flg,7	;時報音出力許可フラグ = ON か？
		goto	sigsw02		;No. 禁止

		movlw	3		;Yes. 許可
		movwf	lp_cnt1		;ループカウンタ

sigsw01		call	buzzer_pi	;"ピッ" ブザー音出力
		call	wait_30ms
		decfsz	lp_cnt1,F	;ループカウンタ - 1 = 0 か？
		goto	sigsw01		;No
		goto	sigsw03

sigsw02		call	buzzer_buu	;"ブー" ブザー音出力

sigsw03		btfss	PORTA,_swSIG	;SIGNAL スイッチ = OFF か？
		goto	$ - 1		;No

		call	wait_30ms	;チャッタリング吸収
		return

;==========================================================================
;	    各 BCD カウンタのインクリメント / デクリメント計算
;==========================================================================
;--------------------------------------------------------------------------
;		日 BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_dd_inc
		call	month_days	;各月の日数計算
		subwf	bcd_dd,W
		btfss	STATUS,Z	;日 BCD カウンタ = 各月の最終日 か？
		goto	ddinc01		;No

		movlw	h'01'
		movwf	bcd_dd		;日 BCD カウンタ = h'01' 設定
		goto	ddinc02

ddinc01		movlw	bcd_dd		;日 BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

ddinc02		return

;--------------------------------------------------------------------------

;		各月の日数計算

month_days
		movlw	h'02'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月 BCD カウンタ = h'02' か？
		goto	mday02		;No

		movf	bcd_yl,W	;年(下位2桁) BCD カウンタ
		movwf	cur_yl
		movf	bcd_yh,W	;年(上位2桁) BCD カウンタ
		movwf	cur_yh
		call	uruu_check	;平年／閏年の判定
		btfss	uru_flg,0	;閏年 か？
		goto	mday01		;No

		movlw	h'29'		;閏年 2月
		goto	mday04

mday01		movlw	h'28'		;平年 2月
		goto	mday04

mday02		movlw	h'04'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ = h'04' か？
		goto	mday03		;Yes

		movlw	h'06'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ = h'06' か？
		goto	mday03		;Yes

		movlw	h'09'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ = h'09' か？
		goto	mday03		;Yes

		movlw	h'11'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ = h'11' か？
		goto	mday03		;Yes

		movlw	h'31'		;h'01', h'03', h'05', h'07', h'08', h'10', h'12'
		goto	mday04

mday03		movlw	h'30'		;h'04', h'06', h'09', h'11'

mday04		return

;--------------------------------------------------------------------------

;		平年／閏年の判定

uruu_check
		clrf	uru_flg		;平年に設定

		movf	cur_yl,W	;年(下位2桁)(変) BCD カウンタ
		call	bcd2_to_binary	;BCD (2桁) からバイナリ変換
		andlw	h'03'		;下位2ビット
		btfss	STATUS,Z	;下位2ビット = b'00' か？
		goto	uru02		;No. 平年 ... 4で割れない

		movf	cur_yl,W
		btfss	STATUS,Z	;年(下位2桁)(変) BCD カウンタ = h'00' か？
		goto	uru01		;No. 閏年 ... 100で割れない

		movf	cur_yh,W	;年(上位2桁)(変) BCD カウンタ
		call	bcd2_to_binary	;BCD (2桁) からバイナリ変換
		andlw	h'03'		;下位2ビット
		btfss	STATUS,Z	;下位2ビット = b'00' か？
		goto	uru02		;No. 平年 ... 400で割れない

uru01		bsf	uru_flg,0	;閏年に設定

uru02		return

;--------------------------------------------------------------------------

;		BCD (2桁) からバイナリ変換

bcd2_to_binary
		movwf	work2		;退避
		swapf	work2,W		;上位4ビット(10位)を BCD からバイナリ変換
		andlw	h'0f'
		movwf	work1
		bcf	STATUS,C
		rlf	work1,F		;2倍
		rlf	work1,F		;4倍
		addwf	work1,F		;5倍
		rlf	work1,F		;10倍

		movf	work2,W		;下位4ビット(単位)
		andlw	h'0f'
		addwf	work1,W		;10位 + 単位 = W レジスタ
		return

;--------------------------------------------------------------------------
;		月 BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_nn_inc
		movlw	bcd_nn		;月 BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

		movlw	h'13'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月 BCD カウンタ = h'13' か？
		goto	nninc01		;No

		movlw	h'01'
		movwf	bcd_nn		;月 BCD カウンタ = h'01' 設定

nninc01		return

#ifdef comment
;--------------------------------------------------------------------------
;		年(4桁) BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_yyyy_inc
		call	bcd_yl_inc	;年(下位2桁) BCD カウンタのインクリメント
		btfss	STATUS,C	;年(下位2桁) BCD カウンタ >= 'a0' か？
		goto	yyinc01		;No

		call	bcd_yh_inc	;年(上位2桁) BCD カウンタのインクリメント
		btfss	STATUS,C	;年(上位2桁) BCD カウンタ >= 'a0' か？
		goto	yyinc01		;No

		movlw	h'01'
		movwf	bcd_yl		;9999 → (0000) → 0001

yyinc01		return
#endif

;--------------------------------------------------------------------------
;		年(下位2桁) BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_yl_inc
		movlw	bcd_yl		;年(下位2桁) BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

		movlw	h'a0'
		subwf	bcd_yl,W
		btfss	STATUS,Z	;年(下位2桁) BCD カウンタ = 'a0' か？
		goto	ylinc01		;No

		clrf	bcd_yl		;年(下位2桁) BCD カウンタ = h'00' 設定

ylinc01		return

#ifdef comment
;--------------------------------------------------------------------------
;		年(上位2桁) BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_yh_inc
		movlw	bcd_yh		;年(上位2桁) BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

		movlw	h'a0'
		subwf	bcd_yh,W
		btfss	STATUS,Z	;年(上位2桁) BCD カウンタ = 'a0' か？
		goto	yhinc01		;No

		clrf	bcd_yh		;年(上位2桁) BCD カウンタ = h'00' 設定

yhinc01		return
#endif

;--------------------------------------------------------------------------
;		日 BCD カウンタのデクリメント
;--------------------------------------------------------------------------

bcd_dd_dec
		decf	bcd_dd,F	;日 BCD カウンタ -1 更新
		btfss	STATUS,Z	;日 BCD カウンタ = h'00' か？
		goto	dddec01		;No

		call	month_days	;各月の日数計算
		movwf	bcd_dd		;日 BCD カウンタ 設定
		goto	dddec02

dddec01		movf	bcd_dd,W
		andlw	h'0f'		;下位4ビット
		sublw	h'0f'
		btfss	STATUS,Z	;下位4ビット = h'0f' か？
		goto	dddec02		;No

		movlw	h'06'
		subwf	bcd_dd,F	;日 BCD カウンタ 更新

dddec02		return

;--------------------------------------------------------------------------
;		月 BCD カウンタのデクリメント
;--------------------------------------------------------------------------

bcd_nn_dec
		decf	bcd_nn,F	;月 BCD カウンタ -1 更新
		btfss	STATUS,Z	;月 BCD カウンタ = h'00' か？
		goto	nndec01		;No

		movlw	h'12'
		goto	nndec02

nndec01		movlw	h'0f'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月 BCD カウンタ = h'0f' か？
		goto	nndec03		;No

		movlw	h'09'

nndec02		movwf	bcd_nn		;月 BCD カウンタの設定

nndec03		return

#ifdef comment
;--------------------------------------------------------------------------
;		年(4桁) BCD カウンタのデクリメント
;--------------------------------------------------------------------------

bcd_yyyy_dec
		call	bcd_yl_dec	;年(下位2桁) BCD カウンタのデクリメント
		movf	bcd_yl,W
		btfsc	STATUS,Z	;年(下位2桁) BCD カウンタ <> '00' か？
		goto	yydec01		;No
		
		movlw	h'99'
		subwf	bcd_yl,W
		btfss	STATUS,Z	;年(下位2桁) BCD カウンタ = '99' か？
		goto	yydec02		;No

		call	bcd_yh_dec	;年(上位2桁) BCD カウンタのデクリメント
		goto	yydec02

yydec01		movf	bcd_yh,W
		btfss	STATUS,Z	;年(上位2桁) BCD カウンタ = '00' か？
		goto	yydec02		;No

		movlw	h'99'
		movwf	bcd_yh
		movwf	bcd_yl		;0001 → (0000) → 9999

yydec02		return
#endif

;--------------------------------------------------------------------------
;		年(下位2桁) BCD カウンタのデクリメント
;--------------------------------------------------------------------------

bcd_yl_dec
		decf	bcd_yl,F	;年(下位2桁) BCD カウンタ -1 更新
		incf	bcd_yl,W
		btfss	STATUS,Z	;年(下位2桁) BCD カウンタ = h'ff' か？
		goto	yldec01		;No

		movlw	h'66'
		subwf	bcd_yl,F	;年(下位2桁) BCD カウンタ 更新
		goto	yldec02

yldec01		movf	bcd_yl,W
		andlw	h'0f'		;下位4ビット
		sublw	h'0f'
		btfss	STATUS,Z	;下位4ビット = h'0f' か？
		goto	yldec02		;No

		movlw	h'06'
		subwf	bcd_yl,F	;年(下位2桁) BCD カウンタ 更新

yldec02		return

#ifdef comment
;--------------------------------------------------------------------------
;		年(上位2桁) BCD カウンタのデクリメント
;--------------------------------------------------------------------------

bcd_yh_dec
		decf	bcd_yh,F	;年(上位2桁) BCD カウンタ -1 更新
		incf	bcd_yh,W
		btfss	STATUS,Z	;年(上位2桁) BCD カウンタ = h'ff' か？
		goto	yhdec01		;No

		movlw	h'66'
		subwf	bcd_yh,F	;年(上位2桁) BCD カウンタ 更新
		goto	yhdec02

yhdec01		movf	bcd_yh,W
		andlw	h'0f'		;下位4ビット
		sublw	h'0f'
		btfss	STATUS,Z	;下位4ビット = h'0f' か？
		goto	yhdec02		;No

		movlw	h'06'
		subwf	bcd_yh,F	;年(上位2桁) BCD カウンタ 更新

yhdec02		return	
#endif

;--------------------------------------------------------------------------
;		秒 BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_ss_inc
		movlw	bcd_ss		;秒 BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'60'
		subwf	bcd_ss,W
		btfsc	STATUS,C	;秒 BCD カウンタ < h'60' か？
		clrf	bcd_ss		;No. 秒 BCD カウンタのクリア
		return

;--------------------------------------------------------------------------
;		分 BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_mm_inc
		movlw	bcd_mm		;分 BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'60'
		subwf	bcd_mm,W
		btfsc	STATUS,C	;分 BCD カウンタ < h'60' か？
		clrf	bcd_mm		;No. 分 BCD カウンタのクリア
		return

;--------------------------------------------------------------------------
;		時 BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_hh_inc
		movlw	bcd_hh		;時 BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'24'
		subwf	bcd_hh,W
		btfsc	STATUS,C	;時 BCD カウンタ < h'24' か？
		clrf	bcd_hh		;No. 時 BCD カウンタのクリア
		return

;--------------------------------------------------------------------------
;		秒 BCD カウンタのデクリメント
;--------------------------------------------------------------------------

bcd_ss_dec
		movlw	bcd_ss		;秒 BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	dec_bcd		;BCDデクリメント
		movlw	h'f9'		;h'00' - h'01' - h'06'
		subwf	bcd_ss,W
		btfss	STATUS,Z	;秒 BCD カウンタ = h'f9' か？
		goto	ssdec01		;No

		movlw	h'59'
		movwf	bcd_ss		;秒 BCD カウンタ = h'59' 設定

ssdec01		return

;--------------------------------------------------------------------------
;		分 BCD カウンタのデクリメント
;--------------------------------------------------------------------------

bcd_mm_dec
		movlw	bcd_mm		;分 BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	dec_bcd		;BCDデクリメント
		movlw	h'f9'		;h'00' - h'01' - h'06'
		subwf	bcd_mm,W
		btfss	STATUS,Z	;分 BCD カウンタ = h'f9' か？
		goto	mmdec01		;No

		movlw	h'59'
		movwf	bcd_mm		;分 BCD カウンタ = h'59' 設定

mmdec01		return

;--------------------------------------------------------------------------
;		時 BCD カウンタのデクリメント
;--------------------------------------------------------------------------

bcd_hh_dec
		movlw	bcd_hh		;時 BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	dec_bcd		;BCDデクリメント
		movlw	h'f9'		;h'00' - h'01' - h'06'
		subwf	bcd_hh,W
		btfss	STATUS,Z	;時 BCD カウンタ = h'f9' か？
		goto	hhdec01		;No

		movlw	h'23'
		movwf	bcd_hh		;時 BCD カウンタ = h'23' 設定

hhdec01		return

;--------------------------------------------------------------------------

;		BCD インクリメント

inc_bcd
		incf	INDF,F		;BCD カウンタ +1 更新
		movf	INDF,W
		andlw	h'0f'		;下位4ビット
		sublw	h'0a'
		btfss	STATUS,Z	;下位4ビット = d'10' か？
		return			;No

		movlw	h'06'
		addwf	INDF,F		;下位4ビット = 0, 上位4ビット = +1
		return

;--------------------------------------------------------------------------

;		BCD デクリメント

dec_bcd
		movf	INDF,W
		andlw	h'0f'		;下位4ビット
		btfsc	STATUS,Z	;下位4ビット <> h'00' か？
		goto	dec01		;No

		decf	INDF,F		;-1 更新
		return

dec01		decf	INDF,F		;-1 更新
		movlw	h'06'
		subwf	INDF,F		;下位4ビット = 9
		return

;==========================================================================
;	    表示モードカウンタ mod_cnt 値による LCD 表示の遷移
;==========================================================================

;		mod_cnt = 0		[20xx/xx/xx (xxx)]
;					[  xx xx:xx:xx   ]

;		mod_cnt = 1		[20xx/xx/xx (xxx)]
;					[-xx.xﾟC xxx.x % ]

;		mod_cnt = 2		[  xx xx:xx:xx   ]
;					[-xx.xﾟC xxx.x % ]

;		mod_cnt = 3		[  xx xx:xx:xx   ]
;					[20xx/xx/xx (xxx)]

;		mod_cnt = 4		[-xx.xﾟC xxx.x % ]
;					[20xx/xx/xx (xxx)]

;		mod_cnt = 5		[-xx.xﾟC xxx.x % ]
;					[  xx xx:xx:xx   ]

;==========================================================================
;		年月日(曜日)を LCD（1602A）モジュールに表示
;==========================================================================

;		[20  /  /   (   )]	;年月日(曜日)の表示
;		 0123456789ABCDEF

date_display
		btfsc	mod_flg,7	;表示モード変更フラグ = ON か？
		goto	datdp01		;Yes

		movf	bcd_hh,W	;時 BCD カウンタ
		iorwf	bcd_mm,W	;分 BCD カウンタ
		iorwf	bcd_ss,W	;秒 BCD カウンタ
		btfss	STATUS,Z	;時,分,秒 BCD カウンタ = 0 か？
		goto	datdp03		;No

datdp01		movlw	2
		subwf	mod_cnt,W
		btfsc	STATUS,Z	;mod_cnt = 2 か？
		goto	datdp03		;Yes

		movlw	h'80'		;DDRAM の先頭アドレス
		btfss	STATUS,C	;mod_cnt < 2 か？
		goto	datdp02		;Yes

		movlw	5
		subwf	mod_cnt,W
		btfsc	STATUS,Z	;mod_cnt = 5 か？
		goto	datdp03		;Yes

		movlw	h'c0'		;DDRAM の先頭アドレス

datdp02		movwf	work3		;DDRAM の先頭アドレスを記憶
		call	I2CxLcd_Cmd	;LCD へコマンドを出力

;		[20  /  /   (   )]	;年月日(曜日)の表示
		Disp_I2CxLcd	0,date_temp,1	;テンプレートの表示

		; 年の表示
		movlw	h'02'		;表示位置 = h'02'
		iorwf	work3,W		;+ DDRAM の先頭アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力
		call	yy_disp		;年の表示

		; 月の表示
		movlw	'/'		;'/'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		call	nn_disp		;月の表示

		; 日の表示
		movlw	'/'		;'/'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		call	dd_disp		;日の表示

		; 曜日の表示
		movlw	h'0c'		;表示位置 = h'0c'
		iorwf	work3,W		;+ DDRAM の先頭アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力
		call	ww_disp		;曜日の表示

datdp03		return

;==========================================================================
;		AM/PM 時分秒を LCD（1602A）モジュールに表示
;==========================================================================

;		[       :  :     ]	;AM/PM 時分秒の表示
;		 0123456789ABCDEF

time_display
		movlw	1
		subwf	mod_cnt,W
		btfsc	STATUS,Z	;mod_cnt = 1 か？
		goto	timdp05		;Yes

		btfss	STATUS,C	;mod_cnt < 1 か？
		goto	timdp01		;Yes

		movlw	4
		subwf	mod_cnt,W
		btfsc	STATUS,Z	;mod_cnt = 4 か？
		goto	timdp05		;Yes

		movlw	h'80'		;DDRAM の先頭アドレス
		btfss	STATUS,C	;mod_cnt < 4 か？
		goto	timdp02		;Yes

timdp01		movlw	h'c0'		;DDRAM の先頭アドレス

timdp02		movwf	work3		;DDRAM の先頭アドレスを記憶
		btfsc	mod_flg,7	;表示モード変更フラグ = ON か？
		goto	timdp03		;Yes

		; 秒の表示
		movlw	h'0b'		;表示位置 = h'0b'
		iorwf	work3,W		;+ DDRAM の先頭アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力
		call	ss_disp		;秒の表示

		movf	bcd_ss,W	;秒 BCD カウンタ
		btfss	STATUS,Z	;秒 BCD カウンタ = h'00' か？
		goto	timdp05		;No

		; 分の表示
		movlw	h'08'		;表示位置 = h'08'
		iorwf	work3,W		;+ DDRAM の先頭アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力
		call	mm_disp		;分の表示

		movf	bcd_mm,W	;分 BCD カウンタ
		btfss	STATUS,Z	;分 BCD カウンタ = h'00' か？
		goto	timdp05		;No

		; 時の表示
		movlw	h'05'		;表示位置 = h'05'
		iorwf	work3,W		;+ DDRAM の先頭アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力
		call	hh_disp		;時の表示
		goto	timdp04		;Yes

		; 表示モードを変更したとき
timdp03		movf	work3,W
		call	I2CxLcd_Cmd	;LCD へコマンドを出力

;		[       :  :     ]	;AM/PM 時分秒の表示
		Disp_I2CxLcd	0,time_temp,1	;テンプレートの表示

		; 時の表示
		movlw	h'05'		;表示位置 = h'05'
		iorwf	work3,W		;+ DDRAM の先頭アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力
		call	hh_disp		;時の表示

		; 分の表示
		movlw	':'		;':'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		call	mm_disp		;分の表示

		; 秒の表示
		movlw	':'		;':'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		call	ss_disp		;秒の表示

		; AM/PM の表示
timdp04		movlw	h'02'		;表示位置 = h'02'
		iorwf	work3,W		;+ DDRAM の先頭アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力
		call	ampm_disp	;AM/PM の表示

timdp05		return

;--------------------------------------------------------------------------

		; 年の表示
yy_disp
		swapf	bcd_yy,W	;10 Year
		andlw	h'0f'		;
		iorlw	h'30'		;'0'～'9'
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movf	bcd_yy,W	;Year
		andlw	h'0f'		;
		iorlw	h'30'		;'0'～'9'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		return

;--------------------------------------------------------------------------

		; 月の表示
nn_disp
		swapf	bcd_nn,W	;10 Month
		andlw	h'01'		;
		iorlw	h'30'		;'0'～'1'
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movf	bcd_nn,W	;Month
		andlw	h'0f'		;
		iorlw	h'30'		;'0'～'9'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		return

;--------------------------------------------------------------------------

		; 日の表示
dd_disp
		swapf	bcd_dd,W	;10 Date
		andlw	h'03'		;
		iorlw	h'30'		;'0'～'3'
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movf	bcd_dd,W	;Date
		andlw	h'0f'		;
		iorlw	h'30'		;'0'～'9'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		return

;--------------------------------------------------------------------------

		; 曜日の表示
ww_disp
		movlw	high week_table	;テーブルデータの先頭 high アドレス
		movwf	lcd_addr_high	;
		movlw	low week_table	;テーブルデータの先頭 low アドレス
		movwf	lcd_addr_low	;

		decf	bcd_ww,W	;Day, 1～7 → 0～6 に変換
		movwf	work2
		bcf	STATUS,C	;C = 0
		rlf	work2,F		;
		rlf	work2,W		;x 4 倍
		addwf	lcd_addr_low,F	;読み出すデータの low アドレスの更新
		btfsc	STATUS,C	;オーバーフローした場合は
		incf	lcd_addr_high,F	;読み出すデータの high アドレスの更新

		call	I2CxLcd_Disp	;LCD へ文字列データを出力
		return

		; 曜日 データテーブル
week_table
		dt	"SUN",0		;Day = 1
		dt	"MON",0		;      2
		dt	"TUE",0		;      3
		dt	"WED",0		;      4
		dt	"THU",0		;      5
		dt	"FRI",0		;      6
		dt	"SAT",0		;      7

;--------------------------------------------------------------------------

		; AM/PM の表示
ampm_disp
		btfss	time_flg,1	;時間表示モードフラグ.bit1=1: 12/24 = 1(12) か？
		goto	apmdp03		;No

		btfsc	time_flg,0	;時間表示モードフラグ.bit0=0: AM/PM = 0(AM) か？
		goto	apmdp01		;No

		movlw	'A'		;'A'
		goto	apmdp02

apmdp01		movlw	'P'		;'P'

apmdp02		call	I2CxLcd_Data	;LCD へデータを１文字出力
		movlw	'M'		;'M'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		goto	apmdp04

apmdp03		movlw	' '		;' '
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		movlw	' '		;' '
		call	I2CxLcd_Data	;LCD へデータを１文字出力

apmdp04		return

;--------------------------------------------------------------------------

		; 時の表示
hh_disp
		movf	bcd_hh,W	;時 BCD カウンタ
		movwf	temp_hh		;仮の時 BCD カウンタ
		btfsc	time_flg,1	;時間表示モードフラグ.bit1=1: 12/24 = 1(12) か？
		call	cnv_24to12	;Yes. 24時間表示を12時間表示に変換

		swapf	temp_hh,W	;10 Hours
		andlw	h'03'		;
		btfss	STATUS,Z	;10 Hours = 0 か？
		goto	hhdp01		;No

		btfss	time_flg,1	;時間表示モードフラグ.bit1=1: 12/24 = 1(12) か？
		goto	hhdp01		;No

		movlw	' '		;' ' ゼロサプレス
		goto	hhdp02

hhdp01		iorlw	h'30'		;'0'～'2'

hhdp02		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movf	temp_hh,W	;Hours
		andlw	h'0f'		;
		iorlw	h'30'		;'0'～'9'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		return

;--------------------------------------------------------------------------

		; 分の表示
mm_disp
		swapf	bcd_mm,W	;10 Minutes
		andlw	h'07'		;
		iorlw	h'30'		;'0'～'5'
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movf	bcd_mm,W	;Minutes
		andlw	h'0f'		;
		iorlw	h'30'		;'0'～'9'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		return

;--------------------------------------------------------------------------

		; 秒の表示
ss_disp
		swapf	bcd_ss,W	;10 Seconds
		andlw	h'07'		;
		iorlw	h'30'		;'0'～'5'
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movf	bcd_ss,W	;Seconds
		andlw	h'0f'		;
		iorlw	h'30'		;'0'～'9'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		return

;--------------------------------------------------------------------------
;		24時間表示を12時間表示に変換
;--------------------------------------------------------------------------

;(24H) 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
;(12H) 12  1  2  3  4  5  6  7  8  9 10 11 12  1  2  3  4  5  6  7  8  9 10 11
;      am am am am am am am am am am am am pm pm pm pm pm pm pm pm pm pm pm pm
;                                          -----------------------------------
;     +12                                 -12
;    ( 12 ef f0 f1 f2 f3 f4 f5 f6 f7 fe ff 00 01 02 03 04 05 06 07 0e 0f 10 11 )

cnv_24to12
		; (am)
		bcf	time_flg,0	;時間表示モードフラグ.bit0=0: am に設定

		movf	temp_hh,W
		btfss	STATUS,Z	;仮の時 BCD カウンタ = h'00' か？
		goto	cnv01		;No

		movlw	h'12'
		movwf	temp_hh		;仮の時 BCD カウンタ temp_hh = h'12'
		goto	cnv02

cnv01		movlw	h'12'
		subwf	temp_hh,W
		btfss	STATUS,C	;仮の時 BCD カウンタ < h'12' か？
		goto	cnv02		;Yes

		; (pm)
		bsf	time_flg,0	;時間表示モードフラグ.bit0=1: pm に設定

		btfsc	STATUS,Z	;仮の時 BCD カウンタ = h'12' か？
		goto	cnv02		;Yes

		movwf	temp_hh		;仮の時 BCD カウンタ temp_hh = temp_hh - 12
		movlw	h'0e'
		subwf	temp_hh,W
		btfss	STATUS,C	;仮の時 BCD カウンタ < h'0e' か？
		goto	cnv02		;Yes

		movlw	h'10'
		subwf	temp_hh,W
		btfsc	STATUS,C	;仮の時 BCD カウンタ < h'10' か？
		goto	cnv02		;No

		movlw	h'06'
		subwf	temp_hh,F	;補正

cnv02		return

;==========================================================================
;		温度、湿度を LCD（1602A）モジュールに表示
;==========================================================================

;#define		_debug

;		[   . ﾟC    .  % ]	;温度、湿度の表示
;		 0123456789ABCDEF

tmp_hum_display
		movf	mod_cnt,W
		btfsc	STATUS,Z	;mod_cnt = 0 か？
		goto	th_dp10		;Yes

		movlw	3
		subwf	mod_cnt,W
		btfsc	STATUS,Z	;mod_cnt = 3 か？
		goto	th_dp10		;Yes

		movlw	h'80'		;DDRAM の先頭アドレス
		btfss	STATUS,C	;mod_cnt < 3 か？
		movlw	h'c0'		;Yes. DDRAM の先頭アドレス

		movwf	work3		;DDRAM の先頭アドレスを記憶
		call	I2CxLcd_Cmd	;LCD へコマンドを出力

#ifdef _debug	;;;;;;;;;;

	call	test_disp
	return

#endif		;;;;;;;;;;

		btfsc	time_cnt,7	;タイムアウトエラー か？
		goto	th_dp07		;Yes

		btfsc	time_cnt,6	;チェックサム(CRC)エラー か？
		goto	th_dp08		;Yes
;;
		btfsc	mod_flg,7	;表示モード変更フラグ = ON か？
		goto	th_dp01		;Yes

		; 前回温度と同値かの判定
		movf	temperature_l,W	;
		subwf	m_temp_l,W
		btfss	STATUS,Z	;temperature_l = m_temp_l か？
		goto	th_dp02		;No

		movf	temperature_h,W	;
		subwf	m_temp_h,W
		btfss	STATUS,Z	;temperature_h = m_temp_h か？
		goto	th_dp02		;No
		goto	th_dp03		;Yes

;		[   . ﾟC    .  % ]	;温度、湿度の表示
th_dp01		Disp_I2CxLcd	0,tmp_hum_temp,1	;テンプレートの表示

		movf	work3,W		;
		call	I2CxLcd_Cmd	;LCD へコマンドを出力

		; 温度の表示
th_dp02		movlw	' '
		btfsc	temperature_h,7	;マイナスの温度 か？
		movlw	'-'		;Yes
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movf	temperature_h,W	;温度上位 8 bit
		movwf	m_temp_h	;今回値を記憶
		andlw	h'7f'
		movwf	data_h
		movf	temperature_l,W	;温度下位 8 bit
		movwf	m_temp_l	;今回値を記憶
		movwf	data_l
		call	bindec16c_cnv	;16 ビット数値を 10進数 5桁の文字列に変換

		movlw	'0'
		subwf	buff2,W
		movlw	' '
		btfss	STATUS,Z	;buff2 = '0' か？
		movf	buff2,W		;No
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movf	buff3,W		;
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		movlw	'.'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		movf	buff4,W		;
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		btfsc	mod_flg,7	;表示モード変更フラグ = ON か？
		goto	th_dp04		;Yes

		; 前回湿度と同値かの判定
th_dp03		movf	humidity_l,W	;
		subwf	m_humi_l,W
		btfss	STATUS,Z	;temperature_l = m_temp_l か？
		goto	th_dp04		;No

		movf	humidity_h,W	;
		subwf	m_humi_h,W
		btfsc	STATUS,Z	;temperature_h = m_temp_h か？
		goto	th_dp10		;Yes

		; 湿度の表示
th_dp04		movlw	h'08'		;表示位置 = h'08'
		iorwf	work3,W		;+ DDRAM の先頭アドレス
		call	I2CxLcd_Cmd	;LCD へコマンドを出力

		movf	humidity_h,W	;湿度上位 8 bit
		movwf	m_humi_h	;今回値を記憶
		movwf	data_h
		movf	humidity_l,W	;湿度下位 8 bit
		movwf	m_humi_l	;今回値を記憶
		movwf	data_l
		call	bindec16c_cnv	;16 ビット数値を 10進数 5桁の文字列に変換

		movlw	'0'
		subwf	buff1,W
		btfss	STATUS,Z	;buff1 = '0' か？
		goto	th_dp05		;No

		movlw	' '
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		movlw	'0'
		subwf	buff2,W
		movlw	' '
		btfss	STATUS,Z	;buff2 = '0' か？
		movf	buff2,W		;No
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		goto	th_dp06

th_dp05		movf	buff1,W		;
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		movf	buff2,W		;
		call	I2CxLcd_Data	;LCD へデータを１文字出力

th_dp06		movf	buff3,W		;
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		movlw	'.'
		call	I2CxLcd_Data	;LCD へデータを１文字出力
		movf	buff4,W		;
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		btfsc	mod_flg,6	;エラー表示の記憶フラグ = ON か？
		clrf	mod_flg		;Yes. bit7,6 をクリア
		goto	th_dp10

		; エラーの表示
th_dp07	;	[DHT22 Time Out! ]	;タイムアウトエラー
		Disp_I2CxLcd	0,timout_err,1	;
		goto	th_dp09

th_dp08	;	[DHT22 CRC Error!]	;チェックサム(CRC)エラー
		Disp_I2CxLcd	0,crc_err,1	;

th_dp09		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		bsf	mod_flg,6	;エラー表示の記憶フラグ = ON

th_dp10		return

;==========================================================================

		org	h'0600'		;MPLAB IDE v8.92 のリンクエラー対策

;--------------------------------------------------------------------------
;		16 ビット数値を 10進数 5桁の文字列に変換
;--------------------------------------------------------------------------

		;	(data_h,data_l): 変換する 16 ビット数値
		;	work1: ワーク

bindec16c_cnv
		movlw	buff + 4	;変換文字列の格納エリア
		movwf	FSR		;間接アドレスの設定
		call	bd16c		;(04) 最下位変換
		call	bd16c		;(03)
		call	bd16c		;(02)
		call	bd16c		;(01)
		call	bd16c		;(00) 最上位変換
		return

		; ÷10（10で除算）
bd16c
		movlw	16		;16ビット繰り返し
		movwf	lp_cnt1		;ループカウンタに設定
		clrf	work1

bd16c01		bcf	STATUS,C	;キャリフラグのクリア
		rlf	data_l,F
		rlf	data_h,F
		rlf	work1,F
		movlw	-10		;-10 = h'f6'
		addwf	work1,W
		btfss	STATUS,C	;C = 1 か？
		goto	bd16c02		;No

		movwf	work1		;
		incf	data_l,F	;

bd16c02		decfsz	lp_cnt1,F	;ループカウンタ - 1 = 0 か？
		goto	bd16c01		;No

		movf	work1,W		;余り
		iorlw	h'30'
		movwf	INDF		;文字コードに変換
		decf	FSR,F		;間接アドレスの更新
		return

;==========================================================================
;		（ デバッグ用 ）
;==========================================================================

#ifdef _debug

		; レジスタ内容の表示
test_disp
		movlw	humidity_h
		movwf	FSR		;間接アドレスに設定
		movlw	4
		movwf	lp_cnt1		;ループカウンタ

tdsp01		movf	INDF,W
		call	lcd_hex_out
		incf	FSR,F		;間接アドレスの更新
		movlw	' '
		call	I2CxLcd_Data	;LCD へデータを１文字出力

		decfsz	lp_cnt1,F	;ループカウンタ - 1 = 0 か？
		goto	tdsp01

		movf	work2,W		;受信データ 1 バイト, チェックサム
		call	lcd_hex_out

		return

;--------------------------------------------------------------------------

#define		cnvtmp	buff
#define		hextmp	buff + 1

		; １バイト変換 (BIN → HEX 文字) ２文字 LCD 出力
lcd_hex_out
		movwf	cnvtmp		;変換データの一時保存
		swapf	cnvtmp,W
		andlw	h'0f'
		call	hex_conv	;上位４ビットの変換
		call	I2CxLcd_Data	;I2C LCD へデータを１文字出力

		movlw	h'0f'
		andwf	cnvtmp,W
		call	hex_conv	;下位４ビットの変換
		call	I2CxLcd_Data	;I2C LCD へデータを１文字出力
		return

		; ４ビット変換 (BIN → HEX 文字)
hex_conv
		movwf	hextmp
		sublw	h'0a'
		btfsc	STATUS,Z	;
		goto	hcnv01		;W = h'0a' 

		btfss	STATUS,C	;
		goto	hcnv01		;W > h'0a' 

		movlw	h'30'		;0 ～ 9
		goto	hcnv02

hcnv01		movlw	h'40' - 9	;A ～ F

hcnv02		addwf	hextmp,W
		return

#endif

;--------------------------------------------------------------------------
;		該当日の曜日を取得
;--------------------------------------------------------------------------

; 入力:		bcd_yh: 年(上位2桁)_BCD カウンタ, bcd_yl: 年(下位2桁)_BCD カウンタ,
;		bcd_nn: 月_BCD カウンタ, bcd_dd: 日_BCD カウンタ

; 出力:		cur_week: ( 0:日, 1:月, 2:火, 3:水, 4:木, 5:金, 6:土 )
;  (+1して出力)	cur_week: ( 1:日, 2:月, 3:火, 4:水, 5:木, 6:金, 7:土 )

; ワーク:	cur_yh, cur_yl, xxx_yh, work2
; call:		bcd2_to_binary, uruu_check, inc_bcd, month_day2

day_week
		movlw	h'01'
		movwf	cur_yl		;西暦元年 = '0001' とする
		clrf	cur_yh		;

		movlw	h'01'
		movwf	cur_week	;初期設定 (西暦元年1月1日 = 月曜日 とする)

		; 年の変換 (400年後毎の同月同日は同じ曜日)

		movf	bcd_yh,W	;年(上位2桁)_BCD カウンタ
		call	bcd2_to_binary	;バイナリ変換
		movwf	xxx_yh		;
					;
dweek01		movlw	4		;
		subwf	xxx_yh,W	;
		btfss	STATUS,C	;xxx_yh < 4 か？
		goto	dweek03		;Yes
					;
		btfss	STATUS,Z	;xxx_yh = 4 か？
		goto	dweek02		;No
					;
		movf	bcd_yl,W	;
		btfsc	STATUS,Z	;bcd_yl = 0 か？
		goto	dweek03		;Yes
					;
dweek02		movlw	4		;
		subwf	xxx_yh,F	;
		goto	dweek01		;

		; 年の計算

dweek03		movf	bcd_yl,W	;年(下位2桁)_BCD カウンタ
		subwf	cur_yl,W
		btfss	STATUS,Z	;cur_yl = bcd_yl か？
		goto	dweek04		;No

		movf	xxx_yh,W	;xxx_yh =< 4 (400年以下に変換)
		subwf	cur_yh,W
		btfsc	STATUS,Z	;cur_yh = xxx_yh か？
		goto	dweek05		;Yes

dweek04		movlw	365 % 7		;365 % 7 = 365 - 7 * 52 = 1
		addwf	cur_week,F
		call	uruu_check	;平年／閏年の判定
		btfsc	uru_flg,0	;平年 か？
		incf	cur_week,F	;No. 閏年

		movlw	7
		subwf	cur_week,W
		btfsc	STATUS,C	;cur_week < 7 か？
		movwf	cur_week	;No

		movlw	cur_yl		;年(下位2桁)(変) BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

		movlw	h'a0'
		subwf	cur_yl,W
		btfss	STATUS,Z	;年(下位2桁)(変) BCD カウンタ = h'a0' か？
		goto	dweek03		;No

		clrf	cur_yl		;年(下位2桁)(変) BCD カウンタ = h'00' 設定

		movlw	cur_yh		;年(上位2桁)(変) BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント
		goto	dweek03

		; 月の計算

dweek05		movlw	h'01'
		movwf	cur_nn		;月(変) BCD カウンタ

dweek06		movf	bcd_nn,W	;月_BCD カウンタ
		subwf	cur_nn,W
		btfsc	STATUS,Z	;cur_nn = bcd_nn か？
		goto	dweek08		;Yes

		movf	cur_nn,W
		call	bcd2_to_binary	;BCD (2桁) からバイナリ変換
		movwf	work2		;退避
		call	month_day2	;月データのテーブル読み出し	;;;;;
		addwf	cur_week,F
		movlw	h'02'
		subwf	cur_nn,W
		btfss	STATUS,Z	;cur_nn = 2 か？
		goto	dweek07		;No

		call	uruu_check	;平年／閏年の判定
		btfsc	uru_flg,0	;平年 か？
		incf	cur_week,F	;No. 閏年

dweek07		movlw	7
		subwf	cur_week,W
		btfsc	STATUS,C	;cur_week < 7 か？
		movwf	cur_week	;No

		movlw	cur_nn		;月(変) BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント
		goto	dweek06

		; 日の計算

dweek08		movf	bcd_dd,W	;日_BCD カウンタ
		call	bcd2_to_binary	;BCD (2桁) からバイナリ変換
		addwf	cur_week,F
		decf	cur_week,F	;-1（当日分）

dweek09		movlw	7
		subwf	cur_week,W
		btfss	STATUS,C	;cur_week < 7 か？
		goto	dweek10		;Yes

		movwf	cur_week	;No
		goto	dweek09

dweek10		incf	cur_week,F	;0～6 → 1～7 に変換

		movf	cur_week,W	;;
		return

;--------------------------------------------------------------------------

month_day2
		decf	work2,W
		addwf	PCL,F		;プログラム・カウンタに加算

day_tbl		retlw	31 % 7		; 1:  31 % 7 = 3
		retlw	28 % 7		; 2:  28 % 7 = 0
		retlw	31 % 7		; 3:  31 % 7 = 3
		retlw	30 % 7		; 4:  30 % 7 = 2
		retlw	31 % 7		; 5:  31 % 7 = 3
		retlw	30 % 7		; 6:  30 % 7 = 2
		retlw	31 % 7		; 7:  31 % 7 = 3
		retlw	31 % 7		; 8:  31 % 7 = 3
		retlw	30 % 7		; 9:  30 % 7 = 2
		retlw	31 % 7		;10:  31 % 7 = 3
		retlw	30 % 7		;11:  30 % 7 = 2
;		retlw	31 % 7		;12:  31 % 7 = 3  (使用しない)

;==========================================================================
;		時報音出力コントロール
;==========================================================================

;  NHKの時報は、1000ミリ秒以上の無音、予報音3回、正報音1回、1000ミリ秒以上の無音という構成になっている。 
;  予報音は、一定音量の440Hzの正弦波を100ミリ秒発振させ、その後900ミリ秒の無音を置く。
;  これを1セットとして、正時の3秒前から3回繰り返している。
;  正報音は、880Hzの正弦波を発振させ、1000ミリ秒間一定の音量に保ち、次の2000ミリ秒で減衰させている。
;  出典: フリー百科事典『ウィキペディア（Wikipedia）』 ( http://ja.wikipedia.org/wiki/%E6%99%82%E5%A0%B1 )

;		時報音出力コントロール	

time_signal
		btfss	sig_flg,7	;時報音出力許可フラグ = ON か？
		goto	ts102		;No

		movlw	h'59'
		subwf	bcd_mm,W	;分 BCD カウンタ
		btfss	STATUS,Z	;bcd_mm = h'59' か？
		goto	ts101		;No

		movlw	h'57'
		subwf	bcd_ss,W	;秒 BCD カウンタ
		btfss	STATUS,C	;bcd_ss >= h'57' か？
		goto	ts101		;No

		; "プッ"		;予報音 (440Hz)
		call	buzzer_pu	;"プッ"
;		bsf	sig_flg,0	;予報音フラグのセット ... 本プログラムではフラグは使用しない
		goto	ts102

ts101		movf	bcd_ss,W
		iorwf	bcd_mm,W
		btfss	STATUS,Z	;bcd_ss = bcd_mm = h'00' か？
		goto	ts102		;No

		; "ポッ～～ン"		;正報音 (880Hz)
		call	buzzer_poon	;"ポッ～～ン"
;		bsf	sig_flg,1	;正報音フラグのセット ... 本プログラムではフラグは使用しない

ts102		return

;==========================================================================
;		アラーム（ブザー）音出力ルーチン
;==========================================================================

		; 時報予報音 "プッ" ブザー音出力 (100 mS)
buzzer_pu
		Sound_M		f_ra, 100
		return

		; 時報正報音 "ポッ～～ン" ブザー音出力 (1000 mS)
buzzer_poon
		call	buzzer_po_1_4
		call	buzzer_po_1_4
		call	buzzer_po_1_4

		; "ポッ～～ン" 1/4 ブザー音出力
buzzer_po_1_4
		Sound_M		f_rah, 250
		return

		; "ピッ" ブザー音出力
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

		; ブザー音出力コントロール
buzzer_control
		bsf	STATUS,RP0	;バンク 1
		bsf	PIE1,TMR1IE	;タイマー１割り込みを許可
		bcf	STATUS,RP0	;バンク 0

		call	wait_xxms	;入力 W: 音長（ループカウンタ）

		bsf	STATUS,RP0	;バンク 1
		bcf	PIE1,TMR1IE	;タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0
		return

;==========================================================================
;		ウェイト・ルーチン (8 MHz)
;==========================================================================

		; 10μ秒 ウェイトルーチン
wait_10us
		movlw	4		;1
		movwf	wt1cnt		;1
wu03		nop			;1
		decfsz	wt1cnt,F	;1,2
		goto	wu03		;2,0	1+1+(1+1+2)*3+(1+2+0)=17
		nop			;1
		return			;2	17+1+2=20
					;Total	20/8MHz*4 = 10 μS

		; 40μ秒 ウェイトルーチン
wait_40us
		movlw	15		;1
		movwf	wt1cnt		;1
wu01		goto	$+1		;2
		decfsz	wt1cnt,F	;1,2
		goto	wu01		;2,0	1+1+(2+1+2)*14+(2+2+0)=76
		goto	$+1		;2
		return			;2	76+2+2=80
					;Total	80/8MHz*4 = 40 μS

		; 100μ秒 ウェイトルーチン
wait_100us
		movlw	39		;1
		movwf	wt1cnt		;1
wu02		goto	$+1		;2
		decfsz	wt1cnt,F	;1,2
		goto	wu02		;2,0	1+1+(2+1+2)*38+(2+2+0)=196
		goto	$+1		;2
		return			;2	196+2+2=200
					;Total	200/8MHz*4 = 100 μS = 0.1 mS

		; 30m 秒 ウェイトルーチン
wait_30ms
		movlw	30
		goto	wait_xxms

		; 50m 秒 ウエイト
wait_50ms
		movlw	50
		goto	wait_xxms

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100
		goto	wait_xxms

		; 200m 秒 ウェイトルーチン
wait_200ms
		movlw	200
		goto	wait_xxms

		; 1m 秒 ウェイトルーチン
wait_1ms
		movlw	1

		; xx m 秒（ 1m 秒 x W ）ウェイトルーチン
wait_xxms
		movwf	wt2cnt		;1

w1m01		movlw	221		;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)*220+(2+2+2+2+0)=1988

		nop			;1
		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt2cnt,F	;1,2
		goto	w1m01		;2,0	(1+1+1988+1+2+2+1+2)*(W-1)+(1+1+1988+1+2+2+2+0)=1998*W-1

		return			;2	1+(1998*W-1)+2=1998*W+2
					;Total	(1998*W+2)/8MHz*4 = (999*W + 1) μS

		; 1 秒 ウェイトルーチン
wait_1sec
		movlw	10
w1s01		movwf	wt3cnt

w1s02		call	wait_100ms
		decfsz	wt3cnt,F
		goto	w1s02
		return

;==========================================================================
;		割り込み処理
;==========================================================================

interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		swapf	STATUS,W
		movwf	s_save		;STATUS レジスタの保存
		movf	FSR,W
		movwf	f_save		;FSR レジスタの保存

		bcf	STATUS,RP0	;バンク 0
		btfsc	INTCON,INTF	;外部(RA2/INT)割り込み か？
		goto	ra2_int		;Yes

		btfsc	PIR1,TMR1IF	;タイマー１割り込み か？
		goto	t1_int		;Yes
		goto	int_end		;(Illegal interrupt)

;---------------- 外部(RA2/INT)割り込み処理 -------------------------------

ra2_int		bcf	INTCON,INTF	;外部(RA2/INT)割り込みフラグをクリア
		bsf	int_flg,0	;bit0: RTC DS3231 から年月日、時分秒の読み出し要求フラグ = ON
		movlw	b'00000010'
	;;	xorwf	int_flg,F	;bit1: DHT22 から温度、湿度の読み出し要求フラグ = ON/OFF, （変更）*
		addwf	int_flg,F	;bit1-2: 4 秒カウンタ
					;bit3: DHT22 から温度、湿度の読み出し要求フラグ = ON
		goto	int_end

;---------------- タイマー１割り込み処理 ----------------------------------

t1_int		bcf	PIR1,TMR1IF	;タイマー１割込みフラグをクリア

		movf	const_high,W	;音階用分周定数 high を
		movwf	TMR1H		;TMR1H に設定
		movf	const_low,W	;音階用分周定数 low を
		movwf	TMR1L		;TMR1L に設定

		movlw	1 << _BZ	;対象ビットをセット
		xorwf	PORTC,F		;出力をビット反転
;		goto	int_end

		; レジスタの復帰

int_end		movf	f_save,W
		movwf	FSR		;FSR レジスタの復帰
		swapf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'2100'

eep_st		de	"Copyright (C) 2020-2021 by M.Yamamoto"

;==========================================================================

		end			;プログラムの終了
