PIC16F84Aを用いた連結型時計(Cascade Clock)の製作
はじめに
私が電子工作を始めた頃、電子工作界隈では丁度PICマイコンが流行っていた。
私も例に漏れず、少ない小遣いをかき集めてPIC16F84Aを買い漁り、C言語を習得していろいろなものを作ったわけだが、勢い余って買い集めすぎたあまり、使いきれなかった在庫が2022年10月時点で4個余っていた。
PIC16F84Aよりもはるかに性能がいいマイコンが山ほど出ているため、普段は全くと言っていいほど使い道がなく、何年も持て余していた代物であった。
これらをまとめて使い切るアイデアとして、1桁の時刻表示と設定スイッチを持つ桁ユニットを4個並べて連結することで動作する時計「Cascade Clock」を考案し制作したので、その機能・動作・設計思想を本記事で紹介したい。
制作物の紹介
今回制作したものとその動作を、下のツイートにある動画にまとめた。
動画冒頭のようにユニット同士を接続することで各ユニットが自分の桁数を認識し、0:12でスイッチを押すことで桁設定を完了している。設定した桁を数字で2秒間表示し、その後自動的に時計動作に移行しhhmm表示で時刻を表示する。時計動作時は、桁ごとに、タクトスイッチのクリックによる表示のカウントアップと、長押しによる桁リセットをすることで、任意のタイミングで時刻設定をすることができる。
また、動画0:54~0:59のように時計動作中にユニット同士の接続を切っても、1:21~1:31のように再接続して再度桁設定を行うことで、再び時計として動作させることも可能だ。このとき、動画1:00~1:20のように、桁ユニットの並び順を変更しても、左からhhmm表示の時計として動作するように設計した。
制作目標・目標仕様
今回の大目標はズバリ、「PIC16F84Aをたくさん使う製作物を作る」ことである。
その目標を達成するための手段として、今回「デジタル時計」を選んだ。
その時計は、以下のような機能(仕様)を持つ時計であり、これを実現することを今回の制作の目標とした。
- 1桁の7セグLEDと1個タクトスイッチを1ユニットとする。
- ユニット4個を左右一列に連結することで、左から「時時分分(hhmm)」で時刻を表示する。
- 各ユニットの7セグLEDは、現在時刻の、自ユニットが該当する桁を表示し、タクトスイッチは自ユニットの時刻設定に用いる。
- ユニット の接続により自桁がどの桁かを自動認識する。また、動作中に接続を切って桁を入れ替えても、再接続することで時計として再度動作させられる。
- すべてのユニットは、同一のハードウェア、同一のソフトウェアで動作させる。
- 1ユニット当たりの電源は電池1個とする。
- 1ユニットの制御に用いる素子は1個のPIC16F84Aを用いる。
設計思想・動作説明
本章では、前章で述べたような動作をどのように実現させたのかを紹介したい。
以下では、ハードウェア・ソフトウェアそれぞれについて、セクションを分けて説明する。
ハードウェア
ここでは、ユニットのハードウェア構成、および、実際の回路や基板を紹介する。
PIC16F84Aのピンアサイン
目標仕様の達成ために以下のハードウェア構成を考案した。
(PIC16F84Aデータシートより抜粋)
このハードウェア構成に必要なデバイスと、各デバイスの制御に必要な端子数は以下の通りである。
デバイス | 必要なピン数 | I/O | 機能・内訳など |
---|---|---|---|
7セグLED | 8 | O | 数値表示。A~Gのセグメント + 小数点制御 |
タクトスイッチ | 1 | I | モード設定・時刻設定用。要専用入力端子 |
STATUS LED | 1 | O | 状態確認用。デバッグに使用 |
前桁入力 | 3 | I | モード設定、桁上がり信号受信用 |
次桁出力 | 3 | O | モード設定、桁上がり信号送信用 |
合計 | 16 | - | 必要なI/Oポート端子数 |
これらのデバイスに必要なピンを1つ1つ割り当てていきたいところだが、PIC16F84Aでは不可能である。なぜなら、PIC16F84AのI/Oポートは、下図のようにPORTA(RA0~RA5の5本)とPORTB(RB0~RB7の8本)の合計13本しかないためである。これでは必要I/O数が3本足りないため、いずれかのピンを共用にする必要がある。(STATUS LEDを廃止しても2本不足のため、どのみち共用は必要である)
(PIC16F84Aのデータシートより抜粋)
この問題を解決するために、7セグLEDの制御端子と次桁出力を共用にすることを検討した。
アノードコモンの7セグLEDを用いた場合、各数字の点灯時の出力パターンは以下の表のようになる。
表示する数字 | a | b | c | d | e | f | g |
---|---|---|---|---|---|---|---|
0 | L | L | L | L | L | L | H |
1 | H | L | L | H | H | H | H |
2 | L | L | H | L | L | H | L |
3 | L | L | L | L | H | H | L |
4 | H | L | L | H | H | L | L |
5 | L | H | L | L | H | L | L |
6 | L | H | L | L | L | L | L |
7 | L | L | L | H | H | H | H |
8 | L | L | L | L | L | L | L |
9 | L | L | L | L | H | L | L |
消灯 | H | H | H | H | H | H | H |
(アノードコモンのため、H=消灯、L=点灯であることに注意)
これらのうち、a,b,cの出力パターンに着目したとき、以下の表のようにどの数字でも使われていない出力パターン(太字)が4つ存在することがわかる。
a | b | c | 使用回数 | 表示する数字 |
---|---|---|---|---|
L | L | L | 5 | 0, 3, 7, 8, 9の表示 |
H | L | L | 5 | 1,4の表示 |
L | H | L | 1 | 5,6の表示 |
H | H | L | 0 | なし |
L | L | H | 1 | 2の表示 |
H | L | H | 0 | なし |
L | H | H | 0 | なし |
H | H | H | 0 | なし |
このため、時計として動作しているとき、前桁の制御信号を受け取った際にこの太字のパターンの信号のみを制御信号として処理すれば、前桁の数字表示の切替による誤動作は起きえない。後述するが、時計動作時の制御信号は2種類で足りるため、7セグLEDのa,b,cの制御ピンと、次桁出力ピンを共用することができる。これによって使用するI/Oポートを16-3=13本にすることができ、PIC16F84Aでもギリギリ扱える本数となった。
また、ピンアサインの考慮で重要なのが、入力ピンの配置である。入力ピンとして使用する4本のI/Oが、時刻設定用のタクトスイッチと前桁からの制御信号入力であることから割り込みが使えたほうが都合がよいと判断した。PIC16F84Aの割り込みピンは、INT割り込みピン(RB0)とPORTB割り込みピン(RB4~7)があり、いずれもPORTBであるため、これらをすべてPORTBに配置した。さらに、PORTBにのみ、WPU(Week Pull Up)機能を備えており、スイッチ入力やオープン(無接続)での使用が想定される、今回のような用途にとても便利である。この点からも、入力端子はすべてPORTBに割り当てることで、ハードウェアの簡略化の面でもメリットは大きいと考えた。
PORTA(RA0~4)はいずれも出力として使用できる。一応、RA4の出力はオープンドレイン出力であることに注意が必要だが、今回はアノードコモン出力の7セグLEDを用いるため問題にならない。
最終的に、配線の引きまわしやすさ等も考慮して以下のようにI/Oピンを割り当てた。
ポート | I/O | 用途 |
---|---|---|
RA0 | O | 7セグLED: DP |
RA1 | O | 7セグLED: D |
RA2 | O | 7セグLED: F |
RA3 | O | 7セグLED: G |
RA4 | O | 7セグLED: E |
RB0 | I | タクトスイッチ入力 |
RB1 | O | 7セグLED: A, 次桁出力 (OUT0) |
RB2 | O | 7セグLED: C, 次桁出力 (OUT1) |
RB3 | O | 7セグLED: B, 次桁出力 (OUT2) |
RB4 | O | STATUS LED |
RB5 | I | 前桁入力 (IN0) |
RB6 | I | 前桁入力 (IN1) |
RB7 | I | 前桁入力 (IN2) |
電源
電源は、本機が複数のユニットを入れ替えて接続する、というコンセプトであることから、以下の条件を満たすものがよいと考えた。
- 各ユニットが独立した電源を持つ。
- ACアダプタ等は使用せずバッテリー駆動とする (コードが絡まるため)
- 1ユニットあたりに使用する電池の個数は1個とする (コストを抑えるため)
PIC16F84Aの電源電圧として最低2V必要であるため、乾電池1本(1.5V)では動作は難しい。電池だけで動作させることを考えると、LiPoバッテリー(3.6V)を使うのが最適解であるが、筆者はLiPoバッテリーを扱った経験がなくノウハウが全くないため、今回は不採用とした。
最終的に、HOLTEK社のPFM式ステップアップDC/DCコンバーターであるHT7733Aを用いて、乾電池1個を昇圧して3.3Vを供給する方式を採用した。回路構成はデータシートの回路構成をそのまま使用した。
(HT77XXA共通データシートより抜粋)
回路図
上記を踏まえ、下図のような回路図にした。大きく分けて、電池+DC/DCコンバータで構成される電源部分(上半分)と、スイッチ・7セグLED・PIC16F84Aで構成されるメイン部分(下半分)に分けられる。なるべく部品点数を減らしたかったのもあり、かなりシンプルな回路構成となった。
実際に制作した基板
全体像は以下のようになっている。
基板上部にある1桁の7セグLEDで、自機の担当する桁の表示を行い、画面中央にあるタクトスイッチで、その表示値を設定する。また、基板左右についているのはL型のピンヘッダ/ピンソケットで、これでユニット同士を接続することができる。これらを接続し制御するのが、中央にあるPIC16F84Aである。さらに、基板下部にはボタン電池ホルダー(LR44用)とDC/DCコンバータを配置しており、これによって電池1個で3.3Vを供給し、PICマイコンを動かせるようにしている。(動作テスト時、ボタン電池では出力電流が不足することが明らかになったため最終的には使用していない)
ソフトウェア
ここでは、PIC16F84Aに書き込んだプログラムのアルゴリズムを説明し、実際にどのように動作しているのかを説明する。
全体動作
遷移する状態は以下の通りである。
-
- 初期設定:入出力ピン、タイマー、割り込みの設定
-
- 動作モード設定:前桁・次桁との接続状態から自ユニットが何桁目かを検知し、時計動作時の動作モードを決定する。
-
- 時計動作:動作モード設定で設定した動作モードに従い、時計として動作する。
また、1.動作モード設定と2.時計動作の間を状態遷移するには、以下の条件を満たす必要がある。
- 1→2:末桁(分1の位)の場合、タクトスイッチが押される。
それ以外の桁の場合、前桁からの完了信号を受け取る。 - 2→1:末桁(分1の位)の場合、前桁入力の状態が変化する。
それ以外の場合、前桁入力端子がすべてオープンになる。
これらについての詳細を以下セクションで説明する。
各状態での動作
本セクションでは、各モードにおいてユニット同士を接続したときにどのような動作をしているのかを説明する。
状態0:初期設定
この状態では、電源オンによる起動直後に自ユニットのI/Oピン、TMR0の設定、割り込み設定を行う。
I/Oピンの設定については、ハードウェアの節で説明した通りである。TMR0は、PIC16F84Aに内臓するインターバルタイマであり、8msごとにTMR0割り込みが発生するように設定している。また、割り込み設定は、INT割り込み、TMR0割り込み、PORTB割り込み(入力ピンに設定したRB4~7の状態変化をトリガとする割り込み)を有効にしている。
状態1:動作モード設定
この状態では、自ユニットがどの桁にいるのかを認識し、時計動作に移行する際の動作モードを決定する。実際に行う処理は、以下のような処理である。
-
IN2 = Hのとき、OUT2=Hを出力を維持した状態でIN0を1ビット目、IN1を2ビット目とした2進数を読み込み、自機のモードを認識して変数modeに格納する。
例えば、IN0=L, IN1=Hの場合、自機のモード=10(2進数)=2(10進数)となり、mode=2を格納する。 -
1.で格納したmodeから1引いた数を、OUT0を1ビット目、 OUT1を2ビット目とした2進数を次桁出力に出力する。
1.で上げた例の場合、mode-1 = 2-1 = 1となるため、OUT0 =H, OUT1=Lを出力する。 -
以下のイベントのいずれかが発生するまで、1,2を繰り返す。
(a) 自ユニットがmode=3で、かつ、タクトスイッチが押されたとき
(b) 自ユニットがmode=3以外で、かつ、IN0=Lを検出したとき -
(a)または(b)を検出したら、検出した時点でのmodeを保持し、動作モード設定を完了し、OUT2=Hを出力する。(次桁に3(b)のイベントを発生させるため)
状態2: 時計動作時
この状態では、1.の動作モード設定で設定した変数modeに従って、実際に時計として動作する。
1.で設定した変数modeにより、自ユニットのカウントアップ方法と時刻設定の可否が下表のように設定できる。
mode | 動作モード | カウントアップ方法 | 時刻設定 |
---|---|---|---|
3 | 分1の位 (10進カウンタ) | 毎分自動(TMR0割り込みで生成) | あり |
2 | 分10の位 (6進カウンタ) | 前桁からの制御信号 | あり |
1 | 時1の位 (24進カウンタ1桁目) | 前桁からの制御信号 | あり |
0 | 時10の位 (10進カウンタ2桁目) | 前桁からの制御信号 | なし(前桁から連動) |
表中の時刻設定については、対応する桁の時刻をタクトスイッチによって設定できるかを示している。mode=0 (時10の位)以外はタクトスイッチのクリックで表示する数字をカウントアップし、タクトの長押しで0にリセットできるようにしている。mode=0 (時10の位)では、タクトスイッチは使用できないが、前桁の時刻設定に連動して時刻設定ができる。
また、カウントアップ方法は、対応するmodeのユニットが、何をトリガーとしてカウントアップするかを示している。分1の位として動作するmode=3では、TMR0割り込みによって1分を生成することでカウントアップし、それ以外の桁では前桁からの制御信号によってカウントアップする。(下図)
この制御信号は、ハードウェアの節でも説明した通り、7セグの点灯に使用しない出力パターンを制御信号として使用している。次節で説明する切断検知を含め、下表の4個の信号で行っている。
OUT2 (7セグb) | OUT1 (7セグc) | OUT0 (7セグa) | OUT0-2 | 次桁への制御信号 |
---|---|---|---|---|
L | H | H | 3 | 予約(未使用) |
H | L | H | 5 | 表示カウントアップ |
H | H | L | 6 | 表示クリア (0にする) |
H | H | H | 7 | 切断検知 |
状態2.→状態1. 切断検知
状態遷移条件である切断検知は、下図のように、前桁入力の状態が変わることで切断を検知し、状態1の動作モード設定に移行する。切断と判定する基準は動作モードによって異なる。
- 分1の位 (mode = 3) 以外:前桁入力の状態がIN0 = IN1 = IN2 = H、つまり、IN=111(2進数) = 7(10進数) になったとき。つまり、前桁との接続が切れたとき。
- 分1の位 (mode=3):前桁入力の状態がIN0, IN1, IN2のどれかがLになったとき。つまり、もともと接続されていなかった前桁が、組み換えによって新たに接続されたとき。
このような判定にしているのは、前桁入力端子をPORTBのWPU機能により、Openの場合でも常時プルアップしているため、未接続状態の判定としてIN0=IN1=IN2=Hとなるためである。mode=3では、時計動作時には前桁入力に何も接続されておらず、IN0=IN1=IN2=Hとなっているのがデフォルトであるため、前桁入力にほかの桁が接続されたときに動作モード設定に移行する、という方法をとった。
実験:連続測定
これまで説明してきたような設計、検証、動作テストは、数分~数十分程度の動作のみで行っていたため、時計として不可欠な要素である、「長時間動作」と「精度」が考慮に入っていない設計であった。このため、プログラムを大方完成させたあとに、すべてのユニットの電池を新品により変えたうえで、以下のツイートのように簡易的な連続動作テストを行った。
結果としては、
- 約6時間後:表示が暗くなる (周囲が明るいと数字が読みづらい)。
また、誤差が3分出ており、時計としての精度も低い。 - 約2日後:ユニットによってはほぼ表示が見えなくなるが、全ユニットが動作していることを確認済み。
誤差は記録していないが、執筆当時の筆者の記憶では30分程度。
となり、長時間の連続稼働に対し、電池の持ちが悪いことと、時刻の精度が悪いことが課題となった。
ハードウェアの再設計を含め、これらの点を今後の課題としてフィードバックしていきたい。
まとめ
本記事では、PIC16F84Aを用いた、ユニット連結によって動作させるデジタル時計を制作した。
最後に、達成事項と今後の課題をまとめる。
達成できたこと
1.PIC16F84Aをたくさん使う制作物として、桁ユニット同士を連結することで初めて動作するデジタル時計を制作した。(大目標の達成)
2.上記デジタル時計を、同じハードウェア・ソフトウェアで動作できるようにできた。
今後の課題
1.長時間稼働させたとき、電池の消耗が激しくすぐに電池切れになること。
2.表示する時刻の精度が悪いこと。
投稿者の人気記事
-
4558D
さんが
2022/12/18
に
編集
をしました。
(メッセージ: 初版)
-
4558D
さんが
2022/12/18
に
編集
をしました。
ログインしてコメントを投稿する