树莓派RP2350 - 桌面动态温湿度计
本文介绍了树莓派 RP2350 开发板结合 DHT11 模块、锂电池模块、随机眨眼动画,实现 OLED 显示的桌面动态温湿度计的项目设计。
扩展板及 3D 外壳详见:Beetle-RP2350扩展板 - 立创开源硬件平台 .
项目介绍
本项目包括
- 工作原理:ADC 电压采集与电量转换
- 工程调试:电量获取、电量图标显示、DHT11 温湿度显示、OLED 眨眼动画
- 工程代码:合并调试代码,实现完整的项目设计功能
- 效果演示:帧动画显示、动态展示
最终实现桌面动态温湿度计的制作。
工作原理
根据开发板原理图可知,电池 VBAT 的分压电路与主控的 GPIO29 模拟接口相连,因此通过该引脚可实时采集监测电池电压信息,进而实现电量显示。
引脚功能定义详见:Pico-Series-Pinout .
分压计算参考:ADC 采样与分压电阻 .
硬件连接
- GP0 -> DATA (DHT11)
- GP4 -> SDA (OLED)
- GP5 -> SCL (OLED)
- BAT -> Battery Positive
- GND -> Battery Negative
示意图
工程调试
包括 ADC 电量采集、电量的 OLED 显示、DHT11温湿度数据和电量图标的显示、眨眼动画等调试项目。
电量获取
通过 ADC 读取 GPIO29 电压值并终端打印
代码
frommachineimportPin, ADC
importutime
# initialize ADC pin
adc=ADC(Pin(29))
# parameters for voltage divide resistor
R1, R2=1000000, 1000000
DIV_RATIO= (R1+R2) /R1
defget_battery_level():
adc_value=adc.read_u16()
voltage= (adc_value/65535) *3.3
actual_voltage=voltage*DIV_RATIO# voltage division compensation
percent=min(max((actual_voltage-3.3) / (4.2-3.3) *100, 0), 100)
returnpercent, actual_voltage
whileTrue:
percent, voltage=get_battery_level()
print('Battery Voltage: {:.2f} V, Battery Level: {:.1f}%'.format(voltage,percent))
utime.sleep(1)
保存代码,连接开发板,配置解释器并运行。
效果
终端打印 ADC 采集的电池电压值以及电量百分比
电量显示
OLED 显示 ADC 采集的电量百分比。
代码
frommachineimportPin, ADC, I2C
importssd1306
importutime
# initialize ADC pin
adc=ADC(Pin(29))
# initialize OLED
i2c=I2C(0, scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 64, i2c)
# parameters of voltage divide resistor
R1, R2=1000000, 1000000# 1M
Vref_BAT=3.9# battery voltage in full charged state
defget_battery_level():
adc_value=adc.read_u16()
voltage= (adc_value/65535) *3.3
DIV_RATIO= (R1+R2) /R1
actual_voltage=voltage*DIV_RATIO# voltage division compensation
percent=min(max((actual_voltage-3.3) / (Vref_BAT-3.3) *100, 0), 100)
returnpercent, actual_voltage
defdraw_battery(percent):
oled.fill(0)
oled.text('{:.0f}%'.format(percent), 0, 17)
# draw battery cartoon icon
oled.rect(0, 0, 30, 15, 1) # frame (x,y,width,height)
oled.rect(30, 5, 3, 5, 1) # anode
oled.fill_rect(2, 2, int(26*percent/100), 11, 1) # electric percent column
oled.rotate(0)
oled.show()
defBAT_display(percent,x,y): # battery percent, icon position (x,y)
oled.fill(0)
oled.text('{:.0f}%'.format(percent), 0+x, 17+y)
# draw battery cartoon icon
oled.rect(0+x, 0+y, 30, 15, 1) # frame (x,y,width,height)
oled.rect(30+x, 5+y, 3, 5, 1) # anode
oled.fill_rect(2+x, 2+y, int(26*percent/100), 11, 1) # electric percent column
oled.rotate(0)
oled.show()
defdraw_vertical_battery(percent,x,y): # battery percent, icon position (x,y)
oled.fill(0)
oled.text('{:.0f}'.format(percent), 0+x, 33+y)
# draw battery cartoon icon
oled.rect(0+x, 2+y, 15, 30, 1) # frame (x,y,width,height)
oled.rect(5+x, 0+y, 5, 3, 1) # anode
fill_h=int(27*percent/100)
oled.fill_rect(2+x, 2+ (28-fill_h) +y, 11, fill_h, 1) # percent column
oled.rotate(0)
oled.show()
whileTrue:
percent, voltage=get_battery_level()
#draw_battery(percent)
BAT_display(percent,90,2)
#draw_vertical_battery(percent,90,9)
print('Battery Voltage: {:.2f} V, Battery Level: {:.1f}%'.format(voltage,percent))
utime.sleep(2)
保存代码,连接开发板,配置解释器并运行。
效果
电量图标的水平显示
电量图标的竖直显示
DHT11 温湿度计
带电量显示的 DHT11 温湿度计
代码
frommachineimportPin, ADC, I2C
fromPicoDHT22importPicoDHT22
importssd1306
importutime
# initialize ADC pin
adc=ADC(Pin(29))
# initialize OLED
i2c=I2C(0, scl=Pin(5), sda=Pin(4))
oled=ssd1306.SSD1306_I2C(128, 64, i2c)
# parameters of voltage divide resistor
R1, R2=1000000, 1000000
Vref_BAT=3.81# battery voltage in full charged state
defget_battery_level():
adc_value=adc.read_u16()
voltage= (adc_value/65535) *3.3
DIV_RATIO= (R1+R2) /R1
actual_voltage=voltage*DIV_RATIO# voltage division compensation
percent=min(max((actual_voltage-3.3) / (Vref_BAT-3.3) *100, 0), 100)
returnpercent, actual_voltage
defdraw_battery(percent):
oled.fill(0)
oled.text('{:.0f}%'.format(percent), 90, 27)
# draw battery cartoon icon
oled.rect(90, 10, 30, 15, 1) # frame
oled.rect(120, 15, 3, 5, 1) # anode
oled.fill_rect(92, 12, int(26*percent/100), 11, 1) # electric percent column
oled.show()
defBAT_display(percent):
oled.fill(0)
oled.text('{:.0f}%'.format(percent), 90, 27)
# draw battery cartoon icon
oled.rect(90, 10, 30, 15, 1) # frame
oled.rect(120, 15, 3, 5, 1) # anode
oled.fill_rect(92, 12, int(26*percent/100), 11, 1)
oled.show()
defdraw_vertical_battery(percent,x,y):
# 局部清屏并显示电量百分比
oled.fill_rect(x,y,15+8,30+16,0)
oled.text('{:.0f}'.format(percent), 0+x, 33+y)
# 竖版电池绘制
oled.rect(0+x, 2+y, 15, 30, 1) # frame (x,y,width,height)
oled.rect(5+x, 0+y, 5, 3, 1) # anode
fill_h=int(26*percent/100)
oled.fill_rect(2+x, 2+ (28-fill_h) +y, 11, fill_h, 1) # percent column
oled.rotate(0)
oled.show()
defdisplay_TH(temp,humi):
oled.fill_rect(20,15,6*8,64-15,0) # 局部清屏
oled.text("Temperature:", 0, 0)
oled.text("{:.1f} C".format(temp), 20, 15)
oled.text("Humidity:", 0, 35)
oled.text("{:.1f} %".format(humi), 20, 50)
oled.rotate(0) # rotate the screen display for a more comfortable position
oled.show()
dht_sensor=PicoDHT22(Pin(0,Pin.IN,Pin.PULL_UP),dht11=True)
whileTrue:
temp,humi=dht_sensor.read()
percent, voltage=get_battery_level()
#draw_battery(percent)
#BAT_display(percent)
draw_vertical_battery(percent,90,16)
display_TH(temp,humi)
print('Battery Voltage: {:.2f} V, Battery Level: {:.1f}%'.format(voltage,percent))
utime.sleep(2)
效果
电量和温湿度显示,数据刷新的时间间隔为 2 秒
眨眼动画
OLED 显示矩形填充状眼睛,改变形状并利用人眼的视觉暂留效应实现眨眼效果。
代码
frommachineimportPin, I2C
importssd1306
importutime
importurandom
i2c=I2C(0, scl=Pin(5), sda=Pin(4))
oled_width=128
oled_height=64
oled=ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
defdraw_eyes(state,xshift,yshift):
"""state: 0=完全睁开, 1=半闭, 2=完全闭上"""
width,height= (int)(oled_width/5),(int)(oled_height/3)
cx,cy= (int)((oled_width-2.5*width)/2),(int)((oled_height-height)/2) # eyes at scrren center 定位点为矩形左上角
x=cx+xshift
y=cy+yshift
oled.fill_rect(x, y, int(2.5*width), height, 0)
# draw left eye
ifstate==0: # 完全睁开
oled.fill_rect(x, y, width, height, 1)
elifstate==1: # 半闭
oled.fill_rect(x, y+(int)(height/4), width, (int)(height/2), 1)
else: # 完全闭上
oled.hline(x, y+(int)(height/2), width, 1)
# draw right eye
ifstate==0: # 完全睁开
oled.fill_rect(x+width+(int)(width/2), y, width, height, 1)
elifstate==1: # 半闭
oled.fill_rect(x+width+(int)(width/2), y+(int)(height/4), width, (int)(height/2), 1)
else: # 完全闭上
oled.hline(x+width+(int)(width/2), y+(int)(height/2), width, 1)
oled.show()
defblink_eyes(xshift,yshift):
# 睁眼状态保持
draw_eyes(0,xshift,yshift)
utime.sleep(1)
# 眨眼动画序列
draw_eyes(1,xshift,yshift) # 半闭
utime.sleep(0.1)
draw_eyes(2,xshift,yshift) # 全闭
utime.sleep(0.1)
draw_eyes(1,xshift,yshift) # 半闭
utime.sleep(0.1)
draw_eyes(0,xshift,yshift) # 全开
defrandom_eyes():
xshift=urandom.randint(-(int)(oled_width/4),(int)(oled_width/4))
yshift=urandom.randint(-(int)(oled_height/3),(int)(oled_height/3))
oled.fill(0)
blink_eyes(xshift,yshift)
#print(xshift,yshift)
whileTrue:
random_eyes()
#blink_eyes(0,0)
保存代码,连接开发板,配置解释器并运行。
效果
眨眼效果(眼睛位置在屏幕内随机移动)
工程代码
将工程调试的代码合并,实现温湿度数据(包括电池电量)与息屏随机眨眼动画的切换显示。
frommachineimportPin, ADC, I2C
fromPicoDHT22importPicoDHT22
importssd1306
importutime
importurandom
# initialize ADC pin
adc=ADC(Pin(29))
# initialize OLED
i2c=I2C(0, scl=Pin(5), sda=Pin(4))
oled_width=128
oled_height=64
oled=ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
# parameters of voltage divide resistor
R1, R2=1000000, 1000000
Vref_BAT=3.81# battery voltage in full charged state
defget_battery_level():
adc_value=adc.read_u16()
voltage= (adc_value/65535) *3.3
DIV_RATIO= (R1+R2) /R1
actual_voltage=voltage*DIV_RATIO# voltage division compensation
percent=min(max((actual_voltage-3.3) / (Vref_BAT-3.3) *100, 0), 100)
returnpercent, actual_voltage
defdraw_vertical_battery(percent,x,y):
# 局部清屏并显示电量百分比
oled.fill_rect(x,y,15+8,30+16,0)
oled.text('{:.0f}'.format(percent), 0+x, 33+y)
# 竖版电池绘制
oled.rect(0+x, 2+y, 15, 30, 1) # frame (x,y,width,height)
oled.rect(5+x, 0+y, 5, 3, 1) # anode
fill_h=int(26*percent/100)
oled.fill_rect(2+x, 2+ (28-fill_h) +y, 11, fill_h, 1) # percent column
oled.rotate(0)
oled.show()
defdisplay_TH(temp,humi):
oled.fill_rect(20,15,6*8,64-15,0) # part clear
oled.text("Temperature:", 0, 0)
oled.text("{:.1f} C".format(temp), 20, 15)
oled.text("Humidity:", 0, 35)
oled.text("{:.1f} %".format(humi), 20, 50)
oled.rotate(0) # rotate the screen display for a more comfortable position
oled.show()
defdraw_eyes(state,xshift,yshift):
"""state: 0=full open, 1=half open, 2=close"""
width,height= (int)(oled_width/5),(int)(oled_height/3)
cx,cy= (int)((oled_width-2.5*width)/2),(int)((oled_height-height)/2) # eyes at scrren center
x=cx+xshift
y=cy+yshift
oled.fill_rect(x, y, int(2.5*width), height, 0)
# draw left eye
ifstate==0: # full open
oled.fill_rect(x, y, width, height, 1)
elifstate==1: # half open
oled.fill_rect(x, y+(int)(height/4), width, (int)(height/2), 1)
else: # close
oled.hline(x, y+(int)(height/2), width, 1)
# draw right eye
ifstate==0: # full open
oled.fill_rect(x+width+(int)(width/2), y, width, height, 1)
elifstate==1: # half open
oled.fill_rect(x+width+(int)(width/2), y+(int)(height/4), width, (int)(height/2), 1)
else: # close
oled.hline(x+width+(int)(width/2), y+(int)(height/2), width, 1)
oled.show()
defblink_eyes(xshift,yshift):
# keep opening
draw_eyes(0,xshift,yshift)
utime.sleep(0.5)
# blink eyes order
draw_eyes(1,xshift,yshift) # half open
utime.sleep(0.1)
draw_eyes(2,xshift,yshift) # close
utime.sleep(0.1)
draw_eyes(1,xshift,yshift) # half open
utime.sleep(0.1)
draw_eyes(0,xshift,yshift) # full open
utime.sleep(0.5)
defrandom_eyes():
xshift=urandom.randint(-(int)(oled_width/4),(int)(oled_width/4))
yshift=urandom.randint(-(int)(oled_height/3),(int)(oled_height/3))
oled.fill(0)
blink_eyes(xshift,yshift)
#print(xshift,yshift)
dht_sensor=PicoDHT22(Pin(0,Pin.IN,Pin.PULL_UP),dht11=True)
defTH_BAT():
''' temperature and humidity and battery '''
temp,humi=dht_sensor.read()
percent, voltage=get_battery_level()
oled.fill(0)
display_TH(temp,humi)
draw_vertical_battery(percent,90,16)
print('Temperature: {:.2f} C, Humidity: {:.2f} RH, Battery Voltage: {:.2f} V, Battery Level: {:.1f}%'.format(temp,humi,voltage,percent))
utime.sleep(2)
whileTrue:
TH_BAT()
random_eyes()
连接开发板,配置解释器,将代码保存至根目录,取下数据线,连接电池,实现显示效果。
效果
帧动画分别如下
动态演示
总结
本文介绍了树莓派 RP2350 开发板结合 DHT11 模块、锂电池模块、随机眨眼动画,实现 OLED 显示的桌面动态温湿度计的项目设计。通过多任务结合,为更多 DIY 设计提供了可能,如添加按键扫描或语音控制模块,实现指定的功能切换与人机交互,拓展和丰富了该开发板在物联网领域的创新与应用,为 RP2350 的开发设计和产品应用提供了参考。