前回までで温度、湿度のA-D変換された生のディジタル値が読み出せたので、今回はそれらの値を工学値に変換して、温度値(℃)、湿度値(%)としてLCDに表示させるプログラムを説明します。
CCS-Cは高価なだけあってフロート型(実数演算)が使用できるので、簡単に計算のプログラムが作成できますが、WIZ-C(標準版)などでは、フロート型は実装されていません。そこで、16ビットの四則演算だけを使って実数演算相当の処理(SHT11の計算専用)を行う関数を作成しました。
32ビット型の整数演算を使うことができれば比較的簡単に計算できますが、筆者が使っているバージョンのCCS-Cでは、32ビット演算にバグがあるのかうまく計算できないため、CCS-Cで32ビット演算を使うのはあきらめています。WIZ-Cでは32ビット演算がサポートされていますが、サポートされていないコンパイラのことも考慮して16ビットの四則演算だけで計算できるようにしてあります。
(1) 計算の概要
計算のミソjは、桁数の多い数値を因数分解して、掛ける数値を小さくして計算結果が16ビットに納まるようにし、個別に計算した結果ををあとで加算するという方法です。因数分解は中学生の頃の数学で習いましたね。
たとえば、湿度の計算式でA-D変換値の2乗を計算する際の、A-D値が3214の場合を考えます。32142=3214×3214ですが、これを3214×(3000+200+10+4)と考えます。
(3000+200+10+4)から、各桁の四つの数字 "3"、"2"、"1"、"4"を得て、それぞれの値と3214を掛けます。これら個別の計算結果は16ビットに納まっています。下記のように分解した各結果を本来の数値の10のべき乗に応じて、ずらして並べ加算します。なお、グレー部分は3000、200、10、4をそれぞれ3214にストレートに掛け算した時の下位3桁の数値になりますが、この部分は有効数字外として水色の欄のように正規化(百の桁を四捨五入)して考えます。
| 分解して計算 | 四捨五入して正規化 | |||||||||
| 3214×3 = | 9 | 6 | 4 | 2 | 0 | 0 | 0 | 9642×103 | ||
| 3214×2 = | 6 | 4 | 2 | 8 | 0 | 0 | 643×103 | |||
| 3214×1 = | 3 | 2 | 1 | 4 | 0 | 3200×103 | ||||
| 3214×4 = | 1 | 2 | 8 | 5 | 6 | 12×103 | ||||
| +) |
| |||||||||
| 1 | 0 | 3 | 2 | 9 | 7 | 9 | 6 | 10330×103 | ||
この10330×103 を有効数字を4桁に正規化して1033×104とします。湿度の計算ではこの値に2.8×10-6を掛けますが、これを28×10-7として1033×104に掛けると次のようになります。
28×1033×10-3 = 28924×10-3
後の計算で10倍した値として使用するため、10倍した28924×10-2として計算します。小数点以下を四捨五入して次の値が得られます。なお、50を加えて100で割るのは四捨五入するためです。
(28924 + 50) / 100 = 289 (10倍した値)
湿度の計算式の"-4"の項は10倍して"-40"です。"0.0405×(AD値)"の項の計算については説明を省略しますが、2乗のときのような方法で10倍した値を求め、それに"289"と"-40"に加えれば、湿度[%]の10倍した値が整数値で得られます。実際の処理は次のプログラム・リストを参照してください。
(2) 湿度の工学値変換プログラム
ここでは処理を簡単にするために、温度補償なしのリニアライズ(前回掲載の湿度の計算式の計算)だけ行います。変換式を再掲載しておきます。
湿度値 RHlinear = -4 + 0.0405×(AD値) - 2.8×10-6×(AD値)2
各項は10倍して湿度値の10倍した値をもとめます。計算方法などは「(1)計算の概要」を参照してください。実際のプログラムは次のようになります。この関数の戻り値は湿度[%]を10倍した値になります。
WORD CalcHR10(void) {
WORD ad, x1, x2, x3, x4, cd10, b10;// 桁ごとの数値を取り出す
ad = ADValHR;
x1 = ad / 1000;
ad = ad - 1000 * x1;
x2 = ad / 100;
ad = ad - 100 * x2;
x3 = ad / 10;
x4 = ad - 10 * x3;// 桁ごとにA-D値を掛け算する
x1 = ADValHR * x1;
x2 = (ADValHR * x2 + 5) / 10; // 小数点以下四捨五入
x3 = (ADValHR * x3 + 50) / 100; // 小数点以下四捨五入
x4 = (ADValHR * x4 + 500) / 1000; // 小数点以下四捨五入x1 = x1 + x2 + x3 + x4; // 計算結果を合成
x2 = (x1 + 5) / 10; // 1/10する. 小数点以下四捨五入cd10 = (28 * x2 + 50) / 100;
x1 = (ADValHR * 4 + 5) / 10;
x2 = (ADValHR * 5 + 500) / 1000;
b10 = x1 + x2;return -40 + b10 - cd10; // 湿度値を10倍した整数値
}
(3) 温度の工学値変換プログラム
温度の変換は2乗の計算がない単純な比例式ですので処理は簡単です。計算結果は小数点以下第一位まで表示するため、計算結果は10倍したものを求めます。変換式を再掲載します。
温度値 Temperature = -40 + 0.01×(AD値)
温度を10倍した値を求めますが、0.01を整数にするために全項を100倍し、最後に1/10します。関数にするまでもありませんので、マクロで済ませます。項の順序は入れ替えています。
#define CalcTMP10() (ADValTmp- 4000+5)/10; // 温度変換マクロ(10倍値)
ADValTmpはA-D変換されたディジタル値です。+5を加えて10で割っているのは、小数点以下の数値を四捨五入するためです。割り算は整数除算です(余り切り捨て)。
(4) 結果の表示処理
前述の工学値変換した温度値、湿度値の10倍した値を小数点つきで表示するには次のように考えます。
整数部分 = 温度(または湿度)値 / 10 (整数除算)
小数点以下第一位の値 = 温度(または湿度)値 % 10 (剰余)
湿度値の表示処理は次のようになります。工学値変換された湿度値(10倍したもの)は変数"ValHR10"に入っているものとします。なお、"%"を単なる文字として表示させたい場合は、"%%"とします。
sprintf(Str, "%d.%d%%", ValHR10 / 10, ValHR10 % 10); // 文字列を作成
LCDString(Str); // LCDへ表示
このプログラムを実行すると、"67.8%"のようにLCDに湿度値が表示されます。温度値の場合も変数が変わるだけで同じ処理で表示できます。
今回で温度値、湿度値が表示できるようになりました。ところで、A-D変換、変換値読み出しの際には数10ms~百数10msと長い時間の待ち処理が必要ですが、前回のプログラム例のように単純に変換が終了するのを待っていては、その間にほかの処理が何もできなくなり、非常に効率が悪いソフトウェアになってしまいます。次回は、この待ち処理を実質的になくす工夫を説明します。

コメント (1)
はじめまして、私は今PIC16F88とLCD表示器とバキュームセンサを使ったデジタルバキューム計を作ろうと思っています。
しかし、ネットで情報収集してもさっぱり理解できません。
そこで貴殿様のお力をお借りできないかと思い書き込みしています。
こちらにセンサーの特性図があります。http://www.jaspa-oita.or.jp/jissen/2002/j_1407.html ノンターボです。
この、センサーの出力電圧をPICに取り込んでLCDに表示させたいのですがC言語によるプログラムをどの様に書いたら良いかさっぱり分かりません、もし宜しければこの工作物を
今後のテーマに取り上げていただく事出来ませんでしょうか?
ご検討宜しく御願い申し上げます。
投稿者: 吉高 | 2009年3月19日 19:33
日時: 2009年3月19日 19:33