Project Demo

The document below shows a demo. The microcontrolled used here is STEPico, a pin-to-pin version for Pico 2040 based on Raspberry Pi's RP2040 microcontroller.

This code is based on the connection set out in the hardware layout given above. The code is written in MicroPython. You may use Thonny IDE to run this code. If you are unsure about setting up the environment for STEPico and MicroPython, check out this site.

Completed Code
from machine import Pin, I2C, PWM
from utime import sleep
import sh1106
from dht20 import DHT20
from ws2812 import WS2812

# Initialize I2C for the DHT20 sensor
i2c_dht = I2C(1, sda=Pin(10), scl=Pin(11), freq=100000)
dht20 = DHT20(0x38, i2c_dht)

# Initialize I2C for the SH1106 OLED
i2c_oled = I2C(0, sda=Pin(20), scl=Pin(21), freq=100000)
oled = sh1106.SH1106_I2C(128, 64, i2c_oled, rotate=180)
oled.fill(0)
oled.show()

# Initialize rotary encoder
TRA = Pin(16, Pin.IN, Pin.PULL_UP)
TRB = Pin(17, Pin.IN, Pin.PULL_UP)

# Initialize confirm button
confirm_button = Pin(15, Pin.IN, Pin.PULL_UP)

# Initialize GPIO22 for indicating power range status
status_gpio = Pin(22, Pin.OUT)

# Initialize GPIO0 for PWM output control
pwm_gpio = Pin(0)
pwm = PWM(pwm_gpio)
pwm.freq(20000)  # 20kHz PWM frequency

# Initialize WS2812 LEDs
led_pin = 23  # Pin where WS2812 is connected
num_leds = 4
ws2812 = WS2812(led_pin, num_leds, brightness=0.05)

# Default power percentage
target_power = 50.0
target_set = False

# State variables for rotary encoder
last_TRA = TRA.value()
last_TRB = TRB.value()

def update_target_power(pin):
    global target_power
    global last_TRA
    global last_TRB

    TRA_state = TRA.value()
    TRB_state = TRB.value()

    # Determine direction based on TRA and TRB states
    if TRA_state != last_TRA:
        if TRA_state == 0:  # TRA went low
            if TRB_state == 0:
                # TRA low, TRB low: counterclockwise
                target_power -= 5
            else:
                # TRA low, TRB high: clockwise
                target_power += 5
    last_TRA = TRA_state
    last_TRB = TRB_state

def confirm_button_pressed(pin):
    global target_set
    if pin.value() == 0:  # Button pressed
        target_set = True
    else:  # Button released
        target_set = False

# Attach interrupt handlers
TRA.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=update_target_power)
TRB.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=update_target_power)
confirm_button.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=confirm_button_pressed)

def update_leds():
    # Calculate intensity proportional to power % (0-255 scale for WS2812)
    intensity = int(max(0, min(255, (target_power / 100) * 255)))  # Convert percentage to 0-255 range
    
    # Set all LEDs to red with calculated intensity
    ws2812.pixels_fill((0, 0, intensity))  # Fill LEDs with red color
    ws2812.pixels_show()
    
while True:
    # Read DHT20 measurements
    measurements = dht20.measurements
    current_temp = measurements['t']
    current_humi = measurements['rh']
    
    # Calculate PWM duty cycle based on target power (0-100% range)
    duty_cycle = max(0, min(100, target_power))  # Clamp duty cycle between 0% and 100%
    pwm.duty_u16(int(duty_cycle * 65535 / 100))  # Convert percentage to 16-bit value

    # Check if target power is within Β±5% of current temperature
    if abs(target_power - current_temp) <= 5.0:
        status_gpio.value(0)  # Target power is within range
    else:
        status_gpio.value(1)  # Target power is out of range
    
    # Display on OLED
    oled.fill(0)  # Clear the display
    oled.text("Cur. Temp: {:.1f} C".format(current_temp), 0, 0)
    oled.text("Cur. Humi: {:.1f} %".format(current_humi), 0, 16)
    oled.text("Power %: {:.1f}".format(target_power), 0, 32)
    oled.show()

    # Update WS2812 LEDs based on power percentage
    update_leds()

    sleep(0.1)  # Delay for 0.1 seconds

Last updated

Was this helpful?