Temperature logger
Monitor up to 7x DS18b20 1-wire devices using the http://www.atmel.com/dyn/resources/prod_documents/doc0839.pdf AT90S2313 AVR microcontroller. Each device will report its unique ROMID along with the temperature to the rs232 port whenever a change in temperature is detected.
Two DS18b20 shown, one directly attached to the PCB via a 3pin socket others can be connect via additional pins.
The current draw from this device is 25mA. This is too much to drive from the RS232 port however a USB port can drive up to 500mA at 5v. Perfect.
How to save current:
- if we went for an interrupt driven approach rather then a tight loop we could idle down the chip in the meantime. However we are tight on code space. At IDLE the circuit still draws 17mA - so we may save up to 8mA using an interrupt driven approach.
- Using a lower frequency chip say 4Mhz.
Alas its already built now.
2313 Temperature monitor Found 2 1-wire devices 28A83FF6010000DB28 22 28EA31F60100006228 22 28A83FF6010000DB28 23 28A83FF6010000DB28 22
Reference:
- http://pdfserv.maxim-ic.com/en/an/AN162.pdf - 1-wire microcontroller interfacing
- http://pdfserv.maxim-ic.com/en/an/AN162.pdf - DS18B20 1-wire digital thermometer
'******************************************************************** '* 2313temp.bas '* '* Measure temperature using up to 4 1-wire 18b20 or 18s20 devices '* BASCOM '******************************************************************** $regfile = "2313def.dat" $crystal = 10000000 $baud = 9600 Config 1wire = Pd.4 ' DS18x20 ROM ID Const Ds18s20_id = &H10 Const Ds18b20_id = &H28 ' COMMANDS Const Ds18x20_convert_t = &H44 Const Ds18x20_read = &HBE Declare Sub Convallt ' Convert T on ALL sensors Declare Sub Meas_to_cel(id As Byte , Offset As Byte) Declare Sub Monitor Declare Sub Disp_temp(cnt As Byte , Offset As Byte) ' 1-wire devices Const Max1wire = 7 ' Up to 7 each having an 8 byte ROMID Dim Dsid(56) As Byte ' Dallas ID 64bit inc. CRC Dim Dsvalue(max1wire) As Byte ' Value of each sensor Dim Dssign As Byte ' If max1wire > 7 make this a word Dim Cnt1wire As Byte ' Number of 1-wire devices found Dim I As Byte Dim J As Byte Dim K As Byte Dim Meas As Word Dim Sc(9) As Byte ' 1-wire scratch pad 'Sc(1) 'Temperature LSB 'Sc(2) 'Temperature MSB 'Sc(3) 'TH/user byte 1 also SRAM 'Sc(4) 'TL/user byte 2 also SRAM 'Sc(5) 'config also SRAM x R1 R0 1 1 1 1 1 - the r1 r0 are config for resolution - write FF to byte for 12 bit 'Sc(6) 'res 'Sc(7) 'res 'Sc(8) 'res 'Sc(9) '8 CRC '************* MAIN ************** Print "2313 Temperature monitor" ' Gather ROM ID for all 1-wire devices Cnt1wire = 1wirecount() Print "Found " ; Cnt1wire ; " 1-wire devices" If Cnt1wire = 0 Then Idle End If If Cnt1wire > Max1wire Then Cnt1wire = Max1wire End If I = 1 Dsid(i) = 1wsearchfirst() For J = 1 To Cnt1wire I = I + 8 Dsid(i) = 1wsearchnext() Next Do Convallt Waitms 750 Monitor Loop End Sub Monitor J = 1 For I = 1 To Cnt1wire 1wverify Dsid(j) 'Issues the "Match ROM " If Err = 0 Then 1wwrite Ds18x20_read Sc(1) = 1wread(9) If Sc(9) = Crc8(sc(1) , 8) Then Call Disp_temp(i , J) End If End If J = J + 8 Next End Sub 'Makes the Dallas "Convert T" command on the 1w-bus configured in "Config 1wire = Portb. " 'WAIT 200-750 ms after issued, internal conversion time for the sensor 'SKIPS ROM - so it makes the conversion on ALL sensors on the bus simultaniously 'When leaving this sub, NO sensor is selected, but ALL sensors has the actual 'temperature in their scratchpad ( within 750 ms ) Sub Convallt 1wreset ' reset the bus 1wwrite &HCC ' skip rom 1wwrite Ds18x20_convert_t End Sub ' Store WHOLE degree's only ' Display if the value has changed since last polled. Sub Disp_temp(cnt As Byte , Offset As Byte) Meas = 0 Meas = Makeint(sc(1) , Sc(2)) ' 18S20 is only 9bit upscale to 12bit ' If Dsid(offset) = Ds18s20_id Then ' Meas = Meas And &HFFFE ' Shift Meas , Left , 3 ' End If If Meas.15 = 1 Then ' if meas & &H8000 then Set Dssign.cnt ' convert to +ve, (two's complement)++ Meas = Meas Xor &HFFFF Incr Meas Else Reset Dssign.cnt End If Shift Meas , Right , 4 ' If this value different from the stored value ? If Dsvalue(cnt) <> Meas Then ' Dump ROMID of 1-wire device followed by temperature K = Offset + 8 Do Print Hex(dsid(offset)); Incr Offset Loop Until Offset > K Print " "; If Dssign.cnt = 1 Then Print "-"; End If Print Meas Dsvalue(cnt) = Meas End If End Sub
To read the device from a linux box we can use the following snippet of perl. Now that we have a data value in a file we can use this value to feed my rrdtools logging system. Why use an intermediate file? The temperature sensor only sends a value when it detects a change however the logging software wants a value on a periodic basis ;so it can poll this file.
I guess I could have changed the firmware to send a value every (x) mins, however if you want different polling frequencies then you now need to change the firmware to suit, which is more difficult than adjusting your CRON that reads this file!.
#!/usr/bin/perl use Device::SerialPort; # Map 1-wire ROMID to a location %rommap=( "28EA31F60100006228" => "inside", "28A83FF6010000DB28" => "outside" ); # setup SERIAL port my $port = Device::SerialPort->new("/dev/ttyS0") || die "Can't open serial port" ; $port->databits(8); $port->baudrate(9600); $port->parity("none"); $port->stopbits(1); $port->handshake("none"); $port->write_settings || die "no settings"; # Read from serial device my $buffer = ""; while(1) { while ($string_in = $port->input) { $buffer .= $string_in; while ($buffer =~ m/\n/) { ($buffer, $rest) = split('\n',$string_in); process_temp($buffer); $buffer = $rest; } } sleep(1); } exit; sub process_temp() { my ($output) = @_; my ($romid, $temp) = split(' ', $output, 2); my $location = $rommap{$romid}; if ($location eq "") { $location = $romid; } # We update the temperature when a new value is received. # This file will be polled and logged by another $temp =~ s/[\r\n]//g; $file = "/var/run/1wire/$location"; open(FH,">$file") || die "cannot open $file for write"; print FH "$temp\n"; close(FH); }
We run this PERL code in a cron job that poll every 5 mins and transmits the value to the RRD server.
*/5 * * * * /usr/local/bin/xmit_temp.pl >/dev/null
#!/usr/bin/perl # # rrd_hddtemp.pl use IO::Socket; use File::Basename; # Remote RRD server and port my $host = "elmo"; my $port = 13900; my $socket = IO::Socket::INET->new(PeerAddr=> $host, PeerPort=> $port, Proto=> 'tcp', Type=> SOCK_STREAM) or die "Can't talk to $host at $port"; @files = </var/run/1wire/*>; foreach $file (@files) { &ProcessHDD($socket, $file); } close $socket; sub ProcessHDD { my($socket,$file) = @_; open(FH,$file); $temp = <FH>; close FH; $loc = basename($file); $temp =~ s/[\n ]//g; # print "$loc : $temp degrees C\n"; print $socket "update $loc.rrd -t temp N:$temp\n" ; $answer = <$socket>; print $answer; }