21

I have seen plenty of examples for using one temperature sensor with the Raspberry Pi, however, how can I multiplex 5-6 temperature sensors to a Raspberry Pi? I want to read the temperature from several sources simultaneously.

Can I simply assign the GPIO pins on the Raspberry Pi to read from each sensor, essentially replicating the same configuration for one sensor, or do I need some kind of multiplexor that all the sensors would plug into then in turn that would send data in parallel to the Raspberry Pi?

1
  • 1
    From the datasheet: "Each DS18B20 has a unique 64-bit serial code, which allows multiple DS18B20s to function on the same 1-Wire bus.". Try reading the datasheet (don't worry if you don't understand everything).
    – Gerben
    Aug 6, 2013 at 19:57

7 Answers 7

19

Given that your sensor is a DS18B20, which uses the 1-wire protocol, and that the 1-wire driver on the latest RPi Linux kernel can do as many as 64 different addresses on the same 1-wire bus:

If you just connect all of your sensors to the same 3 pins (3v3, GND and GPIO4 - pin number 4 on the connector), you will read their outputs from /sys/bus/w1/devices/28*/w1_slave where the 28* is the individual unique 1-wire address. Check adafruit's tutorial.

Don't forget that you need the 4K7 resistor pulling up on GPIO4, as the internal pull up of the Pi gives you roughly 50K, and that is too much for the sensor, so you will need this extra component. Use only one 4K7 resistor between 3V3 and GPIO4 for any number of sensors connected to the 1-wire bus.

The 1-wire bus receives its name for the ability to supply the needed power through only 1 wire, in some conditions. This is called "parasitic power". Using this "feature" of the protocol will not work with multiple connected sensors. So be sure that you have all 3 pins connected to the array of 18x20s.

4
  • Hey there, I'm currently in the design process of making a 10-sensor temperature logger with some DS18B20s, I've pretty much got what you're saying above except for the parasitic power bit: You should just make sure you are not trying to use parasitic power. What do you mean by this? Do I need to use an external power supply instead of the 3.3V from pin1 on the Pi's GPIO? Or is parasitic power if I only use GND+Data and not the 3V3? - it refused to hot-link to your username :-(
    – Jim
    Dec 12, 2016 at 14:35
  • 2
    @Jim Parasitic power is a feature of the DS18B20 whereby you connect only GND and IO pins to the bus, not VCC. Marco Poli is saying that you shouldn't run it in this mode, instead connecting all 3 wires from the DS18B20s to the Pi. You won't need an external power supply.
    – NoChecksum
    Feb 20, 2018 at 16:08
  • Hi regarding you comment, this is hardcoded in the driver does that mean that connecting temperature sensors to a different GPIO pin (or multiple GPIO pins) will not work?
    – Bprodz
    Mar 5, 2018 at 18:47
  • Bprodz "hardcoded" means that you cannot change it after it has been compiled. To change it you would need to alter the source code and compile it again. So, given that the GPIO pin and the number of sensors are both hardcoded (for the 1-wire bus, I mean), so changing the pin would require you to edit the source code and recompile it. I don't know if it is at all possible to have multiple pins for this bus type and this driver.
    – Marco Poli
    May 9, 2020 at 21:01
4

For reference, here is a short snippet of Python to bitbang the 1-wire GPIO and return the the temperature reading for the first sensor. It should be straightforward enough to modify to return temps for all connected sensors as a list or something similar.

import subprocess, time

def read_onewire_temp():
    '''
    Read in the output of /sys/bus/w1/devices/28-*/w1_slave
    If the CRC check is bad, wait and try again (up to 20 times).
    Return the temp as a float, or None if reading failed.
    '''
    crc_ok = False
    tries = 0
    temp = None
    while not crc_ok and tries < 20:
        # Bitbang the 1-wire interface.
        s = subprocess.check_output('cat /sys/bus/w1/devices/28-*/w1_slave', shell=True).strip()
        lines = s.split('\n')
        line0 = lines[0].split()
        if line0[-1] == 'YES':  # CRC check was good.
            crc_ok = True
            line1 = lines[1].split()
            temp = float(line1[-1][2:])/1000
        # Sleep approx 20ms between attempts.
        time.sleep(0.02)
        tries += 1
    return temp
1
  • needs import subprocess import time to run May 20, 2014 at 4:24
2

Talking over a 1-wire bus can be painful. Whether you're talking to 1 sensor or 100, you'll need to think about timing. I wrote some code for the DS18B20 a few years ago, but it's in Assembly. If it's of any use, here:

;***************************************************************
;Title:     Temperature Logger
;Description:   Polls temperature every two seconds and returns a value
;       in degC as well as the slope (rising, falling, steady)
;***************************************************************
Screen  EQU $F684
;System Equates
PortA   EQU $0000
DDRA    EQU $0002
;Program Equates
TxPin   EQU %00000001
RxPin   EQU %00000010
IntPin  EQU %10000000
;Commands
SkipROM EQU $CC
Convert EQU $44
ReadPad EQU $BE
;Constants
ASCII_0 EQU 48
Poll_D  EQU 2000
;Macros
TxOn    macro    ; Send the 1-wire line Low
    MOVB    #TxPin,DDRA
    MOVB    #$00,PortA
    endm

TxOff   macro    ;Releases the 1-wire line letting it return to High.
    MOVB    #$00,DDRA
    endm


;-------------------------------------
;Main 
;-------------------------------------
    ORG $0D00

        ; Clear registers and initialise ports
Start:  MOVB    #$00, DDRA
Main:   LDD     #$00
        JSR     Init
        LDAA    #SkipROM
        JSR     Write
        LDAA    #Convert
        JSR     Write
        JSR     Wait
        JSR     Init
        LDAA    #SkipROM
        JSR     Write
        LDAA    #ReadPad
        JSR     Write
        JSR     Read    ; read first 8 bits
        TFR     A, B
        JSR     Read    ; read second 8 bits
        ; Convert bytes to BCD
        LSRB
        LSRB
        LSRB
        LSRB
        STD     TempNew
        PSHA
        PSHB
        LDAB    #6
        MUL
        TBA
        PULB
        ABA
        CLRB
Conv_Lp:SUBA    #10
        BMI     Conv_Dn
        INCB
        BRA     Conv_Lp
Conv_Dn:ADDA    #10
        TFR     A, Y
        PULA
        ABA
        TFR     Y, B
        ; convert BCD bytes to ASCII and store in temp register
        LDX     #Temp
        ADDA    #ASCII_0
        STAA    0, X
        INX
        ADDB    #ASCII_0
        STAB    0, X
        LDX     #OutUp  ; print 'The current temp is '
        JSR     Echo
        LDX     #Temp   ; print ASCII bytes
        JSR     Echo
        ; compare stored temp with previously stored and print 'rising', 'falling' or 'steady'
        LDD     TempNew
        SUBD    TempOld
        BGT     Rising
        BEQ     Same
        LDX     #Fall
        BRA     EchDir
Rising: LDX     #Rise
        BRA     EchDir
Same:   LDX     #Steady
EchDir: JSR     Echo
        ; wait 2 seconds
        LDX     #Poll_D
Bla_Lp: JSR     Del1ms
        DBNE    X, Bla_Lp
        ; set new temp as old temp and loop
        LDD     TempNew
        STD     TempOld
        JMP     Main
        SWI


;-------------------------------------
;Subroutines
;-------------------------------------
Init:   TxOn        ; turn pin on
        uDelay  500 ; for 480us
        TxOff       ; turn pin off
        uDelay  70  ; wait 100us before reading presence pulse
        JSR Wait
        RTS
Wait:   LDX #120
Wait_Lp:JSR Del1ms
        DBNE    X, Wait_Lp
        RTS

Write:  PSHX
        PSHA
        LDX     #8  ; 8 bits in a byte
Wr_Loop:BITA    #%00000001
        BNE     Wr_S1   ; bit is set, send a 1
        BEQ     Wr_S0   ; bit is clear, send a 0
Wr_Cont:LSRA    ; shift input byte
        uDelay  100
        DBNE    X, Wr_Loop  ; shifted < 8 times? loop else end
        BRA     Wr_End
Wr_S1:  TxOn    ; on for 6, off for 64
        uDelay  6
        TxOff
        uDelay  64
        BRA     Wr_Cont
Wr_S0:  TxOn    ; on for 60, off for 10
        uDelay  60
        TxOff
        uDelay  10
        BRA     Wr_Cont
Wr_End: PULA
        PULX
        RTS

Read:   PSHB
        LDAB    #%00000001
        CLRA
Rd_Loop:TxOn    ; on for 6, off for 10
        uDelay  6
        TxOff
        uDelay  10
        BRSET   PortA, #RxPin, Rd_Sub1  ; high? add current bit to output byte
Rd_Cont:uDelay  155 ; delay and shift.. 0? shifted 8 times, end
        LSLB
        BNE     Rd_Loop
        BRA     Rd_End
Rd_Sub1:ABA 
        BRA     Rd_Cont
Rd_End: PULB
        RTS

uDelay  macro    ;Delay a mutliple of 1us (works exactly for elays > 1us)
        PSHD
        LDD   #\1
        SUBD  #1
        LSLD
\@LOOP  NOP
        DBNE  D, \@LOOP
        PULD
        endm

;-------------------------------------
;General Functions
;-------------------------------------
; delays
Del1us: RTS

Del1ms: PSHA
        LDAA    #252
Del_ms: JSR     Del1us
        JSR     Del1us
        JSR     Del1us
        CMPA    $0000
        CMPA    $0000
        NOP
        DECA
        BNE     Del_ms
        CMPA    $0000
        NOP
        PULA
        RTS

; display text from address of X to \0
Echo:   PSHY
        PSHB
        LDAB    0, X
Ech_Lp: LDY Screen
        JSR 0, Y
        INX
        LDAB    0, X
        CMPB    #0
        BNE Ech_Lp
        PULB
        PULY
        RTS

Interrupt:
        SWI
        RTI

;-------------------------------------
;Variables
;-------------------------------------
    ORG   $0800
OutUp:  DC.B    'The current temperature is ', 0
Rise:   DC.B    ' and Rising', $0D, $0A, 0
Steady: DC.B    ' and Steady', $0D, $0A, 0
Fall:   DC.B    ' and Falling', $0D, $0A, 0
Temp:   DS  2
    DC.B    0
TempOld:DS  2
TempNew:DS  2
1
  • 3
    The Raspberry pi already has a kernel module for 1-wire and another specifically for 1-wire temperature sensors (that includes de DS18B20). Just load the modules and the temperatature is read from a file, with a reagular file read command. You don't need to manually implement the protocol, if you choose to use the ready-modules.
    – Marco Poli
    Aug 7, 2013 at 14:41
2

If interested, here's a guide I wrote for using a DS18B20 temp sensor (which as stated above can be chained with as many as you want using the same GPIO pin on the Pi) with a Raspberry Pi and some Pyhton code that posts it to a RESTful service that aggregates and displays the temperatures in charts and diagrams on a web site. All code public on the specified GitHub account. http://macgyverdev.blogspot.se/2014/01/weather-station-using-raspberry-pi.html

1

What kind of temperature sensor are you using? If you have something like a DS18B20 then you can chain up to 18446744073709551615 sensors, if you had that many.

2
  • The sensor is a DS18B20 type indeed, however can you please elaborate what is meant by chaining, and if possible, point to a source for the implementation of such a technique. How would one differentiate between the sensor inputs if they were chained? I need to acquire and the output of graph temperature sensor 1, temperature sensor 2....temperature sensor n.
    – jc303
    Aug 6, 2013 at 18:16
  • 2
    @JadCooper each ds18b20 sensor has a 16-bit serial number in it.nwhen you address a sensor with that, it returns data from only that sensor. See (this tutorial)[learn.adafruit.com/… for using them on the pi
    – TheDoctor
    Aug 11, 2013 at 1:48
0

To answer:

how can I multiplex 5-6 temperature sensors to a Raspberry Pi?

There are add on modules you can get that have several buses to connect to the pi.
This video compares their speeds: https://www.youtube.com/watch?v=YbWidNBycls He ends up using a recompiled kernel to achieve multiple GPIO communicating with multiple sensors. He hasn't posted his results on how he got it. But it is possible to multiplex it instead of using just one pin.

Update. He has posted now. He connected 81 sensors to 9 separate GPIO and was able to get all the temperatures in under 3 seconds: https://www.youtube.com/watch?v=JW9wzbp35w8

0

the ideal way to read multiple sensor is use I2C sensors.

this is the only way you can chain multiple sensors together or you can use analog sensors but they will take lot of analog pins but i2c will use only 2 lines. lets say you are using Pi2/3, then i will suggest get a raspberry Pi hat which has I2C port so that you can connect all your i2c devices with Pi within seconds and it will make sure your hardware is correct.

now you have the Pi with an I2C adpter let move on the sensor part. TI,AD,NXP,freescale and lot of other companies make temp sensor with I2C but you want to connect more then one sensor so there are two options.

  1. get 6 different different I2C sensors with different different I2C address, if you have two sensors with same address it wont work.

  2. you can get sensors with address line and just change address and you can connect them with Pi without any address conflict. i will suggest use this TMP 100 sensor i prefer this one because it has 2 address line with floating address line support so you can hookup 6 sensor with one i2c line.

there are advantage of using same sensors are that you dont have to read 6 datasheet to write your code you will need to study one datasheet and write the code its way easy. if your all sensors are same then you will have better results to compare.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.