今回はある程度実用的な卓上時計を作ってみました。日時の表示と温度、湿度、気圧の表示だけのシンプルな機能としました。
主な使用部品
例のごとくほとんどの部品は秋月電子で購入しました。LCD だけ aitendo で購入しています。
そのほか抵抗やコンデンサ、スイッチやソケット等の細かい部品は省略しますが、総額で2560円ほどでした。
センサーが1080円とちょっと高いですが、時計機能だけであれば1000円ちょっとになると思います。
また、電源は単3充電池2本としました。(詳しくは後述しますが USB給電にすればよかったと後悔しております。)
各部品の使い方等は別の記事にまとめてあるので、必要に応じてそちらも参照してください。
回路解説
プログラムの解説の前にまず簡単に回路の解説をしたいと思います。回路図はこんな感じです。
電源部
回路図左上が電源部です。電源は単3充電池2本で、それをDCDCコンバータで5Vに昇圧しています。
ただし、センサーの電源電圧は1.8 ~ 3.6V なので、電池から直接繋げています。
なお、回路図では3Vと書いていますが、充電池なので本当はもうちょっと小さいです。(実測 2.6V)
RTC
回路図左下に RTC があります。図の通り、水晶発振子を外部で接続する必要があります。
特筆すべき点はバックアップ回路で、主電源から LED を通してコンデンサに貯めてあります。
LED を使用したのはダイオードとしての整流作用に加えて、約2Vの順電圧降下があるため、バックアップ電圧の約3Vを簡単に作れるためです。抵抗はただの電流制限用です。
電池交換の間もバックアップされるので時間を正しく保持してくれますが、電池を抜いたまま置いておくとこの回路構成だと1日も持たずにバックアップ電源が切れてしまうので、長時間バックアップしたい場合は素直にリチウム電池を使用するのが良いと思います。
ちなみに SQW は SQuare Wave の略で1Hzの矩形波を PIC に送っていますが、オープンドレインなので PIC でプルアップしています。
ICSP, RESET
ピン数の制約から、ICSP はスイッチの入力ピンと共用しています。
ただし、スイッチも ICSP も使用していないときはどこにも繋がっていないので特に問題はありません。
図で赤色で示したのがリセット関係の線です。普段は PIC によってプルアップされています。PIC も LCD も Low でリセットがかかるので、LCD の SW4 をリセット線に繋げておけば PIC と一緒に LCD もリセットされます。
ただし、PIC の書き込みの際に MCLR ピンには高電圧がかかるので、SW4 を切り離すことで LCD に高電圧がかからないようにしています。
レベル変換モジュール
PIC と RTC、センサーは I2C で通信していますが、センサーは3V動作なので間にレベル変換モジュールを挟んでいます。
PIC からは直接線がつながっているように見えるので、プログラムも特別なことをする必要はありません。
また、I2C 通信は通信線をプルアップする必要がありますが、このモジュールに3Vと5V側両方のプルアップ抵抗がついているのでそれを利用しています。
フォントの製作、表示
RTC の使い方等は冒頭に示した別の記事で書いているので、ここでは文字の表示機能の説明をしたいと思います。
小文字
まずは日付や気温などの表示に使用している小さい文字について説明します。
各文字はマージンを含めて5×8ドットで構成されています。
例えば、’3’という文字であれば、次のように5byteのフォントデータを用意しています。
文字を表示させるときは先頭のページとコラムを指定して、続けてこの5byte を送信すればよいことになります。
空白も含めて11文字分のフォントデータを const char[] の配列としてソースファイルに直接書き込んでいます。
ちなみに ‘℃’ 等の記号も同様に表示できますが動作中に書き換えることがないので、初期化の際に背景としてあらかじめ表示させておくことにしました。
プログラムはこんな感じです。
1 2 3 4 5 6 7 |
void PrintSmallNum(char num, char mask){ int offset = 5*num; //1文字5byte for(char i=0; i<5; i++){ //1文字5列 Sed_Dat(smallNum[offset + i] ^ mask); } } |
LCDのアドレスの指定は関数の外で行います。
5行目の ^ は XOR のビット演算子で、通常は mask = 0 でそのまま表示しますが、mask = 0xFF とすれば下の写真のように白黒を反転させられます。
大文字
次に時刻の表示に使用している大きな数字について説明します。
これはどちらかというとフォントというより画像をそのまま表示させているというイメージの方が良いかもしれません。
例えば、 ‘8’ の場合は下図左のような 12×24 の画像を用意します。
ただし、LCD の中央に非表示領域が約2ドット分あるので実際には下図右のように表示されます。
24行を8行ずつ3段に分けて、小文字のときと同様に1列1byte として計36byte のデータに変換します。
さすがにこれを手作業でやるのは面倒なので、モノクロBMPファイルからデータを自動で変換するプログラムを書きました。(ついでにカラーBMPからモノクロBMPへの変換機能も付けました。)
需要があるかは不明ですが、一応ダウンロードできるようにしておきました。
プログラムは次のようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 |
void PrintLargeNum(char add, char num, char mask){ int offset = 36*num; //1文字36byte for(char i=0; i<3; i++){ Sed_SetAddress(i, 12*add); //1文字12列 for(char j=0; j<12; j++){ Sed_Dat(largeNum[offset] ^ mask); offset++; } } } |
小文字とは違って、大文字は3段にまたがっているので12回ずつアドレスを指定し直しています。
完成
いつもなら最後にプログラムを丸ごと載せたりするのですが、今回は全部載せるとかなりの量になってしまうので別ページに載せてあります。ソースコードのダウンロードも可能です。
完成品の評価ですが、基板全体もディスプレイも見た目的に程よい密度になっていて気に入っています。
ただし1つ重大な問題が…。
単3充電池2本で動作させていると書きましたが、大体2日しか電池が持ちません…。
PIC のクロックを落としたり気温測定の頻度を減らしたり消費電力を減らす努力はしてみたのですが、そもそも LCD がかなり電力を使用しているようでした。
計画の段階で電力を測定しておくべきでしたね。次の製作への反省とします。
今回の記事は以上となります。最後までご覧いただきありがとうございました。
ニコニコ動画に動画を投稿しておりますので、そちらも再生していただけると嬉しいです。