Overview
In this tutorial we will read the Temperature Sensor Value from Raspberry Pi Pico. The Raspberry Pi Pico has internal Temperature Sensor connected to one of a few special pins called ADCs or Analog-to-Digital Converters.
We will connect an I2C OLED Display to the Raspberry Pi Pico & read the Temperature Data from the Sensor. We will then display the temperature on OLED Screen. You can use the mathematical equation to convert the Celcius value to Fahrenheit. You can check the Raspberry Pi Getting Started Tutorial to learn more about its specifications, pins & details.
Bill of Materials
You can buy the Raspberry Pi Pico Board along with the OLED Display Module from the following link.
| S.N. | Components Name | Quantity | Purchase Links |
|---|---|---|---|
| 1 | Raspberry Pi Pico | 1 | Amazon | AliExpress |
| 2 | OLED Display | 1 | Amazon | AliExpress |
| 3 | Jumper Wires | 4 | Amazon | AliExpress |
| 4 | Breadboard | 1 | Amazon | AliExpress |
Hardware Setup
Since we want to display the temperature value on OLED Display, there should be a connection between Raspberry Pi Pico & OLED. The connection diagram is given below.
Connect the SDA & SCL pin of OLED Display to Raspberry Pi Pico GP8 & GP9 Pin respectively. You can use the breadboard to assemble the circuit as shown below.
Temperature Sensor of Raspberry Pi Pico
The internal temperature sensor that comes with the Raspberry Pi Pico is connected to one of the ADCs or Analog-to-Digital Converters. The ADC pin supports a range of values, which is determined by the input voltage applied to the pin.
In the RP2040 Pico Board, the ADC pins support 12-bits, which means that the value can go from 0 to 4095. But the MicroPython code can scale the ADC values to a 16-bit range. So we effectively get the range from 0 to 65535. The microcontroller works at 3.3 V, which means that an ADC pin will return a value of 65535 when 3.3 V is applied to it or 0 when there is no voltage. We can obtain all the in-between values when the voltage applied to the pin is between 0 and 3.3 V.
The ADC pins in the Pico board use their own numbering scheme instead of going by their GPIO pin number. In the pin diagram above you can see the pins labeled ADC0, ADC1, ADC2, and ADC_VREF (technically ADC3), which are the four externally accessible ADC pins. The temperature sensor does not have a physical pin in the board but is accessed as ADC4.
Reading the Temperature Value with MicroPython Code
Now let us see the Temperature Sensor Code for Raspberry Pi Pico. Copy the following Code & hit download & run button.
|
1 2 3 4 5 6 7 8 9 10 11 |
import machine import utime sensor_temp = machine.ADC(4) conversion_factor = 3.3 / (65535) while True: reading = sensor_temp.read_u16() * conversion_factor temperature = 27 - (reading - 0.706)/0.001721 print(temperature) utime.sleep(2) |
The Shell Window will start displaying the temperature value in degree Celcius.
Code Explanation
|
1 2 3 4 5 |
import machine import utime sensor_temp = machine.ADC(4) conversion_factor = 3.3 / (65535) |
We first import machine & utime. The machine module provides the ADC() class to work with ADC pins.
|
1 |
reading = sensor_temp.read_u16() * conversion_factor |
If you print the value of the temperature value you are going to get an integer number between 0 and 65535. So, we have to convert this value either to the Celsius or Fahrenheit degree scales.
The temperature sensor works by delivering a voltage to the ADC4 pin that is proportional to the temperature. From the datasheet, a temperature of 27 degrees Celsius delivers a voltage of 0.706 V. With each additional degree the voltage reduces by 1.721 mV or 0.001721 V. The first step in converting the 16-bit temperature is to convert it back to volts, which is done based on the 3.3 V maximum voltage used by the Pico board.
|
1 |
temperature = 27 - (reading - 0.706)/0.001721 |
With this conversion, the temperature value holds a value between 0 and 3.3. We again have to do the second conversion which brings the temperature to the Celsius scale.
|
1 |
fahrenheit_degrees = celsius_degrees * 9 / 5 + 32 |
If you want to convert the temperature value from degree Celcius to Fahrenheit, you can use this mathematical equation.
Displaying the Raspberry Pi Pico Temperature Values on OLED
Now let us write an additional code to display the temperature value on OLED Screen. For this we need to write a OLED Driver code first as SSD1306 Driver is not available. The whole code is divided into 2 part.
1. ssd1306.py
2. Main.py
ssd1306.py
Open a New Tab & copy the following code. Save the file by the name ssd1306.py.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces from micropython import const import framebuf # register definitions SET_CONTRAST = const(0x81) SET_ENTIRE_ON = const(0xA4) SET_NORM_INV = const(0xA6) SET_DISP = const(0xAE) SET_MEM_ADDR = const(0x20) SET_COL_ADDR = const(0x21) SET_PAGE_ADDR = const(0x22) SET_DISP_START_LINE = const(0x40) SET_SEG_REMAP = const(0xA0) SET_MUX_RATIO = const(0xA8) SET_COM_OUT_DIR = const(0xC0) SET_DISP_OFFSET = const(0xD3) SET_COM_PIN_CFG = const(0xDA) SET_DISP_CLK_DIV = const(0xD5) SET_PRECHARGE = const(0xD9) SET_VCOM_DESEL = const(0xDB) SET_CHARGE_PUMP = const(0x8D) # Subclassing FrameBuffer provides support for graphics primitives # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html class SSD1306(framebuf.FrameBuffer): def __init__(self, width, height, external_vcc): self.width = width self.height = height self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): for cmd in ( SET_DISP | 0x00, # off # address setting SET_MEM_ADDR, 0x00, # horizontal # resolution and layout SET_DISP_START_LINE | 0x00, SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 SET_MUX_RATIO, self.height - 1, SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 SET_DISP_OFFSET, 0x00, SET_COM_PIN_CFG, 0x02 if self.width > 2 * self.height else 0x12, # timing and driving scheme SET_DISP_CLK_DIV, 0x80, SET_PRECHARGE, 0x22 if self.external_vcc else 0xF1, SET_VCOM_DESEL, 0x30, # 0.83*Vcc # display SET_CONTRAST, 0xFF, # maximum SET_ENTIRE_ON, # output follows RAM contents SET_NORM_INV, # not inverted # charge pump SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14, SET_DISP | 0x01, ): # on self.write_cmd(cmd) self.fill(0) self.show() def poweroff(self): self.write_cmd(SET_DISP | 0x00) def poweron(self): self.write_cmd(SET_DISP | 0x01) def contrast(self, contrast): self.write_cmd(SET_CONTRAST) self.write_cmd(contrast) def invert(self, invert): self.write_cmd(SET_NORM_INV | (invert & 1)) def show(self): x0 = 0 x1 = self.width - 1 if self.width == 64: # displays with width of 64 pixels are shifted by 32 x0 += 32 x1 += 32 self.write_cmd(SET_COL_ADDR) self.write_cmd(x0) self.write_cmd(x1) self.write_cmd(SET_PAGE_ADDR) self.write_cmd(0) self.write_cmd(self.pages - 1) self.write_data(self.buffer) class SSD1306_I2C(SSD1306): def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): self.i2c = i2c self.addr = addr self.temp = bytearray(2) self.write_list = [b"\x40", None] # Co=0, D/C#=1 super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.temp[0] = 0x80 # Co=1, D/C#=0 self.temp[1] = cmd self.i2c.writeto(self.addr, self.temp) def write_data(self, buf): self.write_list[1] = buf self.i2c.writevto(self.addr, self.write_list) class SSD1306_SPI(SSD1306): def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): self.rate = 10 * 1024 * 1024 dc.init(dc.OUT, value=0) res.init(res.OUT, value=0) cs.init(cs.OUT, value=1) self.spi = spi self.dc = dc self.res = res self.cs = cs import time self.res(1) time.sleep_ms(1) self.res(0) time.sleep_ms(10) self.res(1) super().__init__(width, height, external_vcc) def write_cmd(self, cmd): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(0) self.cs(0) self.spi.write(bytearray([cmd])) self.cs(1) def write_data(self, buf): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(1) self.cs(0) self.spi.write(buf) self.cs(1) |
main.py
After uploading the SSD1306.py, create a new tab again and copy the following code. Save this code as a name main.py.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# Display Image & text on I2C driven ssd1306 OLED display from machine import Pin, I2C from ssd1306 import SSD1306_I2C import machine import utime sensor_temp = machine.ADC(4) conversion_factor = 3.3 / (65535) WIDTH = 128 # oled display width HEIGHT = 64 # oled display height i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=200000) # Init I2C using pins GP8 & GP9 (default I2C0 pins) print("I2C Address : "+hex(i2c.scan()[0]).upper()) # Display device address print("I2C Configuration: "+str(i2c)) # Display I2C config oled = SSD1306_I2C(WIDTH, HEIGHT, i2c) # Init oled display while True: reading = sensor_temp.read_u16() * conversion_factor temperature = 27 - (reading - 0.706)/0.001721 print(temperature) # Clear the oled display in case it has junk on it. oled.fill(0) # Add some text oled.text("Temp: ",6,8) oled.text(str(round(temperature,2)),50,8) oled.text("*C",95,8) utime.sleep(2) # Finally update the oled display so the image & text is displayed oled.show() |
Once you run the code, the OLED Display will start displaying the temperature value on OLED Screen.
This is how you can read the temperature data using MicroPython Temperature Sensor Code for Raspberry Pi Pico Board. You can also connect an external temperature sensor like DS18B20 with RPI Pico to read external temperatures.












10 Comments
The calculated chip temperature depends critically of the actual Vref value being used in the calculation.
The code example uses a conversion_factor of 3.3 V from the Vdd, however the data sheet teaches us that the 200R resistor R7 causes a voltage drop of 34 mV from Vdd, thus the nominal Vref is only 3.266 V. The actual value may vary, so I measured Vdd(real)=3.258 V and Vref(real)=3.22 V (drop 38 mV).
Calculated temperature ranges vary from 20 to 31 ˚C with this variation of Vref, for the same ADC raw reading.
I attempted to read pin 4 as ADC with Micropython 1.16, but I get the following error:
I found the answer:
temp = ADC(ADC.CORE_TEMP)
this was really the best coding guide i could ever find
To indicate at temp and turn a light on and print current temp. Its sloppy but it works. Thanks for the tut
import machine
import utime
led = machine.Pin(25, machine.Pin.OUT)
while True:
led.value(1)
utime.sleep(15)
print(‘ ‘)
led.value(0)
utime.sleep(15)
print(‘Current Temp’)
“temperature = temperature * 9 / 5 + 32”
Thanks for this! I was beating my brains in trying to get that right. I knew the conversion math, but was trying to solve it too soon in the code. 😀
Why bother converting the temperature to Fahrenheit when you already have it in Celsius?
Thank you for your write up. Works very well.
How can we change the size of the fonts?
Thanks for this! Out of curiosity, I tried it on Pimoroni Pico Lipo and it worked exactly as coded to get the values but seems to run a little hot. However, I just reduced the reading by 20 degrees for the F reading and its at least a little close. Put it by the fireplace and in the freezer to double check and the temp was changing, though not as drastically as I would have expected. Not a great thermometer but a cool trick and probably useful for a few applications.
I am looking for that, too atm. Displaying works fine, but the font is pretty tiny for the use case of a thermometer if you want to be able to read it from some meters away. Did you or someone find a solution to that oir could point me in the right direction please?