Hidden away in the Pico MicroPython guide is a hint that there may be more modules installed in the system than they let on. In the section about picotool, the guide has a seemingly innocuous couple of lines:
frozen modules: _boot, rp2, ds18x20, onewire, uasyncio, uasyncio/core, uasyncio/event, uasyncio/funcs, uasyncio/lock, uasyncio/stream
The third and fourth ‘frozen modules’ are a giveaway: it shows that support for the popular Dallas/Maxim DS18x20 1-Wire temperature sensors is built in. Nowhere else in the guide are they mentioned. I guess someone needs to write them up …
DS18x20 digital temperature sensors — usually sold as DS18B20 by Maxim and the many clone/knock-off suppliers — are handy. They can report temperatures from -55 to 125 °C, although not every sensor will withstand that range. They come in a variety of packages, including immersible sealed units. They give a reliable result, free from ADC noise. They’re fairly cheap, the wiring’s absurdly simple, and you can chain long strings of them together from the same input pin and they’ll all work. What they aren’t, though, is fast: 1-Wire is a slow serial protocol that takes a while to query all of its attached devices and ferry the results back to the controller. But when we’re talking about environmental temperature, querying more often than a few times a minute is unnecessary.
So this is the most complex way you can wire up a DS18x20 sensor:
and this is how it’s wired:
DS18X20 Pico ========= ========= VDD → 3V3 / --47 kΩ-- / DQ → GP22 GND → GND (47 kΩ resistor between DQ and 3V3 as pull-up)
Adding another sensor is no more complicated: connect it exactly as the first, chaining the sensors together —
The code is not complex, either:
# Raspberry Pi Pico - MicroPython DS18X20 Sensor demo # scruss - 2021-02 # -*- coding: utf-8 -*- from machine import Pin from onewire import OneWire from ds18x20 import DS18X20 from time import sleep_ms from ubinascii import hexlify # for sensor ID nice display ds = DS18X20(OneWire(Pin(22))) sensors = ds.scan() while True: ds.convert_temp() sleep_ms(750) # mandatory pause to collect results for s in sensors: print(hexlify(s).decode(), ":", "%6.1f" % (ds.read_temp(s))) print() sleep_ms(2000)
This generic code will read any number of attached sensors and return their readings along with the sensor ID. The sensor ID is a big ugly hex string (the one I’m using right now has an ID of 284c907997070344, but its friends call it ThreeFourFour) that’s unique across all of the sensors that are out there.
If you’re reading a single sensor, the code can be much simpler:
# Raspberry Pi Pico - MicroPython 1x DS18X20 Sensor demo # scruss - 2021-02 # -*- coding: utf-8 -*- from machine import Pin from onewire import OneWire from ds18x20 import DS18X20 from time import sleep_ms ds = DS18X20(OneWire(Pin(22))) sensor_id = ds.scan() # the one and only sensor while True: ds.convert_temp() sleep_ms(750) # wait for results print(ds.read_temp(sensor_id), " °C") sleep_ms(2000)
The important bits of the program:
- Tell your Pico you have a DS18x20 on pin GP22:
ds = DS18X20(OneWire(Pin(22)))
- Get the first (and only) sensor ID:
sensor_id = ds.scan()
- Every time you need a reading:
- Request a temperature reading:
- Wait for results to come back:
- Get the reading back as a floating-point value in °C:
- Request a temperature reading:
That’s it. No faffing about with analogue conversion factors and mystery multipliers. No “will it feel like returning a result this time?” like the DHT sensors. While the 1-Wire protocol is immensely complicated (Trevor Woerner has a really clear summary: Device Enumeration on a 1-Wire Bus) it’s not something you need to understand to make them work.