基于RP2040的简易气象站总结报告
项目介绍
我选择的任务是项目三简易气象站,即制作一个简单的气象台,能够实时播放5个城市的气象信息。该项目需要RP2040 Game Kit板通过提供的ESP32-S2的WiFi模块连接网络,并在RP2040 Game Kit上显示某一个城市的气象信息 (包括 天气、时间、温度、湿度、气压、风速等等),另外还需要通过RP2040 Game Kit上的按键切换显示不同城市的天气信息。
设计思路
本项目主要分为两部分,第一部分是利用ESP32-S2的WIFI模块对网络进行连接,并通过心知天气网提供的API获取相关的天气信息,使用ujson.loads解析有效的json字符串并转化为python对象的字典;第二部分则是lcd显示部分,将获取的天气信息打印在lcd屏幕上,并通过RP2040 Game Kit上的按键切换不同城市的天气信息。
软件流程图
硬件介绍
(1) 采用树莓派Pico核心芯片RP2040:
-
双核Arm Cortex M0+内核,可以运行到133MHz
- 264KB内存
-
性能强大、高度灵活的可编程IO可用于高速数字接口
-
片内温度传感器、并支持外部4路模拟信号输入,内部ADC采样率高达500Ksps、12位精度
-
支持MicroPython、C、C++编程
用到的板上功能:
-
240*240分辨率的彩色IPS LCD,SPI接口,控制器为ST7789
-
2个轻触按键用做输入控制
-
板上外扩2MB Flash,预刷MicroPython的UF2固件
-
双排16Pin连接器,有SPI、I2C以及2路模拟信号输入
-
可以使用MicroPython、C、C++编程
- USB Type C连接器用于供电、程序下载
(2)ESP32-S2模组: - ESP32-S2 是一款高度集成、高性价比、低功耗、主打安全的单核 Wi-Fi SoC,具备强大的功能和丰富的 IO 接口。
- ESP32-S2 集成了丰富的外围设备,有 43 个可编程 GPIO,可以灵活配置为 USB OTG、LCD 接口、摄像头接口、SPI、I2S、UART、ADC、DAC 等常用功能。ESP32-S2 具有 LCD 接口和 14 个可配置的电容触摸 GPIO,可为基于触摸屏和触摸板的设备提供良好的 HMI 解决方案
- WIFI模块:802.11 b/g/n,数据速率高达 150 Mbps,帧聚合 (TX/RX A-MPDU, RX A-MSDU),0.4 µs 保护间隔,工作信道中心频率范围:2412 ~ 2484 MHz
实现功能
驱动ESP32-S2 WiFi模块访问心知天气网,通过API获取天气信息,并打印在RP2040LCD屏幕上,通过B按键可切换五个城市的天气信息
主要代码和说明
屏幕初始化
display.fill(st7789.BLACK)
display.text(font1,"www.eetree.cn",70,230)
display.text(font2,"Initializing...",0,100)#初始化界面
网络初始化
#initialize the serialport and network
network_AT = network.Network(uart = UART(0, baudrate=115200, tx=Pin(12), rx=Pin(13)),
recvInfo = "",#receive buffer global variable
cmd_restore = 'AT+RESTORE',
cmd_mode = 'AT+CWMODE=1',#config as station
cmd_inquiry = 'AT+CIPSTA?',#inquiry the IP addr
cmd_connectRouter = 'AT+CWJAP="Drama","12345678"',#connect to Router
cmd_httpget = 'AT+HTTPCLIENT=2,0,"https://api.seniverse.com/v3/weather/now.json?key=S1LggX5PzW5xN0Wd6&location='+city+'&language=en&unit=c",,,2',
cmd_ack = 'OK'
)
if(network_AT.connectNetwork() == True):
#STATUS
#0:config network error
#1:config network ok
#2:http get error
#3:http get ok
network_status = 1
print ('Done!')
else:
network_status = 0
print('Network Config Error!')#连接网络
连接网络并通过API获取天气信息
if(network_status == 0):
if(network_AT.connectNetwork() == True):
print('config network Done!')
network_status = 1
else:
network_status = 0
print ('Network Config Error!')
elif(network_status == 1):
if(network_AT.httpGet() == True):
#time.sleep(3)
network_status = 3
print('HttpGet Done!')
else:
network_status = 2
elif(network_status == 2):
network_status = 1
time.sleep(1)
print ('HttpGet try again!')
elif(network_status == 3):
#parse json info
print(network_AT.recvInfo)
str_start = network_AT.recvInfo.find('{')
print(str_start)
str_end = network_AT.recvInfo.find(']}')
print(str_end)
weatherInfo_str = network_AT.recvInfo[str_start:str_end+2]
print(weatherInfo_str)#网络连接成功并获取天气信息
解析jason为python字典
weather_json =ujson.loads(weatherInfo_str)
weather_location = weather_json['results'][0]['location']['name']
print(weather_location,end=' ')
weather_now = weather_json['results'][0]['now']['code']
print(weather_now,end=' ')
weather_temp = weather_json['results'][0]['now']['temperature']
print(weather_temp,end='°C')
weather_pressure = weather_json['results'][0]['now']['pressure']
print(weather_pressure,end='Pa')
weather_humidity = weather_json['results'][0]['now']['humidity']
print(weather_humidity,end='%')
weather_wind_speed = weather_json['results'][0]['now']['wind_speed']
print(weather_wind_speed,end=' ')
weather_time = weather_json['results'][0]['last_update']
print(weather_time)#解析json为python对象
打印天气信息
display.fill(st7789.BLACK)
weather_now = int(weather_now)
if(0 <= weather_now <= 3):
weather_now_code = 1 #sunny
display.text(font2,"Sunny",50,30)
elif(weather_now <= 8):
weather_now_code = 2 #cloudy
display.text(font2,"Cloudy",50,30)
elif(weather_now == 9):
weather_now_code = 3 #overcast
display.text(font2,"Overcast",50,30)
elif(weather_now <= 18):
weather_now_code = 4 #rainy
display.text(font2,"Rainy",50,30)
elif(weather_now <= 25):
weather_now_code = 5 #snowy
display.text(font2,"Snowy",50,30)
print(weather_now_code)
display.text(font2,weather_location,80,100)
display.text(font2,weather_temp+"C",100,70)
display.text(font1,"o",140,65)
display.text(font1,"Pressure:"+weather_pressure+"Pa",80,160)
display.text(font1,"Humidity:"+weather_humidity+"%",0,180)
display.text(font1,"Wind Speed"+weather_wind_speed+"km/h",100,180)
display.text(font1,weather_time[0:10],80,210)
network_status = 1
break#在lcd屏幕上打印天气信息
按键切换城市天气信息
if(buttonB.value() == 0):
count=count+1
print(count)
#按下B键则count+1切换城市
if(count==9990):
CityWeather('hainan')
print(count)
time.sleep(10)
if(count==9991):
CityWeather('beijing')
print(count)
time.sleep(10)
if(count==9992):
CityWeather('nanchang')
print(count)
time.sleep(10)
if(count==9993):
CityWeather('chengdu')
print(count)
time.sleep(10)
if(count==9994):
CityWeather('chongqing')
print(count)
time.sleep(10)
if(count==9995):
print(count)
count=9990#循环城市天气
遇到的主要难题及解决方法
首先是ESP32-S2的WiFi模块,先前未接触过相关知识导致对网络连接部分存在许多不解之处,先是查看ESP-AT用户指南学习AT命令集,在参考老师直播所演示的方法完成了网络连接部分的建立与测试
然后是ESP32-S2与RP2040的连接,在观看直播并查看板块资料后确定了连接引脚,才完成了上述的网络连接测试
之后关于心知天气API,我查阅了官网的一系列指南,了解了如何访问网站的API获取所需的天气信息,在老师与同学的耐心解答下学习了如何将json解析为python字典
接下来是LCD屏幕的显示,我参考了之前LCDTest的脚本,初步了解了如何利用SPI驱动LCD,再打开ST7789脚本学习了相关的函数,进一步了解了LCD屏幕的驱动方法成功将获取的天气信息打印在了LCD屏幕上
最后关于按键切换城市天气,我参考了过去同学们使用RP2040制作小游戏的例子学习了按键的使用方法,完成了最终的目标,但是仍然存在一点小问题,即按键切换城市天气不够灵敏,往往需要数秒时间才能完成切换,与用户的交互性还有待提升
未来的计划或建议
未来我还计划完善我所编写的程序,提高程序的响应速度和与用户的交互性能,另外还需要封装重复代码再调用,感觉总体的思路可以进一步简化,此外还打算在屏幕上实现展示天气图片的功能
建议将实例代码中的注释完善一下,有部分代码注释不够明晰难以理解