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?
-
1From 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– Gerben2013年08月06日 19:57:00 +00:00Commented Aug 6, 2013 at 19:57
7 Answers 7
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.
-
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– Jim2016年12月12日 14:35:31 +00:00Commented 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– NoChecksum2018年02月20日 16:08:07 +00:00Commented 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– Bprodz2018年03月05日 18:47:43 +00:00Commented 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– Marco Poli2020年05月09日 21:01:55 +00:00Commented May 9, 2020 at 21:01
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
-
needs import subprocess import time to runPaul Anderson– Paul Anderson2014年05月20日 04:24:01 +00:00Commented May 20, 2014 at 4:24
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 0ドルD00
; 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', 0ドルD, 0ドルA, 0
Steady: DC.B ' and Steady', 0ドルD, 0ドルA, 0
Fall: DC.B ' and Falling', 0ドルD, 0ドルA, 0
Temp: DS 2
DC.B 0
TempOld:DS 2
TempNew:DS 2
-
3The 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– Marco Poli2013年08月07日 14:41:46 +00:00Commented Aug 7, 2013 at 14:41
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
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.
-
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– jc3032013年08月06日 18:16:10 +00:00Commented 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 piTheDoctor– TheDoctor2013年08月11日 01:48:19 +00:00Commented Aug 11, 2013 at 1:48
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
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.
get 6 different different I2C sensors with different different I2C address, if you have two sensors with same address it wont work.
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.