HOME > 技術談話 > PIC® microcontroller > 気圧センサとテキスト表示LCDでグラフ描画(冒険)
はじめに こんな感じ ハードウェア サンプルプログラム 主な仕様 LCDの表示手法
情報の流れ フローチャート ステート制御
動かしてみた 海面校正 時間のズレ まとめ
前回「気圧センサとテキスト表示LCD」を解説しました。このバージョンでは数字表示なんですよね。 気圧変動の傾向がわからない。 利用したLCDはフォントをダウンロードできるので、これを利用して気圧変動をグラフ化できないかと考えました。 そこで少しだけ冒険。テキスト表示LCDを利用してグラフ描画するサンプルプログラムを作ってみました。 相変わらず進捗は遅いかも…。そのような場合は「つぶやき」をチェックしてみてください。 途中経過やホームページの更新タイミングで何かしら独り言をつぶやいてます。 注意事項 SCP1000-D01はVTIテクノロジー社の製品です。 本文中では「テキスト表示可能なLCD」を単に「LCD」と略しています。 |
▲ |
前宣伝と同じ画像で恐縮ですが、基本画面を以下に。 |
上段に気圧と温度を表示します。 下段に気圧の変動を示すグラフを簡易描画します。 過去42件を保持し、常に右端が直近の情報です。 縦1列で2件分の情報を表現しています。 気圧の変動範囲が8ドットを超えると自動縮小します。 |
自動縮小…オートレンジです。 下段のグラフの左に縦棒がありますが、これは「1」を示します。1ドットが 1hPa に相当します。気圧の変動が大きくなり縦8ドットの領域に表現できない場合は1ドットあたりの単位量を変動しますが、同時に左にある数字も変化します(1~5)。 たまたま気圧変動量が少なくなるタイミングがあったので、その前後の状態を撮影してみました。 過去データの更新とグラフ描画は1時間周期で行います。左画面の左端の記録データが押し出された際に過去データ全体の情報を確認して縦8ドットに収まるように再描画します。左が 1dot=2hPa 、右が 1dot=1hPa です。 |
1ドットあたりの単位量が小さくなるとグラフ描画が少しだけ詳細に見えます。 根本的にドット数が少なくて表現力に欠けるのですが、気圧の変化傾向を把握できるかと思います。 見た目はわかりにくいですが…、縦方向の中央にグラフ描画するように縦位置も補正してます。 |
▲ |
前回の「気圧センサとテキスト表示LCD」と同一の回路構成です。 |
▲ |
簡易グラフ描画機能のサンプルプログラムを公開します → PresTx0221.zip 開発環境は MPLAB IDE V8.40 と HI-TECH C V9.70 を利用しています(開発環境の準備)。 2010.11.17 Ver02.21 TX端子を入力設定にする件。見た目の変化はバージョン番号のみです。 HI-TECH C v9.70 で作成されたプログラムを v9.81 以降のコンパイラで再コンパイルする際の注意点 → 開発環境による修正 2011/03/09 |
前回のプログラム構成と以下の点で異なります。 ・スイッチ機能無し ・通信機能無し ・メニュー選択機能無し コンパイラがLite版なのでプログラム容量が増大してます。プログラム作成当初はオーバーフローの嵐。 何とか押し込むために、泣く泣く補助機能を削除しました(約97%使用、残り116ワード)。 今回使用したPICマイコンは PIC16F648A(4Kワード)ですが、PIC16F886(8Kワード)を利用すると余裕のあるプログラムが作成できるかと思います。この辺りは各自のアレンジで。 タイトルに併記していますが、あくまでも「冒険」バージョンなので、このあたりは御容赦願います。 |
▲ |
サンプルプログラムの主な仕様は以下の通りです。 |
項目 | 機能 | 内容 | |
テキスト表示 | 更新周期 | 1秒周期(時間精度はPICマイコン内蔵クロックに依存) | |
気圧表示 | 1hPa単位、900hPa~1155hPa | ||
温度表示 | 1℃単位、-20℃~+70℃ | ||
海面校正 | 簡易校正(プログラム埋め込み型) | ||
グラフ表示 | 更新周期 | 1時間周期 | |
表示画素数 | 縦8dot、横21dot | ||
表示件数 | 42件相当、2件を縦1列に同時表現する方式(詳細は後述) | ||
縦方向分解能 | 1hPa~5hPa、相対位置表示方式、分解能レベル数表示 | ||
表示補正 | オートレンジ、縦方向センター合わせ、更新周期で実施 | ||
その他 | 保持間隔 | 1時間周期 | |
保持件数 | 42件 … 2日に6時間足りない件数、表示の都合による | ||
バックアップ | 無し | ||
LCD再設定 | 1時間周期(グラフ描画と同じタイミング、一瞬の消去を伴う) |
▲ |
(1)好きな形を表示する LCDの機能によりますが、LCD内蔵のCGRAMへデータを登録して任意の文字(形)を表示することができます 今回使用したLCDでは8種の文字(形)を登録し、コード0x00~0x07を指定することで表示することができます。 文字(形)の大きさは縦8dot、横5dotです。登録イメージを以下に示します。 |
英字の「G」を例にデザインしてみました。 LCDに対して登録するコードとデータをインストラクションレジスタに対して書き込みます。 データはLSB合わせ、上から順番にCGRAMに登録します。 今回の例では、 0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0F, 0x00 です。 インストラクションレジスタへのアクセス方法についてはLCDのデータシートを確認願います。 |
(2)グラフを描いてみる… グラフを文字(形)として登録すれば、8種の情報を同時表示することができます。 横5dotなので8文字で都合40dotの情報を表示できるなと…。 |
少々違和感が… |
文字と文字の間に隙間があるんですよね。連続したグラフ描画に隙間が空くのは、ちょっと変。 隙間の中にデータがあるのか、無いのかが微妙です。心の目ではデータがあるように見えてしまいます。 間違いではないけど、隙間が見えるのはなぁ。斜め線はともかく、水平の線は目立つだろうな、この隙間。 横5dotというのは数えやすいけど、時間の世界(60進法、24進法)では半端があるし…。 どうしたものだろう? |
(3)見えないドット LCDのデータシートをじーっと眺めて「ティン」ときました。実は見えないドットが存在します。 |
黒く表示される画素の大きさと文字と文字の隙間の大きさが似ています。 |
文字と文字の隙間も 1dot とし、1文字分の領域を横 3dot として描画すると横の隙間が気にならなくなるのでは? |
間引かれる事で、それっぽく見える感じ |
結構いい感じです。離れて見るものだし、なんてったって「冒険」です。これで行きましょう。 1文字相当が3件分。2倍で6件分。時間との相性が良い感じです。 |
(4)横軸の表現量 表示を間引いて「見栄え」は良くなりましたが、横軸の情報量が半減してしまいました。 個人的趣味からすると過去2日分程度は表示したいところです。都合48件分。対して表示は 24dot 分。 さて…。 単純に横 1dot に2件の情報を重ねて、線として表現してみてはどうでしょう? 疑似的な「斜め線」の意味合いもありますが、描画してみるとこんな感じです。 |
値として、 +1, +1, +2, +3, +4, +6 の6件の情報を仮定します。 2件単位でデータを扱います。 縦列内では情報同士を接続します。 なんとなく元情報を想像できますね。 |
なんとなく、いい感じです。 けど難点が一つ。縦列内での時間経過が見えません。どういうことかというと… |
少し意地悪な解釈ですが、 ・左側:単純上昇 ・右側:上昇+下降+上昇 時間経過が見えないので解釈が複数あります。 |
気圧変動の傾向から考えると上図の例では左側の解釈がしっくりきます。 このあたりは「心の目で見て補完する」ということで。 これで過去48時間相当の領域を確保することができました(最終的には42時間相当になってます)。 |
(5)縦軸の表現量 台風が来ると2日間で 20hPa 以上変動することは過去の記録より判明しています。 そのため、縦軸の 8dot の制限下で 1dot = 1hPa では表示ができなくなることは明らかです。 さて、どのように表現するか… |
表現方法としてはいくつかありますが、 ・左側:捨てる ・右側:最上位、最下位の位置で丸めこむ どちらもしっくりきません。 グラフから変動傾向を察することが困難です。 |
そこで、過去データの最大値と最小値が縦 8dot に収まるように、1dot あたりの重みづけを切り替えます。 オシロスコープでいうところの電圧レンジ切り替えの様な機能でしょうか。 |
重みづけを切り替えてみました。 左側: 1dot = 1hPa 右側: 1dot = 2hPa この方法の方がしっくりきます。 少なくとも表示データが正しく見えます。 |
今回のサンプルプログラムでは、1dot = 1hPa ~ 5hPa までを自動的に判別し切り替えます。言い換えると、一度に表示できるのは8hPa~40hPaの範囲 になります。 40hPa を超える場合は…恐らく大惨事です。表示を見ている暇はありません。直ちに避難して下さい(これ重要)。 ここで注意しなければならないのは、縦位置に対するドットと値の割り付けです。常に一番下のドットが 1000hPa であるという様な「決め」はできません。どのような値が得られても、気圧変動傾向を縦 8dot の中に収めたいと思います。 これを実現するために「縦位置の中央ぞろえ」を行います。過去データをすべてチェックし、そのデータが縦 8dot の中央に配置されるように上下の隙間を調整します。 前述のデータ例であれば以下のようになります。 |
隙間を二分した際に生じる端数は上側に配置します(プログラムの動作結果として…確かそのはず)。 以上の事から、縦 8dot の一番下(#7、+0の位置)に来るドットの気圧はグラフ描画の度に変化します。 |
(6)その他 グラフ描画時に自動的に重みづけを切り替える「オートレンジ機能」を設けましたが、現在表示しているグラフの重みづけがわからないことには気圧の変動傾向を把握することができません。変動が数値として大きい?小さい? 全部で5種類の重みづけ…。表示する場所がない orz 止むをえません。グラフ描画を行う左端に重みを表示することにします。 |
単なる縦棒のように見えますが、数字の「1」です。 ドットあたりの重みづけを 1~5 で表示します。 うーん。1文字分取られてしまった。残念です。 |
以上のことからグラフ描画可能な領域が7文字相当に制限され、結果的に42件までのデータを取り扱います。 |
▲ |
サンプルプログラムでは大きく分けて3つの処理が(見かけ上)同時動作しています。 |
処理 | 概要 | |
測定データ取得 | 気圧センサからの通知により測定済みデータを取得。 | |
1秒表示更新 | 取得済みデータを分解能を補正してテキスト表示。 | |
1時間表示更新 | 過去データの状況を判断してグラフ描画。 |
この3つの処理における情報の流れを簡単にまとめると以下のようになります。 |
この中で面倒なのはグラフ描画の前段階である「ベースラインの決定」でしょうか。 海面校正は実数演算と温度補正を行えばより正確な値を求める事ができますが、今回は簡易計算です。 実際に動作させて気になるのは温度表示が微妙に動くこと。小数点以下第1位で四捨五入していますが、温度が境界点でフラフラすると数字として反映されてしまいます。気圧表示は別として、温度表示に関してはヒステリシスを設けた方が安定した数値を得る事が出来ると思います。 |
▲ |
お決まりの優しくない概略フローチャートです。 基本的な流れは前回のプログラムと同様ですが、メニュー切り替え機能を削除したので、簡易グラフ描画処理への直接分岐を行っています。前回のプログラムに存在したスイッチ機能、通信機能は大人の都合で削除しました。 |
簡易グラフ描画部分の概略フローチャートです。いわゆるステートマシーンっていう動作手法です。 |
▲ |
簡易グラフ描画処理はステップ番号を元に、呼び出される度に専用の処理に分岐します。 各ステップ毎の処理時間は 20ms 以内に完了するように調整しています。 |
ステップ | 概要 | 次ステップ | 処理時間 | |
0 | 初期設定 | 1 | 7ms | |
1 | 秒:時間監視 | 1, 2, 3 | 1ms | |
2 | 秒:LCD初期設定 | 3 | 5ms | |
3 | 秒:測定データ取得 | 4 | 1ms | |
4 | 秒:平均登録 | 5 | 3ms | |
5 | 秒:平均演算 | 6 | 2ms | |
6 | 秒:測定結果表示 | 7 | 7ms | |
7 | (予約) | 8 | - | |
8 | 時間:時間監視 | 9, 23 | 1ms | |
9 | 時間:範囲確認 | 10 | 4ms | |
10 | 時間:外字登録1 | 11 | 4ms | |
11 | 時間:外字登録2-1 | 12 | 10ms | |
12 | 時間:外字登録2-2 | 13 | 10ms | |
13 | 時間:外字登録2-3 | 14 | 10ms | |
14 | 時間:外字登録2-4 | 15 | 10ms | |
15 | 時間:外字登録2-5 | 16 | 10ms | |
16 | 時間:外字登録2-6 | 17 | 10ms | |
17 | 時間:外字登録2-7 | 18 | 10ms | |
18 | 時間:グラフ表示 | 19 | 4ms | |
19 | (予約) | 20 | - | |
20 | (予約) | 21 | - | |
21 | (予約) | 22 | - | |
22 | (予約) | 23 | - | |
23 | 制御単位終了 | 1 | - |
表中の処理時間は概算値です。 見直すと…いくつかのステップは統合することも可能でした。統合すれば別な処理もできるのですが…。 こればかりは作ってみないとわからないのです、作るたびに処理時間を見極める経験値は養われると思います。 ちなみに。機能が分割されているとデバッグが比較的容易です。この辺りの「さじ加減」は経験あるのみです。 処理時間 20ms のさじ加減は…。 メイン処理は 40ms 周期巡回です。非同期で処理される気圧センサからのデータ取得と処理時間を折半しています。 ざっと計算したところでは、基準処理時間に対して最悪でも 50% 以下の負荷になります。 処理時間的には論理崩壊していませんが…プログラム容量は厳しい状態です orz |
▲ |
気象台の測定値とグラフ描画を比較してみました。比較対象は冒頭のサンプル画像です(分解能1hPa)。 比較対象は近所の前橋気象台(約15km北東)です。以下に当時の前橋気象台の海面気圧を載せます。 |
日時 | 気圧 | 日時 | 気圧 | 日時 | 気圧 | 日時 | 気圧 | |||||
7/10 03:00 | 1005.8 | 7/10 15:00 | 1007.2 | 7/11 03:00 | 1011.6 | 7/11 15:00 | 1010.6 | |||||
7/10 04:00 | 1007.0 | 7/10 16:00 | 1007.1 | 7/11 04:00 | 1012.3 | 7/11 16:00 | 1010.3 | |||||
7/10 05:00 | 1007.4 | 7/10 17:00 | 1008.0 | 7/11 05:00 | 1012.1 | 7/11 17:00 | 1009.4 | |||||
7/10 06:00 | 1007.5 | 7/10 18:00 | 1008.9 | 7/11 06:00 | 1012.2 | 7/11 18:00 | 1009.3 | |||||
7/10 07:00 | 1008.1 | 7/10 19:00 | 1009.6 | 7/11 07:00 | 1012.0 | 7/11 19:00 | 1008.9 | |||||
7/10 08:00 | 1008.3 | 7/10 20:00 | 1011.0 | 7/11 08:00 | 1012.3 | 7/11 20:00 | 1008.8 | |||||
7/10 09:00 | 1008.0 | 7/10 21:00 | 1011.6 | 7/11 09:00 | 1012.6 | |||||||
7/10 10:00 | 1008.1 | 7/10 22:00 | 1011.6 | 7/11 10:00 | 1012.3 | |||||||
7/10 11:00 | 1007.8 | 7/10 23:00 | 1012.1 | 7/11 11:00 | 1011.9 | |||||||
7/10 12:00 | 1007.3 | 7/10 24:00 | 1012.4 | 7/11 12:00 | 1011.2 | |||||||
7/10 13:00 | 1006.9 | 7/11 01:00 | 1011.8 | 7/11 13:00 | 1010.9 | |||||||
7/10 14:00 | 1007.0 | 7/11 02:00 | 1011.7 | 7/11 14:00 | 1010.8 |
上図は前橋気象台の値を表計算ソフトでグラフ描画しました。下図はサンプルプログラムでの表示内容です。 |
サンプルプログラムは分解能 1hPa で表示していますが、気持ちとしては小数点以下が欲しいですね(笑 サンプルプログラム側は厳密に校正しているわけではないので値の信頼性は落ちますが、相対的な動きは上手い具合に追従していると思います。 |
後述しますが、表示している数値は現地高度(群馬県高崎市)を利用し、簡易計算で海面校正しています。 |
▲ |
サンプルプログラムでは簡易な海面校正機能を持ちます。 サンプルプログラムでは現地高度を 0m として扱っているので、現地高度(m)を指定してリビルドしてください。 修正方法は「user.c」の「USER_HEIGHT」で高度(m)を指定します。 |
変更の際に「#if 0」を「#if 1」に変更するのを忘れないでください。 現在お住まいの高度を調べる場合は、国土地理院のページが便利です。 → 地図閲覧サービス(ウォッちず) 御近所の測量点を探し、等高線を数えると現地高度を求める事ができます。 → 等高線の見方 投げっぱなし(汗 サンプルプログラムでは 1hPa = 9.0m を利用した簡易校正なので正確さに劣りますが、近い値に収束します。 今回のサンプルプログラムでは取り扱う値が 1hPa 単位なので細かいことは気にしないことにします。 海面校正についてはこちらのページも便利です。 → カシオ計算機株式会社様 当該ページで演算式を見る事ができますが…。PICマイコンでは非常に厳しい演算です orz |
▲ |
今回のサンプルプログラムは源発振に内蔵クロック(4MHz)を利用しています。 PIC16F648Aのデータシートを見ると内蔵クロックの誤差は約2%です。この値は電源電圧、温度によって変動します。 仮に-2%の誤差とした場合、実時間 60分 に対して 58分48秒、計算上は 1分12秒 足りないことになります。この誤差は解消せず累積していく点に注意が必要です。 今回使用したPIC16F648Aはキャリブレーションされた状態で出荷されるとはいえ、内蔵クロックを利用した場合は精度が甘いので時計として利用するには無理があります。 参考 → 発振子の精度 厳密に1秒、1時間を管理する場合は水晶発振子、もしくはRTC(リアルタイムクロック)を外付けする様な回路構成を検討願います。この状態でも誤差は ppm 単位で生じるので定期的な修正等、運用面の工夫も必要です。 ただ…。 今回のサンプルプログラムの様に過去42件(42時間)の傾向を見るならば内蔵クロックでも十分と考えます。 まぁ、42時間で最悪1時間近くずれているわけですが(汗 参考までに、今回利用したハードウェア構成での実績は、42時間で11分30秒短い状態でした。 誤差0.46%程度になりますが、出荷時に設定されたキャリブレーション値が上手く効いている様です。 ただし、個体差はあるので別のPICマイコンを利用した場合は別の値が得られるので過信は禁物です。 |
▲ |
テキスト表示しかできないLCDの割には上手くグラフが描画できたと思います。本当に冒険バージョンです。 さて、実際にサンプルプログラムを利用して動作させた方は気がつくと思うのですが、グラフ描画のタイミングで画面消去が行われます。これは何らかの要因でLCDが誤動作した場合を考慮しての救済措置です。 ブレッドボードで実験すると再現は容易です。運用中に信号線を抜き差しするだけでLCDに表示される文字が化けると思います。これはLCDとの接続が 4bit であることも問題が起きやすい要因の1つになっています。 電源オンで測定し、直ちに電源をオフする装置であれば文字化けしても電源を入れなおすだけで問題は解消されますが、過去データを取り扱う装置では文字化けした場合の電源オフ操作は鬼門です。 情報がバックアップされているなら良いのですが、今回のサンプルプログラムのように揮発性のメモリに情報を蓄積していく場合は電源オフで情報は総て消失します。これは非常に残念な動作です。 バックアップを検討する方法もありますが、今回は定期的にLCDを初期設定することで問題からの復帰を行っています。文字化けした場合は1時間待って下さい。正しい表示に戻ると思います。 ソフト屋さんが施す「ささやかな気遣い」ということで。。 注意: これを1分単位で行うと邪魔に感じますので頻度には御注意を。差し障りのないシーンで適用して下さい。 ちなみに、前回のプログラムでは「メニュー」画面に戻るタイミングで実施しています。 |
▲ |