| ホーム | 私の電子工作作品集 |
[ 初公開日:2025年5月14日 ] |
本機は、前作 "201. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー II" の後継機で、前作に、電源バッテリー(18650 リチウムイオン電池)の電圧監視機能や、
タイマーによる時間監視とアラーム音での通知機能などを追加した、より高機能な万年カレンダーとなっています。 当初は、前作のホームページ上でこれらの追加した機能などを紹介するつもりでいましたが、ハードウエアも新たに製作をし直したこともあって、本機のためのこのホームページを新たに作ることにしました。 したがって、本ページは前作のページと重複するような部分が多くありますが、本ページは本ページとしてご覧になってください。
また、本機(万年カレンダー III)としては、ハードウエア、ソフトウエア共に、3月中にはそのほとんどが完成をしていたのですが、その後の気の緩みと公的な忙しさも少々あって、本ページの作成が大幅に遅れ、結果、ページの公開も遅くなってしまいました。 |
![]() |
||
*注. 入力ポート RA0, RA1, RA4, RA5, RC4, RC5 は、内部プルアップ機能を ON にして使用。 また、SLEEP 中には それらのポート に状態変化割り込み機能を使用。 | ||
**注. リアルタイムクロックモジュールに "DS3231 For PI" を使用する場合には、SQW にプルアップ抵抗が必要。 |
前作 "201. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー II" の回路図では、SSD1306 の VCC をコントロールする目的で挿入した、PIC のポート RC2 に接続されていた抵抗 3.3 KΩとトランジスタ 2SA1015Y が、
実は不要と分かったために本機では撤去をしました。 そして空いたポート RC2 を、電源に使用しているリチウムイオン電池の、電圧チェック用の電圧計として使用できるように、本機ではアナログポートとして新たな機能を追加することにしました。 また、もともと空いていたポート RC4 には TIMER / TMSET スイッチを新設して、これもまた新たな機能を追加しました。 また、上の回路図には I2C インタフェースのための SCL、SDA の両線に、それぞれプルアップ抵抗が挿入されていますが、実はこれらの抵抗も不要です。 後述のリアルタイムクロック( DS3231 )モジュールの 回路図 をご覧になれば分かるように、既にモジュール内に内蔵されていました。 そのリアルタイムクロックモジュールとして、前作では "DS3231 For PI" を改造して使用していましたが、手持ちの残りがなくなったことと、"190. I2C IF モジュール + LCD(1602A) 表示時計" などで使用した、 従来型?の DS3231(RTC)モジュールを、最近、再び入手したのでそちらを使用しました。 |
| 回路図 (PerpetualCalendarIII.CE3) | ページトップ |
上回路図を見ていただくと分かるように、本機では3つのモジュール(黄色に塗りつぶしたもの)を使用しています。 これらのモジュールについて、私が感じた問題点やその他の注意点などを交えて、次に順に挙げていきます。
● 有機 EL ディスプレイ(OLED)( SSD1306 )モジュール 初回に製作した "174. グラフィック液晶表示 万年カレンダー" では、作品名のように、横 128 x 縦 64 ドットのグラフィック液晶(SG12864A)モジュールを使用しましたが、本機では前作(万年カレンダー II)と同様に、 I2C 制御の有機 EL (OLED) モジュールの 128 x 64 グラフィックディスプレイを使用しました。 この有機 EL (OLED) モジュールには SSD1306 という制御チップが使われていて、前者の液晶(SG12864A)モジュールとは制御方法がまったく異なっています。 このモジュールについては、私がアマゾンの中華モールなるものの存在を知ってから初期の 2020 年 8 月ごろに、複数種類の異なった OLED モジュールとともに購入したものの中の一つで、現在まで4年半以上眠らせたままになっていましたが、 前作(万年カレンダー II)に続いて2度目の使用になります。 カタログ写真を見ていると、発光色としては、白色、青色、上2列黄色で下6列青色、の3種類のモジュールが存在するようですが、私は白色のモジュールを選択購入しました。
外観は上写真のようなものですが、実際のサイズはかなり小さなもので 0.96 インチと商品説明には書かれており、写真左側の中央に位置する横長の長方形スクリーン部分のサイズは、実測で約 24.5 x 13.5 mm 程のものです。 実際に表示をさせてみても小さ過ぎる感が強く、実用的にはもっと大きな表示器を選択した方が良いと思います(しかし、価格もそれなりに高価になりますが ・・・)。 今回はこの OLED( SSD1306 )モジュールを使用することも、私にとっては目的の一つなのでこのまま製作を進めます。 価格的には、安価に販売をしているアマゾン内のショップ等では、私が購入をした当時とあまり変わっていないようで、現在でも 500 円少々程度で購入が可能なようです。 ちなみに、"秋月電子" でも大きな差はなく 580 円(2024 年 11 月現在)となっています。 本機のようなお遊びとしての製作物では、お手頃価格?かと思います。 また、このモジュールについても、Arduino や Raspberry Pi 用には各種のライブラリが存在しているようですが、本機のように PIC(特にアセンブラ言語)を使用した場合には、既成のライブラリの存在はまったく期待することはできません。 したがって、プログラム面においてはすべてを自分自身で作成(万年カレンダー II で自作のライブラリを作成済み)することになります。 ● リアルタイムクロック( DS3231 )モジュール 前作 "有機 EL ディスプレイ(OLED) 表示 万年カレンダー II" のクロック源には、左下の写真に示すような RTC モジュール "DS3231 For PI" を使用しましたが、上述もしたように、本機 "万年カレンダー III" では、右下の写真に示すような RTC モジュールを使用しました。 これは私の手持ちにある RTC モジュールの都合なので、DS3231 であればどちらを使用しても良いのですが、本機ではプログラム内で SQW 信号を使用するために、左下写真の "DS3231 For PI" を使用する場合には、その信号線を外部に引き出すための改造と プルアップ抵抗が必要になります。 その場合の改造方法等を "200. 6桁ニキシー管時計 III(IN-17)" の、リアルタイムクロックモジュール( DS3231 For PI ) で詳述しているので、そちらを参考にしてください。 一方、右下写真のモジュールを使用する場合には、下回路図に示すように、SQW 信号端子とそのプルアップ抵抗も内蔵されているので、その点での改造の必要はありませんが、他に、以降に述べるような改造を私は行いました。
本項では、右側の RTC モジュールを本機で使用する上での改造方法、および注意点を述べますが、もちろんこれは絶対的なものではなく、本機ではこのようにした方が良い ― と私が勝手に判断したものなので、 他に良い方法があれば自己責任でもってそのようにすればよいと思います。 改造点は4つあります。 まず1つ目はモジュールのバックアップ用のコイン型バッテリーについてですが、下回路図に示すように、充電池(二次電池) LIR2032 を使用することを想定した充電回路(ダイオード 1N4148 と抵抗 200Ω)が付属されているため、 そのままでは一次電池の CR2032 を使用することはできません。 したがって CR2032 を使用する場合には、ダイオード 1N4148 か抵抗 200Ωのどちらかを取り除いて、充電電流が流れないようにする必要があります。 充電池の LIR2032 は高価なので、私は右下写真のように、抵抗 200Ωを取り外し て一次電池の CR2032 を使用することにしました。 2つ目はモジュールの POWER インジケータ用 LED についてですが、本機を携帯機として使用するためには、極力余計な電流消費を抑えるようにしなければなりません。 また、本機ではこのようなインジケータは不要なため取り除くことにしました。 具体的には下回路図の左上に位置する LED と直列に接続の 抵抗 1KΩを取り外し ました。
本モジュールを購入すると、先の写真に示したように6ピンのL型ピンヘッダが取り付けられていますが、このモジュールを本機で使用するに当たっては、ストレート型のピンヘッダに取り替え る必要があります。 これが3つ目の改造です。 L型ピンヘッダのままだとプリント基板に取り付けたときに、プリント基板の平面に対してモジュール基板が垂直となって空間的に邪魔になるため、本機ではストレート型への交換は必須です。 4つ目は、3つ目で交換した6ピンのストレート型ピンヘッダとは反対側の4ピン端子にも、4ピンのストレート型ピンヘッダを取り付けました。 このピンヘッダの取り付けは任意で必須ではありませんが、横長のモジュール基板を取り付けたときに、 片側だけでは不安定さを感じるため 反対側にもピンヘッダを取り付け、また、プリント基板側にもピンソケットが必要になりますが、それの配線は不要です。 なお、上述の有機 EL (OLED) モジュールの取り付けにも同様のことが言えますが、前作(万年カレンダー II)と同様に、今回も取り敢えず片側だけで取り付けています。 ● TP4056 リチウムイオン電池充電モジュール 本機を使用するための電源として、商用AC電源からスイッチングACアダプタ等を介した方法を採るか、それ以外の電池等の電源とするかを決めるにあたって、本機を据え置き型として使用する場合には当然前者の方が良いのですが、 本機では携帯性を持たすために後者としました。 そして本機では、18650 リチウムイオン電池を採用することにしました。 18650 リチウムイオン電池を使用する場合に、私は生セルタイプを使用することが多くなるため、電池を充電することはもちろんのこと、使用時に過放電(2.4V)、過電流から保護するように、安全面からも "TP4056 リチウムイオン電池充電モジュール" なるものが必須となります。 "TP4056 リチウムイオン電池充電モジュール" として、私は以前には、Micro USB タイプ のモジュールを使用していましたが、最近になって、タイプ C の USB コネクタを使用したモジュールを入手する機会を得たので、 本機では後者のモジュールを使用しました。 前者で使用している USB コネクタは使用時の外力には弱く、容易にモジュール基板から剥がれてしまうことも予測されますが、後者のモジュールでは、USB コネクタがスルーホールでがっちりと取り付けられているため、 使用時に破損させてしまう心配がありません。
タイプ C の USB コネクタを使用したモジュールは、アマゾン等を覗いてみると、Micro USB タイプのモジュールに比べて、かなり高価で販売されているショップを多く見かけますが、私は Temu で安価なショップを見つけたので購入をしてみました。 ちなみに、2024 年 6 月現在において 15 個セットで 445 円でした。 1個当たり 30 円弱ですが、アマゾン等で販売している他のショップでは、これほどの安価な充電モジュールを見かけたことはありません。 願わくは、不良品が混在していないように!と祈るばかりです。 なお、"TP4056 リチウムイオン電池充電モジュール" の機能等については、"197. 18650 リチウムイオン電池充電器" の TP4056 リチウムイオン電池充電モジュール で詳述しているので、そちらを参照してください。 また、上写真のように両者を見比べてみると、購入ショップが異なるためかメーカーも恐らく異なっているらしく、両者では微妙に使用部品の配置や回路構成なども、若干ですが異なっている様子が窺えます。 |
| ページトップ |
以下は外観6面写真です。
|
| ページトップ |
| 機能概要のトップに戻る |
SIGNAL TIMER ZERO DOWN UP MODE ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │●│ │●│ │●│ │●│ │●│ │●│ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ /CANCEL /TMSET /BACK /MAINTE /TMODE /SET MODE スイッチ ..... NORMAL モード / LARGE モードの切り替え MODE スイッチ 長押し ..... SET モードに移行(3秒以上の長押し) (SET スイッチ) UP スイッチ ..... カレンダーめくり機能(1か月前に進める) ( LARGE モード中は無視) UP スイッチ 長押し ..... 24時間表示 / 12時間表示の切り替え(3秒以上の長押し) (TMODE スイッチ) DOWN スイッチ ..... カレンダーめくり機能(1か月後に進める) ( LARGE モード中は無視) DOWN スイッチ 長押し ..... メンテナンス機能に移行(3秒以上の長押し) (MAINTE スイッチ) (カレンダーめくり機能中はカレンダーめくり機能) ZERO スイッチ ..... 毎正時プラス・マイナス5分以内を 00分00秒に設定 (5分以外では無視) TIMER スイッチ ..... タイマーメモリの読み出しと消去 TIMER スイッチ 長押し ..... タイマーメモリの設定(3秒以上の長押し) (TMSET スイッチ) SIGNAL スイッチ ..... 毎時の時報音とタイマー一致音出力の ON / OFF 制御機能
| 機能概要のトップに戻る |
SIGNAL TIMER ZERO DOWN UP MODE ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │●│ │○│ │●│ │●│ │●│ │●│ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ /CANCEL /TMSET /BACK /MAINTE /TMODE /SET SET スイッチ ..... ブリンク位置のポインタを + 1 BACK スイッチ ..... ブリンク位置のポインタを - 1 UP スイッチ ..... ブリンク位置の値を + 1 UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り DOWN スイッチ ..... ブリンク位置の値を - 1 DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り (秒選択時に) SET スイッチ ..... SET モードを終了し、NORMAL / LARGE モードに戻る CANCEL スイッチ ..... SET モードを中断し、NORMAL / LARGE モードに戻る
| 機能概要のトップに戻る |
SIGNAL TIMER ZERO DOWN UP MODE ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │●│ │○│ │●│ │●│ │●│ │●│ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ /CANCEL /TMSET /BACK /MAINTE /TMODE /SET SET スイッチ ..... OLED コントラスト / スリープまでの移行時間 の選択 UP スイッチ ..... ブリンク位置の値を + 1 UP スイッチ 長押し ..... ブリンク位置の値を + 1 早送り UP スイッチ + DOWN スイッチ ..... ブリンク位置の値をデフォルト値に設定 DOWN スイッチ ..... ブリンク位置の値を - 1 DOWN スイッチ 長押し ..... ブリンク位置の値を - 1 早送り DOWN スイッチ + UP スイッチ ..... ブリンク位置の値をデフォルト値に設定 BACK スイッチ ..... メンテナンス機能を終了し、NORMAL / LARGE モードに戻る CANCEL スイッチ ..... メンテナンス機能を中断し、NORMAL / LARGE モードに戻る
| 機能概要のトップに戻る |
SIGNAL TIMER ZERO DOWN UP MODE ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │●│ │○│ │○│ │●│ │●│ │●│ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ /CANCEL /TMSET /BACK /MAINTE /TMODE /SET UP スイッチ ..... ブリンク位置のポインタを + 1 DOWN スイッチ ..... ブリンク位置のポインタを - 1 SET スイッチ ..... タイマー種類選択を終了し、次項目の設定に移行する CANCEL スイッチ ..... タイマー種類選択を中断し、NORMAL / LARGE モードに戻る
SIGNAL TIMER ZERO DOWN UP MODE ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │●│ │●│ │●│ │●│ │●│ │●│ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ /CANCEL /TMSET /BACK /MAINTE /TMODE /SET SET スイッチ ..... ブリンク位置のポインタを + 1 BACK スイッチ ..... ブリンク位置のポインタを - 1 UP スイッチ ..... ブリンク位置の値を + 1 DOWN スイッチ ..... ブリンク位置の値を - 1 (分選択時に) TIMER スイッチ ..... 1件分のタイマー設定を終了し、次の設定に備える CANCEL スイッチ ..... タイマー設定を中断し、NORMAL / LARGE モードに戻る
SIGNAL TIMER ZERO DOWN UP MODE ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ │○│ │●│ │●│ │●│ │●│ │○│ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ /CANCEL /TMSET /BACK /MAINTE /TMODE /SET UP スイッチ ..... ブリンクする表示番号を - 1 DOWN スイッチ ..... ブリンクする表示番号を + 1 ZERO スイッチ ..... ブリンクする表示番号の登録データを消去する TIMER スイッチ ..... タイマーメモリの読み出しを終了し、NORMAL / LARGE モードに戻る
| 機能概要のトップに戻る | ページトップ | |
本機(万年カレンダー III)のプログラムは、もちろん、前作(万年カレンダー II)の延長線上に位置するものであって、前作のプログラムに新しい機能を追加したものなので、使用した PIC も同じ PIC16F1705 を採用してプログラム開発を行っています。 このプログラムの機能追加については、当初の自分自身の心づもりではもっと短期間で行えると思っていたのですが、実際には2か月近くの長丁場となってしまいました。
● 本機で使用した PIC16F1705 のメモリの使用状況 最近の私作の規模が大きいプログラムでは恒例となった、次に挙げるように、データメモリやプログラムメモリの使用状況についてを、ここに示しておきます。 本機のプログラム全体を理解する上で、データメモリの内の特殊機能レジスタ (SFR) や汎用レジスタ(GPR) には、プログラムでどのレジスタにアクセスをしているかとか、4ページあるプログラムメモリの使用状況がどのようになっているか、 などの情報が事前に分かっていると、他の人はもちろんのこと、作者の自分自身でも数か月以上が経ってしまったときには、非常に役に立つものです。
次の TABLE 3-2、TABLE 3-3 は、Microchip Technology Inc. 社の PIC16F1705 データシートから、データメモリの内の一部分を抜粋したもので、私がプログラムで一度でもアクセスをしたレジスタについて、それらがよく分かるように彩色を施しました。 黄色や青色、ピンク色に塗ったレジスタが 特殊機能レジスタ (SFR) で、これらの内で青色のものは、High-Endurance フラッシュメモリにアクセスをするときに必要になるレジスタ群、ピンク色のものは、ADC モジュールのプログラミングに必要となるレジスタ群です。 また、薄緑色や水色のレジスタ群は特殊機能レジスタ (SFR) ではなく、一般の変数など、ユーザが自由に使用できる 汎用レジスタ(GPR) を表しています。 その内の水色のレジスタ群は、リニア データメモリとして使用しています。
| プログラムのトップに戻る |
次表は、本機(プログラムバージョン: Ver. 2.08 現在)における PIC のプログラムメモリの使用状況を、各処理別に分けたメモリ分布(割り付け)をページごとに表したもので、ご覧のように、全ページに亘ってほとんど空きがなくなってしまったので、 今後については大きなプログラム追加などを行うことはまず無理で、バグが発生したときの対処など、小さなプログラム修正しかできない状況になっています。
| プログラムのトップに戻る | 本機では、電源に使用している 18650 リチウムイオン電池の、電圧チェックがいつでも行えるように、PIC 内蔵の A / D コンバータ モジュールを使用して、[メンテナンス機能] 画面を表示したときと、本機がスリープモードからウエイクアップした直後に、 そのときの電池の電圧値をディスプレイ (OLED) 画面上に表示をさせています。 この A / D コンバータ モジュールのプログラミングについては、"194. FMステレオラジオ III" の A / D コンバータ モジュールのプログラミング においても述べたところで、重複する部分も出てきますが、ここでは本機におけるプログラミング例を示しておきます。 まず初めに、次に示すリストは、本機のプログラムで必要となる変数のレジスタ(GPR)割付けと、SFR レジスタ群の初期設定をしている部分で、特に、ADC モジュールを使用するために必要な、固定参照電圧制御レジスタ ( FVRCON )、ADC 制御レジスタ 0 ( ADCON0 )、 ADC 制御レジスタ 1 ( ADCON1 ) について( TABLE 3-3 を参照)の使用法が重要です。 次リスト中の初期化処理以前は変数のレジスタ(GPR)割付けのほんの一部分で、変数 ad_res_hi, ad_res_lo は、バンク切り替えを気にしなくても済むように共通 RAM 領域に定義しています。 また、その下に定義しているレジスタ群は、主に割り算サブルーチンやデータ形式の変換サブルーチン等で使用する変数で、通常であればバンク 0 に割付けるのですが、現在、バンク 0 内はほとんど満タン状態なので、仕方なくバンク 1 内に割付けました。 : : cblock h'70' ;バンク 0(共通 RAM 領域) : ad_res_hi ; ad_res_lo ; : endc cblock h'a0' ;バンク 1 a16_hi ;16ビット演算引き数A(上位) a16_lo ;16ビット演算引き数A(下位) b16_hi ;16ビット演算引き数B(上位) b16_lo ;16ビット演算引き数B(下位) lcnt1 ;ループカウンタ / ワーク lcnt2 ;ループカウンタ x16_hi ;div_16 答えの上位 x16_lo ;div_16 答えの下位 y16_hi ;div_16 余りの上位 y16_lo ;div_16 余りの下位 buff0 ;変換文字列の格納エリア ;┐ buff1 ; ;│ buff2 ; ;│順序を変更しないこと! buff3 ; ;│ buff4 ; ;┘ endc : : ;========================================================================== ; 初期化処理 ;========================================================================== initialize clrf STATUS ;STATUS クリア clrf INTCON ;INTCON クリア ; 内部クロックを 8 MHz に設定 movlb 1 ;バンク 1 movlw b'01110000' ;CLOCK=8MHz movwf OSCCON ; PORTA,PORTC ポートの各機能設定 movlb 0 ;バンク 0 clrf PORTA ; clrf PORTC ; movlb 2 ;バンク 2 clrf LATA ; clrf LATC ; movlb 3 ;バンク 3 clrf ANSELA ;すべて デジタル I/O ポート movlw b'00000100' ; movwf ANSELC ;RC2 のみアナログ入力ポート movlb 1 ;バンク 1 movlw b'00111111' ;RA5-RA0:入力 movwf TRISA ;ポートA の I/0 設定 movlw b'00110100' ;RC5-RC4,RC2:入力, RC3,RC1-RC0:出力 movwf TRISC ;ポートC の I/0 設定 movlb 4 ;バンク 4 movlw b'00110011' ;RA5-RA4,RA1-RA0 movwf WPUA ;プルアップ有効 movlw b'00110000' ;RC5-RC4 movwf WPUC ;プルアップ有効 movlb 7 ;バンク 7 movlw b'00110011' ;RA5-RA4,RA1-RA0 movwf IOCAN ;ポートA の立ち下がりエッジ状態変化割り込み movlw b'00110000' ;RC5-RC4 movwf IOCCN ;ポートC の立ち下がりエッジ状態変化割り込み ; 固定参照電圧の設定 movlb 2 ;バンク 2 movlw b'10000010' ; |||||||| ; bit1-0 ||||||++----- ADFVR<1:0>: ADC FVRバッファゲイン選択ビット ; |||||| 11 = ADC FVRバッファゲインは4倍、出力VADFVR = 4x VFVR ... 固定参照電圧出力は ; |||||| > 10 = ADC FVRバッファゲインは2倍、出力VADFVR = 2x VFVR ... VDDを超える事はできない ; |||||| 01 = ADC FVRバッファゲインは1倍、出力VADFVR = 1x VFVR ; |||||| 00 = ADC FVRバッファはOFF ; |||||| ; bit3-2 ||||++------- CDAFVR<1:0>: コンパレータFVRバッファゲイン選択ビット ; |||| 11 = コンパレータFVRバッファゲインは4倍、出力VCDAFVR = 4x VFVR ; |||| 10 = コンパレータFVRバッファゲインは2倍、出力VCDAFVR = 2x VFVR ; |||| 01 = コンパレータFVRバッファゲインは1倍、出力VCDAFVR = 1x VFVR ; |||| > 00 = コンパレータFVRバッファはOFF ; |||| ; bit4 |||+--------- TSRNG: 温度インジケータ レンジ選択ビット ; ||| 1 = VOUT = VDD - 4VT (Highレンジ) ; ||| > 0 = VOUT = VDD - 2VT (Lowレンジ) ; ||| ; bit5 ||+---------- TSEN: 温度インジケータ イネーブルビット ; || 1 = 温度インジケータを有効 ; || > 0 = 温度インジケータを無効 ; || ; bit6 |+----------- FVRRDY: 固定参照電圧レディ フラグビット ; | 1 = 固定参照電圧出力は使える状態 ; | 0 = 固定参照電圧出力の準備が整っていない(または無効) ; | ; bit7 +------------ FVREN: 固定参照電圧イネーブルビット ; > 1 = 固定参照電圧を有効 ; 0 = 固定参照電圧を無効 movwf FVRCON ;FVRCON: 固定参照電圧制御レジスタ ; ADC モジュールの設定 movlb 1 ;バンク 1 movlw b'00011000' ; |||||||| ; bit0 |||||||+----- ADON: ADCイネーブルビット ; ||||||| 1 = ADCを有効 ; ||||||| > 0 = ADCを無効、消費電流をゼロ ; ||||||| ____ ; bit1 ||||||+------ GO/DONE: A/D変換ステータスビット ; |||||| 1 = A/D変換サイクルを実行中、このビットをセットするとA/D変換サイクルが開始 ; |||||| このビットは、A/D変換が完了するとハードウェアによって自動的にクリア ; |||||| > 0 = A/D変換サイクルが完了(進行中でない) ; |||||| ; bit6-2 |+++++------- CHS<4:0>: アナログ チャンネル選択ビット ; | : ; | : ; | 00111 = AN7 ; | > 00110 = AN6 ; | : ; | 00001 = AN1 ; | 00000 = AN0 ; | ; bit7 +------------ 未実装 movwf ADCON0 ;ADCON0: ADC制御レジスタ0 movlw b'10010011' ; |||||||| ; bit1-0 ||||||++----- ADPREF<1:0>: ADC正側参照電圧コンフィグレーション ビット ; |||||| > 11 = VREF+を内部の固定参照電圧(FVR)モジュールに接続 ; |||||| 10 = VREF+を外部VREF+ピンに接続 ; |||||| 01 = 予約済み ; |||||| 00 = VREF+をVDDに接続 ; |||||| ; bit2 |||||+------- ADNREF: ADC負側参照電圧コンフィグレーション ビット ; ||||| 1 = VREF-を外部VREF-ピンに接続 ; ||||| > 0 = VREF-をVSSに接続 ; ||||| ; bit3 ||||+-------- 未実装 ; |||| ; bit6-4 |+++--------- ADCS<2:0>: ADC変換クロック選択ビット ; | 111 = FRC(内部のRCオシレータから供給されるクロック) ; | 110 = FOSC/64 ; | 101 = FOSC/16 ; | 100 = FOSC/4 ; | 011 = FRC(内部のRCオシレータから供給されるクロック) ; | 010 = FOSC/32 ; | > 001 = FOSC/8 ; | 000 = FOSC/2 ; | ; bit7 +------------ ADFM: A/D変換結果フォーマット選択ビット ; > 1 = 右詰め、変換結果を書き込むとADRESHの上位6ビットが「0」に設定 ; 0 = 左詰め、変換結果を書き込むとADRESLの下位6ビットが「0」に設定 movwf ADCON1 ;ADCON1: ADC制御レジスタ1 ; OPTION_REG の設定 movlb 1 ;バンク 1 movlw b'00000011' ;プルアップ有効、プリスケーラのスケール値 1:16 movwf OPTION_REG ; 割り込みの設定 bcf PIE1,TMR1IE ;TMR1IE: タイマー1割り込みを許可 = 0 movlb 0 ;バンク 0 movlw b'00000001' ;TMR1CS<1:0>: bit7-6=00: Timer1クロック源=命令クロック(FOSC/4)を選択 ;T1CKPS<1:0>: bit5-4=00: プリスケーラ値を1:1 ;TMR1ON: bit0=1: Timer1を有効 movwf T1CON ;Timer1制御レジスタ movlw b'11000000' ;GIE: bit7=1: グローバル割り込みを許可 = 1 ;PEIE: bit6=1: ペリフェラル割り込みを許可 = 1 ;TMR0IE: bit5=0: TMR0 オーバーフロー割り込み許可 = 0 ;INTE: bit4=0: INT 外部割り込み許可 = 0 ;IOCIE: bit3=0: 状態変化割り込み許可 = 0 movwf INTCON ;各割り込み要因の設定 : : ;========================================================================== ; バッテリー(18650 リチウムイオン電池)の電圧測定 ;========================================================================== ; ┌───┐ ┌───┐ ; ┌─┤3.3KΩ├─┤3.3KΩ├── 電源電圧 ; │ └───┘ └───┘ ; RC2(AN6) ──┤ ; │ ┌───┐ ; └─┤3.3KΩ├──────── GND ; └───┘ battery_voltage ; >> BATTERY 電源電圧を測定する movlb 1 ;バンク 1 bsf ADCON0,ADON ;ADC 有効 = 電源 ON movlb 0 ;バンク 0 movlp high wait_20us call wait_20us ;アクイジション時間 (5μS以上) movlp high $ movlb 1 ;バンク 1 bsf ADCON0,ADGO ;A/D 変換開始 btfsc ADCON0,ADGO ;変換完了(ハードでクリア) か? goto $ - 1 ;No bcf ADCON0,ADON ;ADC 無効 = 電源 OFF movlb 0 ;バンク 0 ; >> 結果 = ADRESH:ADRESL (右詰め) に測定電圧値 ; ; 抵抗で分圧した分(2/3)を補正 ... x 3 倍する clrf ad_res_hi clrf ad_res_lo movlw 3 movwf lpcnt ;ループカウンタ battv01 movlb 1 ;バンク 1 movf ADRESL,W ; addwf ad_res_lo,F movf ADRESH,W ; addwfc ad_res_hi,F movlb 0 ;バンク 0 decfsz lpcnt,F ;ループカウンタ - 1 = 0 か? goto battv01 ;No ; >> 結果 = ad_res_hi:ad_res_lo ... x 3 倍に補正したバイナリデータ ; ; 2.048 (V) : X (V) = 1024 : ad_res_hi:ad_res_lo ; ; X (V) = 2.048 * ad_res_hi:ad_res_lo / 1024 ; = 0.002 * ad_res_hi:ad_res_lo ; = ad_res_hi:ad_res_lo / 500 ; ; X (V) * 500 = ad_res_hi:ad_res_lo ; ; >> 0.01 V 単位にするため x 100 倍にする ... 5 で割る ; ; X (V) * 100 = ad_res_hi:ad_res_lo / 5 movlb 1 ;バンク 1 movf ad_res_hi,W ;割られる数 movwf a16_hi movf ad_res_lo,W movwf a16_lo clrf b16_hi ;割る数 movlw 5 movwf b16_lo call div_16 ;16 ビットの割り算 movlb 0 ;バンク 0 ; (a16_hi,a16_lo) ÷ (b16_hi,b16_lo) = (x16_hi,x16_lo) ... (y16_hi,y16_lo) ; ; >> 結果 = 商 (x16_hi,x16_lo) ... 余り (y16_hi,y16_lo) は無視 return ;-------------------------------------------------------------------------- ; 16 ÷ 16 = 16 ビットの割り算 ;-------------------------------------------------------------------------- ; (a16_hi,a16_lo) ÷ (b16_hi,b16_lo) = (x16_hi,x16_lo) ... (y16_hi,y16_lo) ; 使用変数: a16_hi, a16_lo: 割られる数の上,下位 (終了時は0になる) ; b16_hi, b16_lo: 割る数の 上,下位 (終了時に変化しない) ; x16_hi, x16_lo: 答えの 上,下位 (答えが返る) ; y16_hi, y16_lo: 余りの 上,下位 (余りが返る、ワークにも使用) ; lcnt1, lcnt2: ループカウンタ ; C フラグ: エラーフラグ (割る数が0であった場合 C=1) div_16 movlw 16 movwf lcnt1 ;ループカウンタ1 movf b16_lo,W ;割る数下位をワークにコピー movwf y16_lo movf b16_hi,W ;割る数上位をワークにコピー movwf y16_hi d16_01 rlf y16_lo,F ;左シフトする rlf y16_hi,F btfsc STATUS,C ;キャリフラグを見る goto d16_02 ;割る数の上位ビット位置検索 decfsz lcnt1,F goto d16_01 bsf STATUS,C ;割る数が0である。エラー終了 goto d16_09 d16_02 clrf x16_lo ;答え用変数のクリア clrf x16_hi clrf y16_lo ;ワーク変数のクリア clrf y16_hi movlw 16 movwf lcnt2 ;ループカウンタ2 movf lcnt1,W subwf lcnt2,F ;残り、実ループの回数 d16_03 lslf a16_lo,F rlf a16_hi,F rlf y16_lo,F rlf y16_hi,F decfsz lcnt1,F ;割られる数を初期位置までシフト goto d16_03 d16_04 movf b16_hi,W ;現位置での減算が可能かチェック subwf y16_hi,W btfss STATUS,C goto d16_06 movf y16_hi,W subwf b16_hi,W btfss STATUS,C goto d16_05 movf b16_lo,W subwf y16_lo,W btfss STATUS,C goto d16_06 d16_05 movf b16_lo,W subwf y16_lo,F ;ワークから下位を引く btfss STATUS,C ;キャリフラグが 1(正)なら次をスキップ decf y16_hi,F ;上位 -1 movf b16_hi,W subwf y16_hi,F ;ワークから上位を引く bsf STATUS,C ;キャリフラグをセット goto d16_07 d16_06 bcf STATUS,C ;キャリフラグをクリア d16_07 rlf x16_lo,F ;キャリフラグの内容を答えにシフト rlf x16_hi,F movf lcnt2,F btfsc STATUS,Z ;lcnt2 = 0 か? goto d16_08 ;Yes, 終了 decf lcnt2,F ;ビット位置を1つ下げる(右へ) lslf a16_lo,F ;ワークへ1ビット左シフト rlf a16_hi,F rlf y16_lo,F rlf y16_hi,F goto d16_04 d16_08 bcf STATUS,C ;正常終了 d16_09 return この項の 冒頭 でも述べたように、本機では2つの場面で電池の電圧値がディスプレイ (OLED) 画面上に表示されますが、次のリストは [メンテナンス機能] 画面を表示したときに表示される場合の例を示しています。 ;========================================================================== ; バッテリー(18650 リチウムイオン電池)の電圧表示 ;========================================================================== battery_volt__display yOLED_FontPos_M 4+6*2,1 ; bsf echr_flg,6 ;1 bit 左(下)ずらし指示 = 1 yOLED_DispStr_M batt_msg,1 ;2 行目の表示 call battery_voltage ;バッテリーの電圧測定 movlb 1 ;バンク 1 movf x16_hi,W movwf a16_hi movf x16_lo,W movwf a16_lo call bindec16cz_cnv ;16 ビット数値を 10進数 5桁の文字列に変換 movlb 0 ;バンク 0 movlw high (buff0+2) ; movwf FSR0H ; movlw low (buff0+2) ; movwf FSR0L ;間接アドレスの設定 yOLED_FontPos_M 4+6*11,1 ; moviw FSR0++ call ySSD1306_DispChr ;OLED へ1文字出力 movlw '.' call ySSD1306_DispChr ;OLED へ1文字出力 moviw FSR0++ call ySSD1306_DispChr ;OLED へ1文字出力 moviw FSR0++ call ySSD1306_DispChr ;OLED へ1文字出力 return ; dt "=== Maintenance ===",0 ;1 行目 batt_msg dt "[ Batt = . V ]",0 ;2 行目 : : ;-------------------------------------------------------------------------- ; 16 ビット数値を 10進数 5桁の文字列に変換(ゼロサプレス) ;-------------------------------------------------------------------------- ; 使用変数: a16_hi, a16_lo: 変換する 16 ビット数値 ; lcnt1: ワーク ; lcnt2: ループカウンタ ; buff0 + 0〜4: 結果 bindec16cz_cnv movlw high (buff0+4+1) ;変換文字列の格納エリア movwf FSR0H movlw low (buff0+4+1) movwf FSR0L ;間接アドレスの設定 call bd16c ;(04) 最下位変換 call bd16c ;(03) call bd16c ;(02) call bd16c ;(01) call bd16c ;(00) 最上位変換 movlw 4 ; movwf lcnt2 ;ループカウンタに設定 bd16cv01 moviw 0[FSR0] sublw h'30' btfss STATUS,Z ;(INDF) = h'30' か? goto bd16cv02 ;No movlw ' ' movwi FSR0++ decfsz lcnt2,F ;ループカウンタ - 1 = 0 か? goto bd16cv01 ;No bd16cv02 return ; ÷10(10で除算) bd16c movlw 16 ;16ビット繰り返し movwf lcnt2 ;ループカウンタに設定 clrf lcnt1 ;ワーク bd16c01 lslf a16_lo,F rlf a16_hi,F rlf lcnt1,F movlw -10 ;-10 = h'f6' addwf lcnt1,W btfsc STATUS,C ;C = 0 か? movwf lcnt1 ;No btfsc STATUS,C ;C = 0 か? incf a16_lo,F ;No decfsz lcnt2,F ;ループカウンタ - 1 = 0 か? goto bd16c01 ;No movf lcnt1,W ;余り addlw h'30' ;文字コードに変換 movwi --FSR0 return | プログラムのトップに戻る | まず初めに、従来、多くの PIC でデータの保存に使用されていた不揮発性メモリの EEPROM が、PIC16F1705 には存在していません。 同じ PIC16F1 ファミリーでも、例えば PIC16F1827 のように、種類によっては従来通り存在するものもありますが、 PIC16F1705 では EEPROM に代わるものとして、高書き込み耐性プログラム フラッシュメモリ (PFM) が、実装されている全プログラムメモリの内、最終ページ 3 の アドレス 1F80h 〜 1FFFh に 128 バイト 分が備えられています。 高書き込み耐性フラッシュメモリのプログラミングとして、データの読み出しに関してはそれほど難しくなく、反してその書き込みではやや難しく(面倒に)なるので、この項では書き込みに関してを取り上げ、本機における具体例を重点的に述べてみます。 この高書き込み耐性フラッシュメモリの内、次のリスト例のように、本機では先頭番地 save_data から 74 バイトを使用しています。 本機の前身(万年カレンダー II)ではタイマー機能がなく、したがって、そのタイマー用メモリのバックアップ用メモリも不要なため、 次リストの内の save_data から 3 バイトだけを使用していました。 ;========================================================================== ; High-Endurance フラッシュメモリ ;========================================================================== org h'1f80' ; 以下はデフォルト値 save_data dt h'20' ;年(上位)_BCD カウンタ dt 10 ;スリープまでの移行時間(分) dt h'7f' ;OLED コントラスト dt h'a5' ;タイマー用メモリの初期設定制御バイト timer_memory_bup ; (これ以降 70 バイトをタイマー用メモリのバックアップ用として使用) ;========================================================================== end ;プログラムの終了 プログラムの命令(1ワード = 14 ビット)を格納するための、プログラムメモリ全体がフラッシュメモリで構成されているのですが、その内の高書き込み耐性フラッシュメモリ(アドレス 1F80h 〜 1FFFh の 128 バイト分)に関しては、 下位バイトしか存在しなくて(上位バイトがない)、すなわち、1ワード = 8 ビット = 1 バイトとなっています。 EEPROM の場合には、単純に(といっても、それなりの手順はありますが)必要なバイトだけを、読み書きを行えば良かったのですが、フラッシュメモリに(書き換えるために)書き込む場合には、その前に予め書き込むメモリに対して消去処理をしておかなければならない、 というのが EEPROM の場合と比べて最も異なっている点です。 高書き込み耐性フラッシュメモリの旧データを、新データに書き換える場合の事前の消去処理は、たとえ1バイトの書き換えであっても、その対象となる1バイトのメモリだけを消去することができず、そのメモリが所属する行全体を消去しなければなりません。 フラッシュメモリは行単位で構成されていて、1行は一定数のメモリワードで構成されているため、この1行がユーザプログラムで消去できる最小サイズとなっています。 この最小サイズは PIC の種類によって異なっていて、 本機の PIC16F1705 では 32 ワードとなっています。 上述したように、前作(万年カレンダー II)では、高書き込み耐性フラッシュメモリの先頭番地から 3 バイトだけが、データのバックアップ対象として使用されるため、次の黒色リストのように、1行(32 ワード)消去後に 3 バイトだけを書き込んでいました。 そのときの書き込み方法は、まず 1 バイト目と 2 バイト目を 書き込みラッチに書き込む ように指示(PMCON1 レジスタの LWLO ビットをセット) をし、最後の 3 バイト目のときに フラッシュメモリに書き込む ように指示(PMCON1 レジスタの LWLO ビットをクリア) をして、それぞれの書き込みデータを送るようにします。 このように2段階の手順を踏んだ結果、書き込みラッチ上のデータも含めてすべての 3 バイトが、フラッシュメモリに書き込まれます。 : : call flash_mem_erase ;High-Endurance フラッシュメモリを1行(32 ワード)消去 call flash_mem_write ;;RAM バッファから High-Endurance フラッシュメモリへ データ書き込み : : ;-------------------------------------------------------------------------- ; High-Endurance フラッシュメモリを1行(32 ワード)消去 ;-------------------------------------------------------------------------- flash_mem_erase bcf INTCON,GIE ;割り込みを禁止 movlb 3 ;バンク 3 movlw low save_data movwf PMADRL movlw high save_data movwf PMADRH bcf PMCON1,CFGS ;フラッシュメモリにアクセス bsf PMCON1,FREE ;消去操作を指定、ハードウェアでクリア bsf PMCON1,WREN ;書き込みを許可 movlw h'55' movwf PMCON2 ;h'55' を PMCON2 に書き込む movlw h'aa' movwf PMCON2 ;h'aa' を PMCON2 に書き込む bsf PMCON1,WR ;書き込み制御 = ON、ハードウェアでクリア nop nop bcf PMCON1,WREN ;書き込みを禁止 movlb 0 ;バンク 0 bsf INTCON,GIE ;割り込みを許可 return ;-------------------------------------------------------------------------- ; RAM バッファから High-Endurance フラッシュメモリへ データ書き込み ;-------------------------------------------------------------------------- flash_mem_write call ram_buff_write ;個々の変数から RAM バッファへコピー bcf INTCON,GIE ;割り込みを禁止 movlb 3 ;バンク 3 movlw high save_data_ram ;フラッシュメモリの先頭アドレス movwf FSR1H ; movlw low save_data_ram ; movwf FSR1L ;間接アドレスに設定 movlw save_data_end - save_data movwf f_lpcnt ;ループカウンタ movlw low save_data movwf PMADRL ; movlw high save_data movwf PMADRH ; bcf PMCON1,CFGS ;フラッシュメモリにアクセス bsf PMCON1,WREN ;書き込みを許可 bsf PMCON1,LWLO ;書き込みラッチへ書き込み指示 fmemwr01 moviw FSR1++ ;最初のデータバイトを下位にロード movwf PMDATL ; ; moviw FSR1++ ;2番目のデータバイトを上位にロード ; movwf PMDATH ; decfsz f_lpcnt,F ;ループカウンタ - 1 = 0 か? goto fmemwr02 ;No goto fmemwr03 ;Yes fmemwr02 movlw h'55' movwf PMCON2 ;h'55' を PMCON2 に書き込む movlw h'aa' movwf PMCON2 ;h'aa' を PMCON2 に書き込む bsf PMCON1,WR ;書き込み制御 = ON、ハードウェアでクリア nop nop incf PMADRL,F ;記録アドレスの更新 goto fmemwr01 fmemwr03 bcf PMCON1,LWLO ;フラッシュメモリへ書き込み指示 movlw h'55' movwf PMCON2 ;h'55' を PMCON2 に書き込む movlw h'aa' movwf PMCON2 ;h'aa' を PMCON2 に書き込む bsf PMCON1,WR ;書き込み制御 = ON、ハードウェアでクリア nop nop bcf PMCON1,WREN ;書き込みを禁止 movlb 0 ;バンク 0 bsf INTCON,GIE ;割り込みを許可 return ;-------------------------------------------------------------------------- ; 個々の変数から RAM バッファへコピー ram_buff_write movlw high save_data_ram ;引継ぎ情報(データメモリ)の先頭アドレス movwf FSR1H ; movlw low save_data_ram ; movwf FSR1L ;間接アドレスに設定 movf bcd_yh,W ;年(上位2桁)_BCD カウンタ movwi FSR1++ ; movf sleep_time,W ;スリープまでの移行時間(分) movwi FSR1++ ; movf contrast,W ;OLED コントラスト movwi FSR1++ ; return : : ;========================================================================== ; High-Endurance フラッシュメモリ ;========================================================================== org h'1f80' ; 以下はデフォルト値 save_data dt h'20' ;年(上位)_BCD カウンタ dt 10 ;スリープまでの移行時間(分) dt h'7f' ;OLED コントラスト save_data_end ;========================================================================== end ;プログラムの終了これに対して本機(万年カレンダー III)では、高書き込み耐性フラッシュメモリの、先頭番地から 74 バイトがバックアップ対象として使用されるため、次の緑色リストのように書き込み方法はもう少し複雑になって、3行(32 x 3 = 96 ワード)消去後に全 74 バイトの更新データを書き込みます。 このときの書き込み方法は、RAM バッファにある書き込みデータ 74 バイトを、先頭から初めの 32 バイト、次の 32 バイト、残りの 10 バイトの3つのグループに分け、それぞれのグループごとに書き込みを行っています。(flash_mem_write サブルーチン) 具体的には、3つのグループそれぞれが処理できるようなループ(3回)を作り、第1ループが実行されるときには、初めのグループの 1 〜 31 バイト目までは 書き込みラッチに書き込む ように指示(PMCON1 レジスタの LWLO ビットをセット) をし、32 バイト目のときに フラッシュメモリに書き込む ように指示(PMCON1 レジスタの LWLO ビットをクリア) をして、それぞれの書き込みデータを送ると、その結果、書き込みラッチ上のデータも含めて、初めのグループのすべて 32(先頭から 1 〜 32)バイトが、フラッシュメモリに書き込まれます。 同様に、次の第2ループが実行されるときには、次のグループの 1 〜 31(先頭から 33 〜 63)バイト目までは 書き込みラッチに書き込む ように指示(PMCON1 レジスタの LWLO ビットをセット) をし、32(先頭から 64)バイト目のときに フラッシュメモリに書き込む ように指示(PMCON1 レジスタの LWLO ビットをクリア) をして、それぞれの書き込みデータを送ると、その結果、書き込みラッチ上のデータも含めて、次のグループのすべて 32(先頭から 33 〜 64)バイトが、 フラッシュメモリに書き込まれます。 続いて、最後の第3ループが実行されるときには、残りのグループの 1 〜 9(先頭から 65 〜 73)バイト目までは 書き込みラッチに書き込む ように指示(PMCON1 レジスタの LWLO ビットをセット) をし、10(先頭から 74)バイト目のときに フラッシュメモリに書き込む ように指示(PMCON1 レジスタの LWLO ビットをクリア) をして、それぞれの書き込みデータを送ると、その結果、書き込みラッチ上のデータも含めて、残りのグループのすべて 10(先頭から 65 〜 74)バイトが、 フラッシュメモリに書き込まれます。 : : call flash_mem_erase ;High-Endurance フラッシュメモリを3行(32 x 3 ワード)消去 call flash_mem_write ;;RAM バッファから High-Endurance フラッシュメモリへ データ書き込み : : ;-------------------------------------------------------------------------- ; High-Endurance フラッシュメモリを3行(32 x 3 ワード)消去 ;-------------------------------------------------------------------------- flash_mem_erase bcf INTCON,GIE ;割り込みを禁止 movlb 3 ;バンク 3 movlw low save_data ;フラッシュメモリの先頭アドレス movwf PMADRL movlw high save_data movwf PMADRH movlw 3 movwf f_lpcnt ;ループカウンタ(共通 RAM) fmemer01 bcf PMCON1,CFGS ;フラッシュメモリにアクセス bsf PMCON1,FREE ;消去操作を指定、ハードウェアでクリア bsf PMCON1,WREN ;書き込みを許可 movlw h'55' movwf PMCON2 ;h'55' を PMCON2 に書き込む movlw h'aa' movwf PMCON2 ;h'aa' を PMCON2 に書き込む bsf PMCON1,WR ;書き込み制御 = ON、ハードウェアでクリア nop nop bcf PMCON1,WREN ;書き込みを禁止 movlw 32 addwf PMADRL,F decfsz f_lpcnt,F ;ループカウンタ - 1 = 0 か? goto fmemer01 ;No movlb 0 ;バンク 0 bsf INTCON,GIE ;割り込みを許可 return ;-------------------------------------------------------------------------- ; RAM バッファから High-Endurance フラッシュメモリへ データ書き込み ;-------------------------------------------------------------------------- flash_mem_write call ram_buff_write ;個々の変数から RAM バッファへコピー bcf INTCON,GIE ;割り込みを禁止 movlw high save_data_ram ;引継ぎ情報(リニアデータメモリ)の先頭アドレス movwf FSR1H ; movlw low save_data_ram ; movwf FSR1L ;間接アドレスに設定 movlw timer_mem_addr - save_data_ram movwf f_lpcnt ;ループカウンタ(共通 RAM)... 総書き込みバイト数 movlb 3 ;バンク 3 movlw low save_data ;フラッシュメモリの先頭アドレス movwf PMADRL ; movlw high save_data movwf PMADRH ; fmemwr01 movlw 32 ;1 行 = 32 ラッチ数 movwf f_lpcnt2 ;ループカウンタ2(共通 RAM) bcf PMCON1,CFGS ;フラッシュメモリにアクセス bsf PMCON1,WREN ;書き込みを許可 bsf PMCON1,LWLO ;書き込みラッチへ書き込み指示 fmemwr02 moviw FSR1++ ;最初のデータバイトを下位にロード movwf PMDATL ; ; moviw FSR1++ ;2番目のデータバイトを上位にロード ; movwf PMDATH ; decf f_lpcnt,F ; btfsc STATUS,Z ;ループカウンタ - 1 = 0 か? goto fmemwr03 ;Yes decf f_lpcnt2,F ; btfsc STATUS,Z ;ループカウンタ2 - 1 = 0 か? goto fmemwr03 ;Yes movlw h'55' movwf PMCON2 ;h'55' を PMCON2 に書き込む movlw h'aa' movwf PMCON2 ;h'aa' を PMCON2 に書き込む bsf PMCON1,WR ;書き込み制御 = ON、ハードウェアでクリア nop nop incf PMADRL,F ;記録アドレスの更新 goto fmemwr02 fmemwr03 bcf PMCON1,LWLO ;フラッシュメモリへ書き込み指示 movlw h'55' movwf PMCON2 ;h'55' を PMCON2 に書き込む movlw h'aa' movwf PMCON2 ;h'aa' を PMCON2 に書き込む bsf PMCON1,WR ;書き込み制御 = ON、ハードウェアでクリア nop nop incf PMADRL,F ;記録アドレスの更新 bcf PMCON1,WREN ;書き込みを禁止 movf f_lpcnt,F ; btfss STATUS,Z ;ループカウンタ = 0 か? goto fmemwr01 ;No movlb 0 ;バンク 0 bsf INTCON,GIE ;割り込みを許可 return ;-------------------------------------------------------------------------- ; 個々の変数から RAM バッファへコピー ram_buff_write movlw high save_data_ram ;引継ぎ情報(リニアデータメモリ)の先頭アドレス movwf FSR1H ; movlw low save_data_ram ; movwf FSR1L ;間接アドレスに設定 movf bcd_yh,W ;年(上位2桁)_BCD カウンタ movwi FSR1++ ; movf sleep_time,W ;スリープまでの移行時間(分) movwi FSR1++ ; movf contrast,W ;OLED コントラスト movwi FSR1++ ; clrw ;初期設定制御バイト movwi FSR1++ ; return | プログラムのトップに戻る | 「機能概要と使用法」の タイマー機能とスイッチ操作 の項で述べたように、本機におけるタイマー機能には、[メモリの設定]、[メモリの読み出しと消去]、[タイマーメモリの監視] の3機能があり、予めタイマー情報をメモリに設定しておくと、 [タイマーメモリの監視] 機能によって、設定時刻が現在時刻に一致するとアラーム音によって通知をします。 このタイマー情報は、[メモリの読み出し] 機能によっていつでもその内容を確認することができ、不要になった場合には手動で消去することもできますが、タイマー種類が年タイマーでは、アラーム音の通知後はそのタイマー情報は不要になるため、 タイマーメモリから自動的に消去されます。 これらのタイマー機能は、前作 "201. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー II" に、新たな機能として追加をしたもので、PIC16F1705 のプログラムメモリ中のページ2に集中させています。 なお、この機能の核ともいえるタイマー用メモリは次に述べるように、リニア データメモリ内の一部分として存在をしています。 また、停電時のバックアップとして、High-Endurance フラッシュメモリにも同一データが書き込まれます。 次に示す図は、本機プログラムのソースファイル (PerpetualCalendarIII.asm) からコメントの一部を抜き出したもので、「本機におけるリニアデータメモリの使用構成図」を表しています。 ; 本機におけるリニアデータメモリの使用構成図 ;linear_memory equ h'2000' + 80 * 2 ;リニアデータメモリの先頭アドレス ;save_data_ram equ linear_memory ;引継ぎ情報の先頭アドレス ;timer_memory equ save_data_ram + 4 ;タイマー用メモリの先頭アドレス ;timer_capacity equ 10 ;タイマー用メモリの記憶容量の最大値 ;timer_mem_addr equ timer_memory + 7 * timer_capacity ;タイマー用メモリの先頭アドレス ;work_memory equ timer_mem_addr + 2 * timer_capacity ;ワークメモリの先頭アドレス ;next_memory equ work_memory + 7 * timer_capacity ;次に使用できるメモリの先頭アドレス ; linear_memory | | ; save_data_ram +-------------------------------+ 20A0 (h'2000' + 80 * 2) ――――――― ; | (4 bytes) | ↑ ↑ ; timer_memory +-------------------------------+ 20A4 | | ; | | | | ; | | BACKUP | ; | (70 bytes) | (74 bytes) | ; | | | | ; | | ↓ | ; timer_mem_addr +-------------------------------+ 20EA ――― USE ; | (20 bytes) | (164 bytes) ; | | | ; work_memory +-------------------------------+ 20FE | ; | | | ; | | | ; | (70 bytes) | | ; | | | ; | | ↓ ; next_memory +-------------------------------+ 2144 ――――――― ; | | ; | |
本機では、本機におけるデータメモリの使用状況 の TABLE 3-3 に示したように、データメモリの BANK2 以降の 汎用レジスタ(GPR) を、リニア データメモリ(水色に塗ったレジスタ群)として扱い、 その一部分(70 バイト)をタイマー用メモリとして使用しています。 そのタイマー用メモリの内訳は、下図に示すように1件分のタイマー情報を 7 バイトで構成し、最大 10 件分のタイマー情報が扱えるようにプログラミングをしています。 余談ですが、70 バイトのタイマー用メモリ以外の水色に塗ったリニア データメモリ部分は、 主に、タイマー用メモリを扱う上でのワークエリアとして使用しています。
1件分 7 バイトの内、先頭バイトは タイマー制御バイト と呼び、まず、先頭の f ビット(メモリ有効フラグ) = 1 の場合には、その1メモリ単位(7バイト)に書かれているデータ内容すべてが 有効(使用中)であることを示しています。 逆に、f ビット(メモリ有効フラグ) = 0 の場合には、例え他のビットやバイトにデータ内容が残っていても、その1メモリ単位(7バイト)は無効(空き)であることを示し、 他のデータ内容で上書をしても構わないことを意味しています。 本機のタイマー機能の指定には2種類の形態があり、t ビット(タイマー種類フラグ) = 0 の場合には 年タイマー を表し、"年、月、日、時、分" を指定します。 この年タイマーでは監視機能によるアラーム音の通知後はそのタイマー情報は不要になるため、 タイマーメモリから自動的に消去されます。 一方、t ビット(タイマー種類フラグ) = 1 の場合には 週間タイマー を表し、"曜日、時、分" を指定します。 この場合にはタイマーメモリから自動的に消去されることがないため、後述の消去機能によってユーザが手動で消去をしない限り、 いつまでもタイマーメモリ内に残り続け、毎週同時刻になるとアラーム音の通知を行います。 なお、曜日に '00' を指定した場合には、曜日には関係なく毎日指定をしたことになり、毎日同時刻になるとアラーム音の通知を行います。 また、本機においては時間指定のときに、24H / 12H のどちらの時間表示の形式で指定しても構いません。 その別を aa ビット(24H/12H フラグ)で表しています。 タイマー制御バイトの次以降の各バイトは、実際にユーザによって入力された、タイマー情報を格納しておくための各カウンタバイトで、"年4桁"、"月2桁"、"日2桁"、"時2桁"、"分2桁" の各 BCD データ形式で扱われます。 なお、週間タイマーの場合には "年4桁"、"月2桁"、"日2桁" は不要のために使用されず、"日2桁" の位置の下位4ビットが "曜日カウンタ" として使用されます。 そのために、週間タイマーの場合には無駄なメモリが消費されますが、週間タイマーも年タイマーと同一サイズとして扱うことにより、プログラムの簡略化を図っています。 使用した PIC16F1705 には 1K バイトのデータメモリ(汎用レジスタ(GPR))が存在するので、 ふんだんに使用しました。(といっても 70 バイトのみですが ・・・) | プログラムのトップに戻る |
タイマー機能と一口に言っても、この項の 冒頭 でも述べたように大きく分けて、[メモリの設定]、[メモリの読み出しと消去]、[タイマーメモリの監視] の3機能があり、全体としてはかなり大きなプログラム群となっているので、 それらのすべてについてを解説することは簡単にはできません。 したがって、この項ではその内の [タイマーメモリの監視] 機能についてのみを解説します。 次に示すリスト中の timer_memory_monitor サブルーチン で、タイマー用メモリの監視(一致検査)を行っていますが、このサブルーチンが CALL される契機となるのは、次のリストの冒頭にあるように、毎秒ごとの RTC DS3231 から年月日、時分秒を読み出した直後に、まず初めに time_alarm_control サブルーチン が CALL され、そのサブルーチン内で毎分 00 秒を検出したのを契機として、timer_memory_monitor サブルーチンが CALL されます。 その他、time_alarm_control サブルーチン内では、時報音(予報音と正報音)についても、それらを出力するタイミングを検出しています。 そして、実際にアラーム音を出力するのは alarm_sound サブルーチン ですが、下リストの例ではメインルーチン内での、 これらのサブルーチン同士の関係を表しています。 他に、本機がスリープ中においても同様に、時報音やタイマー用メモリの監視を行っていて、SIGNAL スイッチによって "Signal On" の有効に設定されているときには、アラーム音が出力されます。 main : : call clock_rtc_read ;RTC DS3231 から年月日,時分秒を読み出し call time_alarm_control ;時報音、タイマー一致音フラグコントロール : : call alarm_sound ;時報音、タイマー一致音のアラーム出力 : : ;========================================================================== ; 時報音、タイマー一致音フラグコントロール ;========================================================================== ; alm_flg: アラーム音出力フラグ ; bit7: アラーム音出力許可フラグ ; bit3: 時報正報音フラグ ... "ポッ〜〜ン" 音 1 回 ... bcd_ss = h'00' & bcd_mm = h'00' ; bit2: 時報予報音フラグ ... "プッ" 音 3 回 ... bcd_ss >= h'57' & bcd_mm = h'59' ; bit1: タイマー一致音フラグ ... "ピポッピポッ" 音 10 回 ... bcd_ss = h'00' & タイマー条件 ; bit0: タイマー一致音継続中フラグ bcd_ss < h'10' & alm_flg.0 = 1 time_alarm_control btfss alm_flg,7 ;アラーム音出力許可フラグ = 1 か? goto tacon04 ;No movf bcd_ss,W btfss STATUS,Z ;bcd_ss = h'00' か? goto tacon02 ;No movf bcd_mm,W btfss STATUS,Z ;bcd_mm = h'00' か? goto tacon01 ;No ; bcd_ss = h'00' & bcd_mm = h'00' bsf alm_flg,3 ;時報正報音フラグ = 1 ; bcd_ss = h'00' tacon01 movlp high timer_memory_monitor call timer_memory_monitor ;タイマー用メモリの監視(一致検査) movlp high $ btfss STATUS,Z ;一致 か? goto tacon04 ;No bsf alm_flg,1 ;タイマー一致音フラグ = 1 bsf alm_flg,0 ;タイマー一致音継続中フラグ = 1 goto tacon04 tacon02 movlw h'59' subwf bcd_mm,W ;分_BCD カウンタ btfss STATUS,Z ;bcd_mm = h'59' か? goto tacon03 ;No movlw h'57' subwf bcd_ss,W ;秒_BCD カウンタ btfss STATUS,C ;bcd_ss >= h'57' か? goto tacon03 ;No ; bcd_ss >= h'57' & bcd_mm = h'59' bsf alm_flg,2 ;時報予報音フラグ = 1 goto tacon04 tacon03 btfss alm_flg,0 ;タイマー一致音継続中フラグ = 1 か? goto tacon04 ;No ; alm_flg.0 = 1 movlw h'10' subwf bcd_ss,W ;秒_BCD カウンタ btfss STATUS,C ;bcd_ss < h'10' か? bsf alm_flg,1 ;Yes. タイマー一致音フラグ = 1 btfsc STATUS,C ;bcd_ss >= h'10' か? bcf alm_flg,0 ;Yes. タイマー一致音継続中フラグ = 0 tacon04 return ;========================================================================== ; 時報音、タイマー一致音のアラーム出力 ;========================================================================== ; 出力の優先順位: タイマー一致音 > 時報予報音 > 時報正報音 ; 同時に複数のフラグ = 1 の場合は、優先順位の低いものは無視される alarm_sound ; btfss alm_flg,7 ;アラーム音出力許可フラグ = 1 か? ; goto alarm04 ;(このフラグ = 0 のときは、 ;3つのフラグ = 1 になることはない) movlw h'0e' andwf alm_flg,W btfsc STATUS,Z ;どれかアラームフラグ = 1 か? goto alarm04 ;No btfss alm_flg,1 ;タイマー一致音フラグ = 1 か? goto alarm01 ;No call buzzer_pipo2 ;"ピポッピポッ" アラーム音出力 (520 mS) goto alarm03 alarm01 btfss alm_flg,2 ;時報予報音フラグ = ON か? goto alarm02 ;No call buzzer_pu ;"プッ" アラーム音出力 (100 mS) goto alarm03 alarm02 ; btfss alm_flg,3 ;時報正報音フラグ = ON か? ; goto alarm03 ;No call buzzer_poon ;"ポッ〜〜ン" アラーム音出力 (1000 mS) bcf PORTC,_BZ ;ブザー出力ビットを "L" にしておく alarm03 movlw h'81' andwf alm_flg,F ;アラーム音フラグをクリア alarm04 return : : : ;========================================================================== ; タイマー用メモリの監視(一致検査) ;========================================================================== timer_memory_monitor movlw high timer_memory ;タイマー用メモリの先頭アドレス movwf FSR1H ; movlw low timer_memory ; movwf FSR1L ; movlw timer_capacity ;タイマー用メモリの記憶容量の最大値 movwf lpcnt ;ループカウンタ1 tmmon01 btfss INDF1,7 ;タイマー用メモリの f bit = 1 (有効) か? goto tmmon08 ;No btfsc INDF1,0 ;タイマー種類 = 1:週間タイマー か? goto tmmon03 ;Yes ; 2 バイト目 〜 5 バイト目の一致チェック tmmon02 moviw 1[FSR1] ;2 バイト目 subwf bcd_yh,W ;年(上位2桁)_BCD カウンタ btfsc STATUS,Z ;bcd_yh = 1[FSR1] か? goto $ + 4 ;Yes btfss STATUS,C ;bcd_yh > 1[FSR1] か? goto tmmon08 ;No goto tmmon05 ;Yes moviw 2[FSR1] ;3 バイト目 subwf bcd_yl,W ;年(下位2桁)_BCD カウンタ btfsc STATUS,Z ;bcd_yl = 2[FSR1] か? goto $ + 4 ;Yes btfss STATUS,C ;bcd_yl > 2[FSR1] か? goto tmmon08 ;No goto tmmon05 ;Yes moviw 3[FSR1] ;4 バイト目 subwf bcd_nn,W ;月_BCD カウンタ btfsc STATUS,Z ;bcd_nn = 3[FSR1] か? goto $ + 4 ;Yes btfss STATUS,C ;bcd_nn > 3[FSR1] か? goto tmmon08 ;No goto tmmon05 ;Yes moviw 4[FSR1] ;5 バイト目 subwf bcd_dd,W ;日_BCD カウンタ btfsc STATUS,Z ;bcd_dd = 4[FSR1] か? goto tmmon04 ;Yes btfss STATUS,C ;bcd_dd > 4[FSR1] か? goto tmmon08 ;No goto tmmon05 ;Yes tmmon03 moviw 4[FSR1] ;5 バイト目 btfsc STATUS,Z ;4[FSR1] = h'00':"Eday" か? goto tmmon04 ;Yes subwf bcd_ww,W ;曜日_BCD カウンタ btfss STATUS,Z ;bcd_ww = 4[FSR1] か? goto tmmon08 ;No ; 6 バイト目、7 バイト目の一致チェック tmmon04 moviw 5[FSR1] ;6 バイト目 subwf bcd_hh,W ;時_BCD カウンタ btfsc STATUS,Z ;bcd_hh = 5[FSR1] か? goto $ + 4 ;Yes btfss STATUS,C ;bcd_hh > 5[FSR1] か? goto tmmon08 ;No goto tmmon05 ;Yes moviw 6[FSR1] ;7 バイト目 subwf bcd_mm,W ;分_BCD カウンタ btfsc STATUS,Z ;bcd_mm = 6[FSR1] か? goto tmmon06 ;Yes btfss STATUS,C ;bcd_mm > 6[FSR1] か? goto tmmon08 ;No ; (過去のもの) tmmon05 btfsc INDF1,0 ;タイマー種類 = 1:週間タイマー か? goto tmmon08 ;Yes clrf INDF1 ;タイマー用メモリの自動消去 movf FSR1H,W ;退避 movwf addr_high ; movf FSR1L,W ; movwf addr_low ; call yflash_mem_erase_write ;フラッシュメモリの消去とデータ書き込み movf addr_high,W ; movwf FSR1H ; movf addr_low,W ; movwf FSR1L ;復帰 goto tmmon08 ; 一致あり tmmon06 btfsc INDF1,0 ;タイマー種類 = 1:週間タイマー か? goto tmmon07 ;Yes clrf INDF1 ;タイマー用メモリの自動消去 call yflash_mem_erase_write ;フラッシュメモリの消去とデータ書き込み tmmon07 bsf STATUS,Z ;Z フラグ = 1、一致あり goto tmmon09 ; 一致なし tmmon08 addfsr FSR1,7 ;間接アドレス + 7 更新 decfsz lpcnt,F ;ループカウンタ1 - 1 = 0 か? goto tmmon01 ;No bcf STATUS,Z ;Z フラグ = 0、一致なし tmmon09 return 一方、f ビット = 1 の場合には、そのメモリ単位データは有効(使用中)なので、第2バイト以降に格納されている各タイマー情報と現在の情報とが比較検査されますが、本機のタイマー種類には、年タイマーと週間タイマーの2種類があって、 先頭バイト(タイマー制御バイト)内の、t ビット(タイマー種類フラグ)によってどちらかに振り分けられ、それぞれのタイマー種類で比較対象となるバイト位置が異なります。 年タイマーの場合には、まず、第2バイトから第5バイトまでに位置する、"年4桁、月2桁、日2桁" の各 BCD データ4バイトが比較対象となりますが、週間タイマーの場合には、第2バイトから第4バイトまではダミーバイトで使用されず、 第5バイトの下位4ビットが "曜日カウンタ" として比較対象となります。 そして、それぞれの種類で比較一致した場合には、次に、第6バイトと第7バイトに位置する、"時2桁、分2桁" の各 BCD データ2バイトが比較されます。 このように、順にタイマー用メモリ上の各 BCD データが比較されて、すべての BCD データが一致した場合にのみ、 Z フラグ = 1 にセットして当サブルーチンを終了します。 それ以外では不一致なので次のメモリ単位データに移って、f ビット(メモリ有効フラグ)の検査から繰り返しますが、すべてのメモリ単位データで不一致の場合には、Z フラグ = 0 にセットして終了します。 ここで、第6バイト目の "時2桁" について補足をしておくと、本機の [メモリの設定] 機能では "時" の入力設定時に、24H / 12H のどちらの時間表示形式でも入力が可能で、その情報を先頭バイト(タイマー制御バイト)内の、aa ビット(24H/12H フラグ)で 管理をしています。 しかし、これは [メモリの読み出しと消去] 機能で表示確認をさせたときに、入力設定時の表示形式と互換を取るための表示用に使用されますが、第6バイト目の "時2桁" そのものは、常に 24H 形式で登録がされます。 なお、年タイマーで登録されているメモリ単位データは、比較一致を検出した以降ではそのタイマー情報は不要になるため、タイマー用メモリからプログラムで消去をしています。 また、[メモリの設定] 機能で、年タイマーで現在時刻よりも過去の情報を入力した場合には、 一旦はタイマー用メモリに登録されますが、この [タイマーメモリの監視] 機能が実行された時点で、同様にプログラムが消去をしています。 このように、タイマー用メモリの内容に変更が加わった場合には、バックアップ用のフラッシュメモリも更新がされます。 ( 2025/5/17 追記 ) 上述したように、timer_memory_monitor サブルーチンが実行されるのは、SIGNAL スイッチによって "Signal On" の状態に設定されているときに、time_alarm_control サブルーチン内で毎分 00 秒を検出したのを契機とするため、 "Signal Off" の状態に設定されているときには、timer_memory_monitor サブルーチンは実行されません。 したがって、この "Signal Off" 状態のときには上で述べた、年タイマーで現在時刻よりも過去の情報を入力した場合の自動消去も行われません。 上に示した緑色リストは既に修正版に差し替えてありますが、この自動消去をさせる機能に少しばかりの不具合がありました。 消去をする過去の対象データが1件だけのときは良いのですが、複数件あった場合には、1件目だけは消去されますが2件目以降が消去されない ― という事象です。 上の timer_memory_monitor リスト中、(過去のもの)のコメント以下の部分を修正しました。 < (1) 修正前 > ; (過去のもの) tmmon05 btfsc INDF1,0 ;タイマー種類 = 1:週間タイマー か? goto tmmon08 ;Yes clrf INDF1 ;タイマー用メモリの自動消去 call yflash_mem_erase_write ;フラッシュメモリの消去とデータ書き込み goto tmmon08 < (2) 修正後 > ; (過去のもの) tmmon05 btfsc INDF1,0 ;タイマー種類 = 1:週間タイマー か? goto tmmon08 ;Yes clrf INDF1 ;タイマー用メモリの自動消去 movf FSR1H,W ;退避 movwf addr_high ; movf FSR1L,W ; movwf addr_low ; call yflash_mem_erase_write ;フラッシュメモリの消去とデータ書き込み movf addr_high,W ; movwf FSR1H ; movf addr_low,W ; movwf FSR1L ;復帰 goto tmmon08timer_memory_monitor サブルーチンが実行されて、このように自動消去でタイマー用メモリの内容に変更が起こったような場合には、そのデータのバックアップである High-Endurance フラッシュメモリの内容も、yflash_mem_erase_write サブルーチンが新データに書き換えています。 < (1) 修正前 > の timer_memory_monitor サブルーチン内では FSR1 レジスタを使用していますが、そのサブルーチン内から CALL される、yflash_mem_erase_write サブルーチン(実際には flash_mem_write サブルーチン)内でも、同じ FSR1 レジスタが別目的で使用されていたため、flash_mem_write サブルーチンから RETURN したときにはその内容が壊されてしまい、過去の対象データが複数件あった場合には、正しい FSR1 レジスタのデータを引き継ぐことができなかったための事象でした。 そこで < (2) 修正後 > のように、yflash_mem_erase_write サブルーチンを CALL する前後で、FSR1 レジスタの退避、復帰を行うように改めました。 | プログラムのトップに戻る |
| ページトップ | |
使用したプリント基板は、前作( 万年カレンダー II )で使用したものと同様で、メインとなる下図 左側のプリント基板 は、"秋月電子" の "片面ガラスコンポジット・ユニバーサル基板 Bタイプ
めっき仕上げ(95 x 72 mm)日本製 型番: AE-B2-CEM3(販売コード 103230)" ですが、後述の ケース加工図 で示したケース内に収めるためには、
プリント基板の切断等の加工が必要です。 左図に示すように、まず基板下部の ----- X 線の位置で切断をします。 そして、この切断によって失われた基板下部の取り付け用穴の代理となる、新たなΦ3.2 の穴を図のように2か所開けます。 次に、基板右端に位置するスイッチ用基板の取り付けのために用いる、 ジュラコンスペーサ用のΦ3.2 の穴を2か所開けます。
次に 右側のプリント基板 は、"秋月電子" の "片面ガラス・ユニバーサル基板 Cタイプ(72 x 47.5 mm)めっき仕上げ(販売コード 100517)" で、左側メイン基板の右端に取り付けるスイッチ用基板になるもので、 他にコネクタ用の小基板2枚も切り出します。 私は前作( 万年カレンダー II )で使用した残りの基板を使用しました。 | プリント基板部品配置図 (PerpetualCalendarIIIPC0.CE3) | (PerpetualCalendarIII2PC0.CE3) | ページトップ | |
メイン基板に多くのパーツを搭載するにあたっては、それぞれに対して以降に述べるような注意事項があるので、基板を組み立てる上での参考にしてください。
なお、図の中で、細長い長方形の中に ○で表したものはピンヘッダ(オス)を、同様に◎で表したものはピンソケット(メス)を使用することを表しているので、注意をしてください。
・DS3231 RTC モジュール プリント基板の左上角に位置する縦長の四角状のものが DS3231 RTC モジュールで、本機では リアルタイムクロック( DS3231 )モジュール の項で説明をした改造が必要になります。 具体的な改造方法はそちらの項で詳述しているので参考にしてください。 ・TP4056 充電モジュール プリント基板の左下に位置する "TP4056 充電モジュール" の取り付けについては、まず、縦横4か所の各青色線で示す位置の、メイン基板のハンダ面側から 0.4 〜 0.5 mm の錫メッキ線等を通し、モジュール基板上面側で各青色線の対となるもう片方の穴へグルっとUターンをして、 再び、メイン基板のハンダ面側に通した後はんだ付けをします。 このとき、モジュール基板側は 2.54 mm ピッチではないため注意が必要ですが、メイン基板側の穴位置は、前項 プリント基板の加工と部品配置 で示した縦横4か所の各青色線で示したランド穴位置を選択すれば問題はないでしょう。 次に、モジュール基板左側の斜2か所の青色線で示すモジュール基板側の穴に対応するメイン基板側の位置には、ランド穴が開いていないのでこの位置にΦ1 程度の穴を開ける必要があり * ます。 穴を開けた後、前の縦横4か所のときと同要領で斜2か所についても、錫メッキ線等でモジュール基板の固定をします。 ただし、前の縦横4か所についてはその後、メイン基板のハンダ面側で回路の配線が必要になりますが、この斜2か所については回路の配線はありません。
・OLED モジュール プリント基板の上部中央には、本機の目玉である OLED モジュールが位置します。 メイン基板側にはあらかじめ 4P のピンソケットを取り付けておき、OLED モジュール側のピンヘッダと嵌合させます。 このとき、ピンソケットには分割ピンソケットを使用するとその加工が楽になります。 ・トグルスイッチ プリント基板下部中央に位置する POWER スイッチには、3P(1回路)のトグルスイッチで良いのですが、3P でレバーが短いタイプが私の持ち合わせになく、6P(2回路)のものがあったので私は代わりにそれを使用しました。 したがって、3P でレバーが短いタイプを入手した場合には、基板パターン図を 3P(1回路)用に変更をしてください。 本機では ケース加工図 で示したケース(内寸高さ 24 mm)を使用したため、レバーが通常のタイプは不可で、短いタイプでないとケース内に収めることができません。 通常、本機のように時計関連の製作物には POWER スイッチ等は設けない場合が多いのですが、本機の場合には、18650 リチウムイオン電池を充電する場合には、TP4056 充電モジュールの負荷接続端子を開放しておく必要があるために、その目的でスイッチを設置しました。 ・タクトスイッチ用基板との接続コネクタ プリント基板の右端縦長の位置に、タクトスイッチ用基板を取り付けますが、この基板の取り付けには、後述の ケースへのプリント基板の取り付け で説明しているように、私の場合には手持ちの関係で、 13 mm 長のオネジ+メネジの六角ジュラコンスペーサ(廣杉計器 BS-313W)を使用しました。 そして、電気的な接続には、下の プリント基板(2)パターン図 (部品面) (ハンダ面) の項で示した、タクトスイッチ用基板のケーブルコネクタ( 7P ピンソケット(メス))と、メイン基板上に設けた 7P L型ピンヘッダとを、常時接続をさせておきます。 なお、メイン基板側のピンヘッダは、パターン図や写真のように L型でないと接続ができません。 ・その他 プリント基板左下の 3P のピンヘッダ B+ と B- 端子には、本機の電源である 18650 リチウムイオン電池を、電池ホルダからの配線( 3P ピンソケット(メス))を介して接続させます。 電気的には 2P で良いのですが、 2P 状態よりも 3P の方が、しっかりとコネクタ接続ができるために 3P としました。 そのため、真ん中のピンには配線はしていません。 | プリント基板(1)パターン図 (部品面) (PerpetualCalendarIIIPC.CE3) | 左図から黒色文字を除いた図 (PerpetualCalendarIIIPC2.CE3) | ページトップ | |
前項 プリント基板(1)パターン図 (部品面) でも述べたように、下パターン図や写真は、トグルスイッチに 3P(1回路)ではなく 6P(2回路)を使用したものなので、3P(1回路)トグルスイッチを使用した場合には、
スイッチ周りのパターンを適宜変更をしてください。
| プリント基板(1)パターン図 (ハンダ面) (PerpetualCalendarIIIPC1.CE3) | ページトップ | |
本機では、タクトスイッチをプリント基板(2) に取り付けるときには、スイッチの底面を基板にぴったり押し付けて取り付けることが必要です。 (詳細は、後述の ケースへのプリント基板の取り付け の項を参照してください。) |
![]() |
![]() |
| プリント基板(2)パターン図 (部品面) (PerpetualCalendarIII2PC.CE3) | ページトップ |
![]() |
![]() |
| プリント基板(2)パターン図 (ハンダ面) (PerpetualCalendarIII2PC1.CE3) | ページトップ |
本機のケースも、前作( 万年カレンダー II )で使用したものとまったく同じもので、"秋月電子" の "ABS樹脂ケース(蝶番式・中)112−TS ニシムラ (販売コード: 100277)" を使用しました。
外側(内側)寸法が 117 (112) x 84 (80) x 28 (24) mm で、可動式のフタが付いています。
上図の(上面図)及び(左側面図)において、各丸穴の位置寸法を記入* はしてありますが、参考程度に見ておいてください。 実際に穴開けを行う場合には、プリント基板を仮に取り付けた後、ケースが透明で中が透けて見えているので、 現物合わせで丸穴の中心位置を千枚通し等で印を付けて位置決めを行った方が、穴開けがうまくいくと思います。 ただし、(下面図)におけるプリント基板の取り付け用の穴位置は、極力、正確な位置に穴開けを行うように心掛けてください。
上図の(下面図)はケースの裏面側から見た図で、上部の大きな点線の四角部分(72 x 89 mm)がメイン基板の取り付け位置です。 私がプリント基板をケース等に取り付ける場合、通常、両者の間には 5 mm 長のスペーサを挟んで 取り付けることが多いのですが、本機のメイン基板には 5 mm 長のスペーサを使用することができません。 上の プリント基板(1)パターン図 (部品面) の項で、使用した トグルスイッチ について述べたように、本機ではレバーが短いタイプを使用していますが、メイン基板を上図のケース内に納めるためには 5 mm 長のスペーサでは長過ぎて、 上蓋が閉まらなくなってしまいます。 そこで本機では M3 のナットをスペーサ代わり、としました。 ウィルコ で購入したナットで、 "鉄(ニッケルめっき) 六角ナット・1種 FNT-03N" の厚さ 2.4 mm のものです。 ケースの裏面側(外側)の4か所から、それぞれ M3 x 10 サイズのビス(+なべ小ねじ)を通し、ケース内側でスペーサ代わりの M3 ナット → メイン基板 → ポリカーボネート平ワッシャー → M3 ナット、の順に取り付けます。 ポリカーボネート平ワッシャーは、プリント基板表面の傷つき防止とねじ緩み防止を兼ねて挿入をしてあります。(ねじ類の型番等については、使用部品表 を参照のこと) ・電池ホルダーの取り付け 同様に上図の(下面図)で、下部の横に細長い点線の四角部分に、18650 リチウムイオン電池用の電池ホルダーを取り付けます。 私が使用した電池ホルダー、およびその取り付けるときの注意点、方法などについては、 別ページ "198. MP3プレーヤー I" の 電池ホルダーをケースに取り付け を参考にしてください。 | ケース加工図 (PerpetualCalendarIIICS.CE3) | ページトップ | |
下図は本機ケースの右側面側から上部半分ほどを見た図で、2枚のプリント基板やタクトスイッチの取り付けの様子がよく分かるように、右側面を切り取った断面図で表しています。 ケースへのメイン基板の取り付けに当たって、最も重要なのはその上下(高さ)位置で、重複しますが上述した メイン基板の取り付け のように、本機ではトグルスイッチ搭載のために M3 のナットをスペーサ代わりとして使用しています。 そして、前項で述べたケースを使用する限り、この状態が最もベストな上下(高さ)位置で変更することはできません。 また、同図に示すように本機では、スイッチ用プリント基板に取り付けたタクトスイッチのトップが、ケース上面から適度な長さ(X)を飛び出すようにしなければなりません。 そのために、タクトスイッチには手持ちにあった通常のものより少々長い、 スイッチ底面からトップまでの長さが 9.5mm のものを使用し、スイッチ用基板をメイン基板に取り付けるのに、これも手持ちの関係で右写真のような、M3 x 13 mm 長のオネジ+メネジの六角ジュラコンスペーサ(廣杉計器 BS-313W)を使用しました。
余談ですが、タクトスイッチをプリント基板に取り付ける場合に、私は通常、スイッチを基板穴に軽く押し込んだときに、足ピンがくの字に曲がったあたりで進入が止まった位置、すなわち、スイッチ底面が少し基板上面から浮いた位置でハンダ付けをすることが多いのですが、 今回は上図のように、スイッチ底面が基板上面に付くまでスイッチを押し込んで使用しました。 これは使用したタクトスイッチとスペーサの各長さによって X 値を調節するためで、ちなみに図の組み合わせでは X ≒ 2 mm ほどになりました。 | 基板の取り付け図 (pcb_attach.CE3) | ページトップ | |
(主要部品: IC, トランジスタ等) | (データシート) | |||
PICマイコン | .................... | PIC16F1705 | ||
三端子レギュレータ | .................... | S-812C33AY-B-G | ||
有機 EL ディスプレイ(OLED) | .................... | SSD1306 | ||
圧電ブザー | .................... | PKM17EPP-4001 |
| 部品表 | Excel ファイル (PerpetualCalendarIII_parts.xls) | ページトップ |
PIC16F1705 データシート | .......... | https://ww1.microchip.com/downloads/en/DeviceDoc/40001729C.pdf | ||
SSD1306 データシート | .......... | https://akizukidenshi.com/goodsaffix/ssd1306.pdf | ||
174. グラフィック液晶表示 万年カレンダー | .......... | https://xyama.sakura.ne.jp/hp/PerpetualCalendar.html | ||
201. 有機 EL ディスプレイ(OLED) 表示 万年カレンダー II | .......... | https://xyama.sakura.ne.jp/hp/PerpetualCalendarII.html | ||
有機EL (OLED)をPICマイコンで制御 | .......... | https://jr3tgs-homebrew.net/contents/oled_test/oled_test.html |