2022暑假在家一起练
——基于RP2040和ESP32S2实现简易气象站制作
一.项目介绍
本项目依托2022暑假在家一起练,基于RP2040GameKit平台,实现了简易气象站的制作。本项目通过LCD屏幕、2个按键和实现了实时播放5个城市的气象信息功能,取得了良好的效果,具有一定的价值。
项目任务:
- RP2040 Game Kit板通过提供的ESP32-S2的WiFi模块连接网络
- 在RP2040 Game Kit上显示某一个城市的气象信息 - 时间、温度....
- 通过RP2040 Game Kit上的按键能够切换显示不同城市的信息 ,比如:北京、上海、天津、重庆、深圳
二.设计思路
本项目设计围绕RP2040GAMEKIT,首先对RP2040的板载硬件进行实验使用,初步掌握板载的IO硬件以及RP2040能够实现的功能与实际性能。再根据硬件的具体功能,实现设计。设计步骤如下:
1.配置ESP32S2并烧录固件,连接ESP32S2模块与RP2040游戏机板。
采用如图所示flash_download_tool工具烧录文件,选择ESP32S2,develop工作模式,uart通信方式,并在设备管理器中查找到端口号,点击start进行烧录
2.烧录成功后开始写程序。首先配置网络,将心知天气文档获取接口写入文件中,获取实时天气信息。参考链接:
3.最后设计开机进入页面,配置好按键后,以便控制进入与切换地点。
三.硬件介绍
1.RP2040GameKit游戏机板
- 采用树莓派Pico核心芯片RP2040:
- 双核Arm Cortex M0+内核,可以运行到133MHz
- 264KB内存
- 性能强大、高度灵活的可编程IO可用于高速数字接口
- 片内温度传感器、并支持外部4路模拟信号输入,内部ADC采样率高达500Ksps、12位精度
- 支持MicroPython、C、C++编程
- 板上功能:
- 240*240分辨率的彩色IPS LCD,SPI接口,控制器为ST7789
- 四向摇杆 + 2个轻触按键 + 一个三轴姿态传感器MMA7660用做输入控制
- 板上外扩2MB Flash,预刷MicroPython的UF2固件
- 一个红外接收管 + 一个红外发射管
- 一个三轴姿态传感器MMA7660
- 一个蜂鸣器
- 双排16Pin连接器,有SPI、I2C以及2路模拟信号输入
- 可以使用MicroPython、C、C++编程
- USB Type C连接器用于供电、程序下载
2.ESP32-S2模块
(1)ESP32-S2 性能: ESP32-S2 是一款高度集成、高性价比、低功耗、主打安全的单核 Wi-Fi SoC,具备强大的功能和丰富的 IO 接口:
- 为您的连接设备提供安全保障:
基于 RSA-3072 算法的安全启动
基于 AES-XTS-256 算法的 Flash 加密
密码加速器提高云连接性能
有效抵抗物理故障注入攻击
- 显示、触摸以及丰富的 IO 功能:
ESP32-S2 集成了丰富的外围设备,有 43 个可编程 GPIO,可以灵活配置为 USB OTG、LCD 接口、摄像头接口、SPI、I2S、UART、ADC、DAC 等常用功能。ESP32-S2 具有 LCD 接口和 14 个可配置的电容 触摸 GPIO,可为基于触摸屏和触摸板的设备提供良好的 HMI 解决方案。
- 极端温度下良好的 Wi-Fi 性能
(2)ESP32-S2 模组: ESP32-S2 系列模组是通用的 Wi-Fi MCU 模组,功能强大,具有丰富的外设接口,是物联网、可穿戴电子设备和智能家居等应用场景的理想选择。
(3)ESP32-S2 开发板: 乐鑫的 ESP32-S2 系列开发板有丰富的外设接口和功能模块,方便用户快速构建原型,满足用户开发物联网应用的需求。
参考链接:
https://www.espressif.com/zh-hans/support/download/documents
四.功能介绍
1.初始化开机界面:屏幕显示“按A键进入天气预报”
2.按下A键后开始连接网络
3.网络连接成功后显示第一个城市的实时天气情况:温度、湿度、压强,以及地点、时间等。
这里展示的是北京的天气情况,温度29度,压强1000mb,湿度67%.
可以看见屏幕底下出现两行小字,分别表示按下A退出程序,按下B切换城市.
5.按下B切换城市:
6.按下A键退出
7.再次按下A即可重新开始运行程序
五.主要代码
import os
import time,utime
import ujson
import machine
import _thread
import lcd_gui
import network
import st7789 as st7789
from machine import UART,Pin, ADC,RTC,SPI
from buzzer_music import music
from time import sleep
image_sunny = "logo/0sunny.ebm"#48x48
image_cloudy = "logo/7cloudy.ebm"#58x41
image_overcast = "logo/9overcast.ebm"#58x38
image_rain = "logo/13rain.ebm"#58x57
image_snow = "logo/23snow.ebm"#58x55
#按键配置
buttonB = Pin(5,Pin.IN, Pin.PULL_UP)
buttonA = Pin(6,Pin.IN, Pin.PULL_UP)
display_info= lcd_gui.LCD_Display()
st7789_res = 0
st7789_dc = 1
#buttonB = 5
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
display = st7789.ST7789(spi0, disp_width, disp_width,
reset=machine.Pin(st7789_res, machine.Pin.OUT),
dc=machine.Pin(st7789_dc, machine.Pin.OUT),
xstart=0, ystart=0, rotation=0)
#initialize the serialport and network
def getdata():
global i
global record
if(buttonB.value()==0):
i=i+1
print("start")
netconnectpic()
elif buttonB.value()==1 and record==1:
return 0
elif buttonA.value()==0:
return 0
network_AT = network.Network(uart = UART(0, baudrate=115200, tx=Pin(12), rx=Pin(13)),
recvInfo = "",# receive buffer global variable
cmd_retore = 'AT+RESTORE',
cmd_mode = 'AT+CWMODE=1',#config as station
cmd_inquiry = 'AT+CIPSTA?',#inquiry the IP addr
cmd_connectRouter = 'AT+CWJAP="yourwife","password"',#connect to Router
cmd_httpget = 'AT+HTTPCLIENT=2,0,"https://api.seniverse.com/v3/weather/now.json?key=yourkey&location='+loc[i%5]+'&language=en&unit=c",,,2',
cmd_ack = 'OK'
)
#network_AT.sendATCMD(network_AT.cmd_retore,network_AT.cmd_ack,5000)
time.sleep(3)
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!')
time.sleep(3)
while True:
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)
weather_json = ujson.loads(weatherInfo_str)
weather_location = weather_json['results'][0]['location']['name']
print(weather_location,end=' ')
weather_country = weather_json['results'][0]['location']['country']
print(weather_country,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='℃ ')
weather_time = weather_json['results'][0]['last_update']
print(weather_time)
weather_pressure = weather_json['results'][0]['now']['pressure']
print(weather_pressure)
weather_humidity = weather_json['results'][0]['now']['humidity']
print(weather_humidity)
# code
# 1-3 sunny -- 1
# 4-8 cloudy -- 2
# 9- overcast -- 3
# 10-18 rain -- 4
# 19-25 snow -- 5
weather_now = int(weather_now)
display.fill(st7789.BLACK)
display.fill_rect(12, 10, 220, 5, st7789.RED)
display.line(12,10,12,220,st7789.RED)
display.fill_rect(12, 220, 220, 5, st7789.RED)
display.line(230,10,230,220,st7789.RED)
if(0 < weather_now <= 3 ):
weather_now_code = 1 #sunnny
display_info.lcd_display_image(image_sunny,15,48,48)
display_info.lcd_display_text16x32("Sunny",20,70)
elif(weather_now <= 8):
weather_now_code = 2 #cloudy
display_info.lcd_display_image(image_cloudy,15,41,58)
display_info.lcd_display_text16x32("Cloudy",15,70)
elif(weather_now == 9):
weather_now_code = 3 #overcast
display_info.lcd_display_image(image_overcast,15,38,58)
display_info.lcd_display_text16x32("Overcast",15,70)
elif(weather_now <= 18):
weather_now_code = 4 #rain
display_info.lcd_display_image(image_rain,15,57,58)
display_info.lcd_display_text16x32("Rain",15,70)
elif(weather_now <= 25):
weather_now_code = 5 #snow
display_info.lcd_display_image(image_snow,15,55,58)
display_info.lcd_display_text16x32("Snow",15,70)
else:
weather_now_code = 0
print(weather_now_code)
#位置信息
display_info.lcd_display_text16x32(weather_location+" "+weather_country,15,130)
#温度信息
display_info.lcd_display_text16x32(weather_temp+" C",15,100)
display_info.lcd_display_text8x8("o",55,105)
#时间信息
display_info.lcd_display_text8x8(weather_time[0:10],115,50)
#压强信息、相对湿度
display_info.lcd_display_text16x32(weather_pressure+"mb"+" "+weather_humidity+"%",15,160)
#time.sleep(60)
network_status = 1
record=0
break
def initpic():
global record
display.fill(st7789.BLACK)
display_info.lcd_display_image(image_cloudy,20,41,58)
display_info.lcd_display_image(image_snow,85,55,58)
display_info.lcd_display_image(image_sunny,165,48,48)
display_info.lcd_display_text16x32("WEATHER REPORT",10,110)
display_info.lcd_display_text16x32("press A enter",10,180)
while True:
if buttonA.value()==0:
netconnectpic()
while True:
getdata()
record=1
time.sleep(3)
display_info.lcd_display_text8x8("long press A to exit",20,195)
display_info.lcd_display_text8x8("long press B to change",20,210)
if buttonA.value()==0:
break
break
def endpic():
display.fill(st7789.BLACK)
display_info.lcd_display_text16x32("BYE-BYE~",80,120)
display_info.lcd_display_text8x8("press A to restart",40,180)
while True:
if buttonA.value()==0:
time.sleep(5)
global record
record=0
main()
def netconnectpic():
display.fill(st7789.BLACK)
display_info.lcd_display_text16x32("network",10,70)
display_info.lcd_display_text16x32("connecting...",10,120)
def main():
initpic()
endpic()
record=0
loc=['beijing','shanghai','tianjin','chongqing','shenzhen']
i=0
main()
1.代码解析:在YourWIFE 和 PASSWORD中分别填入自己的wife和密码,以便联网获取信息。在心知天气中获得的信息存储在weather_json中,打开httpget里的链接可以看到传递的信息。
参考链接:
六.活动总结与未来计划
通过对本项目的学习,我对esp32模块又有了进一步的了解,其联网获取信息的功能锻炼了我的动手能力和编程能力,对嵌入式开发有了新的体会,受益匪浅。未来期望再次参加活动,了解并学习更多的知识,掌握更多的技能,开拓电子芯片在生活中运用的视野,改变思维模式,在专业上有既定的发展方向。