本文介紹使用Raspberry Pi Pico PIO功能來讀取DHT11溫濕度資料,顯示在1602A LCD上。
一、硬體接線:
LCD 1602A: Raspberry Pi Pico
VSS: GND
VDD: Pin40(VBUS), 5V
VO: 10k可變電阻
RS: Pin 11
RW: GND
E: Pin 10
D4: Pin 6
D5: Pin 7
D6: Pin 8
D7: Pin 9
A: 5V
K: GND
DHT11 Raspberry Pi Pico
Pin2: Pin 16
VDD: 5V
二、PIO程式碼與DHT11 datasheet對照說明:
from machine import Pin
import rp2
from utime import sleep_ms
class DHT11():
""" output humidity(rh) and temperature(temp), call get_data to get values """
@rp2.asm_pio(set_init=rp2.PIO.OUT_HIGH, autopush=True, push_thresh=32, in_shiftdir=rp2.PIO.SHIFT_LEFT)
def dht11():
wrap_target()
set(pindirs,1) # set pin as output
set(pins,0) # set low for 20ms (at least 18ms)
set(x,29) #freq=500000, 1 cycle = 2us (30*30*11*2 = 19.8ms)
label("start_loop_1")
set(y,29)
label("start_loop_2")
jmp(y_dec, "start_loop_2") [10]
jmp(x_dec, "start_loop_1")
set(pins,1) [14] # pull-up for 2us*15 = 30us (20~40 us)
set(pindirs,0) # set pin as input
wait(0,pin,0) [19]
nop() [19] # wait for low 2*(20+20)=80us
wait(1,pin,0) [19]
nop() [19] # wait for high 2*(20+20)=80us
set(x,4) # 5 bytes
label("bytes")
set(y,7) # each byte: 8 bits
label("bits")
wait(0,pin,0) [14] # LOW: wait for 2us*15=30us (50us)
wait(1,pin,0) [19] # HIGH: wait at least 2*20=40 us (26~28us: 0, 70us: 1)
in_(pins,1)
jmp(y_dec,"bits") # autopush and push_thresh=32, auto push 4 data byte
jmp(x_dec,"bytes")
push() # push last one CRC byte
nop() [31] #transmition completed, low for 50us and pull-high
wait(0,pin,0) # block for next
wrap()
def __init__(self, pin_num, smid=0):
self.pin = Pin(pin_num, Pin.IN, Pin.PULL_UP)
self.sm=rp2.StateMachine(smid, self.dht11, freq=500000, in_base=self.pin, set_base=self.pin)
self.sm.active(1)
self.rh=0.0
self.temp=0.0
def get_data(self):
self.sm.restart()
data=self.sm.get()
checksum=self.sm.get()
bytes=[]
for i in range(3,-1,-1):
bytes.append((data>>8*i)&0xff)
if ((bytes[0]+bytes[1]+bytes[2]+bytes[3]) == checksum):
self.rh = float('{}.{}'.format(bytes[0], bytes[1]))
self.temp = float('{}.{}'.format(bytes[2], bytes[3]))
else:
self.rh=0.0
self.temp=0.0
del bytes
sleep_ms(1120) #Sampling period at intervals should be no less than 1 second.
# base on https://github.com/wjdp/micropython-lcd/blob/master/lcd.py
from machine import Pin
from utime import sleep_us
class LCD1602A():
PIN_NAMES = ['RS','E','D4','D5','D6','D7']
# Define some device constants
LCD_WIDTH = 16 # Maximum characters per line
# Designation of T/F for character and command modes
LCD_CHR = True
LCD_CMD = False
LINES = {
0: 0x80, # LCD RAM address for the 1st line
1: 0xC0, # LCD RAM address for the 2nd line
# Add more if desired
}
# Timing constants
E_PULSE = 50
E_DELAY = 50
def __init__(self, rs, e,*,d4=None, d5=None, d6=None, d7=None):
self.pins={}
self.PINS=[rs, e, d4, d5, d6, d7]
# Initialise pins
for pin, pin_name in zip(self.PINS, self.PIN_NAMES):
self.pins['LCD_'+pin_name] = Pin(pin, Pin.OUT)
# Initialise display
self.lcd_byte(0x33,self.LCD_CMD)
self.lcd_byte(0x32,self.LCD_CMD)
self.lcd_byte(0x28,self.LCD_CMD)
self.lcd_byte(0x0C,self.LCD_CMD)
self.lcd_byte(0x06,self.LCD_CMD)
self.lcd_byte(0x01,self.LCD_CMD)
def clear(self):
# Clear the display
self.lcd_byte(0x01,self.LCD_CMD)
def set_line(self, line):
# Set the line that we're going to print to
self.lcd_byte(self.LINES[line], self.LCD_CMD)
def set_string(self, message):
# Pad string out to LCD_WIDTH
# message = message.ljust(LCD_WIDTH," ")
m_length = len(message)
if m_length < self.LCD_WIDTH:
short = self.LCD_WIDTH - m_length
blanks=str()
for i in range(short):
blanks+=' '
message+=blanks
for i in range(self.LCD_WIDTH):
self.lcd_byte(ord(message[i]), self.LCD_CHR)
def lcd_byte(self, bits, mode):
# Send byte to data pins
# bits = data
# mode = True for character
# False for command
self.pin_action('LCD_RS', mode) # RS
# High bits
self.pin_action('LCD_D4', False)
self.pin_action('LCD_D5', False)
self.pin_action('LCD_D6', False)
self.pin_action('LCD_D7', False)
if bits&0x10==0x10:
self.pin_action('LCD_D4', True)
if bits&0x20==0x20:
self.pin_action('LCD_D5', True)
if bits&0x40==0x40:
self.pin_action('LCD_D6', True)
if bits&0x80==0x80:
self.pin_action('LCD_D7', True)
# Toggle 'Enable' pin
self.udelay(self.E_DELAY)
self.pin_action('LCD_E', True)
self.udelay(self.E_PULSE)
self.pin_action('LCD_E', False)
self.udelay(self.E_DELAY)
# Low bits
self.pin_action('LCD_D4', False)
self.pin_action('LCD_D5', False)
self.pin_action('LCD_D6', False)
self.pin_action('LCD_D7', False)
if bits&0x01==0x01:
self.pin_action('LCD_D4', True)
if bits&0x02==0x02:
self.pin_action('LCD_D5', True)
if bits&0x04==0x04:
self.pin_action('LCD_D6', True)
if bits&0x08==0x08:
self.pin_action('LCD_D7', True)
# Toggle 'Enable' pin
self.udelay(self.E_DELAY)
self.pin_action('LCD_E', True)
self.udelay(self.E_PULSE)
self.pin_action('LCD_E', False)
self.udelay(self.E_DELAY)
def udelay(self, us):
# Delay by us microseconds, set as function for portability
#pyb.udelay(us)
sleep_us(us)
def pin_action(self, pin, high):
# Pin high/low functions, set as function for portability
if high:
self.pins[pin].on()
else:
self.pins[pin].off()
from machine import Pin
from DHT import DHT11
from LCD1602A import LCD1602A
import utime
lcd=LCD1602A(11,10, d4=6,d5=7,d6=8,d7=9)
dht=DHT11(16)
while True:
dht.get_data()
lcd.set_line(0)
lcd.set_string("Temp:"+str(dht.temp)+"C")
lcd.set_line(1)
lcd.set_string("RH: "+str(dht.rh)+"%")
#utime.sleep(0.5)








