電子工作12 - デジタル温度計チップDS1820/DS18B20出力を液晶に表示
概要
今回は、温度がデジタル信号で出力されるというMAXIM社製の one-wire デジタル温度計を液晶に表示させる実験を試してみることにした。最初は、正直言ってどんなものか全く分からず、ただ、PICBasic
Pro(現在の小生のものはV 2.46)で開発された関連プログラムがいくつか Web上で見つかったので、とにかく、自分流に回路を組んで実験してみた。
通常の3ピンのトランジスタのような外観のこのチップは、実は仲々の優れもので、次ぎのような特徴を持つ。
1) この温度計チップには、温度センサ、メモリ、制御回路など、すべて入っているので、マイクロプロセッサにつないで、プログラムを作成すれば温度測定ができる。
2) その動作には、3本線(電源、GND、信号)をつなぐか、または2本線(信号、GND)ですむ。
3) 2本線接続モードを使うと、一本の線(正確には、GNDを含めて2本)に複数のこの温度計チップや、同社のone-wire 製品がつなげられる。
4) しかし、1本の信号線を通して、コントロール指令、温度情報のやり取りなどを行うので、タイミングの取り方やプログラミングそのものが易しくない。
差当たって、手元にあるDS1820 (生産中止になり、現在は同等品DS18S20が多く出回っているようだ)を、関連ソフトが結構あるので使ってみることにした。また、3、4年以上前から販売されているDS18B20という温度計チップも試してみた。
DS1820:
-55°C ßà +125°C 精度±0.5°C (高精度表示の方法もあり) 分解能 1/80°C 9-bit
digital word
DS18S20:
-55°C ßà +125°C
精度±0.5°C (高精度表示の方法もあり) 分解能 1/16°C 9-bit digital
word
DS18B20:
-55°C ßà +125°C 精度±0.5°C (高精度表示の方法もあり) 分解能 1/16°C
12-bit digital word
DS1820 と DS18S20 との差: 温度変換速度の差があり、500 msec VS 750 msec
回路
PIC16F877と今回のデジタル温度計チップを組み合わせ、結果を液晶20文字X4行(または、16文字X2行)に表示させることにした。下図に示すように、液晶とPIC16F877の間の接続では、制御線2本(RSとE)、データ線4本(DB4-DB7)の合計6本と、温度計チップから信号線が1本がPIC16F877に入るだけの、シンプルなものである。
Fig. 1
Photo 1は上の回路で組込んだボードを示す(後述のプログラム(A)で動いている)。一番上に20文字x4行の液晶、その下にPIC16F877、更に下に小さいトランジスタのような黒いDS1820チップが、黄色い小さいリセットスイッチの左側に見える。右下に見える小さいボードはDC5V電源である。
Photo 1
Photo 2では、DS18B20、PIC16F877と16文字x2行の液晶を使い、DS1820の場合とは違う後述のプログラム(B)で動かしている。プログラムリストで分かるように、PIC16F877と液晶との結線もDS1820の場合とは多少異なる。ここでは温度の表示精度は±0.5°Cなので、小数点以下1桁目は、0か5になる。液晶の右下に見えるのがDS18B20。
Photo 2
プログラム
プログラム(A): DS1820
を使う場合の例 (Fig. 1、Photo 1)
このプログラムの要点、 順を追って、
1) LCD表示のための設定
2) 各種パラメータの設定
3) OWOutとOWIn (one-wire 製品のためのPBPコマンド) を使って、PORTC.2 (DQ) を通じ、$CCと$44(one-wire 製品特有のコマンド)を温度計チップに送って、温度変換を指令。そして、$CCと$BEを送って、スクラッチパッドというメモリから温度を読込む。
4) 読込んだ温度 temperature (16-bitの2進数)を、適当に算術処理してLCDの表示させる。
'****************** プログラミング備忘録 ********************
[DS18877x.bas] '06.3.21, based on "Basic for PIC Microcontrollers On-line" p.25/26 (Reference)
'This PBP program works on the new board made up of DS1820 and 20x4 LCD.
' The program reads DS1820 1-wire temperature unit and displays the temperature on LCD.
‘Temperature has reached to 127.68°C and stopped when heated with a soldering iron and was ‘measured down to 8.0°C in my refrigerator (06.5.11-12).
'************** LCDと PIC16F877のピン結合 *****************
'Pin connections for LCD (SC2004CS*B, 20x4)
'Pin 1 - Vss (GND) (for 20x4 LCD)
'Pin 2 - Vdd (+5V) (for 20x4 LCD)
'Pin 3 - Vo (Contrast adj.)
'Pin 4 - RS (Register select) to RD2 (PIC)
'Pin 5 - R/W (Read/Wrire input) -> GND here
'Pin 6 - E (Enable) to RD3 (PIC)
'Pin 11 - RD4 (PIC)
'Pin 12 - RD5 (PIC)
'Pin 13 - RD6 (PIC)
'Pin 14 - RD7 (PIC)
'Pin connections for 16F877
'Pin 11 - Vdd (+5V)
'Pin 12 - Vss (GND)
'Pin 15 (RC2) - DS1820 (DS18S20 or DS18B20)
'Pin 21 (RD2) - RS (Pin 4 of LCD)
'Pin 22 (RD3) - E (Pin 6 of LCD)
'Pin 27 (RD4) - Data (Pin 11 of LCD)
'Pin 28 (RD5) - Data (Pin 12 of LCD)
'Pin 29 (RD6) - Data (Pin 13 of LCD)
'Pin 30 (RD7) - Data (Pin 14 of LCD)
'*************** ここからがプログラム本体 ***************
' Define LCD registers and bits
Define LCD_DREG PORTD ‘Connect data pins to PORTD
Define LCD_DBIT 4 ‘Using DB4 – DB7 (4 bits)
Define LCD_RSREG PORTD ‘Connect RS to PORTD
Define LCD_RSBIT 2 ‘Connect RS to PORTD.2
Define LCD_EREG PORTD ‘Connect E to PORTD
Define LCD_EBIT 3 ‘Connect E to PORTD.3
Define LCD_BITS 4 ‘4-bit dara bus
Define LCD_LINES 4 ‘No. of LCD lines
‘---- 各種パラメータの設定 ----
DQ var PORTC.2 ' One-wire data pin
temperature var Word ' Temperature storage
count_remain var Byte ' Count remaining
count_per_c var Byte ' Count per degree C
ADCON1 = 7 ' Set all PORTs to digital
Pause 100
‘---- PICとDS1820とのデータやり取り ----
Main: OWOut DQ,1,[$CC,$44] ' Start temperature conversion
Waitloop: OWIn DQ,4,[count_remain] ' Check for still busy converting
If count_remain = 0 Then Waitloop
OWOut DQ,1,[$CC,$BE] ' Read the temperature
OWIn DQ,0,[temperature.LOWBYTE,temperature.HIGHBYTE,Skip 4,count_remain,count_per_c]
‘---- LCDへの温度表示 (高精度モード) ----
'Display temperature in DEC
' (not valid for negative temperature)
temperature = (((temperature >> 1) * 100) - 25) + (((count_per_c - count_remain) * 100)/count_per_c) ‘温度データの処理
Lcdout $fe,1, “Temp.DS1820=”, DEC (temperature/100),".",DEC2 temperature," C" ‘LCDへ温度10進、小数点2桁表示
Pause 1000 ' Display about once a second
Goto Main ' Do it forever
End
‘************* プログラム本体はここまで ***************
‘********** 秋月のプログラマで焼く時の設定 ***********
'Note: AKI Programmer's configs. - FOSC: XT, WDTE: Enable,
'PWRTE: Enable, BODEN: Enable, LVP=RB3=I/O,
'CPD: Not protect, WRT=Enable, DEBUD=Disable, CP=Not protect
‘****:上記プログラムのHex File (DS18877x..HEX) の内容 ****
今回は、省略した。 DS18877x..HEX の大きさは3,132 バイトであった。
プログラム(B): DS18B20 を使う場合の例 (Photo 2)
サブルーチンを多用してのビット操作によるコマンドやデータの転送、マイクロ秒まで指定できるPauses を使った微妙なタイミング取りが、このプログラムのポイントのようです。
'****************** プログラミング備忘録 ********************
'[DS18877b.bas], ’06.5.29, based on http://www.renton.com/PICX4.htm (Reference)
'Found to work when changed like "temp >> 1" -> "temp >> 4" in the line "Lcdout $fe, 1, dec ‘(temp >> 4),".", 'dec (temp.0 * 5)," degrees C" in the program shown below – Important!
'Temperature has reached 127.5C and stopped when heated by a soldering iron.
'This program reads temperature data from DS18B20 as digital data and display it on LCD.
'************** LCDと PIC16F877のピン結合 *****************
DS1820の場合と多少違う。
'Pin connections for LCD (SC16028B, 16x2)
'Pin 1 – Vdd (+5V) (for 16x2 LCD)
'Pin 2 - Vss (GND) (for 16x2 LCD)
'Pin 3 - Vo (Contrast adj.)
'Pin 4 - RS (Register select) to RE0 (PIC)
'Pin 5 - R/W (Read/Wrire input) -> GND here
'Pin 6 - E (Enable) to RE1 (PIC)
'Pin 11 - RD4 (PIC)
'Pin 12 - RD5 (PIC)
'Pin 13 - RD6 (PIC)
'Pin 14 - RD7 (PIC)
'Pin connections for 16F877
'Pin 8 (RE0) - RS (Pin 4 of LCD)
'Pin 9 (RE1) - E (Pin 6 of LCD)
'Pin 11 - Vdd (+5V)
'Pin 12 - Vss (GND)
'Pin 15 (RC0) - DS18B20
'Pin 27 (RD4) - Data (Pin 11 of LCD)
'Pin 28 (RD5) - Data (Pin 12 of LCD)
'Pin 29 (RD6) - Data (Pin 13 of LCD)
'Pin 30 (RD7) - Data (Pin 14 of LCD)
'*************** ここからがプログラム本体 ***************
' Define LCD pins
Define LCD_DREG PORTD
Define LCD_DBIT 4
Define LCD_RSREG PORTE
Define LCD_RSBIT 0
Define LCD_EREG PORTE
Define LCD_EBIT 1
Define LCD_BITS 4
Define LCD_COMMANDUS 2000 ‘Set command delay time in ms
Define LCD_DATAUS 50 ‘Set data delay time in ms
‘---- 各種パラメータの設定 ----
' Allocate variables
command var byte ' Storage for command
i var byte ' Storage for loop counter
temp var word ' Storage for temperature
DQ var PORTC.0 ' Alias DS18B20 data pin
DQ_DIR var TRISC.0 ' Alias DS18B20 data direction pin
ADCON1 =%10000111 '= 135 Close-up to Right and all PORTs to digital
Low PORTE.2 ' LCD R/W line low (W)
Pause 100 ' Wait for LCD to start
‘---- PICとDS1820とのデータやり取り ----
Lcdout $fe, 1, "Temp degrees C" ' Display sign-on message
' Mainloop to read the temperature and display on LCD
mainloop:
Gosub init1820 ' Init the DS18B20
command = $CC ' Issue Skip ROM command
Gosub write1820
command = $44 ' Start temperature conversion
Gosub write1820
Pause 2000 ' Wait 2 seconds for conversion to complete
Gosub init1820 ' Do another init
command = $CC ' Issue Skip ROM command
Gosub write1820
command = $BE ' Read the temperature
Gosub write1820
Gosub read1820
‘---- LCDへの温度表示 (通常モード) ----
' Display the decimal temperature
Lcdout $fe, 1, dec (temp >> 4),".", dec (temp.0 * 5)," degrees C" ‘Changed from the original’s “temp>>1” to “temp>>4” (4-bit shift)
Goto mainloop ' Do it forever
' Initialize DS18B20 and check for presence
init1820:
Low DQ ' Set the data pin low to init
Pauseus 500 ' Wait > 480us
DQ_DIR = 1 ' Release data pin (set to input for high)
Pauseus 100 ' Wait > 60us
If DQ = 1 Then
Lcdout $fe, 1, "DS1820 not present"
Pause 500
Goto mainloop ' Try again
Endif
Pauseus 400 ' Wait for end of presence pulse
Return
' Write "command" byte to the DS18B20
write1820:
For i = 1 to 8 ' 8 bits to a byte
If command.0 = 0 Then
Gosub write0 ' Write a 0 bit
Else
Gosub write1 ' Write a 1 bit
Endif
command = command >> 1 ' Shift to next bit
Next i
Return
' Write a 0 bit to the DS18B20
write0:
Low DQ
Pauseus 60 ' Low for > 60us for 0
DQ_DIR = 1 ' Release data pin (set to input for high)
Return
' Write a 1 bit to the DS18B20
write1:
Low DQ ' Low for < 15us for 1
@ nop ' Delay 1us at 4MHz
DQ_DIR = 1 ' Release data pin (set to input for high)
Pauseus 60 ' Use up rest of time slot
Return
' Read temperature from the DS18B20
read1820:
For i = 1 to 16 ' 16 bits to a word
temp = temp >> 1 ' Shift down bits
Gosub readbit ' Get the bit to the top of temp
Next i
Return
' Read a bit from the DS18B20
readbit:
temp.15 = 1 ' Preset read bit to 1
Low DQ ' Start the time slot
@ nop ' Delay 1us at 4MHz
DQ_DIR = 1 ' Release data pin (set to input for high)
If DQ = 0 Then
temp.15 = 0 ' Set bit to 0
Endif
Pauseus 60 ' Wait out rest of time slot
Return
End
‘************* プログラム本体はここまで ***************
結果、課題、分かったことなど
1) 市販の温度計と比較して、DS1820/DS18B20の温度はほぼ正しかった(差1°C内)。DS1820を使った場合(高精度温度表示モード)では、少なくとも、表示の少数点以下1桁までの上下動はスムーズであった。半田ゴテを当てて加熱すると、+127.68°Cまで上昇して止まった。あまり冷えない冷蔵庫で8.0°Cまで下がるのを確認した。一方、DS18B20を使った場合(通常温度表示モード)では、最高温度は+127.5°Cまで上昇して止まった。
2) OWOut や OWIn を使わずに、サブルーチンを沢山使って温度計チップに指令を出し、温度を読込む方式のプログラム(DS18B20使ったプログラム(B))は、長めになるが、理解し易いようだ。
3) 上述のプログラムでは、マイナスの温度範囲(-55°Cまで)をカバーしていない。カバーするには、”+”や”-“記号添付を含めた、更なるプログラムの追加や変更が必要である。
4) DS1820などを複数個つなぐ、いわゆるパラサイト接続(電源線不要、信号線とGND線の2本線でOK)にはどんなプログラムが必要なのか、興味あり。
5) DS18B20(12-bitの温度データ)を走らせることにも成功した。正しく温度を表示させるには、オリジナルプログラム(See Reference)の温度表示行"Lcdout $fe, 1, dec (temp >> 1),".", dec (temp.0 * 5), “degrees C"の中の "temp >> 1"部分を"temp >> 4"(4ビット右へシフト)に変えることがポイントであった。上のプログラム(B)で、16-bit長の2進温度データの内、温度に関係する真中の 8 bits を抽出(実際には温度データの下12 bits を抽出して 4 bits shift させる)して10進数で表示させている(精度±0.5°C)。
余談
いじくっていた温度計チップがDS18S20だとばかり思っていて、いくつか公開されているプログラムをPICに組込んでみても動作しない。悶々とすること3カ月。外国のホーラムに質問しても、返答なし。止めようかと、何気なしに虫眼鏡で型番を確認したら、DS18B20ではないか。“S”と”B”を見間違っていたのである。視力低下−ジジイになると良いことなし。
単純明快、外付けなしで直接PICにつなげられる簡便さは良い。あとはソフト次第である。one-wire 製品が結構出回っているようで、うまく使えれば、いろんなことが出来そうである。
やっと、このデジタル温度計チップを使って温度を表示させることに成功した。と言ってもプログラムやチップの使い方を完全に理解しているわけではない。正直、ややこしく、難しい。
それにしても、エレキのメッカ秋葉原でDS18S20など入手出来ないのはどうしたことだろう。
その後、マイクロテクニカでDS18S20 (正真正銘のDS18S20 だが、現在のものは“S”記号がないという)が、1個650円で購入出来た。