Read Internal Temperature Sensor Value from Raspberry Pi Pico
Read OnBoard Temperature Sensor Value from Raspberry Pi Pico

Read Raspberry Pi Pico OnBoard temperature sensor
In this tutorial, we will Read Internal Temperature Sensor Value from Raspberry Pi Pico and display it on an OLED screen. The Raspberry Pi Pico has an internal temperature sensor that is connected to one of its ADC pins. We will connect an I2C OLED display to the Raspberry Pi Pico and use it to display the temperature data. The circuit will be assembled using a breadboard and jumper wires.
Components Required
To complete this tutorial, you will need the following components:
| S.N | COMPONENTS NAME | QUANTITY | PURCHASE LINKS |
|---|---|---|---|
| 1 | Raspberry Pi Pico Basic Starter Kit | 1 | Amazon | AliExpress |
| 2 | Raspberry Pi Pico | 1 | Amazon | AliExpress |
| 3 | 0.96" I2C OLED Display | 1 | Amazon | AliExpress |
| 5 | Breadboard | 1 | Amazon | AliExpress |
| 6 | Jumper Wires | 10 | Amazon | AliExpress |
Interfacing SSD1306 OLED Display with Raspberry Pi Pico
To display the temperature value on the OLED display. We need to establish a connection between the Raspberry Pi Pico and the OLED display. The connection diagram is as follows:

Connect the SDA and SCL (I2C Pins) pins of the OLED display to the Raspberry Pi Pico GP20 and GP21 pins, respectively. You can use the breadboard to assemble the circuit as shown here.

Temperature Sensor of Raspberry Pi Pico
The internal temperature sensor that comes with the Raspberry Pi Pico is connected to one of the ADCs. ADC refers to 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. That 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.
You can check the Raspberry Pi Getting Started Tutorial to learn more about its specifications, pins & details.

The Raspberry Pi Pico board has a set of ADC pins. Basically, it has its own numbering scheme instead of the traditional GPIO pin numbers. The pins labeled ADC0, ADC1, ADC2, and ADC_VREF (technically ADC3). These are the four externally accessible ADC pins. So, the temperature sensor can be accessed as ADC4.
Reading the Pi Pico Temperature Value with MicroPython Code
To read the temperature value, we can use MicroPython code. The code imports the machine and utime modules, and creates an object for the temperature sensor using the ADC() class. It then sets a conversion factor and enters a loop to read the temperature value. Then it converts readings to the Celsius scale. The converted temperature value is then printed to the Shell window.
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)Code Explanation:
We first import the machine and utime modules. The machine module provides the ADC() class to work with ADC pins.
import machine import utime
The sensor_temp variable is created as an object of the ADC class with pin 4 as its argument.
sensor_temp = machine.ADC(4)
We set a conversion factor to convert the 16-bit temperature value back to volts. That is done based on the 3.3 V maximum voltage used by the Pico board.
conversion_factor = 3.3 / (65535)
In the while loop, we read the temperature value using the sensor_temp object’s read_u16() method. Then multiply it with the conversion factor.
reading = sensor_temp.read_u16() * conversion_factor
The temperature value is then converted to the Celsius scale using the following equation. It calculates the temperature based on the voltage delivered by the sensor.
temperature = 27 - (reading - 0.706)/0.001721
If you want to convert the temperature value from degrees Celcius to Fahrenheit. Then you can use this mathematical equation.
fahrenheit_degrees = celsius_degrees * 9 / 5 + 32
Finally, the temperature value is printed on the Shell window. At last delay of 2 seconds is created.
print(temperature) utime.sleep(2)
Displaying the Raspberry Pi Pico Temperature Values on OLED
To display the temperature value on an OLED screen. We need to write an OLED driver code as the SSD1306 driver is not available. The code is divided into two parts: ssd1306.py and main.py. The ssd1306.py file contains the OLED driver code. Meanwhile, the main.py file contains the code to display the temperature value on the OLED screen.
ssd1306.py
To display the temperature value on an OLED screen. we need to write an SSD1306 OLED driver code as the SSD1306 driver is not available by default. Open a new tab in your Thonny IDE and copy the following code. Save the file as ssd1306.py in Raspberry Pi Pico.
# 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 saving the ssd1306.py on Raspberry Pi Pico. Create a new tab again and copy the following code. Save this code as main.py.
# 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()Testing
Once you run the code, the OLED display will start displaying the temperature value on the OLED screen.

Conclusion
This is how you can Read the internal Temperature Sensor Value from Raspberry Pi Pico using MicroPython Programming. Additionally, you can also connect an external temperature sensor like DS18B20 with the RPI Pico to read external temperatures.



