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

203. 有機 EL ディスプレイ(OLED) 表示 キッチン・タイマー II

[ 初公開日:2025年8月6日 ]

 時計関連の作品を製作する場合に、最近の私は、リアルタイムクロック(RTC)として、DS3231 を使用したモジュールを採用することが多いのですが、"195. ドットマトリクス LED コントローラー" の 本機で使用した各種モジュールについて の項で述べたように、DS3231 版と比べると精度が少し低い、と言われている DS1307 版のモジュールも数個を所有しており、 その使い道(使用先)に何か良いアイデアはないものかと、以前から常に思い巡らせていました。

 また、先に公開した "201. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー II"、"202. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー III" で使用した、128 x 64 ドットの OLED モジュールの他、128 x 32 ドットという半分サイズの OLED モジュールも同時期に購入がしてありましたが、中途半端なサイズなこともあってなかなか出番がありません。

 もう一つ、当初、始めて使用する PIC16F1 ファミリでは 14 ピン PIC に拘って、PIC16F1705 と PIC16F18325 の2種類の PIC を購入してあったのですが、"194. FMステレオラジオ III" の製作では PIC16F1705 を採用したこともあって、 それ以来、14 ピンでは PIC16F1705 ばかりを使用してきて、PIC16F18325 は未使用のままでした。

 そこで、このように使用頻度が少なかった、あるいはまったく使用してこなかったこれら3者を、本機 "キッチン・タイマー II" で一気に融合させてみよう、という試みです。





(OLED) ディスプレイの表示例

 本機では、DS1307 版 RTC モジュールの時計情報(年、月、日、時、分、秒)は一切使用しません。 モジュールから1秒ごとに出力される SQ 信号だけを PIC が受けて、タイマーのクロック源としています。 本機で設定できるタイマーの設定値は最大 99 分 59 秒までの範囲 としているため、クロック源としては十分な精度として使用ができます。

本機のプログラムを更新 ( 2025/10/20 更新 )

 以前から PIC16F1 ファミリでプログラムを作成する場合に、PORTx レジスタと LATx レジスタの取り扱いについて、理解不足で不適切な点がありましたが、この度、その点についてのプログラムの更新を行いました。 詳細は プログラム の項の PORTx レジスタと LATx レジスタの取り扱い をご覧になってください。

■ 回路図 ■

*注.  入力ポート RA0, RA1, RA4, RA5, RC4, RC5 は、内部プルアップ機能を ON にして使用。 また、SLEEP 中には それらのポート に状態変化割り込み機能を使用。

 上に示した回路図はもちろん本機 "キッチン・タイマー II" の回路図ですが、これは前作の "202. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー III" の 回路図 で示したものと比べて、 使用した PIC や OLED、RTC の各モジュールに違いはありますが、全体の回路構成はほとんど同じで違いはありません。

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

■ 本機で使用した各モジュール ■

 本機においても上回路図に示すように、3つのモジュール(黄色に塗りつぶしたもの)を使用しています。 これらのモジュールについて、私が感じた問題点やその他の注意点などを交えて、次に順に挙げていきます。
● 有機 EL ディスプレイ(OLED)( SSD1306 )モジュール

 冒頭でも述べたように、"201. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー II"、"202. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー III" では、左下の写真に示す 128 x 64 ドットの OLED モジュールを使用しましたが、本機では右下の写真に示すような 128 x 32 ドットという半分サイズの OLED モジュールを使用 しました。

 これらのモジュールは、私がアマゾンの中華モールなるものの存在を知ってから初期の 2020 年 8 月ごろに、他の複数種類の異なった OLED モジュールとともに購入したもので、もう5年も以前のことになります。 どちらの OLED モジュールにも SSD1306 という同じ制御チップが使われていて、インタフェースには I2C 通信と SPI 通信の2種類のものが存在しますが、どちらも I2C 通信の方を私は選択購入をしてありました。


 外観は上写真のようなものですが、実際のサイズはかなり小さなもので、左のモジュールは 0.96 インチ、右のモジュールは 0.91 インチと商品説明には書かれています。 実際に文字等を表示をさせてみても小さ過ぎる感が強く、実用的にはもっと大きな表示器を選択した方が 良いと思いますが、今回は右側のモジュールを使用しました。

 また、このモジュールについても、Arduino や Raspberry Pi 用には各種のライブラリが存在しているようですが、本機のように PIC(特にアセンブラ言語)を使用した場合には、既成のライブラリの存在はまったく期待することはできません。 したがって、プログラム面においてはすべてを自分自身で作成(万年カレンダー II で自作のライブラリを作成済み)することになります。

● リアルタイムクロック( DS1307 )モジュール

 リアルタイムクロック(RTC)モジュールに関しても冒頭でも述べたように、最近の私が時計関連の作品を製作する場合には、そのときの私の手持ちの都合で次の写真に示すような、2種類の DS3231 版の RTC モジュールを採用してきました。 DS3231 版の RTC モジュールであれば、私が使用した経験上、どちらの RTC モジュールを採用しても、時計としてはかなりの精度を期待することができます。(ただし、"DS3231 For PI" を使用する場合には、SQW 信号を外部に取り出すための改造が必要。)

AT24C32 が搭載された DS3231 版 RTC モジュール RTC モジュール "DS3231 For PI"

 これらの DS3231 版の RTC モジュールの他にも、次の写真に示すような DS1307 版の RTC モジュール を、数個を私は所有していますが両者を比較した場合に、一般的に後者の RTC モジュールは精度が少し低い ― と言われている通り、 私の一度だけの使用経験* ですがその誤差は酷いもので、時計としての作品には採用すべきではありません。  私がこれらそれぞれの RTC モジュールの特徴など違いを良く知らなかった 2020 年 9 月ごろに、アマゾン内のあるショップで、DS1307 版があまりにも安価(@ 83 円)だったので、5個(配送料 69 円)を購入してありました。 したがって1個は既に使用済みですが、 今後の時計としての作品には使用ができない(使用したくない)、DS1307 版の RTC モジュールが4個も在庫があるわけで、何か他に使い道(使用先)はないものかと、日頃から常に思い巡らせていました。

DS1307 版 RTC モジュール

 私のホームページ上には、"キッチン・タイマー" や "ラーメン・タイマー" の類のコンテンツを、現在、数件を公開していますが、それらはどれもまずまずの人気を得ているようです。 中でも "153. キッチン(カウントダウン)・タイマー" は結構な需要があるようですが、公開をしてから既に 12 年も経とうとしており、途中で一度、プログラムの更新を計ってはいますが、数ある私の PIC 作品の中でも比較的初期に近いころの作品でもあるため、自分自身がプログラミング的に今一に感じるところもあります。

 そこで ― というわけでもないのですが、本ページの 冒頭 で述べたように、DS1307 版 RTC モジュール、128 x 32 ドット OLED モジュール、PIC16F18325 の3者を組み合わせた、"キッチン・タイマー" の製作をしてみようと思った次第で、 ハードウエア構成も、"153. キッチン(カウントダウン)・タイマー" とは、まったく異なったものとなりました。

 本機では時計とは異なるため、RTC モジュールからの延々と続く時計情報(年、月、日、時、分、秒)は必要がなく、それらを使用することは一切ありません。 モジュールから1秒ごとに出力される SQ 信号だけを、 PIC の外部(INT)割り込みで受けて、タイマーとしてのクロック源とします。

 したがって、時計とした場合には精度が低い時計情報は、時間が経てば経つほどその誤差の累計は大きくなって行きますが、1秒ごとの SQ 信号だけを利用する本機のようなタイマーの場合には、最大でも 100 分ほどの短時間のカウンタのために、 精度が低い DS1307 版 RTC モジュールでも、その影響を受けることはほとんどありません。

 また、時計情報(年、月、日、時、分、秒)をまったく使用しない本機の使用では、電源を断にしたときに備えての バックアップ用の電池も必要がありません

 このモジュールを本機で使用するに当たっては、右上写真のような位置に、ストレート型の 7 ピンヘッダを取り付けて使用しました。 このモジュールにはピンヘッダは付属していないので、自前で用意をする必要があります。 プリント基板 側に取り付けたピンソケット(メス)で受けて接続をします。

● TP4056 リチウムイオン電池充電モジュール

 本機を使用するための電源としては、最近の私の製作物ではお馴染みとなった 18650 リチウムイオン電池を、やはり本機でも採用することにしました。 そして、18650 リチウムイオン電池を使用する場合に、私は生セルタイプを使用することが多くなるため、 電池を充電することはもちろんのこと、使用時に過放電(2.4V)、過電流から保護するように、安全面からも "TP4056 リチウムイオン電池充電モジュール" なるものが必須となります。

 "TP4056 リチウムイオン電池充電モジュール" として、私は以前には、Micro USB タイプ のモジュールを使用していましたが、最近になって、タイプ C の USB コネクタを使用したモジュールを入手する機会を得たので、 本機では後者のモジュールを使用しました。 前者で使用している USB コネクタは使用時の外力には弱く、容易にモジュール基板から剥がれてしまうことも予測されますが、後者のモジュールでは、USB コネクタがスルーホールでがっちりと取り付けられているため、 使用時に破損させてしまう心配がありません。

Micro USB タイプ充電モジュール タイプ C 充電モジュール

 タイプ C の USB コネクタを使用したモジュールは、アマゾン等を覗いてみると、Micro USB タイプのモジュールに比べて、かなり高価で販売されているショップを多く見かけますが、私は Temu で安価なショップを見つけたので購入をしてみました。 ちなみに、2024 年 6 月現在において 15 個セットで 445 円でした。 1個当たり 30 円弱ですが、アマゾン等で販売している他のショップでは、これほどの安価な充電モジュールを見かけたことはありません。 願わくは、不良品が混在していないように!と祈るばかりです。

 なお、"TP4056 リチウムイオン電池充電モジュール" の機能等については、"197. 18650 リチウムイオン電池充電器" の TP4056 リチウムイオン電池充電モジュール で詳述しているので、そちらを参照してください。 また、上写真のように両者を見比べてみると、購入ショップが異なるためかメーカーも恐らく異なっているらしく、両者では微妙に使用部品の配置や回路構成なども、若干ですが異なっている様子が窺えます。

| ページトップ |

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

右側面側から見た様子 左側面側から見た様子
前側面側から見た様子 後側面側から見た様子

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

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

上蓋を開いてケース内部を見た様子 撮る角度を少し変えてもう1枚
カウンタが動作中の様子 本機の電源 18650 リチウムイオン電池を充電中の様子

| ページトップ |

■ 機能概要と使用法 ■

スイッチ操作と機能間の遷移図
「カウンタ種類の選択」画面(メインルーチン)
「3種類のカウンタ」画面とタイマー時間の設定
「3種類のカウンタ」画面とカウンタ動作
「メンテナンス機能」画面とスイッチ操作


◎ スイッチ操作と機能間の遷移図

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

  • また、本機では RTC モジュールの時計情報(年、月、日、時、分、秒)をまったく使用しないため、電源を断にしたときに備えての バックアップ用の電池は必要がない。

  • さて、本機の電源スイッチを ON にすると、"ピポッ" と開始ブザー音を出力後、プログラムのタイトル、およびバージョン番号などの表示とともに、有機 EL ディスプレイ(OLED) の簡単なデモ表示が数秒間行われる。
    			  Kitchen Timer II
    			    Version x.xx
    			    by m.yamamoto
    

  • このとき、DOWN スイッチと UP スイッチを同時に押しながら電源スイッチを ON にしたときには、デモ表示だけを省略 することができる。

  • ディスプレイ(OLED) のデモ表示が終了すると、PIC の EEPROM メモリに記憶されている、各種の引き継ぎ情報を RAM バッファ、および各種変数へ読み出し後に、"ピピッ" ブザー音とともに、「カウンタ種類の選択」画面(メインルーチン)へと進む。

  • 次の図は、本機におけるスイッチ操作と各機能間の遷移の関係だけを図に表したもので、(XXX)で示す各スイッチを操作することで各機能間を移動する。(なお、各機能内でのスイッチ操作については、以降で説明をするそれぞれの機能の項を参照のこと)
        
        			 CANCEL    LEFT     DOWN      UP      RIGHT    START
        			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
        			 │●│   │●│   │●│   │●│   │●│   │●│
        			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
        			/ MAINTE  / NEXT                    / PREV.  / SELECT
        
        			スイッチ省略名	 (STA): START
        					 (SEL): SELECT
        					 (RIG): RIGHT
        					 (PRV): PREV.
        					  (UP): UP
        					 (DWN): DOWN
        					 (LEF): LEFT
        					 (NEX): NEXT
        					 (CAN): CANCEL
        					 (MNT): MAINTE
        

  • DOWN カウンタ機能 は、START スイッチを押すと、予め設定しておいたタイマー時間を1秒ごとにカウントダウンして行き、そのときどきの残時間(分秒)を LARGE 数字文字で表示するとともに、秒においてはバーグラフでも毎秒更新されて行く様子を表示する。 本機における設定時間は最大 99 分 59 秒までが可能で、予め設定しておいた設定時間が経過してタイムアウトを迎えると、アラームによってその旨を知らせる。

  • UP カウンタ機能 は、START スイッチを押してから CANCEL スイッチが押されるまでの間、毎秒ごとにカウントアップされて行く様子を LARGE 数字文字で表示するとともに、秒においてはバーグラフでも毎秒更新されて行く様子を表示する。 CANCEL スイッチが押されるまでの間 ― というのに上限はないが、 本機では最大 99 分 59 秒までしかカウントすることができないため、それ以上に時間経過をした場合には、表示は 00 分 00 秒に戻って始めからカウントアップを繰り返す。

  • DOWN + UP カウンタ機能 は、その名の通り、START スイッチを押した直後は DOWN カウンタとして機能し、予め設定しておいたタイマー時間からカウントダウンして行き、やがてタイムアウトを迎えるとアラームによってその旨を知らせた後、 引き続き UP カウンタに転じて機能するようになり、CANCEL スイッチが押されるまでの間カウントアップされて行く。 それぞれの DOWN カウンタ、UP カウンタ機能は、上述の単独での DOWN カウンタ機能、UP カウンタ機能と異なるところはない。

| 機能概要のトップに戻る |


◎ 「カウンタ種類の選択」画面(メインルーチン)
    			 CANCEL    LEFT     DOWN      UP      RIGHT    START
    			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
    			 │●│   │●│   │●│   │●│   │●│   │●│
    			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
    			/ MAINTE  / NEXT                    / PREV.  / SELECT
    
    		 NEXT スイッチ        ..... 選択位置のポインタを + 1
    		PREV. スイッチ        ..... 選択位置のポインタを - 1
    
    	       SELECT スイッチ        ..... 選択位置のカウンタ機能へ移行
    
    		   UP スイッチ 長押し ..... UP カウンタ機能へ移行(3秒以上の長押し)
    
    		 DOWN スイッチ 長押し ..... DOWN カウンタ機能へ移行(3秒以上の長押し)
    
    		 DOWN スイッチ 長押し +
    		   UP スイッチ        ..... Down + Up カウンタ機能へ移行(3秒以上の長押し)
    
    	       MAINTE スイッチ 長押し ..... メンテナンス機能に移行(3秒以上の長押し)
    
    
  • 本機では、次の選択メッセージに示すように3種類のカウンタ機能を持ち、まず、どの種類のカウンタを使用するかを選択することから始める。
    			  Counter Select ? x
    			   1. Down
    			   2. Up
    			   3. Down + Up
    
        ..... 1行目の右端の数字は、実際にはブリンク表示されている

  • 初めに表示される上の選択画面では、前回実行されたカウンタ種類が引き継がれ、2行目〜4行目の内のどれか(デフォルトでは 1. Down: 2行目)が選択されて、先頭番号(1./2./3. のどれか)が反転表示され、 かつ、1行目の "Counter Select ? x" メッセージの x 位置には、その選択された番号がブリンク表示される。(上の写真では反転表示になっているだけであるが、実際にはブリンク表示がされる。 以下同様に、ブリンク表示の場合にも写真では反転表示になっている ので注意。)

  • これらのカウンタ種類は、NEXT スイッチ、または PREV. スイッチ を押すことによって変更をすることができ、希望するカウンタ種類を選択後に SELECT スイッチ を押すことによって選択決定され、 "ピピッ" ブザー音とともに次項の「3種類のカウンタ」の初期画面のどれかが表示される。

  • もう一つの選択方法として、直接、希望するカウンタ種類と同名の DOWN スイッチUP スイッチ、または DOWN スイッチ + UP スイッチ (DOWN スイッチを押しながら UP スイッチ)を3秒以上長押しをしていると、 それまで選択表示されていたカウンタ種類には関係なく、長押しによって新たに選択したカウンタ種類と同行の右端に、 "ピッ" ブザー音とともに "Go!" メッセージが追加反転表示されるので、それを合図に各スイッチから指を放すと、 "ピピッ" ブザー音とともに次項の「3種類のカウンタ」の初期画面のどれかが表示される。


  • なお、この「カウンタ種類の選択」画面において、どのスイッチも操作しない状態が3分(デフォルト)以上続くと、省エネのため自動的にディスプレイ (OLED) をスリープさせるとともに、本機自体も スリープモード に移行する。

  • 本機がスリープモードに移行するときには、3分(デフォルト)を経過する3秒前から、秒ごとに "ブッ" ブザー音を3回、また、3分を経過直後に "ブッブー" ブザー音とともにスリープモードに移行する。

  • また、本機自体およびディスプレイ (OLED) がスリープモードになっているときに、全6個のスイッチの内のどれかが操作されると本機は ウエイクアップ して、"ピピッ" ブザー音とともに、再びディスプレイ (OLED) 画面の表示がされるようになる。

| 機能概要のトップに戻る |


◎ 「3種類のカウンタ」画面とタイマー時間の設定
    			 CANCEL    LEFT     DOWN      UP      RIGHT    START
    			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
    			 │●│   │●│   │●│   │●│   │●│   │●│
    			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
    			/ MAINTE  / NEXT                    / PREV.  / SELECT
    
    	        RIGHT スイッチ        ..... ブリンク位置のポインタを + 1
    		 LEFT スイッチ        ..... ブリンク位置のポインタを - 1
    
    		   UP スイッチ        ..... ブリンク位置の値を + 1
    		 DOWN スイッチ        ..... ブリンク位置の値を - 1
    
    	        START スイッチ        ..... 各カウンタの動作を開始
    
    	       CANCEL スイッチ        ..... 「3種類のカウンタ」画面の表示を終了し、
    		                            「カウンタ種類の選択」画面へ戻る
    
    
  • 前項の「カウンタ種類の選択」画面(メインルーチン)で、3種類のカウンタ機能の内のどれかが選択されて移行してくると、次の写真のようにそれぞれ「3種類のカウンタ」画面のどれかが表示される。 これらの「3種類のカウンタ」画面は、 一見どれも同じように見えるが、ディスプレイ画面の右側半分1行目にカウンタ種類が表示されているので、それで区別ができる。

  • この「3種類のカウンタ」画面の内、DOWN カウンタ画面DOWN + UP カウンタ画面 では、DOWN カウンタとしての初期値(タイマー時間)が必要であり、前回使用(設定)された分秒(デフォルトでは 15 分 00 秒)が記憶されているので、 画面左上の LARGE 数字文字の表示位置にその分秒(MM:SS)が表示されるとともに、左端の1文字目(デフォルト)がブリンク表示される。

        DOWN カウンタ画面 DOWN + UP カウンタ画面
        ..... 左端の1文字目がブリンク表示される

  • 画面左上に表示される LARGE 数字文字は、左から 10 分カウンタ、1 分カウンタ、10 秒カウンタ、1 秒カウンタに対応していて、この4つのカウンタの内で変更を希望するカウンタを、まず、RIGHT スイッチ または LEFT スイッチ の操作によって、そのブリンク表示されているカウンタ位置を変更する。

  • 次に、UP スイッチ または DOWN スイッチ の操作によって、ブリンク表示されているカウンタ位置の値を変更する。 このように4つのスイッチの操作によって、4つのカウンタ値を希望する DOWN カウンタとしての初期値(タイマー時間)に 設定する。

  • この状態のとき(4つのカウンタの内のどれか1つがブリンク表示中)に、START スイッチ を押すと(指を放した瞬間から)、"ピピッ" ブザー音とともに1秒ごとのカウントダウンが始まり、そのときどきの残時間(分秒)で画面左上の LARGE 数字文字を更新(ダウン)するとともに、秒においてはバーグラフでも1秒ごとに更新(ダウン)されて行く様子を表示する。

  • また、これら2者の内の DOWN + UP カウンタ画面 では、画面左上の LARGE 数字文字のカウントダウンが始まると同時に、それに加えて、その右横1行目の NORMAL 数字文字が毎秒ごとにカウントアップされて行く様子も表示される。

  • 一方、UP カウンタ画面 では、前項の「カウンタ種類の選択」画面から移行してきた直後から、画面左上の LARGE 数字文字の表示位置には、UP カウンタとしての初期値 00 分 00 秒 が表示されるが、上述2者のカウンタ画面とは異なって、 予め何も設定しておくようなものはないため画面上のどこもブリンク表示されることはなく、画面にはまったく動きがないので注意が必要である。

        UP カウンタ画面

  • このように UP カウンタ画面では、ひたすら、START スイッチが押されるのを待ち続け、やがて、START スイッチ が押されると(指を放した瞬間から)、"ピピッ" ブザー音とともに1秒ごとのカウントアップが始まり、そのときどきの経過時間(分秒)で画面左上の LARGE 数字文字を更新(アップ)するとともに、 秒においてはバーグラフでも1秒ごとに更新(アップ)されて行く様子が表示される。

  • ここで、カウンタ機能には直接関係はないが、3種類のカウンタ画面の右側半分2行目には、本機で使用している電源 18650 リチウムイオン電池の、現在電圧値を表示する機能も搭載しているので、電池の充電時期の判断に使用することができる。

  • そして、これら3者のカウンタ画面において、もしも、START スイッチが押されるよりも以前に CANCEL スイッチ が押された場合には、直ちに、それぞれのカウンタ画面の表示を終了し、前項の「カウンタ種類の選択」画面(メインルーチン)に、 "ピピッ" ブザー音とともに戻る。


  • また、START スイッチ、または CANCEL スイッチのいずれも押されず(DOWN カウンタ画面と DOWN + UP カウンタ画面では、RIGHT、LEFT、UP、DOWN のすべてのスイッチを含む)に、3分(デフォルト)以上が経過すると、 省エネのため自動的にディスプレイ (OLED) をスリープさせるとともに、本機自体も スリープモード に移行する。

  • このスリープモードに移行するときの様子や、やがてウエイクアップするときの様子は、前項の 「カウンタ種類の選択」画面での様子 とまったく同様である。

| 機能概要のトップに戻る |


◎ 「3種類のカウンタ」画面とカウンタ動作

  • 前項で DOWN カウンタ画面、または DOWN + UP カウンタ画面 において START スイッチ が押されると、その前に予め設定しておいた設定時間から1秒ごとにカウントダウンが行われて、その刻々と "分秒" が更新(ダウン)されて行く様子が、 LARGE 数字文字の表示エリアに表示されるとともに、バーグラフの表示エリアにも刻々と "秒" が更新(ダウン)されて行く様子が表示される。

        DOWN カウンタ画面 DOWN + UP カウンタ画面
        どちらも START スイッチが押されてから1秒が経過した様子

  • この2者のカウンタ画面の内 DOWN + UP カウンタ画面 では、上記に加えて、カウンタ画面の右側半分1行目の NORMAL 数字文字の表示エリアにも、毎秒ごとにカウントアップされて "分秒" が更新(アップ)されて行く様子が同時に表示される。 (この場合には DOWN カウンタと UP カウンタが同時に動作をしている。)

      • DOWN + UP カウンタ画面
        1分 35 秒が経過した様子

  • これら2者のカウンタ画面では、DOWN カウンタが 10 秒を経過する(毎 0 秒になる)ごとに "プッ" ブザー音を、また1分を経過する(毎 00 秒になる)ごとに "ププッ" ブザー音を出力して、経過を音声でも知らせる。

  • 以上の動作を、予め設定しておいた設定時間(タイマー時間:本機では最大 99 分 59 秒まで)が経過して、タイムアウトを迎えるまで繰り返し実行するが、やがてタイムアウトを迎える 10 秒前からは、毎秒ごとに "プッ" ブザー音を出力するようになり、 そして、残り時間がゼロになると "ピピピッ" ブザー音を3回繰り返して、カウントダウンが停止したことをアラーム音でも知らせる。

  • その後、実行された設定時間が PIC の EEPROM メモリ内に記憶されているデータと同一であったかどうかの重複チェックが行われ、もしも、異なっていた場合には新たな設定時間として、EEPROM メモリ内の記憶を更新するが、同一のデータであった場合には 記憶を更新することはない。

  • このようにタイムアウトを迎えた両カウンタ画面の内、DOWN カウンタ画面では、最下行にカウンタストップメッセージが出力される。
    			  Counter Stop ! _
    
        DOWN カウンタ画面
        ..... 最下行右端の1文字がブリンク表示される
        タイムアウトになった

  • また、DOWN + UP カウンタ画面では、アラームによってタイムアウトを知らせた後(EEPROM メモリの更新も同様に済ませた後)、LARGE 数字文字の表示エリアに表示されていた DOWN カウンタは、引き続き UP カウンタに転じて(初期値 00 分 00 秒から) 機能するようになり、元々表示されていた、カウンタ画面の右側半分1行目の NORMAL 数字文字の表示エリアについては、タイムアウトを迎えたと同時に表示の更新は停止をする。

  • そして、この UP カウンタによりその刻々と "分秒" が更新(アップ)されて行く様子が、新たに LARGE 数字文字の表示エリアに表示されるとともに、 バーグラフの表示エリアにも刻々と "秒" が更新(アップ)されて行く様子が表示されるようになる。

      • DOWN + UP カウンタ画面
        UP カウンタに転じてから7秒が経過

  • 一方、前項で UP カウンタ画面 において START スイッチ が押されると、初期値 00 分 00 秒から1秒ごとにカウントアップが行われ、その刻々と "分秒" が更新(アップ)されて行く様子が、LARGE 数字文字の表示エリアに表示されるとともに、 バーグラフの表示エリアにも刻々と "秒" が更新(アップ)されて行く様子が表示される。

        UP カウンタ画面
        1分 35 秒が経過後の様子

  • これらの UP カウンタ画面でも、UP カウンタが 10 秒を経過する(毎 0 秒になる)ごとに "プッ" ブザー音を、また1分を経過する(毎 00 秒になる)ごとに "ププッ" ブザー音を出力して、経過を音声でも知らせることは同様である。

  • また、これらの UP カウンタでは、CANCEL スイッチ が押されるまでいつまでもカウントアップをし続け、上限の制限がない。 ただし、本機では最大 99 分 59 秒までしかカウントすることができないため、それ以上に時間経過をした場合には 100 分経過ごとに、その表示が 00 分 00 秒に戻って始めからカウントアップを繰り返す。

  • やがて、CANCEL スイッチ が押されると UP カウンタは停止をし、"ブー" ブザー音とともに UP カウンタ画面の最下行に、カウンタストップメッセージが出力される。
    			  Counter Stop ! _
    
        UP カウンタ画面 DOWN + UP カウンタ画面
        カウントアップを実行中に CANCEL スイッチが押された

  • また、上述の DOWN カウンタ画面、または DOWN + UP カウンタ画面 において、タイムアウトを迎える前で未だカウントダウンを実行中に、CANCEL スイッチ を押して強制的に DOWN カウンタを停止させた場合にも同様に、"ブー" ブザー音とともに これらのカウンタ画面の最下行に、カウンタストップメッセージが出力される。 そしてこの場合には、データの重複チェックは行われず EEPROM メモリ内の記憶を更新することもない。
    			  Counter Stop ! _
    
        DOWN カウンタ画面 DOWN + UP カウンタ画面
        カウントダウンを実行中に CANCEL スイッチが押された

  • このように、いろいろな状況下で DOWN カウンタ、または UP カウンタが停止をしたことによって、その結果としてカウンタストップメッセージが出力され、そのメッセージの右端1文字がブリンク表示される。 ユーザはその結果を十分確認した後に、全6個のスイッチの内のどれかを押して応答をする。

  • そして、全6個のスイッチの内のどれかを押して応答をすると、"ピピッ" ブザー音とともに、それまで実行していた「3種類のカウンタ」画面(DOWN カウンタ画面、UP カウンタ画面、または DOWN + UP カウンタ画面のどれか)と同一の、 カウンタ画面の初期画面に再び戻って表示がされる。

  • カウントダウンやカウントアップを実行中には、これらのカウンタ機能には直接関係はないが、3種類の各カウンタ画面の右側半分2行目に、本機で使用している電源 18650 リチウムイオン電池の 現在電圧値を、5秒ごとに更新をしながら表示 する。 また、これらどちらかのカウンタが実行中には、次に述べるような、スリープモード に移行することはない。

  • なお、上述のようなユーザからの応答待ちの場面においても、どのスイッチも操作しない状態が3分(デフォルト)以上続くと、省エネのため自動的にディスプレイ (OLED) をスリープさせるとともに、本機自体も スリープモード に移行する。 そして、スリープモードに移行するときの様子や、やがてウエイクアップするときの様子は、「カウンタ種類の選択」画面での様子 とまったく同様である。

| 機能概要のトップに戻る |


◎ 「メンテナンス機能」画面とスイッチ操作
    			 CANCEL    LEFT     DOWN      UP      RIGHT    START
    			 ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐   ┌─┐
    			 │●│   │●│   │●│   │●│   │●│   │●│
    			 └─┘   └─┘   └─┘   └─┘   └─┘   └─┘
    			/ MAINTE  / NEXT                    / PREV.  / SELECT
    
    		NEXT スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択
    		PREV.スイッチ        ..... OLED コントラスト / スリープまでの移行時間 の選択
    
    		  UP スイッチ        ..... ブリンク位置の値を + 1
    		  UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り
    
    		  UP スイッチ +
    		DOWN スイッチ        ..... ブリンク位置の値をデフォルト値に設定
    
    		DOWN スイッチ        ..... ブリンク位置の値を - 1
    		DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り
    
    		DOWN スイッチ +
    		  UP スイッチ        ..... ブリンク位置の値をデフォルト値に設定
    
    	      SELECT スイッチ        ..... メンテナンス機能を終了し、メイン(カウンタ種類の選択)に戻る
    
    	      CANCEL スイッチ        ..... メンテナンス機能を中断し、メイン(カウンタ種類の選択)に戻る
    
    
  • 「カウンタ種類の選択」画面(メインルーチン)で、カウンタ種類の選択とは関係ない MAINTE スイッチ を3秒以上長押しをしていると、"ピッ" ブザー音とともに、ディスプレイ画面の最下行に次に示すように、" Maintenance " + "Go!" メッセージが反転表示されるので、それを合図に MAINTE スイッチから指を放すと、ディスプレイ画面が「メンテナンス機能」画面に切り替わる。
    			  Counter Select ? x
    
    
    			   Maintenance  Go!
    

    (上の「カウンタ種類の選択」画面から、次の「メンテナンス機能」画面に切り替わる。)
    			  > OLED Contrast
    			   (001-255) ? _ xxx
    			  > Sleep Time
    			   (00-30) ? _ xx
    
        ..... 2行目右端の3文字がブリンク表示される

  • 本機におけるメンテナンス機能には、OLED コントラストの設定変更 と、スリープまでの移行時間(分)の設定変更、の2つの設定変更機能があり、本「メンテナンス機能」画面に切り替わった直後は、前者の設定変更が選択されて "(001-255) ? _ xxx" メッセージ の "xxx" 部分がブリンク表示される。

  • そこで、前者の設定値を変更したい場合には、UP スイッチ を押すごとに現在値より1ずつ増加し、また DOWN スイッチ を押すごとに1ずつ減少するので、適宜希望する値に変更する。

  • また、後者の設定変更を選択したい場合には、NEXT スイッチ、または PREV. スイッチ を押すことによって、"(00-30) ? _ xx" メッセージ の "xx" 部分がブリンク表示されるので、同様に UP スイッチまたは DOWN スイッチを押すことによって、 希望する値に変更する。


  • このように NEXT スイッチ、または PREV. スイッチは、押すごとに両者の設定変更の選択を交互に切り替えることができ、それぞれで変更できる 設定範囲は 、前者では 001 〜 255 まで、後者では 00 〜 30 まで可能としている。 ただし、後者で 00 を設定した場合には、スリープモードには移行しなくなるので注意が必要である。

    (参考) 前者の設定値として、SSD1306 では 000 の設定も可能ではあるが、その場合には画面が完全に消えてしまうので、本機では設定値から外すことにした。

  • また、UP スイッチまたは DOWN スイッチによる増減幅を大きくしたい場合には、UP スイッチまたは DOWN スイッチを押したまま にしていると、増減値が早送りされる ようになる。

  • なお、OLED コントラストを設定変更、スリープまでの移行時間(分)を設定変更、の2つの設定値のデフォルト値は、それぞれ 127 と 3 に規定されており、それぞれの設定変更が選択されているときに、UP スイッチと DOWN スイッチを同時に押す ことによって、それぞれの デフォルト値に簡単に設定する ことができる。

  • 両者の設定変更が済んで、元の「カウンタ種類の選択」画面(メインルーチン)に戻りたい場合は、SELECT スイッチ を押すことによって行われ、変更された設定値で PIC の EEPROM メモリを更新 後、"ピピッ" ブザー音を出力して 正常に終了したことを知らせる。 なお、EEPROM メモリを更新する前にはデータの重複チェックが行われ、もしも、変更後のデータと EEPROM メモリのデータが同一の場合には、更新をすることはない。

  • また、何らかの理由があって途中で設定変更を中断したい場合には、CANCEL スイッチ を押すことによって、メンテナンス機能に移行する前の「カウンタ種類の選択」画面(メインルーチン)に戻ることができる。 この場合には、それまでに 変更された設定値は破棄 され、"ブー" ブザー音を出力して中断終了したことを知らせる。

  • この「メンテナンス機能」画面においても、どのスイッチも操作しない状態が3分(デフォルト)以上続くと、省エネのため自動的にディスプレイ (OLED) をスリープさせるとともに、本機自体も スリープモード に移行する。 そして、スリープモードに移行するときの様子や、やがてウエイクアップするときの様子は、「カウンタ種類の選択」画面での様子 とまったく同様である。

| 機能概要のトップに戻る | ページトップ |


 (注意) 細かい話にはなりますが、上述の「機能概要と使用法 」の中で使用している多くのディスプレイ (OLED) 画面写真の内で、「カウンタ種類の選択」画面の1行目に "Counter Select ? x" メッセージが表示されますが、その右端のブリンク表示される数字 x の上下表示位置が1ビット下方向にずれていました。

また、「3種類のカウンタ」画面の右側半分2行目には、本機で使用している電源 18650 リチウムイオン電池の現在電圧値が表示されますが、その内の小数点を含む数字部分4文字 x.xx の上下表示位置が、画面の初期値として表示される場合は正常で良いのですが、 各カウンタの表示が更新されだすと、これらの4文字 x.xx の上下表示位置が1ビット上方向にずれてしまっています。

これら2点の件に関しては、見栄えだけの問題で大勢に影響はありませんが、プログラムの作成中にはまったく気付かず、「機能概要と使用法 」のための写真を撮って、編集後に改めて眺めてみたときに初めて気が付きました。 この項で使用しているディスプレイ (OLED) 画面だけで 20 数枚ありますが、これらをまた初めから撮り直して差し替えるのはかなり大変なので、自分でも不本意ではありますが、その2点の不具合を含んだ写真のままであることをご容赦願います。

もちろん、次項で 現在の最新プログラムバージョン (Ver. 1.04) 内に収録してあるプログラムは、これらの不具合を修正したものとなっていますので、ご安心のほどを重ねてお願いします。

■ プログラム ■

 本機では、 PIC には 14 ピンの PIC16F18325、有機 EL ディスプレイ(OLED)モジュールには 128 x 32 ドットサイズ、リアルタイムクロック(RTC)モジュールには DS1307 版、というラインナップで構成をしているのが特徴的と言えます。

 このページの冒頭でも述べたように、私にとって、PIC16F1 ファミリの中でも PIC16F18325 は初めて使用する機種(型番)であり、私が今まで使用をしてきた PIC16F1705、 PIC16F1709、PIC16F1827 などとは、ずいぶんと使用感?が異なっていました。

 PIC の基本となるシステムクロックの指定(選択)方法とか、タイマー0の使用方法とかが、今まで私が使用してきた PIC16F1 ファミリ とはまったく異なっています。 本来であれば、これらについての具体的な解説を本項でするのが良いとは思うのですが、 残念なことに、私自身がそれほど十分に理解ができた ― とは言えないのが現状なので、今は解説をするのは控えさせていただきます。 いつの日か、それができる日が来るかもしれませんが ・・・
 以下に挙げたものは、本機のプログラム内でも行っている重要なプログラミングですが、既に他の作品のホームページ内で詳細に述べているので、そちらへのリンクだけを貼っておきます。 興味がある方はそちら(リンク先)の解説をご覧になってください。  有機 EL ディスプレイ(OLED)( SSD1306 )モジュールのプログラミング では、グラフィック ディスプレイ データ RAM (GDDRAM) の構成、ドライバ IC SSD1306 の I2C インタフェース制御方法、ディスプレイ RAM (GDDRAM) のアドレス指定モードなど、 モジュールを使用する上での基本を解説しています。

 リアルタイムクロック( DS1307 )モジュールのプログラミング では、DS1307 版モジュール を使用する上での基本を解説していますが、本機ではモジュールの初期設定をしているだけで、時計情報(年、月、日、時、分、秒)は必要ないので、 一切それを使用することはありません。

 モジュールの初期設定時に、Seconds Register (00h) の CH(Clock Halt) bit を 0 にクリアして発振器を有効にし、Control Register (07h) の各 bit で 1Hz の矩形波を出力するように設定しています。 このとき、時計情報も一緒に初期設定されますが、本機では無効な動作となります。

 A / D コンバータ モジュールのプログラミング では、PIC の内部モジュールを使用して、本機で使用している電源 18650 リチウムイオン電池の、現在電圧値を表示します。 この機能に関しては、ハード、ソフトウエアともに、 "202. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー III" のものと、まったく同じものを使用しました。

● 本機で使用した PIC16F18325 のメモリの使用状況

 最近の私作の規模が大きいプログラムでは恒例となった、次に挙げるように、データメモリやプログラムメモリの使用状況についてを、ここに示しておきます。

 本機のプログラム全体を理解する上で、データメモリの内の特殊機能レジスタ (SFR) や汎用レジスタ(GPR) には、プログラムでどのレジスタにアクセスをしているかとか、4ページあるプログラムメモリの使用状況がどのようになっているか、 などの情報が事前に分かっていると、他の人はもちろんのこと、作者の自分自身でも数か月以上が経ってしまったときには、非常に役に立つものです。

◎ 本機におけるデータメモリの使用状況

 次の TABLE 4-2 は、Microchip Technology Inc. 社の PIC16F18325 データシートから抜粋したもの、その右横に示す PIC16F18325 DATA MEMORY MAP (BANKS 0-7, 17-18) は私が作成した MEMORY MAP で、 プログラムで一度でもアクセスをしたレジスタについて、それらがよく分かるように彩色を施しました。

 実は、前作の "202. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー III" の プログラム の項で示した、 PIC16F1705 データシート内の TABLE 3-3 に相当する MEMORY MAP が、PIC16F18325 データシート内には存在しないため、PIC16F18325 データシートの "TABLE 4-4: SPECIAL FUNCTION REGISTER SUMMARY BANKS0-31" を基にして私が作り出しました。 このように、特殊機能レジスタ (SFR) の一覧が一目で見渡せるのは、個々の (SFR) を把握するのに非常に便利となります。

 この MEMORY MAP で、黄色や青色、ピンク色に塗ったレジスタが 特殊機能レジスタ (SFR) で、これらの内で青色のものは、EEPROM メモリにアクセスをするときに必要になるレジスタ群、ピンク色のものは、 ADC モジュールのプログラミングに必要となるレジスタ群です。 また、薄緑色のレジスタ群は特殊機能レジスタ (SFR) ではなく、一般の変数など、ユーザが自由に使用できる 汎用レジスタ(GPR) を表しています。


 なお、本機のデバッグ中にはこれらのレジスタの他にも、BANK 31 に存在している スタックポインタ STKPTR レジスタ を、PIC16F1 ファミリではユーザがアクセスすることが可能で、内容を確認する必要に迫られてディスプレイ(OLED) 画面に表示をさせました。

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

◎ 本機におけるプログラムメモリの使用状況

 次表は、本機(プログラムバージョン: Ver. 1.04 現在)における PIC のプログラムメモリの使用状況を、各処理別に分けたメモリ分布(割り付け)をページごとに表したもので、ご覧のようにページ 0 以外のメモリでは、まだまだ十分な空きが残っています。

        ページ 使用メモリ範囲 サイズ プログラム処理
        0 h'0000' 〜 h'0042' 67 words   割り込み処理 
        h'0043' 〜 h'01DE' 412 words   外部サブルーチン include エリア *1 
        h'01DF' 〜 h'0234' 86 words   初期化処理等、他 
        h'0235' 〜 h'0263' 47 words   メインルーチン(カウンタ種類の選択)処理
        h'0264' 〜 h'033E' 219 words   メインルーチン(カウンタ種類の選択)関連の各種表示サブルーチン
        h'033F' 〜 h'03A3' 101 words   メインルーチン(カウンタ種類の選択)内での各種スイッチ処理
        ( NEXT, PREV., SELECT, UP, DOWN, MAINTE スイッチの処理 )
        h'03A4' 〜 h'0469' 198 words   各カウンタ Down/Up/Down+Up Counter(メイン)の処理
        h'046A' 〜 h'05D9' 368 words   各カウンタ Down/Up/Down+Up Counter 関連の各種表示サブルーチン 
        h'05DA' 〜 h'061A' 65 words   クロックカウントダウン/クロックカウントアップ
        h'061B' 〜 h'0695' 123 words   各カウンタ Down/Up/Down+Up Counter 内での各種スイッチ処理
        ( START, RIGHT, LEFT, UP, DOWN スイッチの処理 )
        h'0696' 〜 h'06C9' 52 words   時間の監視とスリープモード処理
        h'06CA' 〜 h'06EA' 33 words   バッテリー(18650 リチウムイオン電池)の電圧測定
        h'06EB' 〜 h'0743' 89 words   アラーム関連、ウェイトルーチン
        h'0744' 〜 h'07FF' 188 words   空き
        1 h'0800' 〜 h'0831' 50 words   ページ変換サブルーチン (Page 1 用)
        h'0832' 〜 h'0895' 100 words   メンテナンス機能の処理
        h'0896' 〜 h'0916' 129 words   メンテナンス機能関連の各種表示サブルーチン
        h'0917' 〜 h'0967' 81 words   メンテナンス機能内での各種スイッチ処理
        ( NEXT, PREV., UP, DOWN スイッチの処理 )
        h'0968' 〜 h'0A0C' 165 words   各種 演算/変換サブルーチン
        h'0A0D' 〜 h'0A9D' 145 words   プログラムタイトルの表示とデモ表示
        h'0A9E' 〜 h'0FFF' 1,378 words   空き
        2 h'1000' 〜 h'17FF' 2,048 words   空き
        3 h'1800' 〜 h'1BBF' 960 words   文字フォント (5 x 7) データ 外部テーブル include エリア *2 
        h'1BC0' 〜 h'1CAF' 240 words   文字フォント (10 x 14) データテーブル
        h'1CB0' 〜 h'1D0B' 92 words   EEPROM メモリ関連アクセス
        h'1D0C' 〜 h'1FFF' 756 words   空き
        *1: I2C (SCLクロック周波数 = 100/400 KHz) サブルーチン(ソフトウエア I2C 版)(I2C_XS.sub)
        I2C RTC(DS3231/1307)モジュール 制御サブルーチン (I2C_RTCII.sub)
        OLED モジュール ( SSD1306 ) 制御サブルーチン (OLED_SSD1306.sub)
        *2: 文字フォント(5 x 7)データテーブル (Font5x7.tbl)

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

● 有機 EL ディスプレイ(OLED) の画面レイアウト

 本機では、横 128 x 縦 32 ドット の OLED モジュールを使用し、下図に示すような画面レイアウトに従って各種の情報を表示させています。 まず、メインとなる DOWN カウンタ、または UP カウンタの内容を、画面の左上 1/4 の部分に LARGE 数字文字で表示をさせています。

DOWN カウンタの画面レイアウト

 次に、画面の右上 1/4 部分の1行目にカウンタの種類の略名(Dw Counter)を表示し、2行目には本機で使用している電源 18650 リチウムイオン電池の、現在電圧値を表示させます。 カウンタ機能には直接関係はありませんが、電池の充電時期の判断に使用します。


UP カウンタの画面レイアウト

 同様に、画面の右上 1/4 部分の1行目にカウンタの種類の略名(Up Counter)を表示し、2行目に電源 18650 リチウムイオン電池の、現在電圧値を表示させるのも同じです。


DOWN + UP カウンタの画面レイアウト

 画面の右上 1/4 部分の1行目にカウンタの種類の略名(+Up)を表示し、その右横にはメインの DOWN カウンタと並行して、同時カウントをする UP カウンタの内容を表示させます。 2行目に表示させるのは、上記2つのカウンタの場合とまったく同様です。


 そして、すべてのカウンタ画面において、画面の上下 1/2 の下部分には DOWN カウンタ、または UP カウンタの内容 "分秒" の内 "秒" が1秒ごとに更新して行く様子を、バーグラフで表示させています。 3行目すべてを使用して刻々と変化する "秒" の更新だけを表します。 最下行4行目の数字は 10 秒ごとのガイドの表記です。

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

● OLED モジュール ( SSD1306 ) 制御サブルーチン

 次に示す緑色リストのサブルーチン群は、元々、"201. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー II" の、プログラムを作成するために必要となる SSD1306 用コマンドに限ってを、SSD1306 データシートの 9 COMMAND TABLE (P 28/59) の中からいくつか選択して、私がサブルーチン集としてまとめ上げたものです。

 このときに使用した OLED モジュールは、横 128 x 縦 64 ドットのモジュールでしたが、本機で使用する OLED モジュールは、横 128 x 縦 32 ドットのため、そのままでは使用することができません。 そこで、どちらのモジュールでも共通に使用することができるように、一部のサブルーチンを書き換えたものが次に紹介するサブルーチン集です。

 このサブルーチン集を簡単に使用するためには、まず、サブルーチン集を外部ファイル(ファイル名:OLED_SSD1306.sub)としておき、メインのプログラム側で
      ;				ドライブ、パス名は、各自の開発環境に合わせるように !!
      		include		C:\Data\Project\PIC\_sub\OLED_SSD1306.sub	;Ver.1.04 以上が必要
      
として include すれば、横 128 x 縦 64 ドットのモジュール用として機能しますが、次の緑色リストの冒頭コメントに書いてあるように
      #define 	_128x32				;128x32 OLED を使用する場合
      
      ;				ドライブ、パス名は、各自の開発環境に合わせるように !!
      		include		C:\Data\Project\PIC\_sub\OLED_SSD1306.sub	;Ver.1.05 以上が必要
      
として include するだけで、横 128 x 縦 32 ドットのモジュール用として機能します。

 また、このサブルーチン集を動作させるためには、他にも、次リストの冒頭部分のコメントで述べているように、I2C インタフェース用の外部ルーチン (I2C_XS.sub) や、外部テーブル (Font5x7.tbl) 等が必要になりますが、 それらは 現在の最新プログラムバージョン に収録をしてあるので、そちらを参照してみてください。
      
      ;==========================================================================
      ;	OLED モジュール ( SSD1306 ) 制御サブルーチン	Ver. 1.05
      ;==========================================================================
      
      ;#define 	_128x32				;128x32 OLED を使用する場合に 
      						;include する側で #define 定義をすること
      
      ;<使用外部ルーチン>
      
      ;(i2c_start, i2c_stop, i2c_byte_send, i2c_ack, i2c_nack)
      
      ;<使用レジスタ>
      
      ;pagex						;表示開始ページ
      ;end_pagex					;表示終了ページ
      ;column						;表示開始カラム
      ;end_column					;表示終了カラム
      ;pattern					;水平ビット位置,垂直パターン,ワーク
      ;echr_flg					;表示文字の機能拡張フラグ
      ;
      ;oled_lpcnt					;ループカウンタ
      
      ;<使用テーブル>
      
      ;font5x7_data_tbl(外部テーブル: Font5x7.tbl)
      ;font10x14_data_tbl
      
      ;==========================================================================
      ;		定数の定義
      ;==========================================================================
      
      SSD1306_Addr	equ	h'3c'			;OLED モジュール ( SSD1306 ) のスレーブアドレス
      
      ;==========================================================================
      ;		マクロ命令定義
      ;==========================================================================
      
      ;		OLED_FontPos_M マクロ		;フォントの表示開始位置指定
      
      OLED_FontPos_M	macro	@col,@row
      		movlw	@col			;
      		movwf	column			;表示カラム
      		movlw	@row			;
      		movwf	pagex			;表示ページ
      		call	SSD1306_FontPos		;表示開始位置指定
      		endm
      
      ;		OLED_DispStr_M マクロ		;キャラクタ (横:6 x 縦:8) 文字列の表示
      
      OLED_DispStr_M	macro	@str_adr,@x
      	#if 	@x != 0
      		movlw	high @str_adr		;文字列の先頭 high アドレス
      		movwf	FSR0H			;
      		movlw	low @str_adr		;文字列の先頭 low アドレス
      		movwf	FSR0L			;
      	#endif
      		call	SSD1306_DispStr		;文字列データ1行表示
      		endm
      
      ;		OLED_DispStr2_M マクロ		;キャラクタ (横:12 x 縦:16) 文字列の表示
      
      OLED_DispStr2_M	macro	@str_adr,@x
      	#if 	@x != 0
      		movlw	high @str_adr		;文字列の先頭 high アドレス
      		movwf	FSR0H			;
      		movlw	low @str_adr		;文字列の先頭 low アドレス
      		movwf	FSR0L			;
      	#endif
      		call	SSD1306_DispStr2	;文字列データ1行表示
      		endm
      
      ;		OLED_Line_H_M マクロ		;水平線表示
      
      OLED_Line_H_M	macro	@col_st,@col_sp,@row,@ptn
      		movlw	@col_st			;
      		movwf	column			;表示開始カラム
      		movlw	@col_sp			;
      		movwf	end_column		;表示終了カラム
      		movlw	@row			;
      		movwf	pagex			;表示ページ
      		movlw	@ptn			;
      		movwf	pattern			;ビット位置
      		call	SSD1306_Line_H		;モジュールの水平線表示
      		endm
      
      ;		OLED_Line_V_M マクロ		;垂直線表示
      
      OLED_Line_V_M	macro	@col,@row_st,@row_sp,@ptn
      		movlw	@col			;
      		movwf	column			;表示カラム
      		movlw	@row_st			;
      		movwf	pagex			;表示開始ページ
      		movlw	@row_sp			;
      		movwf	end_pagex		;表示終了ページ
      		movlw	@ptn			;
      		movwf	pattern			;垂直パターン
      		call	SSD1306_Line_V		;モジュールの垂直線表示
      		endm
      
      ;==========================================================================
      ;		フォントの表示開始位置指定
      ;==========================================================================
      
      ;入力レジスタ:	pagex:		表示ページ
      ;		column:		表示カラム
      
      SSD1306_FontPos
      		call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'00'			;Control byte Co=0, D/C#=0
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'20'			;Set Memory Addressing Mode
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'02'			;Page Addressing Mode
      		call	i2c_byte_send		;1 バイト送信
      
      		movf	pagex,W
      		addlw	h'b0'			;Set Page Start Addrss for Page Addressing Mode
      		call	i2c_byte_send		;1 バイト送信(ページ開始アドレスの設定)
      		movf	column,W
      		andlw	h'0f'			;Set Lower Column Start Address for Page Addressing Mode
      		call	i2c_byte_send		;1 バイト送信(カラム開始アドレスの下位ニブル)
      		swapf	column,W
      		andlw	h'0f'
      		addlw	h'10'			;Set Higher Column Start Address for Page Addressing Mode
      		call	i2c_byte_send		;1 バイト送信(カラム開始アドレスの上位ニブル)
      		call	i2c_stop		;ストップコンディション
      		return
      
      ;==========================================================================
      ;		キャラクタ (横:6 x 縦:8) 文字の表示
      ;==========================================================================
      
      ;入力レジスタ:	W reg:		表示する文字コード (h'20'〜h'df')
      
      ;		echr_flg:	表示文字の機能拡張フラグ	;(Ver.1.01にて追加)
      ;				bit7: ビット反転表示指示
      ;				bit6: 1 bit 左(下)ずらし指示
      
      ;使用レジスタ:	oled_lpcnt, pattern, FSR1H:FSR1L
      
      ;使用テーブル:	font5x7_data_tbl(外部テーブル: Font5x7.tbl)
      
      SSD1306_DispChr
      		movwf	FSR1L			;表示する文字コード
      		clrf	FSR1H
      
      		movlw	h'20'			;h'20'がテーブルの先頭位置
      		subwf	FSR1L,F
      		movf	FSR1L,W			;W に一時退避
      
      		lslf	FSR1L,F			;x2
      		rlf	FSR1H,F
      		lslf	FSR1L,F			;x4
      		rlf	FSR1H,F
      		addwf	FSR1L,F			;x5 ... 退避した W を足す
      		clrw
      		addwfc	FSR1H,F			;C フラグを足す
      
      		movlw	low font5x7_data_tbl	;フォントテーブルデータの先頭 low アドレス
      		addwf	FSR1L,F			;
      		movlw	high font5x7_data_tbl	;フォントテーブルデータの先頭 high アドレス
      		addwfc	FSR1H,F			;
      ;
      		call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'40'			;Control byte Co=0, D/C#=1
      		call	i2c_byte_send		;1 バイト送信
      
      		movlw	5			;
      		movwf	oled_lpcnt		;ループカウンタ
      
      dspchr1		call	oledtbl_read		;テーブルデータの読み出し
      		movwf	pattern			;ワークに一時退避
      		movlp	high $			;この場所の high アドレス
      
      		btfss	echr_flg,7		;ビット反転表示指示 か?
      		goto	dspchr2			;No
      
      		movlw	h'7f'
      		xorwf	pattern,F		;ビット反転
      
      dspchr2		btfsc	echr_flg,6		;1 bit 左(下)ずらし指示 か?
      		lslf	pattern,F		;Yes
      
      		movf	pattern,W		;ワーク
      		call	i2c_byte_send		;1 バイト送信
      
      		addfsr	FSR1,1			;間接アドレス FSR1H:FSR1L + 1
      		decfsz	oled_lpcnt,F		;ループカウンタ - 1 = 0 か?
      		goto	dspchr1			;No
      
      		clrw				;文字間 h'00' 1 バイト追加
      		btfsc	echr_flg,7		;ビット反転表示指示 か?
      		movlw	h'7f'			;Yes. ビット反転
      
      		btfss	echr_flg,6		;1 bit 左(下)ずらし指示 か?
      		goto	dspchr3			;No
      
      		movwf	pattern			;ワーク
      		lslf	pattern,W		;
      
      dspchr3		call	i2c_byte_send		;1 バイト送信
      		call	i2c_stop		;ストップコンディション
      		return
      
      ;==========================================================================
      ;		キャラクタ (横:6 x 縦:8) 文字列の表示
      ;==========================================================================
      
      ;入力レジスタ:	FSR0H:FSR0L:	文字列の先頭アドレス
      
      ;<使用例>	movlw	high title_msg		;文字列の先頭 high アドレス
      ;		movwf	FSR0H			;
      ;		movlw	low title_msg		;文字列の先頭 low アドレス
      ;		movwf	FSR0L			;
      ;		call	SSD1306_DispStr		;文字列データ1行表示
      ;		  :
      ;title_msg	dt	"Perpetual Calendar",0
      
      SSD1306_DispStr
      dspstr1		call	str_read		;文字列データの読み出し
      		movlp	high $			;この場所の high アドレス
      		addfsr	FSR0,1			;間接アドレス FSR0H:FSR0L + 1
      
      		addlw	0
      		btfsc	STATUS,Z		;文字列の終了(h'00') か?
      		goto	dspstr2			;Yes
      
      		call	SSD1306_DispChr		;OLED へデータを1文字出力
      		goto	dspstr1
      
      dspstr2		return
      
      		; テーブルデータの1文字読み出し
      str_read
      		movf	FSR0H,W			;読み出すデータの high アドレス
      		movwf	PCLATH
      		movf	FSR0L,W			;読み出すデータの low アドレス
      		movwf	PCL
      
      ;==========================================================================
      ;		キャラクタ (横:12 x 縦:16) 文字の表示
      ;==========================================================================
      
      ;入力レジスタ:	W: 表示する文字コード (h'2f'(/), h'30'(0) 〜 h'39'(9), h'3a'(:))
      
      ;		echr_flg:	表示文字の機能拡張フラグ	;(Ver.1.01にて追加)
      ;				bit7: ビット反転表示指示
      
      ;使用レジスタ:	oled_lpcnt, pattern, FSR1H:FSR1L
      
      ;使用テーブル:	font10x14_data_tbl
      
      SSD1306_DispChr2
      		movwf	FSR1L			;表示する文字コード
      		clrf	FSR1H
      
      		movlw	h'2f'			;h'2f'がテーブルの先頭位置
      		subwf	FSR1L,F
      
      		lslf	FSR1L,F			;x2
      		rlf	FSR1H,F
      		lslf	FSR1L,F			;x4
      		rlf	FSR1H,F
      		movf	FSR1L,W			;W に一時退避
      		lslf	FSR1L,F			;x8
      		rlf	FSR1H,F
      		lslf	FSR1L,F			;x16
      		rlf	FSR1H,F
      
      		addwf	FSR1L,F			;x20 ... 退避した W を足す
      		clrw
      		addwfc	FSR1H,F			;C フラグを足す
      
      		movlw	low font10x14_data_tbl	;フォントテーブルデータの先頭 low アドレス
      		addwf	FSR1L,F			;
      		movlw	high font10x14_data_tbl	;フォントテーブルデータの先頭 high アドレス
      		addwfc	FSR1H,F			;
      
      SSD1306_DispChr2s
      		call	dsp2chr0		;文字の上位半分の表示
      ;
      		incf	pagex,F			;文字の下位半分の表示位置
      		call	SSD1306_FontPos		;フォントの表示開始位置指定
      
      dsp2chr0	call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'40'			;Control byte Co=0, D/C#=1
      		call	i2c_byte_send		;1 バイト送信
      
      		clrw				;文字間 h'00' 1 バイト追加
      		btfsc	echr_flg,7		;ビット反転表示指示 か?
      		movlw	h'ff'			;Yes. ビット反転
      		call	i2c_byte_send		;1 バイト送信
      
      		movlw	10			;
      		movwf	oled_lpcnt		;ループカウンタ
      
      dsp2chr1	call	oledtbl_read		;テーブルデータの読み出し
      		movwf	pattern			;ワークに一時退避
      		movlp	high $			;この場所の high アドレス
      
      		btfss	echr_flg,7		;ビット反転表示指示 か?
      		goto	dsp2chr2		;No
      
      		movlw	h'ff'
      		xorwf	pattern,F		;ビット反転
      
      dsp2chr2	movf	pattern,W		;ワーク
      		call	i2c_byte_send		;1 バイト送信
      
      		addfsr	FSR1,1			;間接アドレス FSR1H:FSR1L + 1
      		decfsz	oled_lpcnt,F		;ループカウンタ - 1 = 0 か?
      		goto	dsp2chr1		;No
      
      		clrw				;文字間 h'00' 1 バイト追加
      		btfsc	echr_flg,7		;ビット反転表示指示 か?
      		movlw	h'ff'			;Yes. ビット反転
      		call	i2c_byte_send		;1 バイト送信
      		call	i2c_stop		;ストップコンディション
      		return
      
      ;==========================================================================
      ;		キャラクタ (横:12 x 縦:16) 文字列の表示
      ;==========================================================================
      
      ;入力レジスタ:	FSR0H:FSR0L:	文字列の先頭アドレス
      
      ;<使用例>	movlw	high date_msg		;文字列の先頭 high アドレス
      ;		movwf	FSR0H			;
      ;		movlw	low date_msg		;文字列の先頭 low アドレス
      ;		movwf	FSR0L			;
      ;		call	SSD1306_DispStr2	;文字列データ1行表示
      ;		  :
      ;date_msg	dt	"2024/12/02",0
      
      SSD1306_DispStr2
      dsp2str1	call	str_read		;文字列データの読み出し
      		movlp	high $			;この場所の high アドレス
      		addfsr	FSR0,1			;間接アドレス FSR0H:FSR0L + 1
      
      		addlw	0
      		btfsc	STATUS,Z		;文字列の終了(h'00') か?
      		goto	dsp2str2		;Yes
      
      		call	SSD1306_DispChr2	;OLED へデータを1文字出力
      
      		decf	pagex,F			;文字の上位半分の表示位置に戻す
      		movlw	12
      		addwf	column,F		;カラム位置の更新
      		call	SSD1306_FontPos		;次文字の表示位置
      		goto	dsp2str1
      
      dsp2str2	return
      
      ;==========================================================================
      ;		OLED ( SSD1306 ) モジュールの水平線表示
      ;==========================================================================
      
      ;入力レジスタ:	pagex:		表示ページ
      ;		column:		表示開始カラム
      ;		end_column:	表示終了カラム
      ;		pattern:	ビット位置: h'01', h'02', h'04', h'08', h'10', h'20', h'40', h'80'
      
      ;使用レジスタ:	oled_lpcnt:	ループカウンタ
      
      SSD1306_Line_H
      		call	SSD1306_FontPos		;表示開始位置の指定
      
      		movf	column,W		;表示開始カラム
      		subwf	end_column,W		;表示終了カラム
      		addlw	1
      		movwf	oled_lpcnt		;ループカウンタ
      ;
      		call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'40'			;Control byte Co=0, D/C#=1
      		call	i2c_byte_send		;1 バイト送信
      
      oled_lh1	movf	pattern,W		;
      		call	i2c_byte_send		;1 バイト送信
      
      		decfsz	oled_lpcnt,F		;ループカウンタ - 1 = 0 か?
      		goto	oled_lh1		;No
      
      		call	i2c_stop		;ストップコンディション
      		return
      
      ;==========================================================================
      ;		OLED ( SSD1306 ) モジュールの垂直線表示
      ;==========================================================================
      
      ;入力レジスタ:	pagex:		表示開始ページ
      ;		end_pagex:	表示終了ページ
      ;		column:		表示カラム
      ;		pattern:	垂直パターン: h'00' 〜 h'ff'
      
      ;使用レジスタ:	oled_lpcnt:	ループカウンタ
      
      SSD1306_Line_V
      		call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'00'			;Control byte Co=0, D/C#=0
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'20'			;Set Memory Addressing Mode
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'01'			;Vertical Addressing Mode
      		call	i2c_byte_send		;1 バイト送信
      
      		movlw	h'21'			;Set Column Address カラムアドレスの設定
      		call	i2c_byte_send		;1 バイト送信
      		movf	column,W		;Column start address, range: 0-127
      		call	i2c_byte_send		;1 バイト送信
      		movf	column,W		;Column end address, range: 0-127
      		call	i2c_byte_send		;1 バイト送信
      
      		movlw	h'22'			;Set Page Address ページアドレスの設定
      		call	i2c_byte_send		;1 バイト送信
      		movf	pagex,W			;Page start Address, range: 0-7
      		call	i2c_byte_send		;1 バイト送信
      		movf	end_pagex,W		;Page end Address, range: 0-7
      		call	i2c_byte_send		;1 バイト送信
      		call	i2c_stop		;ストップコンディション
      ;
      		movf	pagex,W			;表示開始ページ
      		subwf	end_pagex,W		;表示終了ページ
      		addlw	1
      		movwf	oled_lpcnt		;ループカウンタ
      
      		call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'40'			;Control byte Co=0, D/C#=1
      		call	i2c_byte_send		;1 バイト送信
      
      oled_lv1	movf	pattern,W		;
      		call	i2c_byte_send		;1 バイト送信
      
      		decfsz	oled_lpcnt,F		;ループカウンタ - 1 = 0 か?
      		goto	oled_lv1		;No
      
      		call	i2c_stop		;ストップコンディション
      		return
      
      ;==========================================================================
      ;		OLED ( SSD1306 ) モジュールの画面消去
      ;==========================================================================
      
      ;使用レジスタ:	oled_lpcnt, FSR1H:FSR1L
      
      SSD1306_Clear
      		movlw	high ssd1306_clear_table ;テーブルデータの先頭 high アドレス
      		movwf	FSR1H			;
      		movlw	low ssd1306_clear_table	;テーブルデータの先頭 low アドレス
      		movwf	FSR1L			;
      		movlw	ssd1306_clear_table_end - ssd1306_clear_table
      		movwf	oled_lpcnt		;ループカウンタ
      		call	oledini00		;(SSD1306_Init 内)
      ;
      		call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'40'			;Control byte Co=0, D/C#=1
      		call	i2c_byte_send		;1 バイト送信
      
      	#ifdef	_128x32
      		movlw	high (128 * 4)		;128culomn * 4page
      	#else
      		movlw	high (128 * 8)		;128culomn * 8page
      	#endif
      		movwf	FSR1H
      	#ifdef	_128x32
      		movlw	low (128 * 4)
      	#else
      		movlw	low (128 * 8)
      	#endif
      		movwf	FSR1L			;ループカウンタ
      
      oledclr01	clrw				;h'00'
      		call	i2c_byte_send		;1 バイト送信
      		addfsr	FSR1,-1			;ループカウンタ - 1
      
      		movf	FSR1H,W			;
      		iorwf	FSR1L,W			;
      		btfss	STATUS,Z		;FSR1H = FSR1L = h'00' か?	
      		goto	oledclr01		;No
      
      		call	i2c_stop		;ストップコンディション
      		return
      
      ;--------------------------------------------------------------------------
      
      ;		OLED ( SSD1306 ) の画面消去用コマンドデータ・テーブル
      
      ssd1306_clear_table
      		dt	SSD1306_Addr << 1	;スレーブアドレス
      		dt	h'00'			;Control byte Co=0, D/C#=0
      
      		dt	h'20'			;Set Memory Addressing Mode
      		dt	h'00'			;Horizontal Addressing Mode
      
      		dt	h'21'			;Set Column Address カラムアドレスの設定
      		dt	0			;Column start address, range: 0-127
      		dt	127			;Column end address,   range: 0-127
      
      		dt	h'22'			;Set Page Address ページアドレスの設定
      		dt	0			;Page start Address, range: 0-7
      	
      	#ifdef	_128x32
      		dt	3			;Page end Address,   range: 0-3
      	#else
      		dt	7			;Page end Address,   range: 0-7
      	#endif
      ssd1306_clear_table_end
      
      ;==========================================================================
      ;		OLED ( SSD1306 ) モジュールの初期設定
      ;==========================================================================
      
      ;使用レジスタ:	oled_lpcnt, FSR1H:FSR1L
      
      SSD1306_Init
      		movlw	high ssd1306_init_table	;テーブルデータの先頭 high アドレス
      		movwf	FSR1H			;
      		movlw	low ssd1306_init_table	;テーブルデータの先頭 low アドレス
      		movwf	FSR1L			;
      		movlw	ssd1306_init_table_end - ssd1306_init_table
      		movwf	oled_lpcnt		;ループカウンタ
      
      oledini00	call	i2c_start		;スタートコンディション
      
      oledini01	call	oledtbl_read		;テーブルデータの読み出し
      		call	i2c_byte_send		;1 バイト送信
      
      		addfsr	FSR1,1			;間接アドレス FSR1H:FSR1L + 1
      		decfsz	oled_lpcnt,F		;ループカウンタ - 1 = 0 か?
      		goto	oledini01		;No
      
      		call	i2c_stop		;ストップコンディション
      		return
      
      		; テーブルデータの1文字読み出し
      oledtbl_read
      		movf	FSR1H,W			;読み出すデータの high アドレス
      		movwf	PCLATH
      		movf	FSR1L,W			;読み出すデータの low アドレス
      		movwf	PCL
      
      ;--------------------------------------------------------------------------
      
      ;		OLED ( SSD1306 ) の初期設定用コマンドデータ・テーブル
      
      ssd1306_init_table
      		dt	SSD1306_Addr << 1	;スレーブアドレス
      		dt	h'00'			;Control byte Co=0, D/C#=0
      
      		dt	h'a8'			;Set Multiplex Ratio, 画面の解像度
      	#ifdef	_128x32
      		dt	h'1f'	;h'00'- h'3f'	;32 dot
      	#else
      		dt	h'3f'	;h'00'- h'3f'	;64 dot
      	#endif
      
      		dt	h'd3'			;Set Display Offset, ディスプレイオフセット
      		dt	h'00'	;h'00'- h'3f'	;
      
      		dt	h'40'	;h'40'- h'7f'	;Set Display Start Line
      
      		dt	h'a1'	;h'a0'/ h'a1'	;Set Segment Re-map, 左右反転
      
      		dt	h'c8'	;h'c0'/ h'c8'	;Set COM Output Scan Direction, 上下反転
      
      		dt	h'da'			;Set COM Pins Hardware Configuration, COMピンの構成
      	#ifdef	_128x32
      		dt	h'02'	;h'02'- h'32'	;Sequential COM pin (128x32 のとき)
      	#else
      		dt	h'12'	;h'02'- h'32'	;Alternative COM pin (128x64 のとき)
      	#endif
      
      		dt	h'81'			;Set Contrast Control
      		dt	h'7f'	;h'00'- h'ff'	;コントラスト
      
      		dt	h'a4'	;h'a4'/ h'a5'	;Disable Entire Display On
      
      		dt	h'a6'	;h'a6'/ h'a7'	;Set Normal Display, 白黒反転
      
      		dt	h'd5'			;Set Osc Frequency
      		dt	h'80'	;h'00'- h'ff'	;
      
      		dt	h'8d'			;Enable Charge Pump Regulator
      		dt	h'14'	;h'04'/ h'14'	;
      
      		dt	h'af'	;h'ae'/ h'af'	;Display On, h'ae':OFF / h'af':ON
      ssd1306_init_table_end
      
      ;==========================================================================
      ;		OLED ( SSD1306 ) の Display ON/OFF 制御
      ;==========================================================================
      
      ;入力レジスタ:	W reg:	コマンドデータ h'af':ON / h'ae':OFF
      
      ;使用レジスタ:	pattern: ワーク
      
      SSD1306_DispOnOff
      		movwf	pattern			;ワークに一時退避
      
      		call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'80'			;Control byte Co=1, D/C#=0
      		call	i2c_byte_send		;1 バイト送信
      
      		movf	pattern,W		;コマンドデータを復帰
      		call	i2c_byte_send		;1 バイト送信
      		call	i2c_stop		;ストップコンディション
      		return
      
      ;==========================================================================
      ;		OLED ( SSD1306 ) の コントラスト制御
      ;==========================================================================
      
      ;入力レジスタ:	W reg:	コマンドデータ h'00'- h'ff'
      
      ;使用レジスタ:	pattern: ワーク
      
      SSD1306_Contrast
      		movwf	pattern			;ワークに一時退避
      
      		call	i2c_start		;スタートコンディション
      		movlw	SSD1306_Addr << 1	;スレーブアドレス
      		call	i2c_byte_send		;1 バイト送信
      		movlw	h'00'			;Control byte Co=0, D/C#=0
      		call	i2c_byte_send		;1 バイト送信
      
      		movlw	h'81'			;Set Contrast Control
      		call	i2c_byte_send		;1 バイト送信
      
      		movf	pattern,W		;コマンドデータを復帰
      		call	i2c_byte_send		;1 バイト送信
      		call	i2c_stop		;ストップコンディション
      		return
      
      ;=============================================================== end ======
      
      
 上に示した緑色リストのサブルーチン群の中で、実際に書き換え変更をしたサブルーチンは、OLED ( SSD1306 ) モジュールの 画面消去(SSD1306_Clear)サブルーチンと、 モジュールの 初期設定(SSD1306_Init)サブルーチンの2つだけです。

 なお、改めて言うまでもないことですが注意事項としては、横 128 x 縦 32 ドットのモジュール用として使用する場合には、変数 pagex、end_pagex の指定範囲は 0 〜 3 までで、4 〜 7 を指定してはいけません。

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

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

 本機では、「DOWN カウンタ」画面 と「DOWN + UP カウンタ」画面 では、DOWN カウンタとしての初期値(タイマー時間)が必要なため、その時間(分秒)を予め設定しなければなりませんが、これらの両カウンタ画面の初期画面には、 通常、前回使用された設定値が記憶されていてそれが表示されます。 そして、設定値が変更された場合には、それを新たな設定値としてカウンタ種類とともに、次回に引き継ぐように、PIC 内の EEPROM メモリに記憶がされます。

 また、本機がスリープするまでの移行時間(分)と、OLED ディスプレイ画面のコントラストを決める設定値は、本機の「メンテナンス機能」画面で変更することが可能ですが、変更した場合には、それを新たな設定値として次回にも引き継げるように、 同様に PIC 内の EEPROM メモリに記憶がされます。

 これらの設定値は、本機では、データメモリの BANK 0 内に7個の変数として散在していますが、これらの変数を EEPROM メモリに書き込む(または、読み出す)場合には、直接両者間でやり取りをするのではなく、間にデータメモリの BANK 1 内に設けたバッファ save_data_buff を介して、読み書きを行うようにしています。
 これらの実際のプログラミング例を以降に示しますが、まず、データメモリの設定 では次のリストのように、バンク 0、バンク 1 内に 変数 を定義しています。 この内、バッファ の定義位置に関しては、 本機では間接アドレス指定でアクセスをするため、実際にはどのバンク内であっても構いませんが、バンク 0 には一般の変数が多く定義されているため、バンク 0 内に余裕を持たせるために、バッファについてはバンク 1 内とし7バイト分を使用します。
      
      ;==========================================================================
      ;		定数の定義と変数のレジスタ割付け
      ;==========================================================================
      
      		:
      		:
      
      		cblock	h'20'			;バンク 0
      cnt_dw_10m					;10M(十分)DOWN カウンタ
      cnt_dw_01m					; 1M(分)DOWN カウンタ
      cnt_dw_10s					;10S(十秒)DOWN カウンタ
      cnt_dw_01s					; 1S(秒)DOWN カウンタ
      		:
      		:
      count_type					;カウンタ種類
      		:
      		:
      sleep_time					;スリープまでの移行時間(分)
      contrast					;OLED コントラスト
      		:
      		:
      		endc
      
      		cblock	h'a0'			;バンク 1
      		:
      		:
      save_data_buff					;引継ぎ情報(バックアップデータ)の読み書きバッファ
      		endc
      
      
 次に EEPROM についてですが、PIC16F18325 では独特?なアドレス指定をします。 まず、次のリストに示すように、EEPROM が存在する先頭位置は h'F000' 番地ですが、実際にプログラムで EEPROM に読み書きを行う場合には、 上述した MEMORY MAP の青色に塗った NVMADRH:NVMADRL レジスタペアに、h'7000' + EEPROM アドレス(h'00' 〜 h'FF')を設定します。
      
      ;==========================================================================
      ;		EEPROM エリア
      ;==========================================================================
      
      		org	h'f000'
      
      		:
      		:
      		:
      
      		; 以下はデフォルト値
      
      save_data	de	3			;スリープまでの移行時間(分)
      
      		de	127   ;h'7f'		;OLED コントラスト
      
      		de	1			;カウンタ種類
      
      		de	1			;10M(十分)DOWN カウンタ
      		de	5			; 1M(分)DOWN カウンタ
      		de	0			;10S(十秒)DOWN カウンタ
      		de	0			; 1S(秒)DOWN カウンタ
      save_data_end
      
      
 このように、個々の変数、バッファ、EEPROM 3者の関係を上図に示すところですが、その関係図に従った実際のプログラムが次に示すリストです。

 EEPROM メモリにアクセスするために必要な関連レジスタは、先の MEMORY MAP で青色に塗ったレジスタ群ですが、それらはバンク 17 に集中していて、ここら辺りは私が 199. 多機能携帯デジタル時計 で使用した PIC16F1827 とは、レジスタ名も収容バンクもまったく異なっています。

 一番の相違点は、上述したように PIC16F18325 では NVMADRH レジスタに h'70' を設定する点で、PIC16F1827 では NVMADRH レジスタに相当する EEADRH レジスタは、EEPROM メモリにアクセスする場合にはまったく使用しないことです。
      
      ;==========================================================================
      ;		EEPROM メモリ関連アクセス
      ;==========================================================================
      
      ;--------------------------------------------------------------------------
      ;		バックアップデータを EEPROM から読み出し
      ;--------------------------------------------------------------------------
      
      read_eeprom
      		movlw	high save_data_buff	;引継ぎ情報(バックアップデータ)の先頭アドレス
      		movwf	FSR1H			;
      		movlw	low save_data_buff	;
      		movwf	FSR1L			;間接アドレスに設定
      
      		movlw	save_data_end - save_data ;読み出しバイト数
      		movwf	lpcnt1			;ループカウンタ1
      
      		movlb	17			;バンク 17
      		movlw	h'70'
      		movwf	NVMADRH			;
      		movlw	low save_data
      		movwf	NVMADRL			;EEPROM の記録アドレスを設定
      		bsf	NVMCON1,NVMREGS		;データ EEPROM メモリにアクセス
      
      rdeep01		movlb	17			;バンク 17
      		bsf	NVMCON1,RD		;読み出し制御 = ON
      		movf	NVMDATL,W		;データの読み出し
      		movwi	FSR1++			;RAM バッファへ書き込み
      		incf	NVMADRL,F		;記録アドレスの更新
      
      		movlb	0			;バンク 0
      		decfsz	lpcnt1,F		;ループカウンタ1 - 1 = 0 か?
      		goto	rdeep01			;No
      
      		call	ram_buff_read		;RAM バッファから個々の変数へコピー
      		return
      
      ;--------------------------------------------------------------------------
      
      		; RAM バッファから個々の変数へコピー
      
      ram_buff_read
      		movlw	high save_data_buff	;引継ぎ情報(バックアップデータ)の先頭アドレス
      		movwf	FSR1H			;
      		movlw	low save_data_buff	;
      		movwf	FSR1L			;間接アドレスに設定
      
      		moviw	FSR1++			;
      		movwf	sleep_time		;スリープまでの移行時間(分)
      
      		moviw	FSR1++			;
      		movwf	contrast		;OLED コントラスト
      
      		moviw	FSR1++			;
      		movwf	count_type		;カウンタ種類
      
      dwn_cnt_read
      		moviw	FSR1++			;
      		movwf	cnt_dw_10m		;10M(十分)DOWN カウンタ
      
      		moviw	FSR1++			;
      		movwf	cnt_dw_01m		; 1M(分)DOWN カウンタ
      
      		moviw	FSR1++			;
      		movwf	cnt_dw_10s		;10S(十秒)DOWN カウンタ
      
      		moviw	FSR1++			;
      		movwf	cnt_dw_01s		; 1S(秒)DOWN カウンタ
      		return
      
      ;--------------------------------------------------------------------------
      ;		バックアップデータを EEPROM へ書き込み
      ;--------------------------------------------------------------------------
      
      write_eeprom
      		call	ram_buff_write		;個々の変数から RAM バッファへコピー
      
      		movlw	high save_data_buff	;引継ぎ情報(バックアップデータ)の先頭アドレス
      		movwf	FSR1H			;
      		movlw	low save_data_buff	;
      		movwf	FSR1L			;間接アドレスに設定
      
      		movlw	save_data_end - save_data ;書き込みバイト数
      		movwf	lpcnt1			;ループカウンタ1
      
      		movlb	17			;バンク 17
      		movlw	h'70'
      		movwf	NVMADRH			;
      		movlw	low save_data
      		movwf	NVMADRL			;EEPROM の記録アドレスを設定
      		bsf	NVMCON1,NVMREGS		;データ EEPROM メモリにアクセス
      
      wreep01		movlb	17			;バンク 17
      		moviw	FSR1++			;RAM バッファの読み出し
      		movwf	NVMDATL			;書き込みデータを設定
      
      		bsf	NVMCON1,WREN		;プログラム/消去サイクルを許可
      		bcf	INTCON,GIE		;割り込みを禁止
      		movlw	h'55'
      		movwf	NVMCON2			;h'55' を NVMCON2 に書き込む
      		movlw	h'aa'
      		movwf	NVMCON2			;h'aa' を NVMCON2 に書き込む
      
      		bsf	NVMCON1,WR		;書き込み開始
      		bsf	INTCON,GIE		;割り込みを許可
      		bcf	NVMCON1,WREN		;プログラム/消去サイクルを禁止
      		btfsc	NVMCON1,WR		;書き込み 終了か?
      		goto	$ - 1			;No
      
      		incf	NVMADRL,F		;記録アドレスの更新
      
      		movlb	0			;バンク 0
      		decfsz	lpcnt1,F		;ループカウンタ1 - 1 = 0 か?
      		goto	wreep01			;No
      
      		return
      
      ;--------------------------------------------------------------------------
      
      		; 個々の変数から RAM バッファへコピー
      
      ram_buff_write
      		movlw	high save_data_buff	;引継ぎ情報(バックアップデータ)の先頭アドレス
      		movwf	FSR1H			;
      		movlw	low save_data_buff	;
      		movwf	FSR1L			;間接アドレスに設定
      
      		movf	sleep_time,W		;スリープまでの移行時間(分)
      		movwi	FSR1++			;
      
      		movf	contrast,W		;OLED コントラスト
      		movwi	FSR1++			;
      
      		movf	count_type,W		;カウンタ種類
      		movwi	FSR1++			;
      
      		movf	cnt_dw_10m,W		;10M(十分)DOWN カウンタ
      		movwi	FSR1++			;
      
      		movf	cnt_dw_01m,W		; 1M(分)DOWN カウンタ
      		movwi	FSR1++			;
      
      		movf	cnt_dw_10s,W		;10S(十秒)DOWN カウンタ
      		movwi	FSR1++			;
      
      		movf	cnt_dw_01s,W		; 1S(秒)DOWN カウンタ
      		movwi	FSR1++			;
      		return
      
      ;==========================================================================
      
      
 しかし、PIC16F18325 にしろ PIC16F1827 にしろ、いずれの場合にも不揮発性メモリとして EEPROM が実装されているわけで、それにアクセスするためのプログラミングは、両者では多少異なる点はありますが、比較的容易であると言えます。 これに対して PIC16F1705 / 1709 では、不揮発性メモリとして EEPROM ではなく高書き込み耐性フラッシュメモリが実装されていて、この場合のプログラミングは 私にとってはやや面倒なものに感じました。  上記のように、PIC16F1827 における EEPROM のプログラミング、PIC16F1705 における耐性フラッシュメモリのプログラミング、それぞれで種類の異なる不揮発性メモリの解説を行っているので、参考にしたい方のためにリンクを貼っておきます。 興味のある方は是非ご覧になってください。

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

● PORTx レジスタと LATx レジスタの取り扱い ( 2025/10/20 追記 2025/10/23 追記更新 )

 一般的に、PIC に限らずマイコンと外部の入出力機器(身近なところで言えば、スイッチ類などの入力機器とか LED を代表とする出力機器)との間で、データをやり取りするためには入出力ポートを介して行います。

 私が自分のオリジナル作品に PIC16F1 ファミリを採用し出したのは、約4年ほど前に公開をした "194. FMステレオラジオ III" が始めてで、それ以来、公開をしたものだけを数えると次の表に示すように6作品に及びます。

        (作品名) (使用 PIC) (システムクロック)* (公開日)
          203. 有機 EL ディスプレイ(OLED) 表示 キッチン・タイマー II PIC16F18325 4 MHz 2025/08/06
          202. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー III PIC16F1705 8 MHz 2025/05/14
          201. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー II PIC16F1705 8 MHz 2025/02/16
          199. 多機能携帯デジタル時計 PIC16F1827 4 MHz 2023/12/01
          195. ドットマトリクス LED コントローラー PIC16F1709 8 MHz 2022/04/25
          194. FMステレオラジオ III PIC16F1705 8 MHz 2022/01/27

 また、初めて PIC 作品を製作したのは 20 年ほども以前のことで、PIC16F84A を使用したLチカ "003. LEDフラッシャー"(2015/01/03 公開)でした。 この PIC16F84A を代表とする PIC16F ファミリでは、 TRISx レジスタによって入力と出力のポート設定を行った後は、入力ポートも出力ポートも PORTx レジスタによってデータの入出力を行います。

 このように、始めて私が PIC のプログラムを作成した頃から、出力ポートに設定した PORTx レジスタを、BSF 命令や BCF 命令を使用して操作をする場合には、注意をしてそれらの命令を使用しないと思わぬ結果が現れる場合がある ― ということも、 (私が PIC のアセンブラ命令の勉強をしていた頃、いろいろな先輩方のサイトを拝見して)知識としては知っていました。

 それから約 20 年ほどが経ち、上述のように4年ほど前からは PIC16F ファミリだけでなく、PIC16F1 ファミリのプログラムも扱うようになって、その当初から、出力ポートに LATx レジスタが加わったことは、もちろん分かってはいたのですが、 PORTx レジスタと LATx レジスタの具体的な使い分けが、イマイチ理解できないでいました。

 ここら辺りのことを PIC16F1 ファミリのデータシートで調べてみても、リード・モディファイ・ライト(Read-Modify-Write)というキーワードが出てきて、そのこと自体は分かっても、「だから、どうなんだ?」 イマイチ、データシートに書いてあることが良く理解できないままでした。

 そんなわけもあって、今まで上の表に挙げた6作品すべてにおいて、LATx レジスタは使用しないで PIC16F ファミリとまったく同様に、入力ポートも出力ポートも PORTx レジスタだけを使用したプログラムを作成してきました。 そして、当然のように PORTx レジスタに対して BSF 命令や BCF 命令を使用していましたが、現在まで目立った不具合は経験していません。(たぶん?)

 初めて作成した PIC16F1 ファミリでの、PORTx レジスタだけを使用したプログラム "194. FMステレオラジオ III" では、BSF 命令や BCF 命令による不具合に遭遇しなかった*1 ために、そのままズルズルと今日まで来てしまいました。
    *1: 上表の (システムクロック)* 欄に示すように、4 MHz とか 8 MHz 程度の低い周波数のときには、特に、影響はないようです。
 しかし、PIC16F1 ファミリを使用するようになって4年も経とうとしているのに、今以ってこの問題を解決できないでいつまでもほっておくこともできません。 約4年間も放置していて遅すぎる感は否めませんが、改めてこの問題について調べてみることにしました。

 ネットで検索をしてみると、この問題については何件もヒットしますが、中でも "PICで遊ぶ電子工作" さんの "PORT レジスタと LAT レジスタ" という記事が、? な私を最も納得させてくれました。 この記事では実際に PIC18F1320 を使用した実験回路を使っての説明になっていますが、PIC16F1 ファミリであっても同様です。 ありがとうございました。

 結論として、PIC16F1 ファミリ(PIC16F ファミリ以外の LATx レジスタが存在する PIC すべて)においては、入力ポートには PORTx レジスタ を、出力ポートには LATx レジスタ に対してアクセスするのが基本となります。 もちろん、LATx レジスタに対しては何の気兼ねをすることもなく、BSF 命令や BCF 命令を使用することができます。

 これに対して PIC16F ファミリでは、LATx レジスタが存在しないため、出力ポートの場合にも PORTx レジスタにアクセスすることになるのですが、システムクロックが高速な場合 や、出力ポートに容量性の負荷(コンデンサ)が接続 されているような場合に、 例えば、同一ポート内の他ビット同士(例. PORTC の RC0 ビットと RC1 ビットという様に)に対して、BSF 命令や BCF 命令などのビット命令を連続的に使用すると、上述 のように 自分が 期待する結果とは異なって思わぬ結果が現れてしまう 現象が起こります。

・・・・・

 さて、本機 "203. 有機 EL ディスプレイ(OLED) 表示 キッチン・タイマー II" のプログラムにおいて、本項(PORTx レジスタと LATx レジスタの取り扱い)で述べているように、両レジスタの取り扱いを改めたプログラムに 更新*2(次に示す "現在の最新プログラムバージョン: Ver. 1.05" )をしました。
    *2: 本来であれば本機のプログラムだけではなく、上表に挙げた作品のプログラムすべてを更新すべきですが、*1 の理由により動作には影響がないと思われるので、取り敢えず現状のままとします。
 参考までに、更新前(Ver. 1.04)のプログラムも残しておきますので、興味のある方はご覧になってみてください。 本機のプログラム本体(ソースファイル (KitchenTimerII.asm) Ver. 1.05 )では更新部分は僅かですが、その本体 (KitchenTimerII.asm) から include している I2C (SCLクロック周波数 = 100/400 KHz) サブルーチン(ソフトウエア I2C 版)(I2C_XS_a.sub) Ver. 1.05 では、該当する部分が多いので大幅に更新をしています。

 更新をした I2C (SCLクロック周波数 = 100/400 KHz) サブルーチン(ソフトウエア I2C 版)(I2C_XS_a.sub) は、同一ファイルを PIC16F ファミリでも PIC16F1 ファミリでも、どちらにも対応ができるように if 文(#ifdef)で切り替える構造になっているので、 見づらいかもしれません。

< 以下、独り言 > PIC16F18325 には標準で MSSPx モジュールを内蔵しているのに、なぜ(ソフトウエア I2C 版)を使用しているのか?
こんな質問が来そうです。 この件に関してもそろそろ真剣に考えないと ・・・

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

現在の最新プログラムバージョン: Ver. 1.05 ( 2025/10/20 更新 )

ソースファイル (KitchenTimerII.asm)
 I2C (SCLクロック周波数 = 100/400 KHz) サブルーチン(ソフトウエア I2C 版)(I2C_XS_a.sub) Ver. 1.05
 I2C RTC(DS3231/1307)モジュール 制御サブルーチン (I2C_RTCII.sub) Ver. 1.04
 OLED モジュール ( SSD1306 ) 制御サブルーチン (OLED_SSD1306.sub) Ver. 1.05
 文字フォント(5 x 7)データテーブル (Font5x7a.tbl)
HEX ファイル (KitchenTimerII.hex)
(以下は参考)
ソースファイル (KitchenTimerII_104.asm) Ver. 1.04
I2C (SCLクロック周波数 = 100/400 KHz) サブルーチン(ソフトウエア I2C 版)(I2C_XS.sub) Ver. 1.04

| ページトップ |

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

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

 そして、この切断によって失われた基板下部の取り付け用穴の代理となる、新たなΦ3.2 の穴を図のように2か所開けます。 次に、基板右端に位置するスイッチ用基板の取り付けのために用いる、ジュラコンスペーサ用のΦ3.2 の穴を2か所開けます。


 次に 右側のプリント基板 は、"秋月電子" の "片面ガラス・ユニバーサル基板 Cタイプ(72×47.5mm) めっき仕上げ(販売コード 100517)" で、(A) は左側メイン基板の右端に取り付けるスイッチ用基板になるもので、 他にコネクタ用の小基板3枚 (B) (C) (D) も切り出します。

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

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

 メイン基板に多くのパーツを搭載するにあたっては、それぞれに対して以降に述べるような注意事項があるので、基板を組み立てる上での参考にしてください。 なお、図の中で、細長い長方形の中に ○で表したものはピンヘッダ(オス)を、同様に◎で表したものはピンソケット(メス)を使用することを表しているので、注意をしてください。


上図から黒文字を除去して表示

・DS1307 RTC モジュール
 プリント基板の左上の少し下に位置する四角状のものが DS1307 RTC モジュールで、本機では リアルタイムクロック( D1307 )モジュール の項で述べたように、このモジュールにはピンヘッダが取り付けられていないので、ストレート型の 7 ピンヘッダを自前で用意し取り付ける必要があります。 なお本機の使用では、電源を断にしたときに備えてのバックアップ用の電池は必要がありません。

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

 次に、モジュール基板左側の斜2か所の青色線で示すモジュール基板側の穴に対応するメイン基板側の位置には、ランド穴が開いていないのでこの位置にΦ1 程度の穴を開ける必要があり * ます。 穴を開けた後、前の縦横4か所のときと同要領で斜2か所についても、錫メッキ線等でモジュール基板の固定をします。 ただし、前の縦横4か所についてはその後、メイン基板のハンダ面側で回路の配線が必要になりますが、この斜2か所については回路の配線はありません。
      * モジュール基板のメーカーや、TP4056 リチウムイオン電池充電モジュール で述べた、Micro USB /タイプ C の USB コネクタの種類によっては、モジュール基板の穴位置が多少異なるため、 穴開けが不要な場合もあります。 私の場合にはメイン基板の左端を超えたため、穴を開けなくても錫メッキ線を通すことができました。
 また、この充電モジュールでバッテリに充電中には、充電制御 IC TP4056 がかなり発熱をするので、手持ちにあったヒートシンクを熱伝導シール(両面粘着)で貼り付けました。

・OLED モジュール
 プリント基板の上部中央には、OLED モジュールが位置します。 メイン基板側にはあらかじめ 4P のピンソケット(メス)を取り付けておき、OLED モジュール側のピンヘッダと嵌合させます。 このとき、ピンソケットには分割ピンソケットを使用するとその加工が楽になります。

・トグルスイッチ
 プリント基板下部中央に位置する POWER スイッチには、3P(1回路)のトグルスイッチで良いのですが、3P でレバーが短いタイプが私の持ち合わせになく、6P(2回路)のものがあったので私は代わりにそれを使用しました。 したがって、3P でレバーが短いタイプを入手した場合には、基板パターン図を 3P(1回路)用に変更をしてください。

 本機では ケース加工図 で示したケース(内寸高さ 24 mm)を使用したため、レバーが通常のタイプは不可で、短いタイプでないとケース内に収めることができません。

 本機で 18650 リチウムイオン電池を充電する場合には、TP4056 充電モジュールの負荷接続端子を開放しておく必要があるため、POWER スイッチを OFF にする必要があります。

・圧電スピーカー
 トグルスイッチの右上、すなわち PIC16F18325 の下位置に示す円状のものが圧電スピーカーで、本機では音量が多くなるように少々直径の大きなものを使用しました。 図に示すように、円の左右に取り付け用の穴(M2.6 用)を2個開ける必要があります。

・タクトスイッチ用基板との接続コネクタ
 プリント基板の右端縦長の位置に、タクトスイッチ用基板を取り付けますが、この基板の取り付けには、後述の ケースへのプリント基板の取り付け で説明しているように、私の場合には手持ちの関係で、 13 mm 長のオネジ+メネジの六角ジュラコンスペーサ(廣杉計器 BS-313W)を使用しました。

 そして、電気的な接続には、下の プリント基板(2)パターン図 (部品面) (ハンダ面) の項で示した、タクトスイッチ用基板のケーブルコネクタ( 7P ピンソケット(メス))と、メイン基板上に設けた 7P L型ピンヘッダとを、常時接続をさせておきます。 なお、メイン基板側のピンヘッダは、パターン図や写真のように L型でないと接続ができません。

・その他
 プリント基板左下の 3P のピンヘッダ B+ と B- 端子には、本機の電源である 18650 リチウムイオン電池を、電池ホルダからの配線( 3P ピンソケット(メス))を介して接続させます。 電気的には 2P で良いのですが、 2P 状態よりも 3P の方が、しっかりとコネクタ接続ができるために 3P としました。 そのため、真ん中のピンには配線はしていません。

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

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

 前項 プリント基板(1)パターン図 (部品面) でも述べたように、下パターン図や写真は、トグルスイッチに 3P(1回路)ではなく 6P(2回路)を使用したものなので、3P(1回路)トグルスイッチを使用した場合には、 スイッチ周りのパターンを適宜変更をしてください。


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

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

 本機では、タクトスイッチをプリント基板(2) に取り付けるときには、スイッチの底面を基板にぴったり押し付けて取り付けることが必要です。 (詳細は、後述の ケースへのプリント基板の取り付け の項を参照してください。)

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

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

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

■ ケース加工図 ■

 本機のケースも、前作( 万年カレンダー II万年カレンダー III )で使用したものとまったく同じもので、"秋月電子" の "ABS樹脂ケース(蝶番式・中)112−TS  ニシムラ (販売コード: 100277)" を使用しました。 外側(内側)寸法が 117 (112) x 84 (80) x 28 (24) mm で、可動式のフタが付いています。


 上図の(上面図)及び(左側面図)において、各丸穴の位置寸法を記入* はしてありますが、参考程度に見ておいてください。 実際に穴開けを行う場合には、プリント基板を仮に取り付けた後、ケースが透明で中が透けて見えているので、 現物合わせで丸穴の中心位置を千枚通し等で印を付けて位置決めを行った方が、穴開けがうまくいくと思います。 ただし、(下面図)におけるプリント基板の取り付け用の穴位置は、極力、正確な位置に穴開けを行うように心掛けてください。
      * ユニバーサルプリント基板は 1/10 inch = 2.54 mm というサイズ単位で穴開けがされているため、6個のタクトスイッチのキートップ用の各穴間隔は 10 mm ではなく、実際には 10.16 mm となる。
・メイン基板の取り付け
 上図の(下面図)はケースの裏面側から見た図で、上部の大きな点線の四角部分(72 x 89 mm)がメイン基板の取り付け位置です。 私がプリント基板をケース等に取り付ける場合、通常、両者の間には 5 mm 長のスペーサを挟んで 取り付けることが多いのですが、本機のメイン基板には 5 mm 長のスペーサを使用することができません。

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

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

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

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

■ ケースへのプリント基板の取り付け ■

 下図は本機ケースの右側面側から上部半分ほどを見た図で、2枚のプリント基板やタクトスイッチの取り付けの様子がよく分かるように、右側面を切り取った断面図で表しています。

 ケースへのメイン基板の取り付けに当たって、最も重要なのはその上下(高さ)位置で、重複しますが上述した メイン基板の取り付け のように、本機ではトグルスイッチ搭載のために M3 のナットをスペーサ代わりとして使用しています。 そして、前項で述べたケースを使用する限り、この状態が最もベストな上下(高さ)位置で変更することはできません。

 また、同図に示すように本機では、スイッチ用プリント基板に取り付けたタクトスイッチのトップが、ケース上面から適度な長さ(X)を飛び出すようにしなければなりません。 そのために、タクトスイッチには手持ちにあった通常のものより少々長い、 スイッチ底面からトップまでの長さが 9.5mm のものを使用し、スイッチ用基板をメイン基板に取り付けるのに、これも手持ちの関係で右写真のような、M3 x 13 mm 長のオネジ+メネジの六角ジュラコンスペーサ(廣杉計器 BS-313W)を使用しました。

 余談ですが、タクトスイッチをプリント基板に取り付ける場合に、私は通常、スイッチを基板穴に軽く押し込んだときに、足ピンがくの字に曲がったあたりで進入が止まった位置、すなわち、スイッチ底面が少し基板上面から浮いた位置でハンダ付けをすることが多いのですが、 今回は上図のように、スイッチ底面が基板上面に付くまでスイッチを押し込んで使用しました。 これは使用したタクトスイッチとスペーサの各長さによって X 値を調節するためで、ちなみに図の組み合わせでは X ≒ 2 mm ほどになりました。

| 基板の取り付け図 (pcb_attach.CE3) | ページトップ |

■ 使用部品表 ■

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

(データシート)
PICマイコン .................... PIC16F18325
三端子レギュレータ .................... S-812C33AY-B-G
有機 EL ディスプレイ(OLED) .................... SSD1306
RTC モジュール .................... DS1307
圧電ブザー .................... SPT08

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

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

PIC16F18325 データシート .......... https://akizukidenshi.com/goodsaffix/pic16(l)f18325_18345.pdf
SSD1306 データシート .......... https://akizukidenshi.com/goodsaffix/ssd1306.pdf
DS1307 データシート .......... https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
はじめての PIC-2 / PIC16F18325 .......... http://machoto2.g2.xrea.com/page/P16F18325/P18325_00.htm
195. ドットマトリクス LED コントローラー .......... https://xyama.sakura.ne.jp/hp/MatrixLED_Controller.html
202. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー III .......... https://xyama.sakura.ne.jp/hp/PerpetualCalendarIII.html

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


Copyright (C) 2025 やまもとみのる
初版:2025年8月6日、初公開:2025年8月6日、最終更新:2025年10月23日