;***** PerpetualCalendarIII.asm *******************************************
;
;	有機 EL ディスプレイ(OLED) 表示 万年カレンダー III
;
;	Copyright (C) 2024-2025   by M.Yamamoto. All rights reserved.
;
;	Homepage URL: https://xyama.sakura.ne.jp/hp/PerpetualCalendarIII.html
;
;     ( coding: Ver.0.00 2024/11/17  by M.Yamamoto )
;	coding: Ver.1.00 2025/01/09  初期バージョン
;	update: Ver.1.01 2025/01/14  SETモード時の全該当項目のブリンク表示
;	update: Ver.1.02 2025/01/16  スクリーン関連サブルーチンを Page 1 に移動
;	update: Ver.1.03 2025/01/22  メインルーチンでの24/12時間表示の切り替え,
;			             メンテナンス２機能の追加
;	update: Ver.1.04 2025/01/27  冒頭コメント<機能概要と使用法>の修正
;	update: Ver.1.05 2025/01/28  スリープモード中も時報音を出力に変更
;	update: Ver.2.00 2025/02/18  ハードウエアの変更（II→III）
;	update: Ver.2.01 2025/02/25  電圧計機能の追加（メンテナンス機能内）
;	update: Ver.2.02 2025/03/08  SETモード時のUP,DOWNスイッチ処理の変更
;	update: Ver.2.03 2025/03/27  タイマー機能の追加
;	update: Ver.2.04 2025/04/01  冒頭コメント<機能概要と使用法>の修正
;	update: Ver.2.05 2025/04/24  電圧計機能の追加-2（ウエイクアップ直後）
;	update: Ver.2.06 2025/04/28  フラッシュメモリへ書き込み処理の変更
;	update: Ver.2.07 2025/05/11  小バグ等の吸収と各種調整
;	bugfix: Ver.2.08 2025/05/17  timer_memory_monitor内でFSR1の退避忘れ
;
;******************************************************* PicAsm 0270 ******

;	Device: PIC16F1705	Clock: 8MHz (Internal OSC)

#ifdef comment

　プログラム中のこの文章説明だけでは、その機能等を理解するのが少々難しいと思われるため、次のホームページ上で、
　多くの写真を加えた説明を用意したので、そちらをご覧いただきたい。

	ＵＲＬ： https://xyama.sakura.ne.jp/hp/PerpetualCalendarIII.html#usage

　また、このファイル（PerpetualCalendarIII.asm）はテキストファイルであるが、メモ帳ではファイル中で使用している
　罫線（コメントで使用）の表示処理がうまくできず、見た目がぐちゃぐちゃになる。ただし、現時点（2025/01/24）に
　おいては Microsoft Edge 131.0.2903.112 では、問題なく表示ができるのでドラッグ＆ドロップして同ブラウザで見る
　ことをお勧めする。

 ==================
 <機能概要と使用法>
 ==================

・本機では携帯使用をするために、電源には 18650 リチウムイオン電池を採用している。そして、リアルタイムクロック
　（RTC）モジュールを搭載（バックアップ用のバッテリーも搭載）してあるため、リチウムイオン電池の消耗などで電源
　が切れたときはもちろん、本機の不使用時の長時間の電源断にも、安定した時刻の継続が期待できる。

・また、本機には 18650 リチウムイオン電池のための充電機能も内蔵しているので、USB コネクタから + 5 V 電源を供
　給すれば電池を充電することも可能である。ただし、本機では充電中には本機の電源スイッチを切っておく必要があり、
　充電しながらの連続使用はできない。

---------------------
◎ 本機の起動時の動作
---------------------

・さて、本機の電源スイッチを ON にすると、"ピポッ" と開始ブザー音を出力後、プログラムのタイトル、およびバージ
　ョン番号などの表示とともに、有機 EL ディスプレイ(OLED) のデモ表示が数 10 秒間行われる。

			 Perpetual Calendar
			   (OLED Edition)
			    Version x.xx
			    by m.yamamoto

・ただし、このデモ表示だけで約 20 秒ほどを要するため、DOWN スイッチと UP スイッチを同時に押しながら電源を投入
　すると、デモ表示だけを省略することができる。

・ディスプレイ(OLED) のデモ表示が終了すると、PIC のフラッシュメモリ (High-Endurance) に記憶されている、各種の
　引き継ぎ情報を RAM バッファ、および各種変数へ読み出す。

・その後、リアルタイムクロック（RTC）モジュールの状態がチェックされ、初めて電源を入れたときや、バックアップ用
　バッテリーが異常なとき等に、次のエラーメッセージがディスプレイ(OLED) 画面に表示されるとともに、"ブッブー" 
　ブザー音が出力される。 

			 DS3231 Error !
			         Init ? _

・なお、このときディスプレイ(OLED) 画面では "Init ? " の後 "_" の部分がブリンク表示されているが、これはリアル
　タイムクロック（RTC）モジュールの初期設定をするかどうかを、ユーザに応答を求めていることを表している。ユーザ
　はバックアップ用バッテリーの状態等を確認してその対処を行った後、この場合には６個のスイッチの内のどれかを押
　して応答をする。

・すると、リアルタイムクロック（RTC）モジュールの初期設定を行った後、再度リアルタイムクロック（RTC）モジュー
　ルの状態がチェックされ、なおも NG であれば同様にエラーメッセージの表示が繰り返されるが、OK であれば時計機能
　が開始され、ディスプレイ(OLED) 画面は、時間表示とともにカレンダー表示に切り替わる。このとき表示される画面を 
　NORMAL モード という。 

-------------------------
◎ 基本機能とスイッチ操作
-------------------------
			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │●│   │●│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

		MODE スイッチ        ..... NORMAL モード / LARGE モードの切り替え

		MODE スイッチ 長押し ..... SET モードに移行（３秒以上の長押し）
		(SET スイッチ)

		  UP スイッチ        ..... カレンダーめくり機能（１か月前に進める）
					 （ LARGE モード中は無視）

		  UP スイッチ 長押し ..... 24時間表示 / 12時間表示の切り替え（３秒以上の長押し）
	      (TMODE スイッチ)

		DOWN スイッチ        ..... カレンダーめくり機能（１か月後に進める）
					 （ LARGE モード中は無視）

		DOWN スイッチ 長押し ..... メンテナンス機能に移行（３秒以上の長押し）
	     (MAINTE スイッチ)		 （カレンダーめくり機能中はカレンダーめくり機能）

		ZERO スイッチ        ..... 毎正時プラス・マイナス５分以内を 00分00秒に設定
					 （５分以外では無視）

	       TIMER スイッチ        ..... タイマーメモリの読み出しと消去

	       TIMER スイッチ 長押し ..... タイマーメモリの設定（３秒以上の長押し）
	      (TMSET スイッチ)

	      SIGNAL スイッチ        ..... 毎時の時報音出力を ON/OFF 制御

・初めて本機に電源を投入すると、カレンダーおよび時間は "2025/01/01"、"00:00:00" と、本機をプログラミングした
　ときの設定値から始まって表示をするため、後述の「SET モード機能とスイッチ操作」手順で現在の年月日、時分秒に
　設定をし直す必要がある。

・なお、本機には上図のように操作をするための押しボタンスイッチが６個ありその機能概略を示すが、以降にその使用
　法の詳細を順に説明して行く。

 [ NORMAL / LARGE モードの切り替え機能 ]
 ---------------------------------------

・その設定手順の説明をする前に、LARGE モードについてを先に触れると、上述のように、デモ表示の後 NORMAL モード
　に移行して、ディスプレイ(OLED) 画面は通常の７曜カレンダー表示をしているが、この状態のときに MODE / SET スイ
　ッチを押すと、画面には大きな文字が表示されるようになり、この状態を LARGE モードという。当然ながら文字が大き
　くなったため、７曜カレンダー表示はできない。

・NORMAL モードと LARGE モードは、MODE スイッチを押すごとに交互にそのモードを切り替えることができる。このよう
　に MODE スイッチをチョンと押して、NORMAL モードと LARGE モードを切り替えるのではなく、後述のように長押しを
　することにより、年月日、時分秒を希望値に設定変更することができる SET モードとなる。

 [ カレンダーめくり機能 ]
 ------------------------

・NORMAL モードにおいての UP スイッチまたは DOWN スイッチの振る舞いは、後述の SET モードのように項目の設定値
　を変更するのではなく、現在、ディスプレイ画面に表示されている年月表示とカレンダー表示を、月ごとに前進、また
　は後退させて、紙のカレンダーをめくるように変更表示をする。なお、このときの時分秒の時刻については、カレンダ
　ーめくりの機能とは関係なく現在時刻をきざみ続ける。

・そして、ディスプレイ画面のメッセージエリアには、"←Down Up→" が表示され、かつ、"←Down" または "Up→" のど
　ちらかが反転表示されて、本日の年月日（現在位置）からどちらの方向に偏っているかを表している。本日の年月日に
　もどると、これらのメッセージは消えて７曜カレンダー内の該当日（本日）が反点表示される。

・なお、この "←Down Up→" が表示されている [ カレンダーめくり機能 ] のときには、MODE / SET スイッチの操作を
　しても無視されて、LARGE モードへの切り替え、および SET モードへの移行はできない。また後述するように、TIMER 
　/ TMSET スイッチによる、[タイマー機能] への移行も無視されてできない。

・LARGE モードにおいては７曜カレンダー表示されることがないため、 UP スイッチまたは DOWN スイッチを押しても、
　画面表示の変化はなく無視される。

 [ 24時間表示 / 12時間表示の切り替え機能 ]
 -----------------------------------------

・NORMAL モード、または LARGE モードのときに、UP / TMODE スイッチを３秒間以上押し続けると、"ピッ" とブザー音
　とともに、24時間表示 / 12時間表示の切り替えが行われ、この操作を行うごとに表示形式が交互に切り替わる。

・そして、24時間表示 から 12時間表示になったときには、直ちに "am" または "pm" が、そのときの時 "xx" の設定値
　によって変更表示される。逆に、12時間表示 から 24時間表示になったときには、"am"、"pm" 表示は消える。

 [ ZERO スイッチ機能 ]
 ---------------------

・ZERO ／ BACK スイッチは、後述するように SET モードでは BACK スイッチとして機能するが、それ以外の NORMAL モ
　ード、および LARGE モードでは、毎正時プラス・マイナス５分以内に押されると、00分 00秒に設定するための ZERO 
　スイッチとして機能し、ZERO スイッチを放した直後に、リアルタイムクロック（RTC）モジュールと PIC のフラッシュ
　メモリ (High-Endurance) を更新後、"ピピッ" ブザー音を伴って更新したことを知らせる。

・なお、毎正時プラス・マイナス５分以外に同スイッチが押されたときには、時間を更新することなく無視される。

 [ 毎時の時報音出力の ON / OFF 制御機能 ]
 ----------------------------------------

・SIGNAL / CANCEL スイッチは、押すごとにディスプレイ画面右下のメッセージエリアに、"Signal On" と "Signal Off" 
　を交互に３秒間反転表示し、毎時の時報音のブザー音出力を、有効／無効に交互に設定をする。

・このとき、"Signal On" の有効のときには "ピピピッ" ブザー音を、"Signal Off" の無効のときには "ブー" ブザー音
　を伴って知らせる。なお、電源を投入直後は "Signal On" の有効に設定がされている。

・また、LARGE モードにおいては SET モードに切り替わったときと同様、メッセージエリアの確保のために２行目と３行
　目が上部位置に移動して、同メッセージが反転表示されるが、３秒間の経過後はメッセージエリアの消滅とともに、 通
　常の LARGE モードの表示位置に戻る。

・なお、ここで設定するブザー音出力の有効／無効は、あくまでも毎時の時報音、およびタイマー一致音のアラーム出力
　だけに関わる設定であって、その他のスイッチ操作等に伴なって出力される効果音には、当てはまらないので注意が必
　要である。

 [ スリープモード ]
 ------------------

・NORMAL モード、または LARGE モードのとき（ [ カレンダーめくり機能 ] 時も含めて）に、どのスイッチも操作しな
　い状態が 10 分（デフォルト）以上続くと、省エネのため自動的にディスプレイ (OLED) をスリープさせるとともに、
　本機自体もスリープモードに移行する。（ SET モード機能、 メンテナンス機能を実行中はスリープモードに移行しな
　いので要注意。）

・本機がスリープモードに移行するときには、10 分（デフォルト）を経過する３秒前から、秒ごとに "ブッ" ブザー音を
　３回、また、10 分を経過直後に "ブッブー" ブザー音とともにスリープモードに移行する。

・なお、この移行までの時間は後述の「メンテナンス機能とスイッチ操作」で 0 ～ 60 分の範囲（ただし、0 設定時はス
　リープしない）で変更することができる。

・また、本機自体およびディスプレイ (OLED) がスリープモードになっているときに、６個の全スイッチの内のどれかが
　操作されると本機はウエイクアップして、"ピピッ" ブザー音とともに、再びディスプレイ (OLED) 画面の表示がされる
　ようになる。

・そして、このウエイクアップしたのを契機として、その度ごとの直後に、ディスプレイ画面右下のメッセージエリアに 
　"[Batt=x.xxV]" と、本機に使用している電源 18650 リチウムイオン電池の現在電圧値が、約 10 秒間だけ反転表示さ
　れる。

・このときに、LARGE モードでウエイクアップしたときには、前項の [毎時の時報音とタイマー一致音出力の ON / OFF 
　制御機能] と同様に、メッセージエリアの確保のために２行目と３行目が上部位置に移動して表示されるが、10 秒間の
　経過後はメッセージエリアの消滅とともに、通常の LARGE モードの表示位置に戻る。

-------------------------------
◎ SET モード機能とスイッチ操作
-------------------------------
			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │○│   │●│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

		 SET スイッチ        ..... ブリンク位置のポインタを + 1
		BACK スイッチ        ..... ブリンク位置のポインタを - 1

		  UP スイッチ        ..... ブリンク位置の値を + 1
		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り

		DOWN スイッチ        ..... ブリンク位置の値を - 1
		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り

    (秒選択時に) SET スイッチ        ..... SET モードを終了し、NORMAL / LARGE モードに戻る

	      CANCEL スイッチ        ..... SET モードを中断し、NORMAL / LARGE モードに戻る

・さて、ここで話を戻して、年月日、時分秒の設定を変更する手順は、まず MODE / SET スイッチを３秒間以上押し続け
　ると、"ピッ" とブザー音とともに、ディスプレイ画面右下のメッセージエリアに "SET MODE" と反転表示されて、
　NORMAL モード、または LARGE モードから SET モードに切り替わったことを示し、年月日および時分秒の表示は更新が
　停止する。

・なお、このとき LARGE モードから SET モードに切り替わった場合には、メッセージエリアの確保のため、２行目（曜
　日、am/pm）の表示と３行目（時分秒）の表示が、以降 SET モードの間中は上部位置に移動して表示される。

・そこで MODE / SET スイッチを放すと、メッセージは "Year Hi ?" に変わり、左上の年月 "xxxx/xx" 表示エリアの先
　頭２桁がブリンク表示されて、年の上位２桁の変更が可能となる。

・もし変更が必要であれば、UP スイッチを押すごとに現在値より１づつ増加し、また DOWN スイッチを押すごとに１づつ
　減少するので、適宜希望する値に変更する。

・年の上位２桁の変更が済んだら、再び MODE / SET スイッチを押すとメッセージは "Year Lo ?" に変わり、左上の年月 
　"xxxx/xx" 表示エリアの 年の下位２桁がブリンク表示され、年の下位２桁の変更が可能となる。

・同様に変更が必要であれば、UP スイッチまたは DOWN スイッチを押すことによって、適宜希望する値に変更する。なお、
　これらの値の増減幅を大きくしたい場合には、UP スイッチまたは DOWN スイッチを押したままにしていると、１秒当た
　り 4 ～ 5 の増減幅で更新をするようになる。

・以降、同様に SET スイッチを押すごとに、月 → 日 → 24H/12H → 時 → 分 → 秒 と設定項目を変更することができ
　るので、変更が必要であればその該当項目の選択時に、UP スイッチまたは DOWN スイッチを押すことによって、適宜希
　望する値に変更する。

・また、このときのメッセージエリアには、それぞれ "Month ?"、"Today ?"、"24H/12H ?"、"Hour ?"、"Minute ?"、
　"Second ?" と反転表示され、NORMAL モードでは１行目の該当項目の月、24H/12H、時、分、秒の、それぞれがブリンク
　表示されて選択項目を表す。LARGE モードにおいても位置は異なっているが、該当する項目が同様にブリンク表示され
　る。

・選択項目の日 "xx" については、NORMAL モードでは７曜カレンダー内で該当日（本日）がブリンク表示されるので、同
　様に UP スイッチまたは DOWN スイッチによって、その位置を移動変更することにより選択をする。また、LARGE モー
　ドにおいては１行目の右端２桁がブリンク表示され、他の項目と同様に UP スイッチまたは DOWN スイッチを押すこと
　によって、適宜希望する値に変更する。

・この SET スイッチによって項目を選択中に、誤って希望する項目を通り過ぎてしまったような場合には、BACK スイッ
　チを押すごとにひとつづつ前の項目に戻ることができる。

・最後の秒の項目選択時に更に SET スイッチを押すと、今まで変更されてきた各項目の設定値が、新たな情報としてリア
　ルタイムクロック（RTC）モジュールと PIC のフラッシュメモリ (High-Endurance) に書き込み更新され、その後、SET 
　モードから NORMAL モード、または LARGE モードの、SET モードに移行する前のディスプレイ(OLED) 画面に再び戻っ
　て、その設定値から年月日、時分秒の表示が再開される。

・SET モードでの選択項目の推移をまとめると次図のようになる。

　                              BACK            BACK  BACK  BACK       BACK  BACK  BACK
　            MODE               ←              ←    ←    ←         ←    ←    ←
　            /SET              SET             SET   SET   SET        SET   SET   SET   SET
　NORMALモード ─→ 年(上位２桁) → 年(下位２桁) → 月 → 日 → 24H/12H → 時 → 分 → 秒 ─→ NORMALモード
　(LARGEモード)          │                                                            ↑     (LARGEモード)
　                   BACK└──────────────────────────────┘

・ここで項目 24H/12H について補足をしておくと、これは時表示を 24時間表示にするか 12時間表示にするか、どちらか
　を選択することで、UP スイッチまたは DOWN スイッチのどちらかを押すことによって、交互に切り替えることができる。

・24H を選択した場合は、次の項目に移った時に "24H/12H" 表示エリアには何も表示されないが、12H を選択した場合は、
　次の項目に移った時に "am" または "pm" が、そのときの時 "xx" の設定値によって変更表示される。

・次に、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

・上記のように、最後の秒の項目選択時に更に SET スイッチを押した場合には、リアルタイムクロック（RTC）モジュー
　ル等を更新後、"ピピッ" ブザー音を伴って正常に終了したことを知らせる。

・また、各項目の変更中に何らかの理由があって途中で変更作業を中断したい場合には、SIGNAL / CANCEL スイッチを押
　すことによって、直ちに SET モードから NORMAL モード、または LARGE モードの、SET モードに移行する前に戻るこ
　とができる。この場合には、リアルタイムクロック（RTC）モジュール等を更新することはなく、"ブー" ブザー音を伴
　って中断終了したことを知らせる。

---------------------------------
◎ メンテナンス機能とスイッチ操作
---------------------------------
			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │○│   │●│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

		 SET スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択

		  UP スイッチ        ..... ブリンク位置の値を + 1
		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り

		  UP スイッチ +
		DOWN スイッチ        ..... ブリンク位置の値をデフォルト値に設定

		DOWN スイッチ        ..... ブリンク位置の値を - 1
		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り

		DOWN スイッチ +
		  UP スイッチ        ..... ブリンク位置の値をデフォルト値に設定

		BACK スイッチ        ..... メンテナンス機能を終了し、NORMAL / LARGE モードに戻る

	      CANCEL スイッチ        ..... メンテナンス機能を中断し、NORMAL / LARGE モードに戻る

・NORMAL モードのときに、DOWN / MAINTE スイッチを３秒間以上押し続けると、"ピッ" とブザー音とともに、ディスプ
　レイ画面右下のメッセージエリアに "Maintenance" と反転表示されて、メンテナンス機能への移行準備が行われるので、
　DOWN / MAINTE スイッチを放すと、ディスプレイ画面が [メンテナンス機能] 画面に切り替わる。

・また、LARGE モードのときに、DOWN / MAINTE スイッチを３秒間以上押し続けると、SET モードに切り替わったときと
　同様、メッセージエリアの確保のために２行目と３行目が上部位置に移動して表示され、以降は NORMAL モードのとき
　と同様である。

			=== Maintenance ===
			  [ Batt = x.xxV ]
			 > OLED Contrast
			  (001-255) ? _ xxx
			 > Sleep Time
			  (00-60) ? _ xx

・表示された [メンテナンス機能] 画面の２行目には、本機に使用している電源 18650 リチウムイオン電池の現在電圧値
　を、リアルタイム（５秒ごとに更新）で表示しているので、電池の充電時期の判断に使用することができる。
　
・画面の３行目以降の表示は、本機におけるメンテナンス機能を表し、OLED コントラストの設定変更、スリープまでの移
　行時間（分）の設定変更、の２つの設定変更機能があり、本 [メンテナンス機能] 画面に切り替わった直後は、前者の
　設定変更が選択されて "(001-255) ? _ xxx" メッセージ の "xxx" 部分がブリンク表示される。

・そこで、前者設定値を変更したい場合には、UP スイッチを押すごとに現在値より１づつ増加し、また DOWN スイッチを
　押すごとに１づつ減少するので、適宜希望する値に変更する。

・また、後者の設定変更を選択したい場合には、MODE / SET スイッチを押すことによって "(00-60) ? _ xx" メッセージ
　の "xx" 部分がブリンク表示されるので、同様に UP スイッチまたは DOWN スイッチを押すことによって、希望する値
　に変更する。

・このときの MODE / SET スイッチは、押すごとに両者の設定変更の選択を交互に切り替えることができ、それぞれで変
　更できる設定範囲は、前者では 001 ～ 255 まで、後者では 00 ～ 60 までとなっている。ただし、後者で 00 を設定
　した場合には、スリープモードには移行しなくなるので注意が必要である。

　（余談） 前者の設定値として、SSD1306 では 000 の設定も可能ではあるが、その場合には画面が完全に消えてしまう
　　　　　 ので、本機では設定値から外すことにした。

・また、UP スイッチまたは DOWN スイッチによる増減幅を大きくしたい場合には、UP スイッチまたは DOWN スイッチを
　押したままにしていると、増減値が早送りされるようになる。

・なお、OLED コントラストを設定変更、スリープまでの移行時間（分）を設定変更、の２つの設定値のデフォルト値は、
　それぞれ 127 と 10 に規定されており、それぞれの設定変更が選択されているときに、UP スイッチと DOWN スイッチ
　を同時に押すことによって、それぞれのデフォルト値に簡単に設定することができる。

・両者の設定変更が済んで、元の NORMAL モードまたは LARGE モードに戻りたい場合は、ZERO / BACK スイッチを押すこ
　とによって行われ、変更された設定値で PIC のフラッシュメモリ (High-Endurance) を更新後、"ピピッ" ブザー音を
　伴って正常に終了したことを知らせる。

・また、何らかの理由があって途中で設定変更を中断したい場合には、SIGNAL / CANCEL スイッチを押すことによって、
　メンテナンス機能に移行する前の NORMAL モードまたは LARGE モードに戻ることができる。この場合には、それまでに
　変更された設定値は破棄され、"ブー" ブザー音を伴って中断終了したことを知らせる。

---------------------------------
◎ タイマー機能とスイッチ操作
---------------------------------

・本機におけるタイマー機能には、[メモリの設定]、[メモリの読み出しと消去]、[タイマーメモリの監視] の３機能があ
　り、まず初めにタイマー情報をメモリに設定しておくと、[タイマーメモリの監視] 機能によって、設定時刻が現在時刻
　に一致するとアラーム音によって通知をする。

・これらのメモリに設定したタイマー情報は、[メモリの読み出し] 機能によっていつでもその内容を確認することができ、
　不要になった場合には消去する機能も備えている。

・[メモリの設定] 機能には、年タイマー、週間タイマーの２種類があり、年タイマーでは "年、月、日、時、分" を設定
　するが、監視機能によるアラーム音の通知後はそのタイマー情報は不要になるため、タイマーメモリから自動的に消去
　される。

・また、週間タイマーでは "曜日、時、分" を設定し、これらのタイマー情報は自動的に消去されることがないため、上
　述の消去機能によって消去をしない限り、毎週同時刻になるとアラーム音の通知を行う。なお、曜日には関係なく毎日
　の指定をすることもできる。

・これらの年タイマー、週間タイマーの設定数は、両者を合わせて合計 10 個まで設定をすることができる。

 [ タイマーメモリの設定 ]
 ------------------------

・NORMAL モードのときに、TIMER / TMSET スイッチを３秒間以上押し続けると、"ピッ" とブザー音とともに、ディスプ
　レイ画面右下のメッセージエリアに " TIMER SET " と反転表示されて、[タイマーメモリの設定] 機能への移行準備が
　行われるので、TIMER / TMSET スイッチを放すと、ディスプレイ画面が [タイマーメモリの設定] 機能の [タイマー種
　類の選択] 画面に切り替わる。

・また、LARGE モードのときに、TIMER / TMSET スイッチを３秒間以上押し続けると、SET モードに切り替わったときと
　同様、メッセージエリアの確保のために２行目と３行目が上部位置に移動して表示され、以降は NORMAL モードのとき
　と同様である。

　タイマー種類の選択時
　--------------------
			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │○│   │○│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

			    UP スイッチ ..... ブリンク位置のポインタを + 1
			  DOWN スイッチ ..... ブリンク位置のポインタを - 1

			   SET スイッチ ..... タイマー種類選択を終了し、次項目の設定に移行する

			CANCEL スイッチ ..... タイマー種類選択を中断し、NORMAL / LARGE モードに戻る

・このように TIMER / TMSET スイッチを放すと、初めに次のような [タイマー種類の選択] 画面が表示されるので、年タ
　イマー (Date)、週間タイマー (Weekly) の２種類の内、どちらかを UP または DOWN スイッチによって選択をする。こ
　のときデフォルトでは "Date" が選択されブリンク表示をする。

			= Timer Memory Set =
			
			 Type = Date Weekly
			
			
			 UP/DOWN SET/CANCEL 

・このときの [タイマー種類の選択] 画面の最下行には、"UP/DOWN SET/CANCEL" の文字列が反転表示され、この画面のと
　きに使用ができるスイッチ種類を、簡易的な操作ガイドとして表示がされる。（この画面では UP, DOWN, SET, CANCEL 
　スイッチの４種類だけが使用できることを案内している。）

・UP または DOWN スイッチによってどちらかを選択（ブリンクする表示位置を変更）後、SET スイッチを押すことによっ
　てその選択が決定され、次に、年タイマー (Date)、週間タイマー (Weekly) の、それぞれに決められた [タイマー情報
　の設定] 画面が新たに表示される。

・また、この [タイマー種類の選択] 時には、上記の選択画面を表示する前に、タイマー用メモリに登録をするための空
　きがあるかどうかを事前にチェックをし、空きがある場合のみ選択画面が表示される。

・タイマー用メモリに空きがない場合には、"ブッブー" ブザー音とともに次のメッセージが表示されるので、全スイッチ
　の内のどれかを押すと [タイマーメモリの設定] 機能が終了し、NORMAL モード、または LARGE モードの表示画面に戻
　る。

			  Memory full !
			   Any switch ? _

・なお、この [タイマー種類の選択] 画面のときに、何らかの理由があって選択を中止したい場合には、CANCEL スイッチ
　を押すことによって [タイマーメモリの設定] 機能が中止され、"ブー" ブザー音を出力後、通常の NORMAL モード、ま
　たは LARGE モードの表示画面に戻る。

　タイマー情報の設定時
　--------------------
			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │●│   │●│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

			   SET スイッチ ..... ブリンク位置のポインタを + 1
			  BACK スイッチ ..... ブリンク位置のポインタを - 1

			    UP スイッチ ..... ブリンク位置の値を + 1
			  DOWN スイッチ ..... ブリンク位置の値を - 1

	    (分選択時に) TIMER スイッチ ..... １件分のタイマー設定を終了し、次の設定に備える

			CANCEL スイッチ ..... タイマー設定を中断し、NORMAL / LARGE モードに戻る

・まず、年タイマー (Date) が選択決定された場合には、"ピッ" ブザー音を出力後、次のように SET モード機能のとき
　と同様な設定画面に切り替わり、以降、ブリンク表示されている位置と画面右下のメッセージエリアの案内に従って、
　それぞれの項目を順に入力して行く。

・この [年タイマー (Date) の設定] 画面と SET モード機能の設定画面は、そのほとんどが同様に表示されるが、両者で
　の大きな相違点は、前者では画面右上に "秒（ :xx ）" の項目が表示されないことで、見分けることができる。

・SET モード機能のときと同様のスイッチ操作によって、各項目を選択、入力して行くが、下図のように "分" がブリン
　ク表示して選択されているときに、TIMER スイッチを押すことによって、入力された年タイマー (Date) の情報が、既
　存のタイマー情報と比較（重複データチェック）され、重複エラーがない場合に限って、タイマー用メモリへの書き込
　みが行われ、"ポッポッ" ブザー音が出力される。

・"分" 以外がブリンク表示しているときに、TIMER スイッチを押した場合、または重複データチェックで重複エラーが見
　つかった場合には、タイマー用メモリへの書き込みは行われず、"ブッ" ブザー音を出力して無視をする。

　                              BACK            BACK  BACK  BACK       BACK  BACK
　                               ←              ←    ←    ←         ←    ←
　            SET               SET             SET   SET   SET        SET   SET    TIMER
　種類の選択 ──→ 年(上位２桁) → 年(下位２桁) → 月 → 日 → 24H/12H → 時 → 分 ──→ 種類の選択
　    (Date)            │↑                                                    │↑
　                      ││                                                 SET││
　                  BACK│└──────────────────────────┘│
　                      └────────────────────────────┘

・重複エラーがなくタイマー用メモリへの書き込みが行われた後は、再び [タイマー種類の選択] 画面が表示されるので、
　次のタイマー情報がある場合には引き続き設定をする。（次のタイマー情報がない場合には、CANCEL スイッチ を押し
　て [タイマーメモリの設定] 機能を終了させる。）

・上図には記入がされていないが [タイマー種類の選択] のときと同様に、各項目を選択中に何らかの理由があって設定
　を中止したい場合には、CANCEL スイッチを押すことによって [タイマーメモリの設定機能] が中止され、"ブー" ブザ
　ー音を出力後、通常の NORMAL モード、または LARGE モードの表示画面に戻ることもできる。

・一方、[タイマー種類の選択] 画面のときに、週間タイマー (Weekly) が選択決定された場合には、"ピッ" ブザー音を
　出力後、次の設定画面が表示されて曜日選択から始めるように、デフォルトでは "Eday"（毎日）が選択されブリンク表
　示する。

			= Timer Memory Set =

			Eday
			Su Mo Tu We Th Fr Sa

			    xx:xx		..... 時:分

			SET/BAK UP/DW TIM/CAN

・このときにも設定画面の最下行には、"SET/BAK UP/DW TIM/CAN" の文字列が反転表示され、この画面のときに使用がで
　きるスイッチ種類を、簡易的な操作ガイドとして表示がされる。（この画面では SET, BAK, UP, DOWN, TIMER, CANCEL 
　の全スイッチが使用できることを案内している。）

・初めの曜日選択では UP、または DOWN スイッチによって、希望する曜日の選択をする。そして SET、または BACK スイ
　ッチによって、下図のように各項目間を移動することができ、"分" がブリンク表示して選択されているときに、TIMER 
　スイッチを押すことによって、以降は、上述の [年タイマー (Date) の設定] のときと同様である。

	　                      BACK       BACK  BACK
	　                       ←         ←    ←
	　            SET       SET        SET   SET    TIMER
	　種類の選択 ──→ 曜日 → 24H/12H → 時 → 分 ──→ 種類の選択
	　  (Weekly)        │↑                    │↑
	　                  ││                 SET││
	　              BACK│└──────────┘│
	　                  └────────────┘

・年タイマー (Date)、週間タイマー (Weekly) のタイマー情報が、上述のようにタイマー用メモリへの書き込みが行われ
　た場合には、[タイマーメモリの設定] の終了時に、High-Endurance フラッシュメモリにもそのバックアップが書き込
　まれ、本機の電源スイッチ OFF などの停電時に備える。

 [ タイマーメモリの読み出しと消去 ]
 ----------------------------------
			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │○│   │●│   │●│   │●│   │●│   │○│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

		    UP スイッチ ..... ブリンクする表示番号を - 1
		  DOWN スイッチ ..... ブリンクする表示番号を + 1

		  ZERO スイッチ ..... ブリンクする表示番号の登録データを消去する

		 TIMER スイッチ ..... タイマーメモリの読み出しを終了し、NORMAL / LARGE モードに戻る

・NORMAL モード、または LARGE モードのときに、TIMER / TMSET スイッチを押すと、タイマー用メモリのデータ表示に
　先立って、登録データがあるかどうかを事前にチェックをし、登録データがある場合のみ次のような画面が表示される。

・(1)、(2) の形式は年タイマー (Date) が登録されており、かつ、(1) は 24H、(2) は 12H の時間表示で登録がされて
　いる例を示す。また、(3)、(4) の形式は週間タイマー (Weekly) が登録されており、かつ、(3) は 24H、(4) は 12H 
　の時間表示で登録がされている例を示す。

			= Timer Memory Read =

			xx xxxx/xx/xx   xx:xx     ... (1)
			xx xxxx/xx/xx xx x:xx     ... (2)
			xx       xxxx   xx:xx     ... (3)
			xx       xxxx xx x:xx     ... (4)

			↓:DOWN ↑:UP del:ZERO

・この表示画面の最下行にも、"↓:DOWN ↑:UP del:ZERO" の文字列が反転表示され、この画面のときに使用ができるスイ
　ッチ種類を、簡易的な操作ガイドとして表示がされる。（この画面では DOWN, UP, ZERO の３種類のスイッチが使用で
　きることを案内しているが、他にも、表示はされていないが TIMER スイッチを押すと、データ表示機能を終了する。）

・上図のように、各データ行の左端２桁には登録順に番号が付けられ、01 から始まってデフォルトでは 01 番が選択され
　ブリンク表示をする。本機では、ディスプレイ(OLED) 画面の中央４行だけにしか登録データの表示ができないため、そ
　れ以上の登録データがある場合には、↓:DOWN スイッチ、または ↑:UP スイッチを押すことによって、ブリンク表示す
　る選択番号を変更させ、デフォルトの４行以外の登録データを選択表示させることができる。

・このように、複数の登録データがあっても選択番号を変更させることによって、対象とする登録データを変更させ、も
　しもその登録データが不要になった場合には、ZERO スイッチを押すことによって、その登録データだけをタイマー用メ
　モリから消去する。

・そして、この登録データを消去した場合には、[タイマーメモリの読み出しと消去] の終了時に、High-Endurance フラ
　ッシュメモリにもそのバックアップが書き込まれ、本機の電源スイッチ OFF などの停電時に備える。

・上述した登録データの事前チェックで、登録データがなかった場合には、"ブッブー" ブザー音とともに次のメッセージ
　が表示されるので、全スイッチの内のどれかを押すと [タイマーメモリの読み出しと消去] 機能が終了し、NORMAL モー
　ド、または LARGE モードの表示画面に戻る。

			 "No registration !"
			      "Any switch ? _"

・また、登録データの表示中に TIMER スイッチを押すことによって、同様に、[タイマーメモリの読み出しと消去] 機能
　が終了し、NORMAL モード、または LARGE モードの表示画面に戻る。

 [ タイマーメモリの監視 ]
 ------------------------

・本機がスリープモード中を含む NORMAL モード、または LARGE モードのときに、アラーム音出力が許可されていると、
　本機の時計機能が毎分 "00" 秒になると、監視プログラムによってタイマー用メモリ中に登録がされているタイマー情
　報が検索され、時刻が一致した情報が存在した場合には、"ピポッピポッ" アラーム音を 10 回出力して知らせる。

・このように時刻が一致したタイマー情報は、年タイマー (Date) の場合には以降は不要となるために、自動的にタイマ
　ー用メモリ中から消去される。週間タイマー (Weekly) の場合には、[タイマーメモリの読み出しと消去] 機能で消去を
　行わない限り、いつまでもタイマー用メモリ中に存在をし続けるため、毎週同時刻になるとアラーム音を出力する。

・なお、上述した年タイマー (Date) の場合の [タイマー情報の設定] で、現在時刻よりも過去の情報を入力した場合に
　は、一旦はタイマー用メモリに登録されるが、この監視プログラムが実行された時点で自動的に消去される。

#endif

;==========================================================================

;	PIC16F1705 のピンと用途

;		(1) Vdd: 電源 +3V DC		(14) Vss: 電源 GND
;		(2) RA5: ZERO/BACK SW 入力	(13) RA0: MODE/SET SW 入力 / DAT
;		(3) RA4: DOWN/MAINT SW 入力	(12) RA1: UP/TMODE SW 入力 / CLK
;		(4) RA3: 予備入力 / Vpp		(11) RA2: RTC SQW 入力
;		(5) RC5: SIGNAL/CANCEL SW 入力	(10) RC0: I2C SCL 出力
;		(6) RC4: TIMER/TMSET SW 入力	 (9) RC1: I2C SDA 入出力
;		(7) RC3: 圧電スピーカ 出力	 (8) RC2: BATT 電圧測定入力

;	*注.  RA3 は入力専用で、出力ポートには使えない。

;==========================================================================

		list		p=pic16f1705		;デバイス情報
		include		p16f1705.inc		;インクルードファイル
		errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションワードの設定
;==========================================================================

;	__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
	__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
	__config _CONFIG2, _WRT_OFF & _PPS1WAY_OFF & _ZCDDIS_ON & _PLLEN_OFF & _STVREN_OFF & _BORV_HI & _LPBOR_ON & _LVP_ON

; ------------------------------------
; CONFIGURATION WORD 1 (ADDRESS:8007H)		Data Sheet DS40001729C - page 48
; ------------------------------------
;
;     CONFIG1 = 00 1111 1000 0100
;	        || |||| |||| ||||
;	bit2-0  || |||| |||| |+++---- FOSC<2:0>: オシレータ選択ビット
;	        || |||| |||| |          111 = ECH:    外部クロック、高消費電力モード(4-20 MHz):  OSC1/CLKINピンに供給
;	        || |||| |||| |          110 = ECM:    外部クロック、中消費電力モード(0.5-4 MHz): OSC1/CLKINピンに供給
;	        || |||| |||| |          101 = ECL:    外部クロック、低消費電力モード(0-0.5 MHz): OSC1/CLKINピンに供給
;	        || |||| |||| |      >   100 = INTOSC: 内部HFINTOSC CLKINピンはI/Oとして機能
;	        || |||| |||| |          011 = EXTRC:  CLKINピンに外部RC回路を接続
;	        || |||| |||| |          010 = HSOSC:  OSC1とOSC2ピンの間に高速水晶/セラミック振動子を接続
;	        || |||| |||| |          001 = XTOSC:  OSC1とOSC2ピンの間に水晶/セラミック振動子を接続
;	        || |||| |||| |          000 = LPOSC:  OSC1とOSC2ピンの間に低消費電力水晶振動子を接続
;	        || |||| |||| |
;	bit4-3  || |||| |||+ +------- WDTE<1:0>: ウォッチドッグ タイマ イネーブルビット
;	        || |||| |||             11 = ON:     WDTを有効
;	        || |||| |||             10 = NSLEEP: WDTを動作時は有効、スリープ中は無効
;	        || |||| |||             01 = SWDTEN: WDTをWDTCONレジスタのSWDTENビットで制御
;	        || |||| |||         >   00 = OFF:    WDTを無効
;	        || |||| |||           _____
;	bit5    || |||| ||+---------- PWRTE: パワーアップ タイマ イネーブルビット
;	        || |||| ||              1 = OFF: PWRTを無効
;	        || |||| ||          >   0 = ON:  PWRTを有効
;	        || |||| ||
;	bit6    || |||| |+----------- MCLRE: MCLR/VPPピン機能選択ビット
;	        || |||| |              LVPビット=0 の場合
;	        || |||| |               1 = ON:  MCLR/VPPピンの機能はMCLR、弱プルアップを有効
;	        || |||| |           >   0 = OFF: MCLR/VPPピンはデジタル入力、MCLRは無効、弱プルアップはWPUA3ビットで制御
;	        || |||| |             __
;	bit7    || |||| +------------ CP: コード保護ビット
;	        || ||||             >   1 = OFF: プログラムメモリのコード保護を無効
;	        || ||||                 0 = ON:  プログラムメモリのコード保護を有効
;	        || ||||
;	bit8    || |||+-------------- 未実装
;	        || |||
;	bit10-9 || |++--------------- BOREN<1:0>: ブラウンアウト リセット イネーブルビット
;	        || |                >   11 = ON:     BORを有効
;	        || |                    10 = NSLEEP: BORを動作時は有効、スリープ中は無効
;	        || |                    01 = SBODEN: BORをBORCONレジスタのSBORENビットで制御
;	        || |                    00 = OFF:    BORを無効
;	        || |                  ________
;	bit11   || +----------------- CLKOUTEN: クロック出力イネーブルビット
;	        ||                     FOSCビットがLP、XT、HSモードの場合
;	        ||                      このビットを無視しCLKOUT機能を無効、CLKOUTピンはI/Oとして機能
;	        ||                     FOSCビットがその他のモードの場合
;	        ||                  >   1 = OFF: CLKOUT機能を無効、CLKOUTピンはI/Oとして機能
;	        ||                      0 = ON:  CLKOUTピンのCLKOUT機能を有効
;	        ||
;	bit12   |+------------------- IESO: 内部/外部切り換えビット
;	        |                       1 = ON:  内部/外部切り換えモードを有効
;	        |                   >   0 = OFF: 内部/外部切り換えモードを無効
;	        |
;	bit13   +-------------------- FCMEN: フェイルセーフ クロックモニタ イネーブルビット
;	                                1 = ON:  フェイルセーフ クロックモニタと内部/外部切り換えの両方を有効
;	                            >   0 = OFF: フェイルセーフ クロックモニタを無効
;
; ------------------------------------
; CONFIGURATION WORD 2 (ADDRESS:8008H)		Data Sheet DS40001729C - page 50
; ------------------------------------
;
;     CONFIG2 = 11 0000 1111 1011
;	        || |||| |||| ||||
;	bit1-0  || |||| |||| ||++---- WRT<1:0>: フラッシュメモリ自己書き込み保護ビット
;	        || |||| |||| ||     >   11 = OFF:  書き込み保護を無効
;	        || |||| |||| ||         10 = BOOT: 0000h～01FFhを書き込み保護、0200h～1FFFhをPMCON制御で変更可能
;	        || |||| |||| ||         01 = HALF: 0000h～0FFFhを書き込み保護、1000h～1FFFhをPMCON制御で変更可能
;	        || |||| |||| ||         00 = ALL:  0000h～1FFFhを書き込み保護、PMCON制御によるアドレス変更を不可
;	        || |||| |||| ||
;	bit2    || |||| |||| |+------ PPS1WAY: PPSLOCKビット単方向セット イネーブルビット
;	        || |||| |||| |          1 = ON:  PPSLOCKビットは、ロック解除シーケンスを実行後に一度のみセット可、
;	        || |||| |||| |                   一度PPSLOCKがセットされると、その後PPSレジスタは変更不可
;	        || |||| |||| |      >   0 = OFF: ロック解除シーケンスを実行すれば何度でもPPSLOCKビットをセット/クリア可
;	        || |||| |||| |
;	bit6-3  || |||| |+++ +------- 未実装
;	        || |||| |
;	bit7    || |||| +------------ ZCDDIS: ZCDディセーブルビット
;	        || ||||             >   1 = ON:  ZCDを無効、有効にするにはZCDCONのZCDSENビットをセット
;	        || ||||                 0 = OFF: ZCDを常に有効
;	        || ||||
;	bit8    || |||+-------------- PLLEN: PLLイネーブルビット
;	        || |||                  1 = ON:  4xPLLを有効
;	        || |||              >   0 = OFF: 4xPLLを無効
;	        || |||
;	bit9    || ||+--------------- STVREN: スタック オーバーフロー/アンダーフロー リセット イネーブルビット
;	        || ||                   1 = ON:  スタックのオーバーフロー/アンダーフローによってリセットを発生させる
;	        || ||               >   0 = OFF: スタックのオーバーフロー/アンダーフローによってリセットを発生させない
;	        || ||
;	bit10   || |+---------------- BORV: ブラウンアウト リセット電圧選択ビット
;	        || |                    1 = LO: ブラウンアウト リセット電圧(VBOR)のトリップポイントを低に設定
;	        || |                >   0 = HI: ブラウンアウト リセット電圧(VBOR)のトリップポイントを高に設定                   
;	        || |                  _____
;	bit11   || +----------------- LPBOR: 低消費電力BORイネーブルビット
;	        ||                      1 = OFF: 低消費電力ブラウンアウト リセットを無効
;	        ||                  >   0 = ON:  低消費電力ブラウンアウト リセットを有効
;	        ||                    _____
;	bit12   |+------------------- DEBUG: インサーキット デバッガモード ビット
;	        |                   >   1 = OFF: インサーキット デバッガを無効、ICSPCLKとICSPDATは汎用I/Oピンとして機能
;	        |                       0 = ON:  インサーキット デバッガを有効、ICSPCLKとICSPDATはデバッガ専用
;	        |
;	bit13   +-------------------- LVP: 低電圧プログラミング イネーブルビット
;	                            >   1 = ON:  低電圧プログラミングを有効
;	                                0 = OFF: プログラミング時にMCLRに高電圧の印加が必要

;==========================================================================
;		定数の定義と変数のレジスタ割付け
;==========================================================================

		radix	dec

#define 	ver_no	"2.08"			;バージョン番号

#define 	pagex_wk   end_pagex		;表示ページの退避ワーク
#define 	column_wk  end_column		;表示カラムの退避ワーク
#define 	contrast_wk   temp_yh		;contrast   の退避ワーク
#define 	sleep_time_wk temp_yl		;sleep_time の退避ワーク
#define 	buff	      temp_nn		;変換文字列の格納エリア

linear_memory	equ	h'2000' + 80 * 2	;リニアデータメモリの先頭アドレス
save_data_ram	equ	linear_memory		;引継ぎ情報の先頭アドレス
timer_memory	equ	save_data_ram  + 4	;タイマー用メモリの先頭アドレス
timer_capacity	equ	10			;タイマー用メモリの記憶容量の最大値
timer_mem_addr	equ	timer_memory   + 7 * timer_capacity ;タイマー用メモリの先頭アドレス
work_memory	equ	timer_mem_addr + 2 * timer_capacity ;ワークメモリの先頭アドレス
next_memory	equ	work_memory    + 7 * timer_capacity ;次に使用できるメモリの先頭アドレス

;		  linear_memory	|				|
;		  save_data_ram	+-------------------------------+ 20A0 (h'2000' + 80 * 2) ―――――――
;				|	    (4 bytes)		|			    ↑	    ↑
;		   timer_memory	+-------------------------------+ 20A4			    ｜	    ｜
;				|				|			    ｜	    ｜
;				|				|			  BACKUP    ｜
;				|	   (70 bytes)		|			(74 bytes)  ｜
;				|				|			    ｜	    ｜
;				|				|			    ↓	    ｜
;		 timer_mem_addr	+-------------------------------+ 20EA			  ―――   USE
;				|	   (20 bytes)		|			       (164 bytes)
;				|				|				    ｜
;		    work_memory	+-------------------------------+ 20FE				    ｜
;				|				|				    ｜
;				|				|				    ｜
;				|	   (70 bytes)		|				    ｜
;				|				|				    ｜
;				|				|				    ↓
;		    next_memory	+-------------------------------+ 2144			  ―――――――
;				|				|
;				|				|

tm0_h_val	equ	256 - 250		;ハードタイマー０カウント値（割り込み周期）(4/8Mz*16*250=2msec)
tm0_s_val	equ	250			;ソフトタイマー０カウント値                (2msec*250=500msec)

_swMOD		equ	0			;MODE スイッチ	;PORTA
_swSET		equ	0			;SET  スイッチ
_swUP		equ	1			;UP   スイッチ
_swDWN		equ	4			;DOWN スイッチ
_swZER		equ	5			;ZERO スイッチ
_swBAK		equ	5			;BACK スイッチ

SCL		equ	0			;I2C-LCD SCL	;PORTC
SDA		equ	1			;I2C-LCD SDA
;;OLED_PW	equ	2			;OLED 電源制御
_BZ		equ	3			;アラーム音 出力
_swTIM		equ	4			;TIMER  スイッチ
_swTSET		equ	4			;TMSET  スイッチ
_swSIG		equ	5			;SIGNAL スイッチ
_swCAN		equ	5			;CANCEL スイッチ

f_rah		equ	65536 - 1136		;ラ (880.00 Hz)  at 8MHz
f_doh		equ	65536 - 1911		;ド (523.26 Hz)
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'			;バンク 0
tm0_s_cnt					;ソフトタイマー０カウンタ

bcd_yh						;年(上位2桁)_BCD カウンタ
bcd_yl						;年(下位2桁)_BCD カウンタ
bcd_nn						;月_BCD カウンタ
bcd_dd						;日_BCD カウンタ
bcd_hh						;時_BCD カウンタ
bcd_mm						;分_BCD カウンタ
bcd_ss						;秒_BCD カウンタ
bcd_ww						;曜日_BCD カウンタ
temp_yh		;contrast_wk			;退避用 年(上位2桁)_BCD カウンタ
temp_yl		;temp_sleep_wk			;退避用 年(下位2桁)_BCD カウンタ
temp_nn		;buff: 変換文字列の格納エリア	;退避用 月_BCD カウンタ		;┐
temp_dd		;buff1				;退避用 日_BCD カウンタ		;│順序を変更しないこと!
temp_hh		;buff2				;仮の 時_BCD カウンタ		;┘
cur_yh						;年(上位2桁)(変)_BCD カウンタ
cur_yl						;年(下位2桁)(変)_BCD カウンタ
cur_nn						;月(変)_BCD カウンタ
cur_dd						;日(変)_BCD カウンタ
cur_week					;週位置カウンタ（曜日 0～6）
end_day						;各月の終了日（日数 28～31)
xxx_yh						; (改良)
uru_flag					;閏年フラグ
						; bit0: 0:平年/1:閏年

mode_flg					;モードフラグ
						; bit7: RTC DS3231 読み出し要求引継フラグ
						; bit5: スイッチ入力有りフラグ (メインルーチン)
						; bit4: 状態変化割り込み記憶フラグ
						; bit3: スリープ中状態フラグ
						; bit2: スリープ移行時間チェックフラグ
						; bit1: SETモードフラグ
						; bit0: 0:NORMALモード/1:LARGEモード
updt_flg					;更新フラグ
						; bit7: RTC DS3231 読み出し要求フラグ
						; bit6: 各項目の表示要求フラグ (SETモード)
						; bit5: SIGNAL メッセージフラグ
						; bit4: DOWN/UP メッセージフラグ
						; bit3: 年(上位)_更新フラグ
						; bit2: 年(下位)月_更新フラグ
						; bit1: 日_更新フラグ
						; bit0: 時分秒_更新フラグ
time_flg					;時間表示モードフラグ
						; bit7: bit0フラグの記憶 (SETモード時用)
						; bit1: 0:am/1:pm
						; bit0: 0:24H/1:12H
tcon_flg					;タイミング制御フラグ
						; bit7-4: 0.5秒単位ダウンカウンタ
						; bit3: カウント許可中フラグ
						; bit2: ブリンク制御動作中フラグ/カウント終了フラグ
						; bit1: 0.25秒ブリンクフラグ
						; bit0: 0.5秒/0.25秒経過表示フラグ
alm_flg						;アラーム音出力フラグ
						; bit7: アラーム音出力許可フラグ
						; bit3: 時報正報音フラグ
						; bit2: 時報予報音フラグ
						; bit1: タイマー一致音フラグ	   ;┐不使用
						; bit0: タイマー一致音継続中フラグ ;┘
save_flg					;(bcd_xx → temp_xx) 退避中表示フラグ
						; bit1: (temp_xx > bcd_xx) 大小フラグ
						; bit0: 退避中フラグ
sel_flg						;選択フラグ
						; bit7: 年(上位)フラグ
						; bit6: 年(下位)フラグ
						; bit5: 月フラグ
						; bit4: カレンダフラグ
						; bit3: 24H/12Hフラグ
						; bit2: 時フラグ
						; bit1: 分フラグ
						; bit0: 秒フラグ
tmem_flg					;タイマーメモリフラグ
						; bit7: タイマー処理フラグ, 0:終了/1:タイマー処理
						; bit6: 0:メモリREAD/1:メモリWRITE
						; bit5: mode_flg.bit0 の記憶フラグ
						; bit4: バックアップ要求フラグ
						; bit2: 書き込み無効フラグ
						; bit1: タイマー種類選択の中断フラグ
						; bit0: タイマー種類フラグ, 0:年タイマー/1:週間タイマー

slp_cnt_h					;スリープ移行時間カウンタ high
slp_cnt_l					;スリープ移行時間カウンタ low
sleep_time					;スリープまでの移行時間（分）
contrast					;OLED コントラスト
batt_count					;バッテリー電圧 測定間隔時間/表示時間カウンタ（秒）
tm_week						;曜日カウンタ
cont_byte					;コントロールバイト

const_high					;音階用分周定数 high の保存
const_low					;音階用分周定数 low の保存
wt1cnt						;ウェイト用ループカウンタ
wt2cnt						;ウェイト用ループカウンタ
wt3cnt						;ウェイト用ループカウンタ
lpcnt						;ループカウンタ
work1						;ワーク
work2						;ワーク

; (I2C_XS.sub で使用)
i2ctmp						;送受信データの一時保存
bit_cnt						;ループカウンタ
;wt1cnt				;既存レジスタ	;ループカウンタ

; (I2C_RTCII.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 アドレス

; (OLED_SSD1306.sub で使用)
pagex				;gl_y		;表示開始ページ / Y座標
end_pagex	;pagex_wk 			;表示終了ページ / 表示ページの退避ワーク
column				;gl_x		;表示開始カラム / X座標
end_column	;column_wk			;表示終了カラム / 表示カラムの退避ワーク
pattern				;wr_data	;水平ビット位置,垂直パターン / 書き込みデータ
echr_flg					;表示文字の機能拡張フラグ
						; bit7: ビット反転表示指示
						; bit6: 1 ビットずらし指示
oled_lpcnt					;ループカウンタ
		endc

		cblock	h'70'			;バンク 0（共通 RAM 領域）
f_lpcnt						;ループカウンタ
f_lpcnt2					;ループカウンタ2
ad_res_hi					;
ad_res_lo					;

addr_high					;読み出すデータの high アドレス
addr_low					;読み出すデータの low アドレス
dsp_cnt						;タイマー用メモリの表示カウンタ
valid_cnt					;タイマー用メモリの有効数カウンタ
		endc

		cblock	h'a0'			;バンク 1
a16_hi						;16ビット演算引き数Ａ(上位) 
a16_lo						;16ビット演算引き数Ａ(下位) 
b16_hi						;16ビット演算引き数Ｂ(上位)
b16_lo						;16ビット演算引き数Ｂ(下位)
lcnt1						;ループカウンタ / ワーク
lcnt2						;ループカウンタ
x16_hi						;div_16 答えの上位
x16_lo						;div_16 答えの下位
y16_hi						;div_16 余りの上位
y16_lo						;div_16 余りの下位
buff0						;変換文字列の格納エリア	;┐
buff1						;			;│
buff2						;			;│順序を変更しないこと!
buff3						;			;│
buff4						;			;┘
		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'			;(Page 0)
;--------------------------------------------------------------------------
;==========================================================================

;==========================================================================
;		プログラム開始
;==========================================================================

;		org	h'0000'			;リセットベクタ
		goto	initialize

;==========================================================================
;		割り込み処理
;==========================================================================

		org	h'0004'			;割り込みベクタ

; INTCON:   bit  7     6     5      4      3      2      1      0
;		GIE, PEIE, TMR0IE, INTE, IOCIE, TMR0IF, INTF, IOCIF

interrupt
		movlp	high $			;ページ 0
		movlb	0			;バンク 0

		; 割り込み処理の振り分け

		btfsc	INTCON,INTF		;INT 外部割り込みフラグ = 1 か？
		goto	ra2_int			;Yes

		btfsc	INTCON,TMR0IF		;タイマー０割り込みフラグ = 1 か？
		goto	tm0_int			;Yes

		btfsc	PIR1,TMR1IF		;タイマー１割り込みフラグ = 1 か？
		goto	tm1_int			;Yes

		btfsc	INTCON,IOCIF		;状態変化割り込みフラグ = 1 か？
		goto	ioc_int			;Yes

		goto	int_end			;(Illegal interrupt)

;---------------- 外部(RA2/INT)割り込み処理 -------------------------------

ra2_int		bcf	INTCON,INTF		;外部(RA2/INT)割り込みフラグをクリア
		bsf	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 1

		; スリープ移行時間カウンタの更新
		movf	sleep_time,W		;
		btfsc	STATUS,Z		;sleep_time = 0 か？
		goto	ra2i01			;Yes

		btfsc	mode_flg,3		;スリープ中状態フラグ = 1 か？
		goto	ra2i01			;Yes

		decf	slp_cnt_l,F		;slp_cnt_l - 1
		incf	slp_cnt_l,W		;
		btfsc	STATUS,Z		;slp_cnt_l - 1 < 0 か？
		decf	slp_cnt_h,F		;Yes. slp_cnt_h - 1
		bsf	mode_flg,2	;bit2	;スリープ移行時間チェックフラグ = 1

ra2i01		goto	int_end

;---------------- タイマー０割り込み処理 ----------------------------------

;	tcon_flg: タイミング制御フラグ
;			      >	bit7-4: 0.5秒単位ダウンカウンタ
;			      > bit3:   カウント許可中フラグ
;			      >	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

tm0_int		bcf	INTCON,TMR0IF		;タイマー０割り込みフラグをクリア
		movlw	tm0_h_val		;(4 / 8MHz) * 250 * 16(Prescaler) = 2000μS = 2 mS
		movwf	TMR0

		; 0.5秒/0.25秒 経過チェック
		decfsz	tm0_s_cnt,F		;ソフトタイマー０カウンタ - 1 = 0 か？
		goto	tm0i01			;No
		goto	tm0i03			;Yes

tm0i01		btfsc	mode_flg,1		;SETモードフラグ = 1 か？
		goto	tm0i02			;Yes

		btfss	tmem_flg,7		;タイマー処理フラグ = 1 か？
		goto	tm0i04			;No

tm0i02		movlw	tm0_s_val / 2		;=250/2, 2ms * 125 = 250ms
		subwf	tm0_s_cnt,W
		btfss	STATUS,Z		;tm0_s_cnt = tm0_s_val / 2 か？
		goto	tm0i04			;No

		bsf	tcon_flg,0	;bit0	;0.5秒/0.25秒経過表示フラグ = 1
		movlw	b'00000010'
		xorwf	tcon_flg,F	;bit1	;0.25秒ブリンクフラグ = 反点
		goto	tm0i04

		; 0.5秒 経過動作
tm0i03		movlw	tm0_s_val		;=250, 2ms * 250 = 500ms
		movwf	tm0_s_cnt		;ソフトタイマー０カウンタに設定

		bsf	tcon_flg,0	;bit0	;0.5秒/0.25秒経過表示フラグ = 1
		movlw	b'00000010'
		xorwf	tcon_flg,F	;bit1	;0.25秒ブリンクフラグ = 反点

		btfss	tcon_flg,3		;カウント許可中フラグ = 1 か？
		goto	tm0i04			;No

		; 0.5秒単位ダウンカウンタの更新
		movlw	h'10'
		subwf	tcon_flg,F	;bit7-4	;0.5秒単位ダウンカウンタ - 1

		movlw	h'f0'			;0.5秒単位ダウンカウンタを取り出す
		andwf	tcon_flg,W
		btfss	STATUS,Z		;0.5秒単位ダウンカウンタ = 0 か？
		goto	tm0i04			;No

		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込み許可 = 0
		clrf	tcon_flg		;
		bsf	tcon_flg,2	;bit2	;カウント終了フラグ = 1

tm0i04		goto	int_end

;---------------- タイマー１割り込み処理 ----------------------------------

tm1_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

;---------------- 状態変化割り込み処理 ------------------------------------

ioc_int		movlb	7			;バンク 7
		clrf	IOCAF			;状態変化割り込みフラグをクリアすると
		clrf	IOCCF			;INTCON レジスタの IOCIF ビットもクリアされる
		movlb	0			;バンク 0
		bcf	INTCON,IOCIE		;状態変化割り込み許可 = 0

		bsf	mode_flg,4	;bit4	;状態変化割り込み記憶フラグ = 1
;		goto	int_end

		; 割り込み処理の終了

int_end		retfie				;割り込みからの復帰	

;==========================================================================
;		サブルーチンファイルのインクルード
;==========================================================================

#define 	TRISX	TRISC			;PORTC で I2C を行う場合
#define 	PORTX	PORTC			;
#define 	_not_wait			;Fast mode で使用
#define 	_PIC16F1			;PIC16F1ファミリで使用

;				ドライブ、パス名は、各自の開発環境に合わせるように !!

		include		C:\Data\Project\PIC\_sub\I2C_XS.sub	;Ver.1.04 以上が必要
		include		C:\Data\Project\PIC\_sub\I2C_RTCII.sub	;Ver.1.04 以上が必要
		include		C:\Data\Project\PIC\_sub\OLED_SSD1306.sub

;==========================================================================
;		初期化処理
;==========================================================================

initialize
		clrf	STATUS			;STATUS クリア
	 	clrf	INTCON			;INTCON クリア

		; 内部クロックを 8 MHz に設定

		movlb	1			;バンク 1
		movlw	b'01110000'		;CLOCK=8MHz
		movwf	OSCCON

		; PORTA,PORTC ポートの各機能設定

		movlb	0			;バンク 0
		clrf	PORTA			;
		clrf	PORTC			;

		movlb	2			;バンク 2
		clrf	LATA			;
		clrf	LATC			;

		movlb	3			;バンク 3
		clrf	ANSELA			;すべて デジタル I/O ポート
		movlw	b'00000100'		;
		movwf	ANSELC			;RC2 のみアナログ入力ポート

		movlb	1			;バンク 1
		movlw	b'00111111'		;RA5-RA0:入力
		movwf	TRISA			;ポートA の I/0 設定
		movlw	b'00110100'		;RC5-RC4,RC2:入力, RC3,RC1-RC0:出力
		movwf	TRISC			;ポートC の I/0 設定

		movlb	4			;バンク 4
		movlw	b'00110011'		;RA5-RA4,RA1-RA0
		movwf	WPUA			;プルアップ有効
		movlw	b'00110000'		;RC5-RC4
		movwf	WPUC			;プルアップ有効

		movlb	7			;バンク 7
		movlw	b'00110011'		;RA5-RA4,RA1-RA0
		movwf	IOCAN			;ポートA の立ち下がりエッジ状態変化割り込み
		movlw	b'00110000'		;RC5-RC4
		movwf	IOCCN			;ポートC の立ち下がりエッジ状態変化割り込み

		; 固定参照電圧の設定

		movlb	2			;バンク 2
		movlw	b'10000010'
;			  ||||||||
;		bit1-0	  ||||||++----- ADFVR<1:0>: ADC FVRバッファゲイン選択ビット
;			  ||||||          11 = ADC FVRバッファゲインは4倍、出力VADFVR = 4x VFVR ... 固定参照電圧出力は
;			  ||||||      >   10 = ADC FVRバッファゲインは2倍、出力VADFVR = 2x VFVR ... VDDを超える事はできない
;			  ||||||          01 = ADC FVRバッファゲインは1倍、出力VADFVR = 1x VFVR
;			  ||||||          00 = ADC FVRバッファはOFF
;			  ||||||
;		bit3-2	  ||||++------- CDAFVR<1:0>: コンパレータFVRバッファゲイン選択ビット
;			  ||||            11 = コンパレータFVRバッファゲインは4倍、出力VCDAFVR = 4x VFVR
;			  ||||            10 = コンパレータFVRバッファゲインは2倍、出力VCDAFVR = 2x VFVR
;			  ||||            01 = コンパレータFVRバッファゲインは1倍、出力VCDAFVR = 1x VFVR
;			  ||||        >   00 = コンパレータFVRバッファはOFF
;			  ||||
;		bit4	  |||+--------- TSRNG: 温度インジケータ レンジ選択ビット
;			  |||             1 = VOUT = VDD - 4VT (Highレンジ)
;			  |||         >   0 = VOUT = VDD - 2VT (Lowレンジ)
;			  |||
;		bit5	  ||+---------- TSEN: 温度インジケータ イネーブルビット
;			  ||              1 = 温度インジケータを有効
;			  ||          >   0 = 温度インジケータを無効
;			  ||
;		bit6	  |+----------- FVRRDY: 固定参照電圧レディ フラグビット
;			  |               1 = 固定参照電圧出力は使える状態
;			  |               0 = 固定参照電圧出力の準備が整っていない(または無効)
;			  |
;		bit7	  +------------ FVREN: 固定参照電圧イネーブルビット
;			              >   1 = 固定参照電圧を有効
;			                  0 = 固定参照電圧を無効

		movwf	FVRCON			;FVRCON: 固定参照電圧制御レジスタ

		; ADC モジュールの設定

		movlb	1			;バンク 1
		movlw	b'00011000'
;			  ||||||||
;		bit0	  |||||||+----- ADON: ADCイネーブルビット
;			  |||||||         1 = ADCを有効
;			  |||||||     >   0 = ADCを無効、消費電流をゼロ
;			  |||||||          ____
;		bit1	  ||||||+------ GO/DONE: A/D変換ステータスビット
;			  ||||||          1 = A/D変換サイクルを実行中、このビットをセットするとA/D変換サイクルが開始
;			  ||||||              このビットは、A/D変換が完了するとハードウェアによって自動的にクリア
;			  ||||||      >   0 = A/D変換サイクルが完了(進行中でない)
;			  ||||||
;		bit6-2	  |+++++------- CHS<4:0>: アナログ チャンネル選択ビット
;			  |                 :
;			  |                 :
;			  |               00111 = AN7
;			  |           >   00110 = AN6
;			  |                 :
;			  |               00001 = AN1
;			  |               00000 = AN0
;			  |
;		bit7	  +------------ 未実装

		movwf	ADCON0			;ADCON0: ADC制御レジスタ0

		movlw	b'10010011'
;			  ||||||||
;		bit1-0	  ||||||++----- ADPREF<1:0>: ADC正側参照電圧コンフィグレーション ビット
;			  ||||||      >   11 = VREF+を内部の固定参照電圧(FVR)モジュールに接続
;			  ||||||          10 = VREF+を外部VREF+ピンに接続
;			  ||||||          01 = 予約済み
;			  ||||||          00 = VREF+をVDDに接続
;			  ||||||
;		bit2	  |||||+------- ADNREF: ADC負側参照電圧コンフィグレーション ビット
;			  |||||           1 = VREF-を外部VREF-ピンに接続
;			  |||||       >   0 = VREF-をVSSに接続
;			  |||||
;		bit3	  ||||+-------- 未実装
;			  ||||
;		bit6-4	  |+++--------- ADCS<2:0>: ADC変換クロック選択ビット
;			  |               111 = FRC(内部のRCオシレータから供給されるクロック)
;			  |               110 = FOSC/64
;			  |               101 = FOSC/16
;			  |               100 = FOSC/4
;			  |               011 = FRC(内部のRCオシレータから供給されるクロック)
;			  |               010 = FOSC/32
;			  |           >   001 = FOSC/8
;			  |               000 = FOSC/2
;			  |
;		bit7	  +------------ ADFM: A/D変換結果フォーマット選択ビット
;			              >   1 = 右詰め、変換結果を書き込むとADRESHの上位6ビットが「0」に設定
;			                  0 = 左詰め、変換結果を書き込むとADRESLの下位6ビットが「0」に設定

		movwf	ADCON1			;ADCON1: ADC制御レジスタ1

		; OPTION_REG の設定

		movlb	1			;バンク 1
		movlw	b'00000011'		;プルアップ有効、プリスケーラのスケール値 1:16
		movwf	OPTION_REG

		; 割り込みの設定

		bcf	PIE1,TMR1IE		;TMR1IE: タイマー１割り込みを許可 = 0

		movlb	0			;バンク 0
		movlw	b'00000001'		;TMR1CS<1:0>: bit7-6=00: Timer1クロック源=命令クロック(FOSC/4)を選択
						;T1CKPS<1:0>: bit5-4=00: プリスケーラ値を1:1
						;TMR1ON:      bit0=1:    Timer1を有効
		movwf	T1CON			;Timer1制御レジスタ

		movlw	b'11000000'		;GIE:    bit7=1: グローバル割り込みを許可 = 1
						;PEIE:   bit6=1: ペリフェラル割り込みを許可 = 1
						;TMR0IE: bit5=0: TMR0 オーバーフロー割り込み許可 = 0
						;INTE:   bit4=0: INT 外部割り込み許可 = 0
						;IOCIE:  bit3=0: 状態変化割り込み許可 = 0
		movwf	INTCON			;各割り込み要因の設定

;--------------------------------------------------------------------------

		call	buzzer_pipo		;"ピポッ" ブザー音出力

		; OLED ( SSD1306 ) モジュール の初期設定

		bsf	PORTC,SDA		;SDA="H"
		bsf	PORTC,SCL		;SCL="H"
	;;	bcf	PORTC,OLED_PW		;OLED 電源制御 ON 	<<<<<

		call	SSD1306_Init		;OLED ( SSD1306 ) モジュール の初期設定
		call	SSD1306_Clear		;OLED ( SSD1306 ) モジュール の画面消去

		; プログラムタイトルの表示と 縁枠のドット移動デモ表示

		movlp	high title_demo_display
		call	title_demo_display
		movlp	high $
		clrf	tcon_flg		;タイミング制御フラグの初期設定
		clrf	echr_flg		;表示文字の機能拡張フラグの初期設定
		clrf	mode_flg		;モードフラグの初期設定, (bit0=0:NORMALモード)

		; 引継ぎ情報（バックアップデータ）の読み出し
 
		movlp	high flash_mem_read	;フラッシュメモリから 
		call	flash_mem_read		;RAM バッファへデータ読み出しと
		movlp	high $			;RAM バッファから個々の変数へもコピー

		movf	contrast,W		;バックアップデータで
		call	SSD1306_Contrast	;OLED ( SSD1306 ) の コントラスト制御

;--------------------------------------------------------------------------
;		I2C RTC（DS3231）モジュールのチェック
;--------------------------------------------------------------------------

rtcinit01	Rtc_Read_M	cont_stat,1	;0Fh: Control/Status 読み出し
		btfss	cont_stat,7		;OSF = 1 か？
		goto	rtcinit04		;No

		; DS3231 RTC エラーメッセージの出力

		OLED_FontPos_M	4+6*2,4		;
		OLED_DispStr_M	rtc_err,1	;"DS3231 Error !"

		OLED_FontPos_M	4+6*10,6	;
		OLED_DispStr_M	,0		;"Init ?"

		call	buzzer_bubuu		;"ブッブー" ブザー音出力

		; ブリンク表示（タイマー０監視）

rtcinit02	call	oled_blink_chr		;ブリンク表示とタイミング制御

		call	any_sw_on_check		;どれかのスイッチ = ON をチェック
		btfsc	STATUS,Z		;どれかのスイッチ = ON か？
		goto	rtcinit02		;No

		call	blkchr2			;反転表示 (oled_blink_chr 内)

		; I2C RTC（DS3231）モジュールの初期設定

rtcinit03	call	I2cRtc_Init		;I2C RTC（DS3231）モジュールの初期設定
	;	movlw	h'20'			;
	;	movwf	bcd_yh			;年(上位2桁)_BCD カウンタ
		goto	rtcinit01

		; タイマー０監視の終了

rtcinit04	btfsc	tcon_flg,2		;ブリンク制御動作中フラグ = 1 か？
		bcf	INTCON,TMR0IE		;Yes. TMR0 オーバーフロー割り込み許可 = 0

		; 各変数の初期設定

		call	wait_1s			;1 秒間のウエイト

		clrf	tcon_flg		;タイミング制御フラグの初期設定
		clrf	sel_flg			;選択フラグの初期設定
		clrf	save_flg		;(bcd_xx → temp_xx) 退避中表示フラグの初期設定
		clrf	mode_flg		;モードフラグの初期設定, (bit0=0:NORMALモード)
		clrf	tmem_flg		;タイマーメモリフラグの初期設定
		clrf	alm_flg
		bsf	alm_flg,7		;アラーム音出力フラグの初期設定, (bit7=1:アラーム音出力有効)

		clrf	updt_flg
		call	clock_rtc_read		;RTC DS3231 から年月日、時分秒を読み出し
		bsf	updt_flg,1	   	;日_更新フラグ = 1
		bsf	updt_flg,2	   	;年(下位)月_更新フラグ = 1
		clrf	batt_count		;バッテリー電圧表示時間カウンタの初期設定

		bsf	INTCON,INTE		;外部(RA2/INT)割り込み許可 = 1
		goto	main

;--------------------------------------------------------------------------

;		RTC（DS3231）モジュールのエラーメッセージ

rtc_err		dt	   "DS3231 Error !"   ,0
		dt	           "Init ?"   ,0
;			 01234567890123456789

;--------------------------------------------------------------------------
;	    (横:6 x 縦:8) サイズのブリンク表示とタイミング制御
;--------------------------------------------------------------------------

;	tcon_flg: タイミング制御フラグ
;			       	bit7-4: 0.5秒単位ダウンカウンタ
;			       	bit3:   カウント許可中フラグ
;			      >	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;				bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

oled_blink_chr
		btfsc	tcon_flg,2		;ブリンク制御動作中フラグ = 1 か？
		goto	blkchr1			;Yes

		; タイミング制御の初期設定
		bsf	mode_flg,1		;SETモードフラグ = 1 (仮)
		clrf	tcon_flg
		bsf	tcon_flg,2	;bit2	;ブリンク制御動作中フラグ = 1
		bsf	tcon_flg,0	;bit0	;0.5秒/0.25秒経過表示フラグ = 1
		call	timer_500ms_set		;タイマー０の基本設定

blkchr1		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	blkchr3			;No

		; ブリンク表示
		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0

		bcf	echr_flg,7		;ビット反転表示指示 = 0
		btfsc	tcon_flg,1		;0.25秒ブリンクフラグ = 1 か？

blkchr2		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1

		OLED_FontPos_M	4+6*17,6	;ブリンク表示位置の指定
		movlw	a' '			;
		call	SSD1306_DispChr		;OLED へデータを１文字出力

blkchr3		return

;--------------------------------------------------------------------------
;		全スイッチで どれかのスイッチ = ON をチェック
;--------------------------------------------------------------------------

;		Z フラグ = 0: ON / Z フラグ = 1: OFF

any_sw_on_check
		movf	PORTA,W
		andlw	b'00110011'		;PORTA の全スイッチを読み取る
		xorlw	b'00110011'		;反転
		;           ^^  ^^
		btfss	STATUS,Z		;どれかのスイッチ = ON か？
		goto	allsw01			;Yes

		movf	PORTC,W
		andlw	b'00110000'		;PORTC の全スイッチを読み取る
		xorlw	b'00110000'		;反転
		;           ^^
allsw01		return

;--------------------------------------------------------------------------
;		RTC DS3231 から年月日、時分秒を読み出し
;--------------------------------------------------------------------------

;	updt_flg: 更新フラグ
;				bit7: RTC DS3231 読み出し要求フラグ
;				bit6: 各項目の表示要求フラグ (SETモード)
;				bit5: SIGNAL メッセージフラグ
;				bit4: DOWN/UP メッセージフラグ
;			      >	bit3: 年(上位)_更新フラグ
;			      >	bit2: 年(下位)月_更新フラグ
;			      >	bit1: 日_更新フラグ
;			      > bit0: 時分秒_更新フラグ

clock_rtc_read
		btfsc	mode_flg,1		;SETモードフラグ = 1 か？
		goto	clkrd01			;Yes

		Rtc_Read_M	seconds,7	;RTC DS3231 から年月日、時分秒を読み出し
		call	buffer_to_counter	;バッファからカウンタへコピー
		bsf	updt_flg,0		;時分秒_更新フラグ = 1

		movf	seconds,W		;Seconds: 00-59
		iorwf	minutes,W		;Minutes: 00-59
		iorwf	hours,W			;Hours:   00-23
		btfss	STATUS,Z		;Seconds = Minutes = Hours = 0 か？
		goto	clkrd01			;No

		bsf	updt_flg,1	   ;Yes	;日_更新フラグ = 1
		decf	date,W
		btfss	STATUS,Z		;Date - 1 = 0 か？
		goto	clkrd01			;No

		bsf	updt_flg,2	   ;Yes	;年(下位)月_更新フラグ = 1
		btfss	month,7			;Century ビット = 1 か？
		goto	clkrd01			;No

		bsf	updt_flg,3	   ;Yes	;年(上位)_更新フラグ = 1
		call	xbcd_yh_inc		;年(上位)_BCD カウンタのインクリメント

clkrd01		return

;--------------------------------------------------------------------------
;		バッファと BCD カウンタ間のデータ移動
;--------------------------------------------------------------------------

		; バッファからカウンタへコピー

buffer_to_counter
		movlw	high seconds		;RTC バッファの先頭アドレス
		movwf	FSR1H			;
		movlw	low seconds		;
		movwf	FSR1L			;

		moviw	FSR1++			;Seconds
		movwf	bcd_ss			;秒_BCD カウンタ

		moviw	FSR1++			;Minutes
		movwf	bcd_mm			;分_BCD カウンタ

		moviw	FSR1++			;Hours
		movwf	bcd_hh			;時_BCD カウンタ

		btfsc	save_flg,0	;;;	;(bcd_xx → temp_xx) 退避中表示フラグ = 1 か？
		goto	btc01			;Yes

		moviw	FSR1++			;Day
		movwf	bcd_ww			;曜日_BCD カウンタ

		moviw	FSR1++			;Date
		movwf	bcd_dd			;日_BCD カウンタ

		moviw	FSR1++			;Month
		andlw	h'1f'			;
		movwf	bcd_nn			;月_BCD カウンタ

		moviw	FSR1++			;Year
		movwf	bcd_yl			;年(下位)_BCD カウンタ

btc01		return

;--------------------------------------------------------------------------

		; カウンタからバッファへコピー

counter_to_buffer
		movlw	high seconds		;RTC バッファの先頭アドレス
		movwf	FSR1H			;
		movlw	low seconds		;
		movwf	FSR1L			;

		movf	bcd_ss,W		;秒_BCD カウンタ
		movwi	FSR1++			;Seconds

		movf	bcd_mm,W		;分_BCD カウンタ
		movwi	FSR1++			;Minutes

		movf	bcd_hh,W		;時_BCD カウンタ
		movwi	FSR1++			;Hours

		movf	bcd_ww,W		;曜日_BCD カウンタ
		movwi	FSR1++			;Day

		movf	bcd_dd,W		;日_BCD カウンタ
		movwi	FSR1++			;Date

		movf	bcd_nn,W		;月_BCD カウンタ
		movwi	FSR1++			;Month

		movf	bcd_yl,W		;年(下位)_BCD カウンタ
		movwi	FSR1++			;Year
		return


;==========================================================================
;		メイン・ルーチン
;==========================================================================

;	[スイッチ操作]
;			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │●│   │●│   │●│   │●│   │●│   │●│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

;		MODE スイッチ        ..... NORMAL モード / LARGE モードの切り替え
;
;		MODE スイッチ 長押し ..... SET モードに移行（３秒以上の長押し）
;		(SET スイッチ)

;		  UP スイッチ        ..... カレンダーめくり機能（１か月前に進める）
;					 （ LARGE モード中は無視）

;		  UP スイッチ 長押し ..... 24時間表示 / 12時間表示の切り替え（３秒以上の長押し）
;	      (TMODE スイッチ)

;		DOWN スイッチ        ..... カレンダーめくり機能（１か月後に進める）
;					 （ LARGE モード中は無視）

;		DOWN スイッチ 長押し ..... メンテナンス機能に移行（３秒以上の長押し）
;	     (MAINTE スイッチ)		 （カレンダーめくり機能中はカレンダーめくり機能）

;		ZERO スイッチ        ..... 毎正時プラス・マイナス５分以内を 00分00秒に設定
;					 （５分以外では無視）

;	       TIMER スイッチ        ..... タイマーメモリの読み出し

;	       TIMER スイッチ 長押し ..... タイマーメモリの設定（３秒以上の長押し）
;	      (TMSET スイッチ)

;	      SIGNAL スイッチ        ..... 毎時の時報音出力を ON/OFF 制御

;	mode_flg: モードフラグ
;			      >	bit7: RTC DS3231 読み出し要求引継フラグ
;			      >	bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;			      >	bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;			      >	bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	updt_flg: 更新フラグ
;			      >	bit7: RTC DS3231 読み出し要求フラグ
;				bit6: 各項目の表示要求フラグ (SETモード)
;				bit5: SIGNAL メッセージフラグ
;			      >	bit4: DOWN/UP メッセージフラグ
;				bit3: 年(上位)_更新フラグ
;			      >	bit2: 年(下位)月_更新フラグ
;			      >	bit1: 日_更新フラグ
;			      >	bit0: 時分秒_更新フラグ

;	tcon_flg: タイミング制御フラグ
;			      >	bit7-4: 0.5秒単位ダウンカウンタ
;			      >	bit3:   カウント許可中フラグ
;			      >	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;				bit1:   0.25秒ブリンクフラグ
;				bit0:   0.5秒/0.25秒経過表示フラグ

main
		; RTC DS3231 読み出し, 画面の表示, 時報音出力コントロール

		call	SSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去
		movlp	high week_display
		call	week_display		;曜日タイトルの表示
		movlp	high $

main01		btfss	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 1 か？
		goto	main02			;No

		call	clock_rtc_read	   ;Yes	;RTC DS3231 から年月日,時分秒を読み出し
		call	time_alarm_control	;時報音、タイマー一致音フラグコントロール
		bcf	updt_flg,7	;;;	;RTC DS3231 読み出し要求フラグ = 0
		bsf	mode_flg,7		;RTC DS3231 読み出し要求引継フラグ = 1

main02		btfss	updt_flg,0		;時分秒_更新フラグ = 1 か？
		goto	main03			;No

		call	xtime_ampm_display ;Yes	;時分秒 (hh:mm:ss), (  /am/pm) の表示
		bcf	updt_flg,0		;時分秒_更新フラグ = 0

main03		btfss	updt_flg,2		;年(下位)月_更新フラグ = 1 か？
		goto	main04			;No

		movlp	high yyyymm_display
		call	yyyymm_display	   ;Yes	;年月 (yyyy/mm) の表示
		movlp	high $
		bcf	updt_flg,2		;年(下位)月_更新フラグ = 0

main04		btfss	updt_flg,1		;日_更新フラグ = 1 か？
		goto	main05			;No

		movlp	high calendar_display
		call	calendar_display   ;Yes	;カレンダーの表示
		movlp	high $
		bcf	updt_flg,1		;日_更新フラグ = 0

main05		btfsc	updt_flg,4		;DOWN/UP メッセージフラグ = 1 か？
		call	down_up_display	   ;Yes	;←DOWN/UP→ メッセージの表示
		bcf	updt_flg,4		;DOWN/UP メッセージフラグ = 0

		; スリープモードからウエイクアップ後の 10 秒間バッテリー電圧表示
		; （updt_flg.7 を使用すると、秒の表示更新がときどき切れる → mode_flg.7 に変更）

		btfss	mode_flg,7		;RTC DS3231 読み出し要求引継フラグ = 1 か？
		goto	main09			;No

		bcf	mode_flg,7		;RTC DS3231 読み出し要求引継フラグ = 0
		movf	batt_count,W		;
		btfsc	STATUS,Z		;バッテリー電圧表示時間カウンタ = 0 か？
		goto	main09			;Yes

		decf	batt_count,F		;batt_count - 1
		btfsc	STATUS,Z		;バッテリー電圧表示時間カウンタ = 0 か？
		goto	main06			;Yes

		movf	batt_count,W		;
		sublw	10
		btfss	STATUS,Z		;バッテリー電圧表示時間カウンタ = 10 か？
		goto	main09			;No

		btfsc	mode_flg,0		;bit0: 1:LARGEモード か？
		call	large_display_shift	;Yes. LARGE モード時の１行（ページ）上方にずらし表示

		movlp	high battery_volt__display2
		call	battery_volt__display2	;バッテリーの電圧測定と表示
		movlp	high $
		goto	main09

main06		btfss	mode_flg,0		;bit0: 1:LARGEモード か？
		goto	main07			;No

		call	large_display_shift	;Yes. LARGE モード時の１行（ページ）上方にずらし表示を元に戻す
		goto	main09

main07		OLED_FontPos_M	3+6*8,7		;バッテリー電圧表示をクリア
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		call	rev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		movlw	12
		movwf	lpcnt			;ループカウンタ

main08		movlw	' '
		call	SSD1306_DispChr		;OLED へ１文字出力
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	main08			;No

		btfsc	save_flg,0		;(bcd_xx → temp_xx) 退避中フラグ = 1 か？
		bsf	updt_flg,4		;Yes
main09

		call	alarm_sound		;時報音、タイマー一致音のアラーム出力

		; 各スイッチの入力チェック

		btfss	PORTA,_swMOD		;MODE / SETスイッチ = ON か？
		call	mode_set_switch		;Yes. MODE / SET スイッチの処理

		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		call	up_switch		;Yes. UP スイッチの処理

		btfss	PORTA,_swDWN		;DOWN スイッチ = ON か？
		call	down_switch		;Yes. DOWN スイッチの処理

		btfss	PORTA,_swZER		;ZERO スイッチ = ON か？
		call	zero_switch		;Yes. ZERO スイッチの処理

		btfsc	PORTC,_swTIM		;TIMER スイッチ = ON か？
		goto	main10			;No

		movlp	high timer_switch
		call	timer_switch		;Yes. TIMER スイッチの処理
		movlp	high $

main10		btfss	PORTC,_swSIG		;SIGNAL スイッチ = ON か？
		call	signal_switch	;	;Yes. SIGNAL スイッチの処理
					;	;
		call	sig_disp_clear	;	;表示時間の監視とメッセージクリア

		btfss	mode_flg,5		;スイッチ入力有りフラグ = 1 か？
		goto	main11			;No

		; スリープ移行時間カウンタ（slp_cnt_h:slp_cnt_l）の初期設定

		movf	sleep_time,W		;スリープまでの移行時間（分）
		call	mul8x8_16		;8 x 8 ビット = 16 ビットの乗算

		bcf	mode_flg,5		;スイッチ入力有りフラグ = 0
		btfsc	updt_flg,5		;SIGNAL メッセージフラグ = 1 か？
		goto	main01			;Yes
		goto	main12			;No

		; スリープ移行時間の監視（60 x sleep_time 秒）

main11		call	sleep_control		;時間の監視とスリープモードに移行
		btfss	mode_flg,3		;スリープ中状態フラグ = 1 か？
		goto	main01			;No

		movlw	10 + 1
		movwf	batt_count		;バッテリー電圧表示時間カウンタ = 10 + 1

main12		btfsc	save_flg,0		;(bcd_xx → temp_xx) 退避中フラグ = 1 か？
		bsf	updt_flg,4		;Yes

		movlw	h'01'			;bit0: 0:NORMALモード/1:LARGEモード
		andwf	mode_flg,F		;を残して他のビットはクリアする

		movlw	h'07'	;h'0f'
		iorwf	updt_flg,F
		goto	main

;==========================================================================
;	      UP スイッチの処理 ... メイン・ルーチンから CALL
;==========================================================================

;	[スイッチ操作]

;		  UP スイッチ        ..... カレンダーめくり機能（１か月前に進める）
;					 （ LARGE モード中は無視）

;		  UP スイッチ 長押し ..... 24時間表示 / 12時間表示の切り替え（３秒以上の長押し）
;	      (TMODE スイッチ)

up_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swUP		;再度 UP スイッチ = ON か？
		goto	upsw05			;No

		bsf	mode_flg,5		;スイッチ入力有りフラグ = 1

		; ３秒間長押しの監視 = (4/8Mz*250*16=2msec) * 250 * 6 = 3,000 ms
		call	timer_3sec_set		;３秒間タイマーの設定

upsw01		call	display_update		;RTC DS3231 読み出しと 表示の更新

		btfsc	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	upsw03			;Yes. 24/12時間表示の切り替え

		btfss	PORTA,_swUP		;UP スイッチ = OFF か？
		goto	upsw01			;No

		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止
		clrf	tcon_flg		;タイミング制御フラグをクリア

		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	upsw04			;No. 1:LARGEモード

		; カレンダーめくり機能
		btfss	save_flg,0		;(bcd_xx → temp_xx) 退避中表示フラグ = 1 か？
		call	date_save		;No. 年(上位2桁), 年(下位2桁), 月, 日_BCD カウンタの退避

		call	xbcd_nn_inc		;月_BCD カウンタのインクリメント
		movlw	h'01'
		subwf	bcd_nn,W
		btfss	STATUS,Z		;月_BCD カウンタ = h'01' か？
		goto	upsw02			;No

		movlp	high bcd_yyyy_inc
		call	bcd_yyyy_inc		;年(4桁)_BCD カウンタのインクリメント
		movlp	high $

upsw02		call	date_check		;退避チェック
		goto	upsw04

		; 24時間表示 / 12時間表示 の切り替え
upsw03		clrf	tcon_flg		;タイミング制御フラグをクリア
		movlw	h'01'
		xorwf	time_flg,F		;時間表示フラグ(bit0: 0:24H/1:12H)の更新
		call	xtime_ampm_display	;時分秒 (hh:mm:ss), (  /am/pm) の表示

		call	buzzer_pi		;"ピッ" ブザー音

upsw04		btfss	PORTA,_swUP		;UP スイッチ = OFF か？
		goto	$ - 1			;No

upsw05		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------

		; ３秒間タイマーの設定 = (4/8Mz*250*16=2msec) * 250 * 6 = 3,000 ms

timer_3sec_set
		movlw	h'60'			;6
		movwf	tcon_flg	;bit7-4	;0.5秒単位ダウンカウンタ = 6 (0.5 * 6 = 3 秒) をセット
		bsf	tcon_flg,3	;bit3	;カウント許可中フラグ = 1

		; タイマー０の基本設定= (4/8Mz*250*16=2msec) * 250 = 500 ms

timer_500ms_set
		movlw	tm0_s_val		;ソフトタイマー０カウント値 = 250 (= 2ms * 250 = 500ms)
		movwf	tm0_s_cnt		;ソフトタイマー０カウンタに設定
		movlw	tm0_h_val		;(4 / 8MHz) * 250 * 16(Prescaler) = 2000μS = 2 mS
		movwf	TMR0			;TMR0 に設定
		bsf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを許可
		return

;--------------------------------------------------------------------------

;		RTC DS3231 読み出しと 表示の更新

display_update
		btfss	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 1 か？
		goto	dspup01			;No

		call	clock_rtc_read		;Yes. RTC DS3231 から年月日,時分秒を読み出し
		bcf	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 0

		call	xtime_ampm_display	;時分秒 (hh:mm:ss), (  /am/pm) の表示

dspup01		return

;==========================================================================
;	     DOWN スイッチの処理 ... メイン・ルーチンから CALL
;==========================================================================

;	[スイッチ操作]

;		DOWN スイッチ        ..... カレンダーめくり機能（１か月後に進める）
;					 （ LARGE モード中は無視）

;		DOWN スイッチ 長押し ..... メンテナンス機能に移行（３秒以上の長押し）
;	     (MAINTE スイッチ)		 （カレンダーめくり機能中はカレンダーめくり機能）

down_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swDWN		;再度 DOWN スイッチ = ON か？
		goto	dwnsw05			;No

		bsf	mode_flg,5		;スイッチ入力有りフラグ = 1

		; ３秒間長押しの監視 = (4/8Mz*250*16=2msec) * 250 * 6 = 3,000 ms
		call	timer_3sec_set		;３秒間タイマーの設定

dwnsw01		call	display_update		;RTC DS3231 読み出しと 表示の更新

		btfss	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	dwnsw02			;No

		btfss	save_flg,0		;(bcd_xx → temp_xx) 退避中表示フラグ = 1 か？
		goto	dwnsw06			;No. メンテナンス機能に移行

dwnsw02		btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
		goto	dwnsw01			;No
;
		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止
		clrf	tcon_flg		;タイミング制御フラグをクリア

		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	dwnsw04			;No. 1:LARGEモード

		; カレンダーめくり機能
		btfss	save_flg,0		;(bcd_xx → temp_xx) 退避中表示フラグ = 1 か？
		call	date_save		;No. 年(上位2桁), 年(下位2桁), 月, 日_BCD カウンタの退避

		call	xbcd_nn_dec		;月_BCD カウンタのデクリメント
		movlw	h'12'
		subwf	bcd_nn,W
		btfss	STATUS,Z		;月_BCD カウンタ = h'12' か？
		goto	dwnsw03			;No

		movlp	high bcd_yyyy_dec
		call	bcd_yyyy_dec		;年(4桁)_BCD カウンタのデクリメント
		movlp	high $

dwnsw03		call	date_check		;退避チェック

dwnsw04		btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
		goto	$ - 1			;No

dwnsw05		call	wait_15ms		;チャッタリング吸収
		return

		; メンテナンス機能に移行準備

dwnsw06		btfss	mode_flg,0		;bit0: 1:LARGEモード か？
		goto	dwnsw07			;No. 0:NORMALモード

		bsf	mode_flg,1		;SETモードフラグ = 1 (仮に設定)
		call	large_display_shift	;LARGE モード時の１行（ページ）上方にずらし表示
		bcf	mode_flg,1		;SETモードフラグ = 0 (仮を解除)

dwnsw07		OLED_FontPos_M	3+6*9,7		;
		movlw	h'f0'
		movwf	echr_flg		;表示文字の機能拡張フラグのクリア
		call	rev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		movlw	high (mainte_msg + 4)	;文字列の先頭 high アドレス
		movwf	FSR0H			;
		movlw	low (mainte_msg + 4)	;文字列の先頭 low アドレス
		movwf	FSR0L			;
		movlw	11
		movwf	lpcnt			;ループカウンタ

dwnsw08		call	str_read		;文字列データの読み出し (SSD1306_DispStr 内)
		movlp	high $			;この場所の high アドレス
		addfsr	FSR0,1			;間接アドレス FSR0H:FSR0L + 1

		call	SSD1306_DispChr		;OLED へデータを１文字出力
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	dwnsw08			;No

		call	buzzer_pi		;"ピッ" ブザー音

		btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収
		clrf	tcon_flg		;タイミング制御フラグをクリア
		call	maintenance		;メンテナンス機能
		return

;--------------------------------------------------------------------------
;		年(上位2桁), 年(下位2桁), 月, 日_BCD カウンタ の退避
;--------------------------------------------------------------------------

date_save
		movf	bcd_yh,W		;年(上位2桁)_BCD カウンタ
		movwf	temp_yh			;退避用 年(上位2桁)_BCD カウンタ
		movf	bcd_yl,W		;年(下位2桁)_BCD カウンタ
		movwf	temp_yl			;退避用 年(下位2桁)_BCD カウンタ
		movf	bcd_nn,W		;月_BCD カウンタ
		movwf	temp_nn			;退避用 月_BCD カウンタ
		movf	bcd_dd,W		;日_BCD カウンタ
		movwf	temp_dd			;退避用 日_BCD カウンタ
		bsf	save_flg,0		;退避中フラグ = 1
		return

;--------------------------------------------------------------------------
;	年(上位2桁), 年(下位2桁), 月, 日_BCD カウンタ の退避チェック
;--------------------------------------------------------------------------

;	save_flg: (bcd_xx → temp_xx) 退避中表示フラグ

;			      >	bit1: (temp_xx > bcd_xx) 大小フラグ
;			      >	bit0: 退避中フラグ

date_check
		movf	temp_yh,W		;退避用 年(上位2桁)_BCD カウンタ
		subwf	bcd_yh,W
		btfss	STATUS,C		;年(上位2桁)_BCD カウンタ >= 退避用 か？
		goto	dtck01			;No. <

		btfss	STATUS,Z		;年(上位2桁)_BCD カウンタ = 退避用 か？
		goto	dtck02			;No. >

		movf	temp_yl,W		;退避用 年(下位2桁)_BCD カウンタ
		subwf	bcd_yl,W
		btfss	STATUS,C		;年(下位2桁)_BCD カウンタ >= 退避用 か？
		goto	dtck01			;No. <

		btfss	STATUS,Z		;年(下位2桁)_BCD カウンタ = 退避用 か？
		goto	dtck02			;No. >

		movf	temp_nn,W		;退避用 月_BCD カウンタ
		subwf	bcd_nn,W
		btfss	STATUS,C		;月_BCD カウンタ >= 退避用 か？
		goto	dtck01			;No. <

		btfss	STATUS,Z		;月_BCD カウンタ = 退避用 か？
		goto	dtck02			;No. >

		movf	temp_dd,W		;退避用 日_BCD カウンタ
		subwf	bcd_dd,W
		btfss	STATUS,C		;日_BCD カウンタ >= 退避用 か？
		goto	dtck01			;No. <

		btfss	STATUS,Z		;日_BCD カウンタ = 退避用 か？
		goto	dtck02			;No. >

		clrf	save_flg		;(bcd_xx → temp_xx) 退避中表示フラグのクリア
		goto	dtck03

dtck01		bcf	save_flg,1		;(temp_xx > bcd_xx) 大小フラグ = 0
		goto	dtck03

dtck02		bsf	save_flg,1		;(temp_xx > bcd_xx) 大小フラグ = 1

dtck03		bsf	updt_flg,4		;DOWN/UP メッセージメッセージフラグ = 1
		return

;--------------------------------------------------------------------------
;		DOWN/UP スイッチの 操作中メッセージの表示
;--------------------------------------------------------------------------

down_up_display
		; メッセージエリアのクリア
		movlw	3 + 6 * 11
		movwf	column			;表示先頭カラム
		movlw	1 + 6 * 9
		movwf	oled_lpcnt		;ループカウンタ

		btfss	save_flg,0		;退避中フラグ = 1 か？
		clrf	sel_flg			;No
		call	area_reverse		;メッセージエリアのクリア

		btfss	save_flg,0		;退避中フラグ = 1 か？
		goto	dwnup01			;No

		; DOWN メッセージの表示
		btfss	save_flg,1		;(temp_xx > bcd_xx) 大小フラグ = 0:(bcd_xx < temp_xx) か？
		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1
		bsf	echr_flg,6		;1 ビットずらし指示 = 1

		OLED_FontPos_M	3+6*11,7	;DOWN メッセージの表示開始位置
		call	rev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		OLED_DispStr_M	down_up_msg,1	;メッセージ文字列の表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0

		; UP メッセージの表示
		btfsc	save_flg,1		;(temp_xx > bcd_xx) 大小フラグ = 1:(bcd_xx > temp_xx) か？
		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1
;		bsf	echr_flg,6		;1 ビットずらし指示 = 1

		OLED_FontPos_M	3+6*17,7	;UP メッセージの表示開始位置
		call	rev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		OLED_DispStr_M	,0		;メッセージ文字列の表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0

dwnup01		return

		; DOWN/UP メッセージ・テーブル

down_up_msg	dt	h'7f',"Down",0
			; ←
		dt	"Up",h'7e',0
			;      →

;--------------------------------------------------------------------------
;		メッセージエリアの白黒反転クリア
;--------------------------------------------------------------------------

;入力:		sel_flg:	;選択フラグ, sel_flg = h'00'    のとき h'00'クリア
;					     sel_flg = h'00'以外のとき h'fe'クリア
;		column:		;表示先頭カラム
;		oled_lpcnt:	;ループカウンタ

area_reverse
		movlw	7
		movwf	pagex			;表示ページ
		call	SSD1306_FontPos		;メッセージエリアの先頭位置

		call	i2c_start		;スタートコンディション
		movlw	SSD1306_Addr << 1	;スレーブアドレス
		call	i2c_byte_send		;1 バイト送信
		movlw	h'40'			;Control byte Co=0, D/C#=1
		call	i2c_byte_send		;1 バイト送信

		movf	sel_flg,W		;
		btfss	STATUS,Z		;h'00' クリア処理 か？
		movlw	h'fe'			;No. 白黒反転
		movwf	pattern			;ワーク

arev01		movf	pattern,W		;ワーク
		call	i2c_byte_send		;1 バイト送信
		decfsz	oled_lpcnt,F		;ループカウンタ - 1 = 0 か？
		goto	arev01			;No

		call	i2c_stop		;ストップコンディション
		return

;--------------------------------------------------------------------------
;		h'00' / h'7f' / h'fe' データ１バイト出力
;--------------------------------------------------------------------------

rev_shift_byte
		call	i2c_start		;スタートコンディション
		movlw	SSD1306_Addr << 1	;スレーブアドレス
		call	i2c_byte_send		;1 バイト送信
		movlw	h'c0'			;Control byte Co=1, D/C#=1
		call	i2c_byte_send		;1 バイト送信

		clrw				;文字間 h'00' 1 バイト追加
		btfsc	echr_flg,7		;ビット反転表示指示 か？
		movlw	h'7f'			;Yes. ビット反転
		movwf	pattern			;ワークに一時退避
		btfsc	echr_flg,6		;1 bit 左(下)ずらし指示 か？
		lslf	pattern,F		;Yes. ビットずらし

		movf	pattern,W		;ワーク
		call	i2c_byte_send		;1 バイト送信
		call	i2c_stop		;ストップコンディション
		return

;==========================================================================

;--------------------------------------------------------------------------
;		データ１バイト出力（デモ用サブルーチン内で使用）
;--------------------------------------------------------------------------

;入力:		W reg:	表示データ

data_byte
		movwf	work2			;ワークに一時退避, (変数 pattern 使用は禁止)

		call	i2c_start		;スタートコンディション
		movlw	SSD1306_Addr << 1	;スレーブアドレス
		call	i2c_byte_send		;1 バイト送信
		movlw	h'c0'			;Control byte Co=1, D/C#=1
		call	i2c_byte_send		;1 バイト送信

		movf	work2,W			;データバイトを復帰
		call	i2c_byte_send		;1 バイト送信
		call	i2c_stop		;ストップコンディション
		return

;--------------------------------------------------------------------------
;	    カレンダー / タイマーメモリ 表示エリアの h'00'クリア
;--------------------------------------------------------------------------

calend_area_clear
tmdisp_area_clear
		movlw	high calend_area_table	;カレンダーテーブルデータの先頭 high アドレス
		movwf	FSR1H			;
		movlw	low calend_area_table	;カレンダーテーブルデータの先頭 low アドレス
		movwf	FSR1L			;
		movlw	calend_area_table_end - calend_area_table
		movwf	oled_lpcnt		;ループカウンタ

		call	oledini00		;(SSD1306_Init 内)
;
		call	i2c_start		;スタートコンディション
		movlw	SSD1306_Addr << 1	;スレーブアドレス
		call	i2c_byte_send		;1 バイト送信
		movlw	h'40'			;Control byte Co=0, D/C#=1
		call	i2c_byte_send		;1 バイト送信

		movlw	high (128 * 6)		;= high 768
		btfsc	tmem_flg,7		;タイマー処理フラグ = 1 か？
		movlw	high (128 * 4)		;= high 512
		movwf	FSR1H
		movlw	low (128 * 6)		;= low 768
		btfsc	tmem_flg,7		;タイマー処理フラグ = 1 か？
		movlw	low (128 * 4)		;= low 512
		movwf	FSR1L			;ループカウンタ

calclr01	clrw				;h'00'
		call	i2c_byte_send		;1 バイト送信
		addfsr	FSR1,-1			;ループカウンタ - 1

		movf	FSR1H,W			;
		iorwf	FSR1L,W			;
		btfss	STATUS,Z		;FSR1H = FSR1L = h'00' か？	
		goto	calclr01		;No

		call	i2c_stop		;ストップコンディション
		return

		; カレンダー表示エリアの h'00'クリア用コマンドデータ・テーブル

calend_area_table
		dt	SSD1306_Addr << 1	;スレーブアドレス
		dt	h'00'			;Control byte Co=0, D/C#=0

		dt	h'20'			;Set Memory Addressing Mode
		dt	h'00'			;Horizontal Addressing Mode

		dt	h'21'			;Set Column Address　カラムアドレスの設定
		dt	0			;Column start address, range: 0-127
		dt	127			;Column end address,   range: 0-127

		dt	h'22'			;Set Page Address　ページアドレスの設定
		dt	2			;Page start Address, range: 0-7
		dt	7			;Page end Address,   range: 0-7
calend_area_table_end


;==========================================================================
;	     ZERO スイッチの処理 ... メイン・ルーチンから CALL
;==========================================================================

;	[スイッチ操作]

;		ZERO スイッチ        ..... 毎正時プラス・マイナス５分以内を 00分00秒に設定
;					 （５分以外では無視）

zero_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swZER		;再度 ZERO スイッチ = ON か？
		goto	zersw04			;No

		bsf	mode_flg,5		;スイッチ入力有りフラグ = 1

		movlw	h'05'
		subwf	bcd_mm,W
		btfsc	STATUS,C		;分_BCD カウンタ < h'05' か？
		goto	zersw01			;No

		; 分_BCD カウンタ < h'05' のとき
		bcf	INTCON,INTE		;外部(RA2/INT)割り込み許可 = 0:禁止
		goto	zersw03			;更新

zersw01		movlw	h'55'
		subwf	bcd_mm,W
		btfss	STATUS,C		;分_BCD カウンタ >= h'55' か？
		goto	zersw03			;No. 無視
;
		; 分_BCD カウンタ >= h'55' のとき
		bcf	INTCON,INTE		;外部(RA2/INT)割り込み許可 = 0:禁止
		call	xbcd_hh_inc		;時_BCD カウンタのインクリメント
		movf	bcd_hh,W
		btfss	STATUS,Z		;時_BCD カウンタ = h'00' か？
		goto	zersw03			;No

		call	xbcd_dd_inc		;日_BCD カウンタのインクリメント
		movlw	h'01'
		subwf	bcd_dd,W
		btfss	STATUS,Z		;日_BCD カウンタ = h'01' か？
		goto	zersw02			;No

		call	xbcd_nn_inc		;月_BCD カウンタのインクリメント
		movlw	h'01'
		subwf	bcd_nn,W
		btfss	STATUS,Z		;月_BCD カウンタ = h'01' か？
		goto	zersw02			;No

		movlp	high bcd_yyyy_inc
		call	bcd_yyyy_inc		;年(4桁)_BCD カウンタのインクリメント
		movlp	high $

zersw02		call	xday_week		;該当日の曜日を取得
		movwf	bcd_ww			;曜日_BCD カウンタ
;
zersw03		btfss	PORTA,_swZER		;ZERO スイッチ = OFF か？
		goto	$ - 1			;No

		btfsc	INTCON,INTE		;外部(RA2/INT)割り込み許可 = 0 か？
		goto	zersw04			;No

		; RTC（DS3231）モジュールの更新と High-Endurance フラッシュメモリの更新
		clrf	bcd_mm			;分_BCD カウンタのクリア
		clrf	bcd_ss			;秒_BCD カウンタのクリア
		call	counter_to_buffer
		Rtc_Write_M  seconds,7		;RTC DS3231 へ年月日、時分秒を書き込み

		call	xflash_mem_erase_write	;フラッシュメモリの消去とデータ書き込み

		bsf	INTCON,INTE		;外部(RA2/INT)割り込み許可 = 1:禁止解除
		call	buzzer_pipi		;"ピピッ" ブザー音, (更新時)

zersw04		call	wait_15ms		;チャッタリング吸収
		return

;==========================================================================
;	    SIGNAL スイッチの処理 ... メイン・ルーチンから CALL
;==========================================================================

;	[スイッチ操作]

;	      SIGNAL スイッチ        ..... 毎時の時報音出力を ON/OFF 制御

;	mode_flg: モードフラグ
;			      >	bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;			      >	bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	updt_flg: 更新フラグ
;				bit7: RTC DS3231 読み出し要求フラグ
;				bit6: 各項目の表示要求フラグ (SETモード)
;			      >	bit5: SIGNAL メッセージフラグ
;				bit4: DOWN/UP メッセージフラグ
;				bit3: 年(上位)_更新フラグ
;			      >	bit2: 年(下位)月_更新フラグ
;			      >	bit1: 日_更新フラグ
;			      >	bit0: 時分秒_更新フラグ

;	tcon_flg: タイミング制御フラグ
;			      >	bit7-4: 0.5秒単位ダウンカウンタ
;			      > bit3:   カウント許可中フラグ
;			      >	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;				bit1:   0.25秒ブリンクフラグ
;				bit0:   0.5秒/0.25秒経過表示フラグ

;	alm_flg: アラーム音出力フラグ
;			      >	bit7: アラーム音出力許可フラグ
;				bit6: アラーム音出力済みフラグ
;				bit3: 時報正報音フラグ
;				bit2: 時報予報音フラグ
;				bit1: タイマー一致音フラグ
;				bit0: タイマー一致音継続中フラグ

signal_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTC,_swSIG		;再度 SIGNAL スイッチ = ON か？
		goto	sigsw02			;No

		bsf	mode_flg,5		;スイッチ入力有りフラグ = 1

		btfsc	tcon_flg,3		;カウント許可中フラグ = 1, 許可中 か？
		goto	sigsw02			;Yes

		movlw	b'10000000'
		xorwf	alm_flg,F	;bit7	;アラーム音出力許可フラグの更新

		bsf	updt_flg,5	;bit5	;SIGNAL メッセージフラグ = 1
		btfss	mode_flg,0		;1:LARGEモード か？
		goto	sigsw01			;No. 0:NORMALモード

		clrf	sel_flg			;
		call	large_display_shift	;LARGE モード時の１行（ページ）上方にずらし表示

sigsw01		bsf	sel_flg,0		;選択フラグ = 1, ダミー（area_reverse 白黒反転クリアのため）
		call	signal_display		;SIGNAL スイッチの ON／OFF メッセージの表示
 		clrf	sel_flg			;ダミークリア

		btfsc	alm_flg,7		;アラーム音出力許可フラグ = 1 か？
		call	buzzer_pipipi		;Yes. 許可  "ピピピッ" ブザー音出力
		btfss	alm_flg,7		;アラーム音出力許可フラグ = 0 か？
		call	buzzer_buu		;Yes. 禁止  "ブー" ブザー音出力

		call	timer_3sec_set		;３秒間タイマーの設定

sigsw02		btfss	PORTC,_swSIG		;SIGNAL スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------

;		SIGNAL スイッチの ON／OFF メッセージの表示

signal_display
		; メッセージエリアの白黒反転
		movlw	4 + 6 * 8
		movwf	column			;表示先頭カラム
		movlw	6 * 12
		movwf	oled_lpcnt		;ループカウンタ
		call	area_reverse		;白黒反転クリア

		btfsc	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	sigm01			;Yes

		; メッセージの選択
		movlw	high signal_msg		;文字列データの先頭 high アドレス
		movwf	FSR0H			;
		movlw	low signal_msg		;文字列データの先頭 low アドレス
		movwf	FSR0L			;

		btfss	alm_flg,7		;アラーム音出力許可フラグ = 1 か？
		addfsr	FSR0,10			;No. 間接アドレス FSR0H:FSR0L + 10

		; メッセージの表示
		OLED_FontPos_M	4+6*9,7		;メッセージを表示する先頭位置
		movlw	h'c0'			;h'c0': ビット反転表示とビットずらし指示
		movwf	echr_flg		;
		OLED_DispStr_M	,0		;メッセージ文字列の表示

sigm01		return

		; SIGNAL メッセージ・テーブル

signal_msg 	dt	"Signal On",0		;alm_flg bit7 = 1
 		dt	"Signal Off",0		;alm_flg bit7 = 0

;--------------------------------------------------------------------------

		; SIGNAL メッセージ表示時間の監視と メッセージエリアのクリア

sig_disp_clear
		btfsc	tcon_flg,3		;カウント許可中フラグ = 1 か？
		goto	sdclr03			;Yes

		btfss	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	sdclr03			;No

		bcf	updt_flg,5		;SIGNAL メッセージフラグ = 0
		btfss	mode_flg,0		;1:LARGEモード か？
		goto	sdclr01			;No. 0:NORMALモード

		call	large_display_shift	;LARGE モード時の１行（ページ）上方にずらし表示を元に戻す
		goto	sdclr02

sdclr01		clrf	sel_flg			;ダミークリア
		call	signal_display		;SIGNAL メッセージエリアのクリア

		btfsc	save_flg,0		;(bcd_xx → temp_xx) 退避中フラグ = 1 か？
		bsf	updt_flg,4		;Yes

sdclr02	;	bcf	tcon_flg,2		;カウント終了フラグ = 0
		clrf	tcon_flg		;タイミング制御フラグのクリア

sdclr03		return

;--------------------------------------------------------------------------

		; LARGE モード時の１行（ページ）上方にずらし表示

large_display_shift
		call	SSD1306_Clear		;LARGEモードのとき全画面消去
		movlp	high yyyymm_display_lg
		call	yyyymm_display_lg	;年月 (yyyy/mm) の表示
		call	calendar_display_lg	;カレンダー（日と曜日）の表示
		call	ampm_display_lg		;(  /am/pm) の表示
		call	time_display_lg		;時分秒 (hh:mm:ss) の表示
		movlp	high $
		return


;==========================================================================
;	  MODE / SET スイッチの処理 ... メイン・ルーチンから CALL
;==========================================================================

;	[スイッチ操作]

;		MODE スイッチ        ..... NORMAL モード / LARGE モードの切り替え

;		MODE スイッチ 長押し ..... SET モードに移行（３秒以上の長押し）
;		(SET スイッチ)

;	tcon_flg: タイミング制御フラグ
;			      >	bit7-4: 0.5秒単位ダウンカウンタ
;			      >	bit3:   カウント許可中フラグ
;			      >	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

;	mode_flg: モードフラグ
;			      >	bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;			      >	bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	updt_flg: 更新フラグ
;			      >	bit7: RTC DS3231 読み出し要求フラグ
;			      >	bit6: 各項目の表示要求フラグ (SETモード)
;				bit5: SIGNAL メッセージフラグ
;				bit4: DOWN/UP メッセージフラグ
;			      >	bit3: 年(上位)_更新フラグ
;			      >	bit2: 年(下位)月_更新フラグ
;			      >	bit1: 日_更新フラグ
;			      >	bit0: 時分秒_更新フラグ

;	sel_flg: 選択フラグ
;			      >	bit7: 年(上位)フラグ
;			      >	bit6: 年(下位)フラグ
;			      >	bit5: 月フラグ
;			      >	bit4: カレンダフラグ
;			      >	bit3: 24H/12Hフラグ
;			      >	bit2: 時フラグ
;			      >	bit1: 分フラグ
;			      >	bit0: 秒フラグ

;	save_flg: (bcd_xx → temp_xx) 退避中表示フラグ
;				bit1: (temp_xx > bcd_xx) 大小フラグ
;			      >	bit0: 退避中フラグ

mode_set_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swMOD		;再度 MODE スイッチ = ON か？
		goto	modsw10			;No

		bsf	mode_flg,5		;スイッチ入力有りフラグ = 1

		btfsc	save_flg,0		;(bcd_xx → temp_xx) 退避中フラグ = 1 か？
		goto	modsw09			;Yes

		; ３秒間長押しの監視 = (4/8Mz*250*16=2msec) * 250 * 6 = 3,000 ms

		call	timer_3sec_set		;３秒間タイマーの設定

modsw01		btfss	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 1 か？
		goto	modsw02			;No

		call	clock_rtc_read		;Yes. RTC DS3231 から年月日,時分秒を読み出し
		bcf	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 0

		call	xtime_ampm_display	;時分秒 (hh:mm:ss), (  /am/pm) の表示

modsw02		btfsc	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	modsw03			;Yes. SETモードに移行

		btfss	PORTA,_swMOD		;MODE スイッチ = OFF か？
		goto	modsw01			;No

		; 表示モードフラグの更新

		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止
		clrf	tcon_flg		;タイミング制御フラグをクリア

		movlw	h'01'
		xorwf	mode_flg,F		;bit0: 0:NORMALモード / 1:LARGEモード の切り替え

		movlw	h'07'	;h'0f'
		movwf	updt_flg		;更新フラグを設定
		goto	modsw09

;--------------------------------------------------------------------------
;		SET モード機能 に移行
;--------------------------------------------------------------------------

;	[スイッチ操作]
;			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │●│   │○│   │●│   │●│   │●│   │●│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

;		 SET スイッチ        ..... ブリンク位置のポインタを + 1
;		BACK スイッチ        ..... ブリンク位置のポインタを - 1

;		  UP スイッチ        ..... ブリンク位置の値を + 1
;		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り

;		DOWN スイッチ        ..... ブリンク位置の値を - 1
;		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り

;   (秒選択時に) SET スイッチ        ..... SET モードを終了し、NORMAL / LARGE モードに戻る

;	      CANCEL スイッチ        ..... SET モードを中断し、NORMAL / LARGE モードに戻る

modsw03	;	bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止（割り込み処理内でクリア済み）
		clrf	tcon_flg		;タイミング制御フラグをクリア
		bcf	INTCON,INTE		;INTE: 外部(RA2/INT)割り込みを禁止

		call	buzzer_pi		;"ピッ" ブザー音

		bsf	mode_flg,1		;bit1: SETモードフラグ = 1
		btfss	mode_flg,0		;bit0: 1:LARGEモード か？
		goto	modsw04			;No. 0:NORMALモード

		clrf	sel_flg			;
		call	large_display_shift	;LARGE モード時の１行（ページ）上方にずらし表示

		; SET モード移行メッセージの表示

modsw04		call	setmode_display		;SET モードメッセージの表示

		btfss	PORTA,_swSET		;MODE/SET スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収
		bcf	time_flg,7		;bit0フラグの記憶 (CANCEL 時に備えて)
		btfsc	time_flg,0		;bit0=1: 12H か？
		bsf	time_flg,7		;Yes

		clrf	sel_flg			;
		bsf	sel_flg,7		;年(上位)フラグ = 1
		bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		; タイミング制御の初期設定

		clrf	tcon_flg
		call	timer_500ms_set		;タイマー０の基本設定

		; 各変更項目別の表示を更新

modsw05		btfss	updt_flg,6		;各項目の表示要求フラグ = 1 か？
		goto	modsw06			;No

		movlp	high yyyymm_display
		call	yyyymm_display		;年月 (yyyy/mm) の表示
		call	calendar_display	;カレンダー（日と曜日）の表示
		call	time_display		;時分秒 (hh:mm:ss) の表示	;┐
		call	ampm_display		;24H/12H の表示			;┘順序を変更しないこと!
	;	movlp	high $

		; 各変更項目別の質問メッセージを表示

	;	movlp	high inquiry_display
		call	inquiry_display		;Yes. 質問メッセージの表示
		movlp	high $
		bcf	updt_flg,6		;各項目の表示要求フラグ = 0

		; 該当項目のブリンク表示

modsw06		movlp	high yyyymm_display_blk
		call	yyyymm_display_blk	;年月 (yyyy/mm) のブリンク表示
		call	calendar_display_blk	;変更する該当日のブリンク表示
		call	ampm_display_blk	;24H/12H のブリンク表示
		call	time_display_blk	;時分秒 (hh:mm:ss) のブリンク表示
		movlp	high $

		; SET モード中の各スイッチの入力処理

		btfss	PORTA,_swSET		;SET スイッチ = ON か？
		call	set_switch		;Yes

		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		call	set_up_switch		;Yes

		btfss	PORTA,_swDWN		;DOWN スイッチ = ON か？
		call	set_down_switch		;Yes

		btfss	PORTA,_swBAK		;BACK スイッチ = ON か？
		call	back_switch		;Yes

		movf	sel_flg,W
		btfsc	STATUS,Z		;選択フラグ sel_flg = h'00' か？
		goto	modsw07			;Yes. 終了

		btfsc	PORTC,_swCAN		;CANCEL スイッチ = ON か？
		goto	modsw05			;No

		; SET モードの中断終了

		call	wait_15ms		;チャッタリング吸収
		btfss	PORTC,_swCAN		;CANCEL スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収
;		movlb	3			;バンク 3
;		movf	save_data_ram,W		;フラッシュメモリ
;		movlb	0			;バンク 0

		movlw	high save_data_ram	;引継ぎ情報の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_ram	;
		movwf	FSR1L			;間接アドレスに設定
		movf	INDF1,W			;
		movwf	bcd_yh			;年(上位2桁)_BCD カウンタ

		bcf	time_flg,0		;bit0フラグの復帰
		btfsc	time_flg,7		;bit7=1: 12H か？
		bsf	time_flg,0		;Yes
		bcf	time_flg,7		;

		bsf	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 1
		goto	modsw08			;中断

		; SET モードの終了

modsw07		call	counter_to_buffer	;カウンタからバッファへコピー
		Rtc_Write_M  seconds,7		;RTC DS3231 へ年月日、時分秒を書き込み

		call	xflash_mem_erase_write	;フラッシュメモリの消去とデータ書き込み

modsw08		bcf	mode_flg,1		;SETモードフラグ = 0
		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止
		clrf	tcon_flg		;タイミング制御フラグをクリア
		bsf	INTCON,INTE		;INTE: 外部(RA2/INT)割り込みを禁止解除

		movf	sel_flg,W
		btfsc	STATUS,Z		;選択フラグ sel_flg = h'00' か？
		call	buzzer_pipi		;Yes. "ピピッ" ブザー音, (更新時)

		movf	sel_flg,W
		btfss	STATUS,Z		;選択フラグ sel_flg = h'00' か？
		call	buzzer_buu		;No. "ブー" ブザー音, (中断時)
		clrf	sel_flg			;選択フラグをクリア

		movlw	h'07'	;h'0f'
		iorwf	updt_flg,F		;更新フラグを設定

modsw09		btfss	PORTA,_swMOD		;MODE スイッチ = OFF か？
		goto	$ - 1			;No

modsw10		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------

;		SET モードメッセージの表示

setmode_display
		OLED_FontPos_M	4+6*10,7	;表示開始位置の指定
		movlw	h'c0'			;h'c0': ビット反転表示とビットずらし指示
		movwf	echr_flg		;
		OLED_DispStr_M	setmode_msg,1	;メッセージ文字列の表示
		bcf	echr_flg,7		;ビット反転表示指示解除
		return

setmode_msg	dt	" SET MODE ",0

;--------------------------------------------------------------------------
;		SET スイッチの処理 ... SET モードから CALL
;--------------------------------------------------------------------------

;選択フラグ   sel_flg:（ bit7:年(上位) / 6:年(下位) / 5:月 / 4:日 / 3:24H/12H / 2:時 / 1:分 / 0:秒 ）

set_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swSET		;再度 SET スイッチ = ON か？
		goto	setsw01			;No

		lsrf	sel_flg,F		;選択フラグの更新, 右にシフト
		bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfss	PORTA,_swSET		;SET スイッチ = OFF か？
		goto	$ - 1			;No

setsw01		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		BACK スイッチの処理 ... SET モードから CALL
;--------------------------------------------------------------------------

;選択フラグ   sel_flg:（ bit7:年(上位) / 6:年(下位) / 5:月 / 4:日 / 3:24H/12H / 2:時 / 1:分 / 0:秒 ）

back_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swBAK		;再度 BACK スイッチ = ON か？
		goto	baksw01			;No

		lslf	sel_flg,F		;選択フラグの更新, 左にシフト
		btfsc	STATUS,Z		;選択フラグ = h'00' か？
		bsf	sel_flg,0		;Yes. 0:秒 に設定
		bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfss	PORTA,_swBAK		;BACK スイッチ = OFF か？
		goto	$ - 1			;No

baksw01		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;    UP スイッチの処理 ... SET モード / タイマーメモリの設定 から CALL
;--------------------------------------------------------------------------

;選択フラグ   sel_flg:（ bit7:年(上位) / 6:年(下位) / 5:月 / 4:日   / 3:24H/12H / 2:時 / 1:分 / 0:秒 ）
;							     4:曜日 / 3:24H/12H / 2:時 / 1:分

set_up_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swUP		;再度 UP スイッチ = ON か？
		goto	supsw11			;No

		bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfss	sel_flg,7	       ;;sel_flg = 7:年(上位) か？
		goto	supsw01			;No

		call	xbcd_yh_inc		;年(上位)_BCD カウンタのインクリメント
		goto	supsw05

supsw01		btfss	sel_flg,6	       ;;sel_flg = 6:年(下位) か？
		goto	supsw02			;No

		call	xbcd_yl_inc		;年(下位)_BCD カウンタのインクリメント
		goto	supsw05

supsw02		btfss	sel_flg,5	       ;;sel_flg = 5:月 か？
		goto	supsw03			;No

		call	xbcd_nn_inc		;月_BCD カウンタのインクリメント
		goto	supsw05

supsw03		btfss	sel_flg,4	       ;;sel_flg = 4:カレンダ(日) / 曜日 か？
		goto	supsw06			;No

		btfss	tmem_flg,7		;タイマーメモリ処理フラグ = 1 か？
		goto	supsw04			;No

		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		goto	supsw04			;Yes

		incf	tm_week,F		;曜日カウンタ インクリメント
		btfsc	tm_week,3		;tm_week = 8 か？
		clrf	tm_week			;Yes. tm_week = 0
		goto	supsw10

supsw04		call	xbcd_dd_inc		;日_BCD カウンタのインクリメント

supsw05		call	xday_week		;該当日の曜日を取得
		movwf	bcd_ww			;曜日_BCD カウンタ
		goto	supsw10

supsw06		btfss	sel_flg,3	       ;;sel_flg = 3:24H/12H か？
		goto	supsw07			;No

		movlw	h'01'
		xorwf	time_flg,F		;時間表示フラグ(bit0: 0:24H/1:12H)の更新
		goto	supsw10

supsw07		btfss	sel_flg,2	       ;;sel_flg = 2:時 か？
		goto	supsw08			;No

		call	xbcd_hh_inc		;時_BCD カウンタのインクリメント
		goto	supsw10

supsw08		btfss	sel_flg,1	       ;;sel_flg = 1:分 か？
		goto	supsw09			;No

		call	xbcd_mm_inc		;分_BCD カウンタのインクリメント
		goto	supsw10

supsw09	;	btfss	sel_flg,0	       ;;sel_flg = 0:秒 か？
	;	goto	supsw10			;No

		call	xbcd_ss_inc		;秒_BCD カウンタのインクリメント

supsw10	;	btfss	PORTA_swUP		;UP スイッチ = OFF か？
	;	goto	$ - 1			;No

		call	wait_200ms		;早送りの速度調整

supsw11		return

;--------------------------------------------------------------------------
;    DOWN スイッチの処理 ... SET モード / タイマーメモリの設定 から CALL
;--------------------------------------------------------------------------

;選択フラグ   sel_flg:（ bit7:年(上位) / 6:年(下位) / 5:月 / 4:日   / 3:24H/12H / 2:時 / 1:分 / 0:秒 ）
;							     4:曜日 / 3:24H/12H / 2:時 / 1:分

set_down_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swDWN		;再度 DOWN スイッチ = ON か？
		goto	sdwsw11			;No

		bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfss	sel_flg,7	       ;;sel_flg = 7:年(上位) か？
		goto	sdwsw01			;No

		call	xbcd_yh_dec		;年(上位)_BCD カウンタのデクリメント
		goto	sdwsw05

sdwsw01		btfss	sel_flg,6	       ;;sel_flg = 6:年(下位) か？
		goto	sdwsw02			;No

		call	xbcd_yl_dec		;年(下位)_BCD カウンタのデクリメント
		goto	sdwsw05

sdwsw02		btfss	sel_flg,5	       ;;sel_flg = 5:月 か？
		goto	sdwsw03			;No

		call	xbcd_nn_dec		;月_BCD カウンタのデクリメント
		goto	sdwsw05

sdwsw03		btfss	sel_flg,4	       ;;sel_flg = 4:カレンダ(日) / 曜日 か？
		goto	sdwsw06			;No

		btfss	tmem_flg,7		;タイマーメモリ処理フラグ = 1 か？
		goto	sdwsw04			;No

		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		goto	sdwsw04			;Yes

		decf	tm_week,F		;曜日カウンタ デクリメント
		incf	tm_week,W
		movlw	7
		btfsc	STATUS,Z		;tm_week = 0 か？
		movwf	tm_week			;Yes. tm_week = 7
		goto	sdwsw10

sdwsw04		call	xbcd_dd_dec		;日_BCD カウンタのデクリメント

sdwsw05		call	xday_week		;該当日の曜日を取得
		movwf	bcd_ww			;曜日_BCD カウンタ
		goto	sdwsw10

sdwsw06		btfss	sel_flg,3	       ;;sel_flg = 3:24H/12H か？
		goto	sdwsw07			;No

		movlw	h'01'
		xorwf	time_flg,F		;時間表示フラグ(bit0: 0:24H/1:12H)の更新
		goto	sdwsw10

sdwsw07		btfss	sel_flg,2	       ;;sel_flg = 2:時 か？
		goto	sdwsw08			;No

		call	xbcd_hh_dec		;時_BCD カウンタのデクリメント
		goto	sdwsw10

sdwsw08		btfss	sel_flg,1	       ;;sel_flg = 1:分 か？
		goto	sdwsw09			;No

		call	xbcd_mm_dec		;分_BCD カウンタのデクリメント
		goto	sdwsw10

sdwsw09	;	btfss	sel_flg,0	       ;;sel_flg = 0:秒 か？
	;	goto	sdwsw10			;No

		call	xbcd_ss_dec		;秒_BCD カウンタのデクリメント

sdwsw10	;	btfss	PORTA_swDWN		;DOWN スイッチ = OFF か？
	;	goto	$ - 1			;No

		call	wait_200ms		;早送りの速度調整

sdwsw11		return


;==========================================================================
;		メンテナンス機能
;==========================================================================

;	[スイッチ操作]
;			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │●│   │○│   │●│   │●│   │●│   │●│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

;		 SET スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択

;		  UP スイッチ        ..... ブリンク位置の値を + 1
;		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り

;		  UP スイッチ +
;		DOWN スイッチ        ..... ブリンク位置の値をデフォルト値に設定

;		DOWN スイッチ        ..... ブリンク位置の値を - 1
;		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り

;		DOWN スイッチ +
;		  UP スイッチ        ..... ブリンク位置の値をデフォルト値に設定

;		BACK スイッチ        ..... メンテナンス機能を終了し、NORMAL / LARGE モードに戻る

;	      CANCEL スイッチ        ..... メンテナンス機能を中断し、NORMAL / LARGE モードに戻る

;	sel_flg: 選択フラグ
;			      >	bit7: 年(上位)フラグ / 中断表示フラグ
;			      >	bit6: 年(下位)フラグ / contrast 値変更ありフラグ
;				bit5: 月フラグ
;				bit4: カレンダフラグ
;				bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;			      >	bit1: 分フラグ       / OLED コントラストフラグ
;			      >	bit0: 秒フラグ       / スリープまでの移行時間フラグ

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

maintenance
		call	SSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去

		movf	contrast,W		;(CANCEL 時に備えて退避)
		movwf	contrast_wk		;
		movf	sleep_time,W		;
		movwf	sleep_time_wk		;

		clrf	batt_count		;バッテリー電圧測定間隔時間カウンタ（秒）の初期設定
		clrf	sel_flg			;
		bsf	sel_flg,1		;選択フラグの初期設定
		bsf	sel_flg,6		;contrast 値変更ありフラグ = 1

		; タイミング制御の初期設定

		bsf	mode_flg,1		;SETモードフラグ = 1 (仮に設定 ... ブリンク制御のため)

		clrf	tcon_flg
		call	timer_500ms_set		;タイマー０の基本設定

		; 設定値のブリンク表示制御

maint01		btfss	sel_flg,6		;contrast 値変更ありフラグ = 1 か？
		goto	maint02			;No

		bcf	sel_flg,6		;contrast 値変更ありフラグ = 0
		movf	contrast,W
		call	SSD1306_Contrast	;OLED ( SSD1306 ) の コントラスト制御

		movlp	high mainte_msg_disp
		call	mainte_msg_disp		;メンテナンスメッセージの表示
		movlp	high $

maint02		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	maint04			;No

		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		btfsc	tcon_flg,1		;0.25秒ブリンクフラグ = 1 か？
		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1

		btfss	sel_flg,1		;選択フラグ = bit1: OLED コントラスト か？
		goto	maint03			;No

		movlp	high contrast_disp
		call	contrast_disp		;Yes. OLED コントラスト値の表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		call	sleep_time_disp		;スリープまでの移行時間値の表示
		movlp	high $
		goto	maint04

maint03		movlp	high sleep_time_disp
		call	sleep_time_disp		;スリープまでの移行時間値の表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		call	contrast_disp		;OLED コントラスト値の表示
		movlp	high $

		; バッテリーの電圧測定と表示

maint04		btfss	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 1 か？
		goto	maint05			;No

		bcf	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 0
		incf	batt_count,F		;バッテリー電圧測定間隔時間カウンタ + 1
		movlw	5
		subwf	batt_count,W
		btfss	STATUS,Z		;バッテリー電圧測定間隔時間カウンタ = 5 か？
		goto	maint05			;No

		clrf	batt_count		;バッテリー電圧測定間隔時間カウンタ = 0
		movlp	high battery_volt__display
		call	battery_volt__display	;バッテリーの電圧測定と表示
		movlp	high $

		; メンテナンス機能中の各スイッチの入力処理

maint05		btfss	PORTA,_swSET		;SET スイッチ = ON か？
		call	mainte_set_switch	;Yes

		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		call	mainte_up_switch	;Yes

		btfss	PORTA,_swDWN		;DOWN スイッチ = ON か？
		call	mainte_down_switch	;Yes

		btfss	PORTA,_swBAK		;BACK スイッチ = ON か？
		goto	maint06			;Yes

		btfsc	PORTC,_swCAN		;CANCEL スイッチ = ON か？
		goto	maint01			;No

		; メンテナンス機能の中断終了

		call	wait_15ms		;チャッタリング吸収
		btfss	PORTC,_swCAN		;CANCEL スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収

		movf	sleep_time_wk,W		;(退避データを復帰)
		movwf	sleep_time		;
		movf	contrast_wk,W		;
		movwf	contrast		;
		call	SSD1306_Contrast	;OLED ( SSD1306 ) の コントラスト制御

		bsf	sel_flg,7		;中断表示フラグ = 1
		goto	maint07

		; メンテナンス機能の終了

maint06		call	wait_15ms		;チャッタリング吸収
		btfss	PORTA,_swBAK		;BACK スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収

		call	xflash_mem_erase_write	;フラッシュメモリの消去とデータ書き込み

maint07		bcf	mode_flg,1		;SETモードフラグ = 0 (仮設定を解除)
		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止
		clrf	tcon_flg		;タイミング制御フラグをクリア

		btfss	sel_flg,7		;中断表示フラグ = 1 か？
		call	buzzer_pipi		;No. "ピピッ" ブザー音, (更新時)

		btfsc	sel_flg,7		;中断表示フラグ = 1 か？
		call	buzzer_buu		;Yes. "ブー" ブザー音, (中断時)
		clrf	sel_flg			;選択フラグをクリア

		movlw	h'07'	;h'0f'
		movwf	updt_flg
		bsf	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 1
		return

;--------------------------------------------------------------------------
;		SET スイッチの処理 ... メンテナンス機能から CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		 SET スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択

;	sel_flg: 選択フラグ
;			      >	bit7: 中断表示フラグ
;			      >	bit6: contrast 値変更ありフラグ
;			      >	bit1: OLED コントラストフラグ
;			      >	bit0: スリープまでの移行時間フラグ

mainte_set_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swSET		;再度 SET スイッチ = ON か？
		goto	msetsw01		;No

		movlw	h'03'
		xorwf	sel_flg,F		;選択フラグの更新

		btfss	PORTA,_swSET		;SET スイッチ = OFF か？
		goto	$ - 1			;No

msetsw01	call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		UP スイッチの処理 ... メンテナンス機能から CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		  UP スイッチ        ..... ブリンク位置の値を + 1

;		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り

;		  UP スイッチ +
;		DOWN スイッチ        ..... ブリンク位置の値をデフォルト値に設定

;	sel_flg: 選択フラグ
;			      >	bit7: 中断表示フラグ
;			      >	bit6: contrast 値変更ありフラグ
;			      >	bit1: OLED コントラストフラグ
;			      >	bit0: スリープまでの移行時間フラグ

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

mainte_up_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swUP		;再度 UP スイッチ = ON か？
		goto	mupsw04			;No

		btfsc	PORTA,_swDWN		;DOWN スイッチ = ON か？
		goto	mupsw01			;No

		; デフォルト値に設定
		call	default_set		;デフォルト値に設定
		goto	mupsw04

		; 通常の変更設定
mupsw01		btfss	sel_flg,1		;選択フラグ = bit1: OLED コントラスト か？
		goto	mupsw02			;No

		incf	contrast,F		;contrast + 1, (255 → 0)
		btfsc	STATUS,Z		;contrast = 0 か？
		incf	contrast,F	;Yes	;contrast + 1, (255 → 1)

		bsf	sel_flg,6		;contrast 値変更ありフラグ = 1
		goto	mupsw03

mupsw02		incf	sleep_time,F		;sleep_time + 1
		movlw	60 + 1
		subwf	sleep_time,W		;
		btfsc	STATUS,Z		;sleep_time = 60 + 1 か？
		clrf	sleep_time	;Yes	;sleep_time = 0, (60 → 0)

		call	wait_200ms		;早送りの速度調整

mupsw03	;	btfss	PORTA,_swUP		;UP スイッチ = OFF か？
	;	goto	$ - 1			;No

		call	wait_100ms		;早送りの速度調整

mupsw04		return

;--------------------------------------------------------------------------

;		デフォルト値に設定

default_set
		call	wait_15ms		;チャッタリング吸収
		btfss	sel_flg,1		;選択フラグ = bit1: OLED コントラスト か？
		goto	defset01		;No

		movlw	127	;h'7f'		;contrast のデフォルト値 = 127
		movwf	contrast		;
		bsf	sel_flg,6		;contrast 値変更ありフラグ = 1
		goto	defset02

defset01	movlw	10			;sleep_time のデフォルト値 = 10
		movwf	sleep_time		;

defset02	comf	PORTA,W			;全ビットを反転
		andlw	h'12'
		btfss	STATUS,Z		;DOWN スイッチ and UP スイッチ = OFF か？
		goto	defset02		;No

		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		DOWN スイッチの処理 ... メンテナンス機能から CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		DOWN スイッチ        ..... ブリンク位置の値を - 1

;		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り

;		DOWN スイッチ +
;		  UP スイッチ        ..... ブリンク位置の値をデフォルト値に設定

;	sel_flg: 選択フラグ
;			      >	bit7: 中断表示フラグ
;			      >	bit6: contrast 値変更ありフラグ
;			      >	bit1: OLED コントラストフラグ
;			      >	bit0: スリープまでの移行時間フラグ

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;			 	bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

mainte_down_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swDWN		;再度 DOWN スイッチ = ON か？
		goto	mdwsw04			;No

		btfsc	PORTA,_swUP		;UP スイッチ = ON か？
		goto	mdwsw01			;No

		; デフォルト値に設定
		call	default_set		;デフォルト値に設定
		goto	mdwsw04

		; 通常の変更設定
mdwsw01		btfss	sel_flg,1		;選択フラグ = bit1: OLED コントラスト か？
		goto	mdwsw02			;No

		decf	contrast,F		;contrast - 1, (0 → 255)
		btfsc	STATUS,Z		;contrast = 0 か？
		decf	contrast,F	;Yes	;contrast - 1, (1 → 255)

		bsf	sel_flg,6		;contrast 値変更ありフラグ = 1
		goto	mdwsw03

mdwsw02		decf	sleep_time,F		;sleep_time - 1
		incf	sleep_time,W
		movlw	60
		btfsc	STATUS,Z		;sleep_time < 0 か？
		movwf	sleep_time	;Yes	;sleep_time = 60, (0 → 60)

		call	wait_200ms		;早送りの速度調整

mdwsw03	;	btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
	;	goto	$ - 1			;No

		call	wait_100ms		;早送りの速度調整

mdwsw04		return


;==========================================================================
;	     時間の監視とスリープモードに移行とウェイクアップ
;==========================================================================

;	mode_flg: モードフラグ
;			      >	bit5: スイッチ入力有りフラグ (メインルーチン)
;			      >	bit4: 状態変化割り込み記憶フラグ
;			      >	bit3: スリープ中状態フラグ
;			      >	bit2: スリープ移行時間チェックフラグ ... １秒ごとに ON になる
;				bit1: SETモードフラグ
;				bit0: 0:NORMALモード/1:LARGEモード

sleep_control
		btfss	mode_flg,2		;スリープ移行時間チェックフラグ = 1 か？
		goto	sleep04			;No

		bcf	mode_flg,2		;スリープ移行時間チェックフラグ = 0

		movf	slp_cnt_h,W
		btfss	STATUS,Z		;slp_cnt_h = 0 か？
		goto	sleep04			;No

		movlw	3 + 1
		subwf	slp_cnt_l,W		;
		btfsc	STATUS,C		;スリープ移行までの時間 < 3 + 1 か？
		goto	sleep04			;No

		movf	slp_cnt_l,W		;
		btfsc	STATUS,Z		;slp_cnt_l = 0 か？
		goto	sleep01			;Yes

		call	buzzer_bu		;"ブッ" アラーム音出力 (100 mS)
		goto	sleep04

		; スリープモードに移行準備

sleep01		call	buzzer_bubuu		;"ブッブー" アラーム音出力 (450 mS)

	;;	bsf	PORTC,OLED_PW		;OLED 電源制御 OFF
	;;	; (下２行に変更)
		movlw	h'ae'			;OFF
		call	SSD1306_DispOnOff	;OLED の Display ON/OFF 制御

		bsf	mode_flg,3	;bit3	;スリープ中状態フラグ = 1
		movlb	7			;バンク 7
		clrf	IOCAF			;状態変化割り込みフラグをクリア
		clrf	IOCCF			;状態変化割り込みフラグをクリア
		movlb	0			;バンク 0
		bcf	INTCON,IOCIF		;状態変化割り込みフラグ = 0 ...（必須）
		bsf	INTCON,IOCIE		;状態変化割り込み許可 = 1

sleep02		sleep				;スリープモード
		; 
		;				;wake up
		btfsc	mode_flg,4		;状態変化割り込み記憶フラグ = 1 か？
		goto	sleep03			;Yes

		; INT 外部割り込みのとき

		call	clock_rtc_read		;RTC DS3231 から年月日,時分秒を読み出し
		call	time_alarm_control	;時報音、タイマー一致音フラグコントロール
		call	alarm_sound		;時報音、タイマー一致音のアラーム出力
		goto	sleep02			;No. 再度 sleep

		; 状態変化割り込みのとき

sleep03	;;	bcf	PORTC,OLED_PW		;OLED 電源制御 ON
	;;	call	SSD1306_Init		;OLED ( SSD1306 ) モジュールの初期設定
	;;	; (下２行に変更)
		movlw	h'af'			;ON
		call	SSD1306_DispOnOff	;OLED の Display ON/OFF 制御

		call	buzzer_pipi		;"ピッピッ" アラーム音出力 (230 mS)

		bcf	mode_flg,4		;状態変化割り込み記憶フラグ = 0
	;;	bcf	mode_flg,3		;スリープ中状態フラグ ... (main でクリアする)

		; スリープ移行時間カウンタの初期設定

		movf	sleep_time,W		;スリープまでの移行時間（分）
		call	mul8x8_16		;8 x 8 ビット = 16 ビットの乗算

sleep04		return

;--------------------------------------------------------------------------
;		8 x 8 ビット = 16 ビットの乗算
;--------------------------------------------------------------------------

; 入力:			    W reg: 乗数

; 使用変数:		slp_cnt_h: 結果（上位）
;			slp_cnt_l: 結果（下位）
;		            lpcnt: ループカウンタ

mul8x8_16
		movwf	slp_cnt_l		;乗数を代入
		clrf	slp_cnt_h		;クリア

		movlw	8
		movwf	lpcnt			;ループカウンタ

mul8x01		bcf	STATUS,C		;キャリフラグのクリア		
		btfss	slp_cnt_l,0		;最下位ビット = 0 か？
		goto	mul8x02			;Yes

		movlw	60			;被乗数
		addwf	slp_cnt_h,F	

mul8x02		rrf	slp_cnt_h,F		;
		rrf	slp_cnt_l,F		;
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	mul8x01			;No

		return


;==========================================================================
;		時報音、タイマー一致音フラグコントロール
;==========================================================================

;	alm_flg: アラーム音出力フラグ

;	  bit7: アラーム音出力許可フラグ
;	  bit3: 時報正報音フラグ           ... "ポッ～～ン"   音  1 回 ... bcd_ss  = h'00' & bcd_mm = h'00'
;	  bit2: 時報予報音フラグ           ... "プッ"         音  3 回 ... bcd_ss >= h'57' & bcd_mm = h'59'
;	  bit1: タイマー一致音フラグ       ... "ピポッピポッ" 音 10 回 ... bcd_ss  = h'00' & タイマー条件
;	  bit0: タイマー一致音継続中フラグ				   bcd_ss  < h'10' & alm_flg.0 = 1

time_alarm_control

		btfss	alm_flg,7		;アラーム音出力許可フラグ = 1 か？
		goto	tacon04			;No

		movf	bcd_ss,W
		btfss	STATUS,Z		;bcd_ss = h'00' か？
		goto	tacon02			;No

		movf	bcd_mm,W
		btfss	STATUS,Z		;bcd_mm = h'00' か？
		goto	tacon01			;No

		; bcd_ss = h'00' & bcd_mm = h'00'
		bsf	alm_flg,3		;時報正報音フラグ = 1

		; bcd_ss = h'00'
tacon01		movlp	high timer_memory_monitor
		call	timer_memory_monitor	;タイマー用メモリの監視（一致検査）
		movlp	high $
		btfss	STATUS,Z		;一致 か？
		goto	tacon04			;No

		bsf	alm_flg,1		;タイマー一致音フラグ = 1
		bsf	alm_flg,0		;タイマー一致音継続中フラグ = 1
		goto	tacon04

tacon02		movlw	h'59'
		subwf	bcd_mm,W		;分_BCD カウンタ
		btfss	STATUS,Z		;bcd_mm = h'59' か？
		goto	tacon03			;No

		movlw	h'57'
		subwf	bcd_ss,W		;秒_BCD カウンタ
		btfss	STATUS,C		;bcd_ss >= h'57' か？
		goto	tacon03			;No

		; bcd_ss >= h'57' & bcd_mm = h'59'
		bsf	alm_flg,2		;時報予報音フラグ = 1
		goto	tacon04

tacon03		btfss	alm_flg,0		;タイマー一致音継続中フラグ = 1 か？
		goto	tacon04			;No

		; alm_flg.0 = 1
		movlw	h'10'
		subwf	bcd_ss,W		;秒_BCD カウンタ
		btfss	STATUS,C		;bcd_ss <  h'10' か？
		bsf	alm_flg,1		;Yes. タイマー一致音フラグ = 1
		btfsc	STATUS,C		;bcd_ss >= h'10' か？
		bcf	alm_flg,0		;Yes. タイマー一致音継続中フラグ = 0

tacon04		return

;==========================================================================
;		時報音、タイマー一致音のアラーム出力
;==========================================================================

;	出力の優先順位:  タイマー一致音 > 時報予報音 > 時報正報音

;	同時に複数のフラグ = 1 の場合は、優先順位の低いものは無視される

alarm_sound

;		btfss	alm_flg,7		;アラーム音出力許可フラグ = 1 か？
;		goto	alarm04			;（このフラグ = 0 のときは、
						;３つのフラグ = 1 になることはない）
		movlw	h'0e'
		andwf	alm_flg,W
		btfsc	STATUS,Z		;どれかアラームフラグ = 1 か？
		goto	alarm04			;No

		btfss	alm_flg,1		;タイマー一致音フラグ = 1 か？
		goto	alarm01			;No

		call	buzzer_pipo2		;"ピポッピポッ" アラーム音出力 (520 mS)
		goto	alarm03

alarm01		btfss	alm_flg,2		;時報予報音フラグ = ON か？
		goto	alarm02			;No

		call	buzzer_pu		;"プッ" アラーム音出力 (100 mS)
		goto	alarm03

alarm02	;	btfss	alm_flg,3		;時報正報音フラグ = ON か？
	;	goto	alarm03			;No

		call	buzzer_poon		;"ポッ～～ン" アラーム音出力 (1000 mS)
		bcf	PORTC,_BZ		;ブザー出力ビットを "L" にしておく

alarm03		movlw	h'81'
		andwf	alm_flg,F		;アラーム音フラグをクリア

alarm04		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

		;"ピピピッ" ブザー音 (360 mS)
buzzer_pipipi
		call	buzzer_pi		;"ピッ" ブザー音出力
		call	wait_30ms

		;"ピピッ" ブザー音 (230 mS)
buzzer_pipi
		call	buzzer_pi		;"ピッ" ブザー音出力
		call	wait_30ms

		; "ピッ" ブザー音出力
buzzer_pi
		Sound_M		f_so, pi_tim
		return

		; "ピポッピポッ" ブザー音出力 (490 mS)
buzzer_pipo2
		call	buzzer_pipo		;"ピポッ" ブザー音出力
		call	wait_30ms

		; "ピポッ" ブザー音出力 (230 mS)
buzzer_pipo
		call	buzzer_pi		;"ピッ" ブザー音出力
		call	wait_30ms

		; "ポッ" ブザー音出力
buzzer_po
		Sound_M		f_doh, po_tim
		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
		movlb	1			;バンク 1
		bsf	PIE1,TMR1IE		;TMR1 オーバーフロー割り込み許可 = 1
		movlb	0			;バンク 0

		call	wait_xxms		;入力 W: 音長（ループカウンタ）

		movlb	1			;バンク 1
		bcf	PIE1,TMR1IE		;TMR1 オーバーフロー割り込み許可 = 0
		movlb	0			;バンク 0

		btfss	alm_flg,3		;時報正報音フラグ = 1 のとき以外は
		bcf	PORTC,_BZ		;ブザー出力ビットを "L" にしておく
		return

;==========================================================================
;		ウェイト・ルーチン (8 MHz)
;==========================================================================

		; 20μ秒 ウェイトルーチン

wait_20us
		movlw	7			;1
		nop				;1
		goto	wu01			;2
						;Total	40/8MHz*4 = 20 μS

		; 100μ秒 ウェイトルーチン
wait_100us
		movlw	39			;1

wu01		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

		return				;2	196+2=198
						;Total	198/8MHz*4 = 99 μS = 100 μS = 0.1 mS

		; 15m 秒 ウェイトルーチン
wait_15ms
		movlw	15
		goto	wait_xxms

		; 30m 秒 ウェイトルーチン
wait_30ms
		movlw	30
		goto	wait_xxms

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100
		goto	wait_xxms

		; 200m 秒 ウェイトルーチン
wait_200ms
		movlw	200
		goto	wait_xxms

		; 500m 秒 ウェイトルーチン
wait_500ms
		call	wait_250ms

		; 250m 秒 ウェイトルーチン
wait_250ms
		movlw	250
		goto	wait_xxms

		; 1m 秒 ウェイトルーチン
wait_1ms
		movlw	1

		; ミリ秒（ 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_1s	
		movlw	1

		; 秒（ 1 秒 x W ）単位 ウェイトルーチン
wait_xs
		movwf	wt3cnt			;W 秒間のウエイト

wts01		call	wait_500ms
		call	wait_500ms
		decfsz	wt3cnt,F		;wt3cnt - 1 = 0 か？
		goto	wts01			;No

		return

;==========================================================================
;		ページ変換サブルーチン (Page 0 用)
;==========================================================================

xbcd_yh_inc
		movlp	high bcd_yh_inc
		call	bcd_yh_inc		;年(上位2桁)_BCD カウンタのインクリメント
		movlp	high $
		return

xbcd_yl_inc
		movlp	high bcd_yl_inc
		call	bcd_yl_inc		;年(下位2桁)_BCD カウンタのインクリメント
		movlp	high $
		return

xbcd_nn_inc
		movlp	high bcd_nn_inc
		call	bcd_nn_inc		;月_BCD カウンタのインクリメント
		movlp	high $
		return

xbcd_dd_inc
		movlp	high bcd_dd_inc
		call	bcd_dd_inc		;日_BCD カウンタのインクリメント
		movlp	high $
		return

xbcd_hh_inc
		movlp	high bcd_hh_inc
		call	bcd_hh_inc		;時_BCD カウンタのインクリメント
		movlp	high $
		return

xbcd_mm_inc
		movlp	high bcd_mm_inc
		call	bcd_mm_inc		;分_BCD カウンタのインクリメント
		movlp	high $
		return

xbcd_ss_inc
		movlp	high bcd_ss_inc
		call	bcd_ss_inc		;秒_BCD カウンタのインクリメント
		movlp	high $
		return

xbcd_yh_dec
		movlp	high bcd_yh_dec
		call	bcd_yh_dec		;年(上位2桁)_BCD カウンタのデクリメント
		movlp	high $
		return

xbcd_yl_dec
		movlp	high bcd_yl_dec
		call	bcd_yl_dec		;年(下位2桁)_BCD カウンタのデクリメント
		movlp	high $
		return

xbcd_nn_dec
		movlp	high bcd_nn_dec
		call	bcd_nn_dec		;月_BCD カウンタのデクリメント
		movlp	high $
		return

xbcd_dd_dec
		movlp	high bcd_dd_dec
		call	bcd_dd_dec		;日_BCD カウンタのデクリメント
		movlp	high $
		return

xbcd_hh_dec
		movlp	high bcd_hh_dec
		call	bcd_hh_dec		;時_BCD カウンタのデクリメント
		movlp	high $
		return

xbcd_mm_dec
		movlp	high bcd_mm_dec
		call	bcd_mm_dec		;分_BCD カウンタのデクリメント
		movlp	high $
		return

xbcd_ss_dec
		movlp	high bcd_ss_dec
		call	bcd_ss_dec		;秒_BCD カウンタのデクリメント
		movlp	high $
		return

xday_week
		movlp	high day_week
		call	day_week		;該当日の曜日を取得
		movlp	high $
	;	movwf	bcd_ww			;曜日_BCD カウンタ
		return

xtime_ampm_display
		movlp	high time_display
		call	time_display		;時分秒 (hh:mm:ss) の表示
		call	ampm_display		;(  /am/pm) の表示
		movlp	high $
		return

xflash_mem_erase_write
		movlp	high flash_mem_erase
		call	flash_mem_erase		;フラッシュメモリを３行（32 * 3 ワード）消去
		call	flash_mem_write		;RAM バッファからフラッシュメモリへデータ書き込み
		movlp	high $
		return

;
;==========================================================================
;--------------------------------------------------------------------------
 		org	h'0800'			;(Page 1)
;--------------------------------------------------------------------------
;==========================================================================
;

;==========================================================================
;	    各_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	high bcd_dd		;日_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_dd		;
		movwf	FSR0L			;間接アドレスに設定
		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_flag,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_flag		;平年に設定

		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_flag,0		;閏年に設定

uru02		return

;--------------------------------------------------------------------------

;		BCD (2桁) からバイナリ変換

bcd2_to_binary
		movwf	work2			;退避
		swapf	work2,W			;上位4ビット(10位)を BCD からバイナリ変換
		andlw	h'0f'
		movwf	work1
		lslf	work1,F			;2倍
		lslf	work1,F			;4倍
		addwf	work1,F			;5倍
		lslf	work1,F			;10倍

		movf	work2,W			;下位4ビット(単位)
		andlw	h'0f'
		addwf	work1,W			;10位 + 単位 = W レジスタ
		return

;--------------------------------------------------------------------------
;		月_BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_nn_inc
		movlw	high bcd_nn		;月_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_nn		;
		movwf	FSR0L			;間接アドレスに設定
		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

;--------------------------------------------------------------------------
;		年(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

;--------------------------------------------------------------------------
;		年(下位2桁)_BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_yl_inc
		movlw	high bcd_yl		;年(下位2桁)_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_yl		;
		movwf	FSR0L			;間接アドレスに設定
		call	inc_bcd			;BCD インクリメント

		movlw	h'a0'
		subwf	bcd_yl,W
		btfsc	STATUS,Z		;年(下位2桁)_BCD カウンタ = 'a0' か？
		clrf	bcd_yl			;Yes. 年(下位2桁)_BCD カウンタ = h'00' 設定
		return

;--------------------------------------------------------------------------
;		年(上位2桁)_BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_yh_inc
		movlw	high bcd_yh		;年(上位2桁)_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_yh		;
		movwf	FSR0L			;間接アドレスに設定
		call	inc_bcd			;BCD インクリメント

		movlw	h'a0'
		subwf	bcd_yh,W
		btfsc	STATUS,Z		;年(上位2桁)_BCD カウンタ = 'a0' か？
		clrf	bcd_yh			;Yes. -年(上位2桁)_BCD カウンタ = h'00' 設定
		return

;--------------------------------------------------------------------------
;		日_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

;--------------------------------------------------------------------------
;		年(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

;--------------------------------------------------------------------------
;		年(下位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

;--------------------------------------------------------------------------
;		年(上位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	

;--------------------------------------------------------------------------
;		秒_BCD カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_ss_inc
		movlw	high bcd_ss		;秒_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_ss		;
		movwf	FSR0L			;間接アドレスに設定
		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	high bcd_mm		;分_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_mm		;
		movwf	FSR0L			;間接アドレスに設定
		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	high bcd_hh		;時_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_hh		;
		movwf	FSR0L			;間接アドレスに設定
		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	high bcd_ss		;秒_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_ss		;
		movwf	FSR0L			;間接アドレスに設定
		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	high bcd_mm		;分_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_mm		;
		movwf	FSR0L			;間接アドレスに設定
		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	high bcd_hh		;時_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low bcd_hh		;
		movwf	FSR0L			;間接アドレスに設定
		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	INDF0,F			;BCD カウンタ +1 更新
		movf	INDF0,W
		andlw	h'0f'			;下位4ビット
		sublw	h'0a'
		btfss	STATUS,Z		;下位4ビット = d'10' か？
		return				;No. Z = 0: 桁上がり指定 = 0 (なし) 

		movlw	h'06'
		addwf	INDF0,F			;下位4ビット = 0, 上位4ビット = + 1
		bsf	STATUS,Z		;    Z = 1: 桁上がり指定 = 1 (あり) 
		return

;--------------------------------------------------------------------------

;		BCD デクリメント

dec_bcd
		decf	INDF0,F			;BCD カウンタ -1 更新
		movf	INDF0,W
		andlw	h'0f'			;下位4ビット
		sublw	h'0f'
		btfss	STATUS,Z		;下位4ビット = h'0f' か？
		return				;No. Z = 0: 桁上がり指定 = 0 (なし) 

		movlw	h'06'
		subwf	INDF0,F			;下位4ビット = 9, (上位4ビット = -1)
		bsf	STATUS,Z		;    Z = 1: 桁上がり指定 = 1 (あり) 
		return

;--------------------------------------------------------------------------
;		該当月の先頭曜日の取得
;--------------------------------------------------------------------------

;入力:		bcd_yh: 年(上位2桁)_BCD カウンタ, bcd_yl: 年(下位2桁)_BCD カウンタ, bcd_nn: 月_BCD カウンタ

;出力:		cur_week: ( 0:日, 1:月, 2:火, 3:水, 4:木, 5:金, 6:土 )

; ワーク:	cur_yh, cur_yl, xxx_yh, work2
; call:		bcd2_to_binary, uruu_check, inc_bcd, month_day2

first_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			;
						;
fweek01		movlw	4			;
		subwf	xxx_yh,W		;
		btfss	STATUS,C		;xxx_yh < 4 か？
		goto	fweek03			;Yes
						;
		btfss	STATUS,Z		;xxx_yh = 4 か？
		goto	fweek02			;No
						;
		movf	bcd_yl,W		;
		btfsc	STATUS,Z		;bcd_yl = 0 か？
		goto	fweek03			;Yes
						;
fweek02		movlw	4			;
		subwf	xxx_yh,F		;
		goto	fweek01			;

		; 年の計算
fweek03		movf	bcd_yl,W		;年(下位2桁)_BCD カウンタ
		subwf	cur_yl,W
		btfss	STATUS,Z		;cur_yl = bcd_yl か？
		goto	fweek04			;No

		movf	xxx_yh,W		;xxx_yh =< 4 (400年以下に変換)
		subwf	cur_yh,W
		btfsc	STATUS,Z		;cur_yh = xxx_yh か？
		goto	fweek05			;Yes

fweek04		movlw	365 % 7			;365 % 7 = 365 - 7 * 52 = 1
		addwf	cur_week,F
		call	uruu_check		;平年／閏年の判定
		btfsc	uru_flag,0		;平年 か？
		incf	cur_week,F		;No. 閏年

		movlw	7
		subwf	cur_week,W
		btfsc	STATUS,C		;cur_week < 7 か？
		movwf	cur_week		;No

		movlw	high cur_yl		;年(下位2桁)(変)_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low cur_yl		;
		movwf	FSR0L			;間接アドレスに設定
		call	inc_bcd			;BCD インクリメント

		movlw	h'a0'
		subwf	cur_yl,W
		btfss	STATUS,Z		;年(下位2桁)(変)_BCD カウンタ = h'a0' か？
		goto	fweek03			;No

		clrf	cur_yl			;年(下位2桁)(変)_BCD カウンタ = h'00' 設定

;		movlw	high cur_yh		;年(上位2桁)(変)_BCD カウンタの番地
;		movwf	FSR0H			;
		movlw	low cur_yh		;
		movwf	FSR0L			;間接アドレスに設定
		call	inc_bcd			;BCD インクリメント
		goto	fweek03

		; 月の計算
fweek05		movlw	h'01'
		movwf	cur_nn			;月(変)_BCD カウンタ

fweek06		movf	bcd_nn,W		;月_BCD カウンタ
		subwf	cur_nn,W
		btfsc	STATUS,Z		;cur_nn = bcd_nn か？
		goto	fweek08			;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	fweek07			;No

		call	uruu_check		;平年／閏年の判定
		btfsc	uru_flag,0		;平年 か？
		incf	cur_week,F		;No. 閏年

fweek07		movlw	7
		subwf	cur_week,W
		btfsc	STATUS,C		;cur_week < 7 か？
		movwf	cur_week		;No

;		movlw	high cur_nn		;月(変)_BCD カウンタの番地
;		movwf	FSR0H			;
		movlw	low cur_nn		;
		movwf	FSR0L			;間接アドレスに設定
		call	inc_bcd			;BCD インクリメント
		goto	fweek06

fweek08		return

;--------------------------------------------------------------------------

;		月データのテーブル読み出し

month_day2
		decf	work2,W
		brw

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  (使用しない)

;--------------------------------------------------------------------------
;		該当日の曜日を取得
;--------------------------------------------------------------------------

day_week
		call	first_week		;該当月の先頭曜日の取得

		; 日の計算

		movf	bcd_dd,W		;日_BCD カウンタ
		call	bcd2_to_binary		;BCD (2桁) からバイナリ変換
		addwf	cur_week,F
		decf	cur_week,F		;-1（当日分）

dweek01		movlw	7
		subwf	cur_week,W
		btfss	STATUS,C		;cur_week < 7 か？
		goto	dweek02			;Yes

		movwf	cur_week		;No
		goto	dweek01

dweek02		incf	cur_week,F		;0～6 → 1～7 に変換

		movf	cur_week,W		;;
		return


;==========================================================================
;		変数の定義と マクロ命令の定義 (Page 1 用)
;==========================================================================

#define 	gl_y	pagex			;表示ページ / Y座標
#define 	gl_x	column			;表示カラム / X座標
#define 	wr_data	pattern			;書き込みデータ

;		xOLED_FontPos_M マクロ		;フォントの表示開始位置指定

xOLED_FontPos_M	macro	@col,@row
		movlw	@col			;
		movwf	column			;表示カラム
		movlw	@row			;
		movwf	pagex			;表示ページ
		call	xSSD1306_FontPos	;表示開始位置指定
		endm

;		xOLED_DispStr_M マクロ		;キャラクタ (横:6 x 縦:8) 文字列の表示

xOLED_DispStr_M	macro	@str_adr,@x
	#if 	@x != 0
		movlw	high @str_adr		;文字列の先頭 high アドレス
		movwf	FSR0H			;
		movlw	low @str_adr		;文字列の先頭 low アドレス
		movwf	FSR0L			;
	#endif
		call	xSSD1306_DispStr	;文字列データ１行表示
		endm

;		xOLED_Line_H_M マクロ		;水平線表示

xOLED_Line_H_M	macro	@col_st,@col_sp,@row,@ptn
		movlw	@col_st			;
		movwf	column			;表示開始カラム
		movlw	@col_sp			;
		movwf	end_column		;表示終了カラム
		movlw	@row			;
		movwf	pagex			;表示ページ
		movlw	@ptn			;
		movwf	pattern			;ビット位置
		call	xSSD1306_Line_H		;モジュールの水平線表示
		endm

;		xOLED_Line_V_M マクロ		;垂直線表示

xOLED_Line_V_M	macro	@col,@row_st,@row_sp,@ptn
		movlw	@col			;
		movwf	column			;表示カラム
		movlw	@row_st			;
		movwf	pagex			;表示開始ページ
		movlw	@row_sp			;
		movwf	end_pagex		;表示終了ページ
		movlw	@ptn			;
		movwf	pattern			;垂直パターン
		call	xSSD1306_Line_V		;モジュールの垂直線表示
		endm

;		DispChr2s_M マクロ		;キャラクタ (横:12 x 縦:16) 文字の表示

DispChr2s_M	macro	@font_adr
		movlw	high @font_adr		;フォントテーブルの先頭 high アドレス
		movwf	FSR1H			;
		movlw	low @font_adr		;フォントテーブルの先頭 low アドレス
		movwf	FSR1L			;
		call	DispChr2s		;LARGE キャラクタ文字の表示
		endm

;--------------------------------------------------------------------------
;		ページ変換サブルーチン (Page 1 用)
;--------------------------------------------------------------------------

xSSD1306_FontPos
		movlp	high SSD1306_FontPos
		call	SSD1306_FontPos		;表示開始位置指定
		movlp	high $
		return

xSSD1306_DispChr
		movlp	high SSD1306_DispChr
		call	SSD1306_DispChr		;OLED へデータを１文字出力
		movlp	high $
		return

xSSD1306_DispStr
		movlp	high SSD1306_DispStr
		call	SSD1306_DispStr		;(横:6 x 縦:8) 文字列の表示
		movlp	high $
		return

xSSD1306_DispChr2
		movlp	high SSD1306_DispChr2
		call	SSD1306_DispChr2	;(横:12 x 縦:16) 文字の表示
		movlp	high $
		return

xSSD1306_Line_H
		movlp	high SSD1306_Line_H
		call	SSD1306_Line_H		;モジュールの水平線表示
		movlp	high $
		return

xSSD1306_Line_V
		movlp	high SSD1306_Line_V
		call	SSD1306_Line_V		;モジュールの垂直線表示
		movlp	high $
		return

xdata_byte
		movlp	high data_byte
		call	data_byte		;データ１バイト出力
		movlp	high $
		return

xrev_shift_byte
		movlp	high rev_shift_byte
		call	rev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		movlp	high $
		return

;--------------------------------------------------------------------------

		; 1 秒 ウェイトルーチン
wwait_1s	
		movlw	1

		; 秒（ 1 秒 x W ）単位 ウェイトルーチン
wwait_xs
		movwf	wt3cnt			;W 秒間のウエイト

wwts01		call	wwait_500ms
		call	wwait_500ms
		decfsz	wt3cnt,F		;wt3cnt - 1 = 0 か？
		goto	wwts01			;No

		return

		; 500m 秒 ウェイトルーチン
wwait_500ms
		call	wwait_250ms

		; 250m 秒 ウェイトルーチン
wwait_250ms
		movlw	250
		goto	xwait_xxms

		; 10m 秒 ウェイトルーチン
wwait_10ms
		movlw	10

		; ミリ秒（ 1m 秒 x W ）単位 ウェイトルーチン
xwait_xxms
		movlp	high wait_xxms
		call	wait_xxms		;W ミリ秒間のウエイト
		movlp	high $
		return


;==========================================================================
;		スクリーン表示の各種サブルーチン
;==========================================================================

;--------------------------------------------------------------------------
;		NORMAL モード時の 曜日タイトル の表示
;--------------------------------------------------------------------------

week_display
		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	weekt01			;No. 1:LARGEモード

		movlw	h'40'			;1 bit 左(下)ずらし指示
		movwf	echr_flg		;表示文字の機能拡張フラグ
		xOLED_FontPos_M	4+6*0,1		;
		xOLED_DispStr_M	week_title,1	;"Su Mo Tu We Th Fr Sa"

weekt01		return

week_title	dt	"Su Mo Tu We Th Fr Sa",0
;			 01234567890123456789

;--------------------------------------------------------------------------
;		NORMAL モード時の 年月 (yyyy/mm) の表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;				bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

yyyymm_display
		clrf	echr_flg		;表示文字の機能拡張フラグのクリア
		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	yym01			;No. 1:LARGEモード

		; 年 (上位2桁 yy) の表示
		xOLED_FontPos_M	3+6*0,0		;表示開始位置の指定
		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	bcd_yh,W		;年(上位2桁)_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_yh,W		;年(上位2桁)_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		; 年 (下位2桁 yy/) の表示
		swapf	bcd_yl,W		;年(下位2桁)_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_yl,W		;年(下位2桁)_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movlw	a'/'
		call	xSSD1306_DispChr	;OLED へデータを１文字出力

		; 月 (mm) の表示
		swapf	bcd_nn,W		;月_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_nn,W		;月_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力
		return

		; LARGEモード時の表示
yym01		call	yyyymm_display_lg	;年月 (yyyy/mm) の表示
		return

;--------------------------------------------------------------------------

;		BCD から数字へ変換後 OLED へ１文字出力

number_disp
		andlw	h'0f'
		iorlw	h'30'
		call	xSSD1306_DispChr	;OLED へデータを１文字出力
		return

;--------------------------------------------------------------------------
;		LARGE モード時の 年月 (yyyy/mm) の表示
;--------------------------------------------------------------------------

yyyymm_display_lg

		; 年 (上位2桁 yy) の表示
		xOLED_FontPos_M	4+12*0,0	;表示開始位置の指定

		swapf	bcd_yh,W		;年(上位2桁)_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_yh,W		;年(上位2桁)_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		; 年 (下位2桁 yy/) の表示
	;	xOLED_FontPos_M	4+12*2,0	;表示開始位置の指定

		swapf	bcd_yl,W		;年(下位2桁)_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_yl,W		;年(下位2桁)_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

	;	xOLED_FontPos_M	4+12*4,0	;表示開始位置の指定

		movlw	a'/'
		call	symbol_disp_lg		;LARGE 文字を表示

		; 月 (mm) の表示
	;	xOLED_FontPos_M	4+12*5,0	;表示開始位置の指定

		swapf	bcd_nn,W		;月_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_nn,W		;月_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示
		return

;--------------------------------------------------------------------------

;		BCD から数字へ変換後 LARGE 文字を表示

;入力レジスタ:	W: 表示する文字コード (h'x0'(0) ～ h'x9'(9))

number_disp_lg
		andlw	h'0f'
		iorlw	h'30'

;入力レジスタ:	W: 表示する文字コード (h'2f'(/), h'30'(0) ～ h'39'(9), h'3a'(:))

symbol_disp_lg
		call	xSSD1306_DispChr2	;OLED へデータを１文字出力

;		次文字の表示位置に更新

next_position
		decf	gl_y,F			;文字の上位半分の表示位置に戻す
		movlw	12
		addwf	gl_x,F			;カラム位置の更新
		call	xSSD1306_FontPos	;次文字の表示位置
		return

;--------------------------------------------------------------------------
;	 NORMAL モード / タイマー処理時の 24H/12H (  /am/pm) の表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;				bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;				bit4: カレンダフラグ
;			      >	bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ
;				bit0: 秒フラグ

;	tmem_flg: タイマーメモリフラグ
;			      >	bit7: タイマーメモリ処理フラグ
;			      >	bit6: 0:メモリREAD/1:メモリWRITE
;				bit5: mode_flg.bit0 の記憶フラグ
;				bit4: バックアップ要求フラグ
;				bit2: 書き込み無効フラグ
;				bit1: タイマー種類選択の中断フラグ
;			      >	bit0: タイマー種類フラグ, 0:年タイマー/1:週間タイマー

;	time_flg: 時間表示モードフラグ
;			      >	bit1: 0:am/1:pm
;			      >	bit0: 0:24H/1:12H

ampm_display
		clrf	echr_flg		;表示文字の機能拡張フラグのクリア
		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	ampm05			;No. 1:LARGEモード

ampm00		btfss	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		goto	ampm01			;No

		xOLED_FontPos_M	3+6*0,5		;表示開始位置の指定
		goto	ampm02

ampm01		xOLED_FontPos_M	3+6*8,0		;表示開始位置の指定

ampm02		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		btfss	sel_flg,3		;選択フラグ = bit3: 24H/12H か？
		goto	ampm03			;No

		; 24H / 12H の表示
		movlw	high h24_12_msg		;文字列データの先頭 high アドレス
		movwf	FSR0H			;
		movlw	low h24_12_msg		;文字列データの先頭 low アドレス
		movwf	FSR0L			;

		btfsc	time_flg,0		;bit0=0: 24H か？
		addfsr	FSR0,4			;No. 間接アドレス FSR0H:FSR0L + 4

		call	xSSD1306_DispStr	;キャラクタ (横:6 x 縦:8) 文字列の表示
		goto	ampm04

		; (  /am/pm) の表示
ampm03		movlw	a' '			;
		call	xSSD1306_DispChr	;OLED へデータを１文字出力

		movlw	a'a'
		btfsc	time_flg,1		;bit1=0: am か？
		movlw	a'p'			;No
		btfss	time_flg,0		;bit0=1: 12H か？
		movlw	a' '			;No
		call	xSSD1306_DispChr	;OLED へデータを１文字出力

		movlw	a'm'
		btfss	time_flg,0		;bit0=1: 12H か？
		movlw	a' '			;No
		call	xSSD1306_DispChr	;OLED へデータを１文字出力

ampm04		return

		; LARGEモード時の表示
ampm05		call	ampm_display_lg		;24H / 12H (  /am/pm) の表示
		return

		; 24H / 12H 文字列テーブル

h24_12_msg 	dt	"24H",0			;time_flg: bit0=0
 		dt	"12H",0			;time_flg: bit0=1

;--------------------------------------------------------------------------
;		LARGE モード時の 24H/12H (  /am/pm) の表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;			      >	bit1: SETモードフラグ
;				bit0: 0:NORMALモード/1:LARGEモード

;	updt_flg: 更新フラグ
;				bit7: RTC DS3231 読み出し要求フラグ
;				bit6: 各項目の表示要求フラグ (SETモード)
;			      >	bit5: SIGNAL メッセージフラグ
;				bit4: DOWN/UP メッセージフラグ
;				bit3: 年(上位)_更新フラグ
;				bit2: 年(下位)月_更新フラグ
;				bit1: 日_更新フラグ
;				bit0: 時分秒_更新フラグ

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;				bit4: カレンダフラグ
;			      >	bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ
;				bit0: 秒フラグ

;	time_flg: 時間表示モードフラグ
;			      >	bit1: 0:am/1:pm
;			      >	bit0: 0:24H/1:12H

ampm_display_lg
		; 24H / 12H (  /am/pm) 表示エリアの h'00'クリア
	;	xOLED_FontPos_M	4+12*6,3	;表示開始位置の指定
		movlw	4+12*6
		movwf	gl_x			;X座標
		movlw	3
		btfsc	mode_flg,1		;SETモード か？
		movlw	2			;Yes
		btfsc	updt_flg,5		;SIGNAL メッセージフラグ = 1 か？
		movlw	2			;Yes
		movf	batt_count,F		;
		btfss	STATUS,Z		;バッテリー電圧表示時間カウンタ = 0 か？
		movlw	2			;No
		movwf	gl_y			;Y座標 = 3 / 2
		call	xSSD1306_FontPos	;表示開始位置の指定

		call	space_clear		;３文字スペース（ゼロ）クリア
		call	space_clear
		call	space_clear

		movlw	12 * 3
		subwf	gl_x,F			;カラム位置の更新
		call	xSSD1306_FontPos	;表示開始位置の指定

		btfss	sel_flg,3		;選択フラグ = bit3: 24H/12H か？
		goto	ampmg01			;No

		; 24H / 12H の表示
		movlw	a'2'
		btfsc	time_flg,0		;bit0=0: 24H か？
		movlw	a'1'			;No
		call	symbol_disp_lg		;LARGE 文字を表示

		movlw	a'4'
		btfsc	time_flg,0		;bit0=0: 24H か？
		movlw	a'2'			;No
		call	symbol_disp_lg		;LARGE 文字を表示

		DispChr2s_M	font_large_h	;'H' LARGE キャラクタ文字を表示
		goto	ampmg04

		; (  /am/pm) の表示
ampmg01		btfss	time_flg,0		;bit0=1: 12H か？
		goto	ampmg04			;No

		btfsc	time_flg,1		;bit1=0: am か？
		goto	ampmg02			;No

		DispChr2s_M	font_small_a	;'a' LARGE キャラクタ文字を表示
		goto	ampmg03

ampmg02		DispChr2s_M	font_small_p	;'p' LARGE キャラクタ文字を表示

ampmg03		DispChr2s_M	font_small_m	;'m' LARGE キャラクタ文字を表示

ampmg04		return

;--------------------------------------------------------------------------

;		スペース（ゼロ）文字の表示（クリア）

space_clear
		movlw	high font_space
		movwf	FSR1H			;spaceフォントデータの先頭 high アドレス
		movlw	low font_space
		movwf	FSR1L			;spaceフォントデータの先頭 low アドレス

		call	DispChr2s		;LARGE キャラクタ文字の表示
		return

;--------------------------------------------------------------------------

;		LARGE キャラクタ (横:12 x 縦:16) 文字の表示

;入力:		FSR1H:FSR1L: フォントテーブルの先頭アドレス

DispChr2s
		movlp	high SSD1306_DispChr2s
		call	SSD1306_DispChr2s	;(SSD1306_DispChr2 内)
		movlp	high $

		call	next_position		;次文字の表示位置
		return

;--------------------------------------------------------------------------
;	 NORMAL モード / タイマー処理時の 時分秒 (hh:mm:ss) の表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;				bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	time_flg: 時間表示モードフラグ
;				bit1: 0:am/1:pm
;			      >	bit0: 0:24H/1:12H

;	tmem_flg: タイマーメモリフラグ
;				bit7: タイマーメモリ処理フラグ
;				bit6: 0:メモリREAD/1:メモリWRITE
;				bit5: mode_flg.bit0 の記憶フラグ
;				bit4: バックアップ要求フラグ
;				bit2: 書き込み無効フラグ
;				bit1: タイマー種類選択の中断フラグ
;				bit0: タイマー種類フラグ, 0:年タイマー/1:週間タイマー

time_display
		clrf	echr_flg		;表示文字の機能拡張フラグのクリア
		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	tim06			;No. 1:LARGEモード

		; 時 (hh:) の表示
		btfss	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		goto	tim01			;No

		xOLED_FontPos_M	3+6*4,5		;表示開始位置の指定
		goto	tim02

tim01		xOLED_FontPos_M	3+6*12,0	;表示開始位置の指定

tim02		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	bcd_hh,W		;時_BCD カウンタ 上位4ビット
		btfss	time_flg,0		;時間表示フラグ = 12H か？
		goto	tim03			;No. 24H

		call	cnv_24to12		;24時間表示を12時間表示に変換
		swapf	temp_hh,W		;仮の 時_BCD カウンタ 上位4ビット
		andlw	h'0f'
		btfss	STATUS,Z		;上位4ビット = 0 か？
		goto	tim03			;No

		movlw	a' '			;ゼロサプレス
		call	xSSD1306_DispChr	;OLED へデータを１文字出力
		goto	tim04

tim03		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

tim04		movf	temp_hh,W		;仮の 時_BCD カウンタ 下位4ビット
		btfss	time_flg,0		;時間表示フラグ = 12H か？
		movf	bcd_hh,W		;No. 時_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movlw	a':'
		call	xSSD1306_DispChr	;OLED へデータを１文字出力

		; 分 (mm:) の表示
		swapf	bcd_mm,W		;分_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_mm,W		;分_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		btfsc	tmem_flg,6		;タイマー処理 メモリWRITE か？
		goto	tim05			;Yes

		movlw	a':'
		call	xSSD1306_DispChr	;OLED へデータを１文字出力

		; 秒 (ss) の表示
		swapf	bcd_ss,W		;秒_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_ss,W		;秒_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

tim05		return

		; LARGEモード時の表示
tim06		call	time_display_lg		;時分秒 (hh:mm:ss) の表示
		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 01 02 03 04 05 06 07 08 09 10 11 12 01 02 03 04 05 06 07 08 09 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,1		;bit1=0: am に設定

		movf	bcd_hh,W	;;	;時_BCD カウンタ
		movwf	temp_hh		;;	;仮の 時_BCD カウンタ

		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. (am)

		; (pm)
		bsf	time_flg,1		;bit1=1: pm に設定

		btfsc	STATUS,Z		;仮の時_BCD カウンタ = h'12' か？
		goto	cnv02			;Yes. (pm)

		movwf	temp_hh			;仮の時_BCD カウンタ temp_hh = temp_hh - 12
		movlw	h'0e'
		subwf	temp_hh,W
		btfss	STATUS,C		;仮の時_BCD カウンタ >= h'0e' か？
		goto	cnv02			;No

		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

;--------------------------------------------------------------------------
;		LARGE モード時の 時分秒 (hh:mm:ss) の表示
;--------------------------------------------------------------------------

;	time_flg: 時間表示モードフラグ
;				bit1: 0:am/1:pm
;			      >	bit0: 0:24H/1:12H

time_display_lg

		; 時 (hh:) の表示
	;	xOLED_FontPos_M	4+12*1,6	;表示開始位置の指定
		movlw	4+12*1
		movwf	gl_x			;X座標
		movlw	6
		btfsc	mode_flg,1		;SETモード か？
		movlw	4			;Yes
		btfsc	updt_flg,5		;SIGNAL メッセージフラグ = 1 か？
		movlw	4			;Yes
		movf	batt_count,F		;
		btfss	STATUS,Z		;バッテリー電圧表示時間カウンタ = 0 か？
		movlw	4			;No
		movwf	gl_y			;Y座標 = 6 / 4
		call	xSSD1306_FontPos	;表示開始位置の指定

		swapf	bcd_hh,W		;時_BCD カウンタ 上位4ビット
		btfss	time_flg,0		;時間表示フラグ = 12H か？
		goto	timg01			;No. 24H

		call	cnv_24to12		;24時間表示を12時間表示に変換
		swapf	temp_hh,W		;仮の 時_BCD カウンタ 上位4ビット
		andlw	h'0f'
		btfss	STATUS,Z		;上位4ビット = 0 か？
		goto	timg01			;No

		call	space_clear		;ゼロサプレス
		goto	timg02

timg01		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

timg02		movf	temp_hh,W		;仮の 時_BCD カウンタ 下位4ビット
		btfss	time_flg,0		;時間表示フラグ = 12H か？
		movf	bcd_hh,W		;No. 時_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

	;	xOLED_FontPos_M	4+12*3,6	;表示開始位置の指定

		movlw	a':'
		call	symbol_disp_lg		;LARGE 文字を表示

		; 分 (mm:) の表示
	;	xOLED_FontPos_M	4+12*4,6	;表示開始位置の指定

		swapf	bcd_mm,W		;分_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_mm,W		;分_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

	;	xOLED_FontPos_M	4+12*6,6	;表示開始位置の指定

		movlw	a':'
		call	symbol_disp_lg		;LARGE 文字を表示

		; 秒 (ss) の表示
	;	xOLED_FontPos_M	4+12*7,6	;表示開始位置の指定

		swapf	bcd_ss,W		;秒_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_ss,W		;秒_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示
		return

;--------------------------------------------------------------------------
;	    NORMAL モード / タイマー処理時の カレンダーの表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;				bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	updt_flg: 更新フラグ
;				bit7: RTC DS3231 読み出し要求フラグ
;			      >	bit6: 各項目の表示要求フラグ (SETモード)
;			      >	bit5: SIGNAL メッセージフラグ
;				bit4: DOWN/UP メッセージフラグ
;				bit3: 年(上位)_更新フラグ
;				bit2: 年(下位)月_更新フラグ
;				bit1: 日_更新フラグ
;				bit0: 時分秒_更新フラグ

calendar_display

		clrf	echr_flg		;表示文字の機能拡張フラグのクリア
		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	calen07			;No. 1:LARGEモード

		btfss	updt_flg,6		;各項目の表示要求フラグ = 1 か？
		goto	calen01			;No

		movlp	high calend_area_clear
		call	calend_area_clear	;Yes. カレンダー表示エリアの h'00'クリア
		movlp	high $

		; カレンダー (一ヶ月分) の表示
calen01		call	first_week		;該当月の先頭曜日の取得
		call	month_days		;各月の日数計算
		movwf	end_day			;各月の終了日（日数 28～31)
		movlw	h'01'
		movwf	cur_dd			;日(変)_BCD カウンタの初期設定
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1

		movlw	2
		movwf	pagex			;表示開始ページ
		movf	cur_week,W
		btfsc	STATUS,Z		;cur_week = 0 か？
		incf	pagex,F			;Yes

calen02		movf	cur_week,W
		movwf	work1			;x3 する
		addwf	work1,F			; Su Mo Tu We Th Fr Sa
		addwf	work1,F			; 00 03 06 09 12 15 18
	
		lslf	work1,F			;x2
		movf	work1,W			;W に一時退避
		lslf	work1,F			;x4
		addwf	work1,W			;x6 ... 退避した W を足す

		addlw	3			;+3
		movwf	column			;各日(変)の表示開始カラム

		call	xSSD1306_FontPos	;フォントの表示開始位置指定
;
		btfsc	save_flg,0		;bcd_xx → temp_xx へ退避中表示フラグ = 1 か？
		goto	calen03			;Yes

		movf	bcd_dd,W
		subwf	cur_dd,W
		btfss	STATUS,Z		;cur_dd = bcd_dd か？
		goto	calen03			;No

		movf	column,W		;表示位置 column を退避
		movwf	column_wk
		movf	pagex,W			;表示位置 pagex を退避
		movwf	pagex_wk
		movf	cur_dd,W		;日(変)_BCD カウンタを退避
		movwf	temp_dd

		bsf	echr_flg,7		;ビット反転表示指示 = 1

calen03		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		swapf	cur_dd,W		;日(変)_BCD カウンタ 上位4ビット
		andlw	h'0f'
		btfss	STATUS,Z		;上位4ビット = 0 か？
		goto	calen04			;No

		movlw	a' '			;ゼロサプレス
		call	xSSD1306_DispChr	;OLED へデータを１文字出力
		goto	calen05

calen04		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

calen05		movf	cur_dd,W		;日(変)_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力
		bcf	echr_flg,7		;ビット反転表示指示 = 0

		movf	end_day,W
		subwf	cur_dd,W
		btfsc	STATUS,C		;cur_dd < end_dd か？
		goto	calen06			;No

		movlw	high cur_dd		;日(変)_BCD カウンタの番地
		movwf	FSR0H			;
		movlw	low cur_dd		;
		movwf	FSR0L			;間接アドレスに設定
		call	inc_bcd			;日(変) BCDインクリメント

		incf	cur_week,F		;週位置の更新
		movlw	7
		subwf	cur_week,W
		btfss	STATUS,C		;週位置 < 7 か？
		goto	calen02			;Yes

		clrf	cur_week		;週位置の初期設定
		incf	pagex,F			;表示ページの更新
		goto	calen02			;

calen06		clrf	echr_flg		;表示文字の機能拡張フラグのクリア
		return

		; LARGEモード時の表示
calen07		call	calendar_display_lg	 ;カレンダーの表示
		return

;--------------------------------------------------------------------------
;		LARGE モード時の カレンダー（日と曜日）の表示
;--------------------------------------------------------------------------

calendar_display_lg

		; 日 (/dd) の表示
		xOLED_FontPos_M	4+12*7,0	;表示開始位置の指定

		movlw	a'/'
		call	symbol_disp_lg		;LARGE 文字を表示

	;	xOLED_FontPos_M	4+12*8,0	;表示開始位置の指定

		swapf	bcd_dd,W		;日_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_dd,W		;日_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		; 曜日 (xxx) の表示
	;	xOLED_FontPos_M	4+12*2,3	;表示開始位置の指定

		movlw	4+12*2
		movwf	gl_x			;X座標
		movlw	3
		btfsc	mode_flg,1		;SETモード か？
		movlw	2			;Yes
		btfsc	updt_flg,5		;SIGNAL メッセージフラグ = 1 か？
		movlw	2			;Yes
		movf	batt_count,F		;
		btfss	STATUS,Z		;バッテリー電圧表示時間カウンタ = 0 か？
		movlw	2			;No
		movwf	gl_y			;Y座標 = 3 / 2
		call	xSSD1306_FontPos	;表示開始位置の指定

		call	first_week		;該当月の先頭曜日の取得
		movf	bcd_dd,W
		call	bcd2_to_binary		;BCD (2桁) からバイナリ変換
		addwf	cur_week,F
		decf	cur_week,F		;-1 しておく

caleng01	movlw	7
		subwf	cur_week,W
		btfss	STATUS,C		;cur_week >= 7 か？
		goto	caleng02		;No

		movwf	cur_week
		goto	caleng01

caleng02	movf	cur_week,W
		movwf	FSR0L			;
		clrf	FSR0H

		lslf	FSR0L,F			;x2
		movf	FSR0L,W			;W に一時退避
		lslf	FSR0L,F			;x4
		addwf	FSR0L,F			;x6 ... 退避した W を足す

		movlw	low week_string_tbl
		addwf	FSR0L,F			;曜日文字列アドレステーブルの先頭 low アドレス
		movlw	high week_string_tbl
		addwfc	FSR0H,F			;曜日文字列アドレステーブルの先頭 high アドレス

		movlw	3
		movwf	lpcnt			;ループカウンタ

caleng03	call	adr_read_lg		;アドレステーブルから読み出し
		movlp	high $			;この場所の high アドレス
		movwf	FSR1H			;high アドレス
		addfsr	FSR0,1			;間接アドレス FSR0H:FSR0L + 1

		call	adr_read_lg		;アドレステーブルから読み出し
		movlp	high $			;この場所の high アドレス
		movwf	FSR1L			;low アドレス
		addfsr	FSR0,1			;間接アドレス FSR0H:FSR0L + 1

		call	DispChr2s		;LARGE キャラクタ文字の表示

		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	caleng03		;No

		return

;--------------------------------------------------------------------------

;		アドレステーブルから読み出し
adr_read_lg
		movf	FSR0H,W			;読み出すデータの high アドレス
		movwf	PCLATH
		movf	FSR0L,W			;読み出すデータの low アドレス
		movwf	PCL

;--------------------------------------------------------------------------
;		質問メッセージの表示
;--------------------------------------------------------------------------

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;				bit4: カレンダフラグ
;				bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ
;				bit0: 秒フラグ

inquiry_display
		; メッセージエリアの白黒反転
		movlw	4 + 6 * 9
		movwf	column			;表示先頭カラム
		movlw	6 * 11
		movwf	oled_lpcnt		;ループカウンタ
		movlp	high area_reverse
		call	area_reverse		;白黒反転クリア
		movlp	high $

		movf	sel_flg,W
		btfsc	STATUS,Z		;クリア処理のみ か？
		goto	inq05			;Yes

		; 表示メッセージの選択
		movf	sel_flg,W		;選択フラグ, メッセージの選択
		movwf	work1

		btfss	tmem_flg,7		;タイマーメモリ処理フラグ = 1 か？
		goto	inq01			;No

		sublw	b'00010000'
		btfss	STATUS,Z		;bit4: カレンダフラグ か？
		goto	inq01			;No

		movlw	high inq_day_msg	;文字列データの先頭 high アドレス
		movwf	FSR0H			;
		movlw	low inq_day_msg		;文字列データの先頭 low アドレス
		movwf	FSR0L			;
		goto	inq04

inq01		movlw	high inquiry_msg	;文字列データの先頭 high アドレス
		movwf	FSR0H			;
		movlw	low inquiry_msg		;文字列データの先頭 low アドレス
		movwf	FSR0L			;

inq02		rlf	work1,F
		btfsc	STATUS,C		;終了 か？
		goto	inq04			;Yes

inq03		movlp	high str_read		;(SSD1306_DispStr 内)
		call	str_read		;文字列データの読み出し
		movlp	high $			;この場所の high アドレス
		addfsr	FSR0,1			;間接アドレス FSR0H:FSR0L + 1

		addlw	0
		btfss	STATUS,Z		;文字列の終了(h'00') か？
		goto	inq03			;No
		goto	inq02			;Yes

		; メッセージの表示
inq04		xOLED_FontPos_M	4+6*10,7	;メッセージを表示する先頭位置
		movlw	h'c0'			;h'c0': ビット反転表示とビットずらし指示
		movwf	echr_flg		;
		xOLED_DispStr_M	,0		;メッセージ文字列の表示
		clrf	echr_flg		;表示文字の機能拡張フラグのクリア

inq05		return

		; 質問メッセージ・テーブル

inquiry_msg 	dt	"Year Hi ?",0		;sel_flg = bit7
		dt	"Year Lo ?",0		;sel_flg = bit6
		dt	"Month ? ",0		;sel_flg = bit5
		dt	"Today ?",0		;sel_flg = bit4
		dt	"24H/12H ?",0		;sel_flg = bit3
		dt	"Hour ?",0		;sel_flg = bit2
		dt	"Minute ?",0		;sel_flg = bit1
		dt	"Second ?",0		;sel_flg = bit0

inq_day_msg	dt	"Day ?",0		;sel_flg = bit4	;(Ver.2.02 で追加)


;==========================================================================
;		SETモード時の ブリンク表示 (NORMAL/LARGEモード)
;==========================================================================

;--------------------------------------------------------------------------
;	NORMAL & SET モード時の 年月 (yyyy/mm) のブリンク表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;				bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	sel_flg: 選択フラグ
;			      >	bit7: 年(上位)フラグ
;			      >	bit6: 年(下位)フラグ
;			      >	bit5: 月フラグ
;				bit4: カレンダフラグ
;				bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ
;				bit0: 秒フラグ

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

yyyymm_display_blk

		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	yymb05			;No

		call	bit_rev_flg_set		;ビット反転表示指示フラグの設定
		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	yymb06			;No. 1:LARGEモード

		; 年 (上位2桁 yy) の表示
		btfss	sel_flg,7		;選択フラグ = bit7: 年(上位2桁) か？
		goto	yymb01			;No

		xOLED_FontPos_M	3+6*0,0		;表示開始位置の指定
		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	bcd_yh,W		;年(上位2桁)_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_yh,W		;年(上位2桁)_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力
		goto	yymb03

		; 年 (下位2桁 yy) の表示
yymb01		btfss	sel_flg,6		;選択フラグ = bit6: 年(下位2桁) か？
		goto	yymb02			;No

		xOLED_FontPos_M	3+6*2,0		;表示開始位置の指定
		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	bcd_yl,W		;年(下位2桁)_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_yl,W		;年(下位2桁)_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力
		goto	yymb03

		; 月 (mm) の表示
yymb02		btfss	sel_flg,5		;選択フラグ = bit5: 月 か？
		goto	yymb04			;No

		xOLED_FontPos_M	3+6*5,0		;表示開始位置の指定
		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	bcd_nn,W		;月_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_nn,W		;月_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

yymb03		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0

yymb04		bcf	echr_flg,7		;ビット反転表示指示 = 0

yymb05		return

		; LARGEモード時の表示
yymb06		call	yyyymm_display_blk_lg	;年月 (yyyy/mm) のブリンク表示
		return

;--------------------------------------------------------------------------

;		ビット反転表示指示フラグの設定

bit_rev_flg_set
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		btfsc	tcon_flg,1		;0.25秒ブリンクフラグ = 1 か？
		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1
		return

;--------------------------------------------------------------------------
;		LARGE & SET モード時の 年月 (yyyy/mm) のブリンク表示
;--------------------------------------------------------------------------

;	sel_flg: 選択フラグ
;			      >	bit7: 年(上位)フラグ
;			      >	bit6: 年(下位)フラグ
;			      >	bit5: 月フラグ
;				bit4: カレンダフラグ
;				bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ
;				bit0: 秒フラグ

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;			      >	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

yyyymm_display_blk_lg

		; 年 (上位2桁 yy) の表示
		btfss	sel_flg,7		;選択フラグ = bit7: 年(上位2桁) か？
		goto	yymgb01			;No

		xOLED_FontPos_M	4+12*0,0	;表示開始位置の指定

		swapf	bcd_yh,W		;年(上位2桁)_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_yh,W		;年(上位2桁)_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示
		goto	yymgb03

		; 年 (下位2桁 yy/) の表示
yymgb01		btfss	sel_flg,6		;選択フラグ = bit6: 年(下位2桁) か？
		goto	yymgb02			;No

		xOLED_FontPos_M	4+12*2,0	;表示開始位置の指定

		swapf	bcd_yl,W		;年(下位2桁)_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_yl,W		;年(下位2桁)_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示
		goto	yymgb03

		; 月 (mm) の表示
yymgb02		btfss	sel_flg,5		;選択フラグ = bit5: 月 か？
		goto	yymgb04			;No

		xOLED_FontPos_M	4+12*5,0	;表示開始位置の指定

		swapf	bcd_nn,W		;月_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_nn,W		;月_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

yymgb03		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0

yymgb04		bcf	echr_flg,7		;ビット反転表示指示 = 0
		return

;--------------------------------------------------------------------------
;	 NORMAL & SET モード時の "  " / "am" / "pm" のブリンク表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;				bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;				bit4: カレンダフラグ
;			      >	bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ
;				bit0: 秒フラグ

;	time_flg: 時間表示モードフラグ
;				bit1: 0:am/1:pm
;			      >	bit0: 0:24H/1:12H

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

ampm_display_blk

		btfss	sel_flg,3		;選択フラグ = bit3: 24H/12H か？
		goto	ampmb01			;No

		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	ampmb01			;No

		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0
		call	bit_rev_flg_set		;ビット反転表示指示フラグの設定

		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	ampmb02			;No. 1:LARGEモード

		call	ampm00			;(ampm_display 内)
		bcf	echr_flg,7		;ビット反転表示指示 = 0

ampmb01		return

		; LARGEモード時の表示
ampmb02		call	ampm_display_blk_lg	;24H / 12H のブリンク表示
		return

;--------------------------------------------------------------------------
;		LARGE & SET モード時の (  /am/pm) のブリンク表示
;--------------------------------------------------------------------------

;	time_flg: 時間表示モードフラグ
;				bit1: 0:am/1:pm
;			      >	bit0: 0:24H/1:12H

ampm_display_blk_lg

		; 24H / 12H の表示
		xOLED_FontPos_M	4+12*6,2	;表示開始位置の指定

		movlw	a'2'
		btfsc	time_flg,0		;bit0=0: 24H か？
		movlw	a'1'			;No
		call	symbol_disp_lg		;LARGE 文字を表示

		movlw	a'4'
		btfsc	time_flg,0		;bit0=0: 24H か？
		movlw	a'2'			;No
		call	symbol_disp_lg		;LARGE 文字を表示

		DispChr2s_M	font_large_h	;'H' LARGE キャラクタ文字を表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		return

;--------------------------------------------------------------------------
;	NORMAL & SET モード時の 時分秒 (hh:mm:ss) のブリンク表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;				bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;				bit4: カレンダフラグ
;				bit3: 24H/12Hフラグ
;			      >	bit2: 時フラグ
;			      >	bit1: 分フラグ
;			      >	bit0: 秒フラグ

;	time_flg: 時間表示モードフラグ
;				bit1: 0:am/1:pm
;			      >	bit0: 0:24H/1:12H

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

time_display_blk

		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	timb11			;No

		call	bit_rev_flg_set		;ビット反転表示指示フラグの設定
		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	timb12			;No. 1:LARGEモード

		; 時 (hh) の表示
		btfss	sel_flg,2		;選択フラグ = bit2: 時 か？
		goto	timb05			;No

		btfss	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		goto	timb01			;No

		xOLED_FontPos_M	3+6*4,5		;表示開始位置の指定
		goto	timb02

timb01		xOLED_FontPos_M	3+6*12,0	;表示開始位置の指定

timb02		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	bcd_hh,W		;時_BCD カウンタ 上位4ビット
		btfss	time_flg,0		;時間表示フラグ = 12H か？
		goto	timb03			;No. 24H

		call	cnv_24to12		;24時間表示を12時間表示に変換
		swapf	temp_hh,W		;仮の 時_BCD カウンタ 上位4ビット
		andlw	h'0f'
		btfss	STATUS,Z		;上位4ビット = 0 か？
		goto	timb03			;No

		movlw	a' '			;ゼロサプレス
		call	xSSD1306_DispChr	;OLED へデータを１文字出力
		goto	timb04

timb03		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

timb04		movf	temp_hh,W		;仮の 時_BCD カウンタ 下位4ビット
		btfss	time_flg,0		;時間表示フラグ = 12H か？
		movf	bcd_hh,W		;No. 時_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力
		goto	timb09

		; 分 (mm) の表示
timb05		btfss	sel_flg,1		;選択フラグ = bit1: 分 か？
		goto	timb08			;No

		btfss	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		goto	timb06			;No

		xOLED_FontPos_M	3+6*7,5		;表示開始位置の指定
		goto	timb07

timb06		xOLED_FontPos_M	3+6*15,0	;表示開始位置の指定

timb07		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	bcd_mm,W		;分_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_mm,W		;分_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力
		goto	timb09

		; 秒 (ss) の表示
timb08		btfss	sel_flg,0		;選択フラグ = bit0: 秒 か？
		goto	timb10			;No

		xOLED_FontPos_M	3+6*18,0	;表示開始位置の指定
		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	bcd_ss,W		;秒_BCD カウンタ 上位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

		movf	bcd_ss,W		;秒_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

timb09		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0

timb10		bcf	echr_flg,7		;ビット反転表示指示 = 0

timb11		return

		; LARGEモード時の表示
timb12		call	time_display_blk_lg	;時分秒 (hh:mm:ss) のブリンク表示
		return

;--------------------------------------------------------------------------
;		LARGE & SET モード時の 時分秒 (hh:mm:ss) のブリンク表示
;--------------------------------------------------------------------------

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;				bit4: カレンダフラグ
;				bit3: 24H/12Hフラグ
;			      >	bit2: 時フラグ
;			      >	bit1: 分フラグ
;			      >	bit0: 秒フラグ

;	time_flg: 時間表示モードフラグ
;				bit1: 0:am/1:pm
;			      >	bit0: 0:24H/1:12H

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

time_display_blk_lg

		; 時 (hh) の表示
		btfss	sel_flg,2		;選択フラグ = bit2: 時 か？
		goto	timgb03			;No

		xOLED_FontPos_M	4+12*1,4	;表示開始位置の指定

		swapf	bcd_hh,W		;時_BCD カウンタ 上位4ビット
		btfss	time_flg,0		;時間表示フラグ = 12H か？
		goto	timgb01			;No. 24H

		call	cnv_24to12		;24時間表示を12時間表示に変換
		swapf	temp_hh,W		;仮の 時_BCD カウンタ 上位4ビット
		andlw	h'0f'
		btfss	STATUS,Z		;上位4ビット = 0 か？
		goto	timgb01			;No

		call	space_clear		;ゼロサプレス
		goto	timgb02

timgb01		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

timgb02		movf	temp_hh,W		;仮の 時_BCD カウンタ 下位4ビット
		btfss	time_flg,0		;時間表示フラグ = 12H か？
		movf	bcd_hh,W		;No. 時_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示
		goto	timgb05

		; 分 (mm) の表示
timgb03		btfss	sel_flg,1		;選択フラグ = bit1: 分 か？
		goto	timgb04			;No

		xOLED_FontPos_M	4+12*4,4	;表示開始位置の指定

		swapf	bcd_mm,W		;分_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_mm,W		;分_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示
		goto	timgb05

		; 秒 (ss) の表示
timgb04		btfss	sel_flg,0		;選択フラグ = bit0: 秒 か？
		goto	timgb06

		xOLED_FontPos_M	4+12*7,4	;表示開始位置の指定

		swapf	bcd_ss,W		;秒_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_ss,W		;秒_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

timgb05		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0

timgb06		bcf	echr_flg,7		;ビット反転表示指示 = 0
		return

;--------------------------------------------------------------------------
;	NORMAL & SET モード時の カレンダー（該当日）のブリンク表示
;--------------------------------------------------------------------------

;	mode_flg: モードフラグ
;				bit5: スイッチ入力有りフラグ (メインルーチン)
;				bit4: 状態変化割り込み記憶フラグ
;				bit3: スリープ中状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;				bit1: SETモードフラグ
;			      >	bit0: 0:NORMALモード/1:LARGEモード

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;			      >	bit4: カレンダフラグ
;				bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ
;				bit0: 秒フラグ

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;			      >	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

calendar_display_blk

		btfss	sel_flg,4		;選択フラグ = bit4: カレンダ か？
		goto	caleb03			;No

		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	caleb03			;No

		call	bit_rev_flg_set		;ビット反転表示指示フラグの設定
		btfsc	mode_flg,0		;0:NORMALモード か？
		goto	caleb04			;No. 1:LARGEモード

		; 該当日のブリンク表示位置を復帰
		movf	column_wk,W
		movwf	column			;表示位置 column を復帰
		movf	pagex_wk,W
		movwf	pagex			;表示位置 pagex を復帰
		call	xSSD1306_FontPos	;フォントの表示開始位置指定

		; 該当日をブリンク表示
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		call	bit_rev_flg_set		;ビット反転表示指示フラグの設定
		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		swapf	temp_dd,W		;退避用 日_BCD カウンタ 上位4ビット
		andlw	h'0f'
		btfss	STATUS,Z		;上位4ビット = 0 か？
		goto	caleb01			;No

		movlw	a' '			;ゼロサプレス
		call	xSSD1306_DispChr	;OLED へデータを１文字出力
		goto	caleb02

caleb01		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力

caleb02		movf	temp_dd,W		;退避用 日_BCD カウンタ 下位4ビット
		call	number_disp		;BCD から数字へ変換後 OLED へ１文字出力
		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0

caleb03		return

		; LARGEモード時の表示
caleb04		call	calendar_display_blk_lg	 ;カレンダーのブリンク表示
		return

;--------------------------------------------------------------------------
;		LARGE & SET モード時の カレンダー（日）のブリンク表示
;--------------------------------------------------------------------------

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;			      >	bit4: カレンダフラグ
;				bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ
;				bit0: 秒フラグ

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.25秒ブリンクフラグ
;			      >	bit0:   0.5秒/0.25秒経過表示フラグ

calendar_display_blk_lg

		; 日 (dd) の表示
		xOLED_FontPos_M	4+12*8,0	;表示開始位置の指定

		swapf	bcd_dd,W		;日_BCD カウンタ 上位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示

		movf	bcd_dd,W		;日_BCD カウンタ 下位4ビット
		call	number_disp_lg		;BCD から数字へ変換後 LARGE 文字を表示
		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		return


;==========================================================================
;	    プログラムタイトルの表示と 縁枠のドット移動デモ表示
;==========================================================================

title_demo_display

		; プログラムタイトルの表示

		clrf	echr_flg		;表示文字の機能拡張フラグ = Normal

		xOLED_FontPos_M	4+6*1,1
		xOLED_DispStr_M	prog_title,1	;"Perpetual Calendar"

		xOLED_FontPos_M	4+6*3,2
		xOLED_DispStr_M	,0		;"(OLED Edition)"

		xOLED_FontPos_M	4+6*4,4
		xOLED_DispStr_M	,0		;"Version x.xx"

		xOLED_FontPos_M	1+6*4,6
		xOLED_DispStr_M	,0		;"by m.yamamoto"

		; デモ表示の省略チェック

		movf	PORTA,W
		andlw	b'00110011'		;PORTA の全スイッチを読み取る
		xorlw	b'00100001'		;反転
		;            ^  ^
		btfsc	STATUS,Z		;DOWN + UP スイッチ = ON か？
		goto	tddsp03			;Yes

		; 縁枠のドット移動デモ表示

		call	edge_frame_on		;上下左右縁枠の表示
		movlw	2
		call	wwait_xs		;2 秒間のウエイト
 
		call	edge_frame_off		;上下左右縁枠の消去
		call	wwait_1s		;1 秒間のウエイト

		call	demo_display		;縁枠のドット移動デモ表示
		call	wwait_1s		;1 秒間のウエイト

		movlw	2
		movwf	lpcnt			;ループカウンタの初期設定

tddsp01		call	edge_frame_on		;上下左右縁枠の表示
		call	wwait_500ms		;500 m秒のウェイト

		call	edge_frame_off		;上下左右縁枠の消去
		call	wwait_500ms		;500 m秒のウェイト

		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	tddsp01			;No

		movlw	3
		movwf	lpcnt			;ループカウンタの初期設定

tddsp02		call	edge_frame_on		;上下左右縁枠の表示
		call	wwait_250ms		;250 m秒のウェイト

		call	edge_frame_off		;上下左右縁枠の消去
		call	wwait_250ms		;250 m秒のウェイト

		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	tddsp02			;No

		call	wwait_500ms		;500 m秒のウェイト

tddsp03		call	edge_frame_on		;上下左右縁枠の表示
		movlw	3
		call	wwait_xs		;3 秒間のウエイト

		movlp	high SSD1306_Clear
		call	SSD1306_Clear		;全画面消去
		movlp	high $
		return

;--------------------------------------------------------------------------

		; プログラムタイトル メッセージ

prog_title	dt	 "Perpetual Calendar",0
		dt	   "(OLED Edition)"  ,0
		dt	    "Version ",ver_no,0
		dt	    "by m.yamamoto"  ,0
;			 01234567890123456789

;--------------------------------------------------------------------------
;		上下左右縁枠の表示と消去
;--------------------------------------------------------------------------

edge_frame_on
		xOLED_Line_H_M	  0,127,0,h'01'	;上の横線 ;表示
		xOLED_Line_H_M	  0,127,7,h'80'	;下の横線
		xOLED_Line_V_M	  0,  0,7,h'ff'	;左の縦線
		xOLED_Line_V_M	127,  0,7,h'ff'	;右の縦線
		return

edge_frame_off
		xOLED_Line_H_M	  0,127,0,h'00'	;上の横線 ;消去
		xOLED_Line_H_M	  0,127,7,h'00'	;下の横線
		xOLED_Line_V_M	  0,  0,7,h'00'	;左の縦線
		xOLED_Line_V_M	127,  0,7,h'00'	;右の縦線
		return

;==========================================================================
;		上下左右縁枠の ドット移動デモ表示
;==========================================================================

demo_display
		call	demo1_display
		call	demo2_display
		call	demo3_display
		call	demo4_display
		return

;--------------------------------------------------------------------------
;			　　　(1)
;			　　　→→
;		デモ-1	 (2)↓　　↓(4)
;			　　　→→
;			　　　(3)
;--------------------------------------------------------------------------

demo1_display
		movlw	2
		movwf	lpcnt			;ループカウンタの初期設定

;		左上→右上方向と 左上→左下方向に ドット増(lpcnt=2)／減(lpcnt=1)移行

demo101		clrf	gl_y			;Y座標(左縁線用)の初期設定
		clrf	gl_x			;X座標(上縁線用)の初期設定

demo102		movlw	h'01'
		movwf	wr_data			;WriteData(左縁線用)の初期設定

demo103		call	upper_left_right	;(1) 上縁線(左→右)の表示
		btfsc	gl_x,0			;gl_x % 2 = 1 か？
		call	left_upper_lower   ;Yes	;(2) 左縁線(上→下)の表示

		call	wwait_10ms		;10 ミリ秒ウェイト

		;繰り返しチェック
		movlw	h'0f'
		andwf	gl_x,W
		btfss	STATUS,Z		;gl_x % 16 = 0 か？
		goto	demo103			;No

		incf	gl_y,F			;Y座標の更新
		btfss	gl_x,7			;gl_x = 128 か？
		goto	demo102			;No

;		左下→右下方向と 右上→右下方向に ドット増(lpcnt=2)／減(lpcnt=1)移行

		clrf	gl_y			;Y座標(右縁線用)の初期設定
		clrf	gl_x			;X座標(下縁線用)の初期設定

demo104		movlw	h'01'
		movwf	wr_data			;WriteData(右縁線用)の初期設定

demo105		call	lower_left_right	;(3) 下縁線(左→右)の表示
		btfsc	gl_x,0			;gl_x % 2 = 1 か？
		call	right_upper_lower  ;Yes	;(4) 右縁線(上→下)の表示

		call	wwait_10ms		;10 ミリ秒ウェイト

		;繰り返しチェック
		movlw	h'0f'
		andwf	gl_x,W
		btfss	STATUS,Z		;gl_x % 16 = 0 か？
		goto	demo105			;No

		incf	gl_y,F			;Y座標の更新
		btfss	gl_x,7			;gl_x = 128 か？
		goto	demo104			;No
;
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	demo101			;No

		return

;--------------------------------------------------------------------------
;			　　　 (1)
;			　　　←←
;		デモ-2	 (4)↓　　↓(2)
;			　　　←←
;			　　　 (3)
;--------------------------------------------------------------------------

demo2_display
		movlw	2
		movwf	lpcnt			;ループカウンタの初期設定

;		右上→左上方向と 右上→右下方向に ドット増(lpcnt=2)／減(lpcnt=1)移行

demo201		clrf	gl_y			;Y座標(右縁線用)の初期設定
		movlw	127
		movwf	gl_x			;X座標(上縁線用)の初期設定

demo202		movlw	h'01'
		movwf	wr_data			;WriteData(右縁線用)の初期設定

demo203		call	upper_right_left	;(1) 上縁線(右→左)の表示
		btfss	gl_x,0			;gl_x % 2 = 0 か？
		call	right_upper_lower  ;Yes	;(2) 右縁線(上→下)の表示

		call	wwait_10ms		;10 ミリ秒ウェイト

		;繰り返しチェック
		incf	gl_x,W
		andlw	h'0f'
		btfss	STATUS,Z		;gl_x % 16 = 0 か？
		goto	demo203			;No

		incf	gl_y,F			;Y座標の更新
		incfsz	gl_x,W			;gl_x + 1 = 0 か？
		goto	demo202			;No

;		右下→左下方向と 左上→左下方向に ドット増(lpcnt=2)／減(lpcnt=1)移行

		clrf	gl_y			;Y座標(左縁線用)の初期設定
		movlw	127
		movwf	gl_x			;X座標(下縁線用)の初期設定

demo204		movlw	h'01'
		movwf	wr_data			;WriteData(左縁線用)の初期設定

demo205		call	lower_right_left	;(3) 下縁線(右→左)の表示
		btfss	gl_x,0			;gl_x % 2 = 0 か？
		call	left_upper_lower   ;Yes	;(4) 左縁線(上→下)の表示

		call	wwait_10ms		;10 ミリ秒ウェイト

		;繰り返しチェック
		incf	gl_x,W
		andlw	h'0f'
		btfss	STATUS,Z		;gl_x % 16 = 0 か？
		goto	demo205			;No

		incf	gl_y,F			;Y座標の更新
		incfsz	gl_x,W			;gl_x + 1 = 0 か？
		goto	demo204			;No
;
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	demo201			;No

		return

;--------------------------------------------------------------------------
;			　　　 (3)
;			　　　←←
;		デモ-3	 (4)↑　　↑(2)
;			　　　←←
;			　　　 (1)
;--------------------------------------------------------------------------

demo3_display
		movlw	2
		movwf	lpcnt			;ループカウンタの初期設定

;		右下→左下方向と 右下→右上方向に ドット増(lpcnt=2)／減(lpcnt=1)移行

demo301		movlw	7
		movwf	gl_y			;Y座標(右縁線用)の初期設定
		movlw	127
		movwf	gl_x			;X座標(下縁線用)の初期設定

demo302		movlw	h'80'
		movwf	wr_data			;WriteData(右縁線用)の初期設定

demo303		call	lower_right_left	;(1) 下縁線(右→左)の表示
		btfss	gl_x,0			;gl_x % 2 = 0 か？
		call	right_lower_upper  ;Yes	;(2) 右縁線(下→上)の表示

		call	wwait_10ms		;10 ミリ秒ウェイト

		;繰り返しチェック
		incf	gl_x,W
		andlw	h'0f'
		btfss	STATUS,Z		;gl_x % 16 = 0 か？
		goto	demo303			;No

		decf	gl_y,F			;Y座標の更新
		incfsz	gl_x,W			;gl_x + 1 = 0 か？
		goto	demo302			;No

;		右上→左上方向と 左下→左上方向に ドット増(lpcnt=2)／減(lpcnt=1)移行

		movlw	7
		movwf	gl_y			;Y座標(左縁線用)の初期設定
		movlw	127
		movwf	gl_x			;X座標(上縁線用)の初期設定

demo304		movlw	h'80'
		movwf	wr_data			;WriteData(左縁線用)の初期設定

demo305		call	upper_right_left	;(3) 上縁線(右→左)の表示
		btfss	gl_x,0			;gl_x % 2 = 0 か？
		call	left_lower_upper   ;Yes	;(4) 左縁線(下→上)の表示

		call	wwait_10ms		;10 ミリ秒ウェイト

		;繰り返しチェック
		incf	gl_x,W
		andlw	h'0f'
		btfss	STATUS,Z		;gl_x % 16 = 0 か？
		goto	demo305			;No

		decf	gl_y,F			;Y座標の更新
		incfsz	gl_x,W			;gl_x + 1 = 0 か？
		goto	demo304			;No
;
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	demo301			;No

		return

;--------------------------------------------------------------------------
;			　　　(3)
;			　　　→→
;		デモ-4	 (2)↑　　↑(4)
;			　　　→→
;			　　　(1)
;--------------------------------------------------------------------------

demo4_display
		movlw	2
		movwf	lpcnt			;ループカウンタの初期設定

;		左下→右下方向と 左下→左上方向に ドット増(lpcnt=2)／減(lpcnt=1)移行

demo401		movlw	7
		movwf	gl_y			;Y座標(左縁線用)の初期設定
		clrf	gl_x			;X座標(下縁線用)の初期設定

demo402		movlw	h'80'
		movwf	wr_data			;WriteData(左縁線用)の初期設定

demo403		call	lower_left_right	;(1) 下縁線(左→右)の表示
		btfsc	gl_x,0			;gl_x % 2 = 1 か？
		call	left_lower_upper   ;Yes	;(2) 左縁線(下→上)の表示

		call	wwait_10ms		;10 ミリ秒ウェイト

		;繰り返しチェック
		movlw	h'0f'
		andwf	gl_x,W
		btfss	STATUS,Z		;gl_x % 16 = 0 か？
		goto	demo403			;No

		decf	gl_y,F			;Y座標の更新
		btfss	gl_x,7			;gl_x = 128 か？
		goto	demo402			;No

;		左上→右上方向と 右下→右上方向に ドット増(lpcnt=2)／減(lpcnt=1)移行

		movlw	7
		movwf	gl_y			;Y座標(右縁線用)の初期設定
		clrf	gl_x			;X座標(上縁線用)の初期設定

demo404		movlw	h'80'
		movwf	wr_data			;WriteData(右縁線用)の初期設定

demo405		call	upper_left_right	;(3) 上縁線(左→右)の表示
		btfsc	gl_x,0			;gl_x % 2 = 1 か？
		call	right_lower_upper  ;Yes	;(4) 右縁線(下→上)の表示

		call	wwait_10ms		;10 ミリ秒ウェイト

		;繰り返しチェック
		movlw	h'0f'
		andwf	gl_x,W
		btfss	STATUS,Z		;gl_x % 16 = 0 か？
		goto	demo405			;No

		decf	gl_y,F			;Y座標の更新
		btfss	gl_x,7			;gl_x = 128 か？
		goto	demo404			;No
;
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	demo401			;No

		return

;--------------------------------------------------------------------------

;		上縁線(左→右)の表示

;入力:		gl_x:    表示カラム

upper_left_right
		movf	gl_x,W
		btfsc	STATUS,Z		;gl_x = 0 か？
		goto	ulr01			;Yes

		movlw	127
		subwf	gl_x,W
		btfsc	STATUS,Z		;gl_x = 127 か？
		goto	ulr01			;Yes

		movf	gl_y,W			;退避
		movwf	work1
		clrf	gl_y			;Y座標 = 0 (固定)
		call	xSSD1306_FontPos	;X座標 = 0～127 (可変)
		movf	work1,W
		movwf	gl_y			;復帰

		movlw	h'01'			;WriteData = h'01'
		btfss	lpcnt,1			;lpcnt = 2 か？
		clrw			;No	;WriteData = h'00'
		call	xdata_byte		;データ１バイト出力, 上縁線の書き込み

ulr01		incf	gl_x,F			;X座標の更新
		return

;--------------------------------------------------------------------------

;		上縁線(右→左)の表示

;入力:		gl_x:    表示カラム

upper_right_left
		movlw	127
		subwf	gl_x,W
		btfsc	STATUS,Z		;gl_x = 127 か？
		goto	url01			;Yes

		movf	gl_x,W
		btfsc	STATUS,Z		;gl_x = 0 か？
		goto	url01			;Yes

		movf	gl_y,W			;退避
		movwf	work1
		clrf	gl_y			;Y座標 = 0 (固定)
		call	xSSD1306_FontPos	;X座標 = 0～127 (可変)
		movf	work1,W
		movwf	gl_y			;復帰

		movlw	h'01'			;WriteData = h'01'
		btfss	lpcnt,1			;lpcnt = 2 か？
		clrw			;No	;WriteData = h'00'
		call	xdata_byte		;データ１バイト出力, 上縁線の書き込み

url01		decf	gl_x,F			;X座標の更新
		return

;--------------------------------------------------------------------------

;		下縁線(左→右)の表示

;入力:		gl_x:    表示カラム

lower_left_right
		movf	gl_x,W
		btfsc	STATUS,Z		;gl_x = 0 か？
		goto	llr01			;Yes

		movlw	127
		subwf	gl_x,W
		btfsc	STATUS,Z		;gl_x = 127 か？
		goto	llr01			;Yes

		movf	gl_y,W			;退避
		movwf	work1
		movlw	7
		movwf	gl_y			;Y座標 = 7 (固定)
		call	xSSD1306_FontPos	;X座標 = 0～127 (可変)
		movf	work1,W
		movwf	gl_y			;復帰

		movlw	h'80'			;WriteData = h'80'
		btfss	lpcnt,1			;lpcnt = 2 か？
		clrw			;No	;WriteData = h'00'
		call	xdata_byte		;データ１バイト出力, 上縁線の書き込み

llr01		incf	gl_x,F			;X座標の更新
		return

;--------------------------------------------------------------------------

;		下縁線(右→左)の表示

;入力:		gl_x:    表示カラム

lower_right_left
		movlw	127
		subwf	gl_x,W
		btfsc	STATUS,Z		;gl_x = 127 か？
		goto	lrl01			;Yes

		movf	gl_x,W
		btfsc	STATUS,Z		;gl_x = 0 か？
		goto	lrl01			;Yes

		movf	gl_y,W			;退避
		movwf	work1
		movlw	7
		movwf	gl_y			;Y座標 = 7 (固定)
		call	xSSD1306_FontPos	;X座標 = 0～127 (可変)
		movf	work1,W
		movwf	gl_y			;復帰

		movlw	h'80'			;WriteData = h'80'
		btfss	lpcnt,1			;lpcnt = 2 か？
		clrw			;No	;WriteData = h'00'
		call	xdata_byte		;データ１バイト出力, 上縁線の書き込み

lrl01		decf	gl_x,F			;X座標の更新
		return

;--------------------------------------------------------------------------

;		左縁線(上→下)の表示

;入力:		gl_y:    表示ページ
;		wr_data: 表示データ

left_upper_lower
		movf	gl_x,W			;退避
		movwf	work1
		clrf	gl_x			;X座標 = 0 (固定)
		call	xSSD1306_FontPos	;Y座標 = 0～7 (可変)
		movf	work1,W
		movwf	gl_x			;復帰

		movf	wr_data,W		;WriteData = h'01',h'03',h'07',h'0f',h'1f',h'3f',h'7f',h'ff'
		btfsc	lpcnt,0			;lpcnt = 1 か？
		xorlw	h'ff'		;Yes	;反転値    = h'fe',h'fc',h'f8',h'f0',h'e0',h'c0',h'80',h'00'
		call	xdata_byte		;データ１バイト出力, 左縁線の書き込み (可変)

		bsf	STATUS,C
		rlf	wr_data,F		;WriteDataの更新
		return

;--------------------------------------------------------------------------

;		左縁線(下→上)の表示

;入力:		gl_y:    表示ページ
;		wr_data: 表示データ

left_lower_upper
		movf	gl_x,W			;退避
		movwf	work1
		clrf	gl_x			;X座標 = 0 (固定)
		call	xSSD1306_FontPos	;Y座標 = 0～7 (可変)
		movf	work1,W
		movwf	gl_x			;復帰

		movf	wr_data,W		;WriteData = h'80',h'c0',h'e0',h'f0',h'f8',h'fc',h'fe',h'ff'
		btfsc	lpcnt,0			;lpcnt = 1 か？
		xorlw	h'ff'		;Yes	;反転値    = h'7f',h'3f',h'1f',h'0f',h'07',h'03',h'01',h'00'
		call	xdata_byte		;データ１バイト出力, 左縁線の書き込み (可変)

		bsf	STATUS,C
		rrf	wr_data,F		;WriteDataの更新
		return

;--------------------------------------------------------------------------

;		右縁線(上→下)の表示

;入力:		gl_y:    表示ページ
;		wr_data: 表示データ

right_upper_lower
		movf	gl_x,W			;退避
		movwf	work1
		movlw	127
		movwf	gl_x			;X座標 = 127 (固定)
		call	xSSD1306_FontPos	;Y座標 = 0～7 (可変)
		movf	work1,W
		movwf	gl_x			;復帰

		movf	wr_data,W		;WriteData = h'01',h'03',h'07',h'0f',h'1f',h'3f',h'7f',h'ff'
		btfsc	lpcnt,0			;lpcnt = 1 か？
		xorlw	h'ff'		;Yes	;反転値    = h'fe',h'fc',h'f8',h'f0',h'e0',h'c0',h'80',h'00'
		call	xdata_byte		;データ１バイト出力, 右縁線の書き込み (可変)

		bsf	STATUS,C
		rlf	wr_data,F		;WriteDataの更新
		return

;--------------------------------------------------------------------------

;		右縁線(下→上)の表示

;入力:		gl_y:    表示ページ
;		wr_data: 表示データ

right_lower_upper
		movf	gl_x,W			;退避
		movwf	work1
		movlw	127
		movwf	gl_x			;X座標 = 127 (固定)
		call	xSSD1306_FontPos	;Y座標 = 0～7 (可変)
		movf	work1,W
		movwf	gl_x			;復帰

		movf	wr_data,W		;WriteData = h'80',h'c0',h'e0',h'f0',h'f8',h'fc',h'fe',h'ff'
		btfsc	lpcnt,0			;lpcnt = 1 か？
		xorlw	h'ff'		;Yes	;反転値    = h'7f',h'3f',h'1f',h'0f',h'07',h'03',h'01',h'00'
		call	xdata_byte		;データ１バイト出力, 右縁線の書き込み (可変)

		bsf	STATUS,C
		rrf	wr_data,F		;WriteDataの更新
		return


;==========================================================================
;		メンテナンスメッセージの表示
;==========================================================================

mainte_msg_disp
		xOLED_FontPos_M	7+6*0,0		;
		clrf	echr_flg		;表示文字の機能拡張フラグのクリア
		xOLED_DispStr_M	mainte_msg,1	;1 行目の表示

	;;	xOLED_FontPos_M	4+6*2,1		;
	;;	bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
	;;	xOLED_DispStr_M	,0		;2 行目の表示
;
		xOLED_FontPos_M	3+6*1,3		;
		bcf	echr_flg,6		;1 bit 左(下)ずらし指示 = 0
		xOLED_DispStr_M	,0		;3 行目の表示

		xOLED_FontPos_M	3+6*2,4		;
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		xOLED_DispStr_M	,0		;4 行目の表示
;
		xOLED_FontPos_M	3+6*1,6		;
		bcf	echr_flg,6		;1 bit 左(下)ずらし指示 = 0
		xOLED_DispStr_M	,0		;5 行目の表示

		xOLED_FontPos_M	3+6*2,7		;
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		xOLED_DispStr_M	,0		;6 行目の表示
		clrf	echr_flg		;表示文字の機能拡張フラグのクリア
;
		movlp	high battery_volt__display			;;
		call	battery_volt__display	;バッテリーの電圧表示	;;
		movlp	high $			;2 行目の表示		;;

		call	contrast_disp		;OLED コントラスト値の表示
		call	sleep_time_disp		;スリープまでの移行時間（分）値の表示
		return

mainte_msg
		dt	"=== Maintenance ===",0	;1 行目
	;;	dt	  "[ Batt =  .  V ]",0	;2 行目
		dt	 "> OLED Contrast",0	;3 行目
		dt	  "(001-255) ? _",0	;4 行目
		dt	 "> Sleep Time",0	;5 行目
		dt	  "(00-60) ? _",0	;6 行目

;--------------------------------------------------------------------------
;		OLED コントラスト値の表示
;--------------------------------------------------------------------------

contrast_disp
		xOLED_FontPos_M	3+6*16-1,4	;
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		movf	contrast,W		;OLED コントラスト
		movwf	work1
		call	bindec8c_cnv		;8 ビット数値を 10進数 3桁の文字列に変換

		movlw	high buff		;
		movwf	FSR0H			;
		movlw	low buff		;
		movwf	FSR0L			;

		moviw	FSR0++
		call	xSSD1306_DispChr	;100 位
		moviw	FSR0++
		call	xSSD1306_DispChr	; 10 位
		moviw	FSR0++
		call	xSSD1306_DispChr	;  1 位
		return

;--------------------------------------------------------------------------
;		スリープまでの移行時間（分）値の表示
;--------------------------------------------------------------------------

sleep_time_disp
		xOLED_FontPos_M	3+6*14-1,7	;
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		call	xrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		movf	sleep_time,W		;スリープまでの移行時間（分）
		movwf	work1
		call	bindec8c_cnv		;8 ビット数値を 10進数 3桁の文字列に変換

		movlw	high (buff+1)		;
		movwf	FSR0H			;
		movlw	low (buff+1)		;
		movwf	FSR0L			;

		moviw	FSR0++
		call	xSSD1306_DispChr	; 10 位
		moviw	FSR0++
		call	xSSD1306_DispChr	;  1 位
		return

;--------------------------------------------------------------------------
;		8 ビット数値を 10進数 3桁の文字列に変換
;--------------------------------------------------------------------------

; 使用変数:	         work1: 変換する 8 ビット数値
;		         work2: ワーク
;		         lpcnt: ループカウンタ
;		   buff + 0～2: 結果

bindec8c_cnv
		movlw	high (buff+2+1)		;変換文字列の格納エリア
		movwf	FSR0H
		movlw	low (buff+2+1)
		movwf	FSR0L			;間接アドレスの設定

		call	bd8c			;(02) 最下位変換
		call	bd8c			;(01)
		call	bd8c			;(00) 最上位変換
		return

		; ÷10（10で除算）
bd8c
		movlw	8			;8ビット繰り返し
		movwf	lpcnt			;シフトカウンタに設定
		clrf	work2			;一時余り格納場所のクリア

bd8c01		lslf	work1,F
		rlf	work2,F

		movlw	-10			;-10 = h'f6'
		addwf	work2,W
		btfsc	STATUS,C		;C = 0 か？
		movwf	work2			;No
		btfsc	STATUS,C		;C = 0 か？
		incf	work1,F			;No
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	bd8c01			;No

		movf	work2,W			;余り
		addlw	h'30'			;文字コードに変換
		movwi	--FSR0
		return

;
;==========================================================================
;--------------------------------------------------------------------------
 		org	h'1000'			;(Page 2)
;--------------------------------------------------------------------------
;==========================================================================

;--------------------------------------------------------------------------
;		マクロ命令の定義 (Page 2 用)
;--------------------------------------------------------------------------

;		yOLED_FontPos_M マクロ		;フォントの表示開始位置指定

yOLED_FontPos_M	macro	@col,@row
		movlw	@col			;
		movwf	column			;表示カラム
		movlw	@row			;
		movwf	pagex			;表示ページ
		call	ySSD1306_FontPos	;表示開始位置指定
		endm

;		yOLED_DispStr_M マクロ		;キャラクタ (横:6 x 縦:8) 文字列の表示

yOLED_DispStr_M	macro	@str_adr,@x
	#if 	@x != 0
		movlw	high @str_adr		;文字列の先頭 high アドレス
		movwf	FSR0H			;
		movlw	low @str_adr		;文字列の先頭 low アドレス
		movwf	FSR0L			;
	#endif
		call	ySSD1306_DispStr	;文字列データ１行表示
		endm

;--------------------------------------------------------------------------
;		ページ変換サブルーチン (Page 2 用)
;--------------------------------------------------------------------------

ySSD1306_FontPos
		movlp	high SSD1306_FontPos
		call	SSD1306_FontPos		;表示開始位置指定
		movlp	high $
		return

ySSD1306_DispChr
		movlp	high SSD1306_DispChr
		call	SSD1306_DispChr		;OLED へデータを１文字出力
		movlp	high $
		return

ySSD1306_DispStr
		movlp	high SSD1306_DispStr
		call	SSD1306_DispStr		;(横:6 x 縦:8) 文字列の表示
		movlp	high $
		return

ySSD1306_Line_H
		movlp	high SSD1306_Line_H
		call	SSD1306_Line_H		;水平線表示
		movlp	high $
		return

ySSD1306_Clear
		movlp	high SSD1306_Clear
		call	SSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去
		movlp	high $
		return

ytmdisp_area_clear
		movlp	high tmdisp_area_clear
		call	tmdisp_area_clear	;タイマーメモリ表示エリア (page2～5) の h'00'クリア
		movlp	high $
		return

yrev_shift_byte
		movlp	high rev_shift_byte
		call	rev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		movlp	high $
		return

ybit_rev_flg_set
		movlp	high bit_rev_flg_set
		call	bit_rev_flg_set		;ビット反転表示指示フラグの設定
		movlp	high $
		return
;
ywait_15ms
		movlp	high wait_15ms
		call	wait_15ms		;15m 秒 ウェイトルーチン
		movlp	high $
		return

ybuzzer_pi
		movlp	high buzzer_pi
		call	buzzer_pi		;"ピッ" ブザー音
		movlp	high $
		return

ybuzzer_pipi
		movlp	high buzzer_pipi
		call	buzzer_pipi		;"ピピッ" ブザー音
		movlp	high $
		return

ybuzzer_bu
		movlp	high buzzer_bu
		call	buzzer_bu		;"ブッ" ブザー音
		movlp	high $
		return

ybuzzer_buu
		movlp	high buzzer_buu
		call	buzzer_buu		;"ブー" ブザー音
		movlp	high $
		return

ybuzzer_popo
		movlp	high buzzer_po
		call	buzzer_po		;"ポッポッ" ブザー音
		call	wait_30ms
		call	buzzer_po
		movlp	high $
		return

yflash_mem_erase_write
		movlp	high flash_mem_erase
		call	flash_mem_erase		;フラッシュメモリを３行（32 * 3 ワード）消去
		call	flash_mem_write		;RAM バッファからフラッシュメモリへデータ書き込み
		movlp	high $
		return


;==========================================================================
;		バッテリー（18650 リチウムイオン電池）の電圧測定
;==========================================================================

;			    ┌───┐  ┌───┐
;			┌─┤3.3KΩ├─┤3.3KΩ├── 電源電圧
;			│  └───┘  └───┘
;	   RC2(AN6) ──┤
;			│  ┌───┐
;			└─┤3.3KΩ├──────── GND
;			    └───┘

battery_voltage

;	     >> BATTERY 電源電圧を測定する

		movlb	1			;バンク 1
		bsf	ADCON0,ADON		;ADC 有効 = 電源 ON
		movlb	0			;バンク 0
		movlp	high wait_20us
		call	wait_20us		;アクイジション時間 (5μS以上)
		movlp	high $
		movlb	1			;バンク 1
		bsf	ADCON0,ADGO		;A/D 変換開始
		btfsc	ADCON0,ADGO		;変換完了(ハードでクリア) か？
		goto	$ - 1			;No

		bcf	ADCON0,ADON		;ADC 無効 = 電源 OFF
		movlb	0			;バンク 0

;	     >> 結果 = ADRESH:ADRESL (右詰め) に測定電圧値
;
;		抵抗で分圧した分(2/3)を補正 ... x 3 倍する

		clrf	ad_res_hi
		clrf	ad_res_lo
		movlw	3
		movwf	lpcnt			;ループカウンタ

battv01		movlb	1			;バンク 1
		movf	ADRESL,W		;
		addwf	ad_res_lo,F
		movf	ADRESH,W		;
		addwfc	ad_res_hi,F
		movlb	0			;バンク 0
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	battv01			;No

;	     >> 結果 = ad_res_hi:ad_res_lo ... x 3 倍に補正したバイナリデータ
;
;	  2.048 (V) : X (V) = 1024 : ad_res_hi:ad_res_lo
;
;	              X (V) = 2.048 * ad_res_hi:ad_res_lo / 1024
;	                    = 0.002 * ad_res_hi:ad_res_lo
;        	            = ad_res_hi:ad_res_lo / 500
;
;	        X (V) * 500 = ad_res_hi:ad_res_lo
;
;	     >> 0.01 V 単位にするため x 100 倍にする ... 5 で割る
;
;	        X (V) * 100 = ad_res_hi:ad_res_lo / 5

		movlb	1			;バンク 1
		movf	ad_res_hi,W		;割られる数
		movwf	a16_hi
		movf	ad_res_lo,W
		movwf	a16_lo
		clrf	b16_hi			;割る数
		movlw	5
		movwf	b16_lo
		call	div_16			;16 ビットの割り算
		movlb	0			;バンク 0

;	(a16_hi,a16_lo) ÷ (b16_hi,b16_lo) = (x16_hi,x16_lo) ... (y16_hi,y16_lo) 
;
;	     >> 結果 = 商 (x16_hi,x16_lo) ... 余り (y16_hi,y16_lo) は無視

		return

;--------------------------------------------------------------------------
;		16 ÷ 16 ＝ 16 ビットの割り算
;--------------------------------------------------------------------------

;	(a16_hi,a16_lo) ÷ (b16_hi,b16_lo) = (x16_hi,x16_lo) ... (y16_hi,y16_lo) 

; 使用変数:	a16_hi, a16_lo: 割られる数の上,下位	(終了時は０になる)
;		b16_hi, b16_lo: 割る数の    上,下位	(終了時に変化しない)
;		x16_hi, x16_lo: 答えの      上,下位	(答えが返る)
;		y16_hi, y16_lo: 余りの      上,下位	(余りが返る、ワークにも使用)
;		lcnt1,  lcnt2:  ループカウンタ
;		C フラグ:	エラーフラグ		(割る数が０であった場合 C=1)

div_16
		movlw	16
		movwf	lcnt1			;ループカウンタ1
		movf	b16_lo,W		;割る数下位をワークにコピー
		movwf	y16_lo
		movf	b16_hi,W		;割る数上位をワークにコピー
		movwf	y16_hi

d16_01		rlf	y16_lo,F		;左シフトする
		rlf	y16_hi,F
		btfsc	STATUS,C		;キャリフラグを見る
		goto	d16_02			;割る数の上位ビット位置検索

		decfsz	lcnt1,F
		goto	d16_01

		bsf	STATUS,C		;割る数が０である。エラー終了
		goto	d16_09

d16_02		clrf	x16_lo			;答え用変数のクリア
		clrf	x16_hi
		clrf	y16_lo			;ワーク変数のクリア
		clrf	y16_hi

		movlw	16
		movwf	lcnt2			;ループカウンタ2
		movf	lcnt1,W
		subwf	lcnt2,F			;残り、実ループの回数

d16_03		lslf	a16_lo,F
		rlf	a16_hi,F
		rlf	y16_lo,F
		rlf	y16_hi,F
		decfsz	lcnt1,F			;割られる数を初期位置までシフト
		goto	d16_03

d16_04		movf	b16_hi,W		;現位置での減算が可能かチェック
		subwf	y16_hi,W
		btfss	STATUS,C
		goto	d16_06

		movf	y16_hi,W
		subwf	b16_hi,W
		btfss	STATUS,C
		goto	d16_05

		movf	b16_lo,W
		subwf	y16_lo,W
		btfss	STATUS,C
		goto	d16_06

d16_05		movf	b16_lo,W
		subwf	y16_lo,F		;ワークから下位を引く
		btfss	STATUS,C		;キャリフラグが 1（正）なら次をスキップ
		decf	y16_hi,F		;上位 -1

		movf	b16_hi,W
		subwf	y16_hi,F		;ワークから上位を引く
		bsf	STATUS,C		;キャリフラグをセット
		goto	d16_07

d16_06		bcf	STATUS,C		;キャリフラグをクリア

d16_07		rlf	x16_lo,F		;キャリフラグの内容を答えにシフト
		rlf	x16_hi,F
		movf	lcnt2,F
		btfsc	STATUS,Z		;lcnt2 = 0 か？
		goto	d16_08			;Yes, 終了

		decf	lcnt2,F			;ビット位置を１つ下げる（右へ）
		lslf	a16_lo,F		;ワークへ１ビット左シフト
		rlf	a16_hi,F
		rlf	y16_lo,F
		rlf	y16_hi,F
		goto	d16_04

d16_08		bcf	STATUS,C		;正常終了

d16_09		return

;==========================================================================
;		バッテリー（18650 リチウムイオン電池）の電圧表示
;==========================================================================

battery_volt__display

		yOLED_FontPos_M	4+6*2,1		;
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		yOLED_DispStr_M	batt_msg,1	;2 行目の表示

		call	battery_voltage		;バッテリーの電圧測定

		movlb	1			;バンク 1
		movf	x16_hi,W
		movwf	a16_hi
		movf	x16_lo,W
		movwf	a16_lo
		call	bindec16cz_cnv		;16 ビット数値を 10進数 5桁の文字列に変換
		movlb	0			;バンク 0

		movlw	high (buff0+2)		;
		movwf	FSR0H			;
		movlw	low (buff0+2)		;
		movwf	FSR0L			;間接アドレスの設定

		yOLED_FontPos_M	4+6*11,1	;
		moviw	FSR0++
		call	ySSD1306_DispChr	;OLED へ１文字出力
		movlw	'.'
		call	ySSD1306_DispChr	;OLED へ１文字出力
		moviw	FSR0++
		call	ySSD1306_DispChr	;OLED へ１文字出力
		moviw	FSR0++
		call	ySSD1306_DispChr	;OLED へ１文字出力
		return

	;	dt	"=== Maintenance ===",0	;1 行目
batt_msg	dt	  "[ Batt =  .  V ]",0	;2 行目

;--------------------------------------------------------------------------

battery_volt__display2

		yOLED_FontPos_M	3+6*8,7		;
		movlw	h'c0'			;h'c0': ビット反転表示とビットずらし指示
		movwf	echr_flg		;
		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		yOLED_DispStr_M	batt_msg2,1	;7 行目の表示

		call	battery_voltage		;バッテリーの電圧測定

		movlb	1			;バンク 1
		movf	x16_hi,W
		movwf	a16_hi
		movf	x16_lo,W
		movwf	a16_lo
		call	bindec16cz_cnv		;16 ビット数値を 10進数 5桁の文字列に変換
		movlb	0			;バンク 0

		movlw	high (buff0+2)		;
		movwf	FSR0H			;
		movlw	low (buff0+2)		;
		movwf	FSR0L			;間接アドレスの設定

		yOLED_FontPos_M	4+6*14,7	;
		moviw	FSR0++
		call	ySSD1306_DispChr	;OLED へ１文字出力
		movlw	'.'
		call	ySSD1306_DispChr	;OLED へ１文字出力
		moviw	FSR0++
		call	ySSD1306_DispChr	;OLED へ１文字出力
		moviw	FSR0++
		call	ySSD1306_DispChr	;OLED へ１文字出力
		clrf	echr_flg		;表示文字の機能拡張フラグのクリア
		return

batt_msg2	dt	  "[Batt= .  V]",0	;

;--------------------------------------------------------------------------
;		16 ビット数値を 10進数 5桁の文字列に変換（ゼロサプレス)
;--------------------------------------------------------------------------

; 使用変数:	a16_hi, a16_lo: 変換する 16 ビット数値
;		 	 lcnt1: ワーク
;		         lcnt2: ループカウンタ
;		  buff0 + 0～4: 結果

bindec16cz_cnv
		movlw	high (buff0+4+1)	;変換文字列の格納エリア
		movwf	FSR0H
		movlw	low (buff0+4+1)
		movwf	FSR0L			;間接アドレスの設定

		call	bd16c			;(04) 最下位変換
		call	bd16c			;(03)
		call	bd16c			;(02)
		call	bd16c			;(01)
		call	bd16c			;(00) 最上位変換

		movlw	4			;
		movwf	lcnt2			;ループカウンタに設定

bd16cv01	moviw	0[FSR0]
		sublw	h'30'
		btfss	STATUS,Z		;(INDF) = h'30' か？
		goto	bd16cv02		;No

		movlw	' '
		movwi	FSR0++
		decfsz	lcnt2,F			;ループカウンタ - 1 = 0 か？
		goto	bd16cv01		;No

bd16cv02	return

		; ÷10（10で除算）
bd16c
		movlw	16			;16ビット繰り返し
		movwf	lcnt2			;ループカウンタに設定
		clrf	lcnt1			;ワーク

bd16c01		lslf	a16_lo,F
		rlf	a16_hi,F
		rlf	lcnt1,F
		movlw	-10			;-10 = h'f6'
		addwf	lcnt1,W
		btfsc	STATUS,C		;C = 0 か？
		movwf	lcnt1			;No
		btfsc	STATUS,C		;C = 0 か？
		incf	a16_lo,F		;No
		decfsz	lcnt2,F			;ループカウンタ - 1 = 0 か？
		goto	bd16c01			;No

		movf	lcnt1,W			;余り
		addlw	h'30'			;文字コードに変換
		movwi	--FSR0
		return


;==========================================================================
;		タイマー機能の処理
;==========================================================================

;	タイマー用メモリの構成			;タイマー用メモリのサイズ = 7 バイト x 10 メモリ = 70 バイト

;	+0        +1        +2        +3        +4        +5        +6
;	f---.-aat yyyy.yyyy yyyy.yyyy nnnn.nnnn dddd.dddd hhhh.hhhh mmmm.mmmm
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| ||||
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| ++++-- 一分(0～9)
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| ++++------- 十分(0～5)
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| ||||
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| |||| |||| ++++------------ 一時(0～9)
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| |||| ++++----------------- 十時(0～2)
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| ||||
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| ++++---------------------- 一日(0～9) / 曜日（t=1 のとき）
;	|||| |||| |||| |||| |||| |||| |||| |||| ||||                                          0000: EDAY
;	|||| |||| |||| |||| |||| |||| |||| |||| ||||                                          0001: SUN
;	|||| |||| |||| |||| |||| |||| |||| |||| ||||                                          0010: MON
;	|||| |||| |||| |||| |||| |||| |||| |||| ||||                                          0011: TUE
;	|||| |||| |||| |||| |||| |||| |||| |||| ||||                                          0100: WED
;	|||| |||| |||| |||| |||| |||| |||| |||| ||||                                          0101: THU
;	|||| |||| |||| |||| |||| |||| |||| |||| ||||                                          0110: FRI
;	|||| |||| |||| |||| |||| |||| |||| |||| ||||                                          0111: SAT
;	|||| |||| |||| |||| |||| |||| |||| |||| |||| 
;	|||| |||| |||| |||| |||| |||| |||| |||| ++++--------------------------- 十日(0～3)
;	|||| |||| |||| |||| |||| |||| |||| ||||
;	|||| |||| |||| |||| |||| |||| |||| ++++-------------------------------- 一月(0～9)
;	|||| |||| |||| |||| |||| |||| ++++------------------------------------- 十月(0～1)
;	|||| |||| |||| |||| |||| ||||
;	|||| |||| |||| |||| |||| ++++------------------------------------------ 一年(0～9)
;	|||| |||| |||| |||| ++++----------------------------------------------- 十年(0～9)
;	|||| |||| |||| ++++---------------------------------------------------- 百年(0～9)
;	|||| |||| ++++--------------------------------------------------------- 千年(0～9)
;	|||| ||||
;	|||| |||+-------------------------------------------------------------- タイマー種類
;	|||| |||                                                                  0: 年タイマー
;	|||| |||                                                                  1: 週間タイマー
;	|||| |||
;	|||| |++--------------------------------------------------------------- 24H/12H
;	|||| |                                                                   00: "  "
;	|||| |                                                                   01: "am"
;	|||| |                                                                   11: "pm"
;	|||| |  
;	|+++ +----------------------------------------------------------------- 未使用
;	|                              
;	+---------------------------------------------------------------------- メモリ有効フラグ
;	                                                                          0: 無効（空き）
;	                                                                          1: 有効（使用中）

;		本機におけるリニアデータメモリの使用構成図

;linear_memory	equ	h'2000' + 80 * 2	;リニアデータメモリの先頭アドレス
;save_data_ram	equ	linear_memory		;引継ぎ情報の先頭アドレス
;timer_memory	equ	save_data_ram  + 4	;タイマー用メモリの先頭アドレス
;timer_capacity	equ	10			;タイマー用メモリの記憶容量の最大値
;timer_mem_addr	equ	timer_memory   + 7 * timer_capacity ;タイマー用メモリの先頭アドレス
;work_memory	equ	timer_mem_addr + 2 * timer_capacity ;ワークメモリの先頭アドレス
;next_memory	equ	work_memory    + 7 * timer_capacity ;次に使用できるメモリの先頭アドレス

;		  linear_memory	|				|
;		  save_data_ram	+-------------------------------+ 20A0 (h'2000' + 80 * 2) ―――――――
;				|	    (4 bytes)		|			    ↑	    ↑
;		   timer_memory	+-------------------------------+ 20A4			    ｜	    ｜
;				|				|			    ｜	    ｜
;				|				|			  BACKUP    ｜
;				|	   (70 bytes)		|			(74 bytes)  ｜
;				|				|			    ｜	    ｜
;				|				|			    ↓	    ｜
;		 timer_mem_addr	+-------------------------------+ 20EA			  ―――   USE
;				|	   (20 bytes)		|			       (164 bytes)
;				|				|				    ｜
;		    work_memory	+-------------------------------+ 20FE				    ｜
;				|				|				    ｜
;				|				|				    ｜
;				|	   (70 bytes)		|				    ｜
;				|				|				    ｜
;				|				|				    ↓
;		    next_memory	+-------------------------------+ 2144			  ―――――――
;				|				|
;				|				|

;==========================================================================
;	     TIMER スイッチの処理 ... メイン・ルーチンから CALL
;==========================================================================

;	[スイッチ操作]

;	       TIMER スイッチ        ..... タイマーメモリの読み出しと消去

;	       TIMER スイッチ 長押し ..... タイマーメモリの設定（３秒以上の長押し）
;	      (TMSET スイッチ)

;	tmem_flg: タイマーメモリフラグ
;			      >	bit7: タイマー処理フラグ, 0:終了/1:タイマー処理
;			      >	bit6: 0:メモリREAD/1:メモリWRITE
;			      >	bit5: mode_flg.bit0 の記憶フラグ
;			      >	bit4: バックアップ要求フラグ
;				bit2: 書き込み無効フラグ
;			      >	bit1: タイマー種類選択の中断フラグ
;				bit0: タイマー種類フラグ, 0:年タイマー/1:週間タイマー

timer_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTC,_swTIM		;再度 TIMER スイッチ = ON か？
		goto	timsw06			;No

		bsf	mode_flg,5		;スイッチ入力有りフラグ = 1
		btfsc	save_flg,0		;(bcd_xx → temp_xx) 退避中フラグ = 1 か？
		goto	timsw06			;Yes

		bsf	tmem_flg,7		;タイマーメモリ処理フラグ = 1

		; ３秒間長押しの監視 = (4/8Mz*250*16=2msec) * 250 * 6 = 3,000 ms
		movlp	high timer_3sec_set
		call	timer_3sec_set		;３秒間タイマーの設定
		movlp	high $

timsw01		movlp	high display_update
		call	display_update		;RTC DS3231 読み出しと 表示の更新
		movlp	high $

		btfsc	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	timsw02			;Yes

		btfss	PORTC,_swTIM		;TIMER スイッチ = OFF か？
		goto	timsw01			;No

		; タイマーメモリの読み出しと消去

		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止
		clrf	tcon_flg		;タイミング制御フラグをクリア
;		bcf	tmem_flg,6		;0:メモリREAD/1:メモリWRITEフラグ = 0
		call	timer_memory_read     ;;;タイマーメモリの読み出しと消去
		goto	timsw04

		; タイマーメモリ設定に移行準備

timsw02	;	bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止（割り込み処理内でクリア済み）
		clrf	tcon_flg		;タイミング制御フラグをクリア
		bcf	INTCON,INTE		;INTE: 外部(RA2/INT)割り込みを禁止

		bsf	tmem_flg,6		;0:メモリREAD/1:メモリWRITEフラグ = 1
		btfss	mode_flg,0		;bit0: 1:LARGEモード か？
		goto	timsw03			;No. 0:NORMALモード

		bsf	tmem_flg,5		;Yes. mode_flg.bit0 の記憶
		bsf	mode_flg,1		;SET モードフラグ = 1 (仮に設定)
		movlp	high large_display_shift
		call	large_display_shift	;LARGE モード時の１行（ページ）上方にずらし表示
		movlp	high $
		bcf	mode_flg,1		;SET モードフラグ = 0 (仮を解除)
		bcf	mode_flg,0		;0:NORMAL モードに仮設定 (タイマーメモリ設定中)	

		; タイマーメモリ設定の移行メッセージの表示

timsw03		yOLED_FontPos_M	4+6*9,7		;
		movlw	h'c0'			;h'c0': ビット反転表示とビットずらし指示
		movwf	echr_flg		;
		yOLED_DispStr_M timeset_msg,1	;メッセージ文字列の表示
		bcf	echr_flg,7		;ビット反転表示指示解除

		call	ybuzzer_pi		;"ピッ" ブザー音

		btfss	PORTC,_swTIM		;TIMER スイッチ = OFF か？
		goto	$ - 1			;No

		; タイマーメモリの設定

		call	ywait_15ms		;チャッタリング吸収
		movf	bcd_yh,W		;年(上位2桁)_BCD カウンタを退避
		movwf	temp_yh			;退避用 年(上位2桁)_BCD カウンタ
		bcf	time_flg,7		;bit0フラグを退避
		btfsc	time_flg,0		;bit0=1: 12H か？
		bsf	time_flg,7		;Yes

		call	timer_memory_set      ;;;タイマーメモリの設定

		bcf	time_flg,0		;bit0フラグを復帰
		btfsc	time_flg,7		;bit7=1: 12H か？
		bsf	time_flg,0		;Yes
		bcf	time_flg,7		;
		movf	temp_yh,W		;退避用 年(上位2桁)_BCD カウンタ
		movwf	bcd_yh			;年(上位2桁)_BCD カウンタを復帰
		bsf	INTCON,INTE		;INTE: 外部(RA2/INT)割り込みを許可

		; タイマー機能処理の終了

timsw04		btfss	tmem_flg,4		;バックアップ要求フラグ = 1 か？
		goto	timsw05			;No

		call	timer_mem_organize	;タイマー用メモリデータの整理
		call	yflash_mem_erase_write	;フラッシュメモリの消去とデータ書き込み

timsw05		btfss	PORTC,_swCAN		;CANCEL スイッチ = OFF か？
		goto	$ - 1			;No

		btfsc	tmem_flg,5		;mode_flg.bit0 の記憶 = 1 か？
		bsf	mode_flg,0		;Yes. 1:LARGEモード
		clrf	tmem_flg		;タイマーメモリフラグをクリア
		bsf	updt_flg,7		;RTC DS3231 読み出し要求フラグ = 1

timsw06		call	ywait_15ms		;チャッタリング吸収
		return

timeset_msg	dt	" TIMER SET ",0

;--------------------------------------------------------------------------
;		タイマー用メモリデータの整理
;--------------------------------------------------------------------------

timer_mem_organize

		; 有効データをワークメモリにコピー移動

		clrf	valid_cnt		;タイマー用メモリの無効数カウンタの初期設定
		movlw	high timer_memory	;タイマー用メモリの先頭アドレス
		movwf	FSR0H			;
		movlw	low timer_memory	;
		movwf	FSR0L			;

		movlw	high work_memory	;ワークメモリの先頭アドレス
		movwf	FSR1H			;
		movlw	low work_memory		;
		movwf	FSR1L			;

		movlw	timer_capacity		;タイマー用メモリの記憶容量の最大値
		movwf	lpcnt			;ループカウンタ
;
tmorg01		btfsc	INDF0,7			;コントロールバイトの f bit = 1 (有効) か？
		goto	tmorg02			;Yes

		incf	valid_cnt,F		;タイマー用メモリの無効数カウンタ + 1
		addfsr	FSR0,7			;間接アドレス + 7 更新
		goto	tmorg04

tmorg02		movlw	7
		movwf	work1			;ループカウンタ

tmorg03		moviw	FSR0++			;
		movwi	FSR1++			;ワークメモリへコピー	
		decfsz	work1,F			;ループカウンタ - 1 = 0 か？
		goto	tmorg03			;No

tmorg04		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	tmorg01			;No

		; 残りのワークメモリを無効データとして h'00' クリア

		movf	valid_cnt,W		;無効数カウンタ
		movwf	lpcnt			;ループカウンタ
		btfsc	STATUS,Z		;無効数カウンタ valid_cnt = 0 か？
		goto	tmorg07			;Yes

tmorg05		movlw	7
		movwf	work1			;ループカウンタ

tmorg06		clrw
		movwi	FSR1++			;ワークメモリへコピー	
		decfsz	work1,F			;ループカウンタ - 1 = 0 か？
		goto	tmorg06			;No

		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	tmorg05			;No

		; タイマー用メモリに書き戻し

tmorg07		movlw	high work_memory	;ワークメモリの先頭アドレス
		movwf	FSR1H			;
		movlw	low work_memory		;
		movwf	FSR1L			;

		movlw	high timer_memory	;タイマー用メモリの先頭アドレス
		movwf	FSR0H			;
		movlw	low timer_memory	;
		movwf	FSR0L			;

		movlw	7 * timer_capacity
		movwf	lpcnt			;ループカウンタ

tmorg08		moviw	FSR1++			;
		movwi	FSR0++			;ワークメモリへコピー	
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	tmorg08			;No

		return

;==========================================================================
;		タイマーメモリの設定
;==========================================================================

;	[スイッチ操作]
;			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │●│   │●│   │●│   │●│   │●│   │●│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

;			   SET スイッチ ..... ブリンク位置のポインタを + 1
;			  BACK スイッチ ..... ブリンク位置のポインタを - 1

;			    UP スイッチ ..... ブリンク位置の値を + 1
;			  DOWN スイッチ ..... ブリンク位置の値を - 1

; (タイマー種類選択時に)   SET スイッチ ..... タイマー種類選択を終了し、次項目の設定に移行する

;	    (分選択時に) TMSET スイッチ ..... １件分のタイマー設定を終了し、次の設定に備える

;			CANCEL スイッチ ..... タイマー設定を中断し、NORMAL / LARGE モードに戻る

;	tmem_flg: タイマーメモリフラグ
;			      >	bit7: タイマー処理フラグ, 0:終了/1:タイマー処理
;			      >	bit6: 0:メモリREAD/1:メモリWRITE
;			      >	bit5: mode_flg.bit0 の記憶フラグ
;				bit4: バックアップ要求フラグ
;				bit2: 書き込み無効フラグ
;			      >	bit1: タイマー種類選択の中断フラグ
;			      > bit0: タイマー種類フラグ, 0:年タイマー/1:週間タイマー

;	sel_flg: 選択フラグ
;				bit7: 年(上位)フラグ
;				bit6: 年(下位)フラグ
;				bit5: 月フラグ
;				bit4: 日フラグ/曜日フラグ
;				bit3: 24H/12Hフラグ
;				bit2: 時フラグ
;				bit1: 分フラグ

timer_memory_set
		; タイミング制御の初期設定

		clrf	tcon_flg
		movlp	high timer_500ms_set
		call	timer_500ms_set		;タイマー０の基本設定
		movlp	high $

		; タイマーメモリの設定タイトルの表示

tmset01		call	ySSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去
		clrf	echr_flg		;初期設定

;			"= Timer Memory Set ="
;			 01234567890123456789

		yOLED_FontPos_M	4+6*0,0		;
		yOLED_DispStr_M timer_set_msg,1	;メッセージ文字列の表示

		; タイマー用メモリの空きチェック

		call	valid_memory_address	;有効なタイマー用メモリ数のカウント
		movlw	timer_capacity		;タイマー用メモリの記憶容量の最大値
		subwf	valid_cnt,W		;
		btfss	STATUS,C		;有効数カウンタ < 記憶容量の最大値 か？
		goto	tmset02			;Yes

		; タイマー用メモリの空きがないとき

;			  "Memory full !"
;			   "Any switch ?"
;		 	 01234567890123456789

		yOLED_FontPos_M	4+6*2,3		;
		yOLED_DispStr_M mem_full_msg,1	;"Memory full !" 文字列の表示

		call	any_switch		; "Any switch ?" 文字列の表示と応答入力
		goto	tmset13

		; タイマー種類の選択

tmset02		call	timer_type_select      ;;タイマー種類の選択
		btfsc	tmem_flg,1		;タイマー種類選択の中断フラグ = 1 か？
		goto	tmset12			;Yes

		call	ybuzzer_pi		;"ピッ" ブザー音

		clrf	bcd_hh			;時_BCD カウンタ
		clrf	bcd_mm			;分_BCD カウンタ
		clrf	sel_flg			;選択フラグ
		bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfsc	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		goto	tmset05			;No. 1:週間タイマー

	    ; ----- タイマー種類フラグ = 0:年タイマー の処理 -----

		call	ySSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去

		bsf	sel_flg,7		;選択フラグ = 7:年(上位)
		movlw	h'01'
		movwf	bcd_dd			;日_BCD カウンタ

		; 各変更項目別の表示を更新

tmset03		movlp	high yyyymm_display
		call	yyyymm_display		;年月 (yyyy/mm) の表示
		call	week_display		;曜日タイトルの表示
		call	calendar_display	;カレンダー（日と曜日）の表示
		call	time_display		;時分 (hh:mm) の表示	;┐
		call	ampm_display		;24H/12H の表示		;┘順序を変更しないこと!
	;	movlp	high $

		; 各変更項目別の質問メッセージを表示

	;	movlp	high inquiry_display
		call	inquiry_display		;質問メッセージの表示
		movlp	high $

		; 該当項目のブリンク表示

tmset04		movlp	high yyyymm_display_blk
		call	yyyymm_display_blk	;年月 (yyyy/mm) のブリンク表示
		call	calendar_display_blk	;変更する該当日のブリンク表示
		call	ampm_display_blk	;24H/12H のブリンク表示
		call	time_display_blk	;時分 (hh:mm) のブリンク表示
		movlp	high $
		goto	tmset08

	    ; ----- タイマー種類フラグ = 1:週間タイマー の処理 -----

		; スイッチ操作ガイドの表示

;			"SET/BAK UP/DW TIM/CAN"

tmset05		movlp	high tmdisp_area_clear
		call	tmdisp_area_clear	;タイマーメモリ 表示エリアの h'00'クリア
		movlp	high $

		yOLED_FontPos_M	1,7		;表示開始位置指定
		bsf	echr_flg,7		;ビット反転表示指示 = 1
		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		yOLED_DispStr_M s2key_guide_msg,1 ;メッセージ文字列の表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0

		bsf	sel_flg,4		;選択フラグ = 4:曜日
		clrf	tm_week			;曜日カウンタ = 0:Eday 初期設定

		; 各変更項目別の表示を更新

tmset06		call	eday_display		;"Eday" 文字列の表示

		yOLED_FontPos_M	3+6*0,3		;
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		yOLED_DispStr_M	week_title,1	;"Su Mo Tu We Th Fr Sa" 文字列の表示
		bcf	echr_flg,6		;1 bit 左(下)ずらし指示 = 0

		movlp	high ampm_display
		call	time_display		;時分 (hh:mm) の表示	;┐
		call	ampm_display		;24H/12H の表示		;┘順序を変更しないこと!
		movlp	high $

		; 該当項目のブリンク表示

tmset07		call	week_display_blk_rev	;曜日選択のブリンク表示 / 反転表示

		movlp	high ampm_display_blk
		call	ampm_display_blk	;24H/12H のブリンク表示
	;	movlp	high $

	;	movlp	high time_display_blk
		call	time_display_blk	;時分 (hh:mm) のブリンク表示
		movlp	high $

	    ; ----- タイマー種類フラグ = 0:年タイマー, 1:週間タイマー の共通処理 -----

		; タイマーメモリ設定中の各スイッチの入力処理

tmset08		bcf	updt_flg,6		;各項目の表示要求フラグ = 0

		btfss	PORTA,_swSET		;SET スイッチ = ON か？
		call	tmset_set_switch	;Yes

		btfsc	PORTA,_swUP		;UP スイッチ = ON か？
		goto	$ + 4			;No

		movlp	high set_up_switch	;Yes
		call	set_up_switch		;
		movlp	high $			;

		btfsc	PORTA,_swDWN		;DOWN スイッチ = ON か？
		goto	$ + 4			;No

		movlp	high set_down_switch	;Yes
		call	set_down_switch		;
		movlp	high $			;

		btfss	PORTA,_swBAK		;BACK スイッチ = ON か？
		call	tmset_back_switch	;Yes

		btfss	updt_flg,6		;各項目の表示要求フラグ = 1 か？
		goto	tmset09			;No

		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		goto	tmset03			;Yes
		goto	tmset06			;No

tmset09		btfsc	PORTC,_swTIM		;TIMER スイッチ = ON か？
		goto	tmset10			;No

		call	tmset_timer_switch	;タイマー用メモリへの書き込み
		btfss	tmem_flg,2		;書き込み無効フラグ = 1 か？
		goto	tmset01			;No. 再度 次の設定に備えてタイマー用メモリの空きチェックへ

		bcf	tmem_flg,2		;書き込み無効フラグ = 0
		goto	tmset11			;Yes

tmset10		btfss	PORTC,_swCAN		;CANCEL スイッチ = ON か？
		goto	tmset12			;Yes. 中断

tmset11		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		goto	tmset04			;Yes
		goto	tmset07			;No

		; タイマーメモリ設定の中断終了

tmset12		call	ybuzzer_buu		;"ブー" ブザー音, (中断時)
		btfss	PORTC,_swCAN		;CANCEL スイッチ = OFF か？
		goto	$ - 1			;No

tmset13		call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------

timer_set_msg	dt	"= Timer Memory Set =",0
;			 01234567890123456789

s2key_guide_msg	dt	"SET/BAK UP/DW TIM/CAN",0
;			 012345678901234567890

mem_full_msg	dt	"Memory full !",0

;--------------------------------------------------------------------------
;		タイマー種類の選択
;--------------------------------------------------------------------------

;	[スイッチ操作]
;			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │●│   │○│   │○│   │●│   │●│   │●│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

;			    UP スイッチ ..... ブリンク位置のポインタを + 1
;			  DOWN スイッチ ..... ブリンク位置のポインタを - 1

;			   SET スイッチ ..... タイマー種類選択を終了し、次項目の設定に移行する

;			CANCEL スイッチ ..... タイマー種類選択を中断し、NORMAL / LARGE モードに戻る

timer_type_select

		; スイッチ操作ガイドの表示

;			" UP/DOWN SET/CANCEL "

		yOLED_FontPos_M	1,7		;表示開始位置指定
		bsf	echr_flg,7		;ビット反転表示指示 = 1
		movlw	3
		call	multi_rev_shift		;h'00' / h'7f' / h'fe' 複数バイト出力
		yOLED_DispStr_M s1key_guide_msg,1 ;メッセージ文字列の表示
		movlw	3
		call	multi_rev_shift		;h'00' / h'7f' / h'fe' 複数バイト出力
		bcf	echr_flg,7		;ビット反転表示指示 = 0

		; タイマー種類の選択

;			 "Type = Date Weekly"
;			 01234567890123456789

		yOLED_FontPos_M	4+6*1,2		;
		yOLED_DispStr_M timtype_msg,1	;"Type =" 文字列の表示

tmsel01		call	timtype_d_disp		;"Date"   文字列の表示
		call	timtype_w_disp		;"Weekly" 文字列の表示
		bcf	updt_flg,6		;各項目の表示要求フラグ = 0

tmsel02		call	timtype_display_blk    ;;タイマー種類のブリンク表示

		; タイマー種類の選択中の各スイッチの入力処理

		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		call	tmsel_up_switch		;Yes

		btfss	PORTA,_swDWN		;DOWN スイッチ = ON か？
		call	tmsel_down_switch	;Yes

		btfsc	updt_flg,6		;各項目の表示要求フラグ = 1 か？
		goto	tmsel01			;Yes

		btfss	PORTA,_swSET		;SET スイッチ = ON か？
		goto	tmsel03			;Yes

		btfsc	PORTC,_swCAN		;CANCEL スイッチ = ON か？
		goto	tmsel02			;No

		; タイマー種類の選択の中断終了

		call	ywait_15ms		;チャッタリング吸収
		bsf	tmem_flg,1		;タイマー種類選択の中断フラグ = 1
		goto	tmsel04

		; タイマー種類の選択の終了

tmsel03		call	ywait_15ms		;チャッタリング吸収

		btfss	PORTA,_swSET		;SET スイッチ = OFF か？
		goto	$ - 1			;No

tmsel04		btfss	PORTC,_swCAN		;CANCEL スイッチ = OFF か？
		goto	$ - 1			;No

		call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------

;			 01234567890123456789
;			 "Type = Date Weekly"

timtype_msg	dt	"Type =",0
timtype_d_msg	dt	"Date",0		;日付
timtype_w_msg	dt	"Weekly",0		;週間

s1key_guide_msg	dt	" UP/DOWN SET/CANCEL ",0
;			 01234567890123456789

;--------------------------------------------------------------------------

		; "Date" 文字列の表示
timtype_d_disp
		yOLED_FontPos_M	3+6*8,2		;表示開始位置の指定
		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		yOLED_DispStr_M	timtype_d_msg,1	;メッセージ文字列の表示
		return

		; "Weekly" 文字列の表示
timtype_w_disp
		yOLED_FontPos_M	3+6*13,2	;表示開始位置の指定
		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		yOLED_DispStr_M	timtype_w_msg,1	;メッセージ文字列の表示
		return

;--------------------------------------------------------------------------
;		タイマー種類文字列のブリンク表示
;--------------------------------------------------------------------------

timtype_display_blk
;			 "Type = Date Weekly"
;			         ^    ^
;			 01234567890123456789

		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	tmtb01			;No

		call	ybit_rev_flg_set	;ビット反転表示指示フラグの設定

		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		call	timtype_d_disp		;Yes. "Date" 文字列のブリンク表示

		btfsc	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		call	timtype_w_disp		;Yes. "Weekly" 文字列のブリンク表示

		bcf	echr_flg,7		;ビット反転表示指示 = 0
		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0

tmtb01		return

;--------------------------------------------------------------------------
;		UP スイッチの処理 ... タイマー種類選択から CALL
;--------------------------------------------------------------------------

tmsel_up_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swUP		;再度 UP スイッチ = ON か？
		goto	tselusw01		;No

		bsf	updt_flg,6		;各項目の表示要求フラグ = 1
		movlw	h'01'
		xorwf	tmem_flg,F		;選択フラグの更新

		btfss	PORTA,_swUP		;UP スイッチ = OFF か？
		goto	$ - 1			;No

tselusw01	call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		DOWN スイッチの処理 ... タイマー種類選択から CALL
;--------------------------------------------------------------------------

tmsel_down_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swDWN		;再度 DOWN スイッチ = ON か？
		goto	tseldsw01		;No

		bsf	updt_flg,6		;各項目の表示要求フラグ = 1
		movlw	h'01'
		xorwf	tmem_flg,F		;選択フラグの更新

		btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
		goto	$ - 1			;No

tseldsw01	call	ywait_15ms		;チャッタリング吸収
		return

;==========================================================================

;--------------------------------------------------------------------------
;		曜日選択のブリンク表示 / 反転表示
;--------------------------------------------------------------------------

week_display_blk_rev

		btfsc	sel_flg,4		;選択フラグ = bit4:曜日フラグ か？
		goto	weekb01			;Yes

		bsf	echr_flg,7		;ビット反転表示指示 = 1
		goto	weekb02

weekb01		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	weekb07			;No

;			"Eday"
;			 ^
;			"Su Mo Tu We Th Fr Sa"
;                        ^  ^  ^  ^  ^  ^  ^
;			 01234567890123456789

		call	ybit_rev_flg_set	;ビット反転表示指示フラグの設定

weekb02		movf	tm_week,W		;
		btfss	STATUS,Z		;曜日カウンタ = 0 か？
		goto	weekb03			;No

		; "Eday" ブリンク表示 / 反転表示

		call	eday_display		;"Eday" 文字列の表示
		goto	weekb06

		; "Su Mo Tu We Th Fr Sa" ブリンク表示 / 反転表示

weekb03		movlw	3+6*0
		movwf	column			;表示カラム
		movlw	3
		movwf	pagex			;表示ページ

		movlw	high week_title		;文字列の先頭 high アドレス
		movwf	FSR0H			;
		movlw	low week_title		;文字列の先頭 low アドレス
		movwf	FSR0L			;

		decf	tm_week,W		;
		btfsc	STATUS,Z		;曜日カウンタ - 1 = 0 か？
		goto	weekb05			;Yes

		movwf	work1			;ループカウンタ

weekb04		movlw	6*3
		addwf	column,F		;表示カラムの更新
		addfsr	FSR0,3			;間接アドレス FSR0H:FSR0L + 3
		decfsz	work1,F			;ループカウンタ - 1 = 0 か？
		goto	weekb04			;No

weekb05		call	ySSD1306_FontPos	;表示開始位置の指定
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		moviw	FSR0++
		call	ySSD1306_DispChr	;OLED へ１文字出力
		moviw	FSR0++
		call	ySSD1306_DispChr	;OLED へ１文字出力
		bcf	echr_flg,6		;1 bit 左(下)ずらし指示 = 0

weekb06		btfsc	sel_flg,4		;選択フラグ = bit4:曜日フラグ か？
		bcf	tcon_flg,0		;Yes. 0.5秒/0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0

weekb07		return

;--------------------------------------------------------------------------

		; "Eday" 文字列の表示
eday_display
		yOLED_FontPos_M	3+6*0,2		;曜日表示開始位置の指定
		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		yOLED_DispStr_M	week_eday,1	;"Eday" 文字列の表示
		return

week_eday	dt	"Eday",0

;week_title	dt	"Su Mo Tu We Th Fr Sa",0	; (Page 1 内)
;			 01234567890123456789

;--------------------------------------------------------------------------
;	    SET スイッチの処理 ... タイマーメモリの設定から CALL
;--------------------------------------------------------------------------

;選択フラグ   sel_flg:  bit7:年(上位) / 6:年(下位) / 5:月 / 4:日   / 3:24H/12H / 2:時 / 1:分 / ( 0:秒 )
;						            4:曜日 / 3:24H/12H / 2:時 / 1:分
tmset_set_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swSET		;再度 SET スイッチ = ON か？
		goto	tsetsw02		;No

		lsrf	sel_flg,F		;選択フラグの更新, 右にシフト
		btfss	sel_flg,0		;sel_flg = bit0 か？
		goto	tsetsw01		;No

		clrf	sel_flg
		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		bsf	sel_flg,7		;Yes. 7:年(上位) に設定
		btfsc	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		bsf	sel_flg,4		;Yes. 4:曜日 に設定

tsetsw01	bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfss	PORTA,_swSET		;SET スイッチ = OFF か？
		goto	$ - 1			;No

tsetsw02	call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;	    BACK スイッチの処理 ... タイマーメモリの設定から CALL
;--------------------------------------------------------------------------

;選択フラグ   sel_flg:  bit7:年(上位) / 6:年(下位) / 5:月 / 4:日   / 3:24H/12H / 2:時 / 1:分 / ( 0:秒 )
;						            4:曜日 / 3:24H/12H / 2:時 / 1:分
tmset_back_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swBAK		;再度 BACK スイッチ = ON か？
		goto	tbaksw03		;No

		lslf	sel_flg,F		;選択フラグの更新, 左にシフト
		btfsc	STATUS,Z		;選択フラグ = h'00' か？
		goto	tbaksw01		;Yes

		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		goto	tbaksw02		;Yes

		btfss	sel_flg,5		;sel_flg = bit5 か？
		goto	tbaksw02		;No

		clrf	sel_flg			;タイマー種類フラグ = 1:週間タイマー のとき

tbaksw01	bsf	sel_flg,1		;bit1:分 に設定

tbaksw02	bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfss	PORTA,_swBAK		;BACK スイッチ = OFF か？
		goto	$ - 1			;No

tbaksw03	call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;	    TMSET スイッチの処理 ... タイマーメモリの設定から CALL
;--------------------------------------------------------------------------

;選択フラグ   sel_flg:  bit7:年(上位) / 6:年(下位) / 5:月 / 4:日   / 3:24H/12H / 2:時 / 1:分 / ( 0:秒 )
;						            4:曜日 / 3:24H/12H / 2:時 / 1:分
tmset_timer_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTC,_swTIM		;再度 TIMER/TMSET スイッチ = ON か？
		goto	ttimsw03		;No

		btfss	sel_flg,1		;選択フラグ = bit1:分フラグ か？
		goto	ttimsw01		;No

		call	duplicate_check		;重複データチェック
		btfsc	STATUS,C		;タイマーメモリ書き込み(重複)エラー か？
		goto	ttimsw01		;Yes

		call	write_timer_memory	;タイマー用メモリへの書き込み
		bsf	tmem_flg,4		;バックアップ要求フラグ = 1
		call	ybuzzer_popo		;"ポッポッ" ブザー音出力
		goto	ttimsw02

ttimsw01	bsf	tmem_flg,2		;書き込み無効フラグ = 1
		call	ybuzzer_bu		;"ブッ" ブザー音出力

ttimsw02	btfss	PORTC,_swTIM		;TIMER/TMSET スイッチ = OFF か？
		goto	$ -1			;No

ttimsw03	call	ywait_15ms		;チャッタリング吸収
		return

;==========================================================================

;--------------------------------------------------------------------------
;	     タイマー用メモリへ書き込み前の重複データチェック
;--------------------------------------------------------------------------

duplicate_check

		clrf	cont_byte		;コントロールバイトの初期設定
		btfsc	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		bsf	cont_byte,0		;Yes
		lslf	time_flg,W		;時間表示モードフラグ
		iorwf	cont_byte,F		;
		bsf	cont_byte,7		;メモリ有効フラグ = 1

		movlw	high timer_memory	;タイマー用メモリの先頭アドレス
		movwf	FSR1H			;
		movlw	low timer_memory	;
		movwf	FSR1L			;

		movlw	timer_capacity
		movwf	lpcnt			;ループカウンタ

dupck01		moviw	0[FSR1]			;1 バイト目
		subwf	cont_byte,W		;コントロールバイト
		btfss	STATUS,Z		;cont_byte = 0[FSR1] か？
		goto	dupck04			;No

		btfss	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		goto	dupck02			;No. 0:年タイマー

		moviw	4[FSR1]			;5 バイト目
		subwf	tm_week,W		;曜日カウンタ
		goto	dupck03			;Yes

dupck02		moviw	1[FSR1]			;2 バイト目
		subwf	bcd_yh,W		;年(上位2桁)_BCD カウンタ
		btfss	STATUS,Z		;bcd_yh = 1[FSR1] か？
		goto	dupck04			;No

		moviw	2[FSR1]			;3 バイト目
		subwf	bcd_yl,W		;年(下位2桁)_BCD カウンタ
		btfss	STATUS,Z		;bcd_yl = 2[FSR1] か？
		goto	dupck04			;No

		moviw	3[FSR1]			;4 バイト目
		subwf	bcd_nn,W		;月_BCD カウンタ
		btfss	STATUS,Z		;bcd_nn = 3[FSR1] か？
		goto	dupck04			;No

		moviw	4[FSR1]			;5 バイト目
		subwf	bcd_dd,W		;日_BCD カウンタ

dupck03		btfss	STATUS,Z		;bcd_dd or tm_week = 4[FSR1] か？
		goto	dupck04			;No

		moviw	5[FSR1]			;6 バイト目
		subwf	bcd_hh,W		;時_BCD カウンタ
		btfss	STATUS,Z		;bcd_hh = 5[FSR1] か？
		goto	dupck04			;No

		moviw	6[FSR1]			;7 バイト目
		subwf	bcd_mm,W		;分_BCD カウンタ
		btfss	STATUS,Z		;bcd_mm = 6[FSR1] か？
		goto	dupck04			;No

		bsf	STATUS,C		;C フラグ = 1、重複エラー表示
		goto	dupck05

dupck04		addfsr	FSR1,7			;間接アドレス + 7 更新
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	dupck01			;No

		bcf	STATUS,C		;C フラグ = 0、重複エラーなし表示

dupck05		return

;--------------------------------------------------------------------------
;		タイマー用メモリへの書き込み
;--------------------------------------------------------------------------

write_timer_memory

		movlw	high timer_memory	;タイマー用メモリの先頭アドレス
		movwf	FSR1H			;
		movlw	low timer_memory	;
		movwf	FSR1L			;

		movlw	timer_capacity
		movwf	lpcnt			;ループカウンタ

wrtmm01		btfss	INDF1,7			;cont_byte の f bit = 1 (有効) か？
		goto	wrtmm02			;No. 空き

		addfsr	FSR1,7			;間接アドレス + 7 更新
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	wrtmm01			;No

		bsf	STATUS,C		;C フラグ = 1、メモリオーバーエラー表示
		goto	wrtmm03			;空きなし

		; タイマー用メモリへ書き込み

wrtmm02		clrf	INDF1			;コントロールバイトの初期設定

		btfsc	tmem_flg,0		;タイマー種類フラグ = 1:週間タイマー か？
		bsf	INDF1,0			;Yes

		lslf	time_flg,W		;時間表示モードフラグ
		iorwf	INDF1,F			;
		bsf	INDF1,7			;メモリ有効フラグ = 1

		addfsr	FSR1,1			;間接アドレス + 1 更新

		clrw				;h'00'
		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		movf	bcd_yh,W		;Yes. 年(上位2桁)_BCD カウンタ
		movwi	FSR1++			;

	;	clrw				;h'00'
		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		movf	bcd_yl,W		;Yes. 年(下位2桁)_BCD カウンタ
		movwi	FSR1++			;

	;	clrw				;h'00'
		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		movf	bcd_nn,W		;Yes. 月_BCD カウンタ
		movwi	FSR1++			;

		movf	tm_week,W		;曜日カウンタ
		btfss	tmem_flg,0		;タイマー種類フラグ = 0:年タイマー か？
		movf	bcd_dd,W		;Yes. 日_BCD カウンタ
		movwi	FSR1++			;

		movf	bcd_hh,W		;時_BCD カウンタ
		movwi	FSR1++			;
		movf	bcd_mm,W		;分_BCD カウンタ
		movwi	FSR1++			;

		bcf	STATUS,C		;C フラグ = 0、書き込み済み

wrtmm03		return

;==========================================================================
;		タイマーメモリの読み出しと消去
;==========================================================================

;	[スイッチ操作]
;			 SIGNAL    TIMER    ZERO     DOWN      UP      MODE
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │○│   │●│   │●│   │●│   │●│   │○│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/CANCEL   /TMSET   /BACK   /MAINTE   /TMODE    /SET

;		    UP スイッチ ..... ブリンクする表示番号を - 1
;		  DOWN スイッチ ..... ブリンクする表示番号を + 1

;		  ZERO スイッチ ..... ブリンクする表示番号の登録データを消去する

;		 TIMER スイッチ ..... タイマーメモリの読み出しを終了し、NORMAL / LARGE モードに戻る

;	tmem_flg: タイマーメモリフラグ
;			      >	bit7: タイマー処理フラグ, 0:終了/1:タイマー処理
;			      >	bit6: 0:メモリREAD/1:メモリWRITE
;			      >	bit5: mode_flg.bit0 の記憶フラグ
;			      >	bit4: バックアップ要求フラグ
;				bit2: 書き込み無効フラグ
;				bit1: タイマー種類選択の中断フラグ
;				bit0: タイマー種類フラグ, 0:年タイマー/1:週間タイマー

timer_memory_read
		; タイミング制御の初期設定

		clrf	tcon_flg
		movlp	high timer_500ms_set
		call	timer_500ms_set		;タイマー０の基本設定
		movlp	high $

		; タイマーメモリの読み出しタイトルの表示

		call	ySSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去
		clrf	echr_flg		;初期設定

;			"= Timer Memory Read ="
;			 012345678901234567890
		yOLED_FontPos_M	1+6*0,0		;
		yOLED_DispStr_M timer_read_msg,1 ;メッセージ文字列の表示

		clrf	dsp_cnt			;
		incf	dsp_cnt,F		;表示カウンタ = 1 初期設定

tmrd01		call	ytmdisp_area_clear	;タイマーメモリ表示エリア (page2～5) の h'00'クリア

		call	valid_memory_address   ;;有効なタイマー用メモリ数のカウントとアドレスの記憶
		movf	valid_cnt,W		;
		btfss	STATUS,Z		;タイマー用メモリの有効数カウンタ = 0 か？
		goto	tmrd02			;No

		; 登録なしのとき		;----------------------------------------

;			 "No registration !"
;			      "Any switch ?"
;		 	 01234567890123456789

		movlp	high wait_1s
		call	wait_1s			;1 秒 ウェイトルーチン
		movlp	high $

		yOLED_FontPos_M	0,7		;スイッチ操作ガイドエリアをクリア
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		movlw	128
		call	multi_rev_shift		;h'00' / h'7f' / h'fe' 複数バイト出力

		yOLED_FontPos_M	1+6*1,3		;
		yOLED_DispStr_M no_regist_msg,1	;"No registration !" 文字列の表示

		call	any_switch		;"Any switch ?" 文字列の表示と応答入力
		goto	tmrd08			;Yes

		; スイッチ操作ガイドの表示	;----------------------------------------

;			"↓:DOWN ↑:UP del:ZERO"

tmrd02		yOLED_FontPos_M	1,7		;表示開始位置指定
		bsf	echr_flg,7		;ビット反転表示指示 = 1
		movlw	3
		call	multi_rev_shift		;h'00' / h'7f' / h'fe' 複数バイト出力
		yOLED_DispStr_M rkey_guide_msg,1 ;メッセージ文字列の表示
		movlw	3
		call	multi_rev_shift		;h'00' / h'7f' / h'fe' 複数バイト出力
		bcf	echr_flg,7		;ビット反転表示指示 = 0

		; タイマー用メモリの表示

tmrd03		call	ytmdisp_area_clear	;タイマーメモリ表示エリア (page2～5) の h'00'クリア

;			"xx xxxx/xx/xx x xx:xx"
;			"xx       xxxx x xx:xx"
;			 012345678901234567890

		movf	dsp_cnt,W		;
		movwf	work2			;dsp_cnt を退避

		call	top_dsp_cnt_no		;先頭の表示番号（カウンタ）の指定
		movlw	4
		movwf	lpcnt			;ループカウンタ

tmrd04		call	dsp_cnt_to_pagex	;表示番号 dsp_cnt から pagex に変換
		call	target_address		;対象アドレスを設定
		call	timer_memory_display   ;;タイマー用メモリの読み出しと表示

		movf	dsp_cnt,W
		subwf	valid_cnt,W
		btfsc	STATUS,Z		;dsp_cnt = valid_cnt か？
		goto	tmrd05			;Yes

		incf	dsp_cnt,F		;表示カウンタ + 1
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	tmrd04			;No

tmrd05		movf	work2,W			;
		movwf	dsp_cnt			;dsp_cnt を復帰

		; 表示番号のブリンク表示

tmrd06		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	tmrd07			;No

		call	ybit_rev_flg_set	;ビット反転表示指示フラグの設定
		call	dsp_cnt_to_pagex	;dsp_cnt から pagex に変換
		call	line_no_display		;表示番号の表示

		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0

		; タイマーメモリ設定中の各スイッチの入力処理

tmrd07		bcf	updt_flg,6		;各項目の表示要求フラグ = 0

		btfss	PORTA,_swDWN		;DOWN スイッチ = ON か？
		call	tmrd_down_switch	;Yes

		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		call	tmrd_up_switch		;Yes

		btfsc	updt_flg,6		;各項目の表示要求フラグ = 1 か？
		goto	tmrd03			;Yes

		btfss	PORTA,_swZER		;ZERO スイッチ = ON か？
		call	tmrd_zero_switch	;Yes

		btfsc	updt_flg,6		;各項目の表示要求フラグ = 1 か？
		goto	tmrd01			;Yes

		btfsc	PORTC,_swTIM		;TIMERL スイッチ = ON か？
		goto	tmrd06			;No

		; タイマーメモリの読み出しと消去処理の終了

		call	ywait_15ms		;チャッタリング吸収
		btfss	PORTC,_swTIM		;TIMERL スイッチ = OFF か？
		goto	$ - 1			;No

		call	ySSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去

tmrd08		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込みを禁止

		call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------

timer_read_msg	dt	"= Timer Memory Read =",0

no_regist_msg	dt	 "No registration !",0
any_sw_msg	dt	      "Any switch ?",0
;		 	 012345678901234567890

rkey_guide_msg	dt	h'8e',":DOWN ",h'8f',":UP del:ZERO",0
;			 ↓             ↑

;--------------------------------------------------------------------------

		; "Any switch ?" メッセージ文字列の表示と応答入力

any_switch
		movlp	high buzzer_bubuu
		call	buzzer_bubuu		;"ブッブー" ブザー音
		call	wait_1s			;1 秒 ウェイトルーチン
		movlp	high $

		movlw	1+6*6			;
		btfsc	tmem_flg,6		;0:メモリREAD/1:メモリWRITE
		movlw	4+6*3			;
		movwf	column			;表示カラム
		movlw	5			;
		movwf	pagex			;表示ページ
		call	ySSD1306_FontPos	;表示開始位置指定
		yOLED_DispStr_M any_sw_msg,1	;"Any switch ? " メッセージ文字列の表示

		movlw	1+6*19
		btfsc	tmem_flg,6		;0:メモリREAD/1:メモリWRITE
		movlw	4+6*16
		movwf	column			;表示カラム

anysw01		btfss	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 1 か？
		goto	anysw02			;No

		call	ySSD1306_FontPos	;表示開始位置指定
		call	ybit_rev_flg_set	;ビット反転表示指示フラグの設定
		movlw	a' '
		call	ySSD1306_DispChr	;OLED へデータを１文字出力
		bcf	tcon_flg,0		;0.5秒/0.25秒経過表示フラグ = 0

		; 各スイッチの入力処理
anysw02		movlp	high any_sw_on_check
		call	any_sw_on_check		;どれかのスイッチ = ON をチェック
		movlp	high $
		btfsc	STATUS,Z		;どれかのスイッチ = ON か？
		goto	anysw01			;No

		call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------

		; 先頭の表示番号（カウンタ）の指定

top_dsp_cnt_no
		movlw	9
		subwf	dsp_cnt,W		;
		movlw	9
		btfsc	STATUS,C		;dsp_cnt >= 9 か？
		goto	topno01			;Yes

		movlw	5
		subwf	dsp_cnt,W		;
		movlw	5
		btfsc	STATUS,C		;dsp_cnt >= 5 か？
		goto	topno01			;Yes

		movlw	1

topno01		movwf	dsp_cnt			;先頭の表示番号
		return

;--------------------------------------------------------------------------

		; 表示番号 dsp_cnt から pagex に変換

dsp_cnt_to_pagex
		movlw	9
		subwf	dsp_cnt,W		;
		btfss	STATUS,C		;dsp_cnt >= 9 か？
		goto	dtp01			;No

		movlw	7
		subwf	dsp_cnt,W		;dsp_cnt - 7
		movwf	pagex			;表示ページ
		goto	dtp03

dtp01		movlw	5
		subwf	dsp_cnt,W		;
		btfss	STATUS,C		;dsp_cnt >= 5 か？
		goto	dtp02			;No

		movlw	3
		subwf	dsp_cnt,W		;dsp_cnt - 3
		movwf	pagex			;表示ページ
		goto	dtp03

dtp02		incf	dsp_cnt,W		;dsp_cnt + 1
		movwf	pagex			;表示ページ

dtp03		return

; <参考>	dsp_cnt		pagex

;		   1	   +1	  2
;		   2	   +1	  3
;		   3	   +1	  4
;		   4	   +1	  5

;		   5	   -3	  2
;		   6	   -3	  3
;		   7	   -3	  4
;		   8	   -3	  5

;		   9	   -7	  2
;		  10	   -7	  3

;--------------------------------------------------------------------------

		; 対象アドレスを設定

target_address
		decf	dsp_cnt,W
		movwf	FSR1L			;
		addwf	FSR1L,F			;x2
		clrf	FSR1H			;
		movlw	low timer_mem_addr	;有効データアドレスの記憶アドレス
		addwf	FSR1L,F			;
		movlw	high timer_mem_addr	;
		addwfc	FSR1H,F			;

		moviw	FSR1++			;FSR0H:FSR0L 有効データアドレスの設定
		movwf	FSR0H			;
		moviw	FSR1++			;
		movwf	FSR0L			;
		return

;--------------------------------------------------------------------------
;	  DOWN スイッチの処理 ... タイマーメモリの読み出しから CALL
;--------------------------------------------------------------------------

tmrd_down_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swDWN		;再度 DOWN スイッチ = ON か？
		goto	trddsw01		;No

		incf	dsp_cnt,F		;表示カウンタ + 1
		incf	valid_cnt,W
		subwf	dsp_cnt,W		;
		movlw	1
		btfsc	STATUS,Z		;表示カウンタ = 有効数カウンタ + 1 か？
		movwf	dsp_cnt			;Yes. 表示カウンタ = 1

		bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
		goto	$ - 1			;No

trddsw01	call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;	  UP スイッチの処理 ... タイマーメモリの読み出しから CALL
;--------------------------------------------------------------------------

tmrd_up_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swUP		;再度 UP スイッチ = ON か？
		goto	trdusw01		;No

		movf	valid_cnt,W
		decf	dsp_cnt,F		;表示カウンタ - 1
		btfsc	STATUS,Z		;表示カウンタ = 0 か？
		movwf	dsp_cnt			;Yes. 表示カウンタ = 有効数カウンタ

		bsf	updt_flg,6		;各項目の表示要求フラグ = 1

		btfss	PORTA,_swUP		;UP スイッチ = OFF か？
		goto	$ - 1			;No

trdusw01	call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;	  ZERO スイッチの処理 ... タイマーメモリの読み出しから CALL
;--------------------------------------------------------------------------

tmrd_zero_switch
		call	ywait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swZER		;再度 ZERO スイッチ = ON か？
		goto	trdzsw02		;No

		call	target_address		;対象アドレスを設定
		clrw
		movwf	INDF0			;データ内容を消去

		movf	dsp_cnt,W
		subwf	valid_cnt,W
		btfsc	STATUS,Z		;dsp_cnt = valid_cnt か？
		decf	dsp_cnt,F		;Yes. dsp_cnt - 1

		bsf	updt_flg,6		;各項目の表示要求フラグ = 1
		bsf	tmem_flg,4		;バックアップ要求フラグ = 1

		call	ybuzzer_pipi		;"ピピッ" ブザー音

		btfss	PORTA,_swZER		;ZERO スイッチ = OFF か？
		goto	$ - 1			;No

trdzsw02	call	ywait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		タイマー用メモリの読み出しと表示
;--------------------------------------------------------------------------

timer_memory_display

		moviw	FSR0++			;コントロールバイト
		movwf	cont_byte		;ワーク

;			"xx xxxx/xx/xx x xx:xx"
;			"xx       xxxx x xx:xx"
;			 012345678901234567890
;			 a  b     c    d e

		; 表示番号の表示		;(a)
		call	line_no_display		;表示番号の表示

		btfss	cont_byte,0		;タイマー種類フラグ = 1:週間タイマー か？
		goto	tmdsp01			;No. 0:年タイマー

		; 曜日の表示			;(c)
		call	yweek_display		;曜日の表示
		goto	tmdsp02

tmdsp01		movlw	1+6*3			;(b)
		movwf	column			;表示開始カラム
		call	ySSD1306_FontPos	;表示開始位置指定

		; 年 (上位2桁 yy) の表示
		call	number2_disp		;BCD から数字へ変換後 OLED へ２文字出力

		; 年 (下位2桁 yy/) の表示
		call	number2_disp		;BCD から数字へ変換後 OLED へ２文字出力

		movlw	a'/'
		call	ySSD1306_DispChr	;OLED へデータを１文字出力

		; 月 (mm) の表示
		call	number2_disp		;BCD から数字へ変換後 OLED へ２文字出力

		movlw	a'/'
		call	ySSD1306_DispChr	;OLED へデータを１文字出力

		; 日 (dd) の表示
		call	number2_disp		;BCD から数字へ変換後 OLED へ２文字出力

		movlw	a' '
		call	ySSD1306_DispChr	;OLED へデータを１文字出力

		; (  /am/pm) の表示
tmdsp02		movlw	1+6*14			;(d)
		movwf	column			;表示開始カラム
		call	ySSD1306_FontPos	;表示開始位置指定

		movlw	a'a'
		btfsc	cont_byte,2		;bit2=0: am か？
		movlw	a'p'			;No
		btfss	cont_byte,1		;bit1=1: 12H か？
		movlw	a' '			;No
		call	ySSD1306_DispChr	;OLED へデータを１文字出力

		movlw	a'm'
		btfss	cont_byte,1		;bit1=1: 12H か？
		movlw	a' '			;No
		call	ySSD1306_DispChr	;OLED へデータを１文字出力

		; 時 (hh) の表示		;(e)
		btfsc	cont_byte,1		;bit1=1: 12H か？
		goto	tmdsp03			;Yes

		call	number2_disp		;BCD から数字へ変換後 OLED へ２文字出力
		goto	tmdsp06

tmdsp03		call	cnv__24to12		;24時間表示を12時間表示に変換-2

		swapf	temp_hh,W		;時_BCD カウンタ 上位4ビット
		andlw	h'0f'
		btfss	STATUS,Z		;上位4ビット = 0 か？
		goto	tmdsp04			;No

		movlw	a' '			;ゼロサプレス
		call	ySSD1306_DispChr	;OLED へデータを１文字出力
		goto	tmdsp05

tmdsp04		call	ynumber_disp		;BCD から数字へ変換後 OLED へ１文字出力

tmdsp05		movf	temp_hh,W		;X_BCD カウンタ 下位4ビット
		call	ynumber_disp		;BCD から数字へ変換後 OLED へ１文字出力

tmdsp06		movlw	a':'
		call	ySSD1306_DispChr	;OLED へデータを１文字出力

		; 分 (mm) の表示
		call	number2_disp		;BCD から数字へ変換後 OLED へ２文字出力
		return

;--------------------------------------------------------------------------

		; h'00' / h'7f' / h'fe' 複数バイト出力

multi_rev_shift
		movwf	lpcnt			;ループカウンタ

mulrs01		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' 1 バイト出力
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	mulrs01			;No

		return

;--------------------------------------------------------------------------

		; X_BCD カウンタ 上位,下位4ビットを数字へ変換後 OLED へ２文字出力

number2_disp
		swapf	INDF0,W			;X_BCD カウンタ 上位4ビット
		call	ynumber_disp		;BCD から数字へ変換後 OLED へ１文字出力

		moviw	INDF0++			;X_BCD カウンタ 下位4ビット
		call	ynumber_disp		;BCD から数字へ変換後 OLED へ１文字出力
		return

;--------------------------------------------------------------------------

		; BCD から数字へ変換後 OLED へ１文字出力

ynumber_disp
		andlw	h'0f'
		iorlw	h'30'
		call	ySSD1306_DispChr	;OLED へデータを１文字出力
		return

;--------------------------------------------------------------------------

		; 表示番号の表示

line_no_display
		movlw	0			;(a)
		movwf	column			;表示開始カラム
		call	ySSD1306_FontPos	;表示開始位置指定
		call	yrev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力

		movf	dsp_cnt,W		;
		movwf	work1			;dsp_cnt を退避

		movlw	10
		subwf	dsp_cnt,W
		btfss	STATUS,C		;dsp_cnt < 10 か？
		goto	lineno01		;Yes

		movwf	dsp_cnt			;BCD に変換
		bsf	dsp_cnt,4		;dsp_cnt + h'10'

lineno01	swapf	dsp_cnt,W		;表示カウンタ 上位4ビット
		call	ynumber_disp
		movf	dsp_cnt,W		;表示カウンタ 下位4ビット
		call	ynumber_disp

		movf	work1,W			;
		movwf	dsp_cnt			;dsp_cnt を復帰
		return

;--------------------------------------------------------------------------

		; 曜日名の表示

;			"xx       xxxx x xx:xx"
;			          ^^
;			 012345678901234567890

yweek_display
		addfsr	FSR0,3			;

		movf	FSR0H,W			;退避
		movwf	addr_high		;
		movf	FSR0L,W			;
		movwf	addr_low		;

		movf	INDF0,W			;曜日カウンタ(0～7)
		btfss	STATUS,Z		;曜日カウンタ = 0 か？
		goto	wdsp01			;No

		movlw	low week_eday		;曜日名 "Eday" の先頭アドレス
		movwf	FSR0L			;
		movlw	high week_eday		;
		movwf	FSR0H			;

		movlw	1+6*9			;
		movwf	column			;表示開始カラム
		call	ySSD1306_FontPos	;表示開始位置指定

		moviw	INDF0++
		call	ySSD1306_DispChr	;OLED へデータを１文字出力
		goto	wdsp02

wdsp01		movwf	FSR0L
		decf	FSR0L,W			;曜日カウンタ - 1
		movwf	FSR0L
		addwf	FSR0L,F
		addwf	FSR0L,F			;x3

		clrf	FSR0H			;
		movlw	low yweek_name		;
		addwf	FSR0L,F			;
		movlw	high yweek_name		;
		addwfc	FSR0H,F			;曜日名の先頭アドレス

		movlw	1+6*10			;
		movwf	column			;表示開始カラム
		call	ySSD1306_FontPos	;表示開始位置指定

wdsp02		moviw	INDF0++
		call	ySSD1306_DispChr	;OLED へデータを１文字出力
		moviw	INDF0++
		call	ySSD1306_DispChr	;OLED へデータを１文字出力
		moviw	INDF0++
		call	ySSD1306_DispChr	;OLED へデータを１文字出力

		movf	addr_high,W		;復帰
		movwf	FSR0H			;
		movf	addr_low,W		;
		movwf	FSR0L			;
		addfsr	FSR0,1			;
		return

;--------------------------------------------------------------------------

;week_eday	dt	"Eday",0

yweek_name	dt	"SunMonTueWedThuFriSat"
;			 012345678901234567890

;--------------------------------------------------------------------------
;		24時間表示を12時間表示に変換-2
;--------------------------------------------------------------------------

cnv__24to12
		; (am)
	;;	bcf	time_flg,1		;bit1=0: am に設定

		moviw	INDF0++		;;	;時_BCD カウンタ
		movwf	temp_hh		;;	;仮の 時_BCD カウンタ

		movf	temp_hh,W
		btfss	STATUS,Z		;仮の 時_BCD カウンタ = h'00' か？
		goto	cnv_01			;No

		movlw	h'12'
		movwf	temp_hh			;仮の 時_BCD カウンタ temp_hh = h'12'
		goto	cnv_02

cnv_01		movlw	h'12'
		subwf	temp_hh,W
		btfss	STATUS,C		;仮の時_BCD カウンタ < h'12' か？
		goto	cnv_02			;Yes. (am)

		; (pm)
	;;	bsf	time_flg,1		;bit1=1: pm に設定

		btfsc	STATUS,Z		;仮の時_BCD カウンタ = h'12' か？
		goto	cnv_02			;Yes. (pm)

		movwf	temp_hh			;仮の時_BCD カウンタ temp_hh = temp_hh - 12
		movlw	h'0e'
		subwf	temp_hh,W
		btfss	STATUS,C		;仮の時_BCD カウンタ >= h'0e' か？
		goto	cnv_02			;No

		movlw	h'10'
		subwf	temp_hh,W
		btfsc	STATUS,C		;仮の時_BCD カウンタ < h'10' か？
		goto	cnv_02			;No

		movlw	h'06'
		subwf	temp_hh,F		;補正

cnv_02		return

;--------------------------------------------------------------------------
;	    有効なタイマー用メモリ数のカウントとアドレスの記憶
;--------------------------------------------------------------------------

valid_memory_address

		clrf	valid_cnt		;タイマー用メモリの有効数カウンタの初期設定
		movlw	high timer_memory	;タイマー用メモリの先頭アドレス
		movwf	FSR0H			;
		movlw	low timer_memory	;
		movwf	FSR0L			;

		movlw	high timer_mem_addr	;有効データアドレスの先頭アドレス
		movwf	FSR1H			;
		movlw	low timer_mem_addr	;
		movwf	FSR1L			;

		movlw	timer_capacity		;タイマー用メモリの記憶容量の最大値
		movwf	lpcnt			;ループカウンタ

valma01		btfss	INDF0,7			;コントロールバイトの f bit = 1 (有効) か？
		goto	valma02			;No

		incf	valid_cnt,F		;タイマー用メモリの有効数カウンタ + 1

		movf	FSR0H,W			;有効データアドレスの記憶
		movwi	FSR1++			;	
		movf	FSR0L,W			;
		movwi	FSR1++			;	

valma02		addfsr	FSR0,7			;間接アドレス + 7 更新
		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	valma01			;No

		return

;#define test_data
#ifdef test_data

;--------------------------------------------------------------------------
;		テストデータの作成
;--------------------------------------------------------------------------

test_memory_xx
		movlw	high timer_memory	;タイマー用メモリの先頭アドレス
		movwf	FSR0H			;
		movlw	low timer_memory	;
		movwf	FSR0L			;

		movlw	high test_memory	;ROMタイマー用メモリの先頭アドレス
		movwf	FSR1H			;
		movlw	low test_memory		;
		movwf	FSR1L			;

		movlw	test_memory_end - test_memory
		movwf	lpcnt			;ループカウンタ

test01		moviw	FSR1++			;
		movwi	FSR0++			;

		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	test01			;No
;
		movlw	7 * timer_capacity
		movwf	lpcnt
		movlw	test_memory_end - test_memory
		subwf	lpcnt,F			;ループカウンタ
		btfss	STATUS,C		;lpcnt < 70 か？
		goto	test03			;No
		btfsc	STATUS,Z		;lpcnt = 70 か？
		goto	test03			;Yes

test02		clrw				;
		movwi	FSR0++			;

		decfsz	lpcnt,F			;ループカウンタ - 1 = 0 か？
		goto	test02			;No

test03		return

;			+0    +1    +2    +3    +4    +5    +6
test_memory	dt	h'80',h'20',h'25',h'03',h'13',h'09',h'01'
		dt	h'80',h'20',h'25',h'04',h'01',h'10',h'02'
		dt	h'83',h'00',h'00',h'00',h'00',h'09',h'03'
		dt	h'87',h'00',h'00',h'00',h'03',h'09',h'04'
		dt	h'80',h'20',h'25',h'04',h'03',h'11',h'05'
		dt	h'80',h'20',h'25',h'04',h'03',h'11',h'06'
		dt	h'80',h'20',h'25',h'04',h'01',h'10',h'07'
		dt	h'83',h'00',h'00',h'00',h'00',h'09',h'08'
		dt	h'87',h'00',h'00',h'00',h'03',h'11',h'09'
		dt	h'80',h'20',h'25',h'04',h'03',h'11',h'10'
test_memory_end

#endif

;==========================================================================
;		タイマー用メモリの監視（一致検査）
;==========================================================================

timer_memory_monitor

		movlw	high timer_memory	;タイマー用メモリの先頭アドレス
		movwf	FSR1H			;
		movlw	low timer_memory	;
		movwf	FSR1L			;

		movlw	timer_capacity		;タイマー用メモリの記憶容量の最大値
		movwf	lpcnt			;ループカウンタ1

tmmon01		btfss	INDF1,7			;タイマー用メモリの f bit = 1 (有効) か？
		goto	tmmon08			;No

		btfsc	INDF1,0			;タイマー種類 = 1:週間タイマー か？
		goto	tmmon03			;Yes

		; 2 バイト目 ～ 5 バイト目の一致チェック

tmmon02		moviw	1[FSR1]			;2 バイト目
		subwf	bcd_yh,W		;年(上位2桁)_BCD カウンタ
		btfsc	STATUS,Z		;bcd_yh = 1[FSR1] か？
		goto	$ + 4			;Yes
		btfss	STATUS,C		;bcd_yh > 1[FSR1] か？
		goto	tmmon08			;No
		goto	tmmon05			;Yes

		moviw	2[FSR1]			;3 バイト目
		subwf	bcd_yl,W		;年(下位2桁)_BCD カウンタ
		btfsc	STATUS,Z		;bcd_yl = 2[FSR1] か？
		goto	$ + 4			;Yes
		btfss	STATUS,C		;bcd_yl > 2[FSR1] か？
		goto	tmmon08			;No
		goto	tmmon05			;Yes

		moviw	3[FSR1]			;4 バイト目
		subwf	bcd_nn,W		;月_BCD カウンタ
		btfsc	STATUS,Z		;bcd_nn = 3[FSR1] か？
		goto	$ + 4			;Yes
		btfss	STATUS,C		;bcd_nn > 3[FSR1] か？
		goto	tmmon08			;No
		goto	tmmon05			;Yes

		moviw	4[FSR1]			;5 バイト目
		subwf	bcd_dd,W		;日_BCD カウンタ
		btfsc	STATUS,Z		;bcd_dd = 4[FSR1] か？
		goto	tmmon04			;Yes
		btfss	STATUS,C		;bcd_dd > 4[FSR1] か？
		goto	tmmon08			;No
		goto	tmmon05			;Yes

tmmon03		moviw	4[FSR1]			;5 バイト目
		btfsc	STATUS,Z		;4[FSR1] = h'00':"Eday" か？
		goto	tmmon04			;Yes

		subwf	bcd_ww,W		;曜日_BCD カウンタ
		btfss	STATUS,Z		;bcd_ww = 4[FSR1] か？
		goto	tmmon08			;No

		; 6 バイト目、7 バイト目の一致チェック

tmmon04		moviw	5[FSR1]			;6 バイト目
		subwf	bcd_hh,W		;時_BCD カウンタ
		btfsc	STATUS,Z		;bcd_hh = 5[FSR1] か？
		goto	$ + 4			;Yes
		btfss	STATUS,C		;bcd_hh > 5[FSR1] か？
		goto	tmmon08			;No
		goto	tmmon05			;Yes

		moviw	6[FSR1]			;7 バイト目
		subwf	bcd_mm,W		;分_BCD カウンタ
		btfsc	STATUS,Z		;bcd_mm = 6[FSR1] か？
		goto	tmmon06			;Yes
		btfss	STATUS,C		;bcd_mm > 6[FSR1] か？
		goto	tmmon08			;No

		; （過去のもの）

tmmon05		btfsc	INDF1,0			;タイマー種類 = 1:週間タイマー か？
		goto	tmmon08			;Yes

		clrf	INDF1			;タイマー用メモリの自動消去

		movf	FSR1H,W			;退避
		movwf	addr_high		;
		movf	FSR1L,W			;
		movwf	addr_low		;
		call	yflash_mem_erase_write	;フラッシュメモリの消去とデータ書き込み
		movf	addr_high,W		;
		movwf	FSR1H			;
		movf	addr_low,W		;
		movwf	FSR1L			;復帰
		goto	tmmon08

		; 一致あり

tmmon06		btfsc	INDF1,0			;タイマー種類 = 1:週間タイマー か？
		goto	tmmon07			;Yes

		clrf	INDF1			;タイマー用メモリの自動消去
		call	yflash_mem_erase_write	;フラッシュメモリの消去とデータ書き込み

tmmon07		bsf	STATUS,Z		;Z フラグ = 1、一致あり
		goto	tmmon09

		; 一致なし

tmmon08		addfsr	FSR1,7			;間接アドレス + 7 更新
		decfsz	lpcnt,F			;ループカウンタ1 - 1 = 0 か？
		goto	tmmon01			;No

		bcf	STATUS,Z		;Z フラグ = 0、一致なし

tmmon09		return


;
;==========================================================================
;--------------------------------------------------------------------------
 		org	h'1800'			;(Page 3)
;--------------------------------------------------------------------------
;==========================================================================

		include		C:\Data\Project\PIC\_sub\Font5x7a.tbl

;==========================================================================
;	文字フォント（10 x 14）データテーブル （グラフィック LCD 用）
;		h'2f'(/), h'30'(0) ～ h'39'(9), h'3a'(:) 
;==========================================================================

font10x14_data_tbl
		dt	h'00', h'00', h'00', h'00', h'80'	;/   h'2f'
		dt	h'c0', h'e0', h'70', h'38', h'18'
		dt	h'18', h'1c', h'0e', h'07', h'03'
		dt	h'01', h'00', h'00', h'00', h'00'

;		dt	h'f8', h'fc', h'0e', h'06', h'86'	;0   h'30'
;		dt	h'c6', h'e6', h'6e', h'fc', h'f8'
;		dt	h'1f', h'3f', h'76', h'67', h'63'
;		dt	h'61', h'60', h'70', h'3f', h'1f'

		dt	h'f8', h'fc', h'0e', h'06', h'06'	;0   h'30'
		dt	h'06', h'06', h'0e', h'fc', h'f8'
		dt	h'1f', h'3f', h'70', h'60', h'60'
		dt	h'60', h'60', h'70', h'3f', h'1f'

		dt	h'00', h'00', h'18', h'1c', h'fe'	;1   h'31'
		dt	h'fe', h'00', h'00', h'00', h'00'
		dt	h'00', h'00', h'60', h'60', h'7f'
		dt	h'7f', h'60', h'60', h'00', h'00'

		dt	h'18', h'1c', h'0e', h'06', h'06'	;2   h'32'
		dt	h'06', h'86', h'ce', h'fc', h'78'
		dt	h'60', h'70', h'78', h'7c', h'6e'
		dt	h'67', h'63', h'61', h'60', h'60'

		dt	h'06', h'06', h'06', h'06', h'66'	;3   h'33'
		dt	h'f6', h'fe', h'9e', h'0e', h'06'
		dt	h'18', h'38', h'70', h'60', h'60'
		dt	h'60', h'61', h'73', h'3f', h'1e'

		dt	h'80', h'c0', h'e0', h'70', h'38'	;4   h'34'
		dt	h'1c', h'fe', h'fe', h'00', h'00'
		dt	h'07', h'07', h'06', h'06', h'06'
		dt	h'06', h'7f', h'7f', h'06', h'06'

		dt	h'7e', h'7e', h'66', h'66', h'66'	;5   h'35'
		dt	h'66', h'66', h'e6', h'c6', h'86'
		dt	h'18', h'38', h'70', h'60', h'60'
		dt	h'60', h'60', h'70', h'3f', h'1f'

		dt	h'e0', h'f0', h'b8', h'9c', h'8e'	;6   h'36'
		dt	h'86', h'86', h'86', h'00', h'00'
		dt	h'1f', h'3f', h'71', h'61', h'61'
		dt	h'61', h'61', h'73', h'3f', h'1e'

		dt	h'06', h'06', h'06', h'06', h'86'	;7   h'37'
		dt	h'c6', h'e6', h'76', h'3e', h'1e'
		dt	h'00', h'00', h'7e', h'7f', h'03'
		dt	h'01', h'00', h'00', h'00', h'00'

		dt	h'78', h'fc', h'ce', h'86', h'86'	;8   h'38'
		dt	h'86', h'86', h'ce', h'fc', h'78'
		dt	h'1e', h'3f', h'73', h'61', h'61'
		dt	h'61', h'61', h'73', h'3f', h'1e'

		dt	h'78', h'fc', h'ce', h'86', h'86'	;9   h'39'
		dt	h'86', h'86', h'8e', h'fc', h'f8'
		dt	h'00', h'00', h'61', h'61', h'61'
		dt	h'71', h'39', h'1d', h'0f', h'07'

		dt	h'00', h'00', h'00', h'70', h'70'	;:   h'3a'
		dt	h'70', h'00', h'00', h'00', h'00'
		dt	h'00', h'00', h'00', h'1c', h'1c'
		dt	h'1c', h'00', h'00', h'00', h'00'

;--------------------------------------------------------------------------

font_space	dt	h'00', h'00', h'00', h'00', h'00'	;SP  h'20'
		dt	h'00', h'00', h'00', h'00', h'00'
		dt	h'00', h'00', h'00', h'00', h'00'
		dt	h'00', h'00', h'00', h'00', h'00'

font_large_f	dt	h'fe', h'fe', h'86', h'86', h'86'	;F   h'46'
		dt	h'86', h'86', h'86', h'06', h'06'
		dt	h'7f', h'7f', h'01', h'01', h'01'
		dt	h'01', h'01', h'01', h'00', h'00'

font_large_h	dt	h'fe', h'fe', h'80', h'80', h'80'	;H   h'48'
		dt	h'80', h'80', h'80', h'fe', h'fe'
		dt	h'7f', h'7f', h'01', h'01', h'01'
		dt	h'01', h'01', h'01', h'7f', h'7f'

font_large_m	dt	h'fe', h'fe', h'1c', h'78', h'e0'	;M   h'4d'
		dt	h'e0', h'78', h'1c', h'fe', h'fe'
		dt	h'7f', h'7f', h'00', h'00', h'01'
		dt	h'01', h'00', h'00', h'7f', h'7f'

font_large_s	dt	h'78', h'fc', h'ce', h'86', h'86'	;S   h'53'
		dt	h'86', h'86', h'86', h'0e', h'0c'
		dt	h'30', h'70', h'61', h'61', h'61'
		dt	h'61', h'61', h'73', h'3f', h'1e'

font_large_t	dt	h'06', h'06', h'06', h'06', h'fe'	;T   h'54'
		dt	h'fe', h'06', h'06', h'06', h'06'
		dt	h'00', h'00', h'00', h'00', h'7f'
		dt	h'7f', h'00', h'00', h'00', h'00'

font_large_w	dt	h'fe', h'fe', h'00', h'00', h'80'	;W   h'57'
		dt	h'80', h'00', h'00', h'fe', h'fe'
		dt	h'0f', h'1f', h'70', h'60', h'1f'
		dt	h'1f', h'60', h'70', h'1f', h'0f'

font_small_a	dt	h'00', h'40', h'60', h'60', h'60'	;a   h'61'
		dt	h'60', h'60', h'e0', h'c0', h'80'
		dt	h'18', h'3c', h'66', h'66', h'66'
		dt	h'66', h'66', h'36', h'7f', h'7f'

font_small_d	dt	h'80', h'c0', h'e0', h'60', h'60'	;d   h'64'
		dt	h'e0', h'c0', h'80', h'fe', h'fe'
		dt	h'1f', h'3f', h'70', h'60', h'60'
		dt	h'60', h'61', h'31', h'7f', h'7f'

font_small_e	dt	h'80', h'c0', h'e0', h'60', h'60'	;e   h'65'
		dt	h'60', h'60', h'e0', h'c0', h'80'
		dt	h'1f', h'3f', h'76', h'66', h'66'
		dt	h'66', h'66', h'66', h'27', h'03'

font_small_h	dt	h'fe', h'fe', h'80', h'c0', h'e0'	;h   h'68'
		dt	h'60', h'60', h'e0', h'c0', h'80'
		dt	h'7f', h'7f', h'01', h'01', h'00'
		dt	h'00', h'00', h'00', h'7f', h'7f'

font_small_i	dt	h'00', h'00', h'60', h'60', h'e6'	;i   h'69'
		dt	h'e6', h'00', h'00', h'00', h'00'
		dt	h'00', h'00', h'60', h'60', h'7f'
		dt	h'7f', h'60', h'60', h'00', h'00'

font_small_m	dt	h'e0', h'e0', h'c0', h'60', h'c0'	;m   h'6d'
		dt	h'80', h'e0', h'60', h'c0', h'80'
		dt	h'7f', h'7f', h'00', h'00', h'07'
		dt	h'07', h'00', h'00', h'7f', h'7f'

font_small_n	dt	h'e0', h'e0', h'80', h'c0', h'e0'	;n   h'6e'
		dt	h'60', h'60', h'e0', h'c0', h'80'
		dt	h'7f', h'7f', h'03', h'01', h'00'
		dt	h'00', h'00', h'00', h'7f', h'7f'

font_small_o	dt	h'80', h'c0', h'e0', h'60', h'60'	;o   h'6f'
		dt	h'60', h'60', h'e0', h'c0', h'80'
		dt	h'1f', h'3f', h'70', h'60', h'60'
		dt	h'60', h'60', h'70', h'3f', h'1f'

font_small_p	dt	h'e0', h'e0', h'60', h'60', h'60'	;p   h'70'
		dt	h'60', h'60', h'60', h'c0', h'80'
		dt	h'7f', h'7f', h'06', h'06', h'06'
		dt	h'06', h'06', h'06', h'03', h'01'

font_small_r	dt	h'e0', h'e0', h'80', h'c0', h'e0'	;r   h'72'
		dt	h'60', h'60', h'e0', h'c0', h'80'
		dt	h'7f', h'7f', h'01', h'01', h'00'
		dt	h'00', h'00', h'00', h'01', h'01'

font_small_t	dt	h'60', h'60', h'fe', h'fe', h'60'	;t   h'74'
		dt	h'60', h'00', h'00', h'00', h'00'
		dt	h'00', h'00', h'1f', h'3f', h'70'
		dt	h'60', h'60', h'70', h'38', h'18'

font_small_u	dt	h'e0', h'e0', h'00', h'00', h'00'	;u   h'75'
		dt	h'00', h'00', h'00', h'e0', h'e0'
		dt	h'1f', h'3f', h'70', h'60', h'60'
		dt	h'70', h'38', h'18', h'7f', h'7f'

;--------------------------------------------------------------------------

;		曜日文字列のアドレステーブル	0: Sun ～ 6: Sat

week_string_tbl
		retlw	high font_large_s	;0	;S
		retlw	low  font_large_s
		retlw	high font_small_u		;u
		retlw	low  font_small_u
		retlw	high font_small_n		;n
		retlw	low  font_small_n

		retlw	high font_large_m	;1	;M
		retlw	low  font_large_m
		retlw	high font_small_o		;o
		retlw	low  font_small_o
		retlw	high font_small_n		;n
		retlw	low  font_small_n

		retlw	high font_large_t	;2	;T
		retlw	low  font_large_t
		retlw	high font_small_u		;u
		retlw	low  font_small_u
		retlw	high font_small_e		;e
		retlw	low  font_small_e

		retlw	high font_large_w	;3	;W
		retlw	low  font_large_w
		retlw	high font_small_e		;e
		retlw	low  font_small_e
		retlw	high font_small_d		;d
		retlw	low  font_small_d

		retlw	high font_large_t	;4	;T
		retlw	low  font_large_t
		retlw	high font_small_h		;h
		retlw	low  font_small_h
		retlw	high font_small_u		;u
		retlw	low  font_small_u

		retlw	high font_large_f	;5	;F
		retlw	low  font_large_f
		retlw	high font_small_r		;r
		retlw	low  font_small_r
		retlw	high font_small_i		;i
		retlw	low  font_small_i

		retlw	high font_large_s	;6	;S
		retlw	low  font_large_s
		retlw	high font_small_a		;a
		retlw	low  font_small_a
		retlw	high font_small_t		;t
		retlw	low  font_small_t


;==========================================================================
;		High-Endurance フラッシュメモリ関連アクセス
;==========================================================================

;--------------------------------------------------------------------------
;    High-Endurance フラッシュメモリ から RAM バッファへ データ読み出し
;--------------------------------------------------------------------------

flash_mem_read
		movlw	high save_data_ram	;引継ぎ情報（リニアデータメモリ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_ram	;
		movwf	FSR1L			;間接アドレスに設定
		movlw	timer_mem_addr - save_data_ram
		movwf	f_lpcnt			;ループカウンタ（共通 RAM）

		movlb	3			;バンク 3
		movlw	low save_data		;フラッシュメモリの先頭アドレス
		movwf	PMADRL
		movlw	high save_data
		movwf	PMADRH			;記録アドレスを設定

fmemrd01	bcf	PMCON1,CFGS		;フラッシュメモリにアクセス
		bsf	PMCON1,RD		;読み出し制御 = ON、ハードウェアでクリア
		nop
		nop
		movf	PMDATL,W		;下位データの読み出し
		movwi	FSR1++			;
	;	movf	PMDATH,W		;上位データの読み出し
	;	movwi	FSR1++			;
		incf	PMADRL,F		;記録アドレスの更新
		decfsz	f_lpcnt,F		;ループカウンタ - 1 = 0 か？
		goto	fmemrd01		;No

		movlb	0			;バンク 0
		call	ram_buff_read		;RAM バッファから個々の変数へコピー
		return

;--------------------------------------------------------------------------

		; RAM バッファから個々の変数へコピー

ram_buff_read
		movlw	high save_data_ram	;引継ぎ情報（リニアデータメモリ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_ram	;
		movwf	FSR1L			;間接アドレスに設定

		moviw	FSR1++			;
		movwf	bcd_yh			;年(上位2桁)_BCD カウンタ

		moviw	FSR1++			;
		movwf	sleep_time		;スリープまでの移行時間(分)

		moviw	FSR1++			;
		movwf	contrast		;OLED コントラスト

		; 初期設定制御バイトのチェックとタイマー用メモリの初期設定

		moviw	FSR1++			;初期設定制御バイト
		sublw	h'a5'
		btfss	STATUS,Z		;タイマー用メモリの初期設定制御バイト = h'a5' か？
		goto	ramrd02			;No

		; （以降は初めてプログラムが実行されたときの１度のみ実行する）

		movlw	timer_mem_addr - timer_memory
		movwf	f_lpcnt			;ループカウンタ

ramrd01		clrw
		movwi	FSR1++			;タイマー用メモリを h'00' クリア
		decfsz	f_lpcnt,F		;ループカウンタ - 1 = 0 か？
		goto	ramrd01			;No

		; RAM バッファから High-Endurance フラッシュメモリへ 初期データの書き戻し

		call	flash_mem_erase		;High-Endurance フラッシュメモリを３行（32 x 3 ワード）消去
		call	flash_mem_write	       ;;RAM バッファから High-Endurance フラッシュメモリへ データ書き込み

ramrd02		return

;--------------------------------------------------------------------------
;	 High-Endurance フラッシュメモリを３行（32 x 3 ワード）消去
;--------------------------------------------------------------------------

flash_mem_erase
		bcf	INTCON,GIE		;割り込みを禁止
		movlb	3			;バンク 3
		movlw	low save_data		;フラッシュメモリの先頭アドレス
		movwf	PMADRL
		movlw	high save_data
		movwf	PMADRH

		movlw	3
		movwf	f_lpcnt			;ループカウンタ（共通 RAM）

fmemer01	bcf	PMCON1,CFGS		;フラッシュメモリにアクセス
		bsf	PMCON1,FREE		;消去操作を指定、ハードウェアでクリア
		bsf	PMCON1,WREN		;書き込みを許可

		movlw	h'55'
		movwf	PMCON2			;h'55' を PMCON2 に書き込む
		movlw	h'aa'
		movwf	PMCON2			;h'aa' を PMCON2 に書き込む
		bsf	PMCON1,WR		;書き込み制御 = ON、ハードウェアでクリア
		nop
		nop
		bcf	PMCON1,WREN		;書き込みを禁止

		movlw	32
		addwf	PMADRL,F
		decfsz	f_lpcnt,F		;ループカウンタ - 1 = 0 か？
		goto	fmemer01		;No

		movlb	0			;バンク 0
		bsf	INTCON,GIE		;割り込みを許可
		return

;--------------------------------------------------------------------------
;    RAM バッファから High-Endurance フラッシュメモリへ データ書き込み
;--------------------------------------------------------------------------

flash_mem_write
		call	ram_buff_write		;個々の変数から RAM バッファへコピー

		bcf	INTCON,GIE		;割り込みを禁止
		movlw	high save_data_ram	;引継ぎ情報（リニアデータメモリ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_ram	;
		movwf	FSR1L			;間接アドレスに設定
		movlw	timer_mem_addr - save_data_ram
		movwf	f_lpcnt			;ループカウンタ（共通 RAM）... 総書き込みバイト数

		movlb	3			;バンク 3
		movlw	low save_data		;フラッシュメモリの先頭アドレス
		movwf	PMADRL			;
		movlw	high save_data
		movwf	PMADRH			;

fmemwr01	movlw	32			;1 行 = 32 ラッチ数
		movwf	f_lpcnt2		;ループカウンタ2（共通 RAM）

		bcf	PMCON1,CFGS		;フラッシュメモリにアクセス
		bsf	PMCON1,WREN		;書き込みを許可
		bsf	PMCON1,LWLO		;書き込みラッチへ書き込み指示

fmemwr02	moviw	FSR1++			;最初のデータバイトを下位にロード
		movwf	PMDATL			;
	;	moviw	FSR1++			;2番目のデータバイトを上位にロード
	;	movwf	PMDATH			;
		decf	f_lpcnt,F		;
		btfsc	STATUS,Z		;ループカウンタ  - 1 = 0 か？
		goto	fmemwr03		;Yes

		decf	f_lpcnt2,F		;
		btfsc	STATUS,Z		;ループカウンタ2 - 1 = 0 か？
		goto	fmemwr03		;Yes

		movlw	h'55'
		movwf	PMCON2			;h'55' を PMCON2 に書き込む
		movlw	h'aa'
		movwf	PMCON2			;h'aa' を PMCON2 に書き込む
		bsf	PMCON1,WR		;書き込み制御 = ON、ハードウェアでクリア
		nop
		nop
		incf	PMADRL,F		;記録アドレスの更新
		goto	fmemwr02

fmemwr03	bcf	PMCON1,LWLO		;フラッシュメモリへ書き込み指示
		movlw	h'55'
		movwf	PMCON2			;h'55' を PMCON2 に書き込む
		movlw	h'aa'
		movwf	PMCON2			;h'aa' を PMCON2 に書き込む
		bsf	PMCON1,WR		;書き込み制御 = ON、ハードウェアでクリア
		nop
		nop
		incf	PMADRL,F		;記録アドレスの更新
		bcf	PMCON1,WREN		;書き込みを禁止

		movf	f_lpcnt,F		;
		btfss	STATUS,Z		;ループカウンタ = 0 か？
		goto	fmemwr01		;No

		movlb	0			;バンク 0
		bsf	INTCON,GIE		;割り込みを許可
		return

;--------------------------------------------------------------------------

		; 個々の変数から RAM バッファへコピー

ram_buff_write
		movlw	high save_data_ram	;引継ぎ情報（リニアデータメモリ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_ram	;
		movwf	FSR1L			;間接アドレスに設定

		movf	bcd_yh,W		;年(上位2桁)_BCD カウンタ
		movwi	FSR1++			;

		movf	sleep_time,W		;スリープまでの移行時間(分)
		movwi	FSR1++			;

		movf	contrast,W		;OLED コントラスト
		movwi	FSR1++			;

		clrw				;初期設定制御バイト
		movwi	FSR1++			;
		return

;==========================================================================

copyright	de	"Copyright (C) 2024-2025 by M.Yamamoto"
c_end

;==========================================================================
;		High-Endurance フラッシュメモリ
;==========================================================================

		org	h'1f80'

		; 以下はデフォルト値

save_data	dt	h'20'			;年(上位)_BCD カウンタ

		dt	10			;スリープまでの移行時間(分)

		dt	h'7f'			;OLED コントラスト

		dt	h'a5'			;タイマー用メモリの初期設定制御バイト

timer_memory_bup

;	      （これ以降 70 バイトをタイマー用メモリのバックアップ用として使用）

;==========================================================================

		end				;プログラムの終了

