| ホーム |     私の電子工作作品集

199. 多機能携帯デジタル時計

[ 初公開日:2023年12月1日 ]

 本機は携帯使用を想定した多機能のデジタル時計で、現在時刻(年、月、日、曜日、AM/PM、時、分、秒)を表示する時計機能、2種類(詳細測定、長時間測定)のストップウオッチ機能、2種類(インターバル、ウィークリー)のタイマー機能の他、 メンテナンス用途としての現在時刻の設定機能などを有しています。

 長時間の携帯使用をするために、電源には 18650 リチウムイオン電池を採用しました。 そして、本機ではリアルタイムクロック(RTC)モジュールを搭載(バックアップ用のバッテリーも搭載)してあるため、リチウムイオン電池の消耗などで電源が切れたときはもちろん、 本機の不使用時の長時間の電源断にも、安定した時刻の継続が期待できます。


 本機の「現在時刻の表示」機能や「ストップウオッチ(長時間)」機能などでは、長時間に亘る使用が予想されるため、一定時間スイッチの入力がない場合には自動的に LCD の電源を切り、本機の PIC をスリープ状態にさせて電池の消耗を抑えるようにしています。

■ 回路図 ■

*注.  入力ポート RB2, RB3, RB5, RB6, RB7 は、内部プルアップ機能を ON にして使用。 また、SLEEP 中には それらのポート に状態変化割り込み機能を使用。

電源回路の補足説明

 上の回路図では、電源のリチウムイオン電池が POWER スイッチと直結されているように描かれていますが、実際の回路( プリント基板パターン図 (部品面) を参照)では、電池とスイッチとの間には、次の図のように "TP4056 充電モジュール" を挟んで配線をし、リチウムイオン電池を過放電(2.4V)、過電流から保護をするようにしています。


 私は生セルタイプの 18650 リチウムイオン電池を使用することが多くなるため、安全面からもこのような保護回路は必須です。 "TP4056 充電モジュール" については、私の別ページ "197. 18650 リチウムイオン電池充電器" の TP4056 リチウムイオン電池充電モジュール の項で、詳述をしているのでそちらを参考にしてください。

 このモジュールは名前からも分かるように "充電モジュール" なので、本機でもその機能を使用するようにしています。 上写真の左側にある Micro USB コネクタから +5V を供給します。 このときの注意として 充電中は POWER スイッチを OFF にしておく必要があり ます。

 また、私の手持ちの関係で "TP4056 充電モジュール" には、上写真のように表面実装の Micro USB タイプを使用しましたが、使用時の外力には弱く容易にモジュール基板から剥がれてしまうことも予測されるため、新たに購入をされる方は価格が若干高くはなりますが、 Type-C の USB コネクタを使用したモジュールも存在するので、後者の方がスルーホールでがっちりと取り付けられていて安心なので、そちらをお勧めします。

| 回路図 (MultifuncDigitalClock.CE3) | ページトップ |

■ リアルタイムクロックモジュール( DS3231 For PI )■

 約3年ほど以前に5個セットで購入をしたアマゾンでは最もポピュラーな、RTC IC DS3231 と EEPROM の AT24C32 が搭載された RTC モジュール の、手持ちの残り数が僅かとなってきたので 以前から再購入を考えていました。

 しかし、この RTC モジュールは最近では価格が最も高騰しているものの1つで、あまりにも馬鹿げた値段なのでとても再購入をする気にはならず躊躇をしていたところ、この RTC モジュールとは異なった "DS3231 For PI" という、次の写真のような RTC モジュールを、 あるとき、比較的安価に販売しているショップを見つけ、どのようなものかと数個を試し買いしてみました。(ところが、商品が到着して1か月ほどが経った後になって、このショップでも他のショップと同様に高騰をしてしまいました。)


 写真のように驚くほど小さなもの(実測: 13.5 x 13.5 x 高さ 12.5 mm)で、DS3231 の他には、2個のプルアップ用のチップ抵抗、パスコン用のチップコンデンサ、スポット溶接がされた電極に直接ハンダ付けがされていて簡単に交換ができないコイン電池、 5P のピンソケットが一体となっています。 前出の RTC モジュールのように、EEPROM の AT24C32 は搭載されていませんが、どうせ使用する予定は私にはないので構いません。

 名前からも分かるように、この RTC モジュールは Raspberry Pi 用に作られたものらしいのですが、PIC であっても使用することは可能なので問題はありませんが、ただし、この RTC モジュールには次の左回路図のように、SDA, SCL の2本のインタフェース線しか 外部に引き出されていないので、右回路図のように SQW も外部に引き出すように簡単な改造が必要です。 SQW 信号を使用して割り込みで処理をした方が、プログラムの作成では有利になります。


 丁度うまいことに、5P のピンソケットの内1つのピンが未使用 ( NC ) となっているので、この NC ピンに DS3231 の SQW (3 ピン) を接続して、下写真の(赤矢印)のように外部に引き出しました。 そして、SQW ピンには 回路図 に示すようにプルアップ抵抗が必要で、実際の取り付けは プリント基板パターン図 (部品面) を参考にしてください。


 この RTC モジュールで一番問題となるのは、上述のように、コイン電池がハンダ付けされていて簡単には交換をすることができない、という点でしょうか。 コイン電池の寿命がいつ頃やってくるか分かりませんが、そのときにどうするかはそのときに考えるとして、 取り敢えずこのまま使用してみることにします。

| ページトップ |

■ ケース外観と内部の様子 ■

右側面側から見た様子 左側面側から見た様子
前側面側から見た様子 裏面を見た様子

以下は外観6面写真です。

後側面
左側面 正面(上面) 右側面
前側面
背面(下面) 天地を逆にした写真

上蓋を開いてケース内部を見た様子 撮る角度を少し変えてもう1枚
現在時刻を表示している様子 本機の電源の 18650 リチウムイオン電池を充電中の様子

| ページトップ |

■ 機能概要と使用法 ■

  • 本機は、携帯使用を想定した多機能のデジタル時計で、現在時刻(年、月、日、曜日、AM/PM、時、分、秒)を表示する時計機能、2種類(詳細測定、長時間測定)のストップウオッチ機能、2種類(インターバル、ウィークリー)のタイマー機能の他、 メンテナンス用途としての現在時刻の設定機能などを有する。

  • 携帯使用をするために、電源には 18650 リチウムイオン電池を採用している。 そして、本機ではリアルタイムクロック(RTC)モジュールを搭載(バックアップ用のバッテリーも搭載)してあるため、リチウムイオン電池の消耗などで電源が切れたときはもちろん、 本機の不使用時の長時間の電源断にも、安定した時刻の継続が期待できる。

  • また、本機には 18650 リチウムイオン電池のための充電機能も内蔵しているので、USB 端子から + 5 V 電源を供給すれば電池の充電も可能である。 ただし、本機では充電中には本機の電源スイッチを切っておく必要があり、 充電しながらの連続使用はできない。

  • なお、後述の 1:「現在時刻の表示」機能4:「ストップウオッチ(長時間)」機能「5:記録内容の表示」機能 の3機能については、長時間に亘る使用が予想されることもあって、 一定時間スイッチの入力指示がない場合には、自動的に LCD の電源を切り、本機の PIC をスリープ状態にさせて電池の消耗を抑えるようにしている。

  • さて、本機の電源スイッチをオンにすると、"ピポッ" と開始アラーム音とともに LED (緑) を点滅表示した後、LCD 画面にも次の開始メッセージが交互に2秒間ずつ連続2回表示される。
      			[ Multifun ]				[ Ver x.xx ]
      			[ DigClock ]				[  by M.Y  ]
      

  • その後1秒間の空白をおいた後、リアルタイムクロック( RTC )モジュールの状態がチェックされ、異常がなかった場合には、後述の 1:「現在時刻の表示」機能 に実行が移されて時計機能を開始し、 LCD 画面に現在時刻(年、月、日、曜日、AM/PM、時、分、秒)を表示する。

  • 一方、本機に初めて電源を入れたときや、バックアップ用バッテリーを交換したときなどに、次のエラーメッセージが LCD 画面に表示されるとともに、"ブッブー" アラーム音の出力と LED (赤) が点灯される。
      			[ RTC Err! ]	..... DS3231 RTC エラーメッセージ
      			[  Init?_  ]	..... ユーザのスイッチ応答待ち
      

  • ユーザはエラーメッセージの確認をしてバッテリーの交換などの処置を行った後、すべてのタクトスイッチの内のどれかを押して応答をする。

  • すると、リアルタイムクロック( RTC )モジュールが初期設定され、エラーフラグがクリアされるとともに、年月日、時分秒が RTC モジュールをプログラミングしたときの初期値、 "2022/01/01"、"00:00:00" に設定がされて時計機能を開始し、 LED (赤) は消灯される。

  • しかし、表示時刻は現在のリアルな時刻とは異なっているので、一旦、後述の 「メニューの選択」機能 に戻ってから 8:「現在時刻の設定」機能 を選択して、 リアルな現在時刻に設定をし直す必要がある。

  • 次の図は、本機におけるスイッチ操作と各機能間の遷移の関係だけを図に表したもので、(XXX) で示す各スイッチを操作することで各機能間を移動する。 (XXX) + (XXX) と表現されているものは、+ 印の左側スイッチを押しながら 右側スイッチをちょんと押すことを表している。(なお、各機能内でのスイッチ操作については、以降で説明をするそれぞれの機能の項を参照のこと)
        	[ スイッチ操作と各メニュー項目(機能)間との遷移図 ]
        
        		                                               ENABLE   START/
        		Start                         ZERO    TMODE    /ALARM    GOAL
        		┌─┐   ┌─┐    ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
        		│□│   │○│     │○│   │○│   │○│   │○│   │○│
        		└□┘   └─┘     └─┘   └─┘   └─┘   └─┘   └─┘
        		 Stop    CLEAR       EXIT     DOWN      UP      LEFT     RIGHT
        
        			スイッチ省略名	 (EXT): EXIT
        					 (DWN): DOWN
        					  (UP): UP
        					 (LEF): LEFT
        					 (RIG): RIGHT
        					 (ZER): ZERO
        					 (MOD): TIME MODE
        					  (EN): ENABLE
        					 (STA): START/GOAL
        					 (CLR): CLEAR
        
        					 * 印 : 3秒以上の長押し
        
        	 (電源 ON)─────────────┐
        	                                      │
        	                                      ↓
        	┏━━━━━┓                  ┏━━━━━┓                    ┏━━━━━┓
        	┃          ┃ (EXT)    menu=1  ┃          ┃ (EN) + (EXT)       ┃          ┃
        	┃ メニュー ┃────────→┃ 現在時刻 ┃───────┐    ┃ スリープ ┃
        	┃          ┃        │        ┃          ┃              │    ┃          ┃
        	┃  の選択  ┃    ┌─│───→┃  の表示  ┃ (EXT)        │    ┃  モード  ┃
        	┃          ┃    │  │        ┃          ┃───┐      │    ┃          ┃
        	┗━━━━━┛    │  │        ┗━━━━━┛      │      │    ┗━━━━━┛
        	      ↑          │  │            ↑  │   (自動) │      │ 3分    ↑  │
        	      │          │  │            │  └─────│───│────┘  │ (ZER) or (MOD) or
        	      │          │  │            │              │      │        ↑  │ (EXT) or (EN)
        	      │          │  │            └───────│───│────│─┘
        	      │          │  │                            │      │        │  │
        	      └─────│─│──────────────┘      │        │  │
        	      ↑          │  │                                    │        │  │
        	      │          │  │        ┏━━━━━┓              │        │  │
        	      │          │  │        ┃          ┃              │        │  │
        	      │          │  │menu=2  ┃ ストップ ┃ (EXT)        │        │  │
        	      │          │  └───→┃ ウオッチ ┃───┐      │        │  │
        	      │          │  │        ┃  (詳細)  ┃      │      │        │  │
        	      │          │  │        ┃          ┃      │      │        │  │
        	      │          │  │        ┗━━━━━┛      │      │        │  │
        	      │          │  │                            │      │        │  │
        	      └─────│─│──────────────┘      │        │  │
        	      ↑          │  │                                    │        │  │
        	      │          │  │        ┏━━━━━┓              │        │  │
        	      │          │  │        ┃          ┃              │        │  │
        	      │          │  │menu=3  ┃ インター ┃ (EXT)        │        │  │
        	      │          │  └───→┃バル(間隔)┃───┐      │        │  │
        	      │          │  │        ┃ タイマー ┃      │      │        │  │
        	      │          │  │        ┃          ┃      │      │        │  │
        	      │          │  │        ┗━━━━━┛      │      │        │  │
        	      │          │  │                            │      │        │  │
        	      └─────│─│──────────────┘      │        │  │
        	      ↑          │  │                                    │        │  │
        	      │          │  │        ┏━━━━━┓              │        │  │
        	      │          │  │        ┃          ┃ (EN) + (EXT) │        │  │
        	      │          │  │menu=4  ┃ ストップ ┃─────┐  │        │  │
        	      │          │  └───→┃ ウオッチ ┃          │  │        │  │
        	      │          │  │        ┃ (長時間) ┃ (EXT)    │  │        │  │
        	      │          │  │        ┃          ┃───┐  │  │        │  │
        	      │          │  │        ┗━━━━━┛      │  │  │        │  │
        	      │          │  │            ↑  │   (自動) │  │  │ 1分    │  │ (EXT) or
        	      │          │  │            │  └─────│─│─│────┘  │ (EN)  or
        	      │          │  │            │              │  │  │        ↑  │ (STA)
        	      │          │  │            └───────│─│─│────│─┘
        	      │          │  │                            │  │  │        │  │
        	      └─────│─│──────────────┘  │  │        │  │
        	      ↑          │  │                                │  │        │  │
        	      │          │  │        ┏━━━━━┓          │  │        │  │
        	      │          │  │        ┃          ┃←────┘  │        │  │
        	      │          │  │menu=5  ┃ 記録内容 ┃              │        │  │
        	      │          │  └───→┃          ┃              │        │  │
        	      │          │  │        ┃  の表示  ┃ (EXT)        │        │  │
        	      │          │  │        ┃          ┃───┐      │        │  │
        	      │          │  │        ┗━━━━━┛      │      │        │  │
        	      │          │  │            ↑  │   (自動) │      │ 1分    │  │ (EXT) or
        	      │          │  │            │  └─────│───│────┘  │ (RIG) or
        	      │          │  │            │              │      │            │ (LEF)
        	      │          │  │            └───────│───│──────┘
        	      │          │  │                            │      │
        	      └─────│─│──────────────┘      │
        	      ↑          │  │                                    │
        	      │          │  │        ┏━━━━━┓              │
        	      │          │  │        ┃          ┃ (EN) + (EXT) │
        	      │          │  │menu=6  ┃週間タイマ┃─────┐  │
        	      │          │  └───→┃ ーの時刻 ┃          │  │
        	      │          │  │        ┃   設定   ┃ (EXT*) ..│..│..... 設定終了
        	      │          │  │        ┃          ┃───┐  │  │
        	      │          │  │        ┗━━━━━┛ .....│..│..│..... 設定中断終了
        	      │          │  │                            │  │  │
        	      └─────│─│──────────────┘  │  │ (LEF) + (RIG) or
        	      ↑          │  │                                │  │ (RIG) + (LEF)
        	      │          │  │        ┏━━━━━┓          │  │
        	      │          │  │        ┃          ┃←────┘  │
        	      │          │  │menu=7  ┃週間タイマ┃              │
        	      │          │  └───→┃ ーの設定 ┃              │
        	      │          │  │        ┃表示と消去┃ (EXT)        │
        	      │          │  │        ┃          ┃───┐      │
        	      │          │  │        ┗━━━━━┛      │      │
        	      │          │  │                            │      │
        	      └─────│─│──────────────┘      │
        	      ↑          │  │                                    │
        	      │          │  │        ┏━━━━━┓              │
        	      │          │  │        ┃          ┃←──────┘
        	      │          │  │menu=8  ┃ 現在時刻 ┃
        	      │          │  └───→┃          ┃ (LEF) + (RIG) or
        	      │          │  │        ┃  の設定  ┃ (RIG) + (LEF)  ..... 設定中断終了
        	      │          │  │        ┃          ┃───────┐
        	      │          │  │        ┗━━━━━┛ (EXT) .......│..... 設定終了
        	      │          │  │                                    │
        	      │          └─│──────────────────┘
        	      │              │
        	      │              │        ┏━━━━━┓
        	      │              │        ┃          ┃ (LEF) + (RIG) or
        	      │              │menu=9  ┃ スリープ ┃ (RIG) + (LEF)  ..... 設定中断終了
        	      │              └───→┃ 移行時間 ┃───────┐
        	      │                        ┃  の変更  ┃ (EXT) .......│..... 設定終了
        	      │                        ┃          ┃              │
        	      │                        ┗━━━━━┛              │
        	      │                                                    │
        	      └──────────────────────────┘
        
◎ 「メニューの選択」機能
  • 本機には以降で順に説明をするように9つのメニュー項目(機能)があり、本機能である「メニューの選択」LCD 画面によって、希望する各メニュー項目(機能)を選択する。
      			[ Select_x ]	..... メニュー番号 x がブリンク表示   1行目
      
      			[ ClockDsp ]	..... 1:「現在時刻の表示」	   ┐
      			     ・						   │
      			     ・						   │ 2行目
      			     ・						   │
      			[ SleepTim ]	..... 9:「スリープ移行時間の変更」 ┘
      

  • 具体的な各メニュー項目の種類は次の通りで、使用している LCD 画面の表示文字数の制約から、次のような機能の略名で表している。 機能の略名では分かりづらいと思うが右側に付した和名から機能を察していただきたい。 (機能の詳細については各機能の項を参照のこと)

    • 1: ClockDsp ..... 「現在時刻の表示」機能
      2: DtlStopW ..... 「ストップウオッチ(詳細)」機能
      3: ItvTimer ..... 「インターバル(間隔)タイマー」機能
      4: LngStopW ..... 「ストップウオッチ(長時間)」機能
      5: MemoDisp ..... 「記録内容の表示」機能
      6: WkTimSet ..... 「週間タイマーの時刻設定」機能
      7: WkTimDsp ..... 「週間タイマーの設定表示と消去」機能
      8: ClockAdj ..... 「現在時刻の設定」機能
      9: SleepTim ..... 「スリープ移行時間の変更」機能

  • なお、「メニューの選択」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      DOWN スイッチ ........ 前のメニュー項目を表示
      UP スイッチ ........ 次のメニュー項目を表示
      ALARM スイッチ ........ アラーム音出力の有効/無効
      EXIT スイッチ ........ 選択したメニュー項目(機能)に移行

  • 各メニュー項目(機能)を実行した後で、終了をさせるために EXIT スイッチを押すと、本「メニューの選択」機能に再び戻って来る。 ただし2つ例外があって、1つは、6:「週間タイマーの時刻設定」では EXIT スイッチを3秒以上の長押しをしないと、 「メニューの選択」機能には戻らない。 またもう1つは、8:「現在時刻の設定」では EXIT スイッチを押しても、「メニューの選択」機能には戻らず、1:「現在時刻の表示」機能に移行をする。

  • そして、前機能から戻ってきた本「メニューの選択」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。(次の写真等は上に示したものを再掲)
      			[ Select_x ]	..... メニュー番号 x がブリンク表示   1行目
      
      			[ ClockDsp ]	..... 1:「現在時刻の表示」	   ┐
      			     ・						   │
      			     ・						   │ 2行目
      			     ・						   │
      			[ SleepTim ]	..... 9:「スリープ移行時間の変更」 ┘
      

  • 本「メニューの選択」機能に再び戻って来ると、LCD 画面の2行目には戻る以前に実行をしていた機能の略名が表示され、また、1行目の右端 x の部分にはメニュー項目の番号がブリンク表示されて、次に実行すべきメニューの選択を促す。

  • 「メニューの選択」LCD 画面でメニュー項目を変更するには、UP スイッチ、または DOWN スイッチを押すことによって行う。 UP スイッチ は、現在1行目に表示されているメニュー項目番号 x 値を、押すごとに +1 ずつ増加(インクリメント)し、 また DOWN スイッチ は、逆に押すごとに −1 ずつ減少(デクリメント)するとともに、2行目には機能の略名がメニュー項目番号 x 値に応じて変更表示される。

  • そして、UP スイッチの操作では、メニュー項目番号の最大値 9 を超えると最小値 1 に戻る。 また DOWN スイッチの操作では、メニュー項目番号の最小値 1 を超えると最大値 9 に戻る。 このように、UP スイッチ、DOWN スイッチを押すことによって、 メニュー項目を自由に変更することができる。

  • メニュー項目(番号)が決まったら EXIT スイッチ を押すことによって、「メニューの選択」機能から選択をした各メニュー項目(1〜9)別機能に移行(ジャンプ)をする。

  • ALARM スイッチ は、時報予報音、時報正報音、タイマー一致音、その他の効果音など、各種アラーム音の出力を一括して管理するスイッチで、押すごとに有効/無効を繰り返すトグルスイッチとなっている。 この ALARM スイッチは、本「メニューの選択」機能においてだけ操作が可能なスイッチで、各メニュー項目(1〜9)別機能では操作ができないので注意が必要である。

◎ メニュー項目: 1 ... 「現在時刻の表示」機能
  • 本機の中枢であり、現在時刻(年、月、日、曜日、AM/PM、時、分、秒)を表示する時計機能である。 本機ではリアルタイムクロック(RTC)モジュールを搭載(バックアップ用のバッテリーも搭載)してあるため、電池の消耗などで電源が切れたときや 本機の不使用時の長時間の電源断にも、安定した時刻の継続が期待できる。

  • 「メニューの選択」LCD 画面で、メニュー項目 1: [ ClockDsp ] を選択後に EXIT スイッチを押した場合、 または、8:「現在時刻の設定」機能 で EXIT スイッチ を押した場合(通常終了)と、 同機能で LEFT スイッチ + RIGHT スイッチ、または RIGHT スイッチ + LEFT スイッチ の操作をした場合(中断終了)にも、同機能を終了して本機能に移行(ジャンプ)をしてくる。 その他にも、本機では電源を入れた直後には、 「メニューの選択」機能ではなく本「現在時刻の表示」機能が最初に実行される。
      			[ Select_1 ]
      			[ ClockDsp ]	..... 1:「現在時刻の表示」
      

    そして、移行をしてきた本「現在時刻の表示」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • 本機能の現在時刻の LCD 画面表示は、使用した小さな LCD に対して表示させるための情報量が多いため、次に示すように、1行目を偶数秒のときと奇数秒のときとで交互に情報を切り替えて表示をさせている。 すなわち、偶数秒のときには年月日を表示させ、奇数秒のときには曜日と、12 時間表示のときには AM/PM 別の表示をさせ、また、24 時間表示のときには同表示位置は空白表示としている。
      					偶数秒のとき					奇数秒のとき
      			[ xx/xx/xx ]	1行目 ... 年月日の表示		[ (SUN) AM ]	1行目 ... 曜日 AM/PM の表示
      			[ xx:xx:xx ]	2行目 ... 時分秒の表示		[ xx:xx:xx ]	2行目 ... 時分秒の表示
      

  • なお、「現在時刻の表示」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      TMODE スイッチ ........ 12時間表示/24時間表示の切り替え
      ZERO スイッチ ........ 毎正時 00 分 00 秒に設定
      ENABLE スイッチ +
      EXIT スイッチ
      ........ 「現在時刻の設定」に移行
      EXIT スイッチ ........ 「メニューの選択」に戻る

  • 本機の "時"、"分"、"秒" 表示の内、"時" 表示は TMODE(TIME MODE)スイッチ を押すことによって、12 時間表示と 24 時間表示をいつでも切り替えることができる。 TMODE スイッチはトグルスイッチになっていて、押すごとに 12 時間表示と 24 時間表示が交互に切り替わる。

  • 次に、24 時間表示と 12 時間表示の対応を示すが、12 時間表示のときにのみ "xx 時" の先頭の1桁目(左側)は、ゼロサプレスを行なって表示をする。
        	(24H)  00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
        	(12H)  12  1  2  3  4  5  6  7  8  9 10 11 12  1  2  3  4  5  6  7  8  9 10 11
        	       am am am am am am am am am am am am pm pm pm pm pm pm pm pm pm pm pm pm
        
  • 本機で使用しているリアルタイムクロック(RTC)モジュールでは、これらの 12 時間表示、24 時間表示の情報も管理ができるが、本機では、(RTC)には常に 24 時間表示で動作をさせ、12 時間表示のときには本機のプログラム内で変換をして、 LCD 画面に表示をさせている。

  • また、毎正時プラス・マイナス5分以内のときに、ZERO スイッチ を押すと、現在時刻の "分" と "秒" を "00 分 00 秒" に設定し直して、リアルタイムクロック(RTC)モジュールに書き込み、LCD 画面表示もその "00 分 00 秒" から再開始をする。 ただし、毎正時プラス・マイナス5分以外のときには、ZERO スイッチを押しても無視をされる。

  • 本機は携帯用の多機能デジタル時計としての使用を想定していて、電源には 18650 リチウムイオン電池を使用している。 そのために際限なく時計表示をさせておくことはできない。 したがって、この「現在時刻の表示」機能では3分間(デフォルト値)どのスイッチも入力がなかった場合には、自動的に LCD の電源を切り、本機の PIC をスリープ状態にさせて電池の消耗を抑えるようにしている。

  • しかし、このスリープ状態を解除させたい場合には、上述の本機能で使用できる赤字名のスイッチ(TMODE、ZERO、ENABLE、EXIT スイッチ)の内の、どれかを押すことによっていつでも直ちに目覚めさせることができる。

  • スリープ状態になるときには、3分(デフォルト値)を経過する3秒前から、秒ごとに "ブッ" アラーム音と LED (緑) を瞬間点滅させ、3分を経過直後に "ブッブー" アラーム音とともに LED (緑) を点滅させてから、スリープ状態になる。

  • ユーザのスイッチ操作によってスリープ状態から目覚めるときには、目覚めた直後に "ピピッ" アラーム音とともに LED (緑) を点滅させる。 また、スリープ中にも本機の存在感を誇示?するために、1分間に1度、"ピッ" ブザー音とともに LED (赤) を瞬間点滅させている。

  • 本機では毎時の時報音を出力させるための時間監視と、後述の 6:「週間タイマーの時刻設定」機能 で設定をしたタイマー一致の時間監視をさせるために、目覚めているときはもちろん、スリープ状態においても 毎秒ごとに瞬間だけウエイクアップをさせてそれらの時間監視をさせ、時間一致があればそれらに応じた各アラーム音の出力をする。

  • 9つのメニュー項目(機能)の内、1: 本機能と、4:「ストップウオッチ(長時間)」機能5:「記録内容の表示」機能 の3機能についてのみ、リアルタイムクロック(RTC)モジュールによる 時計機能を動作させている。 したがって、それらの3機能では本機のプログラムでいつも上述の時間監視が行われていて、前項の「メニューの選択」機能で述べた ALARM スイッチ によって、 アラーム音の出力が有効になっている場合には各アラーム音を出力する。

  • 本機能を終了させるのには2つの方法があり、単独で EXIT スイッチ を押した場合には「メニューの選択」機能に戻る。 また、ENABLE スイッチ を押しながら EXIT スイッチ を押した場合には、 8:「現在時刻の設定」機能 に移行(ジャンプ)するので、引き続き現在時刻(年、月、日、時、分、秒)の設定作業を行うことができる。

| 「メニューの選択」機能に戻る |

◎ メニュー項目: 2 ... 「ストップウオッチ(詳細)」機能
  • 本機能のストップウオッチは 1/100 秒単位での測定ができるのが特徴で、"99 時間 59 分 59 秒 99" までの表示が可能で、それ以上の3桁目の時表示はできないが 100 時間以上の測定も連続無制限に可能である。 本機能では最大値の表示を過ぎると一旦、"00 時間 00 分 00 秒 00" の表示に戻って引き続きカウントアップを繰り返し行う。

  • しかし、本機能ではこのような長時間に亘る使用は想定をしていないので、PIC をスリープ状態にさせることもしない。 したがって、電池の消耗という観点ではすこぶる不利となる。 もしも、このような長時間に亘る測定をしたい場合には、 1/100 秒単位での測定はできないが(というよりも長時間に亘る測定では 1/100 秒単位の測定などは不要と思われる)、後述の 4:「ストップウオッチ(長時間)」機能 で測定することをお勧めする。

  • 「メニューの選択」LCD 画面で、メニュー項目 2: [ DtlStopW ] を選択後に EXIT スイッチを押すと、本機能に移行(ジャンプ)してくる。
      			[ Select_2 ]
      			[ DtlStopW ]	..... 2:「ストップウオッチ(詳細)」
      

    そして、移行をしてきた本「ストップウオッチ(詳細)」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • なお、「ストップウオッチ(詳細)」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      Start / Stop スイッチ
      (LINE IN = "L" *)
      ........ ストップウオッチ(動作)スタート
      Start / Stop スイッチ
      (LINE IN = "H" *)
      ........ ストップウオッチ(動作)ストップ
      * スタート 信号 (RA4 入力) はインバータにより反転する
      CLEAR スイッチ ........ 全桁 "00" にクリア表示
      EXIT スイッチ ........ 「メニューの選択」に戻る

  • 本機能のストップウオッチの LCD 画面表示は次の通りで、写真左はストップウオッチの動作がスタートする前のもので、初期状態を表している。 写真右はストップウオッチが動作中のもので、1/100 秒の単位では更新が早すぎて値を見届けることは難しい。
      			[ 00:00:00 ]	 ... HH:MM:SS
      			[ (StW) 00 ]	 ... (StW) XX ... XX: 1/100 秒
      

  • Start / Stop スイッチ はトグルスイッチを使用していて、Start 側に倒すと ストップウオッチの動作がスタート し、1/100 秒単位で LCD 画面表示のカウントアップが始まる。 やがて、ストップウオッチを停止したいときには Stop 側に倒すと ストップウオッチの動作がストップ して、LCD 画面表示のカウントアップも停止をするとともに、"ポッポッポッポッ" アラーム音の出力と LED (緑) が点灯して、ストップウオッチが停止したことをユーザに知らせる。

  • このストップウオッチが停止した知らせを受けた後、ユーザはそのときの LCD 画面の表示値を確認する。 そして、再度ストップウオッチの動作停止を繰り返し実行したい場合には、CLEAR スイッチ を押すと 上述のストップウオッチの動作がスタートする前の、 初期状態の LCD 画面表示に戻るとともに LED (緑) が消灯する。

  • 一方、この CLEAR スイッチを押して初期状態の LCD 画面表示に戻す前後のどちらの場合にも、EXIT スイッチ を押すと LED (緑) が点灯している場合には消灯し、本機能を終了して「メニューの選択」機能に戻る。

  • また、本機には LINE IN 入力端子が設けてあり、その入力端子に外部からの電気信号を入力することによって、Start / Stop トグルスイッチを操作したときと同様なストップウオッチ動作を行うことができる。 電気信号が "L" の場合には トグルスイッチを Start 側に倒した場合と同様であり、"H" の場合には トグルスイッチを Stop 側に倒した場合と同様な動作をする。

  • なお、本機のロジック回路は 3.3 V 電源で動作をしているため、この LINE IN 入力端子に入力するための外部電気信号の電圧も、ロジックレベルを合わせる必要がある。

| 「メニューの選択」機能に戻る |

◎ メニュー項目: 3 ... 「インターバル(間隔)タイマー」機能
  • 本機能のタイマーは、分かりやすく例えれば "キッチンタイマー" のような使い方を想定していて、タイマー動作を開始させる前に予め設定をしておいた時間から、ひたすらカウントダウンを繰り返し、残り時間がゼロになるとタイマー動作を停止する。

  • この予め設定をしておくタイマー時間の範囲は、本機能では最大 "99 時間 59 分 59 秒" までが可能で、1秒単位でカウントダウンを繰り返えすが、長時間の設定は電池の消耗という観点ですこぶる不利となる。 この設定値は次回のタイマー動作のときにも使用ができるように、自動的に EEPROM にバックアップがとられる。

  • 「メニューの選択」LCD 画面で、メニュー項目 3: [ ItvTimer ] を選択後に EXIT スイッチを押すと、本機能に移行(ジャンプ)してくる。
      			[ Select_3 ]
      			[ ItvTimer ]	..... 3:「インターバル(間隔)タイマー」
      

    そして、移行をしてきた本「インターバル(間隔)タイマー」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • なお、「インターバル(間隔)タイマー」機能では次図に示す黒塗りすべてのスイッチを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      Start / Stop スイッチ
      (LINE IN = "L" *)
      ........ インターバルタイマー(動作)スタート
      Start / Stop スイッチ
      (LINE IN = "H" *)
      ........ インターバルタイマー(動作)ストップ
      * スタート 信号 (RA4 入力) はインバータにより反転する
      CLEAR スイッチ ........ 前回の設定値を表示
      LEFT スイッチ ........ ブリンク位置のポインタを - 1
      RIGHT スイッチ ........ ブリンク位置のポインタを + 1
      DOWN スイッチ ........ ブリンク位置の値を - 1
      UP スイッチ ........ ブリンク位置の値を + 1
      EXIT スイッチ ........ 「メニューの選択」に戻る

  • 本機能タイマーの LCD 画面表示は次の通りで、2行目のタイマー時間の設定値(HH:MM:SS)には、「メニューの選択」機能から移行をしてきた直後には、バックアップがとられている EEPROM から自動的に読み出されて表示がされる。 ただし、本機能がまったく初めて使用されたときには、バックアップの時間設定値データがないので "00:00:00" が表示される。
      			[ ItvTimer ]	 ... インターバルタイマー
      			[ xx:xx:xx ]	 ... タイマー時間の設定値
      

  • タイマー時間の設定値に "00:00:00" が表示されていたり、現在表示されている設定値を変更したい場合には、DOWN、UP、LEFT、RIGHT の各スイッチを使用して、自分が希望するタイマー時間の設定値に変更する。

  • まず初めに、LEFT または RIGHT スイッチ を押すことによって、ブリンク位置が左または右に移動をするので、変更をしたい "HH"、"MM"、"SS" の位置にポイントする。

  • 次に、ポイントしたブリンク位置の設定値を、UP スイッチ を押すごとに1ずつ増加、または DOWN スイッチ を押すごとに1ずつ減少することができる。 このときの増減幅を大きくしたい場合には、 UP スイッチ、または DOWN スイッチを押したままにしていると、1秒当たり 4 〜 5 の増減幅で更新をするようになる。

  • このようにタイマー時間の設定をした後で、Start / Stop スイッチStart 側に倒すとタイマー動作がスタート し、1秒単位で LCD 画面表示のカウントダウンが始まる。 やがて、残りのタイマー時間がゼロになるとタイマー動作を停止して、LCD 画面表示のカウントダウンも停止をするとともに、"ポッポッポッポッ" アラーム音の出力と LED (緑) が点灯して、タイマーが停止したことをユーザに知らせる。 この知らせを受けた後には、ユーザは Start / Stop スイッチを Stop 側に戻しておく。

  • LCD 画面表示がカウントダウン中に何らかの理由で、Start / Stop スイッチを Stop 側に倒すとタイマー動作は強制的に停止して、同様に "ポッポッポッポッ" アラーム音の出力と LED (緑) が点灯する。

  • また、タイマー時間の設定値に "00:00:00" が表示されているときに、Start / Stop スイッチを Start 側に倒すと、"ブッ" アラーム音の出力とともに LED (赤) が瞬間点滅するエラー表示を、Start / Stop スイッチを Stop 側に戻すまで連続で繰り返される。

  • タイマーが停止したことを確認後 CLEAR スイッチ を押すと、前回のタイマー設定値が再び LCD 画面に表示されるとともに LED (緑) が消灯するが、設定値の変更をしたければ上述と同様にして変更作業を行う。 以降は Start / Stop スイッチの操作によってタイマー動作を繰り返し実行することができる。

  • 一方、この CLEAR スイッチを押して前回のタイマー設定値が LCD 画面に表示される前後のどちらの場合にも、EXIT スイッチ を押すと LED (緑) が点灯している場合には消灯し、本機能を終了して「メニューの選択」機能に戻るが、 その直前に、最終的に用いられたタイマー時間の設定値が EEPROM のバックアップデータと比較され、両者が異なる場合にだけ、前者の設定値が新たなバックアップデータとして EEPROM に再書き込みが行われる。

  • なお、前項の 2:「ストップウオッチ(詳細)」機能 と同様に、LINE IN 入力端子から入力した外部電気信号でもタイマー動作をスタートさせることは可能であるが、そのような使い方は本機能では想定をしていないので あまりお勧めはしない。

| 「メニューの選択」機能に戻る |

◎ メニュー項目: 4 ... 「ストップウオッチ(長時間)」機能
  • 本機能は主に室外での携行使用を想定しており(例えばウォーキングの友として、その間中をずっと本機の持ち歩きをするなど)、下図の ENABLE スイッチと START/GOAL スイッチについては2個ずつ用意して、1組は他のスイッチと同様にプリント基板上に搭載し、 もう1組は本機能のための専用スイッチとも言うべきもので、本機のケースの蓋を閉めた状態でもスイッチの頭がケース外に飛び出すような構造にケース加工を施して、ケースの上蓋に取り付けてある。

  • 実際の運用に当たっては、ウォーキングなどの移動中には本機をポケットや、カバンなどの中に入れられたりして使用されることが多い ― と想定されるため、上述のようなスイッチの取り付け構造や、また、スイッチの誤操作を極力防ぐために、 後述のように2個のスイッチを組み合わせたスイッチ操作を採用している。

  • また、本機能は比較的長時間の携行使用することを想定して、なるべく電池の消耗が少なくて済むように一定時間スイッチ操作がなかったときには、PIC をスリープ状態にさせるなどの考慮をしており、また、測定ができる時間の最小単位は1秒で最大 "99 時間 59 分 59 秒" までの6桁の表示で、それ以上の3桁目の時表示はできないが 100 時間以上の測定も連続無制限に可能である。 本機能では最大値の表示を過ぎると一旦、"00 時間 00 分 00 秒" の表示に戻って引き続きカウントアップを繰り返し行う。

  • このように、秒以下の詳細な測定は本機能ではできないが、もしも、詳細な測定を希望する場合には、前々項の 2:「ストップウオッチ(詳細)」機能 を使用すれば 1/100 秒単位での測定ができるので、 そちらの機能を使用することをお勧めする。

  • 「メニューの選択」LCD 画面で、メニュー項目 4: [ LngStopW ] を選択後に EXIT スイッチを押すと、本機能に移行(ジャンプ)してくる。
      			[ Select_4 ]
      			[ LngStopW ]	..... 4:「ストップウオッチ(長時間)」
      

    そして、移行をしてきた本「ストップウオッチ(長時間)」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • 本機能に移行した直後の LCD 画面表示は次の通りで、1行目には本機能の略名が表示され、2行目には現在時刻 "HH:MM:SS" が刻々と刻まれながら表示される。
      			[ LngStopW ]	..... 本機能の略名を表示
      			[ xx:xx:xx ]	..... 現在時刻 "HH:MM:SS" を刻々と刻みながら表示
      

  • なお、「ストップウオッチ(長時間)」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      (1) ENABLE スイッチ +
      START スイッチ
      ........ (通常のちょん押し) START / SPLIT(LAP)
      (2) ENABLE スイッチ 長押し +
      START スイッチ 長押し
      ........ (3秒以上の長押し) GOAL
      (3) ENABLE スイッチ +
      EXIT スイッチ
      ........ 「記録内容の表示」に移行
      (4) EXIT スイッチ ........ 「メニューの選択」に戻る

  • 下図は、「メニューの選択」機能から本機能に移行をし、再び「メニューの選択」機能へ戻ったり、または「記録内容の表示」機能に移行するまでを図に表したもので、図中の (1) 〜 (4) の番号は上のスイッチ操作の要点の左端に付した番号を指す。
  • 上図において、スタートしてからゴールをするまでの間に、多くのスプリットタイムを記録することを、本機能の一番の目的としている。 これらのスプリットタイムは、スタート(START)時のスイッチ操作 (1) を除いて、その後の、2回目以降に操作 (1) を行うごとに、 PIC の内蔵メモリ(SRAM)に書き込んで記録が取られて行く。
    (スイッチ操作 (1) ENABLE スイッチ + START スイッチ とは、ENABLE スイッチ を押しながら START スイッチ を通常のちょん押しをすることを表す)

  • なお、このスタート(START)時の スイッチ操作 (1) を契機として、スプリットタイムのカウントが [ 00:00:00 ] から開始され、LCD 画面の1行目に表示がされるようになる。 そして、"ドーミーソードー" アラーム音とともに LED (緑) (赤) が交互に点滅して、 スプリットタイムのカウントが スタート (START) をしたことを知らせる。
      			[ xx:xx:xx ]	..... スプリットタイムを1秒ずつ更新しながら表示
      			[ xx:xx:xx ]	..... 現在時刻 "HH:MM:SS" を刻々と刻みながら表示
      

  • 上述のように、PIC の内蔵メモリ(SRAM)に、そのときの スプリットタイム を書き込んで記録が取られるとき、それを知らせるために "ポッポッ" アラーム音とともに LED (緑) を点滅させる。

  • そしてその直後に、LCD 画面の表示が一時的に約5秒間だけ次のように変わって、そのときの 記録番号 とラップタイムが表示される。 ラップタイム は、今回測定したスプリットタイムと、前回測定してメモリ(SRAM)に記録されている スプリットタイムとの差を、時間計算によって求めたものである。
      			[ ** xx ** ]	..... xx に記録番号を表示
      			[ xx:xx:xx ]	..... ラップタイムを表示
      

  • このときの、内蔵メモリ(SRAM)に書き込むことが可能なスプリットタイムの最大数は、現在 40 個に制限がしてあり、書き込んだ後にその最大数に達したかのチェックを行い、最大数に達した場合には、3秒間次のような警告メッセージを LCD 画面に表示して、 かつ、"ブッブッブッブッ" アラーム音とともに LED (赤) が点滅を繰り返えす。
      			[ xx:xx:xx ]	..... スプリットタイム
      			[ Mem Full ]	..... メモリ満タン警告メッセージ
      

  • その後、"ドーソーミードー" アラーム音とともに LED (緑) (赤) が交互に点滅した後、最終の記録番号(40)とラップタイムが約5秒間表示され、本機能は強制的にゴールにさせられ、スプリットタイムのカウントが停止する。 そして、その後は右下の LCD 画面になり現在時刻を更新しながら表示し続ける。
      			[ ** 40 ** ]	..... 最終の記録番号		[ StpW End ]	..... ストップウオッチの動作が終了した
      			[ xx:xx:xx ]	..... 最終のラップタイム	[ xx:xx:xx ]	..... 現在時刻を更新しながら表示し続ける
      

  • 本機能ではスタートしてからゴールするまでを長時間使用することを想定しているが、その間ずっと LCD 画面を表示させておく必要はない。 電池の消耗を抑えるという観点で本機能では1分間(デフォルト値)どのスイッチも入力がなかった場合には、 自動的に LCD の電源を切り、本機の PIC を スリープ状態 にさせている。

  • しかし、このスリープ状態を解除させたい場合には、上述の本機能で使用できる赤字名のスイッチ(ENABLE、START/GOAL 、EXIT スイッチ)の内の、どれかを押すことによっていつでも目覚めさせ、直ちに LCD 画面を表示させることができる。

  • スリープ状態になるときには、1分(デフォルト値)を経過する3秒前から、秒ごとに "ブッ" アラーム音と LED (緑) を瞬間点滅させ、1分を経過直後に "ブッブー" アラーム音とともに LED (緑) を点滅させてから、スリープ状態になる。

  • ユーザのスイッチ操作によってスリープ状態から目覚めるときには、目覚めた直後に "ピピッ" アラーム音とともに LED (緑) を点滅させる。 また、スリープ中にも本機の存在感を誇示?するために、1分間に1度、"ピッ" ブザー音とともに LED (赤) を瞬間点滅させている。

  • また本機能においても、毎時の時報音を出力させるための時間監視と、後述の 6:「週間タイマーの時刻設定」機能 で設定をした、タイマー一致の時間監視をさせているので、目覚めているとき、スリープ中にかかわらず、 時間一致があればそれらに応じた各アラーム音の出力をする。

  • やがて、ゴールをするためにスイッチ操作 (2) が行われると、最後のスプリットタイムが PIC の内蔵メモリ(SRAM)に書き込まれて記録され、"ドーソーミードー" アラーム音とともに LED (緑) (赤) が交互に点滅をするので、それを合図に (2) の操作を止めるようにする。

  • またその直後に、LCD 画面の表示が約5秒間だけ記録番号とラップタイムが表示されることは、スイッチ操作 (1) の場合と同様である。 そして、その後は次の LCD 画面の表示に変わってストップウオッチの動作が終了したことを知らせ、 次のスイッチ操作の指示があるまでは現在時刻を更新しながら表示し続ける。
      			[ StpW End ]	..... ストップウオッチの動作が終了した
      			[ xx:xx:xx ]	..... 現在時刻を更新しながら表示し続ける
      

  • ゴール(GOAL)をした後のスイッチ操作は (3) または (4) のどちらかで、スイッチ操作 (3) を行った場合には次項の 5:「記録内容の表示」機能 に移行して、引き続き、今まで PIC の内蔵メモリ(SRAM)に記録されてきた スプリットタイムを基に、改めて記録番号、スプリットタイム、ラップタイムを表示させることができる。

  • 一方、スイッチ操作 (4) を行った場合には「メニューの選択」機能に戻る。 しかし、本機の電源を切ったり、新たに本機能を実行して新しいスプリットタイムで PIC の内蔵メモリ(SRAM)に上書きをしない限り、 今まで記録されてきたスプリットタイムはいつまでも残っているので、改めて「メニューの選択」機能で 5:「記録内容の表示」機能を選択すれば、同様に記録番号、スプリットタイム、ラップタイムを表示させることができる。

    (ヒント) 「メニューの選択」機能にはスリープモードがないため、改めてスプリットタイム等を表示させる予定はあるがそれまでに時間を要する場合は、5:「記録内容の表示」機能にしておいた方がスリープモードがあるので、電池の消耗を抑えるという観点では良い。 もちろん、本機の電源を切ればすべてのスプリットタイムの記録は消滅をする。

| 「メニューの選択」機能に戻る |

◎ メニュー項目: 5 ... 「記録内容の表示」機能
  • 例えばウォーキングなどの外出先で、前項の 4:「ストップウオッチ(長時間)」機能 によって、PIC の内蔵メモリ(SRAM)に記録をしたスプリットタイムのデータは、4:「ストップウオッチ(長時間)」機能を終了させた後になっても、 帰宅後に、本機能で PIC の内蔵メモリ(SRAM)を読み出し、記録番号スプリットタイムラップタイム を 改めて LCD 画面に表示をさせることができる。(上の(ヒント)を参照のこと)

  • ただし、本機の電源を切ったり、新たに 4:「ストップウオッチ(長時間)」機能を実行して、新しいスプリットタイムで PIC の内蔵メモリ(SRAM)に上書きをした場合は、旧スプリットタイムの記録はすべて消滅をする。 (もしも、4:「ストップウオッチ(長時間)」機能に移行しても、スイッチ操作 (1) を行う以前に、(3) または (4) を行って同機能を終了させた場合には、旧スプリットタイムの記録は消滅をしないですべて残る。)

  • 「メニューの選択」LCD 画面で、メニュー項目 5: [ MemoDisp ] を選択後に EXIT スイッチを押すと、本機能に移行(ジャンプ)してくる。 または、前項の 4:「ストップウオッチ(長時間)」機能で、スイッチ操作 (3)(ENABLE スイッチ + EXIT スイッチ) を行った場合にも、同機能を終了して本機能に移行(ジャンプ)してくる。
      			[ Select_5 ]
      			[ MemoDisp ]	..... 5:「記録内容の表示」
      

    そして、移行をしてきた本「記録内容の表示」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • 本機能に移行した直後の LCD 画面表示は次の通りで、1行目には本機能の略名が表示され、2行目には現在時刻 "HH:MM:SS" が刻々と刻まれながら表示される。
      			[ MemoDisp ]	..... 本機能の略名を表示
      			[ xx:xx:xx ]	..... 現在時刻 "HH:MM:SS" を刻々と刻みながら表示
      

  • ただし、まだ 4:「ストップウオッチ(長時間)」機能が実行されておらず、先に本機能を実行したような場合、すなわち、スプリットタイムのデータが内蔵メモリ(SRAM)に1件も記録されていない場合には、LCD 画面の2行目には "None" の文字列がブリンク表示される。 このときの "None" 文字列は、初めの 0.5 秒間は表示、かつ、"ブッ" アラーム音出力と LED (赤) を瞬間点滅させ、 次の 0.5 秒間は文字列を消滅させる ― の点滅表示を1秒周期で繰り返してユーザに注意喚起する。
      			[ MemoDisp ]	..... 本機能の略名を表示
      			[   None   ]	..... "None" がブリンク表示
      

  • このように、上の "None" 文字列のブリンク表示になったときには、EXIT スイッチ を押して「メニューの選択」機能に戻ることしか選択肢はない。

  • なお、「記録内容の表示」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      LEFT スイッチ ........ 1つ前のデータを表示
      RIGHT スイッチ ........ 1つ後のデータを表示
      EXIT スイッチ ........ 「メニューの選択」に戻る

  • 本機能では、前項の 4:「ストップウオッチ(長時間)」機能によって、PIC の内蔵メモリ(SRAM)に記録をさせた複数のチェック地点での スプリットタイム を、LEFT スイッチ、または RIGHT スイッチを操作するごとに読み出して、 そのときの 記録番号(チェック地点番号)とともに、改めて時間計算を行って求めた ラップタイム の3つの情報を LCD 画面に表示をする。

  • このとき読み出しのキーとなる記録番号は、初めてスイッチ操作があった場合には、それが RIGHT スイッチのときは1番 が、LEFT スイッチのときは記録した最大値 が選択されて、それらが初期値となる。

  • そして、まず初めに記録番号が次の形式で LCD 画面に表示される。 この記録番号は2つのスイッチの内どちらかを操作するごとに更新をするが、 RIGHT スイッチ の場合には、1ずつ増加(インクリメント、最大値に達したときは 次には再び1番に戻る)され、 一方、LEFT スイッチ の場合には、1ずつ減少(デクリメント、1番に達したときは 次には再び最大値に戻る)されて、LCD 画面に表示がされる。
      			[ ** xx ** ]	..... 記録番号 xx を表示
      			[          ]	..... 2行目には何も表示されない
      

  • このときの表示される記録番号は、どちらかのスイッチを押している間中ずっと表示され続けるが、手を離した瞬間に次の形式でスプリットタイム(1行目)、およびラップタイム(2行目)の表示に切り替わる。
      			[ xx:xx:xx ]	..... スプリットタイムを表示
      			[ xx:xx:xx ]	..... ラップタイムを表示
      

  • このようにして2つのスイッチの内どちらかを操作するごとに、記録番号の表示と、スプリットタイム、ラップタイムの表示に切り替わりながら LCD 画面に表示されるが、本機能においても前項の 4:「ストップウオッチ(長時間)」機能と同様に、 1分間(デフォルト値)どのスイッチの入力もなかった場合には、自動的に LCD の電源を切り、本機の PIC を スリープ状態 にさせて電池の消耗を抑えている。

  • このスリープ状態を解除させたい場合には、上述の本機能で使用できる赤字名のスイッチ(LEFT、RIGHT 、EXIT スイッチ)の内の、どれかを押すことによっていつでも目覚めさせ、直ちに LCD 画面を表示させることも前項の機能と同様である。

  • しかし、スリープ状態から目覚めたときには、一旦、次の形式で刻々と更新をしながら現在時刻が表示されるようになるが、次に、LEFT、または RIGHT スイッチのどちらかを操作することによって、再び上述した形式で、記録番号(チェック地点番号)と スプリットタイム、ラップタイムの表示に切り替わる。
      			[ MemoDisp ]	..... 本機能の略名を表示
      			[ xx:xx:xx ]	..... 現在時刻 "HH:MM:SS" を刻々と刻みながら表示
      

  • また本機能においても、毎時の時報音を出力させるための時間監視と、タイマー一致の時間監視をさせているので、目覚めているとき、スリープ中にかかわらず、 時間一致があればそれらに応じた各アラーム音の出力をする。

  • 本機能を終了させたいときには EXIT スイッチ を押すことによって「メニューの選択」機能に戻るが、上述したように、本機の電源を切ったり、新しいスプリットタイムで PIC の内蔵メモリ(SRAM)に上書きをしない限り、 記録されたスプリットタイムはいつまでも残っているので、再び(何度でも)本機能を繰り返すことができる。

| 「メニューの選択」機能に戻る |

◎ メニュー項目: 6 ... 「週間タイマーの時刻設定」機能
  • 本機では9つのメニュー項目(機能)の内、1:「現在時刻の表示」機能4:「ストップウオッチ(長時間)」機能5:「記録内容の表示」機能 の3機能についてのみ、 リアルタイムクロック(RTC)モジュールによる 時計機能を動作させている。

  • そこで、あらかじめ本機能によってタイマー時間を設定しておくと、そのタイマー時間と現在時刻が一致したときに、アラーム音を出力することができる。 本機は携帯使用のためにリレー等を動作させてもあまり意味がないので、 アラーム音の出力だけをする。

  • 本機能は機能名通り週間タイマーとなっており、曜日、時、分の情報を PIC の内蔵メモリ(SRAM)に書き込むとともに、EEPROM にもバックアップがとられるため、本機の電源を切っても設定情報が消えることはない。 そのため次項の 7:「週間タイマーの設定表示と消去」機能 で消去をしない限り、毎週同時刻になるとアラーム音を出力する。

  • 「メニューの選択」LCD 画面で、メニュー項目 6: [ WkTimSet ] を選択後に EXIT スイッチを押すと、本機能に移行(ジャンプ)してくる。
      			[ Select_6 ]
      			[ WkTimSet ]	..... 6:「週間タイマーの時刻設定」
      

    そして、移行をしてきた本「週間タイマーの時刻設定」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • なお、「週間タイマーの時刻設定」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      LEFT スイッチ ........ ブリンク位置のポインタを - 1
      RIGHT スイッチ ........ ブリンク位置のポインタを + 1
      DOWN スイッチ ........ ブリンク位置の値を - 1
      UP スイッチ ........ ブリンク位置の値を + 1
      EXIT スイッチ ........ タイマー情報をメモリに書き込み、次の設定に移る
      LEFT スイッチ +
      RIGHT スイッチ
      ........ 「週間タイマーの時刻設定」を中断し、「メニューの選択」に戻る
      RIGHT スイッチ +
      LEFT スイッチ
      ........ 「週間タイマーの時刻設定」を中断し、「メニューの選択」に戻る
      LEFT(ENABLE) スイッチ +
      EXIT スイッチ
      ........ 「週間タイマーの設定表示と消去」に移行
      EXIT スイッチ 長押し ........ (3秒以上の長押し)「メニューの選択」に戻る (メモリ書き込みは行わない)

  • 本機能のタイマー時刻設定の LCD 画面表示は次の通りで、設定をする前の初期のときの2行目にはすべて "0" が表示され、先頭の "0" 位置がブリンク表示される。 "00:00" の位置に "時"、"分" を設定し、右端の "0" の位置には "曜日" を表す数字を設定する。
      			[ Set EDAY ]	..... 右側に曜日 (略名) を表示
      			[ 00:00  0 ]	..... "HH:MM"、"曜日を表す数字" を設定
      

  • 先頭の "0" 位置がブリンク表示されているのは、初めに "時" を設定することを表しており、UP スイッチ、または DOWN スイッチを押すことによって、"時" の設定値を 24 時間表示で入力する。 UP スイッチ を押すごとに1ずつ増加し、DOWN スイッチ を押すごとに1ずつ減少することができる。 このときの増減幅を大きくしたい場合には、UP スイッチ、または DOWN スイッチを押したままにしていると、1秒当たり 4 〜 5 の増減幅で更新をするようになる。

  • "時" の設定が済んだら次に、"分" を設定するために RIGHT スイッチを押すと、ブリンク位置が "分" の左側 "0" 位置に移動をする。 "時" のときと同様に、UP スイッチ、または DOWN スイッチを押すことによって、"分" を設定する。

  • 最後に "曜日" を設定するためにもう一度 RIGHT スイッチを押すと、次にはブリンク位置が右端の "0" の位置に移動をするので、同様に UP スイッチ、または DOWN スイッチで "曜日" を表す数字を設定する。 すると、数字に対応した曜日の略名が LCD 画面1行目の右側に表示される。 その数字と "曜日"、"略名" の対応表を次に示す。

            設定値 0 1 2 3 4 5 6 7
            曜日 毎日
            (略名) EDAY SUN MON TUE WED THU FRI SAT

  • このように、RIGHT スイッチ は、押すごとにブリンク位置が1ずつ増加(右に移動)をするが、逆に LEFT スイッチ は、押すごとにブリンク位置が1ずつ減少(左に移動)をするので、希望するブリンク位置を自由に変更することができ、 設定をする3つの "時"、"分"、"曜日" 情報は、どの順序で行っても構わない。

  • こうして "時"、"分"、"曜日" の3つのタイマー情報の設定ができたら、次に EXIT スイッチ を押すことによって、タイマー情報用に割り当てた PIC の内蔵メモリ(SRAM)に書き込まれる。 この書き込みを行うときには、 事前に、既に書き込まれているタイマー情報のすべてと、書き込もうとしているタイマー情報とが比較されて、一致する情報があるときには、"ブッ" アラーム音の出力と LED (赤) を点滅させて、注意を喚起するとともに書き込みを中止する。

  • また、内蔵メモリ(SRAM)に書き込むことが可能なタイマー情報の最大数は、現在 20 個に制限がしてあり、既に最大数に達している場合には、次のようなエラーメッセージを約3秒間 LCD 画面に表示をして、かつ、"ブッブッブッブッ" アラーム音とともに LED (赤) が点滅を繰り返えす。 その後、本機能を強制終了して「メニューの選択」機能に戻る。
      			[ Set Err! ]	..... エラーメッセージ
      			[ Mem Full ]	..... メモリ満タン警告メッセージ
      

  • PIC の内蔵メモリ(SRAM)に正常に書き込みができた場合には、"ポッポッ" アラーム音出力と LED (緑) を点滅させて、正常書き込みができたことを報告する。 そして、LCD 画面の2行目を、上述 のようにすべて "0" 表示にし、 かつ、先頭の "0" 位置をブリンク表示して、初期の LCD 画面に戻す。(初期の LCD 画面には戻さないように変更)

  • 上述のように、本機能での EXIT スイッチの動作は、他の機能の場合と異なっているので注意が必要である(他の7つのメニュー項目(機能)のすべてでは、「メニューの選択」機能に戻るときに用いる)。 本機能での EXIT スイッチは、タイマー情報を PIC の内蔵メモリ(SRAM)に書き込む指示をし、書き込んだ後、引き続き次の新たなタイマー情報の設定操作を行うことができるようにする。

  • このようにして PIC の内蔵メモリ(SRAM)に書き込まれたタイマー情報は、上述した 1:「現在時刻の表示」機能、4:「ストップウオッチ(長時間)」機能、5:「記録内容の表示」機能の3機能の内のどれかが実行されているときに、現在時刻が毎分 "00" 秒になるごとにタイマー一致があるかの時間監視をさせ、もし一致があった場合には、一致をした "00" 秒を始めとして合計 10 回、毎秒ごとに "ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、ユーザに知らせる。

  • 本機能でタイマー情報の設定操作中に、何らかの理由で本機能を中断したくなった場合には、LEFT スイッチ + RIGHT スイッチ、または RIGHT スイッチ + LEFT スイッチ の操作をすることで、設定している情報は書き込まれることはなく、 本機能を途中で中断終了して「メニューの選択」機能に戻る。

  • 本機能では、EXIT スイッチを3秒以上の長押しをする ことによって、本機能を正常に終了させ「メニューの選択」機能に戻ることができる。 このとき、現在 PIC の内蔵メモリ(SRAM)に書き込まれているタイマー情報は、 同じ PIC の内蔵メモリ(EEPROM)にもバックアップをとってから本機能を終了する。

| 「メニューの選択」機能に戻る |

◎ メニュー項目: 7 ... 「週間タイマーの設定表示と消去」機能
  • 前項の 6:「週間タイマーの時刻設定」機能 によってタイマー情報の設定を行った直後や、設定を行ってから何日も経って、再度現在の設定状態の確認をしたいときなど、本機能によって PIC の内蔵メモリ(SRAM)に書き込まれている、 タイマー情報の現在の設定状態を1件ずつ LCD 画面上に読み出して確認をすることができる。

  • また、本機能では再確認をした結果、不要になったタイマー情報を個別に内蔵メモリ(SRAM)から消去をしたり、すべてのタイマー情報を一度に全消去をしたりすることができる。 このように内蔵メモリ(SRAM)内の情報の消去をした場合には、 バックアップ用の内蔵メモリ(EEPROM)も自動で更新をする。

  • 「メニューの選択」LCD 画面で、メニュー項目 7: [ WkTimDsp ] を選択後に EXIT スイッチを押すと、本機能に移行(ジャンプ)してくる。 または、前項の 6:「週間タイマーの時刻設定」機能で、スイッチ操作(LEFT(ENABLE) スイッチ + EXIT スイッチ) を行った場合にも、 同機能を終了して本機能に移行(ジャンプ)してくる。
      			[ Select_7 ]
      			[ WkTimDsp ]	..... 7:「週間タイマーの設定表示と消去」
      

    そして、移行をしてきた本「週間タイマーの設定表示と消去」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • なお、「週間タイマーの設定表示と消去」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      LEFT スイッチ ........ 1つ前の登録情報を表示
      RIGHT スイッチ ........ 1つ後の登録情報を表示
      DOWN スイッチ ........ 表示している登録情報を消去
      UP スイッチ +
      DOWN スイッチ
      ........ すべての登録情報を消去
      EXIT スイッチ ........ 「メニューの選択」に戻る

  • 本機能での LCD 画面の表示は次の通りで、まず2行目の nn には 仮につけられた登録情報の番号 が、xx:xx には タイマー時間の時分 "HH:MM" が、そして1行目の www には 曜日 (略名) を表示 する。 本機能に移行をしてきた直後には、nn の登録情報の番号には "01" が選択される。 そして、PIC の内蔵メモリ(SRAM)に書き込まれている、1件目のタイマー情報が読み出され、その情報の時分 "HH:MM" と曜日 (略名) が表示される。
      			[ Dsp  www ]	..... www: 曜日 (略名) を表示
      			[ xx:xx nn ]	..... xx:xx 時分、nn: 登録情報の番号
      

  • 2件目以降のタイマー情報を表示させるときには、RIGHT スイッチ、または LEFT スイッチを押すことによって行ない、RIGHT スイッチ は押すごとに、登録情報の仮番号が1ずつ増加してその登録情報を表示する。 逆に、LEFT スイッチ は押すごとに、登録情報の仮番号が1ずつ減少してその登録情報を表示する。

  • そして、今 LCD 画面に表示されているタイマー情報が不要になった場合には、DOWN スイッチ を押すことによって、その表示されているタイマー情報だけを、内蔵メモリ(SRAM)から 個別に消去する ことができる。 また、すべての登録情報が不要になった場合には、UP スイッチ + DOWN スイッチ のスイッチ操作をすることによって、タイマー情報に割り当てられている内蔵メモリ(SRAM)の すべてを消去 する。 これらの消去をしたときには、"ピッピッ" アラーム音の出力と LED (緑) を点滅させる。

  • また、表示をさせる登録情報が1件もない場合には、nn は "00"、xx:xx は "00:00" 表示となり、www 位置には "None" の文字列が表示されるが、このときの "None" 文字列は、初めの 0.5 秒間は表示、かつ、"ブッ" アラーム音出力と LED (赤) を瞬間点滅させ、 次の 0.5 秒間は文字列を消滅させる ― の点滅表示を1秒周期で繰り返してユーザに知らせる。
      			[ Dsp None ]	..... "None" がブリンク表示
      			[ 00:00 00 ]	..... 00:00 時分、00: 登録情報の番号
      

  • タイマー情報の LCD 画面表示の確認が済んだら、EXIT スイッチ を押すと「メニューの選択」機能に戻ることができる。 また、上の "None" 文字列のブリンク表示になったときには、EXIT スイッチ を押すことしか選択肢はない。

| 「メニューの選択」機能に戻る |

◎ メニュー項目: 8 ... 「現在時刻の設定」機能
  • 本機の電源を初めて入れたときや、バックアップ用バッテリーを交換したときなどに、エラーメッセージが LCD 画面に表示され、それに応答をすると、リアルタイムクロック( RTC )モジュールが初期設定される。 しかし、年月日、時分秒が "2022/01/01"、"00:00:00" と、RTC モジュールをプログラミングしたときの初期値に設定がされるので、これをリアルな現在時刻に設定をし直す必要がある。 本機能はそのようなときのために設けられている。
      			[ 22/01/01 ]	..... RTC モジュールの
      			[ 00:00:00 ]	..... 初期値が表示される
      

  • 「メニューの選択」LCD 画面で、メニュー項目 8: [ ClockAdj ] を選択後に EXIT スイッチを押すと、本機能に移行(ジャンプ)してくる。 または、1:「現在時刻の表示」機能で、ENABLE スイッチ + EXIT スイッチの操作を行った場合にも、 同機能を終了して本機能に移行(ジャンプ)してくる。
      			[ Select_8 ]
      			[ ClockAdj ]	..... 8:「現在時刻の設定」
      

    そして、移行をしてきた本「現在時刻の設定」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • なお、「現在時刻の設定」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      LEFT スイッチ ........ ブリンク位置のポインタを - 1
      RIGHT スイッチ ........ ブリンク位置のポインタを + 1
      DOWN スイッチ ........ ブリンク位置の値を - 1
      UP スイッチ ........ ブリンク位置の値を + 1
      LEFT スイッチ +
      RIGHT スイッチ
      ........ 「現在時刻の設定」を中断し、「現在時刻の表示」に移行
      RIGHT スイッチ +
      LEFT スイッチ
      ........ 「現在時刻の設定」を中断し、「現在時刻の表示」に移行
      EXIT スイッチ ........ 「現在時刻の設定」を終了し、「現在時刻の表示」に移行

  • 本機能に移行(ジャンプ)してくると、まず、LCD 画面には次のように表示がされ、1行目では 年月日を設定する画面である ことを表している。 そして2行目には RTC モジュールに設定がされている現在の年月日が表示され、年 "yy" の左文字がブリンク表示されて、これから 年 "yy" が設定変更の対象であることを意味する。
      			[ Date Set ]	..... 年月日設定メッセージ
      			[ yy/nn/dd ]	..... 年月日の表示と設定
      

  • このブリンク表示される位置を変更したい場合には、RIGHT スイッチ、または LEFT スイッチ を押すことによって、ブリンク位置が右または左に移動をするので、変更をしたい 年 "yy"、月 "nn"、日 "dd" の位置にポイントする。 (この 月 "nn" という表現は、本来 月 "mm" とすべきだが、分 "mm" を優先させたので 月 "nn" とした)

  • このとき、日 "dd" がブリンク表示されているときに RIGHT スイッチを押すと、次の 時分秒を設定する LCD 画面 に変わって 時 "hh" がブリンク表示される。 また 年 "yy" がブリンク表示されているときに LEFT スイッチを押すと、 同様の LCD 画面に変わって 秒 "ss" がブリンク表示される。
      			[ Time Set ]	..... 時分秒設定メッセージ
      			[ hh:mm:ss ]	..... 時分秒の表示と設定
      

  • また、秒 "ss" がブリンク表示されているときに RIGHT スイッチを押すと、前の 年月日を設定する LCD 画面 に変わって 年 "yy" がブリンク表示される。 また 時 "hh" がブリンク表示されているときに LEFT スイッチを押すと、 同様の LCD 画面に変わって 日 "dd" がブリンク表示される。

  • このように、年 "yy"、月 "nn"、日 "dd"、時 "hh"、分 "mm"、秒 "ss" の、どこの位置にも自由にポイントすることができるので、次には、UP スイッチ、または DOWN スイッチを押すことによって、ブリンク位置の項目の設定値を変更することができる。

  • すなわち、UP スイッチ を押すごとに設定値が1ずつ増加し、DOWN スイッチ を押すごとに1ずつ減少する。 このときの増減幅を大きくしたい場合には、UP スイッチ、または DOWN スイッチを押したままにしていると、1秒当たり 4 〜 5 の増減幅で更新をするようになる。

  • 以上のようにしてリアルな現在時刻の設定値が入力できたら、最後に EXIT スイッチ を押すと、リアルタイムクロック( RTC )モジュールにその設定値が書き込まれる。 そして、本機能は終了して 1:「現在時刻の表示」機能 に移行(ジャンプ)をする。 「メニューの選択」機能に戻るのではなく、1:「現在時刻の表示」機能に移行するのは、正しく設定変更ができたかを 直ちに確認ができるようにするためである。

  • 本機能で現在時刻の設定操作中に、何らかの理由で本機能を中断したくなった場合には、LEFT スイッチ + RIGHT スイッチ、または RIGHT スイッチ + LEFT スイッチ の操作をすることで、設定値は RTC モジュールに書き込まれることはなく、 本機能を途中で中断終了して 1:「現在時刻の表示」機能に移行する。

| 「メニューの選択」機能に戻る |

◎ メニュー項目: 9 ... 「スリープ移行時間の変更」機能
  • 本機では9つのメニュー項目(機能)の内、1:「現在時刻の表示」機能4:「ストップウオッチ(長時間)」機能5:「記録内容の表示」機能 の3機能についてのみ、 スリープ機能が動作するようにさせている。 特に、1:「現在時刻の表示」機能、4:「ストップウオッチ(長時間)」機能については、長時間に亘る使用が予想されるため、一定時間スイッチの入力がない場合 には自動的に LCD の電源を切り、 本機の PIC をスリープ状態にさせて電池の消耗を抑えるようにしている。

  • その一定時間を、メニュー項目 1: では 3 分、メニュー項目 4: では 1 分、メニュー項目 5: では 1 分 と、当初は固定をしていたが、使用状況によっては変更ができる方がより便利 ― と考え直して、ここに 1 分 〜 15 分 の範囲 で自由に変更ができる、9:「スリープ移行時間の変更」機能を追加した。

  • 「メニューの選択」LCD 画面で、メニュー項目 9: [ SleepTim ] を選択後に EXIT スイッチを押すと、本機能に移行(ジャンプ)してくる。
      			[ Select_9 ]
      			[ SleepTim ]	..... 9:「スリープ移行時間の変更」
      

    そして、移行をしてきた本「スリープ移行時間の変更」機能では、"ピポッピポッ" アラーム音の出力と LED (緑) を点滅させて、本機能に動作が移ったことを知らせる。

  • なお、「スリープ移行時間の変更」機能では次図に示す黒塗りのスイッチだけを使用し、それらのスイッチ名を赤字で示した名前で呼ぶ。 また、本機能においてのスイッチ操作の要点を先にまとめておくと、次のようになる。
      LEFT スイッチ ........ ブリンク位置のポインタを - 1
      RIGHT スイッチ ........ ブリンク位置のポインタを + 1
      DOWN スイッチ ........ ブリンク位置の値を - 1
      UP スイッチ ........ ブリンク位置の値を + 1
      DOWN スイッチ +
      UP スイッチ
      ........ すべてのデフォルト値を一括設定
      UP スイッチ +
      DOWN スイッチ
      ........ すべてのデフォルト値を一括設定
      LEFT スイッチ +
      RIGHT スイッチ
      ........ 「スリープ移行時間の変更」を中断し、「メニューの選択」に戻る
      RIGHT スイッチ +
      LEFT スイッチ
      ........ 「スリープ移行時間の変更」を中断し、「メニューの選択」に戻る
      EXIT スイッチ ........ 「スリープ移行時間の変更」を終了し、「メニューの選択」に戻る

  • 本機能に動作が移ると LCD 画面には、次の形式で、現在設定されているそれぞれの値(分)が2行目に表示され、かつ、2行目の先頭がブリンク表示、すなわち メニュー項目 1 の設定値を変更するようにユーザに促す。 下の写真例ではデフォルト(既定)値が表示されている。
      			[ M1,M4,M5 ]	..... M1: メニュー項目 1, M4: メニュー項目 4, M5: メニュー項目 5
      			[ xx xx xx ]	..... 現在設定されている、それぞれの値(分)が表示される
      

  • このブリンク表示の位置は、LEFT スイッチ、または RIGHT スイッチ を押すことによって、自由に左または右に移動をするので、変更をしたいメニュー項目の位置にポイントする。

  • 変更をしたいメニュー項目が決まったら、次に UP スッチ を押すごとに1ずつ増加、または DOWN スイッチ を押すごとに1ずつ減少することができる。 これらの設定値は 1 分 〜 15 分 の範囲 で自由に変更設定をすることができる。

  • またこの設定中に、UP スッチ + DOWN スイッチ 、または DOWN スッチ + UP スイッチ の操作をすると、現在どのような設定値が表示されていても、3つすべての設定値を、一瞬にデフォルト値(すなわち、メニュー項目 1: では 3 分、メニュー項目 4: では 1 分、メニュー項目 5: では 1 分)の表示に一括して戻す機能を持つ。

  • 3つすべての設定が済んだら最後に EXIT スイッチ を押すと、それらの設定値が新たなバックアップデータとして EEPROM に書き込みが行われ、本機能を終了して「メニューの選択」機能に戻る。

  • なお、何らかの理由で設定中に本機能を中断したくなった場合には、LEFT スイッチ + RIGHT スイッチ、または RIGHT スイッチ + LEFT スイッチ の操作をすることで、それまでの変更されて表示されている設定値は破棄され、 本機能を終了して「メニューの選択」機能に戻る。
 | 「メニューの選択」機能に戻る | ページトップ |

■ プログラム ■

 アセンブラで PIC16F1 ファミリーのプログラミングを行うのは、私にとって、"194. FMステレオラジオ III" 、"195. ドットマトリクス LED コントローラー" に続いて、 本機が第3作目となります。 前作では PIC16F1705 と PIC16F1709 を使用しましたが、本機には PIC16F1827 を選択してみました。

 PIC16F1827 は 18 ピン PIC で、PIC16F ファミリーの PIC16F627A/628A/648A、PIC16F818/819、PIC16F87/88 などと、ピンコンパチブルとなっています。

 この項では、"リニア データメモリのプログラミング"、"不揮発性メモリ EEPROM のプログラミング"、"様々なテーブルデータ選択のプログラミング"、および "プログラミング時に起きた不具合" などについての経験談を、述べてみたいと思います。
● リニア データメモリのプログラミング

 次の表 TABLE 3-3 は、PIC16F1827 の具体的な データメモリ の一部分をデータシートから抜粋したもので、黄色に彩色した 特殊レジスタ(SFR) を本機のプログラムでは使用しています。 表中の赤線より上に位置するレジスタ群は コアレジスタ と呼ばれ、バンク切り替えを行うことなくすべてのバンクからアクセスができる共通メモリです。

 同表の下方に位置する 汎用レジスタ(GPR) の内、薄緑色に彩色をしたバンク 0 については、従来型データメモリ として使用をし、水色に彩色をしたバンク 1 〜 バンク 4 については、リニア データメモリ *1 として本機のプログラムでは扱っています。

 下図は、上表の汎用レジスタ(GPR)について描き直したもので、本機のプログラムで使用しているリニア データメモリの使用状況を表しています。 上述のように、バンク 1 〜 バンク 4 はリニア データメモリとして扱っており、各バンクの右側に付けた 2000 番台の番号は、リニア データメモリとしてのアドレスを示しています。

 リニア データメモリは、各バンクの 80 バイトずつの領域(下図の左端に示した 80 Bytes ずつの領域)を、すべてつなぎ合わせて 連続領域として使用ができる ようにした仮想領域です。 この概念は、従来の PIC16F ファミリーにはなく、 PIC16F1 ファミリーになって新しく取り入れられたもので、FSRnH と FSRnL のレジスタペアで間接アドレス指定をして、すべての領域を簡単にアクセスすることができます。

 下図内のスプリットメモリについては、バンク 1 〜 バンク 3 の3つのバンクに分散をしていますが、リニア データメモリのアドレスを使用することで、連続領域としてアクセスすることができます。 これに対して、従来の PIC16F ファミリーでは、 間接アドレス指定をしても、各バンクの左側に付けた不連続なアドレスの指定になるので、プログラミングはその分かなり面倒になります。(その実例が、"184. ストップウオッチ II" の "PIC16F628A と PIC16F648A のデータメモリの構成図"、および "ソースファイル (StopWatchII.asm)" にあるので、興味がある方はそちらをご覧ください。)
 次のリストは、本機プログラムのアセンブルリストから抜粋をしたもので、リニア データメモリのアドレスを定義している部分です。 左端の数値がアセンブラ mpasmx.exe によって翻訳された部分で、> 印を付けた行に注目をしてください。 タイマーメモリ、スプリットメモリの各先頭アドレスになり、上図のリニア データメモリのアドレスを示しています。 リスト中で 3 * xxxxx_capacity としてあるのは、どちらも1メモリ要素当たり3バイト構成のため 3 を掛けています。 (なお next_memory (2122h) 以降の領域は本機プログラムでは未使用)
        			:
        			:
                              01297                 radix   dec
        			:
          00002050            01303 linear_memory   equ     h'2000' + 80                      ;リニアデータメモリの先頭アドレス
        > 00002050            01304 timer_memory    equ     linear_memory                     ;タイマー用メモリの先頭アドレス
          00000014            01305 timer_capacity  equ     20                                ;タイマー用メモリの記憶容量の最大値
        > 0000208C            01306 split_memory    equ     timer_memory + 3 * timer_capacity ;スプリット用メモリの先頭アドレス
          00000032            01307 split_capacity  equ     50                                ;スプリットタイムの記憶容量の最大値
        > 00002122            01308 next_memory     equ     split_memory + 3 * split_capacity ;次に使用できるメモリの先頭アドレス
        			:
        			:
        
 実際に、本機のプログラムでリニア データメモリ内のスプリットメモリに、 "時"、"分"、"秒" のスプリットデータを読み書きしている部分が次に示すリストで、このように各バンクをまったく意識しないでプログラミングすることができます。 (上述の "184. ストップウオッチ II" の実例と比べてみると、その違いがよくわかると思います。)
        ;--------------------------------------------------------------------------
        ;		経過時間(スプリットタイム)を書き込み
        ;--------------------------------------------------------------------------
        
        write_split_memory
        
        		movlw	high split_memory	;スプリット用メモリの先頭アドレス
        		movwf	FSR1H			;
        		movlw	low split_memory	;
        		movwf	FSR1L			;
        
        		movf	split_cnt,W
        		btfsc	STATUS,Z		;スプリット番号カウンタ = 0 か?
        		goto	wrmem02			;Yes
        
        		movwf	lp_cnt2			;ループカウンタ2
        
        wrmem01		addfsr	FSR1,3			;
        		decfsz	lp_cnt2,F		;ループカウンタ2 - 1 = 0 か?
        		goto	wrmem01			;No
        
        wrmem02		movf	bcd_hh_s,W		;
        		movwi	FSR1++			;時_BCD カウンタ 書き込み
        
        		movf	bcd_mm_s,W		;
        		movwi	FSR1++			;分_BCD カウンタ 書き込み
        
        		movf	bcd_ss_s,W		;
        		movwi	FSR1++			;秒_BCD カウンタ 書き込み
        
        		incf	split_cnt,F		;スプリット番号カウンタ + 1
        		return
        
        ;--------------------------------------------------------------------------
        ;		経過時間(スプリットタイム)を読み出し
        ;--------------------------------------------------------------------------
        
        read_split_memory
        
        		movlw	high split_memory	;スプリット用メモリの先頭アドレス
        		movwf	FSR1H			;
        		movlw	low split_memory	;
        		movwf	FSR1L			;
        
        		decf	split_cnt,W
        		btfsc	STATUS,Z		;スプリット番号カウンタ - 1 = 0 か?
        		goto	rdmem02			;Yes
        
        		movwf	lp_cnt2			;ループカウンタ2
        
        rdmem01		addfsr	FSR1,3			;
        		decfsz	lp_cnt2,F		;ループカウンタ2 - 1 = 0 か?
        		goto	rdmem01			;No
        
        rdmem02		moviw	FSR1++			;
        		movwf	bcd_hh_w		;時_BCD カウンタ 読み出し
        
        		moviw	FSR1++			;
        		movwf	bcd_mm_w		;分_BCD カウンタ 読み出し
        
        		moviw	FSR1++			;
        		movwf	bcd_ss_w		;秒_BCD カウンタ 読み出し
        
        		return
        
 なお、話が少しばかり逸れますが、リスト中で使用している MOVWI、MOVIW 命令の書き方にはいろいろなバリエーションがあって、上リストの場合には、下のアセンブルリスト例のように (1) (2) どちらの書き方をしても構いません。 両者の違いは (1) では MOVWI 命令が実行される度に、FSR1 の指すポイント/アドレス(FSR1H と FSR1L のレジスタペアの内容)が1ずつインクリメントされていきます。

 これに対して (2) では命令が実行されても FSR1 の指すポイント(FSR1H と FSR1L のレジスタペアの内容)に変化はなく、今 FSR1 が指しているポイントに対しての相対的な位置が指定されます。 1[FSR1] と書けば今 FSR1 が指しているポイントに1プラスしたアドレスを指しますが、FSR1 自体の指すポイントに変化はありません。
            ↓
        0B0D   0829           05632                 movf    bcd_hh_s,W              ;
        0B0E   001E           05633                 movwi   FSR1++                  ;(1)
        0B0F   3FC0           05634                 movwi   0[FSR1]                 ;(2)
        0B10   001E           05635                 movwi   INDF1++                 ;(3)
                              05636 
        0B11   082A           05637                 movf    bcd_mm_s,W              ;
        0B12   001E           05638                 movwi   FSR1++                  ;(1)
        0B13   3FC1           05639                 movwi   1[FSR1]                 ;(2)
        0B14   001E           05640                 movwi   INDF1++                 ;(3)
                              05641 
        0B15   082B           05642                 movf    bcd_ss_s,W              ;
        0B16   001E           05643                 movwi   FSR1++                  ;(1)
        0B17   3FC2           05644                 movwi   2[FSR1]                 ;(2)
        0B18   001E           05645                 movwi   INDF1++                 ;(3)
        
 ところで、上リストの (1) と (3) とを見比べてみてください。 ↓ で示した列部分が翻訳された機械語の部分ですが、まったく同じであることが分かります。 しかし、MOVWI、MOVIW 命令のどちらも同様ですが、次に示すように PIC16F/LF1826/27 のデータシート (DS41391B-page 332, page 333)には、この (3) の書き方は載っていません。
        MOVIW	   Move INDFn to W
        ----------------------------------------
        Syntax:    [ label ] MOVIW ++FSRn
        	   [ label ] MOVIW --FSRn
        	   [ label ] MOVIW FSRn++
        	   [ label ] MOVIW FSRn--
        	   [ label ] MOVIW k[FSRn]
        	   [ label ] MOVIW FSRn		;(4)
        
        Operation: INDFn → W
        
        
        MOVWI	   Move W to INDFn
        ----------------------------------------
        Syntax:    [ label ] MOVWI ++FSRn
        	   [ label ] MOVWI --FSRn
        	   [ label ] MOVWI FSRn++
        	   [ label ] MOVWI FSRn--
        	   [ label ] MOVWI k[FSRn]
        	   [ label ] MOVWI FSRn		;(4)
        
        Operation: W → INDFn
        
 この (3) の書き方は偶然にも私が見つけた?もので、自分が書いたプログラムの中に (1) と (3) の書き方が混在していて、(3) は誤って書いたのですがエラーにはならず、どちらも同じ機械語に翻訳されているのを見つけた次第です。 その後、紛らわしいのでとりあえずデータシート通り (1) の書き方に統一をしました。*2
    *2: ところが、またその後になって、データシート内で (3) の書き方をしている例を見つけました。 このようにメーカーとしての例があることから、どちらの書き方をしても特に問題はなさそうです。

 しかし、データシート の中の (4) の書き方は誤りで、このように書くと次のリストのようにエラーになります。
        Error[124]  : Illegal argument
        0B19                  05648                 movwi   FSR1                    ;(4)
        0B19   3FC0           05649                 movwi   [FSR1]                  ;(5)
                              05650 
        Error[124]  : Illegal argument
        0B1A                  05651                 moviw   FSR1                    ;(4)
        0B1A   3F40           05652                 moviw   [FSR1]                  ;(5)
        
 この場合に (5) のように角カッコ[ ]を付けるとエラーとはならず、 0[FSR1] と書いたときと同等になります。 最初の リスト の3行目 (2) の機械語と比べてみてください。

| プログラムのトップに戻る |


● 不揮発性メモリ EEPROM のプログラミング

 データの保存に使用する 不揮発性メモリ としては、PIC16F1705/1709 のように高書き込み耐性フラッシュメモリ *3 ではなく、PIC16F1827 でも従来の PIC16F ファミリーと同様に EEPROM が搭載 されているので、 その点ではプログラミングも比較的楽に行えます。
 不揮発性メモリのプログラミングで必要な SFR レジスタには、上述の リニア データメモリのプログラミングTABLE 3-3 で示した表の中の、EEADRL、EEADRH、EEDATL、EEDATH、EECON1、EECON2 の6個で、バンク 3 に集中をしています。 この中で EEPROM のプログラミングに限って言えば、EEADRH、EEDATH の2個を除いた、EEADRLEEDATLEECON1EECON2 の4個だけが必要になります。 ちなみに、フラッシュプログラムメモリのプログラミングでは、 6個すべてを使用します。

 本機のプログラムでは、3:「インターバル(間隔)タイマー」機能、6:「週間タイマーの時刻設定」機能、7:「週間タイマーの設定表示と消去」機能、9:「スリープ移行時間の変更」機能の、4つの機能で EEPROM にアクセスをして、それらの機能で必要なバックアップデータを書き込んだり、 読み出したりをしています。

 次に示すリストは、9:「スリープ移行時間の変更」機能の例で、4つの機能の中で最も単純な読み書きを行っているだけなので、例として取り上げました。
        ;--------------------------------------------------------------------------
        ;		スリープ移行時間(分)を EEPROM へ書き込み
        ;--------------------------------------------------------------------------
        
        write_sleep_time
        
        		movlw	high menu_1		;menu_1 スリープ移行時間(分)カウンタのアドレス
        		movwf	FSR0H			;
        		movlw	low menu_1		;
        		movwf	FSR0L			;間接アドレスに設定
        
        		movlw	3			;書き込みバイト数
        		movwf	lp_cnt1			;ループカウンタ1
        
        		movlb	3			;バンク 3
        		movlw	low eep_sleep_time
        		movwf	EEADRL			;EEPROM の記録アドレスを設定
        		bcf	EECON1,CFGS		;フラッシュプログラム/データ EEPROM メモリを選択
        		bcf	EECON1,EEPGD		;データ EEPROM メモリにアクセス
        
        wrslp01		movlb	3			;バンク 3
        		moviw	FSR0++			;BCD カウンタデータの読み出し
        		movwf	EEDATL			;書き込みデータを設定
        
        		bsf	EECON1,WREN		;プログラム/消去サイクルを許可
        	;	bcf	INTCON,GIE		;割り込みを禁止
        		movlw	h'55'
        		movwf	EECON2			;h'55' を EECON2 に書き込む
        		movlw	h'aa'
        		movwf	EECON2			;h'aa' を EECON2 に書き込む
        
        		bsf	EECON1,WR		;書き込み開始
        	;	bsf	INTCON,GIE		;割り込みを許可
        		bcf	EECON1,WREN		;プログラム/消去サイクルを禁止
        		btfsc	EECON1,WR		;書き込み 終了か?
        		goto	$ - 1			;No
        
        		incf	EEADRL,F		;記録アドレスの更新
        
        		movlb	0			;バンク 0
        		decfsz	lp_cnt1,F		;ループカウンタ1 - 1 = 0 か?
        		goto	wrslp01			;No
        
        		return
        
        ;--------------------------------------------------------------------------
        ;		スリープ移行時間(分)を EEPROM から読み出し
        ;--------------------------------------------------------------------------
        
        read_sleep_time
        
        		movlw	high menu_1		;menu_1 スリープ移行時間(分)カウンタのアドレス
        		movwf	FSR0H			;
        		movlw	low menu_1		;
        		movwf	FSR0L			;間接アドレスに設定
        
        		movlw	3			;読み出しバイト数
        		movwf	lp_cnt1			;ループカウンタ1
        
        		movlb	3			;バンク 3
        		movlw	low eep_sleep_time
        		movwf	EEADRL			;EEPROM の記録アドレスを設定
        		bcf	EECON1,CFGS		;フラッシュプログラム/データ EEPROM メモリを選択
        		bcf	EECON1,EEPGD		;データ EEPROM メモリにアクセス
        
        rdslp01		movlb	3			;バンク 3
        		bsf	EECON1,RD		;読み出し制御 = ON
        		movf	EEDATL,W		;データの読み出し
        		movwi	FSR0++			;BCD カウンタデータへ書き込み
        		incf	EEADRL,F		;記録アドレスの更新
        
        		movlb	0			;バンク 0
        		decfsz	lp_cnt1,F		;ループカウンタ1 - 1 = 0 か?
        		goto	rdslp01			;No
        
        		return
        
 なお、EEPROM エリア内のバックアップデータの格納場所の割り付けは、以下のリストのようになっています。
        ;==========================================================================
        ;		EEPROM エリア
        ;==========================================================================
        
        		org	h'f000'
        
        			:
        			:
        
        		; スリープ移行時間(分)のバックアップ格納位置
        
        eep_sleep_time
        		de	3,1,1			;初期(デフォルト)値
        
        		; インターバルタイマーの格納位置
        
        itv_timer_memory
        		de	h'00',h'00',h'00'	;初期値
        
        		; タイマー用メモリのバックアップ格納位置
        
        eep_timer_memory
        		de	h'00'			;初期値
        
        		; (3 * timer_capacity) バイトサイズを使用
        
 ここで EEPROM に関する失敗談を1つ。 本機のプログラミングも終盤に近付いたころ、MPLAB X IDE のトンカチをクリックすると、突然、おかしなエラーメッセージが表示されました。 まだ、ソースプログラムに文法エラーなどが残っているときには、こんなエラーメッセージは現れませんが、文法エラーがなくなった途端、このメッセージが現れたのです。
        make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
        make[1]: Entering directory 'C:/Data/Project/PIC/MultifuncDigitalClock/MultifuncDigitalClock.X'
        make  -f nbproject/Makefile-default.mk dist/default/production/MultifuncDigitalClock.X.production.
        make[2]: Entering directory 'C:/Data/Project/PIC/MultifuncDigitalClock/MultifuncDigitalClock.X'
        "C:\Program Files (x86)\Microchip\MPLABX\v5.35\mpasmx\mpasmx.exe" -q -p16f1827 -l"build/default/production/_ext/465711987/MultifuncDigitalClock.lst" 
              -e"build/default/production/_ext/465711987/MultifuncDigitalClock.err" -o"build/default/production/_ext/465711987/MultifuncDigitalClock.o" 
              "C:/Data/Project/PIC/MultifuncDigitalClock/MultifuncDigitalClock.X/MultifuncDigitalClock.asm" 
        "C:\Program Files (x86)\Microchip\MPLABX\v5.35\mpasmx\mplink.exe"    -p16f1827  -w  -m"dist/default/production/MultifuncDigitalClock.X.production.map"   
              -z__MPLAB_BUILD=1  -odist/default/production/MultifuncDigitalClock.X.production.  build/default/production/_ext/465711987/MultifuncDigitalClock.o     
        MPLINK 5.09, LINKER
        Device Database Version 1.50
        Copyright (c) 1998-2011 Microchip Technology Inc.
      > Error - section '.org_3' can not fit the absolute section. Section '.org_3' start=0x00002100, length=0x0000004a
        Errors    : 1
      
        make[2]: Leaving directory 'C:/Data/Project/PIC/MultifuncDigitalClock/MultifuncDigitalClock.X'
        make[1]: Leaving directory 'C:/Data/Project/PIC/MultifuncDigitalClock/MultifuncDigitalClock.X'
        make[2]: *** [nbproject/Makefile-default.mk:126: dist/default/production/MultifuncDigitalClock.X.production.] Error 1
        make[1]: *** [nbproject/Makefile-default.mk:91: .build-conf] Error 2
        make: *** [nbproject/Makefile-impl.mk:39: .build-impl] Error 2
      
        BUILD FAILED (exit value 2, total time: 1s)
      
 上のメッセージ中で、左端に > 印を付けた行がエラーメッセージな訳で、その行だけを再掲すると
        Error - section '.org_3' can not fit the absolute section. Section '.org_3' start=0x00002100, length=0x0000004a
      
となります。 これはリンカー MPLINK 5.09, LINKER から発せられたもので、どうやらリンクエラーのようです。 start=0x00002100, length=0x0000004a がおかしい ??? と言っているようです。

 念のためアセンブルリストを確認してみても、もちろんエラーなどはどこにも見当たりません。 そして、これに似たエラーメッセージを以前にも見たことを思い出しました。 (興味のある方は "188. FMステレオラジオ II" の PIC16F684 と MPLAB IDE v8.92 のリンクエラーについて を参照のこと)

 このエラーになったときの、リンカーが作り出す .map ファイル の先頭部分を見てみると、
      MPLINK 5.09, LINKER
      Linker Error Map File - Created Sun Oct 01 19:40:54 2023
      
      *Warning* - This is only a partial map file due to a link time error.
         Only sections which were allocated prior to the error are shown below.
      
      CODEPAGES:
          Memory      Start        End              Section    Address Size(Bytes)
       ---------  ---------  ---------            ---------  ---------  ---------
           page0     0x0000     0x07ff               .org_0     0x0000     0x0002
                                                     .org_1     0x0004     0x0ed0
      
           page1     0x0800     0x0fff               .org_2     0x0800     0x0d08
      
         .idlocs     0x8000     0x8003                                           
      
          .devid     0x8006     0x8006                                           
      
         .config     0x8007     0x8008 .config_8007_BUILD/DEFAULT/PRODUCTION/_EXT/46     0x8007     0x0002
                                       .config_8008_BUILD/DEFAULT/PRODUCTION/_EXT/46     0x8008     0x0002
      
          eedata     0xf000     0xf0ff                                           
      
      			:
      			:
      
と出力されています。 ここに解答がありました。 上に表示したリスト中の最下行
          eedata     0xf000     0xf0ff                                           
      
が解答そのものでした。 EEPROM の開始アドレスは 0xf000 だ、というのです。 そうなんです。 私が書いたソースプログラムには、MPLAB X IDE に表示されたエラーメッセージの、開始アドレス start=0x00002100 を指定していたのです。
        ;==========================================================================
        ;		EEPROM エリア
        ;==========================================================================
        
        		org	h'2100'
        
        			:
        			:
        
        		; スリープ移行時間(分)のバックアップ格納位置
        
        eep_sleep_time
        		de	3,1,1			;初期(デフォルト)値
        
        		; インターバルタイマーの格納位置
        
        itv_timer_memory
        		de	h'00',h'00',h'00'	;初期値
        
        		; タイマー用メモリのバックアップ格納位置
        
        eep_timer_memory
        		de	h'00'			;初期値
        
        		; (3 * timer_capacity) バイトサイズを使用
        
 深く考えもしないで、従来の PIC16F ファミリーで指定をしていた開始アドレスを書いていました。 少し考えれば分かるはずで、この領域は PIC16F1 ファミリーでは、通常はプログラムメモリの領域です。 そこに EEPROM が存在するはずがない。 おそまつでした。

 そして、正解は上述のように 0xf000 ですが、このアドレスをデータシート(DS41391B)で探してみましたが、どうやら載っていないようで見つけることができませんでした。

| プログラムのトップに戻る |


● テーブルデータ選択のプログラミング(LCD の表示位置の取得)

 次に示すリスト <例−1> <例−2> は、本機の 2:「ストップウオッチ(詳細)」機能 において、時、分、秒、1/100 秒 のそれぞれを、LCD 画面上のどの位置に表示するかを指示するためのテーブルで、表示位置ポインタ dsp_point( 0〜7 )の値から LCD の DDRAM アドレスを 取得するためのものです。

 従来の PIC16F ファミリーでは <例−1> のように、一般的には addwf PCL,F としてテーブルデータ選択を行っていました。 この命令を使用したときの問題点は、各テーブル要素(この例では8個)が機械語に翻訳されたときにプログラムメモリの xxFF 〜 xx00 番地にまたがった場合には正常な動作をしない ― という点です。
        <例−1>
        dsp_point_table
        		movf	dsp_point,W		;表示位置ポインタ
        
        		addwf	PCL,F
        
        		;	0     1     2     3     4     5      ;  01 23 45  ... dsp_point
        		;	"HH"  "HL"  "MH"  "ML"  "SH"  "SL"   ; "xx:xx:xx" ... 桁
        		;					     ;  01234567
        		dt	h'00',h'01',h'03',h'04',h'06',h'07'  ;            ... DDRAM のアドレス (1行目)
        
        		;	                        6     7      ;        67  ... dsp_point
        		;	                        "XH"  "XL"   ; "(StW) xx" ... 桁
        		;					     ;  01234567
        		dt	                        h'46',h'47'  ;            ... DDRAM のアドレス (2行目)
        
 この <例−1> のように addwf PCL,F とした場合には、次図に示すように PIC16F ファミリー、PIC16F1 ファミリーのどちらの場合にも、xxFF 番地までのテーブル要素に対しては正常に動作をしますが、xx00 番地以降のテーブル要素に対しては、ALU の結果(PCL + W)で オーバーフローしたビットが PCH に反映されません。 したがって、プログラムカウンタ(PC)の指すアドレスは、100 番地を差し引いたアドレスとなって希望するテーブル要素を取得することはできず、多くの場合、プログラムは暴走することになります。

( PIC16F ファミリーの場合 ) ( PIC16F1 ファミリーの場合 )
 そのために、プログラマはこのようなプログラムのメモリ配置とならないように、テーブル要素を置く位置を常に配慮(具体的にはアセンブルリストなどで確認を)しながら、プログラミングを行う必要がありました。 PIC16F1 ファミリーでは、新たに BRW 命令 が追加され、 次のリスト <例−2> がこの BRW 命令を使用した例です。
        <例−2>
        dsp_point_table
        		movf	dsp_point,W		;表示位置ポインタ
        
        		brw
        
        		;	0     1     2     3     4     5      ;  01 23 45  ... dsp_point
        		;	"HH"  "HL"  "MH"  "ML"  "SH"  "SL"   ; "xx:xx:xx" ... 桁
        		;					     ;  01234567
        		dt	h'00',h'01',h'03',h'04',h'06',h'07'  ;            ... DDRAM のアドレス (1行目)
        
        		;	                        6     7      ;        67  ... dsp_point
        		;	                        "XH"  "XL"   ; "(StW) xx" ... 桁
        		;					     ;  01234567
        		dt	                        h'46',h'47'  ;            ... DDRAM のアドレス (2行目)
        
 PIC16F/LF1826/27 のデータシート (DS41391B-page 328)から BRW 命令を抜粋すると、
        BRW              Relative Branch with W
        ----------------------------------------
        Syntax:          [ label ] BRW 
        
        Operands:        None
        
        Operation:       (PC) + (W) → PC
        
        Status Affected: None
        
と、説明があります。 この BRW 命令の動作が分かり易いように図に表してみると、次図に示すように、プログラムカウンタ(PC)の全体(15 ビット)に対して W レジスタの内容を加算するため、<例−1> の場合とは異なって、テーブル要素が xxFF 〜 xx00 番地にまたがっていても、 何の問題も起こりません。
 このように、同様な目的でテーブルデータ選択のプログラミングを行う場合には、PIC16F1 ファミリーでは、addwf PCL,F 命令ではなく BRW 命令を使用する ことによって、何の問題もなく目的を達することができます。

| プログラムのトップに戻る |


● テーブルデータ選択のプログラミング(文字列の LCD 表示)

 本機では9つの機能(メニュー項目)を持たせてありますが、それらのどの機能を実行させるかを、まず、UP スイッチまたは DOWN スイッチの操作よって、LCD 画面上に表示するメニュー項目の1つを選択させ、次に、EXIT スイッチを押すことによって選択が決定されて、 各メニュー項目の機能が実行されます。(「メニューの選択」機能 を参照)

 ここで、「メニューの選択」機能においての、テーブルデータ選択のプログラミングの1つ目を紹介します。 本機で使用している LCD のハード的な制約(8文字 x 2行)から、メニュー項目のすべてを1度に表示させることができません。 そこで、上述のように UP スイッチまたは DOWN スイッチを押すごとに、メニュー番号 menu_no を 1 〜 9 までの範囲で変更させ、その menu_no の値によってメニュー項目の名称(略名)をテーブル引きをして、1行(1項目)ずつ LCD 画面上に表示をしています。
        			:
        			:
        
        		movf	menu_no,W		;メニュー番号
        		movwf	work1			;退避
        		clrf	menu_no
        
        		;	[ Select_  ]		;1行目 ... Select_ の表示
        		;     ( [ ClockDsp ] )		;2行目 ... メニュー項目の表示
        		;	  01234567
        
        		movlw	h'80'			;表示位置指定 (1行目先頭)
        		call	menu_display		;メニュー選択の表示(1行目)	<<<<<
        
        		movf	work1,W			;復帰
        		movwf	menu_no			;メニュー番号
        
        main01		bcf	stat_flg,6		;スイッチ入力有りフラグ = 0
        		movlw	h'0c'			;表示オン/オフコントロール
        		call	I2cLcd_Cmd		;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク
        
        		;     ( [ Select_  ] )		;1行目 ... Select_ の表示
        		;	[ ClockDsp ]		;2行目 ... メニュー項目の表示
        		;	  01234567
        
        		movlw	h'c0'			;表示位置指定 (2行目先頭)
        		call	menu_display		;メニュー項目の表示(2行目)	<<<<<
        
        		movlw	h'87'			;
        		call	I2cLcd_Cmd		;表示位置指定 
        		movf	menu_no,W		;メニュー番号
        		iorlw	h'30'			;数字に変換
        		call	I2cLcd_Data		;I2C LCD へデータを1文字出力
        
        		movlw	h'87'			;
        		call	I2cLcd_Cmd		;表示位置指定 
        		movlw	h'0d'			;表示オン/オフコントロール
        		call	I2cLcd_Cmd		;D=1: 表示オン, C=0: カーソル非表示, B=1: ブリンク
        
        		; 各スイッチの入力チェック
        
        			:
        			:
        
        ;--------------------------------------------------------------------------
        ;		メイン・メニューの表示
        ;--------------------------------------------------------------------------
        
        menu_display
        		call	I2cLcd_Cmd		;I2C LCD へコマンドを出力(表示位置を指定)
        
        		movf	menu_no,W		;メニュー番号
        		movwf	addr_low
        		lslf	addr_low,F		;x 2 倍
        		lslf	addr_low,F		;x 4 倍
        		lslf	addr_low,F		;x 8 倍
        		addwf	addr_low,F		;x 9 倍
        
        		movlw	high menu_table		;テーブルデータの先頭 high アドレス
        		movwf	addr_high		;
        		movlw	low menu_table		;テーブルデータの先頭 low アドレス
        		addwf	addr_low,F		;
        		btfsc	STATUS,C		;オーバーフローした場合は
        		incf	addr_high,F		;high アドレスの更新
        
        		call	I2cLcd_Disp		;I2C LCD へ文字列データを出力
        		return
        
        		; メニュー データテーブル
        menu_table
        		dt	"Select_ ",0		; (例外)   0	「メニューの選択」
        
        		dt	"ClockDsp",0		;menu_no = 1	「現在時刻の表示」
        		dt	"DtlStopW",0		;          2	「ストップウオッチ(詳細)」
        		dt	"ItvTimer",0		;          3	「インターバル(間隔)タイマー」
        		dt	"LngStopW",0		;          4	「ストップウオッチ(長時間)」
        		dt	"MemoDisp",0		;          5	「記録内容の表示」
        		dt	"WkTimSet",0		;          6	「週間タイマーの時刻設定」
        		dt	"WkTimDsp",0		;          7	「週間タイマーの設定表示と消去」
        		dt	"ClockAdj",0		;          8	「現在時刻の設定」
        		dt	"SleepTim",0		;          9	「スリープ移行時間の変更」
        ;			 01234567
        
 上のリスト中で、menu_display サブルーチン 内で使用されている I2cLcd_Disp サブルーチン は、インクルードファイル I2C LCD 制御サブルーチン (I2C_S2_LCD.sub) 内に収容されて * いますが、 次にも掲載をしておきます。 なお、I2cLcd_Cmd、I2cLcd_Data サブルーチンについても、同 I2C_S2_LCD.sub ファイル内に収容されています。
        I2cLcd_Disp
        		call	tbl_read	;テーブルデータの読み出し
        		incf	addr_low,F	;読み出すデータの low アドレスの更新
        		btfsc	STATUS,Z	;オーバーフローした場合は
        		incf	addr_high,F	;読み出すデータの high アドレスの更新
        
        		addlw	0
        		btfsc	STATUS,Z	;h'00' か?
        		goto	i2cldsp01	;Yes
        
        		call	I2cLcd_Data	;LCD へデータを1文字出力
        		goto	I2cLcd_Disp
        
        i2cldsp01	return
        
        		; テーブルデータの1文字読み出し
        tbl_read
        		movf	addr_high,W	;読み出すデータの high アドレス
        		movwf	PCLATH
        		movf	addr_low,W	;読み出すデータの low アドレス
        		movwf	PCL
        
 この I2cLcd_Disp サブルーチンは、PIC16F1 ファミリーの場合には、FSRnH と FSRnL のレジスタペアを使用した方が何かと便利ですが、PIC16F ファミリーにおいても、同一の I2C_S2_LCD.sub ファイルに収容されているサブルーチン群を使用するため、汎用レジスタ(GPR)の addr_high、addr_low をレジスタペアとして使用しています。

 * なお、上に示した I2cLcd_Disp サブルーチンは、後出の テーブルデータ選択のプログラミングで起きた不具合 で述べているように、条件によっては不具合をもたらすことが分かったため、その後、I2cLcd_Disp サブルーチン( 最新版 )のように書き改めました。

| プログラムのトップに戻る |


● テーブルデータ選択のプログラミング(ジャンプ先の振り分け)

 「メニューの選択」機能においての、テーブルデータ選択のプログラミングの2つ目として、この項では FSRnH と FSRnL のレジスタペアを使用した、プログラミング例を紹介しておきます。 前項と同様にメニュー項目の1つを選択後に、EXIT スイッチを押すことによって 選択が決定され、各メニュー項目別の機能処理のプログラムへ ジャンプする部分のプログラミングです。

 やはり前項と同様に menu_no の値(1 〜 9)によって、ジャンプアドレステーブルから各メニュー項目別の機能処理アドレスを取得しています。
        		decf	menu_no,W		;0 始まりにする
        		movwf	FSR1L
        		lslf	FSR1L,F			;2 倍する
        		movlw	low jump_addr_tbl
        		addwf	FSR1L,F			;ジャンプアドレステーブルの先頭 low アドレスを足す
        		clrf	FSR1H
        		movlw	high jump_addr_tbl
        		addwfc	FSR1H,F			;ジャンプアドレステーブルの先頭 high アドレスを足す
        
        		moviw	0[FSR1]			;
        		movwf	PCLATH			;
        		moviw	1[FSR1]			;
        		movwf	PCL			;選択したメニュー項目処理にジャンプ
        
        ;--------------------------------------------------------------------------
        
        		; メニュー番号別ジャンプアドレステーブル
        
        jump_addr_tbl
        		dt	high clock_display	;menu_no = 1	;(ページ 0)
        		dt	low  clock_display
        		dt	high detail_stopwatch	;menu_no = 2	;(ページ 1)
        		dt	low  detail_stopwatch
        		dt	high interval_timer	;menu_no = 3	;(ページ 1)
        		dt	low  interval_timer
        		dt	high long_stopwatch	;menu_no = 4	;(ページ 1)
        		dt	low  long_stopwatch
        		dt	high memory_display	;menu_no = 5	;(ページ 1)
        		dt	low  memory_display
        		dt	high wk_timer_setting	;menu_no = 6	;(ページ 1)
        		dt	low  wk_timer_setting
        		dt	high wk_timer_display	;menu_no = 7	;(ページ 1)
        		dt	low  wk_timer_display
        		dt	high clock_adjust	;menu_no = 8	;(ページ 0)
        		dt	low  clock_adjust
        		dt	high sleep_time_set	;menu_no = 9	;(ページ 1)
        		dt	low  sleep_time_set
        jump_addr_tbl_end
        
 PIC16F1827 ではプログラムメモリが ページ 0 〜 1 の 2 ページしかありませんが、もっと大きなプログラムメモリ(多くのページ)を搭載した PIC であっても、ジャンプアドレステーブルに同様にジャンプアドレスを並べるだけで、 どのページにあるプログラムへも簡単に確実に処理を移す(ジャンプする)ことができます。

| プログラムのトップに戻る |


● テーブルデータ選択のプログラミングで起きた不具合

 本機の 6:「週間タイマーの時刻設定」機能 のプログラミングもほぼ終わって、試験実行を行ったときのお話です。「メニューの選択」機能で本機能を選択後に EXIT スイッチを押した途端、次の LCD 画面が表示されることを期待していたのですが、 予想に反していきなりの暴走で LCD 画面には意味不明な文字が表示されました。
    			[ Set EDAY ]	..... 右側に曜日 (略名) を表示
    			[ 00:00  0 ]	..... "HH:MM"、"曜日を表す数字" を設定
    
 デバッグ中にはこんなことはよくあることなんですが、やはり少なからずショックを受けるのが正直な気持ちです。 なぜ? どうして? ・・・ プログラミングもほぼ万全な気持ちで終えて試験実行に臨むわけで、いきなり予想に反して暴走するとなると、 オーバーに言えば、自分のプログラミングが否定されたような気持にさえなります。

 そのときの関連する部分のリストを次に示します(部分リストのため分かりづらいかもしれませんが、できれば ソースファイル (MultifuncDigitalClock.asm) を参照してください)が、不具合なところはどこなのか? 初めはまったく見当も付きません。 あらゆるところを疑ってリストを何度も何度も見直しますが、リストを見ているだけでは、そんなに簡単には不具合な場所を見つけることはできません。(なお、この 6:「週間タイマーの時刻設定」機能 wk_timer_setting は、 プログラムメモリのページ 1 に存在しています。)
        ;==========================================================================
        ; menu_no = 6		週間タイマーの時刻設定
        ;==========================================================================
        
        wk_timer_setting
        			:
        			:
        			:
        
        		; 「週間タイマーの時刻設定」の初期表示
        
        		;	[ Set EDAY ]		;1行目 ... "Set ", 曜日名の表示
        		;	[ 00:00  0 ]		;2行目 ... 時分, 曜日番号の表示
        		;	  01234567
        
        		movlw	h'80'			;(1行目先頭)
        		call	xI2cLcd_Cmd		;
        
        		movlw	0			;文字列 = 0
        		call	str_disp		;"Set " を表示			..... (1)
        
        tmset01		movlw	h'0c'			;表示オン/オフコントロール
        		call	xI2cLcd_Cmd		;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク
        		movlw	h'c0'			;(2行目先頭)
        		call	xI2cLcd_Cmd		;時の表示位置
        
        		call	xhh_disp		;時の表示
        		movlw	':'			;':'
        		call	xI2cLcd_Data		;I2C LCD へデータを1文字出力
        		call	xmm_disp		;分の表示
        
        		movlw	' '			;
        		call	xI2cLcd_Data		;I2C LCD へデータを1文字出力
        		movlw	' '			;
        		call	xI2cLcd_Data		;I2C LCD へデータを1文字出力
        		call	week_disp		;曜日番号と曜日名の表示
        
        		clrf	hold_cnt		;長押し監視カウンタの初期設定
        
        		; 各スイッチの入力チェック
        
        			:
        			:
        			:
        
        ;--------------------------------------------------------------------------
        
        		; 文字列の表示
        str_disp
        		movwf	addr_low		;文字列番号
        		lslf	addr_low,F		;x 2 倍
        		lslf	addr_low,F		;x 4 倍
        		addwf	addr_low,F		;x 5 倍
        
        		movlw	high str_table		;テーブルデータの先頭 high アドレス
        		movwf	addr_high		;
        		movlw	low str_table		;テーブルデータの先頭 low アドレス
        		addwf	addr_low,F		;
        		btfsc	STATUS,C		;オーバーフローした場合は
        		incf	addr_high,F		;high アドレスの更新
        
        		call	xI2cLcd_Disp		;I2C LCD へ文字列データを出力	..... (2)
        
        		return
        
        		; 文字列 データテーブル
        str_table
        		dt	"Set ",0		;文字列番号 = 0
        		dt	"Err!",0		;             1
        		dt	"Dsp ",0		;             2
        		dt	"None",0     		;             3
        		dt	"    ",0		;             4
        
 こんなときのために MPLAB X IDE には強力なデバッグ機能を備えている(らしい)のですが、英語力の弱い私にとっては高嶺の花というか宝の持ち腐れというか、残念ながら今の私にはまともにこのデバッグ機能を使うことができません。

 そこで、仕方がないので自己流の方法でデバッグを行うことになります。 疑わしい命令をコメントにしてみたり、ときには疑わしい部分の前や後にたとえば goto $ 命令を挿入して実行を止めてみたり、また、ときには疑わしい変数(レジスタ)の内容を LCD 画面上に表示させてみたりもします。

 そんなこんなで、まず、上リストの赤字で示した 命令 (1) が疑わしいということが分かりました。 上リストでは結果が出ているので簡単そうに思えるかもしれませんが、あらゆるところを疑ってのことなので、赤字命令 (1) に行き着くまでにはそれなりの時間を要しています。

 そして、str_disp サブルーチン内に原因があることに大まかに絞られたのですが、次には、このサブルーチン内のどこで不具合を起こしているのか? これがまた大変でした。

 上リストではもう解答が出ていて赤字で示した 命令 (2) が犯人だと分かりますが(真犯人ではない)、そこに行き着くまでにはやはり時間を要しました。 str_disp サブルーチン を、前々項で示した menu_display サブルーチン と比べてみて、扱っている文字列の文字数が異なっているだけで、文字列を LCD 画面に表示させることに違いはありません。

 ページ 0 に存在している menu_display サブルーチンでは、I2cLcd_Disp サブルーチンを CALL しているのに対して、ページ 1 に存在するこの str_disp サブルーチンでは、xI2cLcd_Disp サブルーチンを CALL しているのは、 xI2cLcd_Disp サブルーチンも ページ 1 に存在しているからで、ページ 1 の他の場所で次のように定義をしています。 ですから、実体は I2cLcd_Disp サブルーチンでどちらも変わりはありません。
        xI2cLcd_Disp
        		movlp	high I2cLcd_Disp
        		call	I2cLcd_Disp		;I2C LCD 1行メッセージ表示
        		movlp	high $
        		return
        
 なのに、なぜ xI2cLcd_Disp サブルーチンが犯人になってしまうのか? ここが一番私が悩んだところで、なかなか真の犯人に行き着くことができなかった点でした。 結論を急ぎましょう。 既に前々項で示した I2cLcd_Disp サブルーチン をここにも再掲をしておきます。
        I2cLcd_Disp
        		call	tbl_read	;テーブルデータの読み出し		..... (1)
        		incf	addr_low,F	;読み出すデータの low アドレスの更新	..... (2)
        		btfsc	STATUS,Z	;オーバーフローした場合は		..... (3)
        		incf	addr_high,F	;読み出すデータの high アドレスの更新	..... (4)
        
        		addlw	0		;					..... (5)
        		btfsc	STATUS,Z	;h'00' か?				..... (6)
        		goto	i2cldsp01	;Yes					..... (7)
        
        		call	I2cLcd_Data	;LCD へデータを1文字出力		..... (8)
        		goto	I2cLcd_Disp	;					..... (9)
        
        i2cldsp01	return								..... (10)
        
        		; テーブルデータの1文字読み出し
        tbl_read
        		movf	addr_high,W	;読み出すデータの high アドレス		..... (11)
        		movwf	PCLATH		;					..... (12)
        		movf	addr_low,W	;読み出すデータの low アドレス		..... (13)
        		movwf	PCL		;					..... (14)
        
 I2cLcd_Disp サブルーチンの冒頭で
        		call	tbl_read	;テーブルデータの読み出し
        
 のように、tbl_read サブルーチンを CALL しています。 そして tbl_read サブルーチンではaddr_high、addr_low レジスタペアの内容を、PCLATH、PCL レジスタに代入 をしています。 これが不具合の原因でした。 いや、早まってはいけません。 I2cLcd_Disp サブルーチン、tbl_read サブルーチンともに、それ自体は何の問題もありません。 現に「メニューの選択」機能においての menu_display サブルーチンでは、何の問題もなく LCD 画面に文字列を表示させています。

 では、一体何が問題なのでしょうか? 表示をさせる文字列のデータテーブルそのものに注目をしてみてください。「メニューの選択」機能では、menu_display サブルーチンと同じページ 0 にメニュー データテーブル menu_table が存在 しています。 これに対して、本機能の 6:「週間タイマーの時刻設定」機能では、str_disp サブルーチンと同じページ 1 に文字列データテーブル str_table が存在 しています。 このことに問題があったのです。

 menu_display サブルーチンでの 変数 addr_high にはページ 0 の high アドレスが格納 され、一方、str_disp サブルーチンでの 変数 addr_high にはページ 1 の high アドレスが格納 されて、 同じ実体である I2cLcd_Disp サブルーチンを CALL しています。

 上述したように、MPLAB X IDE のデバッグ機能を使うことができないので、プログラムを実際にトレースすることができないため、あまり正確ではない? かもしれない、私の頭の中でトレースをして行くことにしましよう。 menu_display サブルーチンでの動作には特に問題がないので、とりあえずトレースはパスをし、そして、問題の str_disp サブルーチンの場合をトレース してみます。

 また、I2cLcd_Disp サブルーチンに処理が移ってから問題が発生しているはず? なので、I2cLcd_Disp サブルーチン内をトレースしますが、その前提条件を確認しておきます。 本項の始めに示した リスト 中の赤字の命令 (1) のコメントが示すように、文字列 データテーブル str_table の1行目
        		dt	"Set ",0		;文字列番号 = 0
        
が表示対象となっている文字列で、その内の最初の1文字目 'S' のメモリアドレスが、str_disp サブルーチン によって addr_high、addr_low レジスタペアに代入され、文字 'S' がポイントされています。 そして、トレースにはすぐ上に示した I2cLcd_Disp サブルーチン 内の、各命令の右端に付した黒字番号 (1) 〜 (14) と、次のリストの番号 (15) を使用しながら説明をします。

 なお、文字列を定義している部分の DT 命令はアセンブラ疑似命令で
        		retlw	'S'		;					..... (15)
        		retlw	'e'
        		retlw	't'
        		retlw	' '
        		retlw	0
        
と書いたのと同等になります。 RETLW 命令では1行に1文字(バイト)の定義しかできないので、本項のデータテーブルのように文字列の複数文字を1度に定義したい場合には、通常は DT 疑似命令を使用します。 ちなみに、各文字列の最後に 0 を定義しているのは、 文字列を表示する I2cLcd_Disp サブルーチンが、この 0 を検出することによって文字列の終了としているためで、もし、0 を付け加えるのを忘れると、I2cLcd_Disp サブルーチンは 0 を検出するまでプログラムメモリ内を駆け巡るので、いわゆる暴走状態になります。

 さて、I2cLcd_Disp サブルーチンに処理が移ってくると、いきなり 命令 (1) で tbl_read サブルーチンを CALL しています。 このように、これ以降 CALL 命令と GOTO 命令が現れたときに特に注目をしてください。 この場合には、上で示した xI2cLcd_Disp サブルーチン 内で movlp high I2cLcd_Disp 命令によって、PCLATH レジスタにはページ 0 の high アドレスが格納 されているので、左下の図にしたがって問題なく tbl_read サブルーチンが CALL されます。
 このとき、(1) の次の 命令 (2) のアドレス(ページ 0 のアドレス)をスタックに PUSH して CALL の戻りアドレスを確保しておきます。 CALL された tbl_read サブルーチンでは 命令 (11) → (12) → (13) → (14) と処理を進め、 addr_high、addr_low レジスタペアの内容(ページ 1 のアドレス)をPCLATH、PCL レジスタに代入 をしています。

 すると右上の図にしたがって、ページ 1 に存在している 文字列データテーブル str_table の1行目の1文字目、すなわち、命令 (15) に処理が移ります。 そして、(15) の retlw 'S' 命令 では、 'S' 文字を W レジスタに設定した後、スタックに確保しておいた戻りアドレスをプログラムカウンタ(PC)に POP をするので、問題なく I2cLcd_Disp サブルーチン内の命令 (2) に戻ってきます。

 その後、命令 (3) → (4) → (5) → (6) と処理は進み、次に (7) で GOTO 命令が現れますが、W レジスタには 'S' 文字が設定されていて h'00' ではないため、処理は次の (8) call I2cLcd_Data 命令 へと進みます。 I2cLcd_Data サブルーチンは I2cLcd_Disp サブルーチンとともに、インクルードファイル I2C LCD 制御サブルーチン (I2C_S2_LCD.sub) 内に収容されているので、その存在はページ 0 にあります。

 ところがこの時点では 命令 (11) (12) によって、PCLATH レジスタには ページ 1 の high アドレスが格納 されているので、命令 (8) によって CALL をしても左上の図にしたがった動作のため、 ページ 0 に存在している I2cLcd_Data サブルーチンが CALL されることはなく、プログラムはページ 1 のメモリ内をさまよう(暴走する)ことになります。

 このように、上述した 赤字で示した命令 (2) の xI2cLcd_Disp(または I2cLcd_Disp)サブルーチンそのものが不具合の原因(犯人)ではなく、文字列データテーブル str_table が存在しているメモリ位置 が原因(真犯人)であったのです。 この真犯人を見つけるまでには、恥ずかしながら数日がかかってしまいました。

 また、このメモリ位置が真犯人であることの事実を証明するために、試しに、現在ページ 1 に存在している文字列データテーブル str_table を、ページ 0 に移動をさせてみました。 結果、問題なく文字列 "Set " が LCD 画面上に表示されたことを、 ここに付け加えておきます。

 *(以下は余談なので、項末の 最終的な方法 の前まで読み飛ばしてください。)

 ただ、このままで済ませてしまうと、str_disp サブルーチン から str_table が消えてしまって(ページ 0 に移動)、プログラムの見通しが悪くなるので、実際には次に示すリストのように、新たに I2cLcd_Disp2 サブルーチンを作成して、 赤字で示した命令 (3) のように str_disp サブルーチンを書き直しました。
        ;--------------------------------------------------------------------------
        
        		; 文字列の表示
        str_disp
        		movwf	addr_low		;文字列番号
        		lslf	addr_low,F		;x 2 倍
        		lslf	addr_low,F		;x 4 倍
        		addwf	addr_low,F		;x 5 倍
        
        		movlw	high str_table		;テーブルデータの先頭 high アドレス
        		movwf	addr_high		;
        		movlw	low str_table		;テーブルデータの先頭 low アドレス
        		addwf	addr_low,F		;
        		btfsc	STATUS,C		;オーバーフローした場合は
        		incf	addr_high,F		;high アドレスの更新
        
        	;;	call	xI2cLcd_Disp		;I2C LCD へ文字列データを出力
        		call	I2cLcd_Disp2		;I2C LCD へ文字列データを出力	..... (3)
        
        		return
        
        		; 文字列 データテーブル
        str_table
        		dt	"Set ",0		;文字列番号 = 0
        		dt	"Err!",0		;             1
        		dt	"Dsp ",0		;             2
        		dt	"None",0     		;             3
        		dt	"    ",0		;             4
        
        ;--------------------------------------------------------------------------
        
        I2cLcd_Disp2
        		movlp	high tbl_read
        		call	tbl_read		;テーブルデータの読み出し
        		movlp	high $
        
        		addlw	0
        		btfsc	STATUS,Z		;h'00' か?
        		goto	i2cldsp21		;Yes
        
        		call	xI2cLcd_Data		;LCD へデータを1文字出力
        
        		incf	addr_low,F		;読み出すデータの low アドレスの更新
        		btfsc	STATUS,Z		;オーバーフローした場合は
        		incf	addr_high,F		;読み出すデータの high アドレスの更新
        		goto	I2cLcd_Disp2
        
        i2cldsp21	return
        
 そもそも、私が文字列の表示 str_disp サブルーチンを作成した目的は、同一のサブルーチンでいろいろな文字列を表示させることと、究極は使用するプログラムメモリの量を如何に削減するかにありました。 1つ目の目的では、現在5種類の文字列だけが表示対象で、 あまり利用価値がないともいえますし、2つ目の目的でいえば新たに I2cLcd_Disp2 サブルーチンを作成したことは、メモリ量が増加してまったく理にかなっておりません。

 そのため、たとえば次に示すように
        		movlw	'S'			;
        		call	xI2cLcd_Data		;I2C LCD へデータを1文字出力
        		movlw	'e'			;
        		call	xI2cLcd_Data		;I2C LCD へデータを1文字出力
        		movlw	't'			;
        		call	xI2cLcd_Data		;I2C LCD へデータを1文字出力
        		movlw	' '			;
        		call	xI2cLcd_Data		;I2C LCD へデータを1文字出力
        	;;	movlw	0			;
        	;;	call	xI2cLcd_Data		;I2C LCD へデータを1文字出力
        
と、ベタで並べた方がシンプルで、またシンプル故にこの項で紹介したような不具合なども、入り込む余地などはまったくなくて良いのかもしれません。

 次々項でも述べることですが、本機で採用した PIC16F1827 のプログラムメモリは、4K ワードと少ないにもかかわらず多くの機能を盛り込んだため、プログラムの作成期間中の後半では、プログラムメモリの使用量を如何に少なくするか、ばかりに気を取られていました。 ある意味では、そのために発生した不具合ともいえる経験でした。

不具合を回避するための最終的な方法

 その後、上述した、新たに I2cLcd_Disp2 サブルーチンを作成して str_disp サブルーチンを書き直す方法は、あまり良策ではないと反省をし他の方法を考えてみました。 本来は、既成のサブルーチンファイルにはあまり手を加えたくないのですが、 よりベターと思い直し、インクルードファイル I2C LCD 制御サブルーチン (I2C_S2_LCD.sub) 内に収容されている、I2cLcd_Disp サブルーチンだけを書き直す ように改めました。

 上述した I2cLcd_Disp サブルーチン の、命令 (1) と (2) の間(または、命令 (4) と (5) の間のどちらでも可)に、次の命令群を追加挿入しました。
        	#ifdef	_PIC16F1
        		movlp	high $
        	#else
        		movwf	wt1cnt		;ワーク変数へ退避
        		movlw	high $
        		movwf	PCLATH		;
        		movf	wt1cnt,W	;ワーク変数から復帰
        	#endif
        
 このように書き直しておけば、PIC16F1 ファミリー、PIC16F ファミリーのどちらにも対応することができます。 上の追加挿入リストの #else 以降、すなわち PIC16F ファミリーの場合には、ワーク変数 wt1cnt を使用していますが、本来 wt1cnt は、同サブルーチンファイル (I2C_S2_LCD.sub) 内の、26.3μ秒 ウェイトルーチン wait_26us サブルーチンの中で使用している変数で、上の追加挿入リスト部分を実行時点では未使用となるため、追加挿入した命令群の中でワークとして使用しました。

 したがって、上述した str_disp サブルーチン を書き直す方法はボツとし、初めに示したリストの中の 赤字で示した (2) 行目 の call xI2cLcd_Disp 命令も、変更はしないでそのままとします。 I2C LCD 制御サブルーチンファイル (I2C_S2_LCD.sub) 内の、I2cLcd_Disp サブルーチンだけを次のように書き改めました。( 最新版 )です。
        ;==========================================================================
        ;		I2C LCD 1行メッセージ表示
        ;==========================================================================
        
        ;使用レジスタ:	addr_low, addr_high, wt1cnt
        
        ;<使用例>	movlw	h'80'		;表示位置の DDRAM のアドレスをセット
        ;		call	I2cLcd_Cmd	;LCD へコマンドを出力
        ;		movlw	high st_msg	;メッセージデータの先頭アドレスの high アドレス
        ;		movwf	addr_high	;
        ;		movlw	low st_msg	;メッセージデータの先頭アドレスの low アドレス
        ;		movwf	addr_low	;
        ;		call	I2cLcd_Disp	;メッセージデータ1行表示
        ;		  :
        ;st_msg		dt	"StpWatch",0
        
        I2cLcd_Disp
        		call	tbl_read	;テーブルデータの読み出し
        		incf	addr_low,F	;読み出すデータの low アドレスの更新
        		btfsc	STATUS,Z	;オーバーフローした場合は
        		incf	addr_high,F	;読み出すデータの high アドレスの更新
        
        	#ifdef	_PIC16F1
        		movlp	high $
        	#else
        		movwf	wt1cnt		;ワーク変数へ退避
        		movlw	high $
        		movwf	PCLATH		;
        		movf	wt1cnt,W	;ワーク変数から復帰
        	#endif
        		addlw	0
        		btfsc	STATUS,Z	;h'00' か?
        		goto	i2cldsp01	;Yes
        
        		call	I2cLcd_Data	;LCD へデータを1文字出力
        		goto	I2cLcd_Disp
        
        i2cldsp01	return
        
        		; テーブルデータの1文字読み出し
        tbl_read
        		movf	addr_high,W	;読み出すデータの high アドレス
        		movwf	PCLATH
        		movf	addr_low,W	;読み出すデータの low アドレス
        		movwf	PCL
        
| プログラムのトップに戻る |


● 割り込み処理のプログラミングで起きた不具合

 前項と同様 6:「週間タイマーの時刻設定」機能 のプログラミングをしていたときの続きのお話です。 前項で述べた不具合もようやく解決をして、次に示す初期画面も問題なく表示がされるようになりました。 そして次には、2行目に "HH:MM"、 "曜日を表す数字" を入力してタイマー時刻を設定します。(設定方法は 「週間タイマーの時刻設定」機能 を参照)
    			[ Set EDAY ]	..... 右側に曜日 (略名) を表示
    			[ 00:00  0 ]	..... "HH:MM"、"曜日を表す数字" を設定
    
 LEFT、RIGHT、DOWN、UP の各スイッチを使用してタイマー情報を入力するのですが、まったく問題なく入力ができそれらの LCD 画面への表示についても、見掛け上は何の問題もありません。 後は EXIT スイッチを押して、タイマー用メモリへ情報を書き込むだけです。 本機では、20 個(件)までのタイマー情報を設定することができ、連続して入力することができるようにしてあります。

 当初、1件ずつのタイマー情報を書き込む度に、次の入力に備えて [ 00:00 0 ] のように 0 クリアをしていたのですが、前回入力をした情報の一部が再利用できるようにした方がより便利 ― と考え直し、0 クリアするのを止めて前回の情報が表示されたままになるように、 プログラムを改めたのです。

 その結果、とんでもないことが起こりました。 EXIT スイッチを押した瞬間、今まで入力をして表示がされていた内容とは、まったく異なった内容が表示されるようになってしまいました。 えっ !! ― という驚きしかありません。 なぜ? どうして?

 これがまた、前項で述べた不具合に続いて 新たな不具合との長い戦いの始まりになりました。 しかし、表示された内容をよーく見てみると、どうやら現在時刻(時分)のようでもあります。 なぜ、ここに現在時刻(時分)が現れるのかまったく分かりません。 本「週間タイマーの時刻設定」機能では、現在時刻は不要なのでプログラムで扱ってはいないのです。

 本来、現在時刻のための変数 bcd_hh、bcd_mm、bcd_ww を、本機能でも使用しました。 それは、既存の bcd_hh_inc、bcd_hh_dec、bcd_mm_inc、bcd_mm_dec、hh_disp、mm_disp など、多くのサブルーチンがそっくり使用できるため、あえて本機能用の新たな変数を設けないで、 本機能を実行中には使用されることがない(はずの)、現在時刻用の変数 bcd_hh、bcd_mm、bcd_ww を使用したのです。

 ところが、タイマー用メモリへ情報を書き込むために EXIT スイッチを押した瞬間、自分が入力設定をした bcd_hh、bcd_mm、bcd_ww の内容が、現在時刻の内容に置き換わってタイマー用メモリへ書き込まれ、LCD 画面への表示もその現在時刻の内容に変更されてしまうのです。

 本機では、プログラムで現在時刻を扱っているのは、1:「現在時刻の表示」機能4:「ストップウオッチ(長時間)」機能「5:記録内容の表示」機能 の3機能についてだけで、 それらでは、INT 外部割り込みを使用して RTC モジュール DS3231 から1秒ごとに割り込みが掛かって、I2C 通信で現在時刻を得ています。

 したがって、上記の3機能についてだけ INT 外部割り込みを許可し、6:「週間タイマーの時刻設定」機能を始め、それ以外では INT 外部割り込みは禁止をしています。 それにも拘らず現実には bcd_hh、bcd_mm、bcd_ww の内容が、自分が入力した設定値から RTC モジュール からの読み出し値に更新がされてしまう ― という事実。

 この不具合が起こっているときの本機の "割り込み処理ルーチン(interrupt)" の全リストを、次に示しておきます。 このように本機では、4種類の割り込みを使用しています。
        ;==========================================================================
        ;		割り込み処理
        ;==========================================================================
        
        		org	h'0004'			;割り込みベクタ
        
        interrupt
        		movlp	high $			;ページ 0
        		movlb	0			;バンク 0
        
        		; 割り込み処理の振り分け
        
        		btfsc	INTCON,INTF		;INT 外部割り込みフラグ = 1 か?
        		goto	int_int			;Yes
        
        		btfsc	INTCON,TMR0IF		;TMR0 オーバーフロー割り込みフラグ = 1 か?
        		goto	int_tmr0		;Yes
        
        		btfsc	PIR1,TMR1IF		;TMR1 オーバーフロー割り込みフラグ = 1 か?
        		goto	int_tmr1		;Yes
        
        		btfsc	INTCON,IOCIF		;状態変化割り込みフラグ = 1 か?
        		goto	int_ioc			;Yes
        
        		goto	int_end			;(Illegal interrupt)
        
        ;---------------- INT 外部割り込み処理 ------------------------------------
        
        int_int		bcf	INTCON,INTF		;INT 外部割り込みフラグ = 0
        
        		; 現在時刻の管理
        		call	clock_rtc_read		;RTC DS3231 から年月日、時分秒を読み出し	..... (1)
        
        		movlp	high time_alarm_control
        		call	time_alarm_control	;時報音、タイマー一致音フラグコントロール
        		movlp	high $
        
        		; スリープ移行時間カウンタの更新
        		btfsc	stat2_flg,1		;スリープ中状態フラグ = 1 か?
        		goto	inti01			;Yes
        
        		decf	slp_cnt_l,F		;slp_cnt_l - 1
        		incf	slp_cnt_l,W		;
        		btfsc	STATUS,Z		;slp_cnt_l - 1 < 0 か?
        		decf	slp_cnt_h,F		;Yes. slp_cnt_h - 1
        		bsf	stat2_flg,0		;スリープ移行時間チェックフラグ = 1
        
        inti01		movlw	4			;4:「ストップウオッチ(長時間)」
        		subwf	menu_no,W		;
        		btfss	STATUS,Z		;メニュー番号 = 4 か?
        		goto	inti03			;No
        
        		; 経過時間(スプリットタイム)の管理
        		btfsc	stat_flg,3		;ストップウオッチ動作終了フラグ = 1 か?
        		goto	inti02			;Yes
        
        		btfss	stat_flg,2		;ストップウオッチ動作中フラグ = 1 か?
        		goto	inti03			;No
        
        		movlp	high ssmmhh_inc
        		call	ssmmhh_inc		;秒、分、時_BCD カウンタのインクリメント
        		movlp	high $
        		bsf	stat_flg,1		;経過時間更新フラグ = 1
        
        		; ラップタイム表示時間の監視(5 秒間)
        inti02		btfsc	stat_flg,4		;ラップタイム表示指示フラグ = 1 か?
        		decfsz	laptim_cnt,F		;Yes. ラップタイム表示時間カウンタ - 1 = 0 か?
        		goto	inti03			;No
        
        		bcf	stat_flg,4		;ラップタイム表示指示フラグ = 0
        
        inti03		goto	int_end
        
        ;---------------- TMR0 オーバーフロー割り込み処理 -------------------------
        
        int_tmr0	bcf	INTCON,TMR0IF		;TMR0 オーバーフロー割り込みフラグ = 0
        		movlw	256 - 250		;(4/4MHz) * 250 * 256(Prescaler) = 64000μS = 64 mS
        		movwf	TMR0
        
        		incf	hold_cnt,F		;長押し監視カウンタ + 1
        		movlw	47 + 1			;64ms x 47 = 3,008 mS = 3 秒間の監視
        		subwf	hold_cnt,W
        		btfsc	STATUS,C		;長押し監視カウンタ >= 47 + 1 か?
        		bcf	INTCON,TMR0IE		;Yes. TMR0 オーバーフロー割り込み許可 = 0
        		goto	int_end
        
        ;---------------- TMR1 オーバーフロー割り込み処理 -------------------------
        
        int_tmr1	bcf	PIR1,TMR1IF		;TMR1 オーバーフロー割り込みフラグ = 0
        
        		btfsc	alm_flg,7		;アラーム音出力フラグ = 1 か?
        		goto	int1t02			;Yes
        
        		; 「ストップウオッチ(詳細)」/「インターバル(間隔)タイマー」のとき
        		movlw	high basic_const	;(4 / 4MHz) * 10000 = 0.01 S = 10 mS
        		movwf	TMR1H			;TMR1H に設定
        		movlw	low basic_const		;
        		movwf	TMR1L			;TMR1L に設定
        
        		movlw	2
        		subwf	menu_no,W
        		btfss	STATUS,Z		;メニュー番号 = 2:「ストップウオッチ(詳細)」か?
        		goto	int1t01			;No
        
        		; メニュー番号 = 2:「ストップウオッチ(詳細)」のとき
        		bsf	stat2_flg,3		;1/100 秒更新フラグ = 1
        		call	xxssmmhh_inc		;Yes. 1/100秒、秒、分、時_BCD カウンタのインクリメント
        		goto	int1t03
        
        		; メニュー番号 = 3:「インターバル(間隔)タイマー」のとき
        int1t01		decfsz	bsc_cnt,F		;1 秒作成カウンタ bsc_cnt - 1 = 0 か?
        		goto	int1t03			;No
        
        		movlw	100
        		movwf	bsc_cnt			;10 mS * 100 = 1000 mS = 1 Sec
        
        		bsf	stat2_flg,3		;1 秒更新フラグ = 1 (1/100 秒と兼用)
        		call	ssmmhh_dec		;秒、分、時_BCD カウンタのデクリメント
        		movf	bcd_ss_w,W
        		iorwf	bcd_mm_w,W
        		iorwf	bcd_hh_w,W
        		btfss	STATUS,Z		;3つすべての BCD カウンタ = h'00' か?
        		goto	int1t03			;No
        
        		movlb	1			;バンク 1
        		bcf	PIE1,TMR1IE		;TMR1 オーバーフロー割り込み許可 = 0
        		movlb	0			;バンク 0
        		bsf	stat2_flg,4		;タイムアウトフラグ = 1
        		goto	int1t03
        
        		; ビープ音出力のとき
        int1t02		movf	const_high,W		;音階用分周定数 high を
        		movwf	TMR1H			;TMR1H に設定
        		movf	const_low,W		;音階用分周定数 low を
        		movwf	TMR1L			;TMR1L に設定
        
        		movlw	1 << _BZ		;ブザー音出力, 対象ビットをセット
        		xorwf	PORTA,F			;出力をビット反転
        
        int1t03		goto	int_end
        
        ;---------------- 状態変化割り込み処理 ------------------------------------
        
        int_ioc		movlb	7			;バンク 7
        		clrf	IOCBF			;状態変化割り込みフラグをクリアすると
        						;INTCON レジスタの IOCIF ビットもクリアされる
        		movlb	0			;バンク 0
        		bcf	INTCON,IOCIE		;状態変化割り込み許可 = 0
        
        		bsf	stat2_flg,1		;状態変化割り込み記憶フラグ = 1
        ;		goto	int_end
        
        		; 割り込み処理の終了
        
        int_end		retfie				;割り込みからの復帰	
        
 EXIT スイッチを押した瞬間に不具合が発生するということから、"EXIT スイッチの処理サブルーチン(tim_exit_switch)" も次に示しておきます。 EXIT スイッチ処理では、通常の "ちょん押し" と3秒以上の "長押し" を区別するために、プログラムでは TMR0 オーバーフロー割り込みを使用して、 3秒間以上の時間監視を行っています。
        ;--------------------------------------------------------------------------
        ;	 EXIT スイッチの処理 ...「週間タイマーの時刻設定」から CALL
        ;--------------------------------------------------------------------------
        
        ;		3 (64ms x 47 = 3,008 mS) 秒間以上 長押しの監視
        
        ;	[スイッチ操作]
        
        ;		EXIT スイッチ        ..... タイマー用メモリに書き込み、次の設定に移る
        
        ;		EXIT スイッチ 長押し ..... 「メニューの選択」に戻る  (3秒以上の長押し)
        
        tim_exit_switch
        
        		btfss	PORTB,_swEXT		;EXIT スイッチ = ON か?
        		goto	tmext01			;Yes
        
        		movf	hold_cnt,F
        		btfsc	STATUS,Z		;長押し監視カウンタ = 0 か?
        		goto	tmext04			;Yes
        
        		; (監視時間になる前に スイッチを OFF にした)
        		bcf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込み許可 = 0
        		clrf	hold_cnt		;長押し監視カウンタの初期設定
        		bsf	stat_flg,7	;;	;メモリ書き込み指示フラグ = 1
        		goto	tmext03
        
        tmext01		movf	hold_cnt,F
        		btfss	STATUS,Z		;長押し監視カウンタ = 0 か?
        		goto	tmext02			;No
        
        		incf	hold_cnt,F		;長押し監視カウンタ = 1 始まり
        		movlw	256 - 250		;(4/4MHz) * 250 * 256(Prescaler) = 64000μS = 64 mS
        		movwf	TMR0
        		bsf	INTCON,TMR0IE		;TMR0 オーバーフロー割り込み許可 = 1
        		goto	tmext03
        
        tmext02		btfsc	INTCON,TMR0IE		;TMR0 オーバーフロー割り込み許可 = 1 か?
        		goto	tmext04			;Yes
        
        		; (時間監視を終了しても スイッチが ON のとき)
        		btfss	PORTB,_swEXT		;EXIT スイッチ = OFF か?
        		goto	$ - 1			;No
        
        		bsf	stat2_flg,7	;;	;処理終了フラグ = 1
        
        tmext03		call	xwait_15ms		;チャッタリング吸収
        
        tmext04		return
        
 上に示した2つの抜粋リストから不具合が発生する原因が分かりますでしょうか? ここまで絞ってきても私にはまだ "これだ" という解答が出ていません。 そこで、本機能のときには、割り込み処理ルーチン内の (1) の命令が実行されないようにと、
        ;---------------- INT 外部割り込み処理 ------------------------------------
        
        int_int		bcf	INTCON,INTF		;INT 外部割り込みフラグ = 0
        
        		movlw	6		;;
        		subwf	menu_no,W	;;
        		btfsc	STATUS,Z	;;	;メニュー番号 = 6 か?
        		goto	inti03		;;	;Yes
        
        		; 現在時刻の管理
        		call	clock_rtc_read		;RTC DS3231 から年月日、時分秒を読み出し	..... (1)
        
        			:
        			:
        			:
        
        inti03		goto	int_end
        
のように、仮に書き直した後では EXIT スイッチを押しても、間違いなく (1) の命令は実行されないことが証明されました。 ということは逆に、本 6:「週間タイマーの時刻設定」機能の実行時に INT 外部割り込みを禁止していても、INT 外部割り込みが実行されてしまうことが確定したのです。

 それではなぜこのようなことが起こるのでしょうか? ここでようやく過去にもこれに似た経験をしたことを思い出しました。 "189. ドットマトリクス 8 x 8 LED 表示時計 II ( MAX7219 版)" の 割り込み動作の再確認 で触れたことと同様ですが、再度、次に述べてみます。

 PIC16F1827 のデータシート内の INTCON レジスタの項を改めて見てみると、次のように Note: が書かれています。 英語表記のデータシートのためにいつもあまり注意をしないでスルーをしているのですが、ここには大変重要なことが書かれています。
 前項でも述べたように英語はあまり得意ではないので、"Google 翻訳" の力を借りて日本語に翻訳をしてみると、次のように書かれています。
 右側の日本語文の中で赤色の線を引いた部分が重要で、「割り込みフラグは、イネーブルビットに関係なく設定される。」 当たり前といえば当たり前なんですが、この一文が重要なんです。 先に示した 割り込み処理ルーチン(interrupt) の "割り込み処理の振り分け" 部分を再掲してみると、
        			:
        			:
        
        		; 割り込み処理の振り分け
        
        		btfsc	INTCON,INTF		;INT 外部割り込みフラグ = 1 か?
        		goto	int_int			;Yes
        
        		btfsc	INTCON,TMR0IF		;TMR0 オーバーフロー割り込みフラグ = 1 か?
        		goto	int_tmr0		;Yes
        
        		btfsc	PIR1,TMR1IF		;TMR1 オーバーフロー割り込みフラグ = 1 か?
        		goto	int_tmr1		;Yes
        
        		btfsc	INTCON,IOCIF		;状態変化割り込みフラグ = 1 か?
        		goto	int_ioc			;Yes
        
        		goto	int_end			;(Illegal interrupt)
        
        			:
        			:
        
のように書かれており、INT 外部割り込みは TMR0 オーバーフロー割り込みよりも優先順位が高くなっています。

 また、回路図 を見ていただくと、RTC モジュール DS3231 の SQW 信号(1秒ごと)が PIC の RB0 端子、すなわち INT 外部割り込み入力端子に接続がされており、"Google 翻訳" で翻訳された赤色の線を引いた部分の通り、 INT 外部割り込みが禁止(INTE = 0)されていても、INT 外部割り込みフラグは1秒ごとにセット(INTF = 1) されます。 しかし、INT 外部割り込みが禁止(INTE = 0)されているために、このフラグ(INTF = 1)による 割り込みは起こりません。

 一方、EXIT スイッチが押されると、EXIT スイッチの処理サブルーチン(tim_exit_switch) で示したように、64 mS ごとに TMR0 オーバーフロー割り込み が起こります。 しかし、上の "割り込み処理の振り分け" リストで示したように、TMR0 オーバーフロー割り込みよりも INT 外部割り込み の方が優先順位が高く プログラミングがされているため、初めの TMR0 オーバーフロー割り込みのときには、TMR0 オーバーフロー割り込みの処理ルーチンは実行されずに、 先に INT 外部割り込みの処理ルーチンが実行されてしまいます。

 その結果、割り込み処理ルーチン内の (1) の命令が実行されて、RTC DS3231 から年月日、時分秒が読み出され、本機能で問題となっている変数 bcd_hh、bcd_mm、bcd_ww の内容が置き換わってしまう ― という現象が起こったのです。

 ちなみに、(1) の命令の サブルーチン clock_rtc_read は、本機のプログラム内の他の場所で次のように設定がされています。 また、Rtc_Read_M は私が作成した マクロ命令で、詳細は 現在の最新バージョン の "I2C RTC(DS3231/1307)モジュール 制御サブルーチン (I2C_RTCII.sub)" を参照してください。
        ;--------------------------------------------------------------------------
        ;		RTC DS3231 から年月日、時分秒を読み出し
        ;--------------------------------------------------------------------------
        
        clock_rtc_read
        		Rtc_Read_M	seconds,7	;RTC DS3231 から年月日、時分秒を読み出し
        		call	buffer_to_counter
        		bsf	stat_flg,0		;現在時刻更新フラグ = 1
        		return
        
        ;--------------------------------------------------------------------------
        ;		バッファと_BCD カウンタ間のデータ移動
        ;--------------------------------------------------------------------------
        
        		; バッファからカウンタへコピー
        
        buffer_to_counter
        
        		movlw	high seconds		;RTC バッファの先頭アドレス
        		movwf	FSR1H			;
        		movlw	low seconds		;
        		movwf	FSR1L			;
        
        		moviw	FSR1++			;Seconds
        		movwf	bcd_ss			;秒_BCD カウンタ
        
        		moviw	FSR1++			;Minutes
        		movwf	bcd_mm			;分_BCD カウンタ
        
        		moviw	FSR1++			;Hours
        		movwf	bcd_hh			;時_BCD カウンタ
        
        		moviw	FSR1++			;Day
        		movwf	bcd_ww			;曜日_BCD カウンタ
        
        		moviw	FSR1++			;Date
        		movwf	bcd_dd			;日_BCD カウンタ
        
        		moviw	FSR1++			;Month
        		andlw	h'1f'			;
        		movwf	bcd_nn			;月_BCD カウンタ
        
        		moviw	FSR1++			;Year
        		movwf	bcd_yy			;年_BCD カウンタ
        		return
        
 結論として、今回の不具合の回避策では、上掲した 割り込み処理ルーチン(interrupt) の "割り込み処理の振り分け" 部分を、次に示すリストのように変更をしました。
        ;==========================================================================
        ;		割り込み処理
        ;==========================================================================
        
        		org	h'0004'			;割り込みベクタ
        
        interrupt
        		movlp	high $			;ページ 0
        		movlb	0			;バンク 0
        
        		; 割り込み処理の振り分け
        
        ;;		btfsc	INTCON,INTF		;INT 外部割り込みフラグ = 1 か?
        ;;		goto	int_int			;Yes
        
        		btfsc	INTCON,TMR0IF		;TMR0 オーバーフロー割り込みフラグ = 1 か?
        		goto	int_tmr0		;Yes
        
        		btfsc	PIR1,TMR1IF		;TMR1 オーバーフロー割り込みフラグ = 1 か?
        		goto	int_tmr1		;Yes
        
        		btfsc	INTCON,IOCIF		;状態変化割り込みフラグ = 1 か?
        		goto	int_ioc			;Yes
        
        		btfsc	INTCON,INTF	;;	;INT 外部割り込みフラグ = 1 か?
        		goto	int_int		;;	;Yes
        
        		goto	int_end			;(Illegal interrupt)
        
        			:
        			:
        
 ところが ・・・・・ これでこの件は解決 ― と一時は思ったのですが、また別の事象が現れました。 上記のリストのように順位を入れ替えた結果、"6:「週間タイマーの時刻設定」機能" への上述した影響はなくなったのですが、次の事象、チッ、チッ、チッ、チッ、 という、まさに昔のゼンマイ(懐中)時計の秒針が発するような音が、(小さいですが)出るようになったのです。

 時計である本機としては、これはこれで良い ― という解釈もあるのですが、四六時中鳴っている訳でやはり耳障りだ ― という感情の方が強くなります。

 そこで、次のように4通りの順位に入れ替えてみたのですが、どの順位にしても、メニュー 6 への影響、またはチッチッ音 のどちらかの事象が現れるので、結局、順位の入れ替えは止めにして 元の (a) に戻し ました。 そして、メニュー 6 への影響を避けるため、 上述 した (1) の命令が実行されない方法 にとりあえず変更をしました。
        	順位				メニュー6 への影響	チッチッ音
        
        (a)	 1.   > btfsc	INTCON,INTF	   〇ある		  ×ない
        	 2.	btfsc	INTCON,TMR0IF
        	 3.	btfsc	PIR1,TMR1IF
        	 4.	btfsc	INTCON,IOCIF
        
        (b)	 1.	btfsc	INTCON,TMR0IF
        	 2.   > btfsc	INTCON,INTF	   〇ある		  ×ない
        	 3.	btfsc	PIR1,TMR1IF
        	 4.	btfsc	INTCON,IOCIF
        
        (c)	 1.	btfsc	INTCON,TMR0IF
        	 2.	btfsc	PIR1,TMR1IF
        	 3.   > btfsc	INTCON,INTF	   ×ない		  〇ある
        	 4.	btfsc	INTCON,IOCIF
        
        (d)	 1.	btfsc	INTCON,TMR0IF
        	 2.	btfsc	PIR1,TMR1IF
        	 3.	btfsc	INTCON,IOCIF
        	 4.   > btfsc	INTCON,INTF	   ×ない		  〇ある
        
 以上のように、現在は仮処置ともいえるような方法でメニュー 6 への影響を回避していますが、プログラマの私としてはやはり不本意なので、時間的余裕が十分あるときにもう一度、改めてこの件に関して検討をしてみたいと思います。

| プログラムのトップに戻る |


● コンフィギュレーションワードの設定で起きた不具合

 メニュー項目 2:「ストップウオッチ(詳細)」機能と 3:「インターバル(間隔)タイマー」機能では、CLEAR スイッチを操作するのですが、当初は DOWN スイッチを CLEAR スイッチと読み替えて、同一スイッチを兼用で使用していました。 しかし、DOWN スイッチはプリント基板上の実装位置が Start / Stop スイッチから少し離れているので、兼用から独立した CLEAR スイッチを Start / Stop スイッチの近くに新たに設け、配線は左下図のように DOWN スイッチと並列にして使用していました。

 2:「ストップウオッチ(詳細)」機能では DOWN スイッチ を使用しませんが、3:「インターバル(間隔)タイマー」機能では、DOWN スイッチは DOWN スイッチ の機能があり、CLEAR スイッチは CLEAR スイッチとしての機能があって、 しかし、両スイッチを使用する場面が異なるためポートを兼用にしたのですが、やはりよくありませんでした。

 メニュー項目 2: や 3: ではあまり問題は起こらないのですが、その他の機能を実行中に EXIT スイッチと CLEAR スイッチを、誤って押してしまうことがしばしばあり、当然 DOWN スイッチとしての動作をしてしまいます。
 そこで、右上図のように CLEAR スイッチを、ポート RB2 から他の RA5 に配線替えを行ったのですが、そこで大きな問題が起こりました。 同図に示すように配線替えを行った新ポート RA5 の 4 ピンは MCLR 端子でもあります。 この配線替えを行う以前から MCLR は無効にしデジタル入力として、 コンフィギュレーションワード CONFIG1 で設定がしてありました。 次の文の _MCLRE_OFF がその設定です。
        	__config _CONFIG1, _FOSC_XT & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _IESO_OFF & _FCMEN_OFF
        
 また、旧 CLEAR(DOWN)スイッチのときはポート B でしたが、新 CLEAR スイッチではポート A なので、そこらあたりのプログラムの設定替えを行ったことは言うまでもありません。 このように、ハードウエア、ソフトウエアともに変更(準備万端)して、いざ CLEAR スイッチを押した途端、 本機がリセットされてしまいました。 えっ! どうして? ・・・

 上の文のように _MCLRE_OFF と設定しているじゃないか。 解せない気持ちでいっぱいです。 なぜデジタルピンとして動作をしないのか? MCLR ピンのままなのです。

 PIC16F1827 にはコンフィギュレーションワードが、次のリストに示すように 2 ワード存在します。
        ;==========================================================================
        ;		コンフィギュレーションワードの設定
        ;==========================================================================
        
        	__config _CONFIG1, _FOSC_XT & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _IESO_OFF & _FCMEN_OFF
        	__config _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_HI & _LVP_OFF
        
        ; ------------------------------------
        ; CONFIGURATION WORD 1 (ADDRESS:8007H)		Data Sheet DS41391B - page 50
        ; ------------------------------------
        ;
        ;     CONFIG1 = 00 1001 1000 0001
        ;	        || |||| |||| ||||
        ;	bit2-0  || |||| |||| |+++---- FOSC<2:0>: オシレータ選択ビット
        ;	        || |||| |||| |          111 = ECH:    外部クロック、高消費電力モード(4-20 MHz):  OSC1/CLKINピンに供給
        ;	        || |||| |||| |          110 = ECM:    外部クロック、中消費電力モード(0.5-4 MHz): OSC1/CLKINピンに供給
        ;	        || |||| |||| |          101 = ECL:    外部クロック、低消費電力モード(0-0.5 MHz): OSC1/CLKINピンに供給
        ;	        || |||| |||| |          100 = INTOSC: 内部HFINTOSC CLKINピンはI/Oとして機能
        ;	        || |||| |||| |          011 = EXTRC:  CLKINピンに外部RC回路を接続
        ;	        || |||| |||| |          010 = HS:     OSC1とOSC2ピンの間に高速水晶/セラミック振動子を接続
        ;	        || |||| |||| |      >   001 = XT:     OSC1とOSC2ピンの間に水晶/セラミック振動子を接続
        ;	        || |||| |||| |          000 = LP:     OSC1とOSC2ピンの間に低消費電力水晶振動子を接続
        ;	        || |||| |||| |
        ;	bit4-3  || |||| |||+ +------- WDTE<1:0>: ウォッチドッグ タイマ イネーブルビット
        ;	        || |||| |||             11 = ON:     WDTを有効
        ;	        || |||| |||             10 = NSLEEP: WDTを動作時は有効、スリープ中は無効
        ;	        || |||| |||             01 = SWDTEN: WDTをWDTCONレジスタのSWDTENビットで制御
        ;	        || |||| |||         >   00 = OFF:    WDTを無効
        ;	        || |||| |||           _____
        ;	bit5    || |||| ||+---------- PWRTE: パワーアップ タイマ イネーブルビット
        ;	        || |||| ||              1 = OFF: PWRTを無効
        ;	        || |||| ||          >   0 = ON:  PWRTを有効
        ;	        || |||| ||
        ;	bit6    || |||| |+----------- MCLRE: MCLR/VPPピン機能選択ビット
        ;	        || |||| |              LVPビット=0 の場合
        ;	        || |||| |               1 = ON:  MCLR/VPPピンの機能はMCLR、弱プルアップを有効
        ;	        || |||| |           >   0 = OFF: MCLR/VPPピンはデジタル入力、MCLRは無効、弱プルアップはWPUA3ビットで制御
        ;	        || |||| |             __
        ;	bit7    || |||| +------------ CP: コード保護ビット
        ;	        || ||||             >   1 = OFF: プログラムメモリのコード保護を無効
        ;	        || ||||                 0 = ON:  プログラムメモリのコード保護を有効
        ;	        || ||||               ___
        ;	bit8    || |||+-------------- CPD: データコード保護ビット
        ;	        || |||              >   1 = OFF: データメモリのコード保護を無効
        ;	        || |||                  0 = ON:  データメモリのコード保護を有効
        ;	        || |||
        ;	bit10-9 || |++--------------- BOREN<1:0>: ブラウンアウト リセット イネーブルビット
        ;	        || |                    11 = ON:     BORを有効
        ;	        || |                    10 = NSLEEP: BORを動作時は有効、スリープ中は無効
        ;	        || |                    01 = SBODEN: BORをBORCONレジスタのSBORENビットで制御
        ;	        || |                >   00 = OFF:    BORを無効
        ;	        || |                  ________
        ;	bit11   || +----------------- CLKOUTEN: クロック出力イネーブルビット
        ;	        ||                     FOSCビットがLP、XT、HSモードの場合
        ;	        ||                  >   このビットを無視しCLKOUT機能を無効、CLKOUTピンはI/Oとして機能
        ;	        ||                     FOSCビットがその他のモードの場合
        ;	        ||                      1 = OFF: CLKOUT機能を無効、CLKOUTピンはI/Oとして機能
        ;	        ||                      0 = ON:  CLKOUTピンのCLKOUT機能を有効
        ;	        ||
        ;	bit12   |+------------------- IESO: 内部/外部切り換えビット
        ;	        |                       1 = ON:  内部/外部切り換えモードを有効
        ;	        |                   >   0 = OFF: 内部/外部切り換えモードを無効
        ;	        |
        ;	bit13   +-------------------- FCMEN: フェイルセーフ クロックモニタ イネーブルビット
        ;	                                1 = ON:  フェイルセーフ クロックモニタと内部/外部切り換えの両方を有効
        ;	                            >   0 = OFF: フェイルセーフ クロックモニタを無効
        ;
        ; ------------------------------------
        ; CONFIGURATION WORD 2 (ADDRESS:8008H)		Data Sheet DS41391B - page 52
        ; ------------------------------------
        ;
        ;     CONFIG2 = 01 1000 1111 1111
        ;	        || |||| |||| ||||
        ;	bit1-0  || |||| |||| ||++---- WRT<1:0>: フラッシュメモリ自己書き込み保護ビット
        ;	        || |||| |||| ||     >   11 = OFF:  書き込み保護を無効
        ;	        || |||| |||| ||         10 = BOOT: 0000h〜01FFhを書き込み保護、0200h〜0FFFhをEECON制御で変更可能
        ;	        || |||| |||| ||         01 = HALF: 0000h〜07FFhを書き込み保護、0800h〜0FFFhをEECON制御で変更可能
        ;	        || |||| |||| ||         00 = ALL:  0000h〜0FFFhを書き込み保護、EECON制御によるアドレス変更を不可
        ;	        || |||| |||| ||
        ;	bit3-2  || |||| |||| ++------ 未実装
        ;	        || |||| ||||
        ;	bit4    || |||| |||+--------- 予約
        ;	        || |||| |||
        ;	bit7-5  || |||| +++---------- 未実装
        ;	        || ||||
        ;	bit8    || |||+-------------- PLLEN: PLLイネーブルビット
        ;	        || |||                  1 = ON:  4xPLLを有効
        ;	        || |||              >   0 = OFF: 4xPLLを無効
        ;	        || |||
        ;	bit9    || ||+--------------- STVREN: スタック オーバーフロー/アンダーフロー リセット イネーブルビット
        ;	        || ||                   1 = ON:  スタックのオーバーフロー/アンダーフローによってリセットを発生させる
        ;	        || ||               >   0 = OFF: スタックのオーバーフロー/アンダーフローによってリセットを発生させない
        ;	        || ||
        ;	bit10   || |+---------------- BORV: ブラウンアウト リセット電圧選択ビット
        ;	        || |                    1 = LO: ブラウンアウト リセット電圧(VBOR)のトリップポイントを低に設定
        ;	        || |                >   0 = HI: ブラウンアウト リセット電圧(VBOR)のトリップポイントを高に設定                   
        ;	        || |
        ;	bit11   || +----------------- 未実装
        ;	        ||                    _____
        ;	bit12   |+------------------- DEBUG: インサーキット デバッガモード ビット
        ;	        |                   >   1 = OFF: インサーキット デバッガを無効、ICSPCLKとICSPDATは汎用I/Oピンとして機能
        ;	        |                       0 = ON:  インサーキット デバッガを有効、ICSPCLKとICSPDATはデバッガ専用
        ;	        |
        ;	bit13   +-------------------- LVP: 低電圧プログラミング イネーブルビット
        ;	                                1 = ON:  低電圧プログラミングを有効
        ;	                            >   0 = OFF: プログラミング時にMCLRに高電圧の印加が必要
        
 解答を先に出しておきます。 上(次に再掲)のリストは既に修正済みのものですが、2行目のコンフィギュレーションワード CONFIG2 の設定に問題がありました。
        	__config _CONFIG1, _FOSC_XT & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _IESO_OFF & _FCMEN_OFF
        	__config _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_HI & _LVP_OFF
        
 CONFIG2 の LVP(bit13)ビットの設定に問題があり、上リストに示すように _LVP_OFF が正解ですが、_LVP_ON と設定されていました。 プログラム の冒頭で述べたように、PIC16F1 ファミリーでのプログラミングは、"194. FMステレオラジオ III" 、 "195. ドットマトリクス LED コントローラー" に続いて本機が3作目で、このコンフィギュレーションワードの設定についてはそれらの前作をそのままコピーし、あまり深く考えもしないで異なった部分だけを修正していました。

 PIC16F1827 のデータシート内の CONFIGURATION WORD 1 レジスタ(DS41391B-page 50)の項で、MCLRE(bit6)の説明だけを抜き出すと、


 のように書かれていて、これを "Google 翻訳" で日本語に翻訳をしてみると、次のようになります。
 右側の日本語訳の中で赤色の線を引いたように、「 LVP ビット = 1 の場合、MCLRE ビットは無視される。」と書かれていました。 RA5/MCLR の 4 ピンをデジタル入力として使用するためには、CONFIG1 の MCLRE(bit6)ビット = 0 とし、さらに CONFIG2 の LVP(bit13)ビット = 0 とした、両者の設定を共に 0 にする 必要があったのです。

 上述した "194. FMステレオラジオ III" 、 "195. ドットマトリクス LED コントローラー" で何の問題も起きていないのは、自分(私)ではデジタル入力ピンとしたつもりでいたのですが、実際には、どちらもこの MCLR ピンにスイッチをつないで、 デジタル入力して使用することがなかったためで、また、ICSP 用として挿入した 10 KΩ 抵抗が MCLR ピンとしてのプルアップとして機能をしているためでした。

| プログラムのトップに戻る |


● PIC16F1827 の プログラムメモリについて、など

 PIC16F1827 の プログラムメモリ は、ページ 0 〜 1 の 2 ページ(2K x 2 = 4K = 4,096 ワードだけが実装 されています。 PIC16F1 ファミリーとしてはかなり少ない方だと思いますが、以前から PIC16F1827 を一度使用してみたい、 という個人的な願望もあって本機で採用してみたのですが、メモリ量としてはほぼギリギリに近い状態でした。

 というのも、本機には多くの機能を盛り込んだため、その分プログラム量が増えて使用するメモリ量も多くなるわけです。 私が本機のプログラムを作成している間中、特に後半になってからは、残りのメモリ量を常に気にしながらのプログラミング作業でした。

 PIC16F、PIC16F1 ファミリーでは、アセンブラ1命令 =1ワードですから、逆にいえば、4,096 ワードのプログラムメモリというのは、最大 4,096 個(行)のアセンブラ命令しか書くことができない ― ということになります。 この 4,096 行の命令数が多いかどうかは、個人によって判断が別れるとは思いますが、一般的には、アセンブラ命令でそれ程までの(大きな?)プログラムを作る人は少ない、とも思います。

・コーディングスタイル

 話が少し変わりますが、私のプログラミング(コーディング)スタイルは、ソースプログラムを見ていただくと分かるように、コメント行や空白行を多用して書いています。

 空白行の使用に関して は、GOTO (または RETURN) 命令行の後 と、GOTO の飛び先の ラベルを付した命令行の前 には、例外時を除いて必ず挿入するのを基本としています。 他にも、あるまとまった命令群の前後にも挿入をしています。 そして、この空白行を挿入することで、プログラムの見通しがずば抜けて良くなります。

 コメントに関しては、まず各命令行には、なるべく付けるように(努力を)しています。 コメント行に関して も、まとまった命令群(例えばサブルーチンやそれ以外の場合も多くある)の前には、これも例外時を除いて挿入するのを基本としていますし、 コメント行が複数行に亘ることもしばしばあります。

 私見(自分の経験談)ですが、プログラムというものは書いている時点では集中をしていて、その内容にもよく理解をしながら書いているのですが、完成をして数か月も経つと理解をしていた内容も薄れてきて、1年も経てばすっかり忘れてしまうものです。

 そして、プログラムにはバグが付きもので、理解が薄れた頃、すっかり忘れてしまった頃に、不具合が顔を出すものです。 そのときに少しでも手助けになるように、コメントは多く付ければ多いほど良い、と私は考えています。 そのための1つとして、ソースプログラムの冒頭には、プログラム全体の "機能概要" などもコメントとして付け加えています。

 本機のソースプログラムでは、盛り込んだ機能が多いこともあって、この "機能概要" も極端に大きくなってしまい、ソースプログラム全体(インクルードファイルを含めて)では、何と 8,600 行を超えました。 この内、命令行は 3,840 行程度ですから、 半分以上をコメント行や空白行が占めています。

 本機のプログラムは、ページ 0 とページ 1 の 2 ページに亘っていて、残っているプログラムメモリのワード数は、ページ 0 では約 140 ワードほど、ページ 1 では約 110 ワードほどで、この程度の未使用メモリを残しておかないと、 今後たぶん起こるであろう?バグの対処ができません。 ですから、あまり大きな機能追加なども今後はできません。

・タクトスイッチのチャッタリング対策

 次の図は、本機で使用しているタクトスイッチを始め、メカニカルなスイッチを ON / OFF させたときの、PIC の入力ポートに加わる電圧の変位をイメージして、図に表したものです。 ON したときも OFF したときも、どちらにもその直後にはチャタリングが現れるので、 その影響をプログラムが受けないように対処をしなければなりません。
 そのためのプログラム対策の実例として、例えば、本機の 9:「スリープ移行時間の変更」機能で使用している、LEFT スイッチの処理サブルーチン を掲げると、次のリストに示すように、サブルーチンの入口と出口に約 15 mS のウエイト時間を置いて、 上図に示したチャッタリング期間を吸収しています。
        ;--------------------------------------------------------------------------
        ;	  LEFT スイッチの処理 ...「スリープ移行時間の変更」から CALL
        ;--------------------------------------------------------------------------
        
        ;	[スイッチ操作]
        
        ;		 LEFT スイッチ ..... ブリンク位置のポインタを - 1
        
        ;		 LEFT スイッチ + 
        ;		RIGHT スイッチ ..... 「スリープ移行時間の変更」を中断し、「メニューの選択」に戻る
        
        slp_left_switch
        
        		call	xwait_15ms		;チャッタリング吸収
        		btfsc	PORTB,_swLEF		;再度 LEFT スイッチ = ON か?
        		goto	sllef04			;No
        
        		bsf	stat_flg,6		;スイッチ入力有りフラグ = 1
        		decf	blk_point,F		;ブリンク位置ポインタ - 1
        		incf	blk_point,W
        		movlw	2
        		btfsc	STATUS,Z		;blk_point = -1(W=0) か?
        		movwf	blk_point		;Yes. blk_point = 2 に設定
        
        sllef01		btfsc	PORTB,_swLEF		;LEFT スイッチ = ON か?
        		goto	sllef03			;No
        
        		btfsc	PORTB,_swRIG		;RIGHT スイッチ = ON か?
        		goto	sllef01			;No
        
        		bsf	stat2_flg,7	;;	;処理終了フラグ = 1 (中断終了)
        
        sllef02		comf	PORTB,W			;全ビットを反転
        		andlw	h'c0'
        		btfss	STATUS,Z		;LEFT スイッチ and RIGHT スイッチ = OFF か?
        		goto	sllef02			;No
        
        sllef03		call	xwait_15ms		;チャッタリング吸収
        
        sllef04		return
        
 このウエイト時間の 15 mS が実際に妥当なのかどうかなんですが、私はこれまで PIC で有名なあるサイトの情報を参考にして、30 mS 程度のウエイト時間を使用していました。 最近になって "秋月電子" のホームページにあるタクトスイッチの データシート(cosland/ts-0606_20200714.pdf)を改めて見る機会があり、Page. 1/5 で次の図を見つけました。

 この図によると、チャッタリングは 5 mS Max と書かれています。 そこで、安全マージンを含めて3倍の 15 mS としたウエイトを、本機で初めて使用してみましたが、誤動作もなくまったく問題はなさそうです。 私が従来使用していた 30 mS でも今回の 15 mS でも、 人間的にはあまりにも瞬間過ぎてその差は当然分かりませんが 15 mS で十分のようです。

・ストップウオッチ機能(詳細測定、長時間測定)の精度

 本機では、詳細測定と長時間測定との目的を別とした、2種類のストップウオッチ機能を有しています。 まず、後者の長時間測定を目的とする 4:「ストップウオッチ(長時間)」機能 では、本機の時計機能で使用した リアルタイムクロックモジュール(RTC IC DS3231)による、1秒ごとのパルスを基準クロックに使用をしているため、その精度には信頼に値するものがありますが、逆に1秒以下の測定はできないという弱点があって、最大1秒の表示誤差が生じます。

 次に、前者の詳細測定を目的とする 2:「ストップウオッチ(詳細)」機能 では、本機 PIC の基準クロック ( 1 / 4MHz ) x 4 = 1 μS を、10000 回カウントして TMR1 オーバーフロー割り込みを発生させ、 すなわち 1 μS x 10000 = 1 / 100 S = 0.01 S = 10 mS を 作り出しています。

 しかし、ここで問題があります。 本機では、上記 回路図 のように 4 MHz のクリスタルを使用していますが、私の今までの経験上、PIC のオシレータ入力に繋がっているクリスタルが、必ずしも 4 MHz ぴったりという正確な値では発振をしてくれないために、 その基準クロックも正確な 1 μS とはなりません。

 これを 4 MHz ぴったりに発振をさせるためには、上記回路図で示すクリスタルの右隣りにある2個のコンデンサの値を調整して、ハードウエア的に発振周波数を合わせ込む必要があるのですが、トリマコンデンサに交換をしたり正確な周波数カウンタも必要になったりと、 現実的には結構面倒な作業になります。

 そこで私の場合には、ハードウエア的な方法は採らず(したがって、発振周波数はズレたままで)、次に示すように、プログラム中に記した補正値 xx の値を変更することで、基準となるクロックが 10 mS に近づくように調整をしています。
        xx		equ	-33			;補正値
        basic_const	equ	65536 - (10000 + xx)	;(4 / 4MHz) * 10000 = 0.01 S = 10 mS
        
 発振周波数が 4 MHz より低い場合、すなわち 10 mS より大きくなった場合には、補正値 xx をマイナス値にしてカウント数を 10000 よりも少なくし、また逆に、発振周波数が 4 MHz より高い場合、すなわち 10 mS より小さくなった場合には、 補正値 xx をプラス値にしてカウント数を 10000 よりも多くして、ソフトウエアによる調整をしています。

 上に示した補正値 xx equ -33 は今回私が製作をした本機での例で、発振周波数は使用する PIC やクリスタルの個体差によって異なってくるため、より精度を求める場合は、実際に製作をしたそれぞれの個体に合うように補正をする必要があり、 その場合には、当然プログラムのアセンブルもし直す必要があります。

 この基準クロック 10 mS そのものを測定するのは現実的ではないため、実際には一定時間(たとえば 10 分、またはそれ以上)に拡大した時間を測定しています。

 下に示す表は、私が製作をした本機の例で、カウント数に補正がなかったとき(xx = 0)や、補正をしたとき(xx = -32 〜 -34)の実際の実測値をまとめたものです。 測定に使用した機材は、私の別ページ "145. 長時間ストップウオッチ/タイマー" で紹介をしたもので、右下の写真や図のように接続をします。

 このように、下表の測定時間欄の値は "145. 長時間ストップウオッチ/タイマー" で、本機が一定時間(10 分、または 60 分)出力する電気信号* の長さを測定したものです。

* 本機の ソースプログラムファイル (MultifuncDigitalClock.asm) の中で、"定数の定義と変数のレジスタ割付け" の先頭部分にある次の行
	;#define 	xx_debug			;TMR1 基準時間の調整支援(関連6か所あり)
の先頭の ;(セミコロン)を取り除いてアセンブルをし直すことによって、"TMR1 基準時間の調整支援" プログラムに切り替わる。

・使用法は「メニューの選択」LCD 画面で、メニュー項目 2: [ DtlStopW ] を選択して実行する。

・Start / Stop スイッチ を Start 側に倒すと、PIC の RB7 ピン(ICSP 端子の DAT ピン)に、10 分間だけ "L" 信号を出力するとともに LED(赤) を点灯させて知らせる。

・この 10 分間の "L" 信号の長さを、電気信号で作動するストップウオッチ等で測定する。測定値が 10 分間と大きく異なる場合は、補正値 xx の値を変更しながら正しく 10 分に近づけて行く。
	xx		equ	-33			;補正値
	basic_const	equ	65536 - (10000 + xx)	;(4 / 4MHz) * 10000 = 0.01 S = 10 mS
・"TMR1 基準時間の調整支援" プログラムでメニュー項目 2: [ DtlStopW ] を実行中は、RB7 ピンは出力ポートに切り替わっているので、RIGHT スイッチの操作は絶対にしないように。

・なお、調整の終了時には、上に示した #define 文に再び ; を付してコメント行に戻し、アセンブルをし直すこと。

【ヒント】ソースプログラムを xx_debug で検索をし、関連 (1/6) のところで次の2行を変更すれば、"L" 信号の出力時間を変更することができる。
			movlw	h'10'			; (1)
			subwf	bcd_mm_w,W		;

				↓

			movlw	h'01'			; (2)
			subwf	bcd_hh_w,W		;
 たとえば (1) を (2) ように変更すると、10 分間から 1 時間に延長ができる。

回数 設定時間 補正値 xx 測定時間 誤差
1 10 分 0 10'02"00 + 02"00
2 10'02"00 + 02"00
3 10'02"00 + 02"00
1 10 分 -32 10'00"08 + 00"08
2 10'00"08 + 00"08
3 10'00"08 + 00"08
1 10 分 -33 10'00"01 + 00"01
2 10'00"01 + 00"01
3 10'00"01 + 00"01
1 10 分 -34 09'59"96 - 00"04
2 09'59"96 - 00"04
3 09'59"96 - 00"04
1 60 分 -33 01゚00'00"10 + 00"10
2 01゚00'00"11 + 00"11
3 01゚00'00"11 + 00"11

 この補正値 xx は、上表のように xx = 0 のときの測定時間が分かれば、次のようにして計算で求めることができます。 ただし、"145. 長時間ストップウオッチ/タイマー" での測定値は、正しく信頼できるものとして話を進めます。

 補正値 xx = 0 のときの設定時間 = 10 分というのは、本機としては 10 分間( 10'00"00 ) "L" 信号を出力しているつもりでも、"145. 長時間ストップウオッチ/タイマー" で測定すると、実際には 10'02"00 となり、+ 02"00 の誤差がある ― ということで、
        10000 : X = 10'00"00 : 10'02"00
                   =   600.00 :   602.00
                   =   600    :   602		
        
の関係が成り立ちます。 ただし、= の左辺は 10 mS 当たりのカウント回数、右辺は 10 分に拡大した測定時間の秒数を表し、また、: の左側は理想とする数値、右側は実際の測定値 ― を表しています。 そこで X の値を求めると
                 X = 10000 * 602 / 600
                   = 10033.333…
                   ≒ 10033
        
 したがって、カウント回数の誤差は
        10033 - 10000 = 33
        
となり、この誤差分を補正値として実際のカウント数を 10000 から引いて少なくしてやります。 すなわち 上述 したように
        xx		equ	-33			;補正値
        basic_const	equ	65536 - (10000 + xx)	;(4 / 4MHz) * 10000 = 0.01 S = 10 mS
        
として、TMR1 オーバーフロー割り込みの発生間隔を誤差分だけ小さくして、ストップウオッチをカウントさせるための基準クロックの調整をしています。

| プログラムのトップに戻る |


現在の最新バージョン: Ver. 1.04

ソースファイル (MultifuncDigitalClock.asm)
 I2C LCD 制御サブルーチン (I2C_S2_LCD.sub) Ver. 1.06
 I2C RTC(DS3231/1307)モジュール 制御サブルーチン (I2C_RTCII.sub) Ver. 1.02
HEX ファイル (MultifuncDigitalClock.hex)

| ページトップ |

■ プリント基板の加工と部品配置 ■

 使用したメインとなる下図 左側のプリント基板 は、"秋月電子" の "片面ガラス・ユニバーサル基板 Bタイプ(95×72mm)めっき仕上げ(通販コード P-00518)" ですが、後述の ケース加工図 で示したケース内に収めるためには、プリント基板の切断等の加工が必要です。 左図に示すように、まず基板下部の ----- 線の位置で切断をします。

 そして、この切断によって失われた基板下部の取り付け用穴の代理となる、新たなΦ3.2 の穴を図のように2か所開けます。 次に、基板上部に位置するLCDモジュールの取り付けのために用いる、 木片固定用のΦ2 程度の穴を2か所開けます。

 また、基板左下に位置する四角っぽいものは "TP4056 充電モジュール" ですが、このモジュール基板を本プリント基板上に固定をさせるために、縦横斜6か所の青色線で示す位置で両基板同士の穴に、 0.4 〜 0.5 mm の錫メッキ線等を通してはんだ付けをするのですが、モジュール基板側は 2.54 mm ピッチではないため注意が必要です。

 このとき、左側の斜2か所の青色線で示すモジュール基板側の穴に対応する本プリント基板側の位置には、ランド穴が開いていないのでこの位置にΦ1 程度の穴を開ける必要がありますが、 この穴については、実際にモジュール基板を取り付けるときに、右側の4か所のはんだ付けをした後に現物合わせで開けるとよいと思います。


 次に 右側のプリント基板 は、"秋月電子" の "片面ガラス・ユニバーサル基板 Cタイプ(72×47.5mm)めっき仕上げ(通販コード P-00517)" で、左側メイン基板の右上2個のタクトスイッチと並列に配線をし、 補助用として使用します。

 図の ----- 線に従って、Y1, X1, X2, Y2 の順に切断をします。 Y1 線よりも左側の大きな部分は余りで今回は使用しません。 Y1 線で切断した右側の一番大きな基板がタクトスイッチの補助基板で、 2か所のΦ3.2 の穴を開けることも忘れないでください。 Y1, Y2 で挟まれた小さな基板は、メイン基板との接続のためのコネクタ用に使用します。

| プリント基板部品配置図 (MultifuncDigitalClockPC0.CE3) | (MultifuncDigitalClock2PC0.CE3) | ページトップ |

■ プリント基板パターン図 (部品面) ■

・トグルスイッチ
 プリント基板下部に位置する POWER スイッチと Start / Stop スイッチには、下のパターン図のように 3P(1回路)のトグルスイッチで良いのですが、3P でレバーが短いタイプの持ち合わせがなく、 6P(2回路)のものがあったので私は代わりにそれを使用しました。 したがって、基板写真はパターン図と異なっていることを断っておきます。

 本機では ケース加工図 で示したケース(内寸高さ 24 mm)を使用したため、レバーが通常のタイプは不可で、短いタイプでないとケース内に収めることができません。 次の写真は、レバーが通常のタイプと短いタイプとを比較するために、"秋月電子" のホームページから無断で拝借をし(ごめんなさい)、多少の加工を加えました。

 ここで、トグルスイッチを使用する上での一般的な注意をしておきます。 特に初心者の方は勘違いをし易いので注意が必要です。 下の一番右側の写真では、現在レバーは左側に倒れていますが、 この状態のときには下に伸びている3本のピンの内、どのピンが接続(ON)されているでしょうか? 答えは、真ん中と右側のピン間が ON になっているのです。 レバーをこの状態から右側に倒すと、次には真ん中と左側のピン間が ON に切り替わります。

 このようにトグルスイッチでは、倒したレバーの方向とはいつも逆方向のピン間が ON となることを覚えておいてください。 余談にはなりますが、これに対してスライドスイッチでは、移動させたレバー方向と ON となるピン間はいつも同方向になります。

レバーが通常のタイプ レバーが短いタイプ

・RTC モジュール( DS3231 For PI )
 プリント基板上部左側に位置する 5P のピンヘッダ(オス)は、リアルタイムクロックモジュール の項で説明をした、RTC モジュールのピンソケット(メス)と結合をさせます。 この RTC モジュール( DS3231 For PI )には、本機で必要な SQW 信号が外部に引き出されていないので、その項で説明をした方法にしたがって SQW 信号を引き出す改造を行っておく必要があります。

・LCDモジュール
 プリント基板上部中央に位置するI2C接続LCDモジュール "AQM0802A-RN-GBW" は、基板との接続用の足ピンのピッチが 1.5 mm のため、本基板の 2.54 mm ユニバーサル基板には、そのままでは搭載することができません。 そこで、このピッチの異なる両者間での接続方法を、私の別ページ "184. ストップウオッチ II" の LCDモジュールのプリント基板への取り付け で詳述 しているので、そちらを参照してください。

・TP4056 充電モジュール
 プリント基板下部左側に位置する "TP4056 充電モジュール" の取り付けについては、前項 プリント基板の加工と部品配置 でも少し触れましたが、まず、縦横4か所の各青色線で示す位置の、 本基板のハンダ面側から 0.4 〜 0.5 mm の錫メッキ線等を通し、モジュール基板上面側で各青色線の対となるもう片方の穴へグルっとUターンをして、再び、本基板のハンダ面側に通した後はんだ付けをします。 このとき、モジュール基板側は 2.54 mm ピッチではないため注意が必要ですが、本基板側の穴位置は、前項 プリント基板の加工と部品配置 で示した 縦横4か所の各青色線で示したランド穴位置を選択すれば問題はありません。

 次に、モジュール基板左側の斜2か所の青色線で示すモジュール基板側の穴に対応する本基板側の位置には、ランド穴が開いていないのでこの位置にΦ1 程度の穴を開ける必要があります。 穴を開けた後、前の縦横4か所のときと同要領で斜2か所についても、錫メッキ線等でモジュール基板の固定をします。 ただし、前の縦横4か所についてはその後、本基板のハンダ面側で回路の配線が必要になりますが、 この斜2か所については回路の配線はありません。

また、この充電モジュールでバッテリに充電中には、充電制御 IC TP4056 がかなり発熱をするので、手持ちにあったヒートシンクを熱伝導シール(両面粘着)で貼り付けました。 (下のプリント基板の写真では、ヒートシンクを貼り付ける前のものを掲載。)

・タクトスイッチ補助基板との接続コネクタ
 RTC モジュール用の 5P のピンヘッダのすぐ左下にある 6P のピンヘッダは、ICSP 端子で PIC にプログラムを書き込むときに使用するものですが、プログラムを書き込んだ後の通常時には、 6P のピンヘッダの内の RB6, RB7, GND の 3 ピンを別目的で使用します。

 下の プリント基板(2)パターン図 (部品面) (ハンダ面) の項で示した、タクトスイッチの補助基板のケーブルコネクタ( 3P ピンソケット(メス))と、通常時に接続をさせておきます。 これはメイン基板の右上2個のタクトスイッチと並列に配線をすることで、ケースの蓋を閉じていても補助基板のタクトスイッチで操作を可能にするものです。


 基板左下の B+ と B- 端子ですが、当初、配線をがっちりとさせるために、はんだ付けで配線を行うつもりでいて、その配線をし易くするために 3P のピンヘッダの内の、真ん中のピンを抜いたのですが、はんだ付けではやはり保守性が悪くなるので、 最終的にはコネクタ接続を行うことに変更をしました。 右写真は抜いた状態のときに撮ったもので、現状では抜いたピンをもとに戻して再び 3P にしてあります。(抜いた 2P 状態よりも 3P の方が、しっかりとコネクタ接続ができるため)

 また、プログラムコンフィギュレーションワードの設定で起きた不具合 で述べたように、PIC16F1827 の 4 ピン端子と CLEAR スイッチとの配線替えを終盤になってから行っていますが、 写真を撮った時期よりもずっと後のことなので、同様に右写真には反映がされていませんが、すべて修正をしたパターン図の方が正解なので注意をしてください。

| プリント基板パターン図 (部品面) (MultifuncDigitalClockPC.CE3) | 左図から黒色文字を除いた図 (MultifuncDigitalClockPC2.CE3) | ページトップ |

■ プリント基板パターン図 (ハンダ面) ■

 前項 プリント基板パターン図 (部品面) でも述べたように、トグルスイッチに 3P(1回路)ではなく 6P(2回路)のものを使用したため、基板写真のトグルスイッチ周りのパターンは、 左側のパターン図とは少々異なっていることに注意をしてください。


| プリント基板パターン図 (ハンダ面) (MultifuncDigitalClockPC1.CE3) | ページトップ |

■ プリント基板(2)パターン図 (部品面) (ハンダ面) ■

 既に上の プリント基板パターン図 (部品面) でも述べていますが、次図のケーブルコネクタ( 3P ピンソケット(メス))を、メイン基板の左側に位置する ICSP 端子 6P の内の、RB6, RB7, GND の 3 ピンと接続をしておくことによって、メイン基板の右上2個のタクトスイッチについては、ケースの蓋を閉じていてもこの補助基板のタクトスイッチで同操作が可能なようにします。

 そのために、この補助基板を次項 ケース加工図 の(上面図)の右上位置に、上蓋の内側から取り付け、タクトスイッチのキートップがケース外に飛び出るようにします。


 タクトスイッチをプリント基板に取り付ける場合には、下図の赤文字 A の面(スイッチの底面)を、基板の部品面に押し付けて取り付けるのが一般的なようです。 タクトスイッチが取り付けられて完成品として売られている プリント基板などを見てみると、多くの場合そのような取り付けになっています。(下図は "秋月電子" のホームページに添付されているデータシートから、一部を抜粋したものに書き込みをして使用しました)

 想像ですがこれらの場合、恐らく組み立て用機械(ロボット)がタクトスイッチを取り付けているのであって、人間が手動で取り付けているのではない、と思われます。 したがって、取り付け後の足ピンの形状も歪むことなく、スイッチ位置なども下図右上(P.C.B. LAYOUT)の4点の中央にきちんと配置され、美しい仕上がりになっています。

 ところが、この作業を我々人間が手動で行うような場合、赤文字 A の面(スイッチの底面)を基板の部品面に押し付けるのには、かなり強い力が必要です。 しかも、足ピンの形状は歪んでしまうことが多く、スイッチの取り付け位置も右上図の4点の中央から外れてしまうこともしばしばです。

 したがって、私個人としてはこのような取り付け方は、特別な場合を除いてあまり行っていません。 プリント基板上の4つの穴にタクトスイッチの各足ピンを挿入後、軽くキートップを上から押し込むと、 赤文字 B の足ピン位置(スイッチの底面が 1.8 mm 程浮いたところ)で、一旦、挿入の進行が止まります。

 その少し浮かせた足ピン位置での取り付けが、通常私が行っている方法で、足ピンのはんだ付けをする前に、タクトスイッチの4本の各足ピン位置が水平、垂直ともに傾き(ゆがみなど)がないかを十分に確認をした上ではんだ付けを行います。 この取り付け方法の利点として、キートップを押し付けるのに強い力は不要で、浮かせたスイッチ下の空間に配線を通す( )ことができるなどです。


 しかし、この項でのタクトスイッチの取り付けでは、どちらの方法も使いません。 上図の青色で示した厚さ 1 mm 程度のものを、スイッチの底面とプリント基板の部品面との間に挟み込んで、スイッチを押し込みます。 そして、はんだ付けの後で挟み込んだものを抜き取るのですが、要は、上図の赤文字 C, D 間を 5 mm としたいのです。

 この 5 mm という値は、私が所有するスペーサの中で最も多数を所有している長さであって、それを使用したいためです。 もし 4 mm 長のスペーサをお持ちであれば、何も挟まないで押し込んでください。 なお、これらの値は "秋月電子" の一般的なタクトスイッチである、DTS-63 タイプ(キートップ長が 3.5 mm のもの)を使用した場合です。

| プリント基板(2)パターン図 (部品面) (MultifuncDigitalClock2PC.CE3) | (ハンダ面) (MultifuncDigitalClock2PC1.CE3) | ページトップ |

■ ケース加工図 ■

 本機のケースは、"秋月電子" の "ABS樹脂ケース(蝶番式・中)112−TS ニシムラ (通販コード P-00277)" を使用しました。 外側(内側)寸法が 117 (112) x 84 (80) x 28 (24) mm で、可動式のフタが付いています。


・メイン基板の取り付け
 上図の(下面図)はケースの裏面側から見た図で、上部の大きな点線の四角部分(72 x 89 mm)がメイン基板の取り付け位置です。 私がプリント基板をケース等に取り付ける場合、通常、両者の間には 5 mm 長のスペーサを挟んで 取り付けることが多いのですが、本機のメイン基板には 5 mm 長のスペーサを使用することができません。

 上の プリント基板パターン図 (部品面) の項で、使用したトグルスイッチについて述べたように、本機ではレバーが短いタイプを使用していますが、メイン基板を上図のケース内に納めるためには 5 mm 長のスペーサでは長過ぎて、 上蓋が閉まらなくなってしまいます。 そこで本機では M3 のナットをスペーサ代わり、としました。 ウィルコ で購入したナットで、 "鉄(ニッケルめっき) 六角ナット・1種 FNT-03N" の厚さ 2.4 mm のものです。

 ケースの裏面側(外側)の4か所から、それぞれ M3 x 10 サイズのビス(+なべ小ねじ)を通し、ケース内側でスペーサ代わりの M3 ナット → メイン基板 → ポリカーボネート平ワッシャー → M3 ナット、の順に取り付けます。 ポリカーボネート平ワッシャーは、プリント基板表面の傷つき防止とねじ緩み防止を兼ねて挿入をしてあります。(ねじ類の型番等については、次項の 使用部品表 を参照のこと)

・補助基板の取り付け
 上図の(上面図)はケースの上面側から見た図で、ケース上蓋の右上の小さな点線の四角部分に、補助基板を上蓋の内側から取り付けます。 補助基板には前項 プリント基板(2)パターン図 (部品面) (ハンダ面) で説明をした方法で、 タクトスイッチが取り付けられていることが前提です。

 ケースの上面側(外側)の2か所から、それぞれ M3 x 12 サイズのビス(+なべ小ねじ)を通し、ケース内側で M3 x 5 サイズの中空スペーサ → 補助基板 → M3 ナット、の順に取り付けます。 すると、タクトスイッチのキートップが 1.5 mm 程 ケース外に飛び出すようになります。

・電池ホルダーの取り付け
 上図の(下面図)はケースの裏面側から見た図で、下部の横に細長い点線の四角部分に、18650 リチウムイオン電池用の電池ホルダーを取り付けます。 私が使用した電池ホルダー、およびその取り付けるときの注意点、方法などについては、 別ページ "198. MP3プレーヤー I" の 電池ホルダーをケースに取り付け を参考にしてください。

| ケース加工図 (MultifuncDigitalClockCS.CE3) | ページトップ |

■ 使用部品表 ■

(主要部品: IC, トランジスタ等)

(データシート)
PICマイコン .................... PIC16F1827
三端子レギュレータ .................... S-812C33AY-B-G
トランジスタ .................... 2SA1015
LCDモジュール .................... AQM0802A-RN-GBW
圧電ブザー .................... PKM17EPP-4001

| 部品表 | Excel ファイル (MultifuncDigitalClock_parts.xls) | ページトップ |

■ 参考資料・関連サイト ■

PIC16F1827 データシート .......... https://akizukidenshi.com/download/pic16f1827.pdf
145. 長時間ストップウオッチ/タイマー .......... http://xyama.sakura.ne.jp/hp/StopWatchTimer.html
184. ストップウオッチ II .......... http://xyama.sakura.ne.jp/hp/StopWatchII.html
189. ドットマトリクス 8 x 8 LED 表示時計 II ( MAX7219 版) .......... http://xyama.sakura.ne.jp/hp/Matrix88LED_ClockII.html

| ページトップ | ホーム |


Copyright (C) 2023 やまもとみのる
初版:2023年12月1日、初公開:2023年12月1日、最終更新:2023年12月5日