Raspberry Pi Pico Projects

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.NCOMPONENTS NAMEQUANTITYPURCHASE LINKS
1Raspberry Pi Pico Basic Starter Kit1 Amazon | AliExpress
2Raspberry Pi Pico1 Amazon | AliExpress
30.96" I2C OLED Display1 Amazon | AliExpress
5Breadboard1 Amazon | AliExpress
6Jumper Wires10 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:

Circuit Diagram of Interfacing Raspberry Pi Pico with OLED Display
Circuit Diagram to Read Internal Temperature Sensor Value from Raspberry Pi Pico on OLED Display

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.

Interfacing Raspberry Pi Pico with OLED Display to read Internal Temperature Sensor Value
Interface OLED Display with Raspberry Pi Pico

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.

Raspberry Pi Pico Pinout
Raspberry Pi Pico Pinouts

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.

Read OnBoard Temperature Sensor Value from Raspberry Pi Pico
Reading Internal Temperature Sensor Value from Raspberry Pi Pico on OLED Display

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button