Python Exemplary - RPi Tutorial
deutsch     english    

TEMPERATURE SENSOR

The source code of all examples can be downloaded from here.

 

The temperature is one of the most important physical quantities to be measured in technical systems. There are many different types of temperature sensors: Some of them deliver a voltage directly, other transforms temperature changes to another quantity that is then converted to a voltage. Many modern temperature sensors are integrated with electronic circuits in a single package and output the temperature directly as digital data in a well-established protocol (typically I2C, SPI or 1-Wire).

 

 

Thermistors

 

Thermistors are thermally sensitive resistors. The relation between temperature T and resistance R is highly non-linear. Most thermistors have a Negative Temperature Coefficient (NTC) and exhibit a decrease of the resistance with increasing temperature. The characteristic can be approxmated by a decreasing exponential function. Also Positive Temperature Coefficient thermistors (PTC) are available.

In most cases the resistance changes are converted to voltage changes using the sensor as part of a voltage divider. In data processing systems the output voltage is then fed into a ADC and data transferred to a microprocessor.

 
Typical characteristics of NTCs and PTCs
 
Typical application

(R and RS may be interchanged)

Aim:
Measure the room temperature using a simple NTC.

Circuitry:
Use a breadboard and realize the following wiring with your favorite ADC (see previous ADC page for more information). Here the PCF8591 is used.

Program:

(to be done)

Remarks:
The result is inaccurate due to the following reasons:

  • The voltage change is small, so using a 8-bit ADC in the range 0..3.3V results in a bad temperature resolution
  • The relation from voltage to temperature is non-linear. The conversion is complicated
  • The thermistor shows a self-heating effect, because of its power dissipation
  • Thermistors are widely used for

Thermistors are widely use to detect a certain temperature level, e.g. to stabilize the temperature in a heater, refrigerator, etc. In these applications the absolute value of the temperature is of less importance.

 

 

IC Based Sensors With Analog Output

 

Temperature measurement is very important in many situations, as consequence temperature sensors comes in many different flavors. The LM35 family and TMP35/36/37 are integrated circuit sensors that can be used to measure temperature in quotidian range with a voltage output that is linear with the temperature. The scale factor is 10-20 mV/degree.

In this example we use the LM35, a 3-pin integrated-circuit device with an output voltage that is proportional to the temperature in degrees centigrandes and needs no calibration. Consult the datasheet for more information.

There is no need for additional components. Just connect the middle lead to an ADC of your choice.

The program displays the current temperature in degrees centigrade. Consider the following conversion: Since the sensor delivers a = 10 mV = 0.01 V per degrees centigrade, the output voltage is u = a * T. If the voltage u is applied to the 10-bit ADC powered with 3.3V, the digitized value returned to the program is v = u / 3.3 * 1023. So the relation between the temperature and the value returned from the ADC is v = 0.01 / 3.3 * 1023 * T = 3.1 * T.

Program:[►]

# RaspEasy7c.py
# LM35 temperature sensor

import smbus
import time
#from OLED1306 import OLED1306

def readData(port = 0):
    if port == 0:
        adc_address = 0x48
    elif port == 1:    
        adc_address = 0x4D
    rd = bus.read_word_data(adc_address, 0)
    data = ((rd & 0xFF) << 8) | ((rd & 0xFF00) >> 8)
    data = data >> 2
    return data

print "starting..."
#oled = OLED1306()
#oled.setFontSize(50)

bus = smbus.SMBus(1) 
while True:
    v = readData()
    T = v / 3.1
    print "T = %4.1f centigrades" %T
#    oled.setText(str(int(T + 0.5))) # rounded to int
    time.sleep(1)
Highlight program code (Ctrl+C copy, Ctrl+V paste)

 

 

IC Based Sensors With Digital Output

 


Sensors with I2C bus

The MCP9808 is a cheap and versatile high precision digital temperature sensor with an I2C interface. It's accuracy is typically +-0.25 °C and maximum +-0.5 °C in the temperature range of -20 to 100 °C. It is possibly the best choice to measure ambient temperature with the Raspberry Pi.


Because the chip is only available in SMT, it must be soldered to a SMT adapter or a MCP9808 breakout beard is used, e.g. from Adafruit. Connect VCC, GND, SDA and SCL pins to the GPIO. By wiring the address pins to GND, address 0x18 is selected.

temp9

hand1

If you use a breakout board, you should power it with 3.3V (and not with 5V), or you must remove the pull-up resistors at the SDA and SCL lines.

As you can see in the datasheet, a single I2C word read is necessary to get a temperature value. The data is encoded in the 16 bits returned by the SMBus read_word_data() function and some bit juggling is needed to extract the temperature. The datasheet contains a sample program that explains exactly what to do. It is ported to Python with explicatory comments in the following program.

Program:[►]

# Temp3.py
# Temperature sensor MCP9808

import smbus
import time

i2c_address        = 0x18
temp_register      = 0x05

def readTemp():
    v = bus.read_word_data(i2c_address, temp_register)
    hiByte = v & 0x00FF  # SMBus with reversed byte order
    loByte = (v >> 8) & 0x00FF
    hiByte = hiByte  & 0x1F # clear flag bit
    if hiByte & 0x10 == 0x10:  # temp < 0
        hiByte = hiByte & 0x0F  # clear sign
        temp = 256 - hiByte * 16 + loByte / 16.0 # scale
    else:
        temp = hiByte * 16 + loByte / 16.0 # scale
    return round(temp, 1)

print "starting..."
bus = smbus.SMBus(1) 
while True:
    t = readTemp()
    print "T =", t, "centigrades"  
    time.sleep(1)

Highlight program code (Ctrl+C copy, Ctrl+V paste)


Temperatur Sensor with 1-Wire bus

The DS18B20 can be used as digital thermometer in the range of -55 to 125 oC with +- 0.5 oC accuracy. Since it can be connected directly to the GPIO of the Raspberry Pi, it is the ideal solution for indoor and outdoor temperature measurements. The sensor communicates with the Raspberry Pi with the 1-Wire communication protocol developed by Dallas Semiconductor.

The protocol uses a single line (and ground) that is also called a bus, because every device is connected to it either as listener (high impedance) or as transmitter (pulling it down to ground for some time). The Raspberry Pi acts as the bus master and many bus slaves may be connected to the same line. In idle state, the bus is hold HIGH by a pull-up resistor and all connected slaves are listening.

The master then calls a slave by its address (8 bytes) which is unique for each slave device. To write a logic “1”, the bus line is pulled to ground for 1-15us, to write a logic “0", the bus is low for 60-120 us. To get a reply, the masters enters the listening state and the slave transmits data in the same format. So master and slaves can be transmitters and receivers, but only in one direction at a time. Follows an example of timing to send the byte b0011'0011 = 0x33 (LSB is sent first):

The protocol can be compared with Morse code, where dots and dashes are used. It can also be considered as a kind of Pulse Width Modulation PWM. The address is composed of a 1-byte family code, a 6 byte ID and a 1 byte CRC.

It is very simple to enable the 1-Wire protocol for the DS18B20 sensor with the current version of the NOOBS distribution, becauce the driver is part of the kernel. (In the current RaspiBrick SD-card distribution, 1-Wire protocol is already enabled for GPIO 4 (pin #7.) To activate the driver yourself, edit the file /boot/config.txt:

sudo nano /boot/config.txt

and add the line

dtoverlay=w1-gpio,gpiopin=4

(Set the gpiopin parameter for the GPIO pin you want to reserve. If you omit it, the defaut port GPIO 4 (pin # 7) is used.) Connect the 1-Wire slave device and reboot. Keep in mind that the 1-wire GPIO I/O port should not be used as normal I/O port from now on.

Aim:
Measure every second the room temperature with the DS18B20 digital thermometer chip (data sheet) and display the result in the console and (if available) on an attached display.

 

Circuitry:

The DS18B20 IC is fabricated in a TO-92 or SMT package. With the SMT version, use a module (from Adafruit or others) or solder the chip on a SMT adapter. In most modules the 4.7k pullup resistor is already include, otherwise insert it into the circuit. Connect the data line to the GPIO port that you configure for 1-Wire communication (standard: pin # 7)
 

The design of the 1-Wire driver is somewhat unusual, because data from the sensor cannot be read by a simple function call. After booting the Raspberry Pi, the driver polls the sensor in regular time intervals and writes the result into a file that can be analysed by a user program written in any language including shell scripts. This is a simple way to pass data from one process to another.

(The 1-Wire communication cannot be handled by a Python program, because of the strict timing requirements with pulses in the order of 10 µs)

At boot time, the driver writes the addresses of all active 1-Wire devices in the file

<masterFolder>w1_master_slaves

where we use the notation:

masterFolder = /sys/devices/w1_bus_master1/

For every active slave a subdirectory structure in <masterFolder> is created. Its name is composed by the hexadecimal digits of the address in the format

ff-nnnnnnnnnnnn

where f are the digits for the family (1 byte) and n the ID (6 bytes).

(If you remove the dtoverlay liine in /boot/config.txt, the directory structure of <masterFolder> is erased at the next boot.)

 

Example of the <w1-root> folder

When you enter the subdirectory you find the file structure shown at the right. The current data can be retrieved from the file w1_slave. There are two lines like:

6d 01 4b 46 7f 03 10 70 : crc=70 YES
6d 01 4b 46 7f 03 10 70 : crc=70 t=22812

You find the current temperature in millidegrees centigrades at the end of the second line (starting from position 29).

This information is the key to write your Python program to extract the temperature value.

 

Example of the slave folder

Program:[►]

# Temp1.py

import time
from py7seg import Py7Seg # xxx

masterFolder = "/sys/devices/w1_bus_master1/"

def getSlaveFolders():
    # Get list of all 1-Wire slave folders
    file = open(masterFolder + "w1_master_slaves")
    slaveFolders = file.read().splitlines()
    file.close()
    return slaveFolders

def getTemperature(slaveFolder):
      # Read content of corresponding w1_slave file. Format:
      # 6f 01 4b 46 7f ff 01 10 67 : crc=67 YES
      # 6f 01 4b 46 7f ff 01 10 67 t=22937
      file = open(masterFolder + slaveFolder + '/w1_slave')
      lines = file.read().splitlines()
      file.close()
    
      # Extract temperature from second line
      temperature = float(lines[1][29:]) / 1000
      return temperature

ps = Py7Seg() # xxx
slaveFolders = getSlaveFolders()
while True:
    # Extract temperature from first slave
    temp = getTemperature(slaveFolders[0])
    print("T = %6.2f deg" %temp)
    w = "%4.1f" %temp
    ps.showText(w[0] + w[1] + w[3] + '#'], dp = [0, 1, 0])  
    time.sleep(1)
Highlight program code (Ctrl+C copy, Ctrl+V paste)

Remarks:

You will not get temperature values more frequent than about every second, because getTemperature() blocks until a new value is written in the file. If you do not have a ELV display or you use another display, comment out or modify the lines marked with xxx.

 

Temperatur and Humidity Sensor with 1-Wire bus

The DHT11, DHT22 (also called AM2302) are modules that measure temperature and humitiy and transfer the digitized values over a 1-Wire bus. To use them with the Raspberry Pi, a 1-Wire driver written in C/C++ has to be used, because of the tight requirements for the timing using short pulses in the order of 10-100 us. At the moment two driver sources are available, one from Adafruit und one that is part of the pigpio library. The installation process for both packages is simple, but the pigpio version needs a daemon to be started before the user program runs.

To install the package from Adafruit you may follow the instructions from their homepage (http://www.adafruit.com). The software is already installed in the current version of our Raspibrick SD card distribution.

Aim:
Measure every second the room temperature and humidity with the DHT11 or DHT22/AM2302 sensor and display the result in the console and (if available) on an attached display.

Circuitry:

If you use a sensor mounted on a small adapter board, the pullup resistor is normally included. Connect the data line to the GPIO port that you want to use for 1-Wire communication (usually pin #7).

hand1

If you use an adapter board, you should power it with 3.3V (and not with 5V), or you must remove the pull-up resistor.

 

 

Program:[►]

# DHT1.py

import Adafruit_DHT
import time
from py7seg import Py7Seg # xxx

ps = Py7Seg() # xxx
SENSOR_TYPE = Adafruit_DHT.DHT11
P_DHT = 4 # GPIO numbering (Pin # 7)
while True:
    hum, temp = Adafruit_DHT.read_retry(SENSOR_TYPE, P_DHT)
    if temp == None:
        t = "--.-"
    else:
        t = "%2.1f" %temp
    if hum == None:
        h = "--.-"
    else:
        h = "%2.1f" %hum
    print "Temperature", t, "Humitity", h
    ps.showText("t" + t[0] + t[1] + t[3], dp = [1, 0, 0]) # xxx 
    time.sleep(3)    
    ps.showText("h" + h[0] + h[1] + h[3], dp = [1, 0, 0]) # xxx    
    time.sleep(3)  
Highlight program code (Ctrl+C copy, Ctrl+V paste)