;***** StopWatchII.asm ****************************************************
;
;	ストップウオッチ II （現在時刻、スプリット、ラップタイムを表示）
;
;	Copyright (C) 2020   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2020/04/04  by M.Yamamoto )
;	coding:  Ver. 1.00   2020/05/28  初期バージョン
;	bugfix:  Ver. 1.01   2020/06/02  時間のカウント誤りを修正
;	update:  Ver. x.xx
;
;******************************************************* PicAsm 0251 ******

;	Device: PIC16F628A/PIC16F648A	Clock: 8MHz (セラロック)

#ifdef comment

 <機能概要と使用法>

・本機は、ウォーキングの友として毎日（１回あたり数時間程度）の比較的長時間の携行使用ができるように、なる
　べく電池の消耗が少なくて済むような考慮をしており、単４電池３本を電源としたストップウオッチである。

・初めに、本機には次の遷移図に示すように大きく分けて３つのモードがあり、(XXXX)で示す各スイッチを操作する
　ことでそれらのモード間を移動する。(XXXX)＋(XXXX)と表現されているものは、＋印の左側スイッチを押しながら
　右側スイッチをちょんと押すことを表している。

        モードの遷移図                            GOAL後
                                                 (ENABLE)
	┌─────┐            ┌─────┐    ＋      ┌─────┐
	│          │ (SET)      │          │ (START)    │          │
	│ 時刻設定 │─────→│ ストップ │─────→│  メモリ  │
	│          │            │ ウオッチ │            │ 内容表示 │
	│  モード  │←─────│  モード  │←─────│  モード  │
	│          │   (SELECT) │          │   (SELECT) │          │
	└─────┘      ＋    └─────┘      ＋    └─────┘
	                  (START)                   (START)

　・時刻設定・モード ........... 現在の時刻を設定する（必須ではない、省略可）。設定された時刻をもとに
　　　　　　　　　　　　　　　　 ストップウオッチが動作中は現在時刻を表示し続ける。
　・ストップウオッチ・モード ... ユーザがスイッチ操作をする度に、そのときのスプリットタイムをメモリ内
　　　　　　　　　　　　　　　　 に記憶しつつ、時間計算によってラップタイムを表示する。
　・メモリ内容表示・モード ..... ストップウオッチ・モード中に記憶したメモリ内容を読み出し、改めてスプ
　　　　　　　　　　　　　　　　 リット／ラップタイムを表示する。

・なお、ストップウオッチ・モード、およびメモリ内容表示・モードのときに、(SELECT)+(START)のスイッチ操作を
　すると１つ前のモードに戻ることができるが、それまでに記憶したすべてのスプリットタイムが無効となるので注
　意が必要である。

・また、これらの３つのモードとは別に、ストップウオッチ・モードとメモリ内容表示・モードにおいては、ユーザ
　のスイッチ操作が一定時間なかったときにはスリープモードに移行し、液晶（ＬＣＤ）表示も消して省電力化を図
　るようにしている。 そして、このスリープモード中に(ENABLE)または(START)スイッチを操作することで、すぐに
　目覚めて元のモードに戻ることもできる。

・さて、本機の電源スイッチをオンにすると、"ピポッ"と開始ブザー音とともに LED(緑)を点滅表示した後、ＬＣＤ
　にも次の開始メッセージが交互に２秒間ずつ連続２回表示される。

			[ ** Stop- ]			[ Ver x.xx ]
			[ Watch ** ]			[  by M.Y  ]

 ◆ 時刻設定・モード ◆

・その後、２秒間無表示の後、次のメッセージが表示され、"ピポッピポッ" ブザー音とともに LED(緑)を点滅表示
　して、本機が時刻設定・モードに移行したことを知らせる。そして、その後はユーザからの各種スイッチの入力待
　ちとなる。
			[ Time Set ]
			[ 00:00:00 ]	..... ２行目の先頭の "0" がブリンク表示される。

・なお、本機には次図に示すように５個のスイッチが用意されており、本モードにおいては各スイッチを(XXXX)で示
　した名前で呼ぶこととする。
		                            ←DWN     UP→
		 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
		 │●│   │●│   │●│   │●│   │●│
		 └─┘   └─┘   └─┘   └─┘   └─┘
		(SELECT)  (DOWN)    (UP)    (SET)/  (START)/
		                            ENABLE    GOAL

・本機の機能の１つとして予め設定された時刻をもとに、ストップウオッチが動作中にも現在時刻を表示し続ける機
　能を持たせてある。そのために初めに時刻を設定することを本モードで行うように想定しているが、必須ではない
　ため不要な場合には省略をしても構わないが、その場合には、ストップウオッチの動作中に無意味な時刻表示がさ
　れ続けることになる。

・本モードに移行した直後には、ＬＣＤの２行目には [ 00：00：00 ] と "時"："分"："秒" の形式で初期値が表示
　され、かつ、先頭（左端）の "0" がブリンク表示されている。このブリンク表示されている位置の桁が今選択さ
　れていることを意味し、(SELECT)スイッチを押すことによってその選択桁を自由に変更することができる。

・(SELECT)スイッチ を押すごとに選択桁が右に移動して行き、右端（一秒桁）の次には再び左端（十時桁）に戻る。 
　この選択桁を変更するときに、(START)スイッチを押しながら (SELECT)スイッチを押す（ (START)スイッチ + 
　(SELECT)スイッチ ) と、押すごとに逆の左に移動して行き、左端（十時桁）の次には再び右端（一秒桁）に戻る。

・現在時刻を設定するときに、このようにしてまず、希望する "時"、"分"、"秒" それぞれの "十位"、または "一
　位" の桁を選択しておいて、次に (UP)スイッチ、または (DOWN)スイッチを操作することによって、 現在時刻に
　合わせることができる。

・(UP)スイッチ は、現在表示されている値を押すごとに ＋１ずつ増加（インクリメント）し、また、(DOWN)スイッ
　チ は、逆に押すごとに －１ずつ減少（デクリメント）する。そして、(UP)スイッチの操作では、各桁の最大値を
　超えると "０" に戻る。また (DOWN)スイッチの操作では、各桁の最小値の "０" を超えると各桁の最大値に戻る。

・ただし "時" の入力では、"００" から "２９" まで変更が可能であるが、"２４" 以上を入力した場合には、その
　後 (SELECT)スイッチ、または (START)スイッチ + (SELECT)スイッチの操作を行なっても 他桁への移行はできず、
　"ブッ" というブザー音とともに赤色ＬＥＤが瞬間点滅して、エラー表示をする。

・本機ではこのようにして設定した設定値を、予めプリセット値として登録をしておくことができる。ウォーキング
　（散歩）というものは、毎日朝、または夕方の同時刻ごろに出かけることが多いため、本機を次回（翌日など）の
　使用時には、登録しておいたプリセット値を呼び出して、その設定時刻をわずかな修正だけで済むように考慮をし
　た。

・(START)スイッチ + (UP)スイッチの操作をすると、現在ＬＣＤに表示されている "時"、"分"、"秒" がプリセット
　値として、ＰＩＣの内蔵メモリ（EEPROM）に書き込まれる。また、このプリセット値を読み出す場合には (START)
　スイッチ + (DOWN)スイッチ の操作をすると、現在ＬＣＤに表示されている "時"、"分"、"秒" がプリセット値に
　置き換わる。

・ここで、プリセット値の登録数は５つまで* とした。無駄を省くため書き込み時にチェックをして同値は書き込ま
　ないようにしている。読み出し時には (START)スイッチ + (DOWN)スイッチの操作を繰り返すごとに、登録数だけ
　変更表示されるので希望値を選択する。 ただし、最終値の表示の次には [ 00：00：00 ] を一度表示するように
　した。
（ * 実際にはもっと多くの数を登録することも可能であるが、逆に選択が面倒にもなるため最大５つに制限をした。）

・なお、５つ以上の書き込みを行った場合には、最も古いものから順に消されて新しいものが登録され、いつも５つ
　までを保持する。読み出しのときは最も古いものから順に読み出される。

・このようにして設定をした設定値が実際に時刻として有効になるのは、次に (SET)スイッチ を押した瞬間からで
　ある。その瞬間に本モードの時刻設定・モードは終了をして、次のストップウオッチ・モードに移行をし、そして、
　時刻のカウントを開始する。なお、このとき (START)スイッチ + (SET)スイッチというスイッチ操作もあり、その
　相違はストップウオッチ・モードを参照のこと。

・ここで、時刻設定・モードにおいてのスイッチ操作をまとめておくと、次のようになる。

　                  (SELECT)スイッチ ........  選択桁が右に１桁移動する （ブリンク位置ポインタ + 1） 
　(START)スイッチ + (SELECT)スイッチ ........  選択桁が左に１桁移動する （ブリンク位置ポインタ - 1） 
                    (UP)スイッチ     ........  選択桁の値をインクリメントする （ブリンク位置の値 + 1） 
                    (DOWN)スイッチ   ........  選択桁の値をデクリメントする （ブリンク位置の値 - 1） 
　(START)スイッチ + (UP)スイッチ     ........  EEPROM へプリセット値を書き込む 
　(START)スイッチ + (DOWN)スイッチ   ........  EEPROM からプリセット値を読み出す 
  　　　　　　　　　(SET)スイッチ    ........  時刻設定・モードを終了をする
　(START)スイッチ + (SET)スイッチ    ........  時刻設定・モードを終了をする、（スリープモード中のブザー音を抑止する）

 ◆ ストップウオッチ・モード ◆

・上で述べたように、(SET)スイッチを押した瞬間に時刻設定・モードが終了をして、そのままストップウオッチ・ 
　モードに移行をする。そして、移行をした直後に現在時刻のカウントが開始されＬＣＤには次のメッセージが表示
　されて、"ピポッピポッ" ブザー音とともに LED(緑) を点滅表示してそれを知らせる。その後はユーザからの指示
　としてのスイッチの入力待ちとなる。 

			[ Start On ]
			[ xx:xx:xx ]	..... ２行目に刻々と現在時刻が刻まれながら表示される。

・ストップウオッチ・モードにおいて使用するスイッチは○色のスイッチを除いた３個で、本モードにおいては各ス
　イッチを (XXXX) で示した名前で呼ぶこととする。

		                            ←DWN     UP→
		 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
		 │●│   │○│   │○│   │●│   │●│
		 └─┘   └─┘   └─┘   └─┘   └─┘
		(SELECT)   DOWN      UP      SET /  (START)/
		                           (ENABLE)  (GOAL)

・なお、時刻設定・モードでは述べなかったが、右２個のスイッチは他の３個のスイッチに比べてキートップ長が長
　いものを採用し、本機のケースの蓋を閉めた状態でも頭がケース外に飛び出すような構造にケース加工を施してあ
　り、その他のスイッチはケース内に隠れてしまう。これは、ウォーキングを開始以降はその途中で右２個のスイッ
　チ以外には触れられないようにするためである。

・次図は、本モードに移行してから本モードを終了（メモリ内容表示・モードへ移行）するまでを図に表したもので、
　初めに、前モードの時刻設定・モードのときに (SET)スイッチの操作を契機として本モードに移行をし、予め設定
　されていた時刻から現在時刻のカウントが開始される。 

     現在時刻のカウントがプリセット値から開始される
	 |  スプリットタイムのカウントが [00:00:00] から開始される
	 |      |                                                         |      |
	 |      |←-----------------------------------------------SPLITn→|      |
	 |      |←------------------------------------→|                |      | 
	 |      |←-----------------------SPLIT2→|      |                |      |
	 |      |←------SPLIT1→|                |      |                |      |
	 |      |                |                |      |                |      |
	 |      |←----LAP1----→|←----LAP2----→|------|←----LAPn----→|      |
	 |      |                |                |      |                |      |
	 |─--─|────────|────────|─--─|────────|─--─|
	SET    (1)              (1)              (1)----(1)              (2)--(1)or(2)
	 ↑    START                                                    GOAL     ↑
      （ストップウオッチ・モード開始）                 （メモリ内容表示・モードへ移行）

	       (1) (ENABLE) スイッチ + (START) スイッチ ... 通常のちょん押し
	       (2) (ENABLE) スイッチ + (START) スイッチ ... ５秒ほどの長押し

・その後、ウォーキングを開始すると同時に、ユーザからは最初の (1) (ENABLE)スイッチ + (START)スイッチ 操作
　（上図で START の (1) の位置）が行われて、それを契機として スプリットタイムのカウントが [ 00：00：00 ] 
　から開始され、ＬＣＤの１行目に表示がされるようになる。そして、"ド ミ ソ ドー" ブザー音とともに LED(緑)
　(赤)が交互に点滅して、スプリットタイムのカウントが スタート(START) をしたことを知らせる。

			[ 00:00:00 ]	..... １行目にスプリットタイムのカウントが開始される。
			[ xx:xx:xx ]	..... ２行目に刻々と現在時刻が刻まれながら表示される。

・ウォーキングが始まると、本機は上図で (1)、および (2)の操作をするための各チェック地点以外では、邪魔とな
　ってポケットなどに入れられることを想定しており、そのために起こるであろう、チェック地点以外でのスイッチ
　の誤操作を極力防ぐために、２個のスイッチを組み合わせたスイッチ操作を採用している。すなわち、(ENABLE) 
　スイッチを押しながら (START) スイッチを押す (ENABLE) スイッチ + (START) スイッチという方法である。

・また、STARTの(1)を除いた各チェック地点での(1)のスイッチ操作ごとに、その時点のスプリットタイム がＰＩＣ
　に内蔵のメモリ（SRAM）に書き込まれて記憶され、これを知らせるために "ポポッ" ブザー音とともに LED(緑)を
　点滅表示させる。そしてその直後に、ＬＣＤの表示が一時的に約３秒間だけ次のように変わって、そのときの記憶
　番号（チェック地点番号）とラップタイムが表示される。ラップタイムは、今回測定したスプリットタイムと、前
　回測定してメモリ（SRAM）に記憶されているスプリットタイムとの差を、時間計算によって求めたものである。 

			[ ** xx ** ]	..... １行目の xx に記憶番号が表示される。
			[ xx:xx:xx ]	..... ２行目にラップタイムが表示される。

・このとき、内蔵のメモリ（SRAM）に書き込むことが可能なスプリットタイムの最大数は、PIC16F628Aを使用の場合
　には 58 個、PIC16F648Aを使用の場合には 68 個までである。もしも、これらの最大個数になっているときに、 
　なおも記憶をさせようとしたときには、次のようなエラーメッセージをＬＣＤに表示をして、かつ、"ブッブッブッ
　ブッ" ブザー音とともに LED(赤)が数秒間点滅を繰り返えす。

			[ xx:xx:xx ]
			[ Mem Over ]	..... ２行目にメモリオーバーエラーメッセージが表示される。

・このようにウォーキング中は、各チェック地点で (1)のスイッチ操作をするだけで、それ以外のときにはスイッチ
　操作をする必要がないため、ユーザのスイッチ操作が一定時間（現在１分に設定）なかったときには、ＬＣＤの電
　源を OFF にし ＰＩＣもスリープモードに移行して省電力化を図るようにしている。なお、このスリープモード中
　であっても (ENABLE)スイッチ、または(START)スイッチのどちらかを操作することによって、いつでも即座に目覚
　めさせることができる。

・また、スリープモード中にも本機の存在感を誇示するために、１分間に１度、瞬間 "ピッ" ブザー音とともに LED
　(赤)を点灯させている。ただし、時刻設定・モードから本モードへの移行時に (START)スイッチ + (SET)スイッチ
　の操作をした場合には、"ピッ" ブザー音は抑止され LED(赤) だけを瞬間点灯させる。

・さて、ウォーキングも終盤に近づいていよいよゴールをする場合には、上図のように (2)のスイッチ操作をするが、
　(1) と同じスイッチを使用するために両者の区別をしなければならない。そこで (2)の場合には５秒間ほどの長押
　しをしていると、"ド ソ ミ ドー" ブザー音が鳴り出すとともに LED(緑)(赤)が交互に点滅するので、それを合図
　に (2)の操作を止めるようにする。

・このとき、ゴール地点のスプリットタイムがＰＩＣに内蔵のメモリ（SRAM）に最終的に書き込まれて記憶され、そ
　れらの合図でゴール (GOAL) をしたことを知らせる。またその直後に、ＬＣＤの表示が約３秒間だけ記憶番号とラ
　ップタイムが表示されることは、各チェック地点の場合と同様である。

・そのゴールした後はスプリットタイムのカウントは停止されるが、次のスイッチ操作の指示があるまでは、現在時
　刻は更新されながら表示し続ける。最終的にもう一度 (1)、または (2)のスイッチ操作をすると、その瞬間に本モ
　ードのストップウオッチ・モードが終了をする。  

			[ xx:xx:xx ]	..... １行目のスプリットタイムはカウントが停止される。
			[ xx:xx:xx ]	..... ２行目の現在時刻は更新されながら表示し続ける。

・例外処理として、ストップウオッチ・モード中に何らかの理由があって、本モードを途中で中止をし前モードの時
　刻設定・モードへ戻りたいような場合には、(SELECT)スイッチ + (START)スイッチの操作をすると、それが可能と
　なる。ただし、この場合にはそれまでに記憶されていたスプリットタイムのすべてが無効となるので、このスイッ
　チ操作には十分注意する必要がある。

・ここで、ストップウオッチ・モードにおいてのスイッチ操作をまとめておくと、次のようになる。

　(ENABLE) スイッチ + (START) スイッチ 通常のちょん押し ........  スタートの処理、各チェック地点の処理、
　								  ストップウオッチ・モードの終了 
　(ENABLE) スイッチ + (START) スイッチ ５秒ほどの長押し ........  ゴールの処理、ストップウオッチ・モードの終了 
　(SELECT) スイッチ + (START) スイッチ 通常のちょん押し ........  時刻設定・モードへ戻る（例外処理） 

 ◆ メモリ内容表示・モード ◆

・上で述べたように、前モードでゴール (GOAL)した後にもう一度、(1)、または (2)のスイッチ操作をすると、スト
　ップウオッチ・モードが終了すると同時にメモリ内容表示・モードに移行をする。そして、本モードに移行をした
　直後には次のメッセージがＬＣＤに表示され、"ピポッピポッ" ブザー音とともに LED(緑) を点滅表示してそれを
　知らせる。 その後はユーザからの指示としてのスイッチの入力待ちとなる。 

			[ Mem Disp ]
			[←DWN UP→]

・メモリ内容表示・モードにおいて使用するスイッチは○色のスイッチを除いた３個で、本モードにおいては各スイ
　ッチを (XXXX) で示した名前で呼ぶこととする。

		                           (←DWN)   (UP→)
		 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
		 │●│   │○│   │○│   │●│   │●│
		 └─┘   └─┘   └─┘   └─┘   └─┘
		(SELECT)   DOWN      UP      SET /  (START)/
		                            ENABLE    GOAL 

・本モードでは、前モード中にＰＩＣに内蔵のメモリ（SRAM）内に書き込んで記憶をさせた、各チェック地点でのス
　プリットタイムを、(UP→)スイッチ、または (←DWN)スイッチを操作するごとに読み出して、そのときの記憶番号
　（チェック地点番号）とともに、改めて時間計算を行って求めたラップタイムの３つの情報をＬＣＤに表示をする。
　このとき読み出しのキーとなる記憶番号は、初めてスイッチ操作があった場合には、それが (UP→) スイッチのと
　きは １番が、(←DWN)スイッチのときは最大値が選択されて、それらが初期値となる。

・そして、まず初めに記憶番号が次の形式でＬＣＤに表示される。この記憶番号は２つのスイッチの内どちらかを操
　作するごとに更新をするが、(UP→)スイッチの場合には、＋１ずつ増加（インクリメント、最大値に達したときは
　次には再び１番に戻る）され、一方、(←DWN) スイッチの場合には、－１ずつ減少（デクリメント、１番に達した
　ときは次には再び最大値に戻る）されて、ＬＣＤに表示がされる。

			[ ** xx ** ]	..... １行目には記憶番号 xx が表示される。
			[          ]	..... ２行目には何も表示はされない。

・上で表示される記憶番号は、どちらかのスイッチを押している間中ずっと表示され続けるが、手を離した瞬間に次
　次の形式でスプリットタイム、およびラップタイムの表示に切り替わる。

			[ xx:xx:xx ]	..... １行目にはスプリットタイムが表示される。
			[ xx:xx:xx ]	..... ２行目にはラップタイムが表示される。

・このようにして２つのスイッチの内どちらかを操作するごとに、記憶番号の表示と、スプリットタイム、ラップタ
　イムの表示に切り替わりながらＬＣＤに表示されるが、本モードにおいてもユーザのスイッチ操作が一定時間（現
　在１分に設定）なかったときには、ＬＣＤの電源を OFFにしＰＩＣもスリープモードに移行して省電力化を
　図るようにしている。なお、このスリープモード中であっても (←DWN) ／ (ENABLE) スイッチ、または (UP→) 
　／ (START)スイッチのどちらかを操作することによって、いつでも即座に目覚めさせることができる。

・スリープモードから目覚めたときには、一旦、次の形式で刻々と更新をしながら現在時刻が表示されるようになる
　が、次に、(←DWN)、または (UP→)スイッチのどちらかを操作することによって、再び上述した形式で、記憶番号
　（チェック地点番号）とスプリットタイム、ラップタイムの表示に切り替わる。 

			[ Mem Disp ]
			[ xx:xx:xx ]	..... ２行目には刻々と更新をしながら現在時刻が表示される。

・また、本モードにおいても例外処理として、メモリ内容表示・モード中に何らかの理由があって、本モードを途中
　で中止をし前モードのストップウオッチ・モードへ戻りたいような場合には、(SELECT)スイッチ + (START)スイッ
　チの操作をすると、それが可能となる。ただし、この場合にもそれまでに記憶されていたスプリットタイムのすべ
　てが無効となるので、このスイッチ操作には十分注意する必要がある。

・ここで、メモリ内容表示・モードにおいてのスイッチ操作をまとめておくと、次のようになる。

　                   (UP→)/(START)スイッチ  ..... 次の記憶番号、スプリットタイム、ラップタイムを表示する 
　                   (←DWN)/(ENABLE)スイッチ..... 前の記憶番号、スプリットタイム、ラップタイムを表示する 
　(SELECT)スイッチ + (UP→)/(START)スイッチ  ..... ストップウオッチ・モードへ戻る（例外処理） 

#endif

;==========================================================================

;	PIC16F628A/PIC16F648A のピンと用途

;	 (1) RA2: LCD 電源制御			(18) RA1: LCD SDA
;	 (2) RA3: LED(緑) 出力			(17) RA0: LCD SCL
;	 (3) RA4: LED(赤) 出力			(16) OSC1: オシレータ水晶入力
;	 (4) RA5: 未使用			(15) OSC2: オシレータ水晶出力
;	 (5) VSS: 電源 GND			(14) VDD: 電源 +5V DC
;	 (6) RB0: ブザー音 出力			(13) RB7/T1OSI: Timer1 オシレータ入力
;	 (7) RB1: SELECT スイッチ入力		(12) RB6/T1OSO: Timer1 オシレータ出力
;	 (8) RB2: DOWN スイッチ入力		(11) RB5: START/GOAL / UP→ スイッチ入力
;	 (9) RB3: UP スイッチ入力		(10) RB4: SET/ENABLE / ←DWN スイッチ入力

;	*注.  RA4 の出力はオープンドレインのため、外部抵抗でプルアップしないと、High が
;	      出力されない。
;	      RA5 は入力専用で、出力ポートには使えない。

;==========================================================================

#define 	x16f628a		;どちらかを有効にする
;#define 	x16f648a		;

#ifdef x16f628a
	list		p=pic16f628a	;デバイス情報
	include		p16f628a.inc	;インクルードファイル
#endif
#ifdef x16f648a
	list		p=pic16f648a	;デバイス情報
	include		p16f648a.inc	;インクルードファイル
#endif
	errorlevel	-302		;Eliminate bank warning

	__config _CP_OFF & DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC

;	注. 最近 _DATA_CP_OFF が DATA_CP_OFF に変更されているので注意

;==========================================================================
;		変数、定数の定義とレジスタ割付
;==========================================================================

#define 	ver_no	"1.01"

		radix	dec

SCL		equ	0		;I2C-LCD SCL		;┐
SDA		equ	1		;I2C-LCD SDA		;│
_PWcntl		equ	2		;LCD 電源制御		;│PORTA
_ledG		equ	3		;LED(緑)		;│
_ledR		equ	4		;LED(赤)		;┘

_BZ		equ	0		;アラーム音 出力	;┐
_swSEL		equ	1		;SELECT スイッチ	;│
_swDWN		equ	2		;DOWN   スイッチ	;│
_swUP		equ	3		;UP     スイッチ	;│
_swSET		equ	4		;SET/ENABLE スイッチ	;│PORTB
_swEN		equ	4		;SET/ENABLE スイッチ	;│
_swSTA		equ	5		;START/GOAL スイッチ	;│
_rdDWN		equ	4		;←DWN スイッチ		;│
_rdUP		equ	5		;UP→  スイッチ		;┘

sleep_time	equ	60 * 1		;スリープ移行までの時間	;1 分

;						f		t = 1 / f
f_do2		equ	 956		;ド(1046.52 Hz)		0.0009 55  5479111723
f_soh		equ	1276		;ソ (784.00 Hz)		0.0012 75  5102040816
f_mih		equ	1517		;ミ (659.26 Hz)		0.0015 16  8522282559
f_doh		equ	1911		;ド (523.26 Hz)		0.0019 11  0958223445
f_so		equ	2551		;ソ (392.00 Hz)		0.0025 51  0204081633
f_mi		equ	3034		;ミ (329.63 Hz)		0.0030 33  7044565118
f_do		equ	3822		;ド (261.63 Hz)		0.0038 22  1916446891
;								     |  |
;							   (100μS 桁)  (1μS 桁)
po_tim		equ	100		;音長(ms)
pi_tim		equ	100		;音長
bu_tim		equ	100		;音長
buu_tim		equ	250		;音長
dms_tim		equ	200		;音長

		cblock	h'20'
bcd_hh_t				;時_BCD カウンタ	;┐
bcd_mm_t				;分_BCD カウンタ	;│順序を変更しないこと!（現在時刻用）
bcd_ss_t				;秒_BCD カウンタ	;┘
bcd_hh_s				;時_BCD カウンタ	;┐
bcd_mm_s				;分_BCD カウンタ	;│順序を変更しないこと!（スプリット: 経過時間用）
bcd_ss_s				;秒_BCD カウンタ	;┘
bcd_hh_l				;時_BCD カウンタ	;┐
bcd_mm_l				;分_BCD カウンタ	;│順序を変更しないこと!（ラップ: 区間経過時間用）
bcd_ss_l				;秒_BCD カウンタ	;┘
bcd_hh					;時_BCD カウンタ	;┐
bcd_mm					;分_BCD カウンタ	;│順序を変更しないこと!（ワーク用）
bcd_ss					;秒_BCD カウンタ	;┘

eep_cnt					;EEPROM 登録番号カウンタ
dsp_point				;表示位置ポインタ
dspdgt_t				;表示桁指定フラグ（現在時刻用）
dspdgt_s				;表示桁指定フラグ（経過時間用）
dspdgt_w				;表示桁指定フラグ（ワーク用）
dspdigit				;表示桁指定フラグ
					;bit6: "HH" 桁の指定
					;bit5: "HL" 桁の指定
					;bit4: "MH" 桁の指定
					;bit3: "ML" 桁の指定
					;bit2: "SH" 桁の指定
					;bit1: "SL" 桁の指定
					;bit0:  桁上がり指定
stat_flg				;進行状態フラグ
					;bit7: 例外処理指示フラグ（事前処理時以外）
					;bit6: スイッチ入力有りフラグ（事後処理時）
					;bit5: ラップタイム表示済みフラグ
					;bit4: ラップタイム表示指示フラグ
					;bit3: ストップウオッチ動作終了フラグ
					;bit2: ストップウオッチ動作中フラグ
					;bit1: 経過時間更新フラグ
					;bit0: 現在時刻更新フラグ
stat2_flg				;進行状態-2フラグ
					;bit3: 現在時刻初回表示フラグ（事後処理時）
					;bit2: 現在時刻表示指示フラグ（事後処理時）
					;bit1: スリープ時のビープ音抑止フラグ
					;bit0: RB ポート変化割り込み記憶フラグ
hold_cnt				;START スイッチ長押し時間監視カウンタ
					;bit7: カウンタ動作開始フラグ
					;bit3-0: カウンタ部
split_cnt				;スプリット番号カウンタ
split_cntx				;スプリット番号カウンタ退避用
sleep_cnt				;スリープ移行時間カウンタ
laptim_cnt				;ラップタイム表示時間カウンタ
;chr_wk3				;ワーク: 変換後上位数字	;┐
chr_wk2					;ワーク: 		;│順序を変更しないこと!
chr_wk1					;ワーク: 変換後下位数字	;┘
bin_wk					;ワーク: 変換する値
lpcnt					;ワーク: ループカウンタ
work					;ワーク

const_high				;音階用分周定数 high の保存
const_low				;音階用分周定数 low の保存
t0_work					;音階用分周変数ワーク

wt1cnt					;ウェイト用ループカウンタ
wt2cnt					;ウェイト用ループカウンタ
wt3cnt					;ウェイト用ループカウンタ

; ( I2C_S_LCD.sub で使用 )
addr_high				;読み出すデータの high アドレス
addr_low				;読み出すデータの low アドレス
lcdtmp					;LCD への出力データの一時保存
lcdtmp2					;
i2ctmp					;
bit_cnt					;ループカウンタ

time_mem0				;タイムデータ０の先頭アドレス
;		(w_save - time_mem0)	;((w_save - time_mem0) / 3) データ（１データ = ３バイト）
		endc

		cblock	h'80' - 4
w_save					;W レジスタの退避用
s_save					;STATUS レジスタの退避用
p_save					;PCLATH レジスタの退避用
f_save					;FSR レジスタの退避用
		endc

		cblock	h'a0'		;バンク 1
time_mem1				;タイムデータ１の先頭アドレス
;		(80)..(3 x 26 = 78)	;26 データ（１データ = ３バイト）
		endc

		cblock	h'120'		;バンク 2
time_mem2				;タイムデータ２の先頭アドレス
;		(48)..(3 x 16 = 48)	;16 データ（１データ = ３バイト） PIC16F628A の場合
;		(80)..(3 x 26 = 78)	;26 データ（１データ = ３バイト） PIC16F648A の場合
		endc

;==========================================================================
;		マクロ命令定義
;==========================================================================

;		I2C LCD メッセージデータ表示マクロ

Disp_I2cLcd	macro	@com,@msg,@x
		movlw	@com
		call	I2cLcd_Cmd	;I2C LCD へコマンドを出力
	#if 	@x == 0
	#else
		movlw	high @msg	;メッセージデータの先頭アドレスの high アドレス
		movwf	addr_high	;
		movlw	low @msg	;メッセージデータの先頭アドレスの low アドレス
		movwf	addr_low	;
	#endif
		call	I2cLcd_Disp	;メッセージデータ１行表示
		endm

;		Sound_M マクロ（タイマー０割り込み使用）

Sound_M		macro	@scale,@time
		movlw	@scale / 100	;出力音階
		movwf	const_high
		movwf	t0_work		;ワーク
		movlw	@scale % 100 / 2
		movwf	const_low
		movlw	@time		;出力時間(ms)
	;;	call	buzzer_control	;ブザー音出力コントロール
		goto	buzzer_control	;スタックの消費を抑えるため変更
		endm

Sound_M2	macro	@scale,@time
		movlw	@scale / 100	;出力音階
		movwf	const_high
		movwf	t0_work		;ワーク
		movlw	@scale % 100 / 2
		movwf	const_low
		movlw	@time		;出力時間(ms)
		call	buzzer_control2	;ブザー音出力コントロール
		endm

;==========================================================================
;		プログラム開始
;==========================================================================

		org	0		;リセットベクタ
		goto	init
		org	4		;割り込みベクタ
		goto	interrupt

		org	h'08'

;==========================================================================
;		サブルーチンファイルのインクルード
;==========================================================================

		include		D:\Project\PIC\_sub\I2C_S_LCD.sub

;==========================================================================
;		I2C LCD（ AQM0802A の場合 ）表示用 メッセージ等
;==========================================================================

		; 表示位置テーブル（I2C LCD の DDRAM アドレス）
disp_tbl
		addwf	PCL,F
		;	0     1     2     3     4     5
		dt	h'00',h'01',h'03',h'04',h'06',h'07'
;		dt	h'40',h'41',h'43',h'44',h'46',h'47'

		; スタートメッセージ

start_msg	dt	"** Stop-",0
		dt	"Watch **",0
;			 01234567

		dt	"Ver ",ver_no,0
		dt	" by M.Y ",0
;			 01234567

		; 時刻設定メッセージ

time_set_msg	dt	"Time Set",0
initial_value	dt	"00:00:00",0
;			 01234567

		; ストップウオッチ・モード移行メッセージ

start_on_msg	dt	"Start On",0
;			"xx:xx:xx"
;			 01234567

		; メモリオーバーエラーメッセージ

mem_over_msg	dt	"Mem Over",0
;			"xx:xx:xx"
;			 01234567

		; メモリ内容表示メッセージ

mem_disp_msg	dt	"Mem Disp",0
;		     ←             →
		dt h'08',"DWN UP",h'07',0
;			 01234567

		; 番号テンプレート出力

number_msg	dt	"**    **",0
;			 01234567

;==========================================================================
;		初期化処理
;==========================================================================

init
		; PIC16F628A/PIC16F648A 初期設定

		bcf	STATUS,RP1
		bcf	STATUS,RP0	;バンク 0
		clrf	PORTA		;
		movlw	b'00000111'	;RA3-0 を Digital I/O
		movwf	CMCON		;CMCON の設定

		bsf	STATUS,RP0	;バンク 1
		movlw	b'00100000'	;RA5: 入力, RA4-0: 出力
       		movwf	TRISA		;ポートA の I/0 設定
       		movlw	b'10111110'	;RB7,5-1: 入力, RB6,0: 出力
       		movwf	TRISB		;ポートB の I/0 設定

		movlw	b'01001000'	;bit7:0:     プルアップ抵抗を使用
					;bit6:1:     割り込みパルスの立ち上がりで割り込み
					;bit5:0:     タイマに内部クロックを使用
					;bit4:0:     立ち上がりでカウントアップ
					;bit3=1:     プリスケーラをTMR0タイマーで使用しない
					;bit2-0=000: プリスケーラ 
		movwf	OPTION_REG	;OPTION_REG の設定

		bcf	PIE1,TMR1IE	;タイマー1 割り込み禁止

		bcf	STATUS,RP0	;バンク 0
		movlw	b'00001111'	;bit7-6:    未使用
					;bit5-4=00: プリスケーラ 1:1
					;bit3=1:    発振器を使用
					;bit2=1:    外部入力クロックに同期させない
					;bit1=1:    外部入力クロックを使う
					;bit0=1:    タイマー1 動作有効 
		movwf	T1CON		;T1CON (タイマー１制御用レジスタ）の設定

		movlw	b'11000000'	;bit7=1: GIE  全割り込み許可
					;bit6=1: PEIE 周辺割り込み許可
					;bit5=0: T0IE タイマー0 割り込み禁止
					;bit3=0: RBIE RB ポート変化割り込み禁止
		movwf	INTCON		;INTCON の設定

		; スタートメッセージの表示

		bcf	PORTA,_ledG	;LED(緑) 消灯
		bcf	PORTA,_ledR	;LED(赤) 消灯
		bcf	PORTA,_PWcntl	;LCD 電源 ON
		bsf	PORTA,SDA	;SDA="H"
		bsf	PORTA,SCL	;SCL="H"

		call	buzzer_pipo	;"ピポッ" ブザー音出力と LED(緑)点滅 (Total 260 mS)
		call	I2cLcd_Init	;I2C LCD (AQM0802A) の初期設定
		movlw	h'0c'		;表示オン／オフコントロール
		call	I2cLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク

		movlw	2
		movwf	lpcnt		;メッセージの表示回数
init01
;			[** Stop-]	;スタートメッセージ
;			[Watch **]
		Disp_I2cLcd	h'80',start_msg,1	;DDRAM のアドレスをセット(１行目先頭)
		Disp_I2cLcd	h'c0',         ,0	;DDRAM のアドレスをセット(２行目先頭)
		call	wait_1sec
		call	wait_1sec

;			[Ver x.xx]
;			[ by M.Y ]
		Disp_I2cLcd	h'80',         ,0	;DDRAM のアドレスをセット(１行目先頭)
		Disp_I2cLcd	h'c0',         ,0	;DDRAM のアドレスをセット(２行目先頭)
		call	wait_1sec
		call	wait_1sec

		decfsz	lpcnt,F		;メッセージの表示回数 = 終了 か？
		goto	init01		;No

		movlw	h'01'		;表示クリア
		call	I2cLcd_Cmd	;LCD へコマンドを出力
		call	wait_1sec
		call	wait_1sec
;		goto	time_set_mode	;時刻設定・モードへ移行

;==========================================================================
;		事前処理：現在時刻の設定（時刻設定・モード）
;==========================================================================

;	[スイッチ操作]
;		                           ←DWN     UP→
;		┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;		│●│   │●│   │●│   │●│   │●│
;		└─┘   └─┘   └─┘   └─┘   └─┘
;		SELECT    DOWN      UP      SET /   START /
;		                           ENABLE    GOAL

;				    SELECT スイッチ ON ..... ブリンク位置ポインタ + 1
;	START スイッチ 押しながら + SELECT スイッチ ON ..... ブリンク位置ポインタ - 1

;				    UP スイッチ ON     ..... ブリンク位置の値をインクリメント
;	START スイッチ 押しながら + UP スイッチ ON     ..... EEPROM へプリセット値を書き込み

;				    DOWN スイッチ ON   ..... ブリンク位置の値をデクリメント
;	START スイッチ 押しながら + DOWN スイッチ ON   ..... EEPROM からプリセット値を読み出し

;				    SET スイッチ ON    ..... ストップウオッチ・モードへ移行

time_set_mode
		; 各変数の初期設定とメッセージの表示

		clrf	bcd_hh_t	;時_BCD カウンタ (現在時刻用)
		clrf	bcd_mm_t	;分_BCD カウンタ
		clrf	bcd_ss_t	;秒_BCD カウンタ
		clrf	eep_cnt		;EEPROM 登録番号カウンタの初期設定
		clrf	stat_flg	;進行状態フラグの初期設定
		clrf	stat2_flg	;進行状態-2フラグの初期設定

tmset00		; tmset00: ストップウオッチ・モードからの戻り用ラベル

;			[Time Set]	;時刻設定メッセージ
		Disp_I2cLcd	h'80',time_set_msg,1	;DDRAM のアドレスをセット(１行目先頭)

		btfsc	stat_flg,7	;例外処理指示フラグ = 1 か？
		goto	tmset01		;Yes

;			[00:00:00]
		Disp_I2cLcd	h'c0',            ,0	;DDRAM のアドレスをセット(２行目先頭)

tmset01		call	buzzer_pipo2	;"ピポッピポッ" ブザー音出力と LED(緑)点滅 (Total 520 mS)
		movlw	h'0d'		;表示オン／オフコントロール
		call	I2cLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=1: ブリンク

		clrf	stat_flg	;進行状態フラグの初期設定
		clrf	dsp_point	;ブリンク位置 = 0 初期設定

		; 各スイッチの入力処理

tmset02		movf	dsp_point,W
		call	disp_tbl	;ブリンク位置の DDRAM アドレスを取得
		iorlw	h'c0'		;DDRAM のアドレスをセット(２行目)
		call	I2cLcd_Cmd	;I2C LCD へコマンドを出力

		btfss	PORTB,_swSEL	;SELECT スイッチ = ON か？
		call	select_switch	;Yes

		btfss	PORTB,_swUP	;UP スイッチ = ON か？
		call	up_switch	;Yes

		btfss	PORTB,_swDWN	;DOWN スイッチ = ON か？
		call	down_switch	;Yes

		btfsc	PORTB,_swSET	;SET スイッチ = ON か？
		goto	tmset02		;No
;
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTB,_swSET	;再度 SET スイッチ = ON か？
		goto	tmset02		;No

		movlw	h'0c'		;表示オン／オフコントロール
		call	I2cLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク

		bcf	stat2_flg,1	;スリープ時のビープ音抑止フラグの初期設定
		btfss	PORTB,_swSTA	;START スイッチ = ON か？
		bsf	stat2_flg,1	;Yes. スリープ時のビープ音抑止フラグ = 1

		btfss	PORTB,_swSET	;SET スイッチ = OFF か？
		goto	$ - 1		;No

		goto	main		;ストップウオッチ・モードへ移行

;--------------------------------------------------------------------------
;		SELECT スイッチの処理
;--------------------------------------------------------------------------

;	[スイッチ操作]
;				    SELECT スイッチ ON ..... ブリンク位置ポインタ + 1
;	START スイッチ 押しながら + SELECT スイッチ ON ..... ブリンク位置ポインタ - 1

select_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTB,_swSEL	;再度 SELECT スイッチ = ON か？
		goto	selsw06		;No
 
		movlw	h'24'
		subwf	bcd_hh_t,W	;時_BCD カウンタ - h'24'
		btfss	STATUS,C	;時_BCD カウンタ < h'24' か？
		goto	selsw03		;Yes

		; 時_BCD カウンタ >= h'24' のとき
		btfss	PORTB,_swSTA	;START/GOAL スイッチ = ON か？
		goto	selsw01		;Yes. (BACK 動作)

		movf	dsp_point,W
		btfsc	STATUS,Z	;dsp_point = 0 か？
		goto	selsw04		;Yes
		goto	selsw02		;No. Error

selsw01		movf	dsp_point,W
		btfss	STATUS,Z	;dsp_point = 0 か？
		goto	selsw05		;No
					;Yes. Error
		; エラー表示
selsw02		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	buzzer_bu	;"ブッ" ブザー音出力 (100 mS)
		bcf	PORTA,_ledR	;LED(赤) 消灯
		goto	selsw06		;Error

		; 時_BCD カウンタ < h'24' のとき
selsw03		btfss	PORTB,_swSTA	;START/GOAL スイッチ = ON か？
		goto	selsw05		;Yes. (BACK 動作)

selsw04		incf	dsp_point,F	;ブリンク位置ポインタ + 1
		movlw	5 + 1
		subwf	dsp_point,W	;dsp_point - (5 + 1)
		btfsc	STATUS,C	;dsp_point < (5 + 1) か？
		clrf	dsp_point	;No. ブリンク位置ポインタ = 0 初期設定
		goto	selsw06

selsw05		decf	dsp_point,F	;ブリンク位置ポインタ - 1
		incf	dsp_point,W
		movlw	5
		btfsc	STATUS,Z	;(dsp_point < 0) か？
		movwf	dsp_point	;Yes. ブリンク位置ポインタ = 5 初期設定

selsw06		btfss	PORTB,_swSEL	;SELECT スイッチ = OFF か？
		goto	$ - 1		;No

		return

;--------------------------------------------------------------------------
;		UP スイッチの処理
;--------------------------------------------------------------------------

;	[スイッチ操作]
;				    UP スイッチ ON     ..... ブリンク位置の値をインクリメント
;	START スイッチ 押しながら + UP スイッチ ON     ..... EEPROM へプリセット値を書き込み

;		0     1     2     3     4     5	 	 01 23 45
;		h'00',h'01',h'03',h'04',h'06',h'07'	"xx:xx:xx"
;		"HH"  "HL"  "MH"  "ML"  "SH"  "SL"	 01234567

up_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTB,_swUP	;再度 UP スイッチ = ON か？
		goto	upsw05		;No

		btfss	PORTB,_swSTA	;START スイッチ = ON か？
		goto	upsw03		;Yes

		; ブリンク位置の値をインクリメント

		rrf	dsp_point,W
		andlw	h'03'		;インデックス値
		addlw	bcd_hh_t	;+ BCD カウンタの先頭番地
		movwf	FSR		;間接アドレスの先頭番地の設定

		btfsc	dsp_point,0	;奇数 か？
		goto	upsw01		;Yes

		; 上位４ビットのとき

		movlw	h'10'
		addwf	INDF,F		;上位４ビット = インクリメント
		movlw	h'f0'
		andwf	INDF,W
		movwf	work		;退避

		movf	dsp_point,W
		movlw	h'20' + h'10'	;dsp_point = 0 の場合
		btfss	STATUS,Z	;dsp_point = 0 か？
		movlw	h'50' + h'10'	;No. dsp_point = 2 or 4 の場合

		subwf	work,W		;work - W
		movlw	h'0f'
		btfsc	STATUS,C	;work < W か？
		andwf	INDF,F		;No. 上位４ビット = '0' クリア

		swapf	INDF,W
		goto	upsw02

		; 下位４ビットのとき

upsw01		incf	INDF,F		;下位４ビット = インクリメント
		movlw	h'0f'
		andwf	INDF,W
		sublw	h'09'		;h'09' - W
		movlw	h'f0'
		btfss	STATUS,C	;W =< h'09' か？
		andwf	INDF,F		;No. 下位４ビット = '0' クリア
		movf	INDF,W

upsw02		andlw	h'0f'
		iorlw	h'30'		;数字に変換
		call	I2cLcd_Data	;I2C LCD へデータを１文字出力
		goto	upsw05

		; EEPROM へプリセット値を書き込み

upsw03		call	eeprom_write_xx	;EEPROM へプリセット値を書き込み
		btfsc	STATUS,C	;重複データ か？
		goto	upsw04		;Yes

		; 正常: "ポポッ" ブザー音出力と LED(赤)点滅 (Total 260 mS)
		call	buzzer_po	;"ポッ" ブザー音出力
		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	wait_30ms
		bcf	PORTA,_ledR	;LED(赤) 消灯
		call	buzzer_po	;"ポッ" ブザー音出力
		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	wait_30ms
		bcf	PORTA,_ledR	;LED(赤) 消灯
		goto	upsw05

		; 重複: "ブッブー" ブザー音出力と LED(赤)点灯 (Total 380 mS)
upsw04		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	buzzer_bu	;"ブッ" ブザー音出力
		bcf	PORTA,_ledR	;LED(赤) 消灯
		call	wait_30ms
		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	buzzer_buu	;"ブー" ブザー音出力
		bcf	PORTA,_ledR	;LED(赤) 消灯

upsw05		btfss	PORTB,_swUP	;UP スイッチ = OFF か？
		goto	$ - 1		;No

		return

;--------------------------------------------------------------------------
;		DOWN スイッチの処理
;--------------------------------------------------------------------------

;	[スイッチ操作]
;				    DOWN スイッチ ON   ..... ブリンク位置の値をデクリメント
;	START スイッチ 押しながら + DOWN スイッチ ON   ..... EEPROM からプリセット値を読み出し

;		0     1     2     3     4     5	 	 01 23 45
;		h'00',h'01',h'03',h'04',h'06',h'07'	"xx:xx:xx"
;		"HH"  "HL"  "MH"  "ML"  "SH"  "SL"	 01234567

down_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTB,_swDWN	;再度 DOWN スイッチ = ON か？
		goto	dwnsw08		;No

		btfss	PORTB,_swSTA	;START スイッチ = ON か？
		goto	dwnsw05		;Yes

		; ブリンク位置の値をデクリメント

		rrf	dsp_point,W
		andlw	h'03'		;インデックス値
		addlw	bcd_hh_t	;+ BCD カウンタの先頭番地
		movwf	FSR		;間接アドレスの先頭番地の設定

		btfsc	dsp_point,0	;奇数 か？
		goto	dwnsw02		;Yes

		; 上位４ビットのとき

		movlw	h'f0'
		andwf	INDF,W
		btfsc	STATUS,Z	;上位４ビット = 0 か？
		goto	dwnsw01		;Yes

		movlw	h'10'
		subwf	INDF,F		;上位４ビット = デクリメント
		swapf	INDF,W
		goto	dwnsw04

dwnsw01		movf	dsp_point,W
		movlw	h'20'		;dsp_point = 0 の場合
		btfss	STATUS,Z	;dsp_point = 0 か？
		movlw	h'50'		;No. dsp_point = 2 or 4 の場合
		addwf	INDF,F		;上位４ビット = '2' or '5' をセット
		swapf	INDF,W
		goto	dwnsw04

		; 下位４ビットのとき

dwnsw02		movlw	h'0f'
		andwf	INDF,W
		btfsc	STATUS,Z	;下位４ビット = 0 か？
		goto	dwnsw03		;Yes

		decf	INDF,F		;下位４ビット = デクリメント
		movf	INDF,W
		goto	dwnsw04

dwnsw03		movlw	h'09'
		addwf	INDF,F		;下位４ビット = '9' をセット
		movf	INDF,W

dwnsw04		andlw	h'0f'
		iorlw	h'30'		;数字に変換
		call	I2cLcd_Data	;I2C LCD へデータを１文字出力
		goto	dwnsw08

		; EEPROM からプリセット値を読み出し

dwnsw05		movlw	5
		subwf	eep_cnt,W	;登録番号 - 5
		btfss	STATUS,C	;登録番号 < 5 か？
		goto	dwnsw06		;Yes

		clrf	eep_cnt		;登録番号 = 0（初期値）
		clrf	bcd_hh		;時_BCD カウンタ
		clrf	bcd_mm		;分_BCD カウンタ
		clrf	bcd_ss		;秒_BCD カウンタ
		goto	dwnsw07

dwnsw06		movf	eep_cnt,W	;W = 登録番号
		call	eeprom_read	;EEPROM からプリセット値を読み出し
		incf	eep_cnt,F	;登録番号 + 1 更新

		movf	bcd_hh,W
		iorwf	bcd_mm,W
		iorwf	bcd_ss,W
		btfsc	STATUS,Z	;bcd_hh = bcd_mm = bcd_ss = 0 か？
		clrf	eep_cnt		;Yes. 登録番号 = 0（初期値）

dwnsw07		movf	bcd_hh,W	;時_BCD カウンタ
		movwf	bcd_hh_t
		movf	bcd_mm,W	;分_BCD カウンタ
		movwf	bcd_mm_t
		movf	bcd_ss,W	;秒_BCD カウンタ
		movwf	bcd_ss_t
		movlw	h'7f'		;全桁表示
		movwf	dspdgt_w
		movlw	h'c0'		;表示行指定 (２行目先頭)
		call	time_display	;I2C LCD への "HH:MM:SS" 表示

		; "ポポッ" ブザー音出力と LED(緑)点滅 (Total 260 mS)

		call	buzzer_po	;"ポッ" ブザー音出力
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	wait_30ms
		bcf	PORTA,_ledG	;LED(緑) 消灯
		call	buzzer_po	;"ポッ" ブザー音出力
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	wait_30ms
		bcf	PORTA,_ledG	;LED(緑) 消灯

dwnsw08		btfss	PORTB,_swDWN	;DOWN スイッチ = OFF か？
		goto	$ - 1		;No

		return

;--------------------------------------------------------------------------
;		設定用現在時刻のプリセット値を書き込み／読み出し
;--------------------------------------------------------------------------

		; EEPROM へ新データを書き込み
		;-----------------------------

;		; 登録番号 = 0 ～ 4 まで、all "0" データと重複データは書き込みを禁止
;		; 5 以上は 0 を削除、1 ～ 4 を 0 ～ 3 に移動、4 に新データを書き込み

eeprom_write_xx
		movf	eep_cnt,W
		movwf	work		;退避

		; 新データのチェック

		movlw	h'24'
		subwf	bcd_hh_t,W	;時_BCD カウンタ - h'24'
		btfsc	STATUS,C	;時_BCD カウンタ < h'24' か？
		goto	eepwr_05	;No.  Error（不当データ）, C = 1

		movf	bcd_hh_t,W
		iorwf	bcd_mm_t,W
		iorwf	bcd_ss_t,W
		bsf	STATUS,C	;C = 1
		btfsc	STATUS,Z	;bcd_hh_t = bcd_mm_t = bcd_ss_t = 0 か？
		goto	eepwr_05	;Yes. all "0" データは書き込みを中止, C = 1

		; 重複データのチェック

		clrf	eep_cnt		;登録番号 = 0（初期値）

eepwr_01	movf	eep_cnt,W	;W = 登録番号
		call	eeprom_read	;EEPROM からデータ読み出し

		movf	bcd_hh,W
		iorwf	bcd_mm,W
		iorwf	bcd_ss,W
		btfsc	STATUS,Z	;bcd_hh = bcd_mm = bcd_ss = 0（初期値）か？
		goto	eepwr_04	;Yes

		movf	bcd_hh,W
		xorwf	bcd_hh_t,W
		btfss	STATUS,Z	;bcd_hh = bcd_hh_t か？
		goto	eepwr_02	;No

		movf	bcd_mm,W
		xorwf	bcd_mm_t,W
		btfss	STATUS,Z	;bcd_mm = bcd_mm_t か？
		goto	eepwr_02	;No

		movf	bcd_ss,W
		xorwf	bcd_ss_t,W
		bsf	STATUS,C	;C = 1
		btfsc	STATUS,Z	;bcd_ss = bcd_ss_t か？
		goto	eepwr_05	;Yes. 重複データは書き込みを中止, C = 1

eepwr_02	incf	eep_cnt,F	;登録番号 + 1 更新
		movlw	5
		subwf	eep_cnt,W	;登録番号 - 5
		btfss	STATUS,C	;登録番号 < 5 か？
		goto	eepwr_01	;Yes

		; 既存 EEPROM データの移動（1 ～ 4 を 0 ～ 3 に移動）

		movlw	1
		movwf	eep_cnt		;登録番号 = 1（初期値）

eepwr_03	movf	eep_cnt,W	;W = 登録番号
		call	eeprom_read	;EEPROM からデータ読み出し

		decf	eep_cnt,W	;W = 登録番号 - 1
		call	eeprom_write	;EEPROM へデータ書き込み

		incf	eep_cnt,F	;登録番号 + 1 更新
		movlw	5
		subwf	eep_cnt,W	;登録番号 - 5
		btfss	STATUS,C	;登録番号 < 5 か？
		goto	eepwr_03	;Yes

		decf	eep_cnt,F	;登録番号 - 1 = 4 設定

		; 新データの登録

eepwr_04	movf	bcd_hh_t,W	;時_BCD カウンタ
		movwf	bcd_hh
		movf	bcd_mm_t,W	;分_BCD カウンタ
		movwf	bcd_mm
		movf	bcd_ss_t,W	;秒_BCD カウンタ
		movwf	bcd_ss

		movf	eep_cnt,W	;W = 登録番号
		call	eeprom_write	;EEPROM へデータ書き込み
		bcf	STATUS,C	;C = 0

eepwr_05	movf	work,W
		movwf	eep_cnt		;復帰
		return

;--------------------------------------------------------------------------

		; EEPROM へデータ書き込み
		;-------------------------
eeprom_write
;		; W reg = 登録番号（ 0 ～ 4 ）を入力

		bsf	STATUS,RP0	;バンク1
		movwf	EEADR		;登録番号 x 3
		addwf	EEADR,F		;
		addwf	EEADR,F		;
		movlw	eep_preset - eep_start
		addwf	EEADR,F		;該当登録番号の EEPROM の記録アドレスを設定

		bcf	STATUS,RP0	;バンク0
		movlw	bcd_hh		;BCD_カウンタ（ワーク）の先頭アドレスを
		movwf	FSR		;間接アドレスに設定
		movlw	3
		movwf	lpcnt		;ループカウンタ

eepwr01		movf	INDF,W		;BCD_カウンタを読み出し

		bsf	STATUS,RP0	;バンク 1
		movwf	EEDATA		;書き込みデータを設定
		bsf	EECON1,WREN	;書き込みイネーブル = ON
		movlw	h'55'
		movwf	EECON2		;h'55' を EECON2 に書き込む
		movlw	h'aa'
		movwf	EECON2		;h'aa' を EECON2 に書き込む
		bsf	EECON1,WR	;書き込み開始
		btfsc	EECON1,WR	;書き込み 終了か?
		goto	$ - 1		;No

		incf	EEADR,F		;記録アドレスの更新

		bcf	STATUS,RP0	;バンク 0
		incf	FSR,F		;間接アドレスの更新
		decfsz	lpcnt,F		;ループカウンタ - 1 = 0 か？
		goto	eepwr01		;No

		return

		; EEPROM からデータ読み出し
		;---------------------------
eeprom_read
;		; W reg = 登録番号（ 0 ～ 4 ）を入力

		bsf	STATUS,RP0	;バンク1
		movwf	EEADR		;登録番号 x 3
		addwf	EEADR,F		;
		addwf	EEADR,F		;
		movlw	eep_preset - eep_start
		addwf	EEADR,F		;該当登録番号の EEPROM の記録アドレスを設定

		bcf	STATUS,RP0	;バンク0
		movlw	bcd_hh		;BCD_カウンタ（ワーク）の先頭アドレスを
		movwf	FSR		;間接アドレスに設定
		movlw	3
		movwf	lpcnt		;ループカウンタ

eeprd01		bsf	STATUS,RP0	;バンク 1
		bsf	EECON1,RD	;読み出し制御 = ON
		movf	EEDATA,W	;データの読み出し
		incf	EEADR,F		;記録アドレスの更新

		bcf	STATUS,RP0	;バンク 0
		movwf	INDF		;BCD_カウンタ（ワーク）へ読み出し
		incf	FSR,F		;間接アドレスの更新
		decfsz	lpcnt,F		;ループカウンタ - 1 = 0 か？
		goto	eeprd01		;No

		return

;==========================================================================
;		メインプログラム（ストップウオッチ・モード）
;==========================================================================

;	 |      |                                                         |      |
;	 |      |←-----------------------------------------------SPLITn→|      |
;	 |      |←------------------------------------→|                |      |   ;スプリット（SPLIT）タイム
;	 |      |←-----------------------SPLIT2→|      |                |      |   ;スタートしてからゴールまでの途中経過時間
;	 |      |←------SPLIT1→|                |      |                |      |
;	 |      |                |                |      |                |      |
;	 |      |←----LAP1----→|←----LAP2----→|------|←----LAPn----→|      |   ;ラップ（LAP）タイム
;	 |      |                |                |      |                |      |   ;スタートからゴールまでの区間経過時間
;	 |─--─|────────|────────|─--─|────────|─--─|
;	SET    (1)              (1)              (1)----(1)              (2)--(1)or(2)
;	 ↑    START                                                    GOAL     ↑
;      （ストップウオッチ・モード開始）                                        （メモリ内容表示・モードへ移行）

;	[スイッチ操作]
;		                           ←DWN     UP→
;		┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;		│●│   │○│   │○│   │●│   │●│
;		└─┘   └─┘   └─┘   └─┘   └─┘
;		SELECT    DOWN      UP      SET /   START /
;		                           ENABLE    GOAL

;   (1) ENABLE スイッチ 押しながら + START スイッチ 通常のちょん押し   ..... START/LAP(SPLIT)
;   (2) ENABLE スイッチ 押しながら + START スイッチ ５～６秒以上長押し ..... GOAL

;	SELECT スイッチ 押しながら + START スイッチ 通常のちょん押し   ..... 時刻設定・モードへ戻る
;								   　　　　（ただし、それまでのスプリットタイム記録は無効になる）

		; 各変数の初期設定とメッセージの表示
main
		movlw	low (65536 - 32768)	;１秒毎に"タイマー１割り込み"をさせる
		movwf	TMR1L
		movlw	high (65536 - 32768)
		movwf	TMR1H
		bsf	STATUS,RP0	;バンク 1
		bsf	PIE1,TMR1IE	;タイマー1 割り込み許可
		bcf	STATUS,RP0	;バンク 0

main00		; main00: メモリ内容表示・モードからの戻り用ラベル

		clrf	stat_flg	;進行状態フラグの初期設定
		clrf	sleep_cnt	;スリープ移行時間カウンタの初期設定

main01		; main01: スリープモードからの復帰（ストップウオッチ動作前）用ラベル

;			[Start On]	;ストップウオッチ・モード移行メッセージ
;			[xx:xx:xx]
		Disp_I2cLcd	h'80',start_on_msg,1	;表示行指定 (１行目)

		btfsc	stat2_flg,0	;RB ポート変化割り込み記憶フラグ = 1 か？
		goto	main02		;Yes

		call	buzzer_pipo2	;"ピポッピポッ" ブザー音出力と LED(緑)点滅 (Total 520 mS)

main02		; main02: スリープモードからの復帰（ストップウオッチ動作中）、
		;         スリープモード前の通常ループ用ラベル

		; 経過時間（スプリットタイム）の表示 (１行目)

		bcf	stat2_flg,0	;RB ポート変化割り込み記憶フラグ = 0
		btfsc	stat_flg,4	;ラップタイム表示指示フラグ = 1 か？
		goto	main05		;Yes

		btfss	stat_flg,1	;経過時間更新フラグ = 1 か？
		goto	main03		;No

		movf	bcd_hh_s,W	;時_BCD カウンタ
		movwf	bcd_hh
		movf	bcd_mm_s,W	;分_BCD カウンタ
		movwf	bcd_mm
		movf	bcd_ss_s,W	;秒_BCD カウンタ
		movwf	bcd_ss
		movf	dspdgt_s,W	;経過時間用表示桁指定フラグ
		btfsc	stat_flg,5	;ラップタイム表示済みフラグ = 1 か？
		movlw	h'7f'		;Yes. 全桁表示
		movwf	dspdgt_w
		movlw	h'80'		;表示行指定 (１行目)
		call	time_display	;I2C LCD への "HH:MM:SS" 表示
		bcf	stat_flg,1	;経過時間更新フラグ = 0

		; 現在時刻の表示 (２行目)

main03		btfss	stat_flg,0	;現在時刻更新フラグ = 1 か？
		goto	main08		;No

		movf	bcd_hh_t,W	;時_BCD カウンタ
		movwf	bcd_hh
		movf	bcd_mm_t,W	;分_BCD カウンタ
		movwf	bcd_mm
		movf	bcd_ss_t,W	;秒_BCD カウンタ
		movwf	bcd_ss
		movf	dspdgt_t,W	;現在時刻用表示桁指定フラグ
		btfss	stat_flg,5	;ラップタイム表示済みフラグ = 1 か？
		goto	main04		;No

		bcf	stat_flg,5	;ラップタイム表示済みフラグ = 0
		movlw	h'7f'		;全桁表示

main04		movwf	dspdgt_w
		movlw	h'c0'		;表示行指定 (２行目)
		call	time_display	;I2C LCD への "HH:MM:SS" 表示
		bcf	stat_flg,0	;現在時刻更新フラグ = 0
		goto	main08

		; スプリット／ラップ番号の表示 (１行目)

main05		btfsc	stat_flg,5	;ラップタイム表示済みフラグ = 1 か？
		goto	main08		;Yes

;			[** xx **]
		call	split_no_disp	;スプリット／ラップ番号の表示

		; 区間経過時間（ラップタイム）の表示 (２行目)

		decf	split_cnt,W
		btfss	STATUS,Z	;スプリット番号カウンタ - 1 = 0 か？
		goto	main06		;No

		movf	bcd_hh_s,W	;今回 時_BCD カウンタ
		movwf	bcd_hh
		movf	bcd_mm_s,W	;今回 分_BCD カウンタ
		movwf	bcd_mm
		movf	bcd_ss_s,W	;今回 秒_BCD カウンタ
		movwf	bcd_ss
		goto	main07

main06		decf	split_cnt,F	;前回スプリット番号
		call	read_memory	;前回スプリットタイムの読み出し
		incf	split_cnt,F	;今回スプリット番号に復帰

		call	lap_time_calc	;ラップタイムの計算
		movf	bcd_hh_l,W	;時_BCD カウンタ
		movwf	bcd_hh
		movf	bcd_mm_l,W	;分_BCD カウンタ
		movwf	bcd_mm
		movf	bcd_ss_l,W	;秒_BCD カウンタ
		movwf	bcd_ss

main07		movlw	h'7f'		;全桁表示
		movwf	dspdgt_w	;表示桁指定フラグ
		movlw	h'c0'		;表示行指定 (２行目)
		call	time_display	;I2C LCD への "HH:MM:SS" 表示
		bsf	stat_flg,5	;ラップタイム表示済みフラグ = 1

		; START/GOAL スイッチの入力監視

main08		btfss	PORTB,_swSTA	;START スイッチ = ON か？
		call	start_switch	;Yes
		btfsc	stat_flg,7	;例外処理指示フラグ = 1 か？
		goto	tmset00		;Yes. 時刻設定・モードへ戻る

		btfss	stat_flg,3	;ストップウオッチ動作終了フラグ = 1 か？
		goto	main09		;No

		btfss	stat_flg,2	;ストップウオッチ動作中フラグ = 0 か？
		goto	mem_disp_mode	;Yes. メモリ内容表示・モードへ移行

		; スリープ移行時間の監視（60 x 1 秒）

main09		movlw	sleep_time	;スリープ移行までの時間
		subwf	sleep_cnt,W
		btfss	STATUS,C	;スリープ移行時間カウンタ >= sleep_time か？
		goto	main02		;No

		call	sleep_mode	;スリープモードに移行

		btfsc	stat_flg,2	;ストップウオッチ動作中フラグ = 1 か？
		goto	main10		;Yes

		bsf	stat_flg,0	;現在時刻更新フラグ = 1
		movlw	h'7f'		;全桁表示
		movwf	dspdgt_t	;現在時刻用表示桁指定フラグ
		goto	main01

main10		bsf	stat_flg,0	;現在時刻更新フラグ = 1
		bsf	stat_flg,1	;経過時間更新フラグ = 1
		movlw	h'7f'		;全桁表示
		movwf	dspdgt_t	;現在時刻用表示桁指定フラグ
		movwf	dspdgt_s	;経過時間用表示桁指定フラグ
		goto	main02

;--------------------------------------------------------------------------
;		スリープモードに移行とウェイクアップ
;--------------------------------------------------------------------------

sleep_mode
		call	buzzer_bu	;"ブッ" ブザー音出力 (Total 450 mS)
		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	wait_100ms
		bcf	PORTA,_ledR	;LED(赤) 消灯
		call	buzzer_buu	;"ブー" ブザー音出力

		bcf	PORTA,SDA	;SDA="L"
		bcf	PORTA,SCL	;SCL="L"
		bsf	PORTA,_PWcntl	;LCD 電源 OFF

		bcf	INTCON,RBIF	;RB ポート変化割り込みフラグをクリア ...（必須）
		bsf	INTCON,RBIE	;RB ポート変化割り込みを許可

sleep01		sleep			;スリープモード
		; 
		;			;wake up
		btfsc	stat2_flg,0	;RB ポート変化割り込み記憶フラグ = 1 か？
		goto	sleep02		;Yes

		; タイマー１割り込みのとき

		btfss	stat_flg,2	;ストップウオッチ動作中フラグ = 0 か？
		movf	dspdgt_t,W	;Yes.（現在時刻用）
		btfsc	stat_flg,2	;ストップウオッチ動作中フラグ = 1 か？
		movf	dspdgt_s,W	;Yes.（経過時間用）
		movwf	dspdgt_w	;ワーク
		btfss	dspdgt_w,3	;時刻用表示 "ML" 桁指定フラグ = 1 か？
		goto	sleep01		;No. 再度 sleep
					;スリープ中は１分間隔で以下の動作をする
		bsf	PORTA,_ledR	;LED(赤) 点灯
		btfss	stat2_flg,1	;スリープ時のビープ音抑止フラグ = 1 か？
		call	buzzer_pi	;No. "ピッ" ブザー音出力 (100 mS)
		btfsc	stat2_flg,1	;スリープ時のビープ音抑止フラグ = 1 か？
		call	wait_100ms	;Yes
		bcf	PORTA,_ledR	;LED(赤) 消灯
		goto	sleep01		;再度 sleep

		; RB ポート変化割り込みのとき

sleep02		bcf	PORTA,_PWcntl	;LCD 電源 ON
		bsf	PORTA,SDA	;SDA="H"
		bsf	PORTA,SCL	;SCL="H
		call	I2cLcd_Init	;I2C LCD (AQM0802A) の初期設定
		movlw	h'0c'		;表示オン／オフコントロール
		call	I2cLcd_Cmd	;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク

		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	buzzer_po	;"ポッ" ブザー音出力 (100 mS)
		bcf	PORTA,_ledG	;LED(緑) 消灯
		clrf	sleep_cnt	;スリープ移行時間カウンタの初期設定
		return

;--------------------------------------------------------------------------
;		I2C LCD への "HH:MM:SS" 表示
;--------------------------------------------------------------------------

;		0     1     2     3     4     5	 	 01 23 45
;		h'00',h'01',h'03',h'04',h'06',h'07'	"xx:xx:xx"
;		h'40',h'41',h'43',h'44',h'46',h'47'
;		"HH"  "HL"  "MH"  "ML"  "SH"  "SL"	 01234567

time_display
		movwf	work		;表示行指定 (１／２行目)
		rrf	dspdgt_w,F	;bit0:桁上がり指定ビットをパス
		movlw	6
		movwf	lpcnt		;表示位置ポインタの初期値

tdisp01		rrf	dspdgt_w,F	;"SL","SH","ML","MH","HL","HH" の順にチェック
		btfss	STATUS,C	;桁の指定 bit = 1 か？
		goto	tdisp02		;No

		decfsz	lpcnt,F		;表示位置ポインタ - 1 = 0 か？
		goto	tdisp01		;No

tdisp02		movf	lpcnt,W
		call	disp_tbl	;表示位置テーブル
		iorwf	work,W		;DDRAM のアドレスをセット
		call	I2cLcd_Cmd	;I2C LCD へコマンドを出力

		rrf	lpcnt,W
		andlw	h'03'		;インデックス値
		addlw	bcd_hh		;+ BCD カウンタの先頭番地
		movwf	FSR		;間接アドレスの先頭番地の設定

		btfsc	lpcnt,0		;奇数 か？
		goto	tdisp04		;Yes

tdisp03		swapf	INDF,W		;上位４ビット
		andlw	h'0f'
		iorlw	h'30'		;数字に変換
		call	I2cLcd_Data	;I2C LCD へデータを１文字出力
		incf	lpcnt,F		;表示位置ポインタ + 1

tdisp04		movf	INDF,W		;下位４ビット
		andlw	h'0f'
		iorlw	h'30'		;数字に変換
		call	I2cLcd_Data	;I2C LCD へデータを１文字出力
		incf	lpcnt,F		;表示位置ポインタ + 1
		incf	FSR,F		;間接アドレス + 1

		movlw	6
		subwf	lpcnt,W
		btfsc	STATUS,Z	;表示位置ポインタ = 6 か？
		goto	tdisp05		;Yes

		movlw	":"
		call	I2cLcd_Data	;I2C LCD へデータを１文字出力
		goto	tdisp03

tdisp05		return

;--------------------------------------------------------------------------
;		スプリット／ラップ番号の表示
;--------------------------------------------------------------------------

split_no_dispx
		movlw	h'01'		;クリアディスプレイ
		call	I2cLcd_Cmd	;I2C LCD へコマンドを出力
		call	wait_1ms	;1m 秒 ウェイト

split_no_disp
;			[** xx **]	; 番号テンプレート出力
		Disp_I2cLcd	h'80',number_msg,1	;表示行指定 (１行目)

		movlw	h'83'		;DDRAM のアドレスをセット
		call	I2cLcd_Cmd	;I2C LCD へコマンドを出力

		movf	split_cnt,W	;スプリット番号カウンタ
		call	bin8_dec2chr	;２桁の数字に変換
		movf	chr_wk2,W
		call	I2cLcd_Data	;I2C LCD へデータを１文字出力
		movf	chr_wk1,W
		call	I2cLcd_Data	;I2C LCD へデータを１文字出力
		return

;--------------------------------------------------------------------------

		; ８ビット（１バイト）数値を１０進数２桁の数字文字列に変換
bin8_dec2chr
		movwf	bin_wk		;変換する値
		movlw	chr_wk1 + 1
		movwf	FSR		;間接アドレス
		call	dev_10		;最下位変換
		call	dev_10
;		call	dev_10		;最上位変換（本来は３桁（255まで）に変換）
		return

		; １０で除算
dev_10
		movlw	8
		movwf	lpcnt		;ループカウンタ
		clrf	work		;余りの初期値

dev01		bcf	STATUS,C	;キャリフラグのクリア
		rlf	bin_wk,F
		rlf	work,F
		movlw	h'f6'		;-10
		addwf	work,W
		btfsc	STATUS,C
		movwf	work
		btfsc	STATUS,C
		incf	bin_wk,F
		decfsz	lpcnt,F		;ループカウンタ - 1 = 0 か？
		goto	dev01		;No

		decf	FSR,F		;間接アドレス - 1
		movf	work,W		;余り
		iorlw	h'30'		;数字に変換
		movwf	INDF
		return

;--------------------------------------------------------------------------
;		START/GOAL スイッチの処理
;--------------------------------------------------------------------------

;	[スイッチ操作]

;	ENABLE スイッチ 押しながら + START スイッチ 通常のちょん押し   ..... START/LAP(SPLIT)
;	ENABLE スイッチ 押しながら + START スイッチ ５～６秒以上長押し ..... GOAL

;	SELECT スイッチ 押しながら + START スイッチ 通常のちょん押し   ..... 時刻設定・モードへ戻る
;								   　　　　（ただし、それまでのスプリットタイム記録は無効になる）

start_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTB,_swSTA	;再度 START スイッチ = ON か？
		goto	stasw11		;No

		btfss	PORTB,_swSEL	;SELECT スイッチ = ON か？
		goto	stasw05		;Yes

		btfsc	PORTB,_swEN	;ENABLE スイッチ = ON か？
		goto	stasw11		;No

		btfsc	stat_flg,2	;ストップウオッチ動作中フラグ = 1 か？
		goto	stasw01		;Yes

		; ストップウオッチ動作の開始

;			[00:00:00]	;スプリットタイムの初期値を表示
;			[xx:xx:xx]
		Disp_I2cLcd	h'80',initial_value,1	;１行目表示

		clrf	bcd_hh_s	;時_BCD カウンタ (経過時間用)
		clrf	bcd_mm_s	;分_BCD カウンタ
		clrf	bcd_ss_s	;秒_BCD カウンタ
		clrf	split_cnt	;スプリット番号カウンタの初期設定
		bsf	stat_flg,2	;ストップウオッチ動作中フラグ = 1

		call	dl_mi_so_dh	;"ド ミ ソ ドー" ブザー音出力と LED(緑)(赤)交互点滅 (Total 1150 mS)
		goto	stasw06		;開始時は長押し時間監視と書き込みをしない

		; ゴール後のスイッチ操作

stasw01		btfss	stat_flg,3	;ストップウオッチ動作終了フラグ = 1 か？
		goto	stasw02		;No
					;Yes
		bcf	stat_flg,2	;ストップウオッチ動作中フラグ = 0
		goto	stasw08

		; 経過時間（スプリットタイム）を書き込み

stasw02		movlw	h'80'
		movwf	hold_cnt	;長押し時間監視カウンタを有効
		call	write_memory	;経過時間（スプリットタイム）を書き込み
		btfss	STATUS,C	;メモリオーバーエラー か？
		goto	stasw07		;No

		; メモリオーバーエラーの表示 (２行目)

;			[xx:xx:xx]
;			[Mem Over]	;メモリオーバーエラーメッセージ
		Disp_I2cLcd	h'c0',mem_over_msg,1	;２行目表示

		movlw	4
		movwf	lpcnt		;メッセージの表示回数

stasw03		call	buzzer_bu	;"ブッ" ブザー音出力 (100 mS)
		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	wait_30ms
		bcf	PORTA,_ledR	;LED(赤) 消灯
		decfsz	lpcnt,F		;メッセージの表示回数 = 終了 か？
		goto	stasw03		;No

		movlw	20
		movwf	lpcnt		;LED(赤) 点滅の回数

stasw04		call	wait_100ms
		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	wait_30ms
		bcf	PORTA,_ledR	;LED(赤) 消灯
		decfsz	lpcnt,F		;LED(赤) 点滅の回数 = 終了 か？
		goto	stasw04		;No

		bsf	stat_flg,3	;ストップウオッチ動作終了フラグ = 1
		goto	stasw06

		; 例外処理-1：（事前処理：時刻設定・モードへ復帰）

stasw05		bsf	STATUS,RP0	;バンク 1
		bcf	PIE1,TMR1IE	;タイマー1 割り込み禁止
		bcf	STATUS,RP0	;バンク 0
		bsf	stat_flg,7	;例外処理指示フラグ = 1

stasw06		btfss	PORTB,_swSTA	;START スイッチ = OFF か？
		goto	$ - 1		;No
		goto	stasw10
;;
		; 経過時間（スプリットタイム）のメモリ書き込み正常

stasw07		call	buzzer_po	;"ポッ" ブザー音出力 (Total 260 mS)
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	wait_30ms
		bcf	PORTA,_ledG	;LED(緑) 消灯
		call	buzzer_po	;"ポッ" ブザー音出力
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	wait_30ms
		bcf	PORTA,_ledG	;LED(緑) 消灯

		; START スイッチの OFF 監視

stasw08		movlw	h'85'		;フラグ + カウント値
		subwf	hold_cnt,W
		btfss	STATUS,C	;長押し時間監視カウンタ >= h'85' か？
		goto	stasw09		;No

		bsf	stat_flg,3	;Yes. ストップウオッチ動作終了フラグ = 1
		clrf	hold_cnt	;長押し時間監視カウンタを無効
		call	dh_so_mi_dl	;"ド ソ ミ ドー" ブザー音出力と LED(緑)(赤)交互点滅 (Total 1150 mS)

		; スプリットタイムの進み（約 5 秒）表示を戻す
		call	read_memory	;最終スプリットタイムの読み出し
		movf	bcd_hh,W	;時_BCD カウンタ
		movwf	bcd_hh_s
		movf	bcd_mm,W	;分_BCD カウンタ
		movwf	bcd_mm_s
		movf	bcd_ss,W	;秒_BCD カウンタ
		movwf	bcd_ss_s
		bsf	stat_flg,1	;経過時間更新フラグ = 1

stasw09		btfss	PORTB,_swSTA	;START スイッチ = OFF か？
		goto	stasw08		;No

		btfss	stat_flg,2	;ストップウオッチ動作中フラグ = 1 か？
		goto	stasw10		;No

		bsf	stat_flg,4	;ラップタイム表示指示フラグ = 1
		bcf	stat_flg,5	;ラップタイム表示済みフラグ = 0
		movlw	3		;（約 3 秒）
		movwf	laptim_cnt	;ラップタイム表示時間カウンタの初期設定

stasw10		clrf	hold_cnt	;長押し時間監視カウンタを無効
		clrf	sleep_cnt	;スリープ移行時間カウンタの初期設定

stasw11		return

;--------------------------------------------------------------------------
;		経過時間（スプリットタイム）を書き込み
;--------------------------------------------------------------------------

write_memory
		; バンク１へ書き込みのための手続き（ MAX 26 ）

	;	bcf	STATUS,RP1	;バンク 0  （直接アドレス指定用）
	;	bcf	STATUS,RP0
	;	bcf	STATUS,IRP	;バンク 0,1（間接アドレス指定用）

		movf	bcd_hh_s,W	;時_BCD カウンタ
		movwf	bcd_hh		;
		movf	bcd_mm_s,W	;分_BCD カウンタ
		movwf	bcd_mm		;
		movf	bcd_ss_s,W	;秒_BCD カウンタ
		movwf	bcd_ss		;

		movlw	26
		subwf	split_cnt,W
		btfsc	STATUS,C	;スプリット番号カウンタ >= 26 か？
		goto	wrmem01		;Yes

		movlw	time_mem1	;タイムデータ１の先頭アドレス
		movwf	FSR		;間接アドレス
		movf	split_cnt,W
		goto	wrmem03

		; バンク２へ書き込みのための手続き（ MAX 16 or 26 ）

#ifdef x16f628a				;バンク 2 の GPR サイズが異なるため
wrmem01		movlw	26 + 16		;GPR = 48 バイト
#else
wrmem01		movlw	26 + 26		;GPR = 80 バイト
#endif
		subwf	split_cnt,W
		btfsc	STATUS,C	;スプリット番号カウンタ >= 26 + 16 or 26 + 26 か？
		goto	wrmem02		;Yes

		bsf	STATUS,IRP	;バンク 2,3（間接アドレス指定用）
		movlw	low time_mem2	;タイムデータ２の先頭アドレス
		movwf	FSR		;間接アドレス
		movlw	26
		subwf	split_cnt,W
		goto	wrmem03

		; バンク０へ書き込みのための手続き（ MAX ((w_save - time_mem0) / 3) ）

#ifdef x16f628a
wrmem02		movlw	26 + 16 + ((w_save - time_mem0) / 3)
#else
wrmem02		movlw	26 + 26 + ((w_save - time_mem0) / 3)
#endif
		subwf	split_cnt,W
		btfsc	STATUS,C	;スプリット番号カウンタ >= 26 + 16 + ((w_save - time_mem0) / 3) or 
					;			   26 + 26 + ((w_save - time_mem0) / 3) か？
		goto	wrmem04		;Yes. error

		movlw	time_mem0	;タイムデータ０の先頭アドレス
		movwf	FSR		;間接アドレス
#ifdef x16f628a
		movlw	26 + 16
#else
		movlw	26 + 26
#endif
		subwf	split_cnt,W

		; スプリットタイムを各バンクへ書き込み（バンク１,２,０とも共通）

wrmem03		addwf	FSR,F		;x 3
		addwf	FSR,F
		addwf	FSR,F		;新データの先頭書き込みアドレス

		movf	bcd_hh,W	;時_BCD カウンタ
		movwf	INDF		;時_BCD カウンタ 書き込み
		incf	FSR,F		;間接アドレス + 1

		movf	bcd_mm,W	;分_BCD カウンタ
		movwf	INDF		;分_BCD カウンタ 書き込み
		incf	FSR,F		;間接アドレス + 1

		movf	bcd_ss,W	;秒_BCD カウンタ
		movwf	INDF		;秒_BCD カウンタ 書き込み
		bcf	STATUS,IRP	;バンク 0,1（間接アドレス指定用）... バンク２のとき用

		incf	split_cnt,F	;スプリット番号カウンタ + 1
		bcf	STATUS,C

wrmem04		return

;--------------------------------------------------------------------------
;		経過時間（スプリットタイム）を読み出し
;--------------------------------------------------------------------------

read_memory
		; バンク１から読み出しのための手続き

		movlw	26 + 1
		subwf	split_cnt,W
		btfsc	STATUS,C	;スプリット番号カウンタ < (26 + 1) か？
		goto	rdmem01		;No

		movlw	time_mem1	;タイムデータ１の先頭アドレス
		movwf	FSR		;間接アドレス
		decf	split_cnt,W	;スプリット番号カウンタ - 1
		goto	rdmem03

		; バンク２から読み出しのための手続き

#ifdef x16f628a
rdmem01		movlw	26 + 16 + 1
#else
rdmem01		movlw	26 + 26 + 1
#endif
		subwf	split_cnt,W
		btfsc	STATUS,C	;スプリット番号カウンタ < (26 + 16 + 1) or (26 + 26 + 1) か？
		goto	rdmem02		;No

		bsf	STATUS,IRP	;バンク 2,3（間接アドレス指定用）
		movlw	low time_mem2	;タイムデータ２の先頭アドレス
		movwf	FSR		;間接アドレス
		movlw	26 + 1
		subwf	split_cnt,W	;スプリット番号カウンタ - (26 + 1)
		goto	rdmem03

		; バンク０から読み出しのための手続き

rdmem02		movlw	time_mem0	;タイムデータ０の先頭アドレス
		movwf	FSR		;間接アドレス
#ifdef x16f628a
		movlw	26 + 16 + 1
#else
		movlw	26 + 26 + 1
#endif
		subwf	split_cnt,W	;スプリット番号カウンタ - (26 + 26 + 1) or (26 + 16 + 1)

		; 各バンクからスプリットタイムの読み出し（バンク１,２,０とも共通）

rdmem03		addwf	FSR,F		;x 3
		addwf	FSR,F
		addwf	FSR,F		;データの先頭読み出しアドレス

		movf	INDF,W		;時_BCD カウンタ 読み出し
		movwf	bcd_hh		;時_BCD カウンタ

		incf	FSR,F		;間接アドレス + 1
		movf	INDF,W		;分_BCD カウンタ 読み出し
		movwf	bcd_mm		;分_BCD カウンタ

		incf	FSR,F		;間接アドレス + 1
		movf	INDF,W		;秒_BCD カウンタ 読み出し
		movwf	bcd_ss		;秒_BCD カウンタ

		bcf	STATUS,IRP	;バンク 0,1（間接アドレス指定用）... バンク２のとき用
		return

;--------------------------------------------------------------------------
;     区間経過時間（ラップタイム bcd_xx_l = bcd_xx_s - bcd_xx）の計算
;--------------------------------------------------------------------------

;	 入力： bcd_ss_s, bcd_mm_s, bcd_hh_s ...  今回のスプリットタイム
;		bcd_ss,   bcd_mm,   bcd_hh   ...  前回のスプリットタイム
;	 出力： bcd_ss_l, bcd_mm_l, bcd_hh_l ...（今回の）  ラップタイム

;      （もっと簡潔な方法があるかもしれないが、とりあえず次の方法で計算）

lap_time_calc
		; bcd_ss_s (今回 秒_BCD カウンタ) - bcd_ss (前回 秒_BCD カウンタ)

		movf	bcd_ss_s,W	;今回の下位4ビット
		andlw	h'0f'
		movwf	work
		movf	bcd_ss,W	;前回の下位4ビット
		andlw	h'0f'

		subwf	work,F		;(1)
		btfsc	STATUS,C	;work >= 0 か?
		goto	laptim01	;Yes. C bit = 1

		movlw	h'0a'
		addwf	work,F		;補正
		bcf	STATUS,C	;(1) の C bit = 0 引継ぎ

laptim01	movf	work,W
		movwf	bcd_ss_l	;ラップタイム 秒_BCD 下位4ビット
;
		swapf	bcd_ss_s,W	;今回の上位4ビット
		andlw	h'0f'
		movwf	work
		swapf	bcd_ss,W	;前回の上位4ビット
		andlw	h'0f'
		btfss	STATUS,C	;(1) の結果: C bit = 0 か?
		addlw	1		;Yes

		subwf	work,F		;(2)
		btfsc	STATUS,C	;work >= 0 か?
		goto	laptim02	;Yes. C bit = 1

		movlw	h'06'
		addwf	work,F		;補正
		bcf	STATUS,C	;(2) の C bit = 0 引継ぎ

laptim02	swapf	work,W
		iorwf	bcd_ss_l,F	;ラップタイム 秒_BCD 上位4ビット

		; bcd_mm_s (今回 分_BCD カウンタ) - bcd_mm (前回 分_BCD カウンタ)

		movf	bcd_mm_s,W	;今回の下位4ビット
		andlw	h'0f'
		movwf	work
		movf	bcd_mm,W	;前回の下位4ビット
		andlw	h'0f'
		btfss	STATUS,C	;(2) の結果: C bit = 0 か?
		addlw	1		;Yes

		subwf	work,F		;(3)
		btfsc	STATUS,C	;work >= 0 か?
		goto	laptim03	;Yes. C bit = 1

		movlw	h'0a'
		addwf	work,F		;補正
		bcf	STATUS,C	;(3) の C bit = 0 引継ぎ

laptim03	movf	work,W
		movwf	bcd_mm_l	;ラップタイム 分_BCD 下位4ビット
;
		swapf	bcd_mm_s,W	;今回の上位4ビット
		andlw	h'0f'
		movwf	work
		swapf	bcd_mm,W	;前回の上位4ビット
		andlw	h'0f'
		btfss	STATUS,C	;(3) の結果: C bit = 0 か?
		addlw	1		;Yes

		subwf	work,F		;(4)
		btfsc	STATUS,C	;work >= 0 か?
		goto	laptim04	;Yes. C bit = 1

		movlw	h'06'
		addwf	work,F		;補正
		bcf	STATUS,C	;(4) の C bit = 0 引継ぎ

laptim04	swapf	work,W
		iorwf	bcd_mm_l,F	;ラップタイム 分_BCD 上位4ビット

		; bcd_hh_s (今回 時_BCD カウンタ) - bcd_hh (前回 時_BCD カウンタ)

		movf	bcd_hh_s,W	;今回の下位4ビット
		andlw	h'0f'
		movwf	work
		movf	bcd_hh,W	;前回の下位4ビット
		andlw	h'0f'
		btfss	STATUS,C	;(4) の結果: C bit = 0 か?
		addlw	1		;Yes

		subwf	work,F		;(5)
		btfsc	STATUS,C	;work >= 0 か?
		goto	laptim05	;Yes. C bit = 1

		movlw	h'0a'
		btfsc	bcd_hh_s,5	;上位4ビット = 2 か?
		movlw	h'04'		;Yes
		addwf	work,F		;補正
		bcf	STATUS,C	;(5) の C bit = 0 引継ぎ

laptim05	movf	work,W
		movwf	bcd_hh_l	;ラップタイム 時_BCD 下位4ビット
;
		swapf	bcd_hh_s,W	;今回の上位4ビット
		andlw	h'0f'
		movwf	work
		swapf	bcd_hh,W	;前回の上位4ビット
		andlw	h'0f'
		btfss	STATUS,C	;(5) の結果: C bit = 0 か?
		addlw	1		;Yes

		subwf	work,F		;(6)
		btfsc	STATUS,C	;work >= 0 か?
		goto	laptim06	;Yes. C bit = 1

		movlw	h'03'
		addwf	work,F		;補正
;		bcf	STATUS,C	;(6) の C bit = 0 引継ぎ

laptim06	swapf	work,W
		iorwf	bcd_hh_l,F	;ラップタイム 時_BCD 上位4ビット
		return

;--------------------------------------------------------------------------

;   （参考）	;	 10	0000.1010
		;	  9	0000.1001
		;	  8	0000.1000
		;	  7	0000.0111
		;	  6	0000.0110
		;	  5	0000.0101
		;	  4	0000.0100
		;	  3	0000.0011
		;	  2	0000.0010
		;	  1 	0000.0001
		;	  0	0000.0000
		;	 -1	1111.1111
		;	 -2	1111.1110
		;	 -3	1111.1101
		;	 -4	1111.1100
		;	 -5	1111.1011
		;	 -6	1111.1010
		;	 -7	1111.1001
		;	 -8	1111.1000
		;	 -9	1111.0111
		;	-10	1111.0110

;==========================================================================
;	事後処理：記録データの読み出しと表示（メモリ内容表示・モード）
;==========================================================================

;	[スイッチ操作]
;		                           ←DWN     UP→
;		┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
;		│●│   │○│   │○│   │●│   │●│
;		└─┘   └─┘   └─┘   └─┘   └─┘
;		SELECT    DOWN      UP      SET /   START /
;		                           ENABLE    GOAL

;					    UP→  スイッチ ON ..... 次のデータを表示
;					    ←DWN スイッチ ON ..... 前のデータを表示
;	SELECT スイッチ 押しながら + START（UP→）スイッチ ON ..... ストップウオッチ・モードへ戻る

mem_disp_mode
;			[Mem Disp]	; メモリ内容表示メッセージ
;		       [←DWN UP→]
		Disp_I2cLcd	h'80',mem_disp_msg,1	;DDRAM のアドレスをセット(１行目先頭)
		Disp_I2cLcd	h'c0',            ,0	;DDRAM のアドレスをセット(２行目先頭)

		call	buzzer_pipo2	;"ピポッピポッ" ブザー音出力と LED(緑)点滅 (Total 520 mS)

		movf	split_cnt,W	;スプリット番号カウンタ
		movwf	split_cntx	;スプリット番号カウンタ退避用
		clrf	split_cnt	;スプリット番号カウンタの初期設定
		bcf	stat_flg,6	;スイッチ入力有りフラグ = 0

		; 各スイッチの入力処理

memdsp01	btfss	PORTB,_rdUP	;UP→ スイッチ = ON か？
		call	rd_up_switch	;Yes
		btfsc	stat_flg,7	;例外処理指示フラグ = 1 か？
		goto	main00		;Yes. ストップウオッチ・モードへ戻る

		btfss	PORTB,_rdDWN	;←DWN スイッチ = ON か？
		call	rd_dwn_switch	;Yes

		btfsc	stat_flg,6	;スイッチ入力有りフラグ = 1 か？
		goto	memdsp02	;Yes

		; スリープ移行時間の監視（60 x 1 秒）

		movlw	sleep_time	;スリープ移行までの時間
		subwf	sleep_cnt,W
		btfsc	STATUS,C	;スリープ移行時間カウンタ >= sleep_time か？
		goto	memdsp05	;Yes

		btfss	stat2_flg,2	;現在時刻表示指示フラグ = 1 か？
		goto	memdsp01	;No
		goto	memdsp07	;Yes

;--------------------------------------------------------------------------

		; スプリットタイムの読み出し（今回 = split_cnt）

memdsp02	bcf	stat2_flg,2	;現在時刻表示指示フラグ = 0
		call	wait_100ms	;100m 秒間表示
		call	read_memory	;今回のスプリットタイムの読み出し

		decf	split_cnt,W	;先頭番号 (= 1) か？
		btfsc	STATUS,Z	;スプリット番号カウンタ - 1 = 0 か？
		goto	memdsp03	;Yes

		; スプリット（SPLIT）タイムの表示 (１行目)

		movf	bcd_hh,W	;ラップタイムの計算のために必要
		movwf	bcd_hh_s	;今回 時_BCD カウンタ（スプリットタイム）
		movf	bcd_mm,W
		movwf	bcd_mm_s	;今回 分_BCD カウンタ
		movf	bcd_ss,W
		movwf	bcd_ss_s	;今回 秒_BCD カウンタ

memdsp03	movlw	h'7f'		;全桁表示
		movwf	dspdgt_w	;表示桁指定フラグ
		movlw	h'80'		;DDRAM のアドレスをセット
		call	time_display	;I2C LCD への "HH:MM:SS" 表示

		decf	split_cnt,W	;先頭番号 (= 1) か？
		btfsc	STATUS,Z	;スプリット番号カウンタ - 1 = 0 か？
		goto	memdsp04	;Yes

		; スプリットタイムの読み出し（前回 = split_cnt - 1）とラップタイムの計算

		decf	split_cnt,F	;スプリット番号カウンタ - 1 :前の値に更新
		call	read_memory	;前回のスプリットタイムの読み出し
		incf	split_cnt,F	;スプリット番号カウンタ + 1 :元の値に復帰

		call	lap_time_calc	;ラップタイムの計算（bcd_xx_l = bcd_xx_s - bcd_xx）

		; ラップ（LAP）タイムの表示 (２行目)

		movf	bcd_hh_l,W	;時_BCD カウンタ（ラップタイム）
		movwf	bcd_hh
		movf	bcd_mm_l,W	;分_BCD カウンタ
		movwf	bcd_mm
		movf	bcd_ss_l,W	;秒_BCD カウンタ
		movwf	bcd_ss

memdsp04	movlw	h'7f'		;全桁表示
		movwf	dspdgt_w	;表示桁指定フラグ
		movlw	h'c0'		;DDRAM のアドレスをセット
		call	time_display	;I2C LCD への "HH:MM:SS" 表示

		bcf	stat_flg,6	;スイッチ入力有りフラグ = 0
		goto	memdsp01

;--------------------------------------------------------------------------

		; スリープモードに移行とウェイクアップ後の処理

memdsp05	call	sleep_mode	;スリープモードに移行

;			[Mem Disp]	; メモリ内容表示メッセージ
		Disp_I2cLcd	h'80',mem_disp_msg,1	;DDRAM のアドレスをセット(１行目先頭)

		bcf	stat2_flg,0	;RB ポート変化割り込み記憶フラグ = 0
		call	wait_100ms	;チャッタリング吸収

memdsp06	movf	PORTB,W
		andlw	h'30'		;UP→ or ←dwn スイッチ
		xorlw	h'30'
		btfss	STATUS,Z	;どちらかのスイッチ入力有り か？
		goto	memdsp06	;Yes

		bsf	stat2_flg,2	;現在時刻表示指示フラグ = 1
		bsf	stat2_flg,3	;現在時刻初回表示フラグ = 1

		; 現在時刻の表示 (２行目)

memdsp07	btfss	stat_flg,0	;現在時刻更新フラグ = 1 か？
		goto	memdsp01	;No

		movf	bcd_hh_t,W	;時_BCD カウンタ
		movwf	bcd_hh
		movf	bcd_mm_t,W	;分_BCD カウンタ
		movwf	bcd_mm
		movf	bcd_ss_t,W	;秒_BCD カウンタ
		movwf	bcd_ss

		movf	dspdgt_t,W	;現在時刻用表示桁指定フラグ
		btfsc	stat2_flg,3	;現在時刻初回表示フラグ = 1 か？
		movlw	h'7f'		;Yes. 全桁表示
		movwf	dspdgt_w
		movlw	h'c0'		;表示行指定 (２行目)
		call	time_display	;I2C LCD への "HH:MM:SS" 表示

		bcf	stat2_flg,3	;現在時刻初回表示フラグ = 0
		bcf	stat_flg,0	;現在時刻更新フラグ = 0
		goto	memdsp01

;--------------------------------------------------------------------------
;		UP→ スイッチの処理
;--------------------------------------------------------------------------

;	[スイッチ操作]
;					    UP→  スイッチ ON ..... 次のデータを表示
;	SELECT スイッチ 押しながら + START（UP→）スイッチ ON ..... ストップウオッチ・モードへ戻る

rd_up_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTB,_rdUP	;再度 UP→ スイッチ = ON か？
		goto	rdusw05		;No

		btfss	PORTB,_swSEL	;SELECT スイッチ = ON か？
		goto	rdusw03		;Yes

		movf	split_cnt,W
		btfsc	STATUS,Z	;スプリット番号カウンタ = 0 か？
		goto	rdusw01		;Yes. 初回のみ

		incf	split_cnt,F	;スプリット番号カウンタ + 1
		incf	split_cntx,W	;スプリット番号カウンタ退避用 + 1
		subwf	split_cnt,W
		btfss	STATUS,C	;スプリット番号カウンタ < スプリット番号カウンタ退避用 + 1 か？
		goto	rdusw02		;Yes

rdusw01		movlw	1
		movwf	split_cnt	;スプリット番号カウンタ = 1 に初期設定

;			[** xx **]
rdusw02		call	split_no_dispx	;スプリット／ラップ番号の表示
		goto	rdusw04

		; 例外処理-2：（ストップウオッチ・モードへ復帰）

rdusw03		movf	bcd_hh_t,W	;時_BCD カウンタ
		movwf	bcd_hh
		movf	bcd_mm_t,W	;分_BCD カウンタ
		movwf	bcd_mm
		movf	bcd_ss_t,W	;秒_BCD カウンタ
		movwf	bcd_ss
		movlw	h'7f'		;全桁表示
		movwf	dspdgt_w
		movlw	h'c0'		;表示行指定 (２行目)
		call	time_display	;I2C LCD への "HH:MM:SS" 現在時刻の表示
		bsf	stat_flg,7	;例外処理指示フラグ = 1

rdusw04		btfss	PORTB,_rdUP	;UP→ スイッチ = OFF か？
		goto	$ - 1		;No

		bsf	stat_flg,6	;スイッチ入力有りフラグ = 1
		clrf	sleep_cnt	;スリープ移行時間カウンタの初期設定

rdusw05		return

;--------------------------------------------------------------------------
;		←DWN スイッチの処理
;--------------------------------------------------------------------------

;	[スイッチ操作]
;					    ←DWN スイッチ ON ..... 前のデータを表示

rd_dwn_switch
		call	wait_30ms	;チャッタリング吸収
		btfsc	PORTB,_rdDWN	;再度 ←DWN スイッチ = ON か？
		goto	rddsw03		;No

		movf	split_cnt,W
		btfsc	STATUS,Z	;スプリット番号カウンタ = 0 か？
		goto	rddsw01		;Yes. 初回のみ

		decf	split_cnt,F
		btfss	STATUS,Z	;スプリット番号カウンタ - 1 = 0 か？
		goto	rddsw02		;No

rddsw01		movf	split_cntx,W
		movwf	split_cnt	;スプリット番号カウンタ = スプリット番号カウンタ退避用 に初期設定

;			[** xx **]
rddsw02		call	split_no_dispx	;スプリット／ラップ番号の表示

		btfss	PORTB,_rdDWN	;←DWN スイッチ = OFF か？
		goto	$ - 1		;No

		bsf	stat_flg,6	;スイッチ入力有りフラグ = 1
		clrf	sleep_cnt	;スリープ移行時間カウンタの初期設定

rddsw03		return

;==========================================================================
;		アラーム（ブザー）音出力ルーチン
;==========================================================================

		; "ピッ" ブザー音出力 (100 mS)
buzzer_pi
		Sound_M		f_soh, pi_tim
	;;	return

		; "ポッ" ブザー音出力 (100 mS)
buzzer_po
		Sound_M		f_do2, po_tim
	;;	return

		; "ブッ" ブザー音出力 (100 mS)
buzzer_bu
		Sound_M		f_do, bu_tim
	;;	return

		; "ブー" ブザー音出力 (250 mS)
buzzer_buu
		Sound_M		f_do, buu_tim
	;;	return
;
		; "ド" ブザー音出力 (200 mS)
buzzer_dl
		Sound_M		f_doh, dms_tim
	;;	return

		; "ミ" ブザー音出力 (200 mS)
buzzer_mi
		Sound_M		f_mih, dms_tim
	;;	return

		; "ソ" ブザー音出力 (200 mS)
buzzer_so
		Sound_M		f_soh, dms_tim
	;;	return

		; "ド" ブザー音出力 (200 mS)
buzzer_dh
		Sound_M		f_do2, dms_tim
	;;	return

		; ブザー音出力コントロール
buzzer_control
		movwf	wt2cnt		;退避
		movlw	256 - 200	;4 / 8MHz * 200 = 100 μS
		movwf	TMR0
		movf	wt2cnt,W	;復帰
		bsf	INTCON,T0IE	;bit5(T0IE)=1: タイマー０割り込み許可
		call	wait_xxms	;入力 W: 音長（ループカウンタ）
		bcf	INTCON,T0IE	;bit5(T0IE)=0: タイマー０割り込み禁止
		return

buzzer_control2
		movwf	wt3cnt		;退避
		movlw	256 - 200	;4 / 8MHz * 200 = 100 μS
		movwf	TMR0
		movf	wt3cnt,W	;復帰
		bsf	INTCON,T0IE	;bit5(T0IE)=1: タイマー０割り込み許可
		call	wait_xxms	;入力 W: 音長（ループカウンタ）
		movf	wt3cnt,W	;復帰
		call	wait_xxms	;入力 W: 音長（ループカウンタ）
		bcf	INTCON,T0IE	;bit5(T0IE)=0: タイマー０割り込み禁止
		return

;--------------------------------------------------------------------------

		; "ピポッピポッ" ブザー音出力 (Total 520 mS)

		; (main) → (buzzer_pipo2) → (buzzer_pipo) → (buzzer_pi) → (buzzer_control) → (wait_xxms)
		;        (1)               (2)              (3)            (-)                 (4)		
		;        → (interrupt) → (bcd_ssmmhh_inc) → (inc_bcd)
		;        (5)            (6)                 (7)
buzzer_pipo2
		call	buzzer_pipo	;"ピポッ" ブザー音出力

		; "ピポッ" ブザー音出力と LED(緑)点滅 (Total 260 mS)
buzzer_pipo
		call	buzzer_pi	;"ピッ" ブザー音出力
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	wait_30ms
		bcf	PORTA,_ledG	;LED(緑) 消灯
		call	buzzer_po	;"ポッ" ブザー音出力
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	wait_30ms
		bcf	PORTA,_ledG	;LED(緑) 消灯
		return

		;ストップウオッチ動作開始: 
		;"ド ミ ソ ドー" ブザー音出力と LED(緑)(赤)交互点滅 (Total 1150 mS)
dl_mi_so_dh
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	buzzer_dl	;"ド" ブザー音出力
		bcf	PORTA,_ledG	;LED(緑) 消灯
		call	wait_50ms
		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	buzzer_mi	;"ミ" ブザー音出力
		bcf	PORTA,_ledR	;LED(赤) 消灯
		call	wait_50ms
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	buzzer_so	;"ソ" ブザー音出力
		bcf	PORTA,_ledG	;LED(緑) 消灯
		call	wait_50ms
		bsf	PORTA,_ledR	;LED(赤) 点灯
		Sound_M2	f_do2, dms_tim	;"ドー" ブザー音出力
		bcf	PORTA,_ledR	;LED(赤) 消灯
		return

		;ストップウオッチ動作終了: 
		;"ド ソ ミ ドー" ブザー音出力と LED(緑)(赤)交互点滅 (Total 1150 mS)
dh_so_mi_dl
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	buzzer_dh	;"ド" ブザー音出力
		bcf	PORTA,_ledG	;LED(緑) 消灯
		call	wait_50ms
		bsf	PORTA,_ledR	;LED(赤) 点灯
		call	buzzer_so	;"ソ" ブザー音出力
		bcf	PORTA,_ledR	;LED(赤) 消灯
		call	wait_50ms
		bsf	PORTA,_ledG	;LED(緑) 点灯
		call	buzzer_mi	;"ミ" ブザー音出力
		bcf	PORTA,_ledG	;LED(緑) 消灯
		call	wait_50ms
		bsf	PORTA,_ledR	;LED(赤) 点灯
		Sound_M2	f_doh, dms_tim	;"ドー" ブザー音出力
		bcf	PORTA,_ledR	;LED(赤) 消灯
		return

;==========================================================================
;		ウェイト・ルーチン (8 MHz)
;==========================================================================

		; 100μ秒 ウェイトルーチン
wait_100us
		movlw	39		;1
		movwf	wt1cnt		;1
wu01		goto	$+1		;2
		decfsz	wt1cnt,F	;1,2
		goto	wu01		;2,0	1+1+(2+1+2)*38+(2+2+0)=196
;		goto	$+1		;2
		return			;2	196+2=198
					;Total	198/8MHz*4 = 99 μS = 100 μS = 0.1 mS

		; 30m 秒 ウェイトルーチン
wait_30ms
		movlw	30
		goto	wait_xxms

		; 50m 秒 ウェイトルーチン
wait_50ms
		movlw	50
		goto	wait_xxms

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100
		goto	wait_xxms

		; 200m 秒 ウェイトルーチン
wait_200ms
		movlw	200
		goto	wait_xxms

		; 1m 秒 ウェイトルーチン
wait_1ms
		movlw	1

		; xx m 秒（ 1m 秒 x W ）ウェイトルーチン
wait_xxms
		movwf	wt2cnt		;1

w1m01		movlw	221		;1
		movwf	wt1cnt		;1

w1m02		goto	$ + 1		;2
		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt1cnt,F	;1,2
		goto	w1m02		;2,0	(2+2+2+1+2)*220+(2+2+2+2+0)=1988

		nop			;1
		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt2cnt,F	;1,2
		goto	w1m01		;2,0	(1+1+1988+1+2+2+1+2)*(W-1)+(1+1+1988+1+2+2+2+0)=1998*W-1

		return			;2	1+(1998*W-1)+2=1998*W+2
					;Total	(1998*W+2)/8MHz*4 = (999*W + 1) μS

		; 500m 秒 ウェイトルーチン
wait_500ms
		movlw	5
		goto	w1s01

		; 1 秒 ウェイトルーチン
wait_1sec
		movlw	10
w1s01		movwf	wt3cnt

w1s02		call	wait_100ms
		decfsz	wt3cnt,F
		goto	w1s02
		return

;==========================================================================
;		割り込み処理
;==========================================================================

interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		swapf	STATUS,W
		movwf	s_save		;STATUS レジスタの保存
		movf	PCLATH,W
		movwf	p_save		;PCLATH レジスタの保存
		movf	FSR,W
		movwf	f_save		;FSR レジスタの保存

		btfsc	INTCON,T0IF	;タイマー０割り込み か？
		goto	int_tmr0	;Yes

		btfsc	PIR1,TMR1IF	;タイマー１割り込み か？
		goto	int_tmr1	;Yes

		btfsc	INTCON,RBIF	;RB ポート変化割り込み か？
		goto	int_rb		;Yes
		goto	int_end		;(Illegal interrupt)

		; RB ポート変化割り込み処理

int_rb		bcf	INTCON,RBIF	;RB ポート変化割り込みフラグをクリア
		bcf	INTCON,RBIE	;RB ポート変化割り込みを禁止
		clrf	sleep_cnt	;スリープ移行時間カウンタの初期設定
		bsf	stat2_flg,0	;RB ポート変化割り込み記憶フラグ = 1
		goto	int_end

		; タイマー０割り込み処理（ 100μ秒毎に割り込み: ブザー音出力時のみ ）

;						f		t = 1 / f
;f_do2		equ	 956		;ド(1046.52 Hz)		0.0009 55  5479111723
;f_soh		equ	1276		;ソ (784.00 Hz)		0.0012 75  5102040816
;f_mih		equ	1517		;ミ (659.26 Hz)		0.0015 16  8522282559
;f_doh		equ	1911		;ド (523.26 Hz)		0.0019 11  0958223445
;f_so		equ	2551		;ソ (392.00 Hz)		0.0025 51  0204081633
;f_mi		equ	3034		;ミ (329.63 Hz)		0.0030 33  7044565118
;f_do		equ	3822		;ド (261.63 Hz)		0.0038 22  1916446891
;								     |  |
;							   (100μS 桁)  (1μS 桁)

int_tmr0	bcf	INTCON,T0IF	;タイマー０割り込みフラグをクリア
		decfsz	t0_work,F	;t0_work - 1 = 0 か？
		goto	int02		;No

		movf	const_low,W	;音階用分周定数 low
		movwf	t0_work
					;(4/8MHz) * (1+1+2) * (const_low) = 2μS * (const_low)
int01		nop			;1
		decfsz	t0_work,F	;1,2	t0_work - 1 = 0 か？
		goto	int01		;2,0	No

		movlw	1 << _BZ	;対象ビットをセット
		xorwf	PORTB,F		;出力をビット反転

		movf	const_high,W	;音階用分周定数 high
		movwf	t0_work

int02		movlw	256 - 200	;4 / 8MHz * 200 = 100 μS
		movwf	TMR0
		goto	int_end

		; タイマー１割り込み処理（ 1 秒毎に割り込み ）

int_tmr1	bcf	PIR1,TMR1IF	;タイマ１割り込みフラグをクリア

		movlw	low (65536 - 32768)
		movwf	TMR1L
		movlw	high (65536 - 32768)
		movwf	TMR1H

		; 現在時刻の管理
		movlw	bcd_ss_t	;（現在時刻用） 秒_BCD カウンタの番地
		call	ssmmhh_inc	;時、分、秒_BCD カウンタのインクリメント
		movf	dspdigit,W
		movwf	dspdgt_t	;現在時刻用表示桁指定フラグ
		bsf	stat_flg,0	;現在時刻更新フラグ = 1

		; スリープ移行時間カウンタの更新
		incf	sleep_cnt,F

		; 経過時間（スプリットタイム）の管理
		btfss	stat_flg,2	;ストップウオッチ動作中フラグ = 1 か？
		goto	int_end		;No

		btfsc	stat_flg,3	;ストップウオッチ動作終了フラグ = 1 か？
		goto	int11		;Yes

		movlw	bcd_ss_s	;（経過時間用） 秒_BCD カウンタの番地
		call	ssmmhh_inc	;時、分、秒_BCD カウンタのインクリメント
		movf	dspdigit,W
		movwf	dspdgt_s	;経過時間用表示桁指定フラグ
		bsf	stat_flg,1	;経過時間更新フラグ = 1

		; START スイッチの長押し時間監視カウンタの更新
		btfsc	hold_cnt,7	;長押し時間監視カウンタ = 有効 か？
		incf	hold_cnt,F	;Yes. 長押し時間監視カウンタ + 1

		; ラップタイム表示時間の監視（約 3 秒）
int11		btfsc	stat_flg,4	;ラップタイム表示指示フラグ = 1 か？
		decfsz	laptim_cnt,F	;Yes. ラップタイム表示時間カウンタ - 1 = 0 か？
		goto	int_end		;No

		bcf	stat_flg,4	;ラップタイム表示指示フラグ = 0

		; 割り込み処理の終了

int_end		movf	f_save,W
		movwf	FSR		;FSR レジスタの復帰
		movf	p_save,W
		movwf	PCLATH		;PCLATH レジスタの復帰
		swapf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie			;割り込みからの復帰	

;--------------------------------------------------------------------------
;		時、分、秒_BCD カウンタのインクリメント
;--------------------------------------------------------------------------

		;	dspdigit: bit6: "HH" 桁の指定
		;		  bit5: "HL" 桁の指定
		;		  bit4: "MH" 桁の指定
		;		  bit3: "ML" 桁の指定
		;		  bit2: "SH" 桁の指定
		;		  bit1: "SL" 桁の指定
		;		  bit0:  桁上がり指定

ssmmhh_inc
		movwf	FSR		;秒_BCD カウンタの番地をセット
		clrf	dspdigit	;表示桁指定フラグの初期設定
		bsf	dspdigit,1	;表示桁指定フラグ = "SL" 桁の指定
		call	inc_bcd		;秒 bcd_ss BCDインクリメント
		btfss	dspdigit,0	;桁上がり指定 = 1 か？
		return			;No

		bsf	dspdigit,2	;表示桁指定フラグ = "SH" 桁の指定
		movlw	h'60'
		subwf	INDF,W
		btfss	STATUS,C	;bcd_ss >= h'60' か？
		return			;No

		bsf	dspdigit,3	;表示桁指定フラグ = "ML" 桁の指定
		clrf	INDF		;bcd_ss = h'00'
		decf	FSR,F		;間接アドレス - 1
		call	inc_bcd		;分 bcd_mm BCDインクリメント
		btfss	dspdigit,0	;桁上がり指定 = 1 か？
		return			;No

		bsf	dspdigit,4	;表示桁指定フラグ = "MH" 桁の指定
		movlw	h'60'
		subwf	INDF,W
		btfss	STATUS,C	;bcd_mm >= h'60' か？
		return			;No

		bsf	dspdigit,5	;表示桁指定フラグ = "HL" 桁の指定
		clrf	INDF		;bcd_mm = h'00'
		decf	FSR,F		;間接アドレス - 1
		call	inc_bcd		;時 bcd_hh BCDインクリメント

;;	bugfix:  Ver. 1.01   2020/06/02  時間のカウント誤りを修正（次の２行を削除）
;;		btfss	dspdigit,0	;桁上がり指定 = 1 か？
;;		return			;No

		bsf	dspdigit,6	;表示桁指定フラグ = "HH" 桁の指定
		movlw	h'24'
		subwf	INDF,W
		btfss	STATUS,C	;bcd_hh >= h'24' か？
		return			;No

		clrf	INDF		;bcd_hh = h'00'
		return		

;--------------------------------------------------------------------------

		; BCD インクリメント
inc_bcd
		bcf	dspdigit,0	;表示桁指定フラグ (桁上がり指定 = 0)
		incf	INDF,F		;BCD カウンタ + 1
		movf	INDF,W
		andlw	h'0f'		;下位4ビット
		sublw	h'0a'
		btfss	STATUS,Z	;下位4ビット = h'0a' = d'10' か？
		return			;No

		bsf	dspdigit,0	;表示桁指定フラグ (桁上がり指定 = 1)
		movlw	h'06'
		addwf	INDF,F		;下位4ビット = 0, 上位4ビット = + 1
		return

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'2100'

eep_start	de	"Copyright (C) 2020 by M.Yamamoto"

		de	h'ff'

		; 現在時刻設定のプリセット値の格納位置

eep_preset	de	h'00',h'00',h'00'	;┐
		de	h'00',h'00',h'00'	;│初期値
		de	h'00',h'00',h'00'	;│
		de	h'00',h'00',h'00'	;│格納を 5 個に制限
		de	h'00',h'00',h'00'	;┘

;==========================================================================

		end			;プログラムの終了
