電子工作 4 – 16F819 とLM35でLCD (液晶)上に温度を表示する実験
概要
例によって割安パーツを用いた今回の実験では、10-bitのADCの入ったPIC16F819(\300)と温度センサLM35DZ (\200) を使って温度を測定し、それを液晶表示器(LCD
SC16028、\700)上に表示しようというもの。ADCを使うための設定、液晶表示器と16F819とのピンの結線、取込んだ温度データを処理して、それを表示させる方法など結構複雑でした。現在の段階では、表示値の精度や安定度はイマイチです。
回路
一貫して使い続けているBasicコンパイラPicBasic Pro (PBP) のマニュアルに載っている回路図(そこでは16F84とLCDの組合わせ)を参考に、16F819とLCDを結線した。
温度センサ LM35DZは、レンジが0-100°C、変換率10.0
mV/°C、そして、精度が±1°C。つまり、1度温度が上る毎に10.0mVづつ直線的に出力されるという便利なものです。図中Vdd
には、レギュレータ7805を使ってつくられた5.00Vが供給され、また、温度センサの電源は9Vの角型乾電池を使っています。消費電力は60uA です。
下の写真の液晶上に、センサからの電圧(1行目Volt=0.31V)と変換された温度(2行目
Temp=31C)が表示されているのが見えます。その下の3本足の黒いチップが温度センサLM35DZです。
プログラミング
目標は、16文字2行の液晶上に、1行目“Volt=0.xxV”とセンサからの電圧出力そのままを、そして、そのデータを用いて2行目には“Temp=xxC”と温度(摂氏)を2桁表示させることです。下のプログラムを見てください。 LCD表示のための様々な設定、8MHzの内部クロックを使うための設定(外付けいらずで簡単)、ADCを使うための結構厄介な設定をしています。次いで、外部からのアナログ入力(温度センサからの)(RA0-Pin17)を10個読込んで積算し、それから平均値を求める(バラツキを抑えるため)。ここで問題は、PBP では整数値しか扱えないので、小数点以下の表示が必要な場合は、工夫がいるということです。したがって、得られたVinという平均値(10-bit値)をLCD上の1行目に表示するには、Vin=(Vin*/500)>>2 とした後で、Lcdout $fe, 2, "Volt=",dec(Vin/100),".",DEC2 Vin と書きます。これで Volt=0.31 などと表示されます。この値を2行目に、2桁の温度として表示するには、 Lcdout "Temp=",Dec2 Vin,"C" と書きます。これで、Temp=31C などと表示することが出来ます。
プログラム
下の記述で分かるように、デバイスのピンの結線をはじめ、英語のコメント文がいっぱい入っていてかなり長く見えますが、実際のプログラムは、DEFINE LCD_DREG PORTB 'Set LCD Data port で始まって、goto ADCLoop で終わります。最後の部分の”Note“にはAki Pic programmer configuration の設定項目が記してあります。内部クロックなどの選択はここでします。
'ADLC819h.bas - 16F819 2004.7.1 completed
'This time no digits below decimal point were used.
'Exp. to read a voltage value from PortA.0 which
'is connected to LM35DZ temp. sensor (10 mV/C),
'convert it to a voltage and a temperature and
'display both voltage (1-line) and temp. value
'on LCD(2-line display).
'Note: The points are the use of "Vin=(Vin*/500)>>2" ,
'Lcdout $fe, 2, "Volt=",dec(Vin/100),".",DEC2 Vin and
'Lcdout "Temp=",Dec2 Vin,"C"
'Here, Dec2 means to display the Vin value in a 2-digit
'number.
'Pin connections:
'LCD PIC
'DB4 PortB.4
'DB5 PortB.5
'DB6 PortB.6
'DB7 PortB.7
'RS PortB.1 (add 4.7K pullup resistor to 5 volts)
'E PortB.0
'RW Ground
'Vdd 5.00 volts (also used as +Vref)
'Vss Ground
'Vo Ground (or 20K potentiometer)
'DB0-3 No connect
'ADC input PortA.0
'**New LCD connection setting** See p.88 in PBP Manual
DEFINE LCD_DREG PORTB 'Set LCD Data port
DEFINE LCD_DBIT 4 'Set starting Data bit
'(0 or 4) if 4-bit bus
DEFINE LCD_RSREG PORTB 'Set LCD Register Select port
DEFINE LCD_RSBIT 1 'Set LCD Register Select bit
DEFINE LCD_EREG PORTB 'Set LCD Enable port
DEFINE LCD_EBIT 0 'Set LCD Enable bit
DEFINE LCD_BITS 4 'Set LCD bus size (4 or 8 bits)
DEFINE LCD_LINES 2 'Set number of lines on LCD
DEFINE LCD_COMMANDUS 2000 'Set command delay time in us
DEFINE LCD_DATAUS 50 'Set data delay time in us
'**Setting for ADC of 16F819**
Define ADC_BITS 10 '10-bit ADC used
Define ADC_CLOCK 3 'Internal clock used
Define ADC_SAMPLEUS 50 'Sample timing
OSCCON=%01110100 '=100 (decimal) - Internal OSC setting
'bit7=0(unimplemented), bit6-5-4=111(internal OSC 8MHz),
'bit3=0(unimplemented), bit2=1(frequency stable?),
'bit1-0=00(unimplemented)
ADCON0=%10000101 '=5 (decimal) - ADC setting
'bit7-6=01(Fosc/32 atADSC2?),'bit5-4-3=000(channel 0 (RA0/AN0),
'bit2=1(Ad conversion in progress at ADOn=1),
'bit1=0(unimplemented), bit0=1(AD module is operating)
ADCON1=%10001110 '=142 (decimal) - ADC and pin setting
'bit7=1 (right justified), bit6=0 (disable), bit5-4=00
'(unimplemented), bit3-2-1-0=1110 (AN4-3-2-1-0=DDDDA,
'+Vref-AVdd(supply power), -Vref-AVss(GND))
TRISA=%00100001 'PortA.0-analog input, PortA.5-input,
'all others-output
TRISB=%00000000 'All PortBs are output
Samples var word 'Samples
Sample var byte 'Sample
Vin var Word 'Vin is variable
Samples=0
ADCloop:
For Sample=1 to 10 'Take 10 samples (changed from 20)
ADCIN 0, Vin 'Read ADC ch-0 and save in Vin
'(range 0-1023)
Samples=Samples + Vin
Pause 200 'Wait for LCD to startup
'Seems to be appropriate.
Next sample
Vin=Samples/10 'Mean of 10 Vin values
Vin=(Vin*/500)>>2
Lcdout $fe, 1 'Clear LCD
Lcdout $fe, 2, "Volt=",dec(Vin/100),".",DEC2 Vin
LCDOUT $FE,$C0 'Jump to second line
Lcdout "Temp=",Dec2 Vin,"C"
Samples=0
goto ADCLoop
'Note: Aki Pic programmer configuration for 16F819:
'Same as those on 04.2.13
'FOSC-INTRC__RA6=I/O, WDTE-Enable, PWRTE-Enable, MCLRE-RA5=I/O,
'BODEN-Enable, LVP-RB3=I/O, CPD-Disable, WRT-All-Enable,
'DEBUG-Disable, CCPMX-CCPI=RB2, CP-Disable
余談
今回の実験で、液晶に表示される温度の小数点以下1桁目は不安定で、その増減が連続的でなく(数値が飛ぶ)、市販の液晶温度計のようではありませんでした。 従って、2桁表示を採用することにしました。 Cooler/heater box の中に温度センサと市販のデジタル温度計(NT-301)の針状検出部を入れ比較してみたところ、少なくとも実験した7
- 55°Cの区間では大変直線性が良く、±0.5°C程度の精度はあることが分かりました。小数点以下1桁目まで安定した温度を得るには、12-bit
ADC (0-4095=4096) 内臓のフラッシュタイプPIC(未発売)、プログラミングの工夫、それに、より精度の高い温度センサが必要のようです。巷で\1500-2000
位で売られている様々な液晶温度計の、あの桁上がりのズムーズさ、設計した人、創った人、プロとは凄いものだと脱帽してしまいます。
―間違い―
回路図の液晶(SC1602)のピン表示に誤り見つかりました。
誤 正
Pin 1 VDD -> VDD
Pin 2 VO -> VSS
Pin 2 VSS -> VO