● 実験テーマ85
「PIC24F+NOKIA5110+HDC1000+LPS25Hで温湿度・気圧表示実験」
(PIC24Fで、HDC1000とLPS25Hを動かし、ノキア液晶に温湿度・気圧の3つの値を表示する実験です)
以下、この実験の顛末記です。
■ 2016.12.24
・この実験の最終目標は、「太田さんのホームページ」にあるような、温湿度・気圧の値と
グラフを液晶に表示することである。
今回の実験はその最初のステップである。
太田さんが使っているセンサは、比較的高価な物(温湿度:SHT-11,
気圧:SCP1000)なので
今まで使ってきた物(HDC1000+LPS25H)に置換えることにする。
また、ノキア液晶のY方向が、48dotしかなく、それを3等分して各16dotを、それぞれのエリア
に割り当てている為、それぞれの表示分解能が、かなり低くなる。
温度:3.1℃/dot, 湿度:6.3%/dot, 気圧:1hPa/dotという具合である。
それでも、気圧をオートレンジ(自動シフト)にするなどの工夫で、長時間(30分)のプロット間隔
の描画写真を拝見すると、それなりに見栄え良く表示している。
あと、スクロールは採用してない。いわゆる心電図方式に似た方法を取られている。
ここら辺も変えてみようと思う。
ノキア液晶でグラフ表示する実験は、目盛りとプロットの関係を把握するため、それぞれの要素
を単独(温度・湿度・気圧)で、48dotをフルに使ったものの実験をし、
その後、温度と湿度の2chのみ分離表示する実験をしてみようと思う。
気圧のオートレンジは難しそうなので、液晶をQVGAに変えて、固定スケーリング表示で
温度・湿度ともに3ch分離表示するもを最終的には目指したい。
あと、全て履歴グラフ表示(スクロール式)にしてみようと思っている。
なんて、色々とやりたいことを書いてきたが、実は、余り自信はありません。
それでもチャレンジということで、最低、それぞれの要素を単独(温度・湿度・気圧)で、
48dotをフルに使ったものの実験と、温度と湿度の2chのみ分離表示する実験までは
やってみたいと考えてます。(とにかく出来るところまでやってみよう・・・)
■ 2016.12.27
・PIC24Fで、I2Cを使うには、I2C2の方を使う。
I2C1にはバグがある。
以前のI2C液晶実験でも、I2C2を使った。
あと、Fcy=4MHzでの、I2Cスピード:100kになるI2C2BRGレジスタの値を
設定する必要がある。以前は、Fcy=16MHzでの設定値であった。
ここは、後閑さんのハンドブックの計算表があったので、それを参考にしてみた。
sprintf文を使うので、その設定も必要である。
これは、stdio.hをインクルードするだけで良さそうである。
前に使った、I2Cライブラリは、液晶専用なので、リード関数がない。
PIC24FのI2C記述を考慮して、追加修正しないといけない。
各センサのライブラリも、PIC16F用のものしか無いので、これをPIC24Fに移植し
ないといけない。
これが、ソース作成の主な作業となりそう。
■ 2016.12.29
・一応、ソースは出来た。
早速、コンパイルするもエラー及びワーニング発生。(エラーを無くし、HEX書込み後の動作もおかしい)
以下に、その対処の模様を列記してみた。
@ 以下のグローバル変数は、ライブラリ・ヘッダファイルで宣言されていたが、
メインに、HDC_Read()と、PressureRead()を移動し参照しているため、
メイン頭でも、そのヘッダファイルをインクルードしていた。その為、
2重定義エラー(リンクエラー)になるので、メイン頭に移動した。(ヘッダファイルのそれは削除した)
float Humi ; // 湿度の値を保存する変数
float Temp ; // 温度の値を保存する変数
float Press ; // 大気圧の値を保存する変数
以下は、2重定義エラーが出たときの、IDEの、スナップ・ショットです。
A PIC24Fのデータ型:floatと、doubleは、どちらも32bit浮動小数であるが、doubleにしないと
warningが出るので修正した。ただし動作には関係なかった。
double Humi ; // 湿度の値を保存する変数
double Temp ; // 温度の値を保存する変数
double Press ; // 大気圧の値を保存する変数
<ワーニングメッセージ>
B これでコンパイルは通ったが、HEX書込むも動作がおかしい。
イニシャルメッセージ後の、HDC1000初期化のどこかでループしているようで、先に進まない。
初期化成功・失敗判定後の、"Init OK"
or "Init NG"メッセージが出ない。
HDC_Recive関数中の、I2C_Stop()の中でループしているようだ。
I2C_Stop()冒頭の、Idle_I2C()をコメントアウトすると先に進むが、"Init
NG"になる。(当然)
Idle_I2C()は、I2Cバスがアイドル状態になるのを待つ関数だが、その5つの条件(TRSAT,
RCEN等)
の内の何かが、リセットされなく、ループしていると思われる。
これは、HDC_Receive関数中の、リスタート発行後、下請け関数の、I2C_Recive関数で、
アイドル状態を確認後、何故か勘違いで、もう一回スタートコンディションを発行してから、レジスタ値
を受信していたのが原因だった。(2バイトデータなので、このミスは2ヶ所ということになる。)
これで先に進んだが、"Init NG"になっている。
さらに、I2C_Start関数と、I2C_rStart関数の、スレーブアドレス送出前にも、Idle_I2C()を追加したら、
ようやく"Init OK"になって、測定値が液晶に表示されたが、気圧はよさそうなのだが、温湿度が
おかしい。それぞれ、125℃, 100%になっている。
■ 2016.12.30
・温度レジスタ値を、sprintf文を使って、液晶下段に表示してみた。
やはり思惑通り、0xFFFFになっていた。
データシートにある計算式:温度値=(温度レジスタ値/65536)
x 165℃ - 40℃ で計算すると、125℃になる。
■ 2016.12.31
・気になる、I2Cスピードだが、100kHzになっているか中華オシロで確認してみた。
久しぶりに中華オシロの電源を入れたら、液晶の中央付近のドットが綺麗に欠けていた。
遂にガタが来たか。まあ使えない訳ではないので暫くはこのまま使うことにした。
下の写真のように、100kHzでなく、中途半端に、約147kHzになっていた。
それに、波形が鈍っている。これは、センサモジュールのpull
up=10kをそのまま使っているためで
今迄の経験上、5kΩ位に落とさないと鈍りは取れないはずだが、動作には問題ないと思われる
ので、そのまま行くことにした。
・I2C2BRG = 0x13; // 100kHz@Fcy= 4MHz→ これでやると実測Fslk= 147kと合わない。
後閑さんのソース例で、Fcy=16Mの場合、Fclk=100k の設定値は、I2C1BRG= 9E= 158 であった。
ところが後閑さんのハンドブックの計算式に当てはめて計算すると、
Fclk=Fcy/(2*(I2C2BRG+1)= 50.314Kで合わない??(0x13という値はこの表にあったもの)
WEB検索でのI2C2BRGを求める式で計算すると、(Fcy/Fscl-FCY/10E6)-1=(16E6/100E3-16E6/10E6)-1=157.4
になってほぼ合う。後閑さんの計算式と、I2C1BRGの計算結果例の表にある値は、誤記と思われる。
そこで、この式で、100kHzの設定値を計算すると、
I2C2BRG = 0x27; // (Fcy/Fscl-Fcy/10E6)-1=(4E6/100E3-4E6/10E6)-1=38.6=39
になる。
この値に修正して、確認するも、何故か、"Init
NG"になってしまう。0x13だとok?
中華オシロで見ると、確かに100kHzになっているが・・・
■ 2017.1.1
・HDC1000の初期化で止まっている("Init
NG")ようなので、この時の、I2Cタイミングを、自作ロジアナ
で確認してみた。
(この時、LPS25H初期化ルーチンはコメントアウトし、HDC1000のみのタイミングが見られるようにした。)
初期化のチェックでは、レジスタ・アドレス:0xFFに格納されている、デバイスIDを読出し、
読出したIDが、0x1000であるかを確認する。
正常な、I2Cタイミングであれば、読出しまで、以下の5つのフレーム処理で読出しが完了する。
@ スタートビット+スレーブアドレス+Wビット送出
A レジスタ・アドレス(0xFF)送出
⓷ リスタートビット+スレーブアドレス+Rビット送出
C スレーブより、バス上に、ID上位バイト(0x10)が送られてくるので受信後、ACKビット送出
D スレーブより、バス上に、ID下位バイト(0x00)が送られてくるので受信後、NACKビット+STOPビット送出
ところが、見たところ、4つのフレーム処理で終了してしまっている。
どうも、Cの、リスタートコンディション発行が無視され、直ぐに、0xFFが、2回読出されているようである。
また、Aの時の、0xFFが割れているのが気になる。
調べると、リスタート発行関数:I2C_rStart()で、リスタート発行後の、リードモードで、スレーブアドレスを
送信する前の、エネーブルビットのクリア待ちが、.SENに対してのものになっていた。
これを、.RENに対してのものに修正したら、Fscl= 100kHzでも、初期化に成功し、"Init
OK"なったが
まだ、表示は、125.00℃のままである。
以下に、修正後の、HDC1000初期化までの、I2Cタイミング実測を示す。
しかし温度レジスタを読出すとこが、未だ駄目なようだ。
■ 2017.1.2
・相変わらず、気圧以外の、温湿度表示が、飽和値を示してる。
色々調査してる内に、なんとか、温湿度表示も正常な値を示すようになった。
上手く行かなかった、大きな理由は、2つだった。
@ I2C_Send()
PIC24Fの場合、I2C2TRN= dt; //
送信バッファに、データをセット
の後、while(I2C2STATbits.TBF); // 送信終了待ち
が必要であったが、これが抜けていた。(この辺、PIC16Fとは違うところ)
A HDC1000の、変換終了待ちを、delay_ms設定値で行っているが、7mSでは駄目で、10mSにしたら
動き出した。
スペック的には、14bit分解能で使った場合で、6.5mStyp(max値の記載なし)であるが、センサによって
バラツキがあるようだ。
・動きが良くなったところで、温湿度レジスタの読出し値を液晶に表示してみた。
以下のように、今度は、計算した値になっている。
また、HDC1000初期化後の、湿度レジスタ読出しフレーム(上の写真を取った後のものなので、写真のデータとは異なる)
の実測タイミングを以下に示した。
その時のフレームのみを取れるように、1CHにトリガ用の100uSの同期パルスを入れて取った。
・温湿度も良くなったので、ここらで、修正コメントで汚れたソースを整理して、気圧とともに、3つの値
を表示するようにまとめた。
動作の模様は、このページ・トップの、写真を参照してください。
■ 2017.1.3
・2つだけ気になることが残っていたので、それをやることに。
1つは、HDC1000の変換時間の実測である。
今は、7mSだと駄目で、10mSにしてOKになったので、待ちは余裕を持って10mSとしてある。
これを細かく見てみたら、8mSだとOKなことが判った。
なので、7.5mS近辺と思われる。
2つ目は、温度表示で、マイナスになった場合、'-'を表示してくれるか?だ。
液晶への書式制御に、sprintf文を使っているが、フロート数値がマイナスになった場合、'-'
のアスキー文字を出力してくれるか確認してみた。
実際に、マイナス温度にするためには、本体を冷蔵庫に入れたりして試すしかないが、液晶の
コントラストが濃くなって見えなくなる可能性があるので、強制的に、-20.00℃になる変換値を計算式から
逆算してその値で表示してみることにした。
その値とは、0x1F08(10進で7944)になる。
ちゃんと、'-'を表示してくれることを確認した。
・次回からは、これのグラフ化の為の実験を幾つかやって行く予定だが、どうなることやら・・
<最終回路図>
・こちらから、どうぞ→ 「PIC24F_気圧・温湿度センサ実験」 (PIC24Fトレーニング基板による実験回路です。)
<最終ソース及びヘッダファイル>
・こちらから、どうぞ→ 「GraphicalTmpHumPres_Test_1.c」 (温湿度・気圧値表示テスト・メインソース)
※ 以下のライブラリは、「きむ茶工房」さんの、XC8コンパイラ用のライブラリを基に、C30用のライブラリ用に
改修したものです。(頭の'sk'の文字はオリジナルにあるもので残しました。)
/// I2Cライブラリ
「skI2C_PIC24F_lib.c」
「skI2C_PIC24F_lib.h」
/// HDC1000ライブラリ
「skHDC_PIC24F.c」
「skHDC_PIC24F.h」
///
LPS25Hライブラリ
「skLPS25H_PIC24F.c」
「skLPC25H_PIC24F.h」
※ この他に、以下の液晶ライブラリと、フォントライブラリが必要です。
nokiaGlcdlib.c
nokiaGlcdlib.h
ASCII_font.h