anita2r
Posts: 226
Joined: Sun Dec 23, 2012 6:55 pm
Location: Ottawa, Canada

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Mon Jan 13, 2014 11:33 pm

You're welcome ...

and the steaks were awesome.

Regards

anita2R

lifebeginsatsixty
Posts: 26
Joined: Fri Mar 29, 2013 3:39 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Wed Jan 29, 2014 11:24 am

Well, my PID controller seems to be overshooting a lot more than before so it's timely to get going with something else. But from time to time my DS18B20 won't show up at boot after running the appropriate commands, or will just quit. Sometimes it comes up again and sometimes not. This will be a big problem if I'm depending on it for steak cooking control - anybody got insight or experience about how to deal with this?

Connections seem to be good, 2 meters of cable to Pi.

Thanks,
life begins at sixty

anita2r
Posts: 226
Joined: Sun Dec 23, 2012 6:55 pm
Location: Ottawa, Canada

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Wed Jan 29, 2014 1:55 pm

Hi,

Absent 1-wire sensors is likely a cabling issue.

How are your sensors connected.
- what type of cable have you used
- which wires in the cable are you using for each pin on the sensor
- what value resistor do you have between data and power
- are you powering the sensors at 3.3 volt or are you using parasite power
- is the 1-wire network a single length of cable or are there other sensors attached on different cables.

Another (rare) cause of communication failure can be due to the exact length of the cable, where the signal is reflected back from the end of the cable and arrives at the driving hardware (the Pi's gpio port) at a critical moment. Changing the cable length can solve this.

Regards

anita2R

lifebeginsatsixty
Posts: 26
Joined: Fri Mar 29, 2013 3:39 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Wed Jan 29, 2014 6:38 pm

Using ribbon cable like I used to make the gpio header cable, powered, same wire order as DS18B20 pin order. Soldered at sensor end, crimped connectors at Pi end (not using header cable now).

I checked and see that RJ-45 cat 5 is recommended by several sites (and strongly not recommended by one). Also that there were bad lots of the sensors with certain ROM code ranges. I can check that tomorrow.

I live in Asia and the whole place is shutting down for the Lunar New Year. Anything I need and don't have will have to wait about ten days.

life begins at sixty

lifebeginsatsixty
Posts: 26
Joined: Fri Mar 29, 2013 3:39 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Wed Jan 29, 2014 6:41 pm

Ah, two more. 5.1K resistor, only one sensor attached at this time. Resistor at Pi end. 3.3v power.

lbas

anita2r
Posts: 226
Joined: Sun Dec 23, 2012 6:55 pm
Location: Ottawa, Canada

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Wed Jan 29, 2014 8:08 pm

Hi,

Almost certainly, your problems are due to using ribbon cable.

The advice from Dallas/Maxim is to use twisted pair cabling, and Cat5e meets this criteria very well.
I don't know why anyone would advise against Cat5, let alone strongly advise against.

Use some Cat5e cable.
Connect the data and ground to one pair of wires - blue/blue-white for example.

Use a single wire from another pair for 3.3 volt power.

Leave all other wires unconnected - do not attach them to ground.

Also avoid the temptation to double-up wires to reduce resistance.
Doubling up wires dramatically increases capacitance on the data circuit, as does grounding unused lines. The increased capacitance distorts the waveform, potentially putting the pulses outside the required limits, and so resulting in the one-wire system not communicating with the sensors.

The 5.1K resistor should be fine for a single sensor on a 2 meter cable.

Another issue you may face with the Pi's 1-wire system on pin 4 is occasional failures to get a valid read.
I use a few extra lines of script to test for either a crc failure or a no-conversion failure. A re-read is then performed.

The following code reads all temperature sensors in the 28 family attached to the 1-wire network. Adding, removing or replacing sensors does not require any changes to the script.
In my case, the results are logged to data files. There is also an error log to help in troubleshooting.

Code: Select all

#!/bin/bash
# a script to read and save temperature readings from all the group 28 1-wire temperature sensors
#
# get all devices in the '28' family
FILES=`ls /sys/bus/w1/devices/w1_bus_master1/ | grep '^28'`
# iterate through all the devices
for file in $FILES
    do
      # get the 2 lines of the response from the device
      GETDATA=`cat /sys/bus/w1/devices/w1_bus_master1/$file/w1_slave`
      GETDATA1=`echo "$GETDATA" | grep crc`
      GETDATA2=`echo "$GETDATA" | grep t=`
      # get temperature
      TEMP=`echo $GETDATA2 | sed -n 's/.*t=//;p'`
      #
        # test if crc is 'YES' and temperature is not -62 or +85
        if [ `echo $GETDATA1 | sed 's/^.*\(...\)$/\1/'` == "YES" -a $TEMP != "-62" -a $TEMP != "85000"  ]
           then
               # crc is 'YES' and temperature is not -62 or +85 - so save result
               echo `date +"%d-%m-%Y %H:%M:%S "; echo $GETDATA2 | sed -n 's/.*t=//;p'` >> /var/1w_files/$file
           else
               # there was an error (crc not 'yes' or invalid temperature)
               # try again after waiting 1 second
               sleep 1
               # get the 2 lines of the response from the device again
               GETDATA=`cat /sys/bus/w1/devices/w1_bus_master1/$file/w1_slave`
               GETDATA1=`echo "$GETDATA" | grep crc`
               GETDATA2=`echo "$GETDATA" | grep t=`
               # get the temperature from the new response
               TEMP=`echo $GETDATA2 | sed -n 's/.*t=//;p'`
                  if [ `echo $GETDATA1 | sed 's/^.*\(...\)$/\1/'` == "YES" -a $TEMP != "-62" -a $TEMP != "85000" ]
                      then
                      # save result if crc is 'YES' and temperature is not -62 or +85 - if not, just miss it and move on
                      echo `date +"%d-%m-%Y %H:%M:%S "; echo $GETDATA2 | sed -n 's/.*t=//;p'` >> /var/1w_files/$file
                  fi
               # this is a retry so log the failure - record date/time & device ID
               echo `date +"%d-%m-%Y %H:%M:%S"`" - ""$file" >> /var/1w_files/err.log
           fi
    done
#
exit 0
If you do use any of this code, watch out for the use of backticks ` which are not the same as single quotes '

You could add a re-read loop, which includes setting off a warning if no valid read is obtained after say three attempts - use another gpio pin to connect to a buzzer of some description.

Hope this helps

Regards

anita2R

lifebeginsatsixty
Posts: 26
Joined: Fri Mar 29, 2013 3:39 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Thu Jan 30, 2014 10:14 am

Anita2r,

Everything you've said has been helpful so far so I'd say you don't need to worry.

I'm looking at 15cm of ribbon cable to get out of the probe cover that goes under water and 20cm ribbon cable in my header cable. Easy to replace the rest with cat 5 (which I have, happy packrat). Can replace it all if it's really a problem but the header cable to an external board and then the 15cm on the probe end is quite convenient.

If pin 4 is a problem for the signal is there a recommended pin among the others I might use? Easy to change that with which pin I set up for input via gpio.

Wonder, are there other basic sensors for the 1-wire system? Light intensity maybe? Something else?

Thanks,
lifebeginsatsixty

anita2r
Posts: 226
Joined: Sun Dec 23, 2012 6:55 pm
Location: Ottawa, Canada

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Thu Jan 30, 2014 2:32 pm

Hi,

You should be able to get away with a short length of ribbon cable, as long as the main run is Cat5.

The Pi's 1-wire system only runs on pin 4. Re-reading my post, my reply did indeed suggest that pin 4 was the problem - it is not, it's just that the Pi's 1-wire system which happens to be on pin 4 does seem to throw out errors every so often. As far as I know, the Pi's 1-wire timing is created by a process referred to as 'bit banging' which is less consistent than hardware controlled timing.

You can improve the performance of a 1-wire system by using a device that manages the 1-wire timing in hardware and also replaces the passive pull-up resistor with an active pull-up circuit. On one of my Pi's with 11 sensors on it, I use the HA7s from Embedded Systems. http://www.embeddeddatasystems.com/HA7S ... _p_23.html

It requires more programming to control it and it is connected to the two UART pins instead of pin 4. If you go that route, I can post the code that I use. With 11 sensors my Pi is making over 3000 temperature readings every 24 hours. Most days there are zero read errors, occasionally 1 or two errors (but valid readings obtained in a software controlled re-read) and rarely an unrecoverable error (no valid reads on three attempts).

In the last 7 days I have had 12 read errors (0.05% of the just over 22,000 reads). Six of the errors were two sets of 3 repeats without a valid read - so no valid temperature data for two sensors at one time-point in the week. The other 6 errors were all recoverable with valid temperatures. So the complete failure rate (no valid read for a sensor at a given time-point was 2 (0.01%).

The other advantage of using the HA7s is that unlike the Pi's 1-wire system you can use any of the Dallas/Maxim 1-wire devices. I have tried a small remote solid state relay module built around a 1-wire device.

I haven't looked to see if there are any light sensors for the 1-wire system.
Edit ... here is one: http://www.embeddeddatasystems.com/D2Ph ... _p_13.html
but you would have to use an HA7s or similar - it won't work on the Pi's pin 4 system.

Regards

anita2R

lifebeginsatsixty
Posts: 26
Joined: Fri Mar 29, 2013 3:39 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Sun Feb 02, 2014 9:53 am

Hi There,

I have the cat5 for almost all the distance now, still one sensor and a 5.1K, and made a simple loop to get the date (time) then call the read and print to both the screen and a file. So I just made 480 reads and, from the screen saw one instance of 3 successive fails followed by successes. May be more buried in the file. Sleep 3 after the read to aim at 5 seconds between reads.

I may try using two sensors in the same probe to see if pin 4 gives a bad read on both of them. Still OK with the 5.1K resistor?

Now I have the w1-gpio and w1-therm modules in my etc/modules file I get this message: "w1_master_driver w1_bus_master1: Family 28 for 28.000002ce88da is not registered." I haven't a clue as to whether this is important to me or not.

I read that the gpio pins go directly to the CPU innards so I'm looking at some simple protection. If a 3.3v Zener to ground (with resistor) is good protection then would a 3.3v forward voltage LED do the same thing? Similarly I wonder: what voltage should I send an input pin to assure it kicks on? I may experiment with other things than the DS18B20. Oh, the light sensor you mention is only for yes/no sensing and I hope to measure relative if not absolute intensity.

To try to stay simple I'll stay with the straight sensor(s) to pin 4 for now. The HA7 hasn't shown up at my usual suppliers.

So, muddling through as usual, and slowly.

Thanks again,
lbas

anita2r
Posts: 226
Joined: Sun Dec 23, 2012 6:55 pm
Location: Ottawa, Canada

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Sun Feb 02, 2014 2:08 pm

lifebeginsatsixty wrote:I may try using two sensors in the same probe to see if pin 4 gives a bad read on both of them. Still OK with the 5.1K resistor?

Now I have the w1-gpio and w1-therm modules in my etc/modules file I get this message: "w1_master_driver w1_bus_master1: Family 28 for 28.000002ce88da is not registered." I haven't a clue as to whether this is important to me or not.

I read that the gpio pins go directly to the CPU innards so I'm looking at some simple protection. If a 3.3v Zener to ground (with resistor) is good protection then would a 3.3v forward voltage LED do the same thing? Similarly I wonder: what voltage should I send an input pin to assure it kicks on? I may experiment with other things than the DS18B20. Oh, the light sensor you mention is only for yes/no sensing and I hope to measure relative if not absolute intensity.

To try to stay simple I'll stay with the straight sensor(s) to pin 4 for now. The HA7 hasn't shown up at my usual suppliers.
Glad to hear that you are getting data from the temperature sensors. Occasional misreads do happen - you just need to have something in software to manage them. As you are reading every 5 seconds, losing one reading shouldn't be a problem.

I have not come across the 'not registered' error message. When does it show up - just during bootup or when reading the temperature data.
Does entering: 'dmesg | grep 1w' show the message.
The following thread http://www.raspberrypi.org/phpBB3/viewt ... 04#p468854 may be relevant - the order of the modules in the /etc/modules file may be significant and what you have in the blacklist (/etc/modprobe.d/raspi-blacklist.conf) may also be relevant.
If this persists, it might be worth starting a new thread about it.

Adding more sensors doesn't require changing the resistor value, although 4.7K is the recommended value. If you get more read failures, try reducing the value to 4.7K

You ask about using gpio pins. There are lots of threads about using gpio pins as inputs or outputs.
I am no expert on the electronics, but here is my take on the issue:
(and comments on my 'takes' are welcome :) )
Regarding gpio as Inputs
1 For input a voltage of above 2 volts should be sufficient to be reliably read as 'on'
2 and below 0.8 volts should be reliably read as 'off'
As to protection:
1. If you are only using 3.3 volts for input circuits, then there should be no need for a zener to limit the voltage.
2. gpios as inputs have high impedance, so you don't have to limit current flow.
3. If a gpio is an output, then current limitation is advisable. When set as an output a gpio will try to either pull the connection down to 0 volts or pull it up to 3.3 volts. (The amount of current a gpio can deliver can be changed from about 2ma to 16ma). In general don't use your Pi as a source of power for devices - use it to control transistors that in turn deliver the required power at the required voltage.
4. By including, say a 2.2 K resistor on an input, you can still read the input, but you have some protection in case the gpio gets set as an output.
5. If you are worried about external voltages accidentally getting connected to the Pi, look at the use of optoisolators.

The HA7s is not a common item - I think you can buy it direct from Embedded Data Systems.

Regards

anita2R

feverish
Posts: 486
Joined: Wed Jun 27, 2012 2:29 pm

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Sun Feb 02, 2014 2:44 pm

Dan` wrote:
tonyhughes wrote:If there is any interest, I can elaborate on my setup, which currently includes:

Temperatures displaying on my lock screen of my Android phone (using Tasker & HTTP GET).
Tasker being able to do things like send temperatures to my partner on request, and at scheduled times.
im definately keen to hear more about this. i have just setup my RPi to log 2 ds1820's (more about to be added too) in cacti and will have it setup to email me once it reaches threshold temps (i had this working a year ago but with a usb temp sensor) but would be very interested to hear about having it show on my fone as well.
Cheers
Dan
I'm certainly more than just interested. My from-time-to-time on-going project is to make the hardware in leak-proof brass and copper, avoiding electolysis, to allow me to read vapour temperatures from around 160degreesF to 208F, be able to interrogate the data from afar via an intra-net, and receive alarrms to make me get on my bike and go and sort things out. At present, a household barbecue probe thermometer and webcam do the job passably well, with a solid-state relay controlling the heater unit.
If discrimination is not challenged then we are effectively in collusion with the perpetrators of such behaviour:-Oxford dictionaries

RobinGreig
Posts: 15
Joined: Sat Oct 27, 2012 2:40 am
Location: Calgary, Alberta, Canada

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Sun Feb 02, 2014 3:11 pm

anita2r wrote:Hi,
<snip>
You can improve the performance of a 1-wire system by using a device that manages the 1-wire timing in hardware and also replaces the passive pull-up resistor with an active pull-up circuit. On one of my Pi's with 11 sensors on it, I use the HA7s from Embedded Systems. http://www.embeddeddatasystems.com/HA7S ... _p_23.html

It requires more programming to control it and it is connected to the two UART pins instead of pin 4. If you go that route, I can post the code that I use. With 11 sensors my Pi is making over 3000 temperature readings every 24 hours. Most days there are zero read errors, occasionally 1 or two errors (but valid readings obtained in a software controlled re-read) and rarely an unrecoverable error (no valid reads on three attempts).

The other advantage of using the HA7s is that unlike the Pi's 1-wire system you can use any of the Dallas/Maxim 1-wire devices. I have tried a small remote solid state relay module built around a 1-wire device.
<snip>
Hi anita2r;
I hope that it is not inappropriate for me to jump in like this.
I'm wondering if you wouldn't mind posting your code that you use with the HA7s?
I have several projects using the Pi with DS18B20's and would be interested in checking out the HA7 module as well.

Thanks,
Robin
www.robingreig.ca
Arduino + Raspi + Amateur Radio enthusiast since 2012
VE6RBN Canadian Amateur Radio Callsign

anita2r
Posts: 226
Joined: Sun Dec 23, 2012 6:55 pm
Location: Ottawa, Canada

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Sun Feb 02, 2014 4:29 pm

Hi Robin,

My code is attached below.

Notes:
I use a text file to hold the rom ID's: /var/1w_files/romIds.txt
Change path as necessary.
The rom ID's are in this format - not the format used in the Pi's 1-wire setup
DF0000041875D028
with one entry per line.
The family code is at the end and the first two characters are the crc check digit
The perl script reads from all sensors in that list - as I rarely change sensors, this was easier than doing a search on the 1-wire network and working through the returned id's

The script is called by cron once every 5 minutes - my reading interval.
As I had a few times when a script seemed to get delayed, and it appeared that two copies were running, resulting in really mashed-up results, I added a timed loop to stop reading after one minute - more than enough for the 11 sensors being read. This has stopped the problem and data output seems pretty stable.

Errors are logged to a file - three types - a crc error, a temperature conversion error & an unrecoverable error when 3 reads all result in errors. The log file includes the sensor ID and is timestamped.

As I had been using the Pi's 1-wire system, I wanted to keep output file data in the same format, e.g. files labelled 28-0000041875d02, so there is a function to do that conversion - you may not need it.

There is a fair bit of comment in the code, but if you need further clarification, just ask.

Code: Select all

#!/usr/bin/perl
#
# A script to read and save temperature readings from all the group 28 
#   1-wire temperature sensors
#
# This script is called every 5 minutes by sudo's crontab
# Running as sudo avoids having to change ownership of /dev/ttyAMA0
#  after each reboot
#
# Version 1.10
# Added loop to repeat device reads up to 3 times
#  if there is a crc error or a temperature error
#
# Version 1.20   17 January 2014
# Added an outer while loop to stop the main data gathering from running
#  for more than one minute to avoid a delayed script conflicting
#  with a newly started copy
#
use Device::SerialPort;
use Time::HiRes qw(usleep);
use strict;
#
# variables
my ($port, $resp);						# serial port name, response returned by a read 
my ($id, $temp, $dtTmStamp);			# device id, temperature, date/time stamp 
my ($firstLtr, $tBytes);					# 1st letter of write command,  two temperature bytes from response
my ($longDelay, $shortDelay);			# different delays according to 1-wire command
my ($n);									# general loop counter
my ($rRead, $rRdCnt, $err);				# flag to stop re-reads, re-read count & error id
my ($maxRead, $fName);					# serial read maximum time allowed, output data file name
my ($startTime, $loop);				# controls for main data gathering loop
# arrays
my (@initCmds, @romIds, @temperatures, @id_data);
#
# setup delays
# long delay for R and W commands
$longDelay=0.4;
# short delay for other commands
$shortDelay=0.2;
#
# setup serial port to be used
$port = Device::SerialPort->new("/dev/ttyAMA0");
#
# initialize port
$port->databits(8);
$port->baudrate(9600);
$port->parity("none");
$port->stopbits(1);
$port->write_settings;
#
# get list of ROM ID's to use
open (IDLIST, "/var/1w_files/romIds.txt");
$n=0;
while (<IDLIST>) {
        # get valid ROM ID's from file
        # each starts with a crc and ends with a family code
        chomp $_;
        $romIds[$n]=$_;
        $n++;
}
close (IDLIST);
#
# initial command sequences with length of responses
#   Reset, Skip rom & Convert temperatures
@initCmds = ("R",1, "W01CC\r",2, "W0144\r",2);
#
# use initial commands
for ($n=0; $n<=scalar(@initCmds)-2; $n+=2){
	# write command - send command to write subroutine
	&writePort($initCmds[$n]); 
	# read response
	$resp=&readPort($initCmds[$n], $initCmds[$n+1]+2);
}
#
# only let this part of the script run for a maximum of 1 minute
# set start time & loop flag
$startTime=time();
$loop=1;
while (time() < $startTime + 60 && $loop) {
# loop through all device rom IDs
#  to address them and get scratchpad data with temperatures
foreach (@romIds) {
	$rRead = 1;
	$rRdCnt = 0;
	while ($rRead) {
		# create Address command ('A' + rom ID)
		$id="A$_\r";
		# write Address
		&writePort($id);
		# read response - returns rom ID
		$resp=&readPort($id, 18);
		# request scratchpad data (9 bytes)
		&writePort("W0ABEFFFFFFFFFFFFFFFFFF\r");
		# read response - returns temperature in bytes 1 & 2
		$resp=&readPort("W0ABEFFFFFFFFFFFFFFFFFF\r", 22);
		#
        	# get date/time stamp - we need this now in case of error
        	$dtTmStamp=&dttmStamp;
        	# reformat rom ID to be compatible with Pi's format
        	#  e.g. 28-0000018a29ee (family code first, lower case & no crc)
        	$id=&reFmtRom($id);
		#
		# check crc of scratchpad data - in byte 9
		$resp=&crcChk($resp);
		# test for crc check digit error
		if($resp ne "Error"){
        		#  no error so convert 1st two scratchpad bytes to a temperature
			$tBytes=substr $resp,2,4;
        		$temp=&convT($tBytes);
			# check returned temperature for error message
			if (($temp eq "Error")){
				# invalid temperature error
        	        	$err ="err#2";
                                # log error
                                &errLog($id, $dtTmStamp, $err);
				$rRdCnt++;
				usleep(100000);
			}
			#
			} else {
			# crc error
			$temp = "Error";
			$err = "err#1";
                        # log error
                        &errLog($id, $dtTmStamp, $err);
			$rRdCnt++;
			usleep(100000);
		}
		if ($temp == "Error") {
			# error - so test number of re-reads
			if ($rRdCnt == 3) {
				# error code #3 = unrecoverable error
				$err = "err#3";
				# log error
				&errLog($id, $dtTmStamp, $err);
				# save temperature as 'Error' ($temp = 'Error')
				# save data - rom ID, time stamp and the temperature to an array
				push (@temperatures, "$id#$dtTmStamp $temp");
				# flag to stop re-reads
				$rRead = 0;
				}
			} else {
			# no error - so log and exit 'this' read
			# save data - rom ID, time stamp and the temperature to an array
			push (@temperatures, "$id#$dtTmStamp $temp");
			# flag to stop re-reads
			$rRead = 0;
		}
	}
}
# got to end of data collection - so can exit loop even if not timed out
$loop=0;
}
#
# save data collected in array to individual device files
foreach (@temperatures){
	# split each array element at '#'
	# id before '#' and data after '#'
	@id_data=split(/#/);
        # ID is filename - add it to path
        $fName="/var/1w_files/". $id_data[0];
        # open the data file for writing (append)
        open (DATAOUT, '>>', $fName);
                # add data to file
                print DATAOUT "$id_data[1]\n";
        close (DATAOUT);
}
#
exit 0;
#########################################################################
#
# subroutines and functions
#
#########################################################################
# write to port
sub writePort{
	# write command passed as a parameter
	my ($Cmd) = @_;
	# purge the receive buffer before we send a command
        $port->purge_rx;
	# write to port
	$port->write($Cmd);
}
#########################################################################
# read from port
sub readPort {
        # write command & length of data to be read passed as parameters
        my ($Cmd, $Len) = @_;
        # variables
        my ($sData, $Delay);
	my ($Second, $Minute, $Hour, $Day, $Month, $Year);
        #
	# clear buffers
	$port->lookclear;
	# get first letter of command
	$firstLtr=substr $Cmd,0,1;
        # delay after write - depends on command - W & R need longer
	if (($firstLtr eq "R") || ($firstLtr eq "W")){
		$Delay=$longDelay;
		} else {
		$Delay=$shortDelay;
	}
	# delay
        select(undef,undef,undef,$Delay);
        #
        # read from serial port
        $sData = "";
	# stop read wait if > 10 seconds
	$maxRead = time + 10;
	#
        until ("" ne $sData || time > $maxRead) {
                # wait for correct response length
                $sData = $port->read($Len);
        }
	# As 'R' (reset) has no returned data, return 'Reset'
	if ($firstLtr eq "R"){
        	return("Reset");
		} else {
		return($sData);
	}
}
##########################################################
# Date stamp function
sub dttmStamp {
        # no parameters passed to this function
        # variables
        my ($Year, $Month, $Day, $Hour, $Minute, $Second);
        my $dtStamp;
        #
        # get raw date & time data
        ($Second, $Minute, $Hour, $Day, $Month, $Year) = localtime(time);
        # convert year and month
        $Year += 1900;
        $Month++;
        # create the date, time stamp string
        $dtStamp=sprintf("%02d-%02d-%04d %02d:%02d:%02d",$Day,$Month,$Year,$Hour,$Minute,$Second);
        #
        return ($dtStamp);
}
##########################################################
# Convert temperature function
# returns value as t*1000 to match
#   format used by Raspberry Pi e.g 46.812 C is 46812
sub convT {
        # temperature passed to this function as a parameter
        #   two bytes in LSB, MSB order
        my ($hex) = @_;
        # make sure the parameter is treated as a hex number
        $hex=hex($hex);
        # variables
        my ($hexML, $Sign, $Mult, $Ctemp);
        # set multiplier - change to 0.0625 to return actual temp
        $Mult=62.5;
        #
        # change to MSB, LSB order (16 bit numbers)
        $hexML= unpack('n', pack('v', $hex));
        #
        # determine sign from most significant bit
        # mask off all but highest bit
        if ($hexML & 0x8000) {
                # most sig. bit is 1, (negative number)
                $Sign="-";
                }
                else
                {
                # most sig bit is 0, (positive number)
                $Sign="+";
        }
        # either use value as is (+ve) or do a 2's complement (-ve)
        # first mask off 5 highest bits - keep lowest 11 bits
        $hexML=$hexML & 0x07FF;
        if ($Sign eq "+"){
                # +ve so just multiply
                $Ctemp=$hexML * $Mult;
                }
                else {
                # -ve so 2's complement
                # complement
                $Ctemp = ~$hexML;
                # add one
                $Ctemp++;
                # we only want the lowest 11 bits (of the 64 used)
                $Ctemp=$Ctemp & 0x000007FF;
                # and multiply
                $Ctemp=$Ctemp * $Mult;
                # add '-' sign
                $Ctemp=$Sign . $Ctemp;
        }
        # test temperature value
        # -62500 & 85000 are not valid
        if ($Ctemp eq "-62500" || $Ctemp eq "85000"){
                #error
                $Ctemp = "Error";
        }
        return($Ctemp);
}
##########################################################
# Re-format ROM code function
sub reFmtRom {
        # reformat the ROM ID code to match format used
        # on Raspberry Pi e.g. 28-0000018a51a7
        # also ensures that hex characters are lower case
        # original ROM ID passed as a parameter
        my ( $rom ) = @_;
        # variables
        my $fId;
        #
        $fId = (substr $rom, -3,2) . "-" . (substr $rom, 3,12);
        return(lc($fId));
}
##########################################################
# crc check function
sub crcChk {
        # Function computes crc from 8 bytes of scratchpad data
        #  and compares it to 9th byte (transmitted crc)
        # Returns "Yes" if crc OK, else returns "No"
        #
        # Command code 'BE', 8 bytes of data and 1 byte crc 
        #  are passed as a single parameter to this function 
        my ($Data) = @_;
        #
        # variables
        my ($byte, $crc, $bit, $test);
        my ($i, $n);
        #
        # set initial crc value to zero
        $crc = 0b00000000;
        #
        # main loop - takes 8 bytes of scratchpad data 
        #  bytes are in positions 2/3 through 17/18 (zero based)
        #  positions 0/1 contain the command byte BE
        for ($i=2; $i<=17; $i+=2) {
                #convert pairs of hex digits into number
                $byte=hex(substr $Data, $i, 2);
                # sub-loop to read 8 bits from byte (LS bit first)
                for ($n=0; $n<=7; $n++){
                        #
                        # get LS bit of byte by applying mask
                        $bit = $byte & 0b00000001;
                        #
                        # exclusive OR the LS bit of the crc with the current data bit
                        $test = $crc ^ $bit;
                        # apply mask to get LS bit only
                        $test = $test & 0b00000001;
                        #
                        # test if result was 1 or 0
                       if ($test) {
                                #
                                # result was 1 so need to XOR, right shift &  make MS bit 1
                                #
                                # XOR crc with 0b00011000
                                $crc = $crc ^ 0b00011000;
                                # right shift
                                $crc = $crc >> 1;
                                # make MS bit 1 by OR'ing with 0b10000000
                                $crc = $crc | 0b10000000;
                                }
                                else {
                                #
                                # result was zero, so just right shift crc (MS bit will be 0)   
                                $crc = $crc >> 1;
                        }
                        # shift data byte to right so next bit is in LS bit position
                        $byte = ( $byte >> 1 );
                }
        }
        # compare calculated crc to transmitted crc
        if ($crc == hex(substr $Data, 18, 2)){
                return($Data);
                }
                else {
                return("Error");
        }
}
##########################################################
# log error to file
sub errLog{
        # ID, date/time stamp and error code are passed as a single parameter to this function 
        my ($eId, $eDtTmStamp, $eErr) = @_;
	# append information to end of error log
	open (DATAOUT, '>>', '/var/1w_files/err2.log');
        	# add date/timestamp, device ID and error code
        	print DATAOUT "$eId $eDtTmStamp $eErr\n";
        close (DATAOUT);
}
##########################################################
Regards

anita2R

lifebeginsatsixty
Posts: 26
Joined: Fri Mar 29, 2013 3:39 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Mon Feb 10, 2014 8:16 pm

Gpio pin 4 occasionally missing reads - read that it's possible to set the pin used with the 1-wire bus to a different number but expecting that there would still be the same problem; right? That the problem derives from the way the Pi handles the stuff, not from something associated with the physical pin itself.

Interrupts in the shell seem to be a thorny topic and I haven't gotten a handle on that yet. I don't want to get involved in Python to use their support if it's reasonable. Interrupt to tell me when the heater has turned on or off in the rice cooker.

I get to make my opto-isolators here and it doesn't look like a big deal, maybe just saw out the center leg of the ones made for counting parts flow or somesuch which I can get. Have the output switch 2-3 volts for a gpio input. Am using the twisted pair from an ethernet cable for signal-ground with an odd wire for power now. One of the other wires may get wound on a small toroid core to try as an ac current sensor.

Life goes on and the steaks are great.

lifebeginsatsixty

anita2r
Posts: 226
Joined: Sun Dec 23, 2012 6:55 pm
Location: Ottawa, Canada

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Mon Feb 10, 2014 9:38 pm

Hi,

Yes, occasional read failures appear to be an issue with the bitbanging used by the Pi, so using a different pin is unlikely to make it better.

As mentioned before, you can build in a re-read option, so if there is a failure - just wait a second and repeat. Depending on frequency of reading, you could try re-reading three or four times, to try and get a valid read.

Regards

anita2R

User avatar
ReadiesCards
Posts: 40
Joined: Sun May 13, 2012 5:22 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Thu Feb 20, 2014 6:29 am

Many thanks tonyhughes and anita2r - you saved the day!

Paul

lifebeginsatsixty
Posts: 26
Joined: Fri Mar 29, 2013 3:39 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Sun Mar 23, 2014 1:47 am

Well, I'm still at it. Recording the temps from the DS18B20 every 20 seconds while running the PID controller (controlled by the PT-100) has been a revelation. Now I want to also record when the water bath is on and off. Not by polling but by an interrupt. I've looked and read but haven't been able to piece it together, so I'll ask: how do I set up an interrupt for a gpio pin in a simple bash script? Also, as the input from a series resistor across an LED signalling when power is on to the water bath, is leading edge or trailing edge better to test for?

Thanks,
lifebeginsatsixty

PS And yes, anita2R, I will include a reread option for the DS18B20 for the controller.

User avatar
iinnovations
Posts: 621
Joined: Thu Jun 06, 2013 5:17 pm

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Tue Mar 25, 2014 2:07 pm

That's crazy talk regarding RJ45. I use this pinout: http://interfaceinnovations.org/images/ ... pid_io.jpg

I use extended runs all over the place in my home brewery.

I know I sound like a broken record, but for <$1 you can get a DS2483 and put it on I2C. It beats bitbanging, that is for sure. It will handle much longer buses due to signal processing, multiple devices ... it's just a much better way to go!

Colin
CuPID Controls :: Open Source browser-based sensor and device control
interfaceinnovations.org/cupidcontrols.html
cupidcontrols.com

User avatar
iinnovations
Posts: 621
Joined: Thu Jun 06, 2013 5:17 pm

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Wed Mar 26, 2014 5:52 am

Another question : Why are you using bash or shell when python is available on all debian distros and a much more powerful language?
CuPID Controls :: Open Source browser-based sensor and device control
interfaceinnovations.org/cupidcontrols.html
cupidcontrols.com

achrn
Posts: 374
Joined: Wed Feb 13, 2013 1:22 pm

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Wed Mar 26, 2014 8:29 am

iinnovations wrote:That's crazy talk regarding RJ45. I use this pinout: http://interfaceinnovations.org/images/ ... pid_io.jpg
That has the 1-wire data and the ground on different pairs. I prefer them to be a pair.

User avatar
iinnovations
Posts: 621
Joined: Thu Jun 06, 2013 5:17 pm

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Wed Mar 26, 2014 5:48 pm

achrn wrote:
iinnovations wrote:That's crazy talk regarding RJ45. I use this pinout: http://interfaceinnovations.org/images/ ... pid_io.jpg
That has the 1-wire data and the ground on different pairs. I prefer them to be a pair.
True, pairing with ground would be better. It is partly to support legacy devices. I have still not had issues with long runs with many, many sensors.

Colin
CuPID Controls :: Open Source browser-based sensor and device control
interfaceinnovations.org/cupidcontrols.html
cupidcontrols.com

lifebeginsatsixty
Posts: 26
Joined: Fri Mar 29, 2013 3:39 am

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Thu Mar 27, 2014 1:23 am

I'd like to do it in bash or maybe Perl, that's why. Save Python till later. Here's what I'm doing now.

w1-gpio and w1-therm modules are loaded at startup
gpio mode 7 input
gpio readall
cd .. && cd .. && sys/bus/w1/devices/w1_bus_master1/28-000002ce88da

I made an alias to do a read - simple, not even formatted.
alias cc1='cat w1_slave && cat < w1_slave >> /var/1w_files/28-000002ce88da'
echo `date` | cat >> /var/1w_files/28-000002ce88da

Then for a sous vide run I'll do this on the command line:
i=1; while ((i<=900)); do cc1; sleep 18; ((i++)); done

and have the temps through the run about every 20 seconds.

Works. (I don't pretend to know bash.) I'd like to also do something like,

Oh, and by the way, at the same time whenever this other pin goes high or low I want to note that and the time it happened (maybe 1 second resolution here; 20 seconds is fine for the temperature).

Reading the wiringPi info on multi-threading says to create a new thread thusly:
int piThreadCreate (name) ;

Then create a function with what I want the thread to do:
PI_THREAD (myThread)
{
.. code here to run concurrently with
the main program, probably in an
infinite loop
}

and start that thread in the main program:
x = piThreadCreate (myThread) ;
if (x != 0)
printf ("it didn't start\n")

OK. What I don't see and didn't find searching is how to make this into what I want to do, or something along the same lines I could use as an example and change (which of course is how I got the code I'm using for the read temperature).

I expect to read the change of state of an LED, on or off voltage, through a series resistor to the Pi. This is what I want to watch for and record by means of the new thread. The LED is driven by (via a 5v brick and voltage divider) power to the plug of the sous vide water pot. The PID starts sending the pot power? I want to know that the power came on and when. The PID turns off the power gong to the pot? I want to know that the power went off and when. That's it.

Sorry for the long post, hope it's clear.
lifebeginsatsixty

User avatar
iinnovations
Posts: 621
Joined: Thu Jun 06, 2013 5:17 pm

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Thu Mar 27, 2014 6:25 am

The reason I ask is that - having written plenty of shell scripts when I had no other choice - I find that python is much easier to write. On top of that, the majority of libraries out there for the Pi are based on Python, and as a result you can find pretty much anything you want as an example.

For 1Wire, if you don't want to use a bus master, I would suggest using owfs and the w1 kernel drivers. owpython works quite well, and you can skip all the parsing.

I don't think you need any multithreading. One loop. Check sensor, compare setpoint to control value. Turn on or off. Repeat.

Colin
CuPID Controls :: Open Source browser-based sensor and device control
interfaceinnovations.org/cupidcontrols.html
cupidcontrols.com

User avatar
BAStumm
Posts: 134
Joined: Fri Aug 23, 2013 3:37 pm
Location: Loon Lake, WA USA
Contact: Website

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Thu Mar 27, 2014 4:10 pm

I'm using this: https://www.olimex.com/Products/Modules ... e-hardware

Accepts a Type K thermocouple, has analog input (attach a current sensor for True RMS wattage feedback) and GPIO for pulsing a solid state relay. This allows for temperature and/or wattage control of heating and by customizing the firmware on the PIC of the mod-tc-mk2 you can include your own algorithm for PID temperature/wattage control.

I've worked with control of resistive heating elements for many years. If you want to avoid overshoot/undershoot of temperature then you need to keep a temperature history array to track the rate of change and adjust power to the heater before you reach the desired temperature. Knowing the wattage being applied can be very helpful as you can have your system learn over time the power level required for a certain temperature. Current sensing is not required for zero cross fired SSRs but is for phase angle control.

User avatar
iinnovations
Posts: 621
Joined: Thu Jun 06, 2013 5:17 pm

Re: TUTORIAL: DS18B20 temp sensor. No C or Python!!! Cost: $

Thu Mar 27, 2014 4:16 pm

I agree with a temperature history. It's simply necessary for PID - by definition.

Regarding thermocouples, they're simply the wrong tool for 95% or more of temperature applications. Their noise, poor resolution, the requirement for amplification and lookup tables, one-to-one dedicated interface per sensor, specialty wiring, and cost make them unattractive and I never use them unless I need to exceed the temperatures where a solid-state temperature sensor or thermistor will suffice. This is seldom.

-25C-125C for 1Wire temperature sensors, unique 64-bit ROM, multi-drop bus ... no competition.

Colin
CuPID Controls :: Open Source browser-based sensor and device control
interfaceinnovations.org/cupidcontrols.html
cupidcontrols.com

Return to “Automation, sensing and robotics”