;***** KitchenTimerII.asm *************************************************
;
;	有機 EL ディスプレイ(OLED) 表示 キッチン・タイマー II
;
;	Copyright (C) 2025   by M.Yamamoto. All rights reserved.
;
;	Homepage URL: https://xyama.sakura.ne.jp/hp/KitchenTimerII.html
;
;     ( coding: Ver.0.00 2025/06/06  by M.Yamamoto )
;	coding: Ver.1.00 2025/07/22  初期バージョン
;	update: Ver.1.01 2025/07/27  select_no_blinkでビットずらし解除指示
;	                             battery_volt2_displayでビットずらし指示
;	bugfix: Ver.1.02 2025/08/03  stop_msg_display内でときどきブリンクしなくなる
;	bugfix: Ver.1.03 2025/08/04  counter_display内でときどきシステムがリセット
;	update: Ver.1.04 2025/08/05  コメントを一部修正と追加
;
;******************************************************* PicAsm 0271 ******

;	Device: PIC16F18325	Clock: 4MHz (Internal OSC)

#ifdef comment

　プログラム中のこの文章説明だけでは、その機能等を理解するのが少々難しいと思われるため、次のホームページ上で、
　多くの写真を加えた説明を用意したので、そちらをご覧いただきたい。

	ＵＲＬ： https://xyama.sakura.ne.jp/hp/KitchenTimerII.html#usage

　また、このファイル（KitchenTimerII.asm）はテキストファイルであるが、メモ帳ではファイル中で使用している
　罫線（コメントで使用）の表示処理がうまくできず、見た目がぐちゃぐちゃになる。ただし、現時点（2025/01/24）に
　おいては Microsoft Edge 131.0.2903.112 では、問題なく表示ができるのでドラッグ＆ドロップして同ブラウザで見る
　ことをお勧めする。


 ==================
 <機能概要と使用法>
 ==================

-------------------------------
◎ スイッチ操作と機能間の遷移図
-------------------------------

・本機では電源に 18650 リチウムイオン電池を採用し、その 18650 リチウムイオン電池のための充電機能も内蔵してい
　るので、USB コネクタから + 5 V 電源を供給すれば電池を充電することも可能である。ただし、本機では充電中には本
　機の電源スイッチを切っておく必要があり、充電しながらの連続使用はできない。

・また、本機では RTC モジュールの時計情報（年、月、日、時、分、秒）をまったく使用しないため、電源を断にしたと
　きに備えてのバックアップ用の電池は必要がない。

・さて、本機の電源スイッチを ON にすると、"ピポッ" と開始ブザー音を出力後、プログラムのタイトル、およびバージ
　ョン番号などの表示とともに、有機 EL ディスプレイ(OLED) の簡単なデモ表示が数秒間行われる。

			  Kitchen Timer II
			    Version x.xx
			    by m.yamamoto

・このとき、DOWN スイッチと UP スイッチを同時に押しながら電源スイッチを ON にしたときには、デモ表示だけを省略
　することができる。

・ディスプレイ(OLED) のデモ表示が終了すると、PIC の EEPROM メモリに記憶されている、各種の引き継ぎ情報を RAM 
　バッファ、および各種変数へ読み出し後に、"ピピッ" ブザー音とともに、「カウンタ種類の選択」画面（メインルーチ
　ン）へと進む。

・次の図は、本機におけるスイッチ操作と各機能間の遷移の関係だけを図に表したもので、（XXX）で示す各スイッチを操
　作することで各機能間を移動する。（なお、各機能内でのスイッチ操作については、以降で説明をするそれぞれの機能
　の項を参照のこと）

			 CANCEL    LEFT     DOWN      UP      RIGHT    START
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │●│   │●│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/ MAINTE  / NEXT                    / PREV.  / SELECT

			スイッチ省略名	 (STA): START
					 (SEL): SELECT
					 (RIG): RIGHT
					 (PRV): PREV.
					  (UP): UP
					 (DWN): DOWN
					 (LEF): LEFT
					 (NEX): NEXT
					 (CAN): CANCEL
					 (MNT): MAINTE

	　　（ 図は https://xyama.sakura.ne.jp/KitchenTimerII/_/KitchenTimerIIFigx.png を参照 ）

・DOWN カウンタ機能は、START スイッチを押すと、予め設定しておいたタイマー時間を１秒ごとにカウントダウンして行
　き、そのときどきの残時間（分秒）を LARGE 数字文字で表示するとともに、秒においてはバーグラフでも毎秒更新され
　て行く様子を表示する。本機における設定時間は最大 99 分 59 秒までが可能で、予め設定しておいた設定時間が経過
　してタイムアウトを迎えると、アラームによってその旨を知らせる。

・UP カウンタ機能は、START スイッチを押してから CANCEL スイッチが押されるまでの間、毎秒ごとにカウントアップさ
　れて行く様子を LARGE 数字文字で表示するとともに、秒においてはバーグラフでも毎秒更新されて行く様子を表示する。
　CANCEL スイッチが押されるまでの間 ― というのに上限はないが、本機では最大 99 分 59 秒までしかカウントするこ
　とができないため、それ以上に時間経過をした場合には、表示は 00 分 00 秒に戻って始めからカウントアップを繰り
　返す。

・DOWN + UP カウンタ機能は、その名の通り、START スイッチを押した直後は DOWN カウンタとして機能し、予め設定し
　ておいたタイマー時間からカウントダウンして行き、やがてタイムアウトを迎えるとアラームによってその旨を知らせ
　た後、引き続き UP カウンタに転じて機能するようになり、CANCEL スイッチが押されるまでの間カウントアップされて
　行く。それぞれの DOWN カウンタ、UP カウンタ機能は、上述の単独での DOWN カウンタ機能、UP カウンタ機能と異な
　るところはない。

-----------------------------------------------
◎ 「カウンタ種類の選択」画面（メインルーチン）
-----------------------------------------------

			 CANCEL    LEFT     DOWN      UP      RIGHT    START
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │●│   │●│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/ MAINTE  / NEXT                    / PREV.  / SELECT

		 NEXT スイッチ        ..... 選択位置のポインタを + 1
		PREV. スイッチ        ..... 選択位置のポインタを - 1

	       SELECT スイッチ        ..... 選択位置のカウンタ機能へ移行

		   UP スイッチ 長押し ..... UP カウンタ機能へ移行（３秒以上の長押し）

		 DOWN スイッチ 長押し ..... DOWN カウンタ機能へ移行（３秒以上の長押し）

		 DOWN スイッチ 長押し +
		   UP スイッチ        ..... Down + Up カウンタ機能へ移行（３秒以上の長押し）

	       MAINTE スイッチ 長押し ..... メンテナンス機能に移行（３秒以上の長押し）

・本機では、次の選択メッセージに示すように３種類のカウンタ機能を持ち、まず、どの種類のカウンタを使用するかを
　選択することから始める。

			  Counter Select ? x
			   1. Down
			   2. Up
			   3. Down + Up

・初めに表示される上の選択画面では、前回実行されたカウンタ種類が引き継がれ、２行目～４行目の内のどれか（デフ
　ォルトでは 1. Down: ２行目）が選択されて、先頭番号（1.／2.／3. のどれか）が反転表示され、かつ、１行目の 
　"Counter Select ? x" メッセージの x 位置には、その選択された番号がブリンク表示される。

・これらのカウンタ種類は、NEXT スイッチ、または PREV. スイッチを押すことによって変更をすることができ、希望す
　るカウンタ種類を選択後に SELECT スイッチを押すことによって選択決定され、"ピピッ" ブザー音とともに次項の「３
　種類のカウンタ」の初期画面のどれかが表示される。

・もう一つの選択方法として、直接、希望するカウンタ種類と同名の DOWN スイッチ、UP スイッチ、または DOWN スイッ
　チ + UP スイッチ（DOWN スイッチを押しながら UP スイッチ）を３秒以上長押しをしていると、それまで選択表示され
　ていたカウンタ種類には関係なく、長押しによって新たに選択したカウンタ種類と同行の右端に、"ピッ" ブザー音とと
　もに "Go!" メッセージが追加反転表示されるので、それを合図に各スイッチから指を放すと、"ピピッ" ブザー音とと
　もに次項の「３種類のカウンタ」の初期画面のどれかが表示される。

・なお、この「カウンタ種類の選択」画面において、どのスイッチも操作しない状態が３分（デフォルト）以上続くと、
　省エネのため自動的にディスプレイ (OLED) をスリープさせるとともに、本機自体もスリープモードに移行する。

・本機がスリープモードに移行するときには、３分（デフォルト）を経過する３秒前から、秒ごとに "ブッ" ブザー音を
　３回、また、３分を経過直後に "ブッブー" ブザー音とともにスリープモードに移行する。

・また、本機自体およびディスプレイ (OLED) がスリープモードになっているときに、全６つのスイッチの内のどれかが
　操作されると本機はウエイクアップして、"ピピッ" ブザー音とともに、再びディスプレイ (OLED) 画面の表示がされる
　ようになる。

-------------------------------------------------
◎ 「３種類のカウンタ」画面とタイマー時間の設定
-------------------------------------------------

			 CANCEL    LEFT     DOWN      UP      RIGHT    START
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │●│   │●│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/ MAINTE  / NEXT                    / PREV.  / SELECT

	        RIGHT スイッチ        ..... ブリンク位置のポインタを + 1
		 LEFT スイッチ        ..... ブリンク位置のポインタを - 1

		   UP スイッチ        ..... ブリンク位置の値を + 1
		 DOWN スイッチ        ..... ブリンク位置の値を - 1

	        START スイッチ        ..... 各カウンタの動作を開始

	       CANCEL スイッチ        ..... 「３種類のカウンタ」画面の表示を終了し、
	                                    「カウンタ種類の選択」画面へ戻る

・前項の「カウンタ種類の選択」画面（メインルーチン）で、３種類のカウンタ機能の内のどれかが選択されて移行して
　くると、次の写真のようにそれぞれ「３種類のカウンタ」画面のどれかが表示される。これらの「３種類のカウンタ」
　画面は、一見どれも同じように見えるが、ディスプレイ画面の右側半分１行目にカウンタ種類が表示されているので、
　それで区別ができる。

・この「３種類のカウンタ」画面の内、DOWN カウンタ画面と DOWN + UP カウンタ画面では、DOWN カウンタとしての初期値
　（タイマー時間）が必要であり、前回使用（設定）された時分（デフォルトでは 15 分 00 秒）が記憶されているので、
　画面左上の LARGE 数字文字の表示位置にその時分（MM:SS）が表示されるとともに、左端の１文字目（デフォルト）が
　ブリンク表示される。

		DOWN カウンタ画面        DOWN + UP カウンタ画面

・画面左上に表示される LARGE 数字文字は、左から 10 分カウンタ、1 分カウンタ、10 秒カウンタ、1 秒カウンタに対
　応していて、この４つのカウンタの内で変更を希望するカウンタを、まず、RIGHT スイッチ または LEFT スイッチ の
　操作によって、そのブリンク表示されているカウンタ位置を変更する。

・次に、UP スイッチ または DOWN スイッチ の操作によって、ブリンク表示されているカウンタ位置の値を変更する。 
　このように４つのスイッチの操作によって、４つのカウンタ値を希望する DOWN カウンタとしての初期値（タイマー時
　間）に設定する。

・この状態のとき（４つのカウンタの内のどれか１つがブリンク表示中）に、START スイッチを押すと（指を放した瞬間
　から）、"ピピッ" ブザー音とともに１秒ごとのカウントダウンが始まり、そのときどきの残時間（分秒）で画面左上 
　の LARGE 数字文字を更新（ダウン）するとともに、秒においてはバーグラフでも１秒ごとに更新（ダウン）されて行
　く様子を表示する。

・また、これら２者の内の DOWN + UP カウンタ画面では、画面左上の LARGE 数字文字のカウントダウンが始まると同時
　に、それに加えて、その右横１行目の NORMAL 数字文字が毎秒ごとにカウントアップされて行く様子も表示される。

・一方、UP カウンタ画面では、前項の「カウンタ種類の選択」画面から移行してきた直後から、画面左上の LARGE 数字
　文字の表示位置には、UP カウンタとしての初期値 00 分 00 秒 が表示されるが、上述２者のカウンタ画面とは異なっ
　て、予め何も設定しておくようなものはないため画面上のどこもブリンク表示されることはなく、画面にはまったく動
　きがないので注意が必要である。

		UP カウンタ画面

・このように UP カウンタ画面では、ひたすら、START スイッチが押されるのを待ち続け、やがて、START スイッチが押
　されると（指を放した瞬間から）、"ピピッ" ブザー音とともに１秒ごとのカウントアップが始まり、そのときどきの経
　過時間（分秒）で画面左上の LARGE 数字文字を更新（アップ）するとともに、秒においてはバーグラフでも１秒ごとに
　更新（アップ）されて行く様子が表示される。

・ここで、カウンタ機能には直接関係はないが、３種類のカウンタ画面の右側半分２行目には、本機で使用している電源 
　18650 リチウムイオン電池の、現在電圧値を表示する機能も搭載しているので、電池の充電時期の判断に使用すること
　ができる。

・そして、これら３者のカウンタ画面において、もしも、START スイッチが押されるよりも以前に CANCEL スイッチが押
　された場合には、直ちに、それぞれのカウンタ画面から前項の「カウンタ種類の選択」画面（メインルーチン）に、"ピ
　ピッ" ブザー音とともに戻る。

・また、START スイッチ、または CANCEL スイッチのいずれも押されず（DOWN カウンタ画面と DOWN + UP カウンタ画面
　では、RIGHT、LEFT、UP、DOWN のすべてのスイッチを含む）に、３分（デフォルト）以上が経過すると、省エネのため
　自動的にディスプレイ (OLED) をスリープさせるとともに、本機自体もスリープモードに移行する。

・このスリープモードに移行するときの様子や、やがてウエイクアップするときの様子は、前項の「カウンタ種類の選択」
　画面での様子とまったく同様である。

-----------------------------------------
◎ 「３種類のカウンタ」画面とカウンタ動作
-----------------------------------------

・前項で DOWN カウンタ画面、または DOWN + UP カウンタ画面 において START スイッチ が押されると、その前に予め
　設定しておいた設定時間から１秒ごとにカウントダウンが行われて、その刻々と "分秒" が更新（ダウン）されて行く
　様子が、LARGE 数字文字の表示エリアに表示されるとともに、バーグラフの表示エリアにも刻々と "秒" が更新（ダウ
　ン）されて行く様子が表示される。

・この２者のカウンタ画面の内 DOWN + UP カウンタ画面 では、上記に加えて、カウンタ画面の右側半分１行目の NORMAL 
　数字文字の表示エリアにも、毎秒ごとにカウントアップされて "分秒" が更新（アップ）されて行く様子が同時に表示
　される。（この場合には DOWN カウンタと UP カウンタが同時に動作をしている。）

・これら２者のカウンタ画面では、DOWN カウンタが 10 秒を経過する（毎 0 秒になる）ごとに "プッ" ブザー音を、ま
　た１分を経過する（毎 00 秒になる）ごとに "ププッ" ブザー音を出力して、経過を音声でも知らせる。

・以上の動作を、予め設定しておいた設定時間（タイマー時間：本機では最大 99 分 59 秒まで）が経過して、タイムア
　ウトを迎えるまで繰り返し実行するが、やがてタイムアウトを迎える 10 秒前からは、毎秒ごとに "プッ" ブザー音を
　出力するようになり、そして、残り時間がゼロになると "ピピピッ" ブザー音を３回繰り返して、カウントダウンが停
　止したことをアラーム音でも知らせる。

・その後、実行された設定時間が PIC の EEPROM メモリ内に記憶されているデータと同一であったかどうかの重複チェッ
　クが行われ、もしも、異なっていた場合には新たな設定時間として、EEPROM メモリ内の記憶を更新するが、同一のデー
　タであった場合には記憶を更新することはない。

・このようにタイムアウトを迎えた両カウンタ画面の内、DOWN カウンタ画面では、最下行にカウンタストップメッセージ
　が出力される。

			  Counter Stop ! _

			タイムアウトになった

・また、DOWN + UP カウンタ画面では、アラームによってタイムアウトを知らせた後（EEPROM メモリの更新も同様に済ま
　せた後）、LARGE 数字文字の表示エリアに表示されていた DOWN カウンタは、引き続き UP カウンタに転じて（初期値 
　00 分 00 秒から）機能するようになり、元々表示されていた、カウンタ画面の右側半分１行目の NORMAL 数字文字の表
　示エリアについては、タイムアウトを迎えたと同時に表示の更新は停止をする。

・そして、この UP カウンタによりその刻々と "分秒" が更新（アップ）されて行く様子が、新たに LARGE 数字文字の表
　示エリアに表示されるとともに、バーグラフの表示エリアにも刻々と "秒" が更新（アップ）されて行く様子が表示さ
　れるようになる。

・一方、前項で UP カウンタ画面 において START スイッチが押されると、初期値 00 分 00 秒から１秒ごとにカウント
　アップが行われ、その刻々と "分秒" が更新（アップ）されて行く様子が、LARGE 数字文字の表示エリアに表示される
　とともに、バーグラフの表示エリアにも刻々と "秒" が更新（アップ）されて行く様子が表示される。

・これらの UP カウンタ画面でも、UP カウンタが 10 秒を経過する（毎 0 秒になる）ごとに "プッ" ブザー音を、また
　１分を経過する（毎 00 秒になる）ごとに "ププッ" ブザー音を出力して、経過を音声でも知らせることは同様である。

・また、これらの UP カウンタでは、CANCEL スイッチが押されるまでいつまでもカウントアップをし続け、上限の制限が
　ない。ただし、本機では最大 99 分 59 秒までしかカウントすることができないため、それ以上に時間経過をした場合
　には 100 分経過ごとに、その表示が 00 分 00 秒に戻って始めからカウントアップを繰り返す。

・やがて、CANCEL スイッチが押されると UP カウンタは停止をし、"ブー" ブザー音とともに UP カウンタ画面の最下行
　に、カウンタストップメッセージが出力される。

			  Counter Stop ! _

			カウントアップを実行中に CANCEL スイッチが押された

・また、上述の DOWN カウンタ画面、または DOWN + UP カウンタ画面 において、タイムアウトを迎える前で未だカウン
　トダウンを実行中に、CANCEL スイッチを押して強制的に DOWN カウンタを停止させた場合にも同様に、"ブー" ブザー
　音とともに DOWN カウンタ画面の最下行に、カウンタストップメッセージが出力される。そしてこの場合には、データ
　の重複チェックは行われず EEPROM メモリ内の記憶を更新することもない。

			  Counter Stop ! _

			カウントダウンを実行中に CANCEL スイッチが押された

・このように、いろいろな状況下で DOWN カウンタ、または UP カウンタが停止をしたことによって、その結果としてカ
　ウンタストップメッセージが出力され、そのメッセージの右端１文字がブリンク表示される。ユーザはその結果を十分
　確認した後に、全６個のスイッチの内のどれかを押して応答をする。

・そして、全６個のスイッチの内のどれかを押して応答をすると、"ピピッ" ブザー音とともに、それまで実行していた
　「３種類のカウンタ」画面（DOWN カウンタ画面、UP カウンタ画面、または DOWN + UP カウンタ画面のどれか）と同一
　の、カウンタ画面の初期画面に再び戻って表示がされる。

・カウントダウンやカウントアップを実行中には、これらのカウンタ機能には直接関係はないが、３種類の各カウンタ画
　面の右側半分２行目に、本機で使用している電源 18650 リチウムイオン電池の現在電圧値を、５秒ごとに更新をしなが
　ら表示する。また、これらどちらかのカウンタが実行中には、次に述べるような、スリープモード に移行することはな
　い。

・なお、上述のようなユーザからの応答待ちの場面においても、どのスイッチも操作しない状態が３分（デフォルト）以
　上続くと、省エネのため自動的にディスプレイ (OLED) をスリープさせるとともに、本機自体も スリープモード に移
　行する。そして、スリープモードに移行するときの様子や、やがてウエイクアップするときの様子は、「カウンタ種類
　の選択」画面での様子 とまったく同様である。

-----------------------------------------
◎ 「メンテナンス機能」画面とスイッチ操作
-----------------------------------------

			 CANCEL    LEFT     DOWN      UP      RIGHT    START
			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
			 │●│   │●│   │●│   │●│   │●│   │●│
			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
			/ MAINTE  / NEXT                    / PREV.  / SELECT

		NEXT スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択
		PREV.スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択

		  UP スイッチ        ..... ブリンク位置の値を + 1
		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り

		  UP スイッチ +
		DOWN スイッチ        ..... ブリンク位置の値をデフォルト値に設定

		DOWN スイッチ        ..... ブリンク位置の値を - 1
		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り

		DOWN スイッチ +
		  UP スイッチ        ..... ブリンク位置の値をデフォルト値に設定

	      SELECT スイッチ        ..... メンテナンス機能を終了し、メイン（カウンタ種類の選択）に戻る

	      CANCEL スイッチ        ..... メンテナンス機能を中断し、メイン（カウンタ種類の選択）に戻る

・「カウンタ種類の選択」画面（メインルーチン）で、カウンタ種類の選択とは関係ない MAINTE スイッチ を３秒以上長
　押しをしていると、"ピッ" ブザー音とともに、ディスプレイ画面の最下行に次に示すように、" Maintenance " + "Go!" 
　メッセージが反転表示されるので、それを合図に MAINTE スイッチから指を放すと、ディスプレイ画面が「メンテナン
　ス機能」画面に切り替わる。

			  Counter Select ? x


			   Maintenance  Go!

　（上の「カウンタ種類の選択」画面から、次の「メンテナンス機能」画面に切り替わる。）

			  > OLED Contrast
			   (001-255) ? _ xxx
			  > Sleep Time
			   (00-30) ? _ xx

・本機におけるメンテナンス機能には、OLED コントラストの設定変更と、スリープまでの移行時間（分）の設定変更、の
　２つの設定変更機能があり、本「メンテナンス機能」画面に切り替わった直後は、前者の設定変更が選択されて 
　"(001-255) ? _ xxx" メッセージ の "xxx" 部分がブリンク表示される。

・そこで、前者設定値を変更したい場合には、UP スイッチを押すごとに現在値より１ずつ増加し、また DOWN スイッチを
　押すごとに１ずつ減少するので、適宜希望する値に変更する。

・また、後者の設定変更を選択したい場合には、NEXT スイッチ、または PREV. スイッチを押すことによって、
　"(00-30) ? _ xx" メッセージ の "xx" 部分がブリンク表示されるので、同様に UP スイッチまたは DOWN スイッチを
　押すことによって、 希望する値に変更する。

・このように NEXT スイッチ、または PREV. スイッチは、押すごとに両者の設定変更の選択を交互に切り替えることがで
　き、それぞれで変更できる設定範囲は、前者では 001 ～ 255 まで、後者では 00 ～ 30 まで可能としている。ただし、
　後者で 00 を設定した場合には、スリープモードには移行しなくなるので注意が必要である。

　（参考）前者の設定値として、SSD1306 では 000 の設定も可能ではあるが、その場合には画面が完全に消えてしまう
　　　　　ので、本機では設定値から外すことにした。

・また、UP スイッチまたは DOWN スイッチによる増減幅を大きくしたい場合には、UP スイッチまたは DOWN スイッチを
　押したまま にしていると、増減値が早送りされる ようになる。

・なお、OLED コントラストを設定変更、スリープまでの移行時間（分）を設定変更、の２つの設定値のデフォルト値は、
　それぞれ 127 と 3 に規定されており、それぞれの設定変更が選択されているときに、UP スイッチと DOWN スイッチを
　同時に押すことによって、それぞれのデフォルト値に簡単に設定することができる。

・両者の設定変更が済んで、元の「カウンタ種類の選択」画面（メインルーチン）に戻りたい場合は、SELECT スイッチを
　押すことによって行われ、変更された設定値で PIC の EEPROM メモリを更新後、"ピピッ" ブザー音を出力して正常に
　終了したことを知らせる。なお、EEPROM メモリを更新する前にはデータの重複チェックが行われ、もしも、変更後のデ
　ータと EEPROM メモリのデータが同一の場合には、更新をすることはない。

・また、何らかの理由があって途中で設定変更を中断したい場合には、CANCEL スイッチを押すことによって、メンテナン
　ス機能に移行する前の「カウンタ種類の選択」画面（メインルーチン）に戻ることができる。この場合には、それまで
　に変更された設定値は破棄され、"ブー" ブザー音を出力して中断終了したことを知らせる。

・この「メンテナンス機能」画面においても、どのスイッチも操作しない状態が３分（デフォルト）以上続くと、省エネ
　のため自動的にディスプレイ (OLED) をスリープさせるとともに、本機自体も スリープモード に移行する。そして、
　スリープモードに移行するときの様子や、やがてウエイクアップするときの様子は、「カウンタ種類の選択」画面での
　様子とまったく同様である。

#endif

;==========================================================================

;	PIC16F18325 のピンと用途

;		(1) Vdd: 電源 +3V DC	   (14) Vss: 電源 GND
;		(2) RA5: LEFT SW 入力	   (13) RA0: RIGHT SW 入力 / DAT
;		(3) RA4: DOWN SW 入力	   (12) RA1: UP SW 入力 / CLK
;		(4) RA3: 予備入力 / Vpp	   (11) RA2: RTC SQW 入力
;		(5) RC5: CANCEL SW 入力    (10) RC0: I2C SCL 出力
;		(6) RC4: START SW 入力	    (9) RC1: I2C SDA 入出力
;		(7) RC3: 圧電スピーカ 出力  (8) RC2: BATT 電圧測定入力

;	*注.  RA3 は入力専用で、出力ポートには使えない。

;==========================================================================

		list		p=pic16f18325		;デバイス情報
		include		p16f18325.inc		;インクルードファイル
		errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションワードの設定
;==========================================================================

	__config _CONFIG1, _FEXTOSC_OFF & _RSTOSC_HFINT1 & _CLKOUTEN_OFF & _CSWEN_ON & _FCMEN_OFF
	__config _CONFIG2, _MCLRE_OFF & _PWRTE_OFF & _WDTE_OFF & _LPBOREN_OFF & _BOREN_OFF & _BORV_LOW & _PPS1WAY_OFF & _STVREN_ON & _DEBUG_OFF
	__config _CONFIG3, _WRT_OFF & _LVP_OFF
	__config _CONFIG4, _CP_OFF & _CPD_OFF

; ------------------------------------
; CONFIGURATION WORD 1 (ADDRESS:0007H)		Data Sheet DS40001795K - page 64
; ------------------------------------
;
;     CONFIG1 = 01 1111 1110 1100
;	        || |||| |||| ||||
;	bit2-0  || |||| |||| |+++---- FEXTOSC<2:0>: FEXTOSC 外部発振器モード選択ビット
;	        || |||| |||| |          111 = ECH: EC(外部クロック) 8MHz以上
;	        || |||| |||| |          110 = ECM: EC(外部クロック) 100kHz～8MHz
;	        || |||| |||| |          101 = ECL: EC(外部クロック) 100kHz未満
;	        || |||| |||| |      >   100 = OFF: 発振器無効
;	        || |||| |||| |          011 = 未実装
;	        || |||| |||| |          010 = HS:  HS(水晶発振器) 4MHz以上
;	        || |||| |||| |          001 = XT:  HT(水晶発振器) 100kHz以上、4MHz未満
;	        || |||| |||| |          000 = LP:  LP(水晶発振器) 32.768kHzに最適化
;	        || |||| |||| |
;	bit3    || |||| |||| +------- 未実装
;	        || |||| ||||
;	bit6-4  || |||| |+++--------- RSTOSC<2:0>: COSCビットのパワーアップ時のデフォルト値
;	        || |||| |              この値はCOSCのリセット時のデフォルト値であり、ユーザーソフトウェアが最初に使用する発振器を選択する
;	        || |||| |               111 = EXT1X:   EXTOSCはFEXTOSC<2:0>ビットに従って動作する
;	        || |||| |           >   110 = HFINT1:  HFINTOSC (1MHz)
;	        || |||| |               101 = 予約済み
;	        || |||| |               100 = LFINT:   LFINTOSC
;	        || |||| |               011 = SOSC:    SOSC (32.768kHz)
;	        || |||| |               010 = 予約済み
;	        || |||| |               001 = EXT4X:   EXTOSC（4倍速PLL使用）、EXTOSCはFEXTOSC<2:0>ビットに従って動作する
;	        || |||| |               000 = HFINT32: HFINTOSC (32MHz)
;	        || |||| |
;	bit7    || |||| +------------ 未実装
;	        || ||||               ________
;	bit8    || |||+-------------- CLKOUTEN: クロック出力イネーブルビット
;	        || |||                 FEXTOSC = EC、HS、HT、またはLPの場合：
;	        || |||                  このビットは無視される
;	        || |||                 それ以外の場合：
;	        || |||              >   1 = OFF: CLKOUT機能は無効。OSC2のI/Oまたは発振器機能
;	        || |||                  0 = ON:  CLKOUT機能は有効。OSC2にはFOSC/4クロックが出力される
;	        || |||
;	bit10-9 || |++--------------- 未実装
;	        || |  
;	bit11   || +----------------- CSWEN：クロックスイッチイネーブルビット
;	        ||                  >   1 = ON:  NOSCおよびNDIVへの書き込みが許可される
;	        ||                      0 = OFF: NOSCおよびNDIVビットはユーザーソフトウェアでは変更できない
;	        ||
;	bit12   |+------------------- 未実装
;	        |
;	bit13   +-------------------- FCMEN: フェイルセーフ・クロックモニタ・イネーブルビット
;	                                1 = ON:  FSCMタイマー有効
;	                            >   0 = OFF: FSCMタイマー無効
;
; ------------------------------------
; CONFIGURATION WORD 2 (ADDRESS:0008H)		Data Sheet DS40001795K - page 65
; ------------------------------------
;
;     CONFIG2 = 11 1111 0011 0010
;	        || |||| |||| ||||
;	bit0    || |||| |||| |||+---- MCLRE: マスタークリア（MCLR）有効化ビット
;	        || |||| |||| |||       LVP = 1 の場合：
;	        || |||| |||| |||        RA3 ピンの機能は MCLR
;	        || |||| |||| |||       LVP = 0 の場合：
;	        || |||| |||| |||        1 = ON:  MCLR ピンは MCLR
;	        || |||| |||| |||    >   0 = OFF: MCLR ピンの機能はポート定義機能
;	        || |||| |||| |||      _____
;	bit1    || |||| |||| ||+----- PWRTE: パワーアップタイマー有効化ビット
;	        || |||| |||| ||     >   1 = OFF: PWRT 無効
;	        || |||| |||| ||         0 = ON:  PWRT 有効
;	        || |||| |||| ||
;	bit3-2  || |||| |||| ++------ WDTE<1:0>: ウォッチドッグタイマー有効ビット
;	        || |||| ||||            11 = ON:     WDT が有効。SWDTEN は無視される
;	        || |||| ||||            10 = SLEEP:  WDT は動作中は有効、スリープ/アイドル時は無効。SWDTEN は無視される
;	        || |||| ||||            01 = SWDTEN: WDT は WDTCON レジスタの SWDTEN ビットによって制御される
;	        || |||| ||||        >   00 = OFF:    WDT は無効。SWDTEN は無視される
;	        || |||| ||||
;	bit4    || |||| |||+--------- 未実装
;	        || |||| |||           _______
;	bit5    || |||| ||+---------- LPBOREN: 低消費電力BOR有効化ビット (PIC16LF18325/18345 devices only)
;	        || |||| ||          >   1 = OFF: ULPBORは無効化
;	        || |||| ||              0 = ON:  ULPBORは有効化
;	        || |||| ||
;	bit7-6  || |||| ++----------- BOREN<1:0>: ブラウンアウトリセット有効化ビット
;	        || ||||                有効化すると、BORVビットによってブラウンアウトリセット電圧 (VBOR) が設定される
;	        || ||||                 11 = ON:     ブラウンアウトリセットが有効になる。SBORENビットは無視される
;	        || ||||                 10 = SLEEP:  ブラウンアウトリセットは動作中有効、スリープ中は無効。SBORENビットは無視される
;	        || ||||                 01 = SBOREN: ブラウンアウトリセットはSBORENビットに従って有効になる
;	        || ||||             >   00 = OFF:    ブラウンアウトリセットは無効になる
;	        || ||||
;	bit8    || |||+-------------- 未実装
;	        || |||
;	bit9    || ||+--------------- BORV: ブラウンアウトリセット電圧選択ビット
;	        || ||               >   1 = LOW:  ブラウンアウトリセット電圧 (VBOR) は LFデバイスでは1.9V、Fデバイスでは2.45Vに設定される
;	        || ||                   0 = HIGH: ブラウンアウトリセット電圧 (VBOR) は 2.7Vに設定される
;	        || ||                   16MHz以上の動作には、高い方の電圧設定が推奨される
;	        || ||
;	bit10   || |+---------------- 未実装
;	        || |
;	bit11   || +----------------- PPS1WAY: PPSLOCK一方向セット有効化ビット
;	        ||                      0 = ON:  PPSLOCKビットは1回のみクリアおよびセットできる。
;	        ||                               PPSレジスタは1回のクリア/セットサイクル後もロックされたまま
;	        ||                  >   1 = OFF: PPSLOCKビットは繰り返しセットおよびクリアできる（ロック解除シーケンスに従う）
;	        ||
;	bit12   |+------------------- STVREN: スタックオーバーフロー/アンダーフローリセット有効化ビット
;	        |                   >   1 = ON:  スタックオーバーフローまたはアンダーフローが発生するとリセットが発生する
;	        |                       0 = OFF: スタックオーバーフローまたはアンダーフローが発生してもリセットは発生しない
;	        |                     _____
;	bit13   +-------------------- DEBUG: デバッガ有効化ビット
;	                            >   1 = OFF: バックグラウンドデバッガ無効。ICSPCLKとICSPDATは汎用I/Oピン
;	                                0 = ON:  バックグラウンドデバッガ有効。ICSPCLKとICSPDATはデバッガ専用
;
; ------------------------------------
; CONFIGURATION WORD 3 (ADDRESS:0009H)		Data Sheet DS40001795K - page 66
; ------------------------------------
;
;     CONFIG3 = 01 1111 1111 1111
;	        || |||| |||| ||||
;	bit1-0  || |||| |||| ||++---- WRT<1:0>: NVM自己書き込み保護ビットの使用
;	        || |||| |||| ||     >   11 = OFF:  書き込み保護オフ
;	        || |||| |||| ||         10 = BOOT: 0000h～01FFh 書き込み保護、0200h～1FFFh は変更可能
;	        || |||| |||| ||         01 = HALF: 0000h～0FFFh 書き込み保護、1000h～1FFFh は変更可能
;	        || |||| |||| ||         00 = ALL:  0000h～1FFFh 書き込み保護、アドレス変更不可
;	        || |||| |||| ||         WRTはデバイスの自己書き込み機能にのみ適用される。ICSP経由の書き込みは保護されない
;	        || |||| |||| ||         
;	bit12-2 |+ ++++ ++++ ++------ 未実装
;	        |
;	bit13   +-------------------- LVP: 低電圧プログラミング有効化ビット
;	                                1 = ON:  低電圧プログラミングが有効。MCLR/VPP ピンの機能は MCLR。
;	                                         MCLR コンフィギュレーションビットは無視される
;	                            >   0 = OFF: MCLR の高電圧/VPP をプログラミングに使用する必要がある
;
; ------------------------------------
; CONFIGURATION WORD 4 (ADDRESS:000AH)		Data Sheet DS40001795K - page 67
; ------------------------------------
;
;     CONFIG4 = 11 1111 1111 1111
;	        || |||| |||| ||||     __
;	bit0    || |||| |||| |||+---- CP:  プログラムメモリコード保護ビット
;	        || |||| |||| |||    >   1 = OFF: プログラムメモリコード保護無効
;	        || |||| |||| |||        0 = ON:  プログラムメモリコード保護有効
;	        || |||| |||| |||      ___
;	bit1    || |||| |||| ||+----- CPD: データEEPROMメモリコード保護ビット
;	        || |||| |||| ||     >   1 = OFF: データ EEPROM コード保護無効
;	        || |||| |||| ||         0 = ON:  データ EEPROM コード保護有効
;	        || |||| |||| ||
;	bit13-2 ++ ++++ ++++ ++------ 未実装

;==========================================================================
;		定数の定義と変数のレジスタ割付け
;==========================================================================

		radix	dec

#define 	ver_no	"1.04"			;バージョン番号

#define 	pagex_wk   end_pagex		;表示ページの退避ワーク
#define 	column_wk  end_column		;表示カラムの退避ワーク

#define 	gl_x	column			;表示カラム / X座標
#define 	gl_y	pagex			;表示ページ / Y座標
#define 	wr_data	pattern			;書き込みデータ

#define 	a08	a16_lo			;割られる数
#define 	b08	b16_lo			;割る数
#define 	x08	x16_lo			;答え
#define 	y08	y16_lo			;余り、ワーク

tm0_h_val	equ	65536 - 25000		;ハードタイマー０カウント値（割り込み周期）
						;4/4Mz*1(Pre)*10(Pos)*25000 = 250 msec

_swRIG		equ	0			;RIGHT スイッチ		;PORTA
_swPRV		equ	0			;PREV. スイッチ
_swUP		equ	1			;UP スイッチ
_swDWN		equ	4			;DOWN スイッチ
_swLEF		equ	5			;LEFT スイッチ
_swNEX		equ	5			;NEXT スイッチ

SCL		equ	0			;I2C-LCD SCL		;PORTC
SDA		equ	1			;I2C-LCD SDA
_BZ		equ	3			;アラーム音 出力
_swSTA		equ	4			;START スイッチ
_swSEL		equ	4			;SELECT スイッチ
_swCAN		equ	5			;CANCEL スイッチ
_swMNT		equ	5			;MAINTE スイッチ

f_do2		equ	65536 -  478		;ド(1046.52 Hz)  at 4MHz
f_rah		equ	65536 -  568		;ラ (880.00 Hz)
f_soh		equ	65536 -  638		;ソ (784.00 Hz)
f_mih		equ	65536 -  758		;ミ (659.26 Hz)
f_doh		equ	65536 -  956		;ド (523.26 Hz)
f_ra		equ	65536 - 1136		;ラ (440.00 Hz)
f_so		equ	65536 - 1276		;ソ (392.00 Hz)
f_mi		equ	65536 - 1517		;ミ (329.63 Hz)
f_do		equ	65536 - 1911		;ド (261.63 Hz)
f_do_		equ	65536 - 3822		;ド (130.82 Hz)
po_tim		equ	100			;音長(ms)
pi_tim		equ	100			;音長
bu_tim		equ	100			;音長
buu_tim		equ	250			;音長

		cblock	h'20'			;バンク 0
cnt_dw_10m					;10M（十分）DOWN カウンタ
cnt_dw_01m					; 1M（分）DOWN カウンタ
cnt_dw_10s					;10S（十秒）DOWN カウンタ
cnt_dw_01s					; 1S（秒）DOWN カウンタ
cnt_up_10m					;10M（十分）UP カウンタ
cnt_up_01m					; 1M（分）UP カウンタ
cnt_up_10s					;10S（十秒）UP カウンタ
cnt_up_01s					; 1S（秒）UP カウンタ
cnt_10m						;10M（十分）DOWN  カウンタ 設定値の退避用
cnt_01m						; 1M（分）DOWN  カウンタ   設定値の退避用
cnt_10s						;10S（十秒）DOWN  カウンタ 設定値の退避用
cnt_01s						; 1S（秒）DOWN  カウンタ   設定値の退避用

count_type					;カウンタ種類
						; 1:Down Counter / 2:Up Counter / 3:Down+Up Counter / (4):Up Counter

sel_flg						;選択フラグ                   ( maintenance 内のとき )
			       			; bit7:                     / 中断表示フラグ
						; bit6:                     / contrast 値変更ありフラグ
						; bit5:                     / 中断表示フラグ
			       			; bit4: 
						; bit3: 10M（十分）カウンタ
						; bit2: 1M（分）カウンタ
						; bit1: 10S（十秒）カウンタ / OLED コントラストフラグ
						; bit0: 1S（秒）カウンタ    / スリープまでの移行時間フラグ
updt_flg					;更新フラグ
						; bit7: １秒更新フラグ
						; bit6: 各項目の表示要求フラグ
						; bit5: タイムアウトフラグ
						; bit4: 状態変化割り込み記憶フラグ
						; bit3: スリープ状態フラグ
						; bit2: スリープ移行時間チェックフラグ
						; bit1: カウンタ/メンテ実行要求フラグ
						; bit0: スイッチ入力有りフラグ / 入力データの有効性チェックフラグ
tcon_flg					;タイミング制御フラグ
						; bit7-4: 0.5秒単位ダウンカウンタ
						; bit3: カウント許可中フラグ
						; bit2: ブリンク制御動作中フラグ / カウント終了フラグ
						; bit1: 0.5秒ブリンクフラグ
						; bit0: 0.25秒経過表示フラグ
alm_flg						;アラーム音出力フラグ
						; bit7: アラーム音出力許可フラグ
						; bit3: 
						; bit2: 
						; bit1: １分経過フラグ
						; bit0: 10秒経過/10秒未満フラグ

slp_cnt_h					;スリープ移行時間カウンタ high
slp_cnt_l					;スリープ移行時間カウンタ low
sleep_time					;スリープまでの移行時間（分）
contrast					;OLED コントラスト
batt_count					;バッテリー電圧 測定間隔時間 / 表示時間カウンタ（秒）

const_high					;音階用分周定数 high の保存
const_low					;音階用分周定数 low の保存
wt1cnt						;ウェイト用ループカウンタ
wt2cnt						;ウェイト用ループカウンタ
wt3cnt						;ウェイト用ループカウンタ
lpcnt1						;ループカウンタ
lpcnt2						;ループカウンタ
work1						;ワーク
work2						;ワーク
work3						;ワーク

contrast_wk					;contrast   の退避ワーク
sleep_time_wk					;sleep_time の退避ワーク
buff						;変換文字列の格納エリア
dumy1						;
dumy2						;

; (I2C_XS.sub で使用)
i2ctmp						;送受信データの一時保存
bit_cnt						;ループカウンタ
;wt1cnt				;既存レジスタ	;ループカウンタ

; (I2C_RTCII.sub で使用)
seconds						;00h: Seconds: 00-59, bit7: CH(Clock Halt)
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:   01-12
year						;06h: Year:    00-99
control						;07h: Control:

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 領域）
ad_res_hi					;
ad_res_lo					;
		endc

		cblock	h'a0'			;バンク 1
a16_hi						;16ビット演算引き数Ａ(上位) 
a16_lo		;a08				;16ビット演算引き数Ａ(下位) 
b16_hi						;16ビット演算引き数Ｂ(上位)
b16_lo		;b08				;16ビット演算引き数Ｂ(下位)
lcnt1						;ループカウンタ / ワーク
lcnt2						;ループカウンタ
x16_hi						;div_16 答えの上位
x16_lo		;x08				;div_16 答えの下位
y16_hi						;div_16 余りの上位
y16_lo		;y08				;div_16 余りの下位
buff0						;変換文字列の格納エリア	;┐
buff1						;			;│
buff2						;			;│順序を変更しないこと!
buff3						;			;│
buff4						;			;┘

save_data_buff					;引継ぎ情報（バックアップデータ）の読み書きバッファ
		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,    -   ,  -  ,   -  ,   -   ,  -  , INTEDG

interrupt
		movlp	high $			;ページ 0
		movlb	0			;バンク 0

		; 割り込み処理の振り分け

		btfsc	PIR0,INTF		;INT 外部割り込みフラグ = 1 か？
		goto	int_int			;Yes

		btfsc	PIR0,TMR0IF		;タイマー０割り込みフラグ = 1 か？
		goto	tm0_int			;Yes

		btfsc	PIR1,TMR1IF		;タイマー１割り込みフラグ = 1 か？
		goto	tm1_int			;Yes

		btfsc	PIR0,IOCIF		;状態変化割り込みフラグ = 1 か？
		goto	ioc_int			;Yes

		goto	int_end			;(Illegal interrupt)

;---------------- 外部(INT)割り込み処理 -------------------------------

int_int		bcf	PIR0,INTF		;外部(INT)割り込みフラグをクリア
		bsf	updt_flg,7		;１秒更新フラグ = 1

		; スリープ移行時間カウンタの更新
		movf	sleep_time,W		;
		btfsc	STATUS,Z		;sleep_time = 0 か？
		goto	inti01			;Yes

		bsf	updt_flg,2	;bit2	;スリープ移行時間チェックフラグ = 1

		decf	slp_cnt_l,F		;slp_cnt_l - 1
		incf	slp_cnt_l,W		;
		btfss	STATUS,Z		;slp_cnt_l - 1 < 0 か？
		goto	inti01			;No

		movf	slp_cnt_h,W		;
		btfss	STATUS,Z		;slp_cnt_h = 0 か？
		decf	slp_cnt_h,F		;No. slp_cnt_h - 1

inti01		goto	int_end

;---------------- タイマー０割り込み処理 ----------------------------------

;	tcon_flg: タイミング制御フラグ
;			      >	bit7-4: 0.5秒単位ダウンカウンタ
;			      > bit3:   カウント許可中フラグ
;			      >	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			      >	bit1:   0.5秒ブリンクフラグ
;			      >	bit0:   0.25秒経過表示フラグ

;		　　│← 250m →│← 250m →│← 250m →│← 250m →│
;		　　┌┐　　　　┌┐　　　　┌┐　　　　┌┐　　　　┌┐	 bit0 のリセット（立下り）は
;	bit0:	　　││　　　　││　　　　││　　　　││　　　　││	プログラム内の手動によるもの
;		──┘└────┘└────┘└────┘└────┘└──

;		　　│←──　500 mS　──→│←──　500 mS　──→│
;		　　┌─────┐　　　　　┌─────┐　　　　　┌───
;	bit1:	　　│　　　　　│　　　　　│　　　　　│　　　　　│　　　　
;		──┘　　　　　└─────┘　　　　　└─────┘　　　　

tm0_int		bcf	PIR0,TMR0IF		;タイマー０割込みフラグをクリア
		movlw	high tm0_h_val		;
		movwf	TMR0H			;
		movlw	low tm0_h_val		;
		movwf	TMR0L			;(4/4Mz) * 1(Pre) * 10(Pos) * 25000 = 250 msec

		; 0.25秒 経過の動作
		bsf	tcon_flg,0	;bit0	;0.25秒経過表示フラグ = 1
		movlw	b'00000010'
		xorwf	tcon_flg,F	;bit1	;0.5秒ブリンクフラグ = 反点

		btfsc	tcon_flg,1		;tcon_flg.1 = 0 か？
		goto	tm0i01			;No

		; 0.5秒 経過の動作
		btfss	tcon_flg,3	;bit3	;カウント許可中フラグ = 1 か？
		goto	tm0i01			;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	tm0i01			;No

		bcf	T0CON0,T0EN		;TMR0 有効化ビット = 0
		clrf	tcon_flg		;
		bsf	tcon_flg,2	;bit2	;カウント終了フラグ = 1

tm0i01		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			;PIR0 レジスタの IOCIF ビットもクリアされる
		movlb	1			;バンク 1
		bcf	PIE0,IOCIE		;状態変化割り込み許可 = 0
		movlb	0			;バンク 0

		bsf	updt_flg,4	;bit4	;状態変化割り込み記憶フラグ = 1
;		goto	int_end

		; 割り込み処理の終了

int_end		retfie				;割り込みからの復帰	

;==========================================================================
;		サブルーチンファイルのインクルード
;==========================================================================

#define 	TRISX	TRISC			;PORTC で I2C を行う場合
#define 	PORTX	PORTC			;
#define 	_not_wait			;Clock = 4MHz のため
#define 	_PIC16F1			;PIC16F1ファミリでする場合に
#define 	_DS1307				;DS1307 を使用する場合に 
#define 	_128x32				;128x32 OLED を使用する場合に 

;				ドライブ、パス名は、各自の開発環境に合わせるように !!

		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	;Ver.1.05 以上が必要

;==========================================================================
;		初期化処理
;==========================================================================

initialize
		clrf	STATUS			;STATUS クリア
	 	clrf	INTCON			;INTCON クリア

		; システムクロックの設定

		movlb	18			;バンク 18
		movlw	b'00000110'	;bit3-0	;HFFRQ<3:0> = b'0110': HFINTOSC Frequency Selection bits; 
						;                      HFINTOSC 周波数選択ビット:   = 16MHz
		movwf	OSCFRQ			;HFINTOSC FREQUENCY SELECTION REGISTER: HFINTOSC周波数選択レジスタ

		movlw	b'01100010'	;bit6-4	;NOSC<2:0>  = b'110':  New Oscillator Source Request bits: 
						;                      新しい発振器ソース要求ビット: = HFINTOSC(1MHz)
					;bit3-0	;NDIV<3:0>  = b'0010': New Divider Selection Request bits: 
						;                      新しい分周器選択要求ビット:   = 4
		movwf	OSCCON1			;OSCILLATOR CONTROL REGISTER 1: 発振器制御レジスタ1

		; 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'01001000'
;			  ||||||||
;		bit0	  |||||||+----- ADON: ADCイネーブルビット
;			  |||||||         1 = ADCを有効
;			  |||||||     >   0 = ADCを無効、消費電流をゼロ
;			  |||||||          ____
;		bit1	  ||||||+------ GO/DONE: A/D変換ステータスビット
;			  ||||||          1 = A/D変換サイクルを実行中、このビットをセットするとA/D変換サイクルが開始
;			  ||||||              このビットは、A/D変換が完了するとハードウェアによって自動的にクリア
;			  ||||||      >   0 = A/D変換サイクルが完了(進行中でない)
;			  ||||||
;		bit7-2	  ++++++------- CHS<5:0>: アナログ チャンネル選択ビット
;			                    :
;			                    :
;			                  010011 = ANC3
;			              >   010010 = ANC2
;			                  010001 = ANC1
;			                    :
;			                  000001 = ANA1
;			                  000000 = ANA0

		movwf	ADCON0			;ADCON0: ADC制御レジスタ0

		movlw	b'11000011'
;			  ||||||||
;		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

		; 割り込みの設定

		movlb	0			;バンク 0
	;;;	movlw	b'00011001'	;bit7	;T0EN         =    0: TMR0 有効化ビット = 無効
		movlw	b'00010100'	;bit7	;T0EN         =    0: TMR0 有効化ビット = 無効
					;bit6	;
					;bit5	;T0OUT        =    0: TMR0 出力 (read-only)
					;bit4	;T016BIT      =    1: TMR0 16ビットタイマー動作選択ビット
					;bit3-0	;T0OUTPS<3:0> = 1001: TMR0 ポストスケーラ 選択ビット = 1:10   -----> 0100=1:5
		movwf	T0CON0			;タイマー0 制御レジスタ0

		movlw	b'01000000'	;bit7-5	;T0CS<2:0>   =  010: FOSC/4
					;bit4	;T0ASYNC     =    0: TMR0 入力非同期化有効化ビット = FOSC/4に同期
					;bit3-0	;T0CKPS<3:0> = 0000: TMR0 プリスケーラ 選択ビット = 1:1
		movwf	T0CON1			;タイマー0 制御レジスタ1

		movlb	1			;バンク 1
		bsf	PIE0,INTE	;bit0	;INTE        = 1: INT外部割り込みを許可
		bsf	PIE0,TMR0IE	;bit5	;TMR0IE      = 1: タイマー０割り込みを許可
		bsf	PIE1,TMR1IE	;bit0	;TMR1IE      = 1: タイマー１割り込みを許可

		movlb	0			;バンク 0
		movlw	b'00000000'	;bit7-6	;TMR1CS<1:0> = 00: Timer1クロック源=命令クロック(FOSC/4)を選択
					;bit5-4	;T1CKPS<1:0> = 00: プリスケーラ値を1:1
					;bit0	;TMR1ON      =  0: Timer1を無効
		movwf	T1CON			;タイマー1 制御レジスタ

		movlw	b'11000001'	;bit7	;GIE    = 1: グローバル割り込みを許可
					;bit6	;PEIE   = 1: ペリフェラル割り込みを許可
					;bit0	;INTEDG = 1: INTピンの立ち上がりエッジで割り込み
		movwf	INTCON			;各割り込み要因の設定

;--------------------------------------------------------------------------

		call	buzzer_pipo		;"ピポッ" ブザー音出力

		; OLED ( SSD1306 ) モジュールの初期設定

		bsf	PORTC,SDA		;SDA="H"
		bsf	PORTC,SCL		;SCL="H"

		call	SSD1306_Init		;OLED ( SSD1306 ) モジュール の初期設定
		call	SSD1306_Clear		;OLED ( SSD1306 ) モジュール の画面消去

		; プログラムタイトルの表示

		movlp	high prog_title_display
		call	prog_title_display
		movlp	high $

		; 引継ぎ情報（バックアップデータ）の読み出し
 
		movlp	high read_eeprom	;EEPROM から 
		call	read_eeprom		;RAM バッファへデータ読み出しと
		movlp	high $			;RAM バッファから個々の変数へもコピー

		movf	contrast,W		;バックアップデータで
		call	SSD1306_Contrast	;OLED ( SSD1306 ) の コントラスト制御
		movf	sleep_time,W		;スリープまでの移行時間（分）
		call	mul8x8_16		;8 x 8 ビット = 16 ビットの乗算

		; I2C RTC（DS1307）モジュールの初期設定

		call	I2cRtc_Init		;07h: Control: bit7:OUT = 0, bit4:SQWE = 1, bit1-0:RS1-0 = 00 ... 1Hz
	;;	call	clock_disable		;RTC モジュールの発振器を無効

		; 各変数の初期設定

		call	wait_1s			;1 秒間のウエイト

		clrf	alm_flg			;
		bsf	alm_flg,7		;アラーム音出力許可フラグ = 1
		clrf	updt_flg		;更新フラグの初期設定
		goto	main

;--------------------------------------------------------------------------
;		RTC（DS1307）モジュールの 発振器を有効／無効
;--------------------------------------------------------------------------

clock_enable		; 有効

		bcf	seconds,7		;00h: Seconds.bit7:CH(Clock Halt) = 0: 発振器を有効
		goto	clock01

clock_disable		; 無効

		bsf	seconds,7		;00h: Seconds.bit7:CH(Clock Halt) = 1: 発振器を無効

clock01		Rtc_Write_M	seconds,1
		return

;==========================================================================
;		メイン・ルーチン（カウンタ種類の選択）
;==========================================================================

;	[スイッチ操作]
;			 CANCEL    LEFT     DOWN      UP      RIGHT    START
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │●│   │●│   │●│   │●│   │●│   │●│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/ MAINTE  / NEXT                    / PREV.  / SELECT

;		 NEXT スイッチ        ..... 選択位置のポインタを + 1
;		PREV. スイッチ        ..... 選択位置のポインタを - 1

;	       SELECT スイッチ        ..... 選択位置のカウンタ機能へ移行

;		   UP スイッチ 長押し ..... UP カウンタ機能へ移行（３秒以上の長押し）

;		 DOWN スイッチ 長押し ..... DOWN カウンタ機能へ移行（３秒以上の長押し）

;		 DOWN スイッチ 長押し +
;		   UP スイッチ        ..... Down + Up カウンタ機能へ移行（３秒以上の長押し）

;	       MAINTE スイッチ 長押し ..... メンテナンス機能に移行（３秒以上の長押し）

;	updt_flg: 更新フラグ
;			       	bit7: １秒更新フラグ
;			       	bit6: 中断表示フラグ
;				bit5: タイムアウトフラグ
;				bit4: 状態変化割り込み記憶フラグ
;			       	bit3: スリープ状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;			       	bit1: カウンタ/メンテ実行要求フラグ
;			       	bit0: スイッチ入力有りフラグ

;	sel_flg: 選択フラグ	                            ( maintenance 内のとき )
;			       	bit7:                     / 中断表示フラグ
;				bit6:                     / contrast 値変更ありフラグ
;				bit5:                     / 中断表示フラグ
;			       	bit4: 
;				bit3: 10M（十分）カウンタ
;			       	bit2:  1M（分）カウンタ
;			       	bit1: 10S（十秒）カウンタ / OLED コントラストフラグ
;			       	bit0:  1S（秒）カウンタ   / スリープまでの移行時間フラグ

;	tcon_flg: タイミング制御フラグ
;			       	bit7-4: 0.5秒単位ダウンカウンタ
;			       	bit3:   カウント許可中フラグ
;			       	bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;				bit1:   0.5秒ブリンクフラグ
;				bit0:   0.25秒経過表示フラグ

main
	;;	call	clock_enable		;RTC モジュールの発振器を有効

		; タイミング制御の初期設定

main01		clrf	tcon_flg
		call	timer_250ms_set		;タイマー０の基本設定

		; カウンタ種類の選択メッセージの表示

		call	SSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去
		call	counter_type_display	;カウンタ種類の選択メッセージの表示

		;	 "Counter Select ? _"
		;	 "1. Down"
		;	 "2. Up"
		;	 "3. Down + Up"

		btfss	updt_flg,3		;スリープ状態フラグ = 1 か？
		call	buzzer_pipi		;No. "ピピッ" ブザー音出力
		bcf	updt_flg,3	;; ↓	;スリープ状態フラグ = 0
		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1

main02		btfsc	updt_flg,0		;スイッチ入力有りフラグ = 1 か？
		call	select_no_reverse	;Yes. 選択カウンタの種類番号の反転表示
		call	select_no_blink		;選択カウンタの種類番号のブリンク表示
		bcf	updt_flg,0		;スイッチ入力有りフラグ = 0

		; 各スイッチの入力チェック

		btfss	PORTA,_swNEX		;NEXT スイッチ = ON か？
		call	main_next_switch	;Yes. NEXT スイッチの処理

		btfss	PORTA,_swPRV		;PREV. スイッチ = ON か？
		call	main_prev_switch	;Yes. PREV. スイッチの処理

		btfss	PORTC,_swSEL		;SELECT スイッチ = ON か？
		call	main_select_switch	;Yes. SELECT スイッチの処理

		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		call	main_up_switch		;Yes. UP スイッチの処理

		btfss	PORTA,_swDWN		;DOWN スイッチ = ON か？
		call	main_down_switch	;Yes. DOWN スイッチの処理

		btfsc	updt_flg,0		;スイッチ入力有りフラグ = 1 か？
		goto	main04			;Yes

		btfss	updt_flg,1		;カウンタ/メンテ実行要求フラグ = 1 か？
		goto	main03			;No

		call	counter_display	      ;;;各カウンタ Down/Up/Down+Up Counter の処理
		goto	main04

main03		btfss	PORTC,_swMNT		;MAINTE スイッチ = ON か？
		call	main_mainte_switch	;Yes. MAINTE スイッチの処理

		btfsc	updt_flg,0		;スイッチ入力有りフラグ = 1 か？
		goto	main04			;Yes

		btfss	updt_flg,1		;カウンタ/メンテ実行要求フラグ = 1 か？
		goto	main05			;No

		movlp	high maintenance
		call	maintenance	      ;;;メンテナンス機能の処理
		movlp	high $

		; スリープ移行時間カウンタ（slp_cnt_h:slp_cnt_l）の初期設定

main04		movf	sleep_time,W		;スリープまでの移行時間（分）
		call	mul8x8_16		;8 x 8 ビット = 16 ビットの乗算

		btfss	updt_flg,1		;カウンタ/メンテ実行要求フラグ = 1 か？
		goto	main02			;No

		bcf	updt_flg,1		;カウンタ/メンテ実行要求フラグ = 0
		goto	main01

		; スリープ移行時間の監視（60 x sleep_time 秒）

main05		call	sleep_control		;時間の監視とスリープモードに移行
		btfss	updt_flg,3		;スリープ状態フラグ = 1 か？
		goto	main02			;No

	;;	bcf	updt_flg,3	;; ↑	;スリープ状態フラグ = 0
		goto	main01			;（"ピピッ" ブザー音の出力抑止後にクリアする）

;--------------------------------------------------------------------------
;		カウンタ種類の選択メッセージの表示
;--------------------------------------------------------------------------

counter_type_display

		clrf	echr_flg		;表示文字の機能拡張フラグ = クリア
		OLED_FontPos_M	4+6*1,0
		OLED_DispStr_M	count_select,1	;"Counter Select ? _"

		OLED_FontPos_M	4+6*2,1
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		OLED_DispStr_M	,0		;"1. Down"

		OLED_FontPos_M	4+6*2,2
		OLED_DispStr_M	,0		;"2. Up"

		OLED_FontPos_M	4+6*2,3
		OLED_DispStr_M	,0		;"3. Down + Up"
		return

count_select	dt	 "Counter Select ? _",0
		dt	 "1. Down",0
		dt	 "2. Up",0
		dt	 "3. Down + Up",0
;			 01234567890123456789

;--------------------------------------------------------------------------
;		選択カウンタの種類番号の反転表示
;--------------------------------------------------------------------------

select_no_reverse
		movlw	4+6*2-1			;
		movwf	gl_x			;X座標
		movlw	3			;
		movwf	gl_y			;Y座標, ループカウンタ

		movlw	h'40'			;h'40': ビットずらし指示
		movwf	echr_flg		;

snrev01		call	SSD1306_FontPos		;表示開始位置指定
		call	rev_shift_byte		;データ１バイト出力

		movf	gl_y,W			;
		iorlw	h'30'			;数字に変換
		call	SSD1306_DispChr		;OLED へ１文字出力
		movlw	a'.'
		call	SSD1306_DispChr		;OLED へ１文字出力

		decfsz	gl_y,F			;ループカウンタ - 1 = 0 か？
		goto	snrev01			;No
;
		movf	count_type,W		;カウンタ種類
		movwf	gl_y
		call	SSD1306_FontPos		;表示開始位置指定
		movlw	h'c0'			;h'c0': ビット反転表示とビットずらし指示
		movwf	echr_flg		;
		call	rev_shift_byte		;データ１バイト出力

		movf	count_type,W		;カウンタ種類
		iorlw	h'30'			;数字に変換
		call	SSD1306_DispChr		;OLED へ１文字出力
		movlw	a'.'
		call	SSD1306_DispChr		;OLED へ１文字出力
		return

;--------------------------------------------------------------------------
;		選択カウンタの種類番号のブリンク表示
;--------------------------------------------------------------------------

select_no_blink
		btfss	tcon_flg,0		;0.25秒経過表示フラグ = 1 か？
		goto	snblk01			;No

		bcf	tcon_flg,0		;0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		btfsc	tcon_flg,1		;0.5秒ブリンクフラグ = 1 か？
		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1

		OLED_FontPos_M	4+6*18-1,0

		bcf	echr_flg,6		;ビットずらし指示 = 0	;(Ver.1.01)
		call	rev_shift_byte		;データ１バイト出力
		movf	count_type,W		;カウンタ種類
		iorlw	h'30'			;数字に変換
		call	SSD1306_DispChr		;OLED へ１文字出力

snblk01		return

;--------------------------------------------------------------------------
;		"Go!" 文字列の表示
;--------------------------------------------------------------------------

go_str_display
		clrf	tcon_flg		;タイミング制御フラグをクリア

		movlw	4+6*16-1		;
		movwf	gl_x			;X座標
		movf	count_type,W		;カウンタ種類
		movwf	gl_y			;Y座標
		call	SSD1306_FontPos		;表示開始位置指定

go_str_disp
		movlw	h'c0'			;h'c0': ビット反転表示とビットずらし指示
		movwf	echr_flg		;
		call	rev_shift_byte		;データ１バイト出力

		OLED_DispStr_M	go_str,1	;"Go!" 文字列の表示

		call	buzzer_pi		;"ピッ" ブザー音
		return

go_str		dt	"Go!",0

;--------------------------------------------------------------------------
;		" Maintenance " + "Go!" 文字列の表示
;--------------------------------------------------------------------------

Maintenance_go_display

		movlw	3
		movwf	lpcnt1			;ループカウンタ1

mntgo01		movf	lpcnt1,W		;Y座標
		call	line_clear		;１行単位で画面消去

		decfsz	lpcnt1,F		;ループカウンタ1 - 1 = 0 か？
		goto	mntgo01			;No
;
		OLED_FontPos_M	4+6*1,3		;
		movlw	h'c0'			;h'c0': ビット反転表示とビットずらし指示
		movwf	echr_flg		;
		call	rev_shift_byte		;データ１バイト出力
		OLED_DispStr_M	mainte_go_str,1	;" Maintenance " の表示
;
		movlw	6*15-1
		addwf	gl_x,F			;X座標の更新
		call	SSD1306_FontPos		;表示開始位置指定

		call	go_str_disp		;"Go!" 文字列の表示 (go_str_display 内)
		return

mainte_go_str	dt	" Maintenance ",0

;--------------------------------------------------------------------------
;		１行単位で画面消去
;--------------------------------------------------------------------------

;	入力:	W reg:		Y座標

line_clear
		movwf	gl_y			;Y座標
		clrf	gl_x			;X座標 = 0
		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 バイト送信

		movlw	128
		movwf	oled_lpcnt		;ループカウンタ

lclr01		clrw				;h'00'
		call	i2c_byte_send		;1 バイト送信

		decfsz	oled_lpcnt,F		;ループカウンタ - 1 = 0 か？
		goto	lclr01			;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

;--------------------------------------------------------------------------
;	３秒間タイマーの設定 = (250 msec * 2 = 500 msec) * 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

		; タイマー０カウントレジスタの基本設定

timer_250ms_set
		movlw	high tm0_h_val		;(4/4Mz) * 1(Pre) * 10(Pos) * 25000 = 250 msec
		movwf	TMR0H			;
		movlw	low tm0_h_val		;
		movwf	TMR0L			;

		bsf	T0CON0,T0EN		;TMR0 有効化ビット = 1
		return

;==========================================================================
;	  メイン・ルーチン（カウンタ種類の選択）内のスイッチ処理
;==========================================================================
;--------------------------------------------------------------------------
;		NEXT スイッチの処理 ... メイン・ルーチンから CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		NEXT スイッチ        ..... 選択位置のポインタを + 1

;	count_type: カウンタ種類 = 1:Down Counter / 2:Up Counter / 3:Down+Up Counter

main_next_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swNEX		;再度 NEXT スイッチ = ON か？
		goto	nexsw01			;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1

		incf	count_type,F		;カウンタ種類の +1 更新
		movlw	h'04'
		subwf	count_type,W		;
		movlw	h'01'
		btfsc	STATUS,C		;count_type >= 4 か？
		movwf	count_type		;Yes. count_type = 1

		btfss	PORTA,_swNEX		;NEXT スイッチ = OFF か？
		goto	$ - 1			;No

nexsw01		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		PREV. スイッチの処理 ... メイン・ルーチンから CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		PREV. スイッチ        ..... 選択位置のポインタを - 1

;	count_type: カウンタ種類 = 1:Down Counter / 2:Up Counter / 3:Down+Up Counter

main_prev_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swPRV		;再度 PREV. スイッチ = ON か？
		goto	prvsw01			;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1

		decf	count_type,F		;カウンタ種類の -1 更新
		movlw	h'03'
		btfsc	STATUS,Z		;count_type = 0 か？
		movwf	count_type		;Yes. count_type = 3

		btfss	PORTA,_swPRV		;PREV. スイッチ = OFF か？
		goto	$ - 1			;No

prvsw01		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		SELECT スイッチの処理 ... メイン・ルーチンから CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;	       SELECT スイッチ        ..... 選択位置のカウンタ機能へ移行

main_select_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTC,_swSEL		;再度 SELECT スイッチ = ON か？
		goto	selsw01			;No

;		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1
		bsf	updt_flg,1		;カウンタ実行要求フラグ = 1

		btfss	PORTC,_swSEL		;SELECT スイッチ = OFF か？
		goto	$ - 1			;No

selsw01		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		UP スイッチの処理 ... メイン・ルーチンから CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		   UP スイッチ 長押し ..... UP カウンタ機能へ移行（３秒以上の長押し）

main_up_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swUP		;再度 UP スイッチ = ON か？
		goto	upsw04			;No

		; ３秒間長押しの監視 = (250 msec * 2 = 500 msec) * 6 = 3,000 ms
		call	timer_3sec_set		;３秒間タイマーの設定

upsw01		call	select_no_blink		;選択カウンタの種類番号のブリンク表示

		btfsc	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	upsw02			;Yes

		btfss	PORTA,_swUP		;UP スイッチ = OFF か？
		goto	upsw01			;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1
		bcf	tcon_flg,3		;カウント許可中フラグ = 0, カウント中断
		goto	upsw03			;無視

upsw02		bsf	updt_flg,1		;カウンタ実行要求フラグ = 1
		movlw	h'02'
		movwf	count_type		;count_type = 2

		call	select_no_blink		;選択カウンタの種類番号のブリンク表示
		call	select_no_reverse	;選択カウンタの種類番号の反転表示
		call	go_str_display		;"Go!" 文字列の表示

upsw03		btfss	PORTA,_swUP		;UP スイッチ = OFF か？
		goto	$ - 1			;No

upsw04		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		DOWN スイッチの処理 ... メイン・ルーチンから CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		 DOWN スイッチ 長押し ..... DOWN カウンタ機能へ移行（３秒以上の長押し）

;		 DOWN スイッチ 長押し +
;		   UP スイッチ        ..... Down + Up カウンタ機能へ移行（３秒以上の長押し）

main_down_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swDWN		;再度 DOWN スイッチ = ON か？
		goto	dwnsw04			;No

		; ３秒間長押しの監視 = (250 msec * 2 = 500 msec) * 6 = 3,000 ms
		call	timer_3sec_set		;３秒間タイマーの設定

dwnsw01		call	select_no_blink		;選択カウンタの種類番号のブリンク表示

		btfsc	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	dwnsw02			;Yes

		btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
		goto	dwnsw01			;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1
		bcf	tcon_flg,3		;カウント許可中フラグ = 0, カウント中断
		goto	dwnsw03			;無視

dwnsw02		bsf	updt_flg,1		;カウンタ実行要求フラグ = 1
		movlw	h'01'
		movwf	count_type		;count_type = 1

		movlw	h'03'
		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		movwf	count_type		;Yes. count_type = 3

		call	select_no_blink		;選択カウンタの種類番号のブリンク表示
		call	select_no_reverse	;選択カウンタの種類番号の反転表示
		call	go_str_display		;"Go!" 文字列の表示

dwnsw03		comf	PORTA,W			;全ビットを反転
		andlw	h'12'
		btfss	STATUS,Z		;DOWN スイッチ and UP スイッチ = OFF か？
		goto	dwnsw03			;No

dwnsw04		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		MAINTE スイッチの処理 ... メイン・ルーチンから CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;	       MAINTE スイッチ 長押し ..... メンテナンス機能に移行（３秒以上の長押し）

main_mainte_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTC,_swMNT		;再度 MAINTE スイッチ = ON か？
		goto	mntsw04			;No

		; ３秒間長押しの監視 = (250 msec * 2 = 500 msec) * 6 = 3,000 ms
		call	timer_3sec_set		;３秒間タイマーの設定

mntsw01		call	select_no_blink		;選択カウンタの種類番号のブリンク表示

		btfsc	tcon_flg,2		;カウント終了フラグ = 1 か？
		goto	mntsw02			;Yes

		btfss	PORTC,_swMNT		;MAINTE スイッチ = OFF か？
		goto	mntsw01			;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1
		bcf	tcon_flg,3		;カウント許可中フラグ = 0, カウント中断
		goto	mntsw03			;無視

mntsw02		bsf	updt_flg,1		;カウンタ実行要求フラグ = 1
		call	Maintenance_go_display	;" Maintenance " + "Go!" 文字列の表示

mntsw03		btfss	PORTC,_swMNT		;MAINTE スイッチ = OFF か？
		goto	$ - 1			;No

mntsw04		call	wait_15ms		;チャッタリング吸収
		return

;==========================================================================
;		各カウンタ Down/Up/Down+Up Counter の表示
;==========================================================================

;	[スイッチ操作]
;			 CANCEL    LEFT     DOWN      UP      RIGHT    START
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │●│   │●│   │●│   │●│   │●│   │●│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/ MAINTE  / NEXT                    / PREV.  / SELECT

;		RIGHT スイッチ        ..... 選択位置のポインタを + 1
;		 LEFT スイッチ        ..... 選択位置のポインタを - 1

;		   UP スイッチ        ..... ブリンク位置の値を + 1
;		 DOWN スイッチ        ..... ブリンク位置の値を - 1

;		START スイッチ        ..... 各カウンタ動作を実行する

;	       CANCEL スイッチ        ..... カウンタ動作を実行中に押すと動作を中止する
;		                            カウンタ動作を実行前に押すと「カウンタ種類の選択」に戻る

;	updt_flg: 更新フラグ
;			       	bit7: １秒更新フラグ
;			       	bit6: 各項目の表示要求フラグ
;				bit5: タイムアウトフラグ
;				bit4: 状態変化割り込み記憶フラグ
;			       	bit3: スリープ状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;			       	bit1: カウンタ/メンテ実行要求フラグ
;			       	bit0: スイッチ入力有りフラグ / 有効性チェックフラグ

counter_display

		; タイミング制御の初期設定

		clrf	tcon_flg
		call	timer_250ms_set		;タイマー０の基本設定

		; 各種変数の初期設定

cdsp01		call	SSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去
		call	buzzer_pipi		;"ピピッ" ブザー音出力

		clrf	sel_flg
		bsf	sel_flg,3		;sel_flg = bit3:10M
		clrf	batt_count		;バッテリー電圧測定間隔時間カウンタ（秒）の初期設定

		btfss	count_type,0		;count_type = 2:Up Counter か？
		goto	cdsp02			;Yes

		; count_type = 1, 3 のとき
		movlw	high (save_data_buff+3)	;引継ぎ情報（バックアップデータ）の先頭アドレス + 3
		movwf	FSR1H			;
		movlw	low (save_data_buff+3)	;
		movwf	FSR1L			;間接アドレスに設定
		movlp	high dwn_cnt_read	;(ram_buff_read 内)
		call	dwn_cnt_read		;cnt_dw_10m, cnt_dw_01m, cnt_dw_10s, cnt_dw_01s の読み出し
		movlp	high $

		btfss	count_type,1		;count_type = 1:Down Counter か？
		goto	cdsp03			;Yes

		; count_type = 2, 3 のとき
cdsp02		clrf	cnt_up_10m		;10M（十分）UP カウンタ
		clrf	cnt_up_01m		; 1M（分）UP カウンタ
		clrf	cnt_up_10s		;10S（十秒）UP カウンタ
		clrf	cnt_up_01s		; 1S（秒）UP カウンタ

		; スクリーン画面の初期表示

cdsp03		call	counter_name_display	;カウンタ名（"Xx Counter"）の表示
		call	guide_number_display	;ガイド数字（０～５）の表示
		call	battery_volt_display	;バッテリーの電圧測定と表示

		movlw	3
		subwf	count_type,W
		btfsc	STATUS,Z		;count_type = 3 か？
		call	mm_ss_display		;Yes. Up Counter の NORMAL 文字表示

		; スリープ移行時間カウンタ（slp_cnt_h:slp_cnt_l）の初期設定

cdsp04		movf	sleep_time,W		;スリープまでの移行時間（分）
		call	mul8x8_16		;8 x 8 ビット = 16 ビットの乗算

		; バーグラフと 分秒 (mm:ss) の LARGE 文字の表示と更新

		call	bar_initial_graph_display ;バーグラフの初期表示
		call	mm_ss_display_lg	;分秒 (mm:ss) の LARGE 文字表示

cdsp05		btfss	count_type,0		;count_type = 2:Up Counter か？
		goto	cdsp06			;Yes

		call	mm_ss_display_blk_lg	;選択文字のブリンク表示
		bcf	updt_flg,0		;スイッチ入力有りフラグ = 0

		; 各スイッチの入力チェック（タイマー分秒の設定）

; updt_flg.bit0:    _swRIG, _swLEF, _swUP, _swDWN  ... スイッチ入力有りフラグ
;		    _swSTA			   ... 有効性チェックフラグ

		btfss	PORTA,_swRIG		;RIGHT スイッチ = ON か？
		call	cnt_right_switch	;Yes. RIGHT スイッチの処理

		btfss	PORTA,_swLEF		;LEFT スイッチ = ON か？
		call	cnt_left_switch		;Yes. LEFT スイッチの処理

		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		call	cnt_up_switch		;Yes. UP スイッチの処理

		btfss	PORTA,_swDWN		;DOWN スイッチ = ON か？
		call	cnt_down_switch		;Yes. DOWN スイッチの処理

		btfsc	updt_flg,0		;スイッチ入力有りフラグ = 1 か？
		goto	cdsp04			;Yes

cdsp06		btfss	PORTC,_swSTA		;START スイッチ = ON か？
		call	cnt_start_switch	;Yes. START スイッチの処理

		btfsc	updt_flg,0		;有効性チェックフラグ = 1: Ok か？
		goto	cdsp07			;Yes			;(Ver.1.03) call cdsp07 間違い
;;
;;	(Ver.1.03) bugfix
;;	この counter_display サブルーチン内で、START スイッチにより何度もカウンタ動作を繰り返す、とシステムが
;;	リセットされる症状が現れる。（スタックメモリがオーバーフローする。STKPTR レジスタの内容を表示して確認）
;;	原因： goto を間違って call としていた。 コピー間違い？と思われる。

		btfss	PORTC,_swCAN		;CANCEL スイッチ = ON か？
		goto	cdsp0z			;Yes

		; スリープ移行時間の監視（60 x sleep_time 秒）

		call	sleep_control		;時間の監視とスリープモードに移行
		btfss	updt_flg,3		;スリープ状態フラグ = 1 か？
		goto	cdsp05			;No

		bcf	updt_flg,3		;スリープ状態フラグ = 0
		goto	cdsp04			;

		; 各カウンタの動作開始の準備

cdsp07		bcf	updt_flg,0		;有効性チェックフラグ = 0
		call	buzzer_pipi		;"ピピッ" ブザー音出力
		bcf	updt_flg,7	;;	;１秒更新フラグ = 0

; ---------------------- 以下、各カウンタの表示と更新 繰り返し ----------------------

; count_type:		bit2	bit1	bit0
;		= 1:	  0	  0	  1	;down
;		= 2:	  0	  1	  0	;up
;		= 3:	  0	  1	  1	;down + up
;	      (	= 4: )	  1	  0	  0	;up

cdsp08		btfss	updt_flg,7		;１秒更新フラグ = 1 か？
		goto	cdsp15			;No

		bcf	updt_flg,7		;１秒更新フラグ = 0
		btfss	count_type,0		;count_type = 1,3 か？
		goto	cdsp10			;No. count_type = 2,(4)

	; count_type = 1,3 のとき

		call	clock_count_down      ;;;タイマー・カウントダウン
		call	bar_update_graph_display ;バーグラフの更新表示

		movf	cnt_dw_01s,W
		btfsc	STATUS,Z		;cnt_dw_01s = 0 か？
		bsf	alm_flg,0		;Yes. 10秒経過フラグ = 1
		iorwf	cnt_dw_10s,W
		btfsc	STATUS,Z		;cnt_dw_10s = cnt_dw_01s = 0 か？
		bsf	alm_flg,1		;Yes. １分経過フラグ = 1

		movf	cnt_dw_10m,W		;残り 10秒未満のチェック
		iorwf	cnt_dw_01m,W
		iorwf	cnt_dw_10s,W
		btfsc	STATUS,Z		;cnt_dw_10m = cnt_dw_01m = cnt_dw_10s = 0 か？
		bsf	alm_flg,0		;Yes. 10秒未満フラグ = 1

		movlw	5
		subwf	cnt_dw_10s,W
		btfss	STATUS,Z		;cnt_dw_10s = 5 か？
		goto	cdsp09			;No

		movlw	9
		subwf	cnt_dw_01s,W
		btfsc	STATUS,Z		;cnt_dw_01s = 9 か？
		call	bar_initial_graph_display ;Yes. バーグラフの初期表示

cdsp09		btfss	count_type,1		;bit1 = 0: count_type = 1 か？
		goto	cdsp12			;Yes

	; count_type = 2,3,(4) のとき

cdsp10		call	clock_count_up	      ;;;ストップウオッチ・カウントアップ

		btfss	count_type,0		;count_type = 3 か？
		goto	cdsp11			;No

		call	mm_ss_display		;Up Counter の NORMAL 文字表示
		goto	cdsp12

cdsp11		call	bar_update_graph_display ;バーグラフの更新表示

		movf	cnt_up_01s,W
		btfsc	STATUS,Z		;cnt_up_01s = 0 か？
		bsf	alm_flg,0		;Yes. 10秒経過フラグ = 1
		iorwf	cnt_up_10s,W
		btfsc	STATUS,Z		;cnt_up_10s = cnt_up_01s = 0 か？
		bsf	alm_flg,1		;Yes. １分経過フラグ = 1

		btfsc	STATUS,Z		;再度 cnt_up_10s = cnt_up_01s = 0 か？
		call	bar_initial_graph_display ;Yes. バーグラフの初期表示

	; count_type = 1,2,3,(4) すべて

cdsp12		call	mm_ss_display_lg	;分秒 (mm:ss) の LARGE 文字表示

		btfsc	updt_flg,5		;タイムアウトフラグ = 1 か？
		goto	cdsp16			;Yes

		; アラーム音の出力

		btfss	alm_flg,1		;１分経過フラグ = 1 か？
		goto	cdsp13			;No

		call	buzzer_pupu		;Yes. "ププッ" ブザー音出力 (230 mS)
		bcf	alm_flg,1		;１分経過フラグ = 0
		bcf	alm_flg,0		;10秒経過フラグ = 0

cdsp13		btfsc	alm_flg,0		;10秒経過/10秒未満フラグ = 1 か？
		call	buzzer_pu		;Yes. "プッ" ブザー音出力 (100 mS)
		bcf	alm_flg,0		;10秒経過フラグ = 0

		; バッテリーの電圧測定と表示

cdsp14		incf	batt_count,F		;バッテリー電圧測定間隔時間カウンタ + 1
		movlw	5
		subwf	batt_count,W
		btfss	STATUS,Z		;バッテリー電圧測定間隔時間カウンタ = 5 か？
		goto	cdsp15			;No

		call	battery_volt2_display	;バッテリーの電圧測定と表示
		clrf	batt_count		;バッテリー電圧測定間隔時間カウンタ = 0

cdsp15		btfsc	PORTC,_swCAN		;CANCEL スイッチ = ON か？
		goto	cdsp08			;No

; ---------------------- 以上、各カウンタの表示と更新 繰り返し ----------------------

		call	wait_15ms		;チャッタリング吸収	;(Ver.1.02) wwait_15ms 間違い
		btfss	PORTC,_swCAN		;CANCEL スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収	;(Ver.1.02) wwait_15ms 間違い
		goto	cdsp23
;;
;; ↓	(Ver.1.02) bugfix
;;	下のサブルーチンを実行（cdsp24　call　stop_msg_display　;カウンタストップメッセージの出力）
;;	したときに "Counter Stop ! x" メッセージの右端 x が、ときどきブリンクしなくなる症状が現れる。
;;	原因： wait_15ms を間違って wwait_15ms としていた。 コピー間違い？と思われる。

		; タイムアウトしたとき（count_type = 1,3 のとき）

cdsp16		movlw	3
		movwf	lpcnt2			;ループカウンタ
		clrf	cnt_up_01s		;cnt_up_01s = 0

cdsp17		call	buzzer_pipipi		;"ピピピッ" ブザー音 (360 mS)
		btfss	updt_flg,7		;１秒更新フラグ = 1 か？
		goto	cdsp18			;No

		incf	cnt_up_01s,F		;cnt_up_01s + 1
		bcf	updt_flg,7		;１秒更新フラグ = 0

cdsp18		call	wait_500ms		;500m 秒 ウェイト
		btfss	updt_flg,7		;１秒更新フラグ = 1 か？
		goto	cdsp19			;No

		incf	cnt_up_01s,F		;cnt_up_01s + 1
		bcf	updt_flg,7		;１秒更新フラグ = 0

cdsp19		decfsz	lpcnt2,F		;ループカウンタ - 1 = 0 か？
		goto	cdsp17			;No

		movf	cnt_10m,W		;設定値の復帰
		movwf	cnt_dw_10m
		movf	cnt_01m,W		;
		movwf	cnt_dw_01m
		movf	cnt_10s,W		;
		movwf	cnt_dw_10s
		movf	cnt_01s,W		;
		movwf	cnt_dw_01s

		; 重複データのチェック
		movlw	high (save_data_buff+3)	;引継ぎ情報（バックアップデータ）の先頭アドレス + 3
		movwf	FSR1H			;
		movlw	low (save_data_buff+3)	;
		movwf	FSR1L			;間接アドレスに設定

		moviw	FSR1++			;
		subwf	cnt_dw_10m,W
		btfss	STATUS,Z		;cnt_dw_10m = INDF1 か？
		goto	cdsp20			;No

		moviw	FSR1++			;
		subwf	cnt_dw_01m,W
		btfss	STATUS,Z		;cnt_dw_01m = INDF1 か？
		goto	cdsp20			;No

		moviw	FSR1++			;
		subwf	cnt_dw_10s,W
		btfss	STATUS,Z		;cnt_dw_10s = INDF1 か？
		goto	cdsp20			;No

		moviw	FSR1++			;
		subwf	cnt_dw_01s,W
		btfsc	STATUS,Z		;cnt_dw_01s = INDF1 か？
		goto	cdsp21			;Yes

		; 重複データのチェック OK のとき
cdsp20		movlp	high write_eeprom
		call	write_eeprom		;バックアップデータを EEPROM へ書き込み
		movlp	high $

cdsp21		movlw	h'80'			;
		andwf	alm_flg,F		;アラーム音出力許可フラグ
		bcf	updt_flg,5		;タイムアウトフラグ = 0
		btfsc	count_type,1		;count_type = 1 か？
		goto	cdsp22			;No

		call	wait_500ms		;500m 秒 ウェイト
		goto	cdsp24			;終了

cdsp22		clrf	cnt_up_10m		;10M（十分）UP カウンタ
		clrf	cnt_up_01m		; 1M（分）UP カウンタ
		clrf	cnt_up_10s		;10S（十秒）UP カウンタ

		movf	cnt_up_01s,W		; 1S（秒）UP カウンタ
		movwf	cnt_dw_01s		; 1S（秒）DOWN カウンタ
		call	bar_initial_graph_display ;バーグラフの初期表示

		incf	count_type,F		;count_type = (4) に更新
		call	mm_ss_display_lg	;分秒 (mm:ss) の LARGE 文字表示
		goto	cdsp14	;cdsp08

		; CANCEL スイッチ = ON の処理

cdsp23		btfsc	count_type,2		;count_type = (4) か？
		decf	count_type,F		;Yes. count_type = 3 に戻す

		bsf	updt_flg,6		;中断表示フラグ = 1

		; カウンタストップメッセージの出力と応答
;; ↑
cdsp24		call	stop_msg_display	;カウンタストップメッセージの出力
		bcf	updt_flg,6		;中断表示フラグ = 0
		goto	cdsp01

cdsp0z		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		カウンタ名（"Xx Counter"）の表示
;--------------------------------------------------------------------------

counter_name_display

		clrf	echr_flg		;表示文字の機能拡張フラグ = クリア
		movlw	69			;
		movwf	gl_x			;gl_x
		clrf	gl_y			;gl_y = 0
		call	SSD1306_FontPos		;表示開始位置の指定

		movlw	3
		subwf	count_type,W
		btfss	STATUS,Z		;count_type = 3 か？
		goto	cname01			;No

		movlw	a'+'			;
		call	SSD1306_DispChr		;OLED へ１文字出力

		movlw	77			;
		movwf	gl_x			;gl_x
		call	SSD1306_FontPos		;表示開始位置の指定

cname01		decf	count_type,W		;
		movlw	a'D'			;
		btfss	STATUS,Z		;count_type = 1 か？
		movlw	a'U'			;No
		call	SSD1306_DispChr		;OLED へ１文字出力

		decf	count_type,W		;
		movlw	a'w'			;
		btfss	STATUS,Z		;count_type = 1 か？
		movlw	a'p'			;No
		call	SSD1306_DispChr		;OLED へ１文字出力

		movlw	3
		subwf	count_type,W
		btfsc	STATUS,Z		;count_type = 3 か？
		goto	cname02			;Yes

		movlw	14
		addwf	gl_x,F			;83
		call	SSD1306_FontPos		;表示開始位置の指定

		OLED_DispStr_M	count_str,1	;"Counter" 文字列の表示

cname02		return

count_str	dt	 "Counter",0
		dt	 " Stop !",0

;count_type =	1	01	69	Dw
;		2	10	69	Up
;		3	11	77	Up

;--------------------------------------------------------------------------
;		分秒 (mm:ss) Down/Up Counter の LARGE 文字表示
;--------------------------------------------------------------------------

mm_ss_display_lg

		clrf	echr_flg		;表示文字の機能拡張フラグ = クリア

		; 分 (mm:) の表示
		OLED_FontPos_M	3+12*0,0	;表示開始位置の指定

		movf	cnt_dw_10m,W		;10M（十分）DOWN カウンタ
		btfss	count_type,0		;count_type = 1,3 か？
		movf	cnt_up_10m,W		;No. 10M（十分）UP カウンタ
		call	number_disp_lg		;数字へ変換後 LARGE 文字を表示

		movf	cnt_dw_01m,W		;1M（分）DOWN カウンタ
		btfss	count_type,0		;count_type = 1,3 か？
		movf	cnt_up_01m,W		;No. 1M（分）UP カウンタ
		call	number_disp_lg		;数字へ変換後 LARGE 文字を表示

		movlw	a':'
		call	symbol_disp_lg		;LARGE 文字を表示

		; 秒 (ss) の表示
;		OLED_FontPos_M	3+12*3-1,0	;表示開始位置の指定
		movlw	3+12*3-1		;38
		movwf	gl_x			;
		call	SSD1306_FontPos		;表示開始位置の指定

		movf	cnt_dw_10s,W		;10S（十秒）DOWN カウンタ
		btfss	count_type,0		;count_type = 1,3 か？
		movf	cnt_up_10s,W		;No. 10S（十秒）UP カウンタ
		call	number_disp_lg		;数字へ変換後 LARGE 文字を表示

		movf	cnt_dw_01s,W		;1S（秒）DOWN カウンタ
		btfss	count_type,0		;count_type = 1,3 か？
		movf	cnt_up_01s,W		;No. 1S（秒）UP カウンタ
		call	number_disp_lg		;数字へ変換後 LARGE 文字を表示
		return

;--------------------------------------------------------------------------

;		数値を数字へ変換後 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	SSD1306_DispChr2	;OLED へデータを１文字出力

;		次文字の表示位置に更新

next_position
		decf	gl_y,F			;文字の上位半分の表示位置に戻す
		movlw	12
		addwf	gl_x,F			;カラム位置の更新
		call	SSD1306_FontPos		;次文字の表示位置
		return

;--------------------------------------------------------------------------
;	   分秒 (mm:ss) Down Counter の LARGE 文字のブリンク表示
;--------------------------------------------------------------------------

mm_ss_display_blk_lg

		btfss	tcon_flg,0		;0.25秒経過表示フラグ = 1 か？
		goto	blklg01			;No

		bcf	tcon_flg,0		;0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		btfsc	tcon_flg,1		;0.5秒ブリンクフラグ = 1 か？
		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1

		btfsc	sel_flg,3		;sel_flg = bit3:10M か？
		movlw	3+12*0		; 3	;Yes
		btfsc	sel_flg,2		;sel_flg = bit2: 1M か？
		movlw	3+12*1		;15	;Yes
		btfsc	sel_flg,1		;sel_flg = bit1:10S か？
		movlw	3+12*3-1	;38	;Yes
		btfsc	sel_flg,0		;sel_flg = bit0: 1S か？
		movlw	3+12*4-1	;50	;Yes
		movwf	gl_x			;
		clrf	gl_y		; 0	;
		call	SSD1306_FontPos		;表示開始位置の指定

		btfsc	sel_flg,3		;sel_flg = bit3:10M か？
		movf	cnt_dw_10m,W		;Yes. 10M（十分）DOWN カウンタ
		btfsc	sel_flg,2		;sel_flg = bit2:1M か？
		movf	cnt_dw_01m,W		;Yes. 1M（分）DOWN カウンタ
		btfsc	sel_flg,1		;sel_flg = bit1:10S か？
		movf	cnt_dw_10s,W		;Yes. 10S（十秒）DOWN カウンタ
		btfsc	sel_flg,0		;sel_flg = bit0:1S か？
		movf	cnt_dw_01s,W		;Yes. 1S（秒）DOWN カウンタ

		call	number_disp_lg		;数字へ変換後 LARGE 文字を表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0

blklg01		return

;--------------------------------------------------------------------------
;		分秒 (mm:ss) Up Counter の NORMAL 文字表示
;--------------------------------------------------------------------------

mm_ss_display
		bcf	echr_flg,6		;1 bit 左(下)ずらし指示 = 0

		; 分 (mm:) の表示
		OLED_FontPos_M	77+6*3,0	;表示開始位置の指定
		movf	cnt_up_10m,W		;10M（十分）カウンタ
		call	number_disp		;数字へ変換後 文字を表示
		movf	cnt_up_01m,W		;1M（分）カウンタ
		call	number_disp		;数字へ変換後 文字を表示

		movlw	a':'
		call	SSD1306_DispChr		;OLED へデータを１文字出力

		; 秒 (ss) の表示
		movf	cnt_up_10s,W		;10S（十秒）カウンタ
		call	number_disp		;数字へ変換後 文字を表示
		movf	cnt_up_01s,W		;1S（秒）カウンタ
		call	number_disp		;数字へ変換後 文字を表示
		return

;--------------------------------------------------------------------------

;		数値を数字へ変換後 OLED へ１文字出力

number_disp
;		andlw	h'0f'
		iorlw	h'30'
		call	SSD1306_DispChr		;OLED へデータを１文字出力
		return

;--------------------------------------------------------------------------
;		ガイド数字（０～５）の表示
;--------------------------------------------------------------------------

guide_number_display

		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		movlw	2
		movwf	gl_x
		movlw	3
		movwf	gl_y

		movlw	a'0'			;表示数字の初期値
		movwf	work1

		movlw	6
		movwf	lpcnt2			;ループカウンタ

gnum01		call	SSD1306_FontPos		;表示開始位置指定
		movf	work1,W
		call	SSD1306_DispChr		;OLED へ１文字出力

		incf	work1,F			;表示数字の更新
		movlw	20
		addwf	gl_x,F			;X座標の更新

		decfsz	lpcnt2,F		;ループカウンタ - 1 = 0 か？
		goto	gnum01			;No

		return

;--------------------------------------------------------------------------
;		バーグラフの初期表示
;--------------------------------------------------------------------------

bar_initial_graph_display

		movlw	4
		movwf	gl_x			;X座標
		movlw	2
		movwf	gl_y			;Y座標

		clrf	work1			;表示値の初期値
		btfss	count_type,0		;カウンタ種別 = 1,3 か？
		goto	binit03			;No

		; cnt_dw_01s + (10 * cnt_dw_10s) + 1 の計算

		movf	cnt_dw_01s,W		;1S（秒）DOWN カウンタ
		movwf	work2
		movf	cnt_dw_10s,W		;10S（十秒）DOWN カウンタ
		btfsc	STATUS,Z		;cnt_dw_10s = 0 か？
		goto	binit02			;Yes

		movwf	lpcnt2			;ループカウンタ

binit01		movlw	10
		addwf	work2,F			;
		decfsz	lpcnt2,F		;ループカウンタ - 1 = 0 か？
		goto	binit01			;No

binit02		incf	work2,F			;cnt_dw_01s + (10 * cnt_dw_10s) + 1

		; バーグラフの表示

binit03		clrf	lpcnt2			;ループカウンタ = 0

binit04		call	SSD1306_FontPos		;表示開始位置指定

		btfss	count_type,0		;カウンタ種別 = 1,3 か？
		goto	binit05			;No

		movf	work2,W			;cnt_dw_01s + (10 * cnt_dw_10s) + 1
		subwf	lpcnt2,W		;lpcnt2 - work2
		movlw	h'00'			;
		btfss	STATUS,C		;lpcnt2 < work2 か？
		movlw	h'3c'			;Yes
		movwf	work1			;表示値

binit05		movf	lpcnt2,W

		movlb	1		;;	;バンク 1
		movwf	a08		;	;割られる数
		movlw	5		;
		movwf	b08		;	;割る数
		movlp	high div_8	;
		call	div_8		;	;8 ÷ 8 ＝ 8 ビットの割り算
		movlp	high $		;
		movf	y08,F		;	;余り
		movlb	0		;;	;バンク 0

		movlw	h'00'			;
		btfsc	STATUS,Z		;余り = 0 か？
		movlw	h'c0'	;h'80'		;Yes
		iorwf	work1,W

		movf	lpcnt2,F
		btfsc	STATUS,Z		;lpcnt2 = 0 か？
		movlw	h'fc'	;h'bc'		;Yes
		call	data_byte	       ;;データ１バイト出力

		movlw	2
		addwf	gl_x,F			;X座標の更新

		incf	lpcnt2,F		;ループカウンタ + 1
		movlw	60 + 1			;
		subwf	lpcnt2,W		;
		btfss	STATUS,C		;ループカウンタ = lpcnt2 < 60 + 1 か？
		goto	binit04			;No

		return

;--------------------------------------------------------------------------
;		バーグラフの更新表示
;--------------------------------------------------------------------------

bar_update_graph_display

		movlw	4
		btfsc	count_type,0		;カウンタ種別 = 1,3 か？
		movlw	4 + 2			;Yes
		movwf	gl_x			;X座標
		movlw	2
		movwf	gl_y			;Y座標

		movf	cnt_dw_01s,W		;1S（秒）DOWN カウンタ
		btfss	count_type,0		;カウンタ種別 = 1,3 か？
		movf	cnt_up_01s,W		;No. 1S（秒）UP カウンタ
		movwf	work1			;

		movf	cnt_dw_10s,W		;10S（十秒）DOWN カウンタ
		btfss	count_type,0		;カウンタ種別 = 1,3 か？
		movf	cnt_up_10s,W		;No. 10S（十秒）UP カウンタ
		btfsc	STATUS,Z		;cnt_xx_10s = 0 か？
		goto	bupdt02			;Yes

		movwf	lpcnt2			;ループカウンタ

bupdt01		movlw	10
		addwf	work1,F			;
		decfsz	lpcnt2,F		;ループカウンタ - 1 = 0 か？
		goto	bupdt01			;No

bupdt02		lslf	work1,W			;x2
		addwf	gl_x,F			;X座標

		call	SSD1306_FontPos		;表示開始位置指定
;
		btfss	count_type,0		;カウンタ種別 = 1,3 か？
		goto	bupdt04			;No

		; カウンタ種別 = 1,3 のとき
		movlw	9
		subwf	cnt_dw_01s,W		;1S（秒）DOWN カウンタ
		btfsc	STATUS,Z		;cnt_dw_01s = 9 か？
		goto	bupdt03			;Yes

		movlw	4
		subwf	cnt_dw_01s,W		;1S（秒）DOWN カウンタ
		btfsc	STATUS,Z		;cnt_dw_01s = 4 か？
		goto	bupdt03			;Yes

		clrw				;
		goto	bupdt06

bupdt03		movlw	h'c0'	;h'80'		;
		goto	bupdt06

		; カウンタ種別 = 2,(4) のとき
bupdt04		movf	cnt_up_01s,W		;1S（秒）UP カウンタ
		btfsc	STATUS,Z		;cnt_up_01s = 0 か？
		goto	bupdt05			;Yes

		sublw	5
		btfsc	STATUS,Z		;cnt_up_01s = 5 か？
		goto	bupdt05			;Yes

		movlw	h'3c'			;
		goto	bupdt06

bupdt05		movlw	h'fc'	;h'8c'		;

bupdt06		call	data_byte		;データ１バイト出力
		return

;--------------------------------------------------------------------------
;		データ１バイト出力
;--------------------------------------------------------------------------

;入力:		W reg:	表示データ

data_byte
		movwf	work3			;ワークに一時退避, (変数 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	work3,W			;データバイトを復帰
		call	i2c_byte_send		;1 バイト送信
		call	i2c_stop		;ストップコンディション
		return

;--------------------------------------------------------------------------
;		バッテリー（18650 リチウムイオン電池）の電圧表示
;--------------------------------------------------------------------------

battery_volt_display

		;"[ x.xx V ]"

		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		OLED_FontPos_M	73,1		;表示開始位置の指定
		movlw	'['
		call	SSD1306_DispChr		;OLED へ１文字出力

		movlw	73+6*6-2
		movwf	gl_x
		call	SSD1306_FontPos		;表示開始位置指定
		movlw	'V'
		call	SSD1306_DispChr		;OLED へ１文字出力

		movlw	73+6*7
		movwf	gl_x
		call	SSD1306_FontPos		;表示開始位置指定
		movlw	']'
		call	SSD1306_DispChr		;OLED へ１文字出力

battery_volt2_display

		call	battery_voltage		;バッテリーの電圧測定

		movlb	1			;バンク 1
		movf	x16_hi,W
		movwf	a16_hi
		movf	x16_lo,W
		movwf	a16_lo
		movlp	high bindec16cz_cnv
		call	bindec16cz_cnv		;16 ビット数値を 10進数 5桁の文字列に変換
		movlp	high $
		movlb	0			;バンク 0

		movlw	high (buff0+2)		;変換文字列の先頭アドレス
		movwf	FSR0H			;
		movlw	low (buff0+2)		;
		movwf	FSR0L			;間接アドレスに設定

		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1	;(Ver.1.01)
		OLED_FontPos_M	73+8,1		;表示開始位置の指定
		moviw	FSR0++
		call	SSD1306_DispChr		;OLED へ１文字出力
		movlw	'.'
		call	SSD1306_DispChr		;OLED へ１文字出力
		moviw	FSR0++
		call	SSD1306_DispChr		;OLED へ１文字出力
		moviw	FSR0++
		call	SSD1306_DispChr		;OLED へ１文字出力
		return

;--------------------------------------------------------------------------
;		カウンタストップメッセージの出力
;--------------------------------------------------------------------------

stop_msg_display

		movlw	2
		call	line_clear		;１行単位で画面消去
		movlw	3
		call	line_clear		;１行単位で画面消去

		OLED_FontPos_M	6*3,3		;表示開始位置の指定
		OLED_DispStr_M	count_str,1	;"Counter" 文字列の表示
		OLED_DispStr_M	,0		;" Stop !" 文字列の表示

		btfsc	updt_flg,6		;中断表示フラグ = 1 か？
 		call	buzzer_buu		;Yes. "ブー" ブザー音, (中断時)

		; スリープ移行時間カウンタ（slp_cnt_h:slp_cnt_l）の初期設定

spmsg01		movf	sleep_time,W		;スリープまでの移行時間（分）
		call	mul8x8_16		;8 x 8 ビット = 16 ビットの乗算

spmsg02		btfss	tcon_flg,0		;0.25秒経過表示フラグ = 1 か？
		goto	spmsg03			;No

		bcf	tcon_flg,0		;0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		btfsc	tcon_flg,1		;0.5秒ブリンクフラグ = 1 か？
		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1

		movlw	6*18
		movwf	gl_x			;X座標
		call	SSD1306_FontPos		;表示開始位置の指定
		movlw	a' '			;
		call	SSD1306_DispChr		;OLED へ１文字出力
		bcf	echr_flg,7		;ビット反転表示指示 = 0

spmsg03		comf	PORTA,W
		andlw	b'00110011'		;PORTA の全スイッチを読み取る
		btfss	STATUS,Z		;どれかのスイッチ = ON か？
		goto	spmsg04			;Yes

		comf	PORTC,W
		andlw	b'00110000'		;PORTC の全スイッチを読み取る
		btfss	STATUS,Z		;どれかのスイッチ = ON か？
		goto	spmsg04			;Yes

		; スリープ移行時間の監視（60 x sleep_time 秒）

		call	sleep_control		;時間の監視とスリープモードに移行
		btfss	updt_flg,3		;スリープ状態フラグ = 1 か？
		goto	spmsg02			;No

		bcf	updt_flg,3		;スリープ状態フラグ = 0
	;;	goto	spmsg01			;（sleep_control 内で再設定する）
		goto	spmsg02

spmsg04		call	wait_15ms		;チャッタリング吸収
		comf	PORTA,W
		andlw	b'00110011'		;PORTA の全スイッチを読み取る
		btfss	STATUS,Z		;どれかのスイッチ = OFF か？
		goto	spmsg04			;No

		comf	PORTC,W
		andlw	b'00110000'		;PORTC の全スイッチを読み取る
		btfss	STATUS,Z		;どれかのスイッチ = OFF か？
		goto	spmsg04			;No

		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		タイマー・クロックカウントダウン
;--------------------------------------------------------------------------

clock_count_down
		decfsz	cnt_dw_01s,W		;秒 DOWN カウンタ - 1 = 0 か？
		goto	cdw01			;No

		movf	cnt_dw_10s,W 
		btfss	STATUS,Z		;十秒 DOWN カウンタ = 0 か？
		goto	cdw01			;No

		movf	cnt_dw_01m,W
		btfss	STATUS,Z		;分 DOWN カウンタ = 0 か？
		goto	cdw01			;No

		movf	cnt_dw_10m,W
		btfss	STATUS,Z		;十分 DOWN カウンタ = 0 か？
		goto	cdw01			;No

		decf	cnt_dw_01s,F		;秒 DOWN カウンタ - 1
		bsf	updt_flg,5	       ;;タイムアウトフラグ = 1 設定
		goto	cdw05

cdw01		movf	cnt_dw_01s,W
		btfsc	STATUS,Z		;秒 DOWN カウンタ = 0 か？
		goto	cdw02			;Yes
		decf	cnt_dw_01s,F		;秒 DOWN カウンタ - 1
		goto	cdw05

cdw02		movlw	9
		movwf	cnt_dw_01s		;秒 DOWN カウンタ = 9
		movf	cnt_dw_10s,W 
		btfsc	STATUS,Z		;十秒 DOWN カウンタ = 0 か？
		goto	cdw03			;Yes
		decf	cnt_dw_10s,F		;十秒 DOWN カウンタ - 1
		goto	cdw05

cdw03		movlw	5 
		movwf	cnt_dw_10s		;十秒 DOWN カウンタ = 5
		movf	cnt_dw_01m,W
		btfsc	STATUS,Z		;分 DOWN カウンタ = 0 か？
		goto	cdw04			;Yes
		decf	cnt_dw_01m,F		;分 DOWN カウンタ - 1
		goto	cdw05

cdw04		movlw	9
		movwf	cnt_dw_01m		;分 DOWN カウンタ = 9
		movf	cnt_dw_10m,W
		btfsc	STATUS,Z		;十分 DOWN カウンタ = 0 か？
		goto	cdw05			;Yes
		decf	cnt_dw_10m,F		;十分 DOWN カウンタ - 1

cdw05		return

;--------------------------------------------------------------------------
;		ストップウオッチ・クロックカウントアップ
;--------------------------------------------------------------------------

clock_count_up
		incf	cnt_up_01s,F		;秒 UP カウンタ + 1
		movlw	10
		subwf	cnt_up_01s,W
		btfss	STATUS,C		;秒 UP カウンタ >= 10 か？
		goto	cup01			;No

		clrf	cnt_up_01s		;秒 UP カウンタ = 0

		incf	cnt_up_10s,F		;十秒 UP カウンタ + 1
		movlw	6
		subwf	cnt_up_10s,W
		btfss	STATUS,C		;十秒 UP カウンタ >= 6 か？
		goto	cup01			;No

		clrf	cnt_up_10s		;十秒 UP カウンタ = 0

		incf	cnt_up_01m,F		;分 UP カウンタ + 1
		movlw	10
		subwf	cnt_up_01m,W
		btfss	STATUS,C		;分 UP カウンタ >= 10 か？
		goto	cup01			;No

		clrf	cnt_up_01m		;分 UP カウンタ = 0

		incf	cnt_up_10m,F		;十分 UP カウンタ + 1
		movlw	10
		subwf	cnt_up_10m,W
		btfss	STATUS,C		;十分 UP カウンタ >= 10 か？
		goto	cup01			;No

		clrf	cnt_up_10m		;十分 UP カウンタ = 0

cup01		return

;==========================================================================
;	各カウンタ Down/Up/Down+Up Counter の表示 内のスイッチ処理
;==========================================================================
;--------------------------------------------------------------------------
;		START スイッチの処理 ... counter_display から CALL
;--------------------------------------------------------------------------

cnt_start_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTC,_swSTA		;再度 START スイッチ = ON か？
		goto	cstasw03		;No

		btfss	count_type,0		;count_type = 1,3 か？
		goto	cstasw02		;No

		movf	cnt_dw_10m,W		;入力データの有効性チェック
		iorwf	cnt_dw_01m,W		;
		iorwf	cnt_dw_10s,W		;
		iorwf	cnt_dw_01s,W		;
		btfss	STATUS,Z		;cnt_dw_10m = cnt_dw_01m = cnt_dw_10s = cnt_dw_01s = 0 か？
		goto	cstasw01		;No.  OK

		call	buzzer_buu		;Yes. NG: "ブー" ブザー音出力
		goto	cstasw03

cstasw01	movf	cnt_dw_10m,W		;設定値の退避
		movwf	cnt_10m
		movf	cnt_dw_01m,W		;
		movwf	cnt_01m
		movf	cnt_dw_10s,W		;
		movwf	cnt_10s
		movf	cnt_dw_01s,W		;
		movwf	cnt_01s

cstasw02	bsf	updt_flg,0		;有効性チェックフラグ = 1: OK

cstasw03	btfss	PORTC,_swSTA		;START スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		RIGHT スイッチの処理 ... counter_display から CALL
;--------------------------------------------------------------------------

; sel_flg: 選択フラグ = bit3:10M（十分）/ 2:1M（分）/ 1:10S（十秒）/ 0:1S（秒）カウンタ

cnt_right_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swRIG		;再度 RIGHT スイッチ = ON か？
		goto	crigsw01		;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1

		lsrf	sel_flg,F		;選択フラグの更新, 右にシフト
		btfsc	STATUS,Z		;sel_flg = 0 か？
		bsf	sel_flg,3		;Yes. bit3 = 1

		btfss	PORTA,_swRIG		;RIGHT スイッチ = OFF か？
		goto	$ - 1			;No

crigsw01	call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		LEFT スイッチの処理 ... counter_display から CALL
;--------------------------------------------------------------------------

; sel_flg: 選択フラグ = bit3:10M（十分）/ 2:1M（分）/ 1:10S（十秒）/ 0:1S（秒）カウンタ

cnt_left_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swLEF		;再度 LEFT スイッチ = ON か？
		goto	clefsw01		;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1

		lslf	sel_flg,F		;選択フラグの更新, 左にシフト
		movlw	1
		btfsc	sel_flg,4		;sel_flg = bit4 か？
		movwf	sel_flg			;Yes. bit0 = 1

		btfss	PORTA,_swLEF		;LEFT スイッチ = OFF か？
		goto	$ - 1			;No

clefsw01	call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		UP スイッチの処理 ... counter_display から CALL
;--------------------------------------------------------------------------

; sel_flg: 選択フラグ = bit3:10M（十分）/ 2:1M（分）/ 1:10S（十秒）/ 0:1S（秒）カウンタ

cnt_up_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swUP		;再度 UP スイッチ = ON か？
		goto	cupsw04			;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1

		btfss	sel_flg,3		;選択フラグ = bit3: 10M（十分） か？
		goto	cupsw01			;No

		incf	cnt_dw_10m,F		;10M（十分）DOWN カウンタの +1 更新
		movlw	10
		subwf	cnt_dw_10m,W
		btfsc	STATUS,C		;cnt_dw_10m >= 10 か？
		clrf	cnt_dw_10m		;Yes. 10M（十分）DOWN カウンタ = 0
		goto	cupsw04

cupsw01		btfss	sel_flg,2		;選択フラグ = bit2: 1M（分） か？
		goto	cupsw02			;No

		incf	cnt_dw_01m,F		;1M（分）DOWN カウンタの +1 更新
		movlw	10
		subwf	cnt_dw_01m,W
		btfsc	STATUS,C		;cnt_dw_01m >= 10 か？
		clrf	cnt_dw_01m		;Yes. 1M（分）DOWN カウンタ = 0
		goto	cupsw04

cupsw02		btfss	sel_flg,1		;選択フラグ = bit1: 10S（十秒） か？
		goto	cupsw03			;No

		incf	cnt_dw_10s,F		;10S（十秒）DOWN カウンタの +1 更新
		movlw	6
		subwf	cnt_dw_10s,W
		btfsc	STATUS,C		;cnt_dw_10S >= 6 か？
		clrf	cnt_dw_10s		;Yes. 10S（十秒）DOWN カウンタ = 0
		goto	cupsw04

cupsw03	;	btfss	sel_flg,0		;選択フラグ = bit0: 1S（秒） か？
	;	goto	cupsw0_			;No

		incf	cnt_dw_01s,F		;1S（秒）DOWN カウンタの +1 更新
		movlw	10
		subwf	cnt_dw_01s,W
		btfsc	STATUS,C		;cnt_dw_01S >= 10 か？
		clrf	cnt_dw_01s		;Yes. 1S（秒）DOWN カウンタ = 0

cupsw04		btfss	PORTA,_swUP		;UP スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		DOWN スイッチの処理 ... counter_display から CALL
;--------------------------------------------------------------------------

; sel_flg: 選択フラグ = bit3:10M（十分）/ 2:1M（分）/ 1:10S（十秒）/ 0:1S（秒）カウンタ

cnt_down_switch
		call	wait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swDWN		;再度 DOWN スイッチ = ON か？
		goto	cdwnsw04		;No

		bsf	updt_flg,0		;スイッチ入力有りフラグ = 1

		btfss	sel_flg,3		;選択フラグ = bit3: 10M（十分） か？
		goto	cdwnsw01		;No

		decf	cnt_dw_10m,F		;10M（十分）DOWN カウンタの -1 更新
		incf	cnt_dw_10m,W		;
		movlw	9
		btfsc	STATUS,Z		;cnt_dw_10m = 0 か？
		movwf	cnt_dw_10m		;Yes. 10M（十分）DOWN カウンタ = 9
		goto	cdwnsw04

cdwnsw01	btfss	sel_flg,2		;選択フラグ = bit2: 1M（分） か？
		goto	cdwnsw02		;No

		decf	cnt_dw_01m,F		;1M（分）DOWN カウンタの -1 更新
		incf	cnt_dw_01m,W		;
		movlw	9
		btfsc	STATUS,Z		;cnt_dw_01m = 0 か？
		movwf	cnt_dw_01m		;Yes. 1M（分）DOWN カウンタ = 9
		goto	cdwnsw04

cdwnsw02	btfss	sel_flg,1		;選択フラグ = bit1: 10S（十秒） か？
		goto	cdwnsw03		;No

		decf	cnt_dw_10s,F		;10S（十秒）DOWN カウンタの -1 更新
		incf	cnt_dw_10s,W		;
		movlw	5
		btfsc	STATUS,Z		;cnt_dw_10s = 0 か？
		movwf	cnt_dw_10s		;Yes. 10S（十秒）DOWN カウンタ = 5
		goto	cdwnsw04

cdwnsw03 ;	btfss	sel_flg,0		;選択フラグ = bit0: 1S（秒） か？
	 ;	goto	cdwnsw0_		;No

		decf	cnt_dw_01s,F		;1S（秒）DOWN カウンタの -1 更新
		incf	cnt_dw_01s,W		;
		movlw	9
		btfsc	STATUS,Z		;cnt_dw_01s = 0 か？
		movwf	cnt_dw_01s		;Yes. 1S（秒）DOWN カウンタ = 9

cdwnsw04	btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
		goto	$ - 1			;No

		call	wait_15ms		;チャッタリング吸収
		return


;==========================================================================
;	     時間の監視とスリープモードに移行とウェイクアップ
;==========================================================================

;	updt_flg: モードフラグ
;			       	bit7: １秒更新フラグ
;			       	bit6: 各項目の表示要求フラグ
;				bit5: 
;				bit4: 状態変化割り込み記憶フラグ
;			       	bit3: スリープ状態フラグ
;				bit2: スリープ移行時間チェックフラグ
;			       	bit1: カウンタ実行要求フラグ
;			       	bit0: スイッチ入力有りフラグ

sleep_control
		btfss	updt_flg,2		;スリープ移行時間チェックフラグ = 1 か？
		goto	sleep03			;No

		bcf	updt_flg,2		;スリープ移行時間チェックフラグ = 0

		movf	slp_cnt_h,W
		btfss	STATUS,Z		;slp_cnt_h = 0 か？
		goto	sleep03			;No

		movlw	3 + 1
		subwf	slp_cnt_l,W		;
		btfsc	STATUS,C		;スリープ移行までの時間 < 3 + 1 か？
		goto	sleep03			;No

		movf	slp_cnt_l,W		;
		btfsc	STATUS,Z		;slp_cnt_l = 0 か？
		goto	sleep01			;Yes

		call	buzzer_bu		;"ブッ" アラーム音出力 (100 mS)
		goto	sleep03

		; スリープモードに移行準備

sleep01		call	buzzer_bubuu		;"ブッブー" アラーム音出力 (450 mS)

		bcf	T0CON0,T0EN		;TMR0 有効化ビット = 0
	;;	call	clock_disable		;RTC モジュールの発振器を無効
	; ???	無効にするとなぜか wake up しなくなる ???

		movlw	h'ae'			;OFF
		call	SSD1306_DispOnOff	;OLED の Display ON/OFF 制御

		movlb	7			;バンク 7
		clrf	IOCAF			;状態変化割り込みフラグをクリア
		clrf	IOCCF			;状態変化割り込みフラグをクリア
		movlb	1			;バンク 1
		bsf	PIE0,IOCIE		;状態変化割り込み許可 = 1
		movlb	0			;バンク 0
		bsf	updt_flg,3	;bit3	;スリープ状態フラグ = 1

sleep02		sleep				;スリープモード
		; 
		;				;wake up
		btfss	updt_flg,4		;状態変化割り込み記憶フラグ = 1 か？
		goto	sleep02			;No. 再度 sleep

		; 状態変化割り込みのとき

		movlw	h'af'			;ON
		call	SSD1306_DispOnOff	;OLED の Display ON/OFF 制御
		call	clock_enable		;RTC モジュールの発振器を有効
		bsf	T0CON0,T0EN		;TMR0 有効化ビット = 1

		call	buzzer_pipi		;"ピピッ" アラーム音出力 (230 mS)

		bcf	updt_flg,4		;状態変化割り込み記憶フラグ = 0
	;;	bcf	updt_flg,3		;スリープ状態フラグ ... (呼び出し側でクリアする)

		; スリープ移行時間カウンタの初期設定

		movf	sleep_time,W		;スリープまでの移行時間（分）
		call	mul8x8_16		;8 x 8 ビット = 16 ビットの乗算

sleep03		return

;--------------------------------------------------------------------------
;		8 x 8 ビット = 16 ビットの乗算
;--------------------------------------------------------------------------

; 入力:			    W reg: 乗数

; 使用変数:		slp_cnt_h: 結果（上位）
;			slp_cnt_l: 結果（下位）
;		           lpcnt2: ループカウンタ

mul8x8_16
		movwf	slp_cnt_l		;乗数を代入
		clrf	slp_cnt_h		;クリア

		movlw	8
		movwf	lpcnt2			;ループカウンタ

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	lpcnt2,F		;ループカウンタ - 1 = 0 か？
		goto	mul8x01			;No

		return


;==========================================================================
;		バッテリー（18650 リチウムイオン電池）の電圧測定
;==========================================================================

;			    ┌───┐  ┌───┐
;			┌─┤3.3KΩ├─┤3.3KΩ├── 電源電圧
;			│  └───┘  └───┘
;	  RC2(ANC2) ──┤
;			│  ┌───┐
;			└─┤3.3KΩ├──────── GND
;			    └───┘

battery_voltage

;	     >> BATTERY 電源電圧を測定する

		movlb	1			;バンク 1
		bsf	ADCON0,ADON		;ADC 有効 = 電源 ON
;		movlb	0			;バンク 0
		call	wait_10us		;アクイジション時間
;		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	lpcnt1			;ループカウンタ

battv01		movlb	1			;バンク 1
		movf	ADRESL,W		;
		addwf	ad_res_lo,F
		movf	ADRESH,W		;
		addwfc	ad_res_hi,F
		movlb	0			;バンク 0
		decfsz	lpcnt1,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
		movlp	high div_16
		call	div_16			;16 ビットの割り算
		movlp	high $
		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


;==========================================================================
;		アラーム（ブザー）音出力ルーチン
;==========================================================================

		; "ププッ" ブザー音 (230 mS)
buzzer_pupu
		call	buzzer_pu		;"プッ" ブザー音出力
		call	wait_30ms

		; "プッ" ブザー音出力 (100 mS)
buzzer_pu
		Sound_M		f_ra, 100
		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
		bsf	T1CON,TMR1ON      	;Timer1を有効
		call	wait_xxms		;入力 W: 音長（ループカウンタ）
		bcf	T1CON,TMR1ON      	;Timer1を無効

		bcf	PORTC,_BZ		;ブザー出力ビットを "L" にしておく
		return

;==========================================================================
;		ウェイト・ルーチン (4 MHz)	(Page 0 用)
;==========================================================================

		; 10μ秒 ウェイトルーチン

wait_10us
		goto	$ + 1			;2
		goto	$ + 1			;2
		goto	$ + 1			;2
		goto	$ + 1			;2
		return				;2	2+2+2+2+2=10
						;Total	10/4MHz*4 = 10 μS

		; 15m 秒 ウェイトルーチン
wait_15ms
		movlw	15
		goto	wait_xxms

		; 30m 秒 ウェイトルーチン
wait_30ms
		movlw	30
		goto	wait_xxms

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100
		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	110			;1
		movwf	wt1cnt			;1

w1m02		goto	$ + 1			;2
		goto	$ + 1			;2
		goto	$ + 1			;2
		decfsz	wt1cnt,F		;1,2
		goto	w1m02			;2,0	(2+2+2+1+2)*109+(2+2+2+2+0)=989

		goto	$ + 1			;2
		goto	$ + 1			;2
		decfsz	wt2cnt,F		;1,2
		goto	w1m01			;2,0	(1+1+989+2+2+1+2)*(W-1)+(1+1+989+2+2+2+0)=998*W-1

		return				;2	1+(998*W-1)+2=998*W+2
						;Total	(998*W+2)/4MHz*4 = (998*W + 2) μS

		; 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

;
;==========================================================================
;--------------------------------------------------------------------------
 		org	h'0800'			;(Page 1)
;--------------------------------------------------------------------------
;==========================================================================

;--------------------------------------------------------------------------
;		マクロ命令の定義 (Page 1 用)
;--------------------------------------------------------------------------

;		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

;--------------------------------------------------------------------------
;		ページ変換サブルーチン (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_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

xSSD1306_Clear
		movlp	high SSD1306_Clear
		call	SSD1306_Clear		;モジュールの画面消去
		movlp	high $
		return

xSSD1306_Contrast
		movlp	high SSD1306_Contrast
		call	SSD1306_Contrast	;モジュールのコントラスト制御
		movlp	high $
		return

xrev_shift_byte
		movlp	high rev_shift_byte
		call	rev_shift_byte		;h'00' / h'7f' / h'fe' １バイト出力
		movlp	high $
		return

;--------------------------------------------------------------------------
;		ウェイト・ルーチン (4 MHz)	(Page 1 用)
;--------------------------------------------------------------------------

		; 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

		; 200m 秒 ウェイトルーチン
wwait_200ms
		call	wwait_100ms

		; 100m 秒 ウェイトルーチン
wwait_100ms
		movlw	100
		goto	xwait_xxms

		; 15m 秒 ウェイトルーチン
wwait_15ms
		movlw	15

		; ミリ秒（ 1m 秒 x W ）単位 ウェイトルーチン
xwait_xxms
		movlp	high wait_xxms
		call	wait_xxms		;W ミリ秒間のウエイト
		movlp	high $
		return


;==========================================================================
;		メンテナンス機能
;==========================================================================

;	[スイッチ操作]
;			 CANCEL    LEFT     DOWN      UP      RIGHT    START
;			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;			 │●│   │●│   │●│   │●│   │●│   │●│
;			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
;			/ MAINTE  / NEXT                    / PREV.  / SELECT

;		NEXT スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択
;		PREV.スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択

;		  UP スイッチ        ..... ブリンク位置の値を + 1
;		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り

;		  UP スイッチ +
;		DOWN スイッチ        ..... ブリンク位置の値をデフォルト値に設定

;		DOWN スイッチ        ..... ブリンク位置の値を - 1
;		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り

;		DOWN スイッチ +
;		  UP スイッチ        ..... ブリンク位置の値をデフォルト値に設定

;	      SELECT スイッチ        ..... メンテナンス機能を終了し、メイン（カウンタ種類の選択）に戻る

;	      CANCEL スイッチ        ..... メンテナンス機能を中断し、メイン（カウンタ種類の選択）に戻る

;	sel_flg: 選択フラグ	                            ( maintenance 内のとき )
;			       	bit7:                     / 中断表示フラグ
;				bit6:                     / contrast 値変更ありフラグ
;				bit5:                     / 中断表示フラグ
;			       	bit4: 
;				bit3: 10M（十分）カウンタ
;			       	bit2:  1M（分）カウンタ
;			       	bit1: 10S（十秒）カウンタ / OLED コントラストフラグ
;			       	bit0:  1S（秒）カウンタ   / スリープまでの移行時間フラグ

;	tcon_flg: タイミング制御フラグ
;				bit7-4: 0.5秒単位ダウンカウンタ
;				bit3:   カウント許可中フラグ
;				bit2:   ブリンク制御動作中フラグ/カウント終了フラグ
;			       	bit1:   0.5秒ブリンクフラグ
;			       	bit0:   0.25秒経過表示フラグ

maintenance
		call	xSSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去
		movlp	high buzzer_pipi
		call	buzzer_pipi		;"ピピッ" ブザー音出力
		movlp	high $

		movf	contrast,W		;(CANCEL 時に備えて退避)
		movwf	contrast_wk		;
		movf	sleep_time,W		;
		movwf	sleep_time_wk		;

		clrf	sel_flg			;
		bsf	sel_flg,1		;選択フラグの初期設定
		bsf	sel_flg,6		;contrast 値変更ありフラグ = 1

		; タイミング制御の初期設定

		clrf	tcon_flg
		movlp	high timer_250ms_set
		call	timer_250ms_set		;タイマー０の基本設定
		movlp	high $

		; スリープ移行時間カウンタ（slp_cnt_h:slp_cnt_l）の初期設定

maint01		movf	sleep_time,W		;スリープまでの移行時間（分）
		movlp	high mul8x8_16
		call	mul8x8_16		;8 x 8 ビット = 16 ビットの乗算
		movlp	high $

		; 設定値のブリンク表示制御

maint02		btfss	sel_flg,6		;contrast 値変更ありフラグ = 1 か？
		goto	maint03			;No

		bcf	sel_flg,6		;contrast 値変更ありフラグ = 0
		movf	contrast,W
		call	xSSD1306_Contrast	;OLED ( SSD1306 ) の コントラスト制御

		call	mainte_msg_disp		;メンテナンスメッセージの表示

maint03		btfss	tcon_flg,0		;0.25秒経過表示フラグ = 1 か？
		goto	maint05			;No

		bcf	tcon_flg,0		;0.25秒経過表示フラグ = 0
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		btfsc	tcon_flg,1		;0.5秒ブリンクフラグ = 1 か？
		bsf	echr_flg,7		;Yes. ビット反転表示指示 = 1

		btfss	sel_flg,1		;選択フラグ = bit1: OLED コントラスト か？
		goto	maint04			;No

		call	contrast_disp		;Yes. OLED コントラスト値の表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		call	sleep_time_disp		;スリープまでの移行時間値の表示
		goto	maint05

maint04		call	sleep_time_disp		;スリープまでの移行時間値の表示
		bcf	echr_flg,7		;ビット反転表示指示 = 0
		call	contrast_disp		;OLED コントラスト値の表示

		; メンテナンス機能中の各スイッチの入力処理

maint05		bcf	sel_flg,5		;スイッチ入力有りフラグ = 0

		btfss	PORTA,_swNEX		;NEXT スイッチ = ON か？
		call	mainte_next_switch	;Yes

		btfss	PORTA,_swPRV		;PREV. スイッチ = ON か？
		call	mainte_prev_switch	;Yes

		btfss	PORTA,_swUP		;UP スイッチ = ON か？
		call	mainte_up_switch	;Yes

		btfss	PORTA,_swDWN		;DOWN スイッチ = ON か？
		call	mainte_down_switch	;Yes

		btfsc	sel_flg,5		;スイッチ入力有りフラグ = 1 か？
		goto	maint01			;Yes

		btfss	PORTC,_swSEL		;SELECT スイッチ = ON か？
		goto	maint07			;Yes

		btfss	PORTC,_swCAN		;CANCEL スイッチ = ON か？
		goto	maint06			;Yes

		; スリープ移行時間の監視（60 x sleep_time 秒）

		movlp	high sleep_control
		call	sleep_control		;時間の監視とスリープモードに移行
		movlp	high $
	;	btfss	updt_flg,3		;スリープ状態フラグ = 1 か？
	;	goto	maint02			;No

		bcf	updt_flg,3		;スリープ状態フラグ = 0
		goto	maint02

		; メンテナンス機能の中断終了

maint06		call	wwait_15ms		;チャッタリング吸収
		btfss	PORTC,_swCAN		;CANCEL スイッチ = OFF か？
		goto	$ - 1			;No

		call	wwait_15ms		;チャッタリング吸収

		movf	sleep_time_wk,W		;(退避データを復帰)
		movwf	sleep_time		;
		movf	contrast_wk,W		;
		movwf	contrast		;
		call	xSSD1306_Contrast	;OLED ( SSD1306 ) の コントラスト制御

		bsf	sel_flg,7		;中断表示フラグ = 1
		goto	maint09

		; メンテナンス機能の終了

maint07		call	wwait_15ms		;チャッタリング吸収
		btfss	PORTC,_swSEL		;SELECT スイッチ = OFF か？
		goto	$ - 1			;No

		call	wwait_15ms		;チャッタリング吸収

		; 重複データのチェック
		movlw	high save_data_buff	;引継ぎ情報（バックアップデータ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_buff	;
		movwf	FSR1L			;間接アドレスに設定

		moviw	FSR1++			;
		subwf	sleep_time,W
		btfss	STATUS,Z		;sleep_time = INDF1 か？
		goto	maint08			;No

		moviw	FSR1++			;
		subwf	contrast,W
		btfsc	STATUS,Z		;contrast = INDF1 か？
		goto	maint09			;Yes

		; 重複データのチェック OK のとき
maint08		movlp	high write_eeprom
		call	write_eeprom		;バックアップデータを EEPROM へ書き込み更新
		movlp	high $

maint09	;;;	bcf	T0CON0,T0EN		;TMR0 有効化ビット = 0
		clrf	tcon_flg		;タイミング制御フラグをクリア

		movlp	high buzzer_pipi
		btfss	sel_flg,7		;中断表示フラグ = 1 か？
		call	buzzer_pipi		;No. "ピピッ" ブザー音, (更新時)

		btfsc	sel_flg,7		;中断表示フラグ = 1 か？
		call	buzzer_buu		;Yes. "ブー" ブザー音, (中断時)
		movlp	high $

		call	wwait_1s		; 1 秒 ウェイト
		clrf	sel_flg			;選択フラグをクリア
		return

;--------------------------------------------------------------------------
;		メンテナンスメッセージの表示
;--------------------------------------------------------------------------

mainte_msg_disp
		xOLED_FontPos_M	3+6*1,0		;
		clrf	echr_flg		;表示文字の機能拡張フラグ = クリア
		xOLED_DispStr_M	mainte_msg,1	;1 行目の表示

		xOLED_FontPos_M	3+6*2,1		;
		xOLED_DispStr_M	,0		;2 行目の表示

		xOLED_FontPos_M	3+6*1,2		;
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		xOLED_DispStr_M	,0		;3 行目の表示

		xOLED_FontPos_M	3+6*2,3		;
		xOLED_DispStr_M	,0		;4 行目の表示
		clrf	echr_flg		;表示文字の機能拡張フラグ = クリア

		call	contrast_disp		;OLED コントラスト値の表示
		call	sleep_time_disp		;スリープまでの移行時間（分）値の表示
		return

mainte_msg
		dt	 "> OLED Contrast",0	;1 行目
		dt	  "(001-255) ? _",0	;2 行目
		dt	 "> Sleep Time",0	;3 行目
		dt	  "(00-30) ? _",0	;4 行目

;--------------------------------------------------------------------------
;		OLED コントラスト値の表示
;--------------------------------------------------------------------------

contrast_disp
		xOLED_FontPos_M	3+6*16-1,1	;
		bcf	echr_flg,6		;1 bit 左(下)ずらし指示 = 0
		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,3	;
		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

;==========================================================================
;		メンテナンス機能内のスイッチ処理
;==========================================================================
;--------------------------------------------------------------------------
;		NEXT スイッチの処理 ... メンテナンス機能から CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		NEXT スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択

;	sel_flg: 選択フラグ
;			       	bit7: 中断表示フラグ
;			       	bit6: contrast 値変更ありフラグ
;			      >	bit1: OLED コントラストフラグ
;			      >	bit0: スリープまでの移行時間フラグ

mainte_next_switch
		call	wwait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swNEX		;再度 NEXT スイッチ = ON か？
		goto	mnexsw01		;No

		bsf	sel_flg,5		;スイッチ入力有りフラグ = 1
		movlw	h'03'
		xorwf	sel_flg,F		;選択フラグの更新

		btfss	PORTA,_swNEX		;NEXT スイッチ = OFF か？
		goto	$ - 1			;No

mnexsw01	call	wwait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		PREV. スイッチの処理 ... メンテナンス機能から CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		PREV.スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択

;	sel_flg: 選択フラグ
;			       	bit7: 中断表示フラグ
;			       	bit6: contrast 値変更ありフラグ
;			      >	bit1: OLED コントラストフラグ
;			      >	bit0: スリープまでの移行時間フラグ

mainte_prev_switch
		call	wwait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swPRV		;再度 PREV. スイッチ = ON か？
		goto	mprvsw01		;No

		bsf	sel_flg,5		;スイッチ入力有りフラグ = 1
		movlw	h'03'
		xorwf	sel_flg,F		;選択フラグの更新

		btfss	PORTA,_swPRV		;PREV. スイッチ = OFF か？
		goto	$ - 1			;No

mprvsw01	call	wwait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		UP スイッチの処理 ... メンテナンス機能から CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		  UP スイッチ        ..... ブリンク位置の値を + 1

;		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り

;		  UP スイッチ +
;		DOWN スイッチ        ..... ブリンク位置の値をデフォルト値に設定

;	sel_flg: 選択フラグ
;			      >	bit7: 中断表示フラグ
;			      >	bit6: contrast 値変更ありフラグ
;			      >	bit1: OLED コントラストフラグ
;			      >	bit0: スリープまでの移行時間フラグ

mainte_up_switch
		call	wwait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swUP		;再度 UP スイッチ = ON か？
		goto	mupsw04			;No

		bsf	sel_flg,5		;スイッチ入力有りフラグ = 1
		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	30 + 1
		subwf	sleep_time,W		;
		btfsc	STATUS,Z		;sleep_time = 30 + 1 か？
		clrf	sleep_time	;Yes	;sleep_time = 0, (30 → 0)

		call	wwait_200ms		;早送りの速度調整

mupsw03	;	btfss	PORTA,_swUP		;UP スイッチ = OFF か？
	;	goto	$ - 1			;No

		call	wwait_100ms		;早送りの速度調整

mupsw04		return

;--------------------------------------------------------------------------

;		デフォルト値に設定

default_set
		call	wwait_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	wwait_15ms		;チャッタリング吸収
		return

;--------------------------------------------------------------------------
;		DOWN スイッチの処理 ... メンテナンス機能から CALL
;--------------------------------------------------------------------------

;	[スイッチ操作]

;		DOWN スイッチ        ..... ブリンク位置の値を - 1

;		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り

;		DOWN スイッチ +
;		  UP スイッチ        ..... ブリンク位置の値をデフォルト値に設定

;	sel_flg: 選択フラグ
;			      >	bit7: 中断表示フラグ
;			      >	bit6: contrast 値変更ありフラグ
;			      >	bit1: OLED コントラストフラグ
;			      >	bit0: スリープまでの移行時間フラグ

mainte_down_switch
		call	wwait_15ms		;チャッタリング吸収
		btfsc	PORTA,_swDWN		;再度 DOWN スイッチ = ON か？
		goto	mdwsw04			;No

		bsf	sel_flg,5		;スイッチ入力有りフラグ = 1
		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, (0 → 254)

		bsf	sel_flg,6		;contrast 値変更ありフラグ = 1
		goto	mdwsw03

mdwsw02		decf	sleep_time,F		;sleep_time - 1
		incf	sleep_time,W
		movlw	30
		btfsc	STATUS,Z		;sleep_time < 0 か？
		movwf	sleep_time	;Yes	;sleep_time = 30, (0 → 30)

		call	wwait_200ms		;早送りの速度調整

mdwsw03	;	btfss	PORTA,_swDWN		;DOWN スイッチ = OFF か？
	;	goto	$ - 1			;No

		call	wwait_100ms		;早送りの速度調整

mdwsw04		return


;==========================================================================
;		各種 演算／変換サブルーチン
;==========================================================================
;--------------------------------------------------------------------------
;		8 ÷ 8 ＝ 8 ビットの割り算
;--------------------------------------------------------------------------

;	(a08) ÷ (b08) = (x08) ... (y08) 

; 使用変数:		 a08: 割られる数	(終了時は０になる)
;			 b08: 割る数		(終了時に変化しない)
;			 x08: 答え		(答えが返る)
;			 y08: 余り		(余りが返る、ワークにも使用)
;		lcnt1, lcnt2: ループカウンタ
;		    C フラグ: エラーフラグ	(割る数が０であった場合 C=1)

div_8
		movlw	8
		movwf	lcnt1			;ループカウンタ1
		movf	b08,W			;割る数をワークにコピー
		movwf	y08

d8_01		rlf	y08,F			;左シフトする
		btfsc	STATUS,C		;キャリフラグを見る
		goto	d8_02			;割る数の上位ビット位置検索

		decfsz	lcnt1,F
		goto	d8_01

		bsf	STATUS,C		;割る数が０である。エラー終了
		goto	d8_08

d8_02		clrf	x08			;答え用変数のクリア
		clrf	y08			;ワーク変数のクリア

		movlw	8
		movwf	lcnt2			;ループカウンタ2
		movf	lcnt1,W
		subwf	lcnt2,F			;残り、実ループの回数

d8_03		lslf	a08,F
		rlf	y08,F
		decfsz	lcnt1,F			;割られる数を初期位置までシフト
		goto	d8_03

d8_04		movf	b08,W			;現位置での減算が可能かチェック
		subwf	y08,W
		btfss	STATUS,C
		goto	d8_05			;引くことが不可能

		movf	b08,W
		subwf	y08,F
		bsf	STATUS,C		;キャリフラグをセット
		goto	d8_06

d8_05		bcf	STATUS,C		;キャリフラグをクリア

d8_06		rlf	x08,F			;キャリフラグの内容を答えにシフト
		movf	lcnt2,F
		btfsc	STATUS,Z		;lcnt2 = 0 か？
		goto	d8_07			;Yes, 終了

		decf	lcnt2,F			;ビット位置を１つ下げる（右へ）
		lslf	a08,F			;ワークへ１ビット左シフト
		rlf	y08,F
		goto	d8_04

d8_07		bcf	STATUS,C		;正常終了

d8_08		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

;--------------------------------------------------------------------------
;		8 ビット数値を 10進数 3桁の文字列に変換
;--------------------------------------------------------------------------

; 使用変数:	         work1: 変換する 8 ビット数値
;		         work2: ワーク
;		        lpcnt2: ループカウンタ
;		   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	lpcnt2			;シフトカウンタに設定
		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	lpcnt2,F		;ループカウンタ - 1 = 0 か？
		goto	bd8c01			;No

		movf	work2,W			;余り
		addlw	h'30'			;文字コードに変換
		movwi	--FSR0
		return

;--------------------------------------------------------------------------
;		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


;==========================================================================
;		プログラムタイトルの表示
;==========================================================================

prog_title_display

		; プログラムタイトルの表示

		clrf	echr_flg		;表示文字の機能拡張フラグ = クリア

		xOLED_FontPos_M	4+6*2,0
		xOLED_DispStr_M	prog_title,1	;"Kitchen Timer II"

		xOLED_FontPos_M	4+6*4,1
		bsf	echr_flg,6		;1 bit 左(下)ずらし指示 = 1
		xOLED_DispStr_M	,0		;"Version x.xx"

		xOLED_FontPos_M	1+6*4,3
		xOLED_DispStr_M	,0		;"by m.yamamoto"
		clrf	echr_flg		;表示文字の機能拡張フラグ = クリア

		; デモ表示の省略チェック

		movf	PORTA,W
		andlw	b'00110011'		;PORTA の全スイッチを読み取る
		xorlw	b'00100001'		;反転
		;            ^  ^
		btfss	STATUS,Z		;DOWN + UP スイッチ = ON か？
		call	edge_frame		;No. 左右縁枠の表示と消去

		movlw	3
		call	wwait_xs		;3 秒間のウエイト
		call	xSSD1306_Clear		;OLED ( SSD1306 ) モジュールの画面消去
		return

;--------------------------------------------------------------------------

		; プログラムタイトル メッセージ

prog_title	dt	  "Kitchen Timer II",0	;1 行目
		dt	    "Version ",ver_no,0	;2 行目
		dt	    "by m.yamamoto"  ,0	;4 行目
;			 01234567890123456789

;--------------------------------------------------------------------------
;		左右縁枠の表示と消去
;--------------------------------------------------------------------------

edge_frame
		movlw	0
		movwf	pagex			;表示開始ページ
		movlw	3
		movwf	end_pagex		;表示終了ページ

		clrf	work3			;ウェイト不使用フラグ = 0
		movlw	2
		movwf	lpcnt1			;ループカウンタ1

edgfr01		movlw	h'ff'			;表示
		call	edge_frame_1		;
		clrw				;消去
		call	edge_frame_1		;

		decfsz	lpcnt1,F		;ループカウンタ1 - 1 = 0 か？
		goto	edgfr01			;No

edgfr02		movlw	h'ff'			;表示
		call	edge_frame_1		;
		clrw				;消去
		call	edge_frame_2		;
		call	wwait_1s		;1 秒間のウエイト

		bsf	work3,7			;ウェイト不使用フラグ = 1
		movlw	2
		movwf	lpcnt1			;ループカウンタ1

edgfr03		movlw	h'ff'			;表示
		call	edge_frame_1		;
		call	wwait_1s		;1 秒間のウエイト

		clrw				;消去
		call	edge_frame_1		;
		call	wwait_1s		;1 秒間のウエイト

		decfsz	lpcnt1,F		;ループカウンタ1 - 1 = 0 か？
		goto	edgfr03			;No

		movlw	h'ff'			;表示
		call	edge_frame_1		;
		call	wwait_1s		;1 秒間のウエイト
		return

;--------------------------------------------------------------------------

; 入力:		W reg:	h'00': 消去 / h'ff': 表示

edge_frame_1
		movwf	pattern			;垂直パターン

		clrf	work1			;左側の縦線
		movlw	127
		movwf	work2			;右側の縦線

		movlw	8
		movwf	lpcnt2			;ループカウンタ2

edgf101		movf	work1,W
		movwf	column			;表示カラム
		call	xSSD1306_Line_V		;左側の垂直線表示

		movf	work2,W
		movwf	column			;表示カラム
		call	xSSD1306_Line_V		;右側の垂直線表示

		btfss	work3,7			;ウェイト不使用フラグ = 1 か？
		call	wwait_250ms		;No. 250 ミリ秒ウェイト

		incf	work1,F			;更新
		decf	work2,F			;

		decfsz	lpcnt2,F		;ループカウンタ2 - 1 = 0 か？
		goto	edgf101			;No

		return

;--------------------------------------------------------------------------

edge_frame_2
		movwf	pattern			;垂直パターン

		movlw	8
		movwf	lpcnt2			;ループカウンタ2

edgf201		decf	work1,F			;更新
		incf	work2,F			;

		movf	work1,W
		movwf	column			;表示カラム
		call	xSSD1306_Line_V		;左側の垂直線表示

		movf	work2,W
		movwf	column			;表示カラム
		call	xSSD1306_Line_V		;右側の垂直線表示

		call	wwait_250ms		;250 ミリ秒ウェイト

		decfsz	lpcnt2,F		;ループカウンタ2 - 1 = 0 か？
		goto	edgf201			;No

		return

;
;==========================================================================
;--------------------------------------------------------------------------
 		org	h'1800'			;(Page 3)
;--------------------------------------------------------------------------
;==========================================================================

;		文字フォント（5 x 7）ファイルのインクルード

;				ドライブ、パス名は、各自の開発環境に合わせるように !!

		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'


;==========================================================================
;		EEPROM メモリ関連アクセス
;==========================================================================

;--------------------------------------------------------------------------
;		バックアップデータを EEPROM から読み出し
;--------------------------------------------------------------------------

read_eeprom
		movlw	high save_data_buff	;引継ぎ情報（バックアップデータ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_buff	;
		movwf	FSR1L			;間接アドレスに設定

		movlw	save_data_end - save_data ;読み出しバイト数
		movwf	lpcnt1			;ループカウンタ1

		movlb	17			;バンク 17
		movlw	h'70'
		movwf	NVMADRH			;
		movlw	low save_data
		movwf	NVMADRL			;EEPROM の記録アドレスを設定
		bsf	NVMCON1,NVMREGS		;データ EEPROM メモリにアクセス

rdeep01		movlb	17			;バンク 17
		bsf	NVMCON1,RD		;読み出し制御 = ON
		movf	NVMDATL,W		;データの読み出し
		movwi	FSR1++			;RAM バッファへ書き込み
		incf	NVMADRL,F		;記録アドレスの更新

		movlb	0			;バンク 0
		decfsz	lpcnt1,F		;ループカウンタ1 - 1 = 0 か？
		goto	rdeep01			;No

		call	ram_buff_read		;RAM バッファから個々の変数へコピー
		return

;--------------------------------------------------------------------------

		; RAM バッファから個々の変数へコピー

ram_buff_read
		movlw	high save_data_buff	;引継ぎ情報（バックアップデータ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_buff	;
		movwf	FSR1L			;間接アドレスに設定

		moviw	FSR1++			;
		movwf	sleep_time		;スリープまでの移行時間(分)

		moviw	FSR1++			;
		movwf	contrast		;OLED コントラスト

		moviw	FSR1++			;
		movwf	count_type		;カウンタ種類

dwn_cnt_read
		moviw	FSR1++			;
		movwf	cnt_dw_10m		;10M（十分）DOWN カウンタ

		moviw	FSR1++			;
		movwf	cnt_dw_01m		; 1M（分）DOWN カウンタ

		moviw	FSR1++			;
		movwf	cnt_dw_10s		;10S（十秒）DOWN カウンタ

		moviw	FSR1++			;
		movwf	cnt_dw_01s		; 1S（秒）DOWN カウンタ
		return

;--------------------------------------------------------------------------
;		バックアップデータを EEPROM へ書き込み
;--------------------------------------------------------------------------

write_eeprom
		call	ram_buff_write		;個々の変数から RAM バッファへコピー

		movlw	high save_data_buff	;引継ぎ情報（バックアップデータ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_buff	;
		movwf	FSR1L			;間接アドレスに設定

		movlw	save_data_end - save_data ;書き込みバイト数
		movwf	lpcnt1			;ループカウンタ1

		movlb	17			;バンク 17
		movlw	h'70'
		movwf	NVMADRH			;
		movlw	low save_data
		movwf	NVMADRL			;EEPROM の記録アドレスを設定
		bsf	NVMCON1,NVMREGS		;データ EEPROM メモリにアクセス

wreep01		movlb	17			;バンク 17
		moviw	FSR1++			;RAM バッファの読み出し
		movwf	NVMDATL			;書き込みデータを設定

		bsf	NVMCON1,WREN		;プログラム/消去サイクルを許可
		bcf	INTCON,GIE		;割り込みを禁止
		movlw	h'55'
		movwf	NVMCON2			;h'55' を NVMCON2 に書き込む
		movlw	h'aa'
		movwf	NVMCON2			;h'aa' を NVMCON2 に書き込む

		bsf	NVMCON1,WR		;書き込み開始
		bsf	INTCON,GIE		;割り込みを許可
		bcf	NVMCON1,WREN		;プログラム/消去サイクルを禁止
		btfsc	NVMCON1,WR		;書き込み 終了か?
		goto	$ - 1			;No

		incf	NVMADRL,F		;記録アドレスの更新

		movlb	0			;バンク 0
		decfsz	lpcnt1,F		;ループカウンタ1 - 1 = 0 か？
		goto	wreep01			;No

		return

;--------------------------------------------------------------------------

		; 個々の変数から RAM バッファへコピー

ram_buff_write
		movlw	high save_data_buff	;引継ぎ情報（バックアップデータ）の先頭アドレス
		movwf	FSR1H			;
		movlw	low save_data_buff	;
		movwf	FSR1L			;間接アドレスに設定

		movf	sleep_time,W		;スリープまでの移行時間(分)
		movwi	FSR1++			;

		movf	contrast,W		;OLED コントラスト
		movwi	FSR1++			;

		movf	count_type,W		;カウンタ種類
		movwi	FSR1++			;

		movf	cnt_dw_10m,W		;10M（十分）DOWN カウンタ
		movwi	FSR1++			;

		movf	cnt_dw_01m,W		; 1M（分）DOWN カウンタ
		movwi	FSR1++			;

		movf	cnt_dw_10s,W		;10S（十秒）DOWN カウンタ
		movwi	FSR1++			;

		movf	cnt_dw_01s,W		; 1S（秒）DOWN カウンタ
		movwi	FSR1++			;
		return

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'f000'

eep_start	de	"Copyright (C) 2025 by M.Yamamoto"

		de	h'ff'

		; 以下はデフォルト値

save_data	de	3			;スリープまでの移行時間(分)

		de	127   ;h'7f'		;OLED コントラスト

		de	1			;カウンタ種類

		de	1			;10M（十分）DOWN カウンタ
		de	5			; 1M（分）DOWN カウンタ
		de	0			;10S（十秒）DOWN カウンタ
		de	0			; 1S（秒）DOWN カウンタ
save_data_end

;==========================================================================

		end				;プログラムの終了
