基于RP2040实现简易气象站
在RP2040 Game Kit上显示五个城市的气象信息 - 时间、温度、湿度、气压
标签
树莓派
ESP32
MicroPython
RP2040
2022暑假在家练
Austin
更新2022-09-02
集美大学诚毅学院
648

内容介绍

一、项目介绍

RP2040 Game Kit板通过提供的ESP32-S2的WiFi模块连接网络

在RP2040 Game Kit上显示五个城市的气象信息 - 时间、温度、湿度、气压....

通过RP2040 Game Kit上的按键能够切换龙岩、北京、厦门、深圳、上海的城市的信息

二、硬件介绍

RP2040 Game Kit是基于树莓派RP2040的嵌入式系统学习平台,通过USB Type-C连接器供电,采用RP2040作为主控,具有双核Arm Cortex M0+内核和264KB内存,可通过MicroPython或C/C++编程,性能强大。板上四向摇杆 + 2个轻触按键 + 一个三轴姿态传感器MMA7660用做输入控制,并有240*240分辨率的彩色LCD屏显示,片内温度传感器、并支持外部4路模拟信号输入,内部ADC采样率高达500Ksps。

ESP32-s2模块是乐鑫官方推出的Wi-Fi模块。除了Wi-Fi模块,该模块还包含蓝牙4.0模块。双核CPU工作频率为80至240 MHz,包含两个Wi-Fi和蓝牙模块以及各种输入和输出引脚。

硬件连接

RP2040

ESP32-S2

3V3

3.3V

GND

GND

PIN16(IO12)TX

U0RXD

PIN14(IO13)RX

U0TXD

三、设计思路及软件流程图

  1. 程序开始时使esp32连上WIFI
  2. 发送http请求,使用和风天气API获取五个城市的天气信息
  3. 对返回的数据进行解析,得到想要的天气信息
  4. 推动摇杆的各个方向都可以切换各自的城市信息(向上——深圳,向下——北京,向左——上海,向右——厦门),A键可以查看龙岩的天气信息
  5. 在第一次获取城市天气信息成功后每十分钟自动更新为最新的天气信息

FqDMgQ9oaP7HZpcXIuOEzA-jkvkf

(由于获取5个城市信息的时间较慢且获取时无法切换城市,所以获取周期为十分钟更新一次)

实现的功能及图片展示

获取天气信息界面

FqYFI3uk4xm3EjayqSsOESgLovCB

选择界面

FhIFOljD_9JXMwD5xKRT6mBIT2bI

厦门天气界面

FpWLhs7FPm2-3ZIdxYESRXFeUdWc

北京天气界面

Fnie_b9oEGks90vlo9XDFOLM0koG

上海天气界面

Fnd-k-lHFAUV2Fv86HqRqux1xfEz

深圳天气界面

FtOL9n9xYdTworsbLLA9rfBrfB-Z

龙岩天气界面

FiovtsKSEuMoa2uIEbfe4o-o-M96

五、主要代码片段及说明

屏幕的初始化及按键和摇杆的初始化

xAxis = ADC(Pin(28))
yAxis = ADC(Pin(29))
buttonB = Pin(5,Pin.IN, Pin.PULL_UP) #B
buttonA = Pin(6,Pin.IN, Pin.PULL_UP) #A

st7789_res = 0
st7789_dc  = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
print(uos.uname())
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)
print(spi0)
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)

 

 

建立两个线程,这块线程实现切换城市。如果天气信息获取完成,开始判断按键或摇杆是否触发,成功触发则切换所显示的城市天气信息。

def fun1():
    while True:
        lock.acquire()
        if over == 1:
            if buttonA.value() == 0:
                print("龙岩")
                display.fill(st7789.BLACK)
                display.text_gb32(font3,128, "龙岩", 10, 110)
                display.text_gb32(font3,128, "℃", 185, 80,color=0x001F)
                display.text(font2,weather_temp_LY,150, 80,color=0x001F)
                display.text_gb48(font3,144, weather_time_LY[11:16], 110, 10,color=0x07E0)
                display.text(font1,weather_time_LY[0:10],80,230)
                display.text_gb32(font3,128, "湿度", 90, 150)
                display.text_gb32(font3,128, "气压", 90, 180)
                display.text(font2,":"+weather_humidity_LY,150, 150,color=0xF05F)
                display.text(font2,":"+weather_pressure_LY,150, 180,color=0xF05F)
                f_image = open(weather[LY_code],'rb')
                for column in range(1,96):
                    buf=f_image.read(192)
                    display.blit_buffer(buf, 1, column, 96, 1)
            
            elif xAxis.read_u16() > 50000:
                print("北京")
                display.fill(st7789.BLACK)
                display.text_gb32(font3,128, "北京", 10, 110)
                display.text_gb32(font3,128, "℃", 185, 80,color=0x001F)
                display.text(font2,weather_temp_BJ,150, 80,color=0x001F)
                display.text_gb48(font3,144, weather_time_BJ[11:16], 110, 10,color=0x07E0)
                display.text(font1,weather_time_BJ[0:10],80,230)
                display.text_gb32(font3,128, "湿度", 90, 150)
                display.text_gb32(font3,128, "气压", 90, 180)
                display.text(font2,":"+weather_humidity_BJ,150, 150,color=0xF05F)
                display.text(font2,":"+weather_pressure_BJ,150, 180,color=0xF05F)
                f_image = open(weather[BJ_code],'rb')
                for column in range(1,96):
                    buf=f_image.read(192)
                    display.blit_buffer(buf, 1, column, 96, 1)
            
            elif xAxis.read_u16() < 10000:
                print("深圳")
                display.fill(st7789.BLACK)
                display.text_gb32(font3,128, "深圳", 10, 110)
                display.text_gb32(font3,128, "℃", 185, 80,color=0x001F)
                display.text(font2,weather_temp_SZ,150, 80,color=0x001F)
                display.text_gb48(font3,144, weather_time_SZ[11:16], 110, 10,color=0x07E0)
                display.text(font1,weather_time_SZ[0:10],80,230)
                display.text_gb32(font3,128, "湿度", 90, 150)
                display.text_gb32(font3,128, "气压", 90, 180)
                display.text(font2,":"+weather_humidity_SZ,150, 150,color=0xF05F)
                display.text(font2,":"+weather_pressure_SZ,150, 180,color=0xF05F)
                f_image = open(weather[SZ_code],'rb')
                for column in range(1,96):
                    buf=f_image.read(192)
                    display.blit_buffer(buf, 1, column, 96, 1)
        
            elif yAxis.read_u16() > 50000:
                print("厦门")
                display.fill(st7789.BLACK)
                display.text_gb32(font3,128, "厦门", 10, 110)
                display.text_gb32(font3,128, "℃", 185, 80,color=0x001F)
                display.text(font2,weather_temp_XM,150, 80,color=0x001F)
                display.text_gb48(font3,144, weather_time_XM[11:16], 110, 10,color=0x07E0)
                display.text(font1,weather_time_XM[0:10],80,230)
                display.text_gb32(font3,128, "湿度", 90, 150)
                display.text_gb32(font3,128, "气压", 90, 180)
                display.text(font2,":"+weather_humidity_XM,150, 150,color=0xF05F)
                display.text(font2,":"+weather_pressure_XM,150, 180,color=0xF05F)
                f_image = open(weather[XM_code],'rb')
                for column in range(1,96):
                    buf=f_image.read(192)
                    display.blit_buffer(buf, 1, column, 96, 1)
            
            elif yAxis.read_u16() < 10000:
                print("上海")
                display.fill(st7789.BLACK)
                display.text_gb32(font3,128, "上海", 10, 110)
                display.text_gb32(font3,128, "℃", 185, 80,color=0x001F)
                display.text(font2,weather_temp_SH,150, 80,color=0x001F)
                display.text_gb48(font3,144, weather_time_SH[11:16], 110, 10,color=0x07E0)
                display.text(font1,weather_time_SH[0:10],80,230)
                display.text_gb32(font3,128, "湿度", 90, 150)
                display.text_gb32(font3,128, "气压", 90, 180)
                display.text(font2,":"+weather_humidity_SH,150, 150,color=0xF05F)
                display.text(font2,":"+weather_pressure_SH,150, 180,color=0xF05F)
                f_image = open(weather[SH_code],'rb')
                for column in range(1,96):
                    buf=f_image.read(192)
                    display.blit_buffer(buf, 1, column, 96, 1)
            lock.release()

这块线程用作获取天气,uart.write向串口发送at指令使esp32向和风天气发送http客户端请求,while (utime.ticks_ms()-t) < 10000:内用作获取esp32返回的数值,前面的while get_LY == 0:用作防止有时候获取的信息不完整导致得不到想要的内容,直到获取完整信息后退出循环,其中获取的信息中间会出现“+HTTPCLIENT:”的字样,需要清除,不然会导致后面的JSON解析失败。

while True:
    lock.acquire()
    uart = UART(0,baudrate=115200, tx=Pin(12), rx=Pin(13))
    display.fill(st7789.BLACK)
    display.text_gb32(font3,128, "获取当前天气中", 10, 100,color=0x001F)
    w = 0
    get_LY = 0
    while get_LY == 0:
        print('龙岩')
        print ('Start Get Weather info from seniverse')
        uart.write(http[w] + '\r\n')
        t=utime.ticks_ms()
        while (utime.ticks_ms()-t) < 10000:
            re=uart.read()
            if(re != None):
                recv = str(re.decode())
                
                if(recv.find('OK') >=0 ):
                    print ('Data Getted!')
        r = 135
        for i in range(35):
            r += 1
            re = '+HTTPCLIENT:'+str(r)+','
            recv = recv.replace(str(re),'')
        print(recv)
        time.sleep(0.01)
        str_start = recv.find('{')
        print(recv.find('{"code"'))
        print(str_start)
        str_end = recv.find(']}')
        print(str_end)
        if recv.find('{"code"') == -1 or recv.find(']}') == -1:
            get_LY = 0
        else:
            get_LY = 1
    weatherInfo_str = recv[str_start:str_end+2]
    print(weatherInfo_str)
    time.sleep(0.3)
    weather_json = ujson.loads(weatherInfo_str)
    weather_now_LY = weather_json['now']['text']
    print(weather_now_LY,end=' ')
    weather_temp_LY = weather_json['now']['temp']
    print(weather_temp_LY,end='  ')
    weather_time_LY = weather_json['updateTime']
    print(weather_time_LY)
    weather_humidity_LY = weather_json['now']['humidity']
    print(weather_humidity_LY)
    weather_pressure_LY = weather_json['now']['pressure']
    print(weather_pressure_LY)
    if(weather_now_LY == "晴" ):
        LY_code = 0
    elif(weather_now_LY == "多云" ):
        LY_code = 1
    elif(weather_now_LY == "阴" ):
        LY_code = 2
    elif(weather_now_LY == "雨" or "大雨" or "小雨" or "中雨" or "暴雨"):
        LY_code = 3
    else:
        LY_code = 0
    print(LY_code)

    w = 1
    get_BJ = 0
    while get_BJ == 0:
        print('北京')
        print ('Start Get Weather info from seniverse')
        uart.write(http[w] + '\r\n')
        t=utime.ticks_ms()
        while (utime.ticks_ms()-t) < 10000:
            re=uart.read()
            if(re != None):
                recv = str(re.decode())
                
                if(recv.find('OK') >=0 ):
                    print ('Data Getted!')
        r = 135
        for i in range(35):
            r += 1
            re = '+HTTPCLIENT:'+str(r)+','
            recv = recv.replace(str(re),'')
        print(recv)
        time.sleep(0.01)
        str_start = recv.find('{')
        print(str_start)
        print(recv.find('{"code"'))
        str_end = recv.find(']}')
        print(str_end)
        if recv.find('{"code"') == -1 or recv.find(']}') == -1:
            get_BJ = 0
        else:
            get_BJ = 1
    weatherInfo_str = recv[str_start:str_end+3]
    print(weatherInfo_str)
    time.sleep(0.3)
    weather_json_BJ = ujson.loads(weatherInfo_str)
    weather_now_BJ = weather_json_BJ['now']['text']
    print(weather_now_BJ,end=' ')
    weather_temp_BJ = weather_json_BJ['now']['temp']
    print(weather_temp_BJ,end='  ')
    weather_time_BJ = weather_json_BJ['updateTime']
    print(weather_time_BJ)
    weather_humidity_BJ = weather_json_BJ['now']['humidity']
    print(weather_humidity_BJ)
    weather_pressure_BJ = weather_json_BJ['now']['pressure']
    print(weather_pressure_BJ)
    if(weather_now_BJ == "晴" ):
        BJ_code = 0
    elif(weather_now_BJ == "多云" ):
        BJ_code = 1
    elif(weather_now_BJ == "阴" ):
        BJ_code = 2
    elif(weather_now_BJ == "雨" or "大雨" or "小雨" or "中雨" or "暴雨"):
        BJ_code = 3
    else:
        BJ_code = 0
    print(BJ_code)

   
    w = 2
    get_SZ = 0
    while get_SZ == 0:
        print('深圳')
        print ('Start Get Weather info from seniverse')
        uart.write(http[w] + '\r\n')
        t=utime.ticks_ms()
        while (utime.ticks_ms()-t) < 10000:
            re=uart.read()
            if(re != None):
                recv = str(re.decode())
                
                if(recv.find('OK') >=0 ):
                    print ('Data Getted!')
        r = 135
        for i in range(35):
            r += 1
            re = '+HTTPCLIENT:'+str(r)+','
            recv = recv.replace(str(re),'')
        print(recv)
        time.sleep(0.01)
        str_start = recv.find('{')
        print(str_start)
        print(recv.find('{"code"'))
        str_end = recv.find(']}')
        if recv.find('{"code"') == -1 or recv.find(']}') == -1:
            get_SZ = 0
        else:
            get_SZ = 1
    print(str_end)
    weatherInfo_str = recv[str_start:str_end+2]
    print(weatherInfo_str)
    time.sleep(0.3)
    weather_json_SZ = ujson.loads(weatherInfo_str)
    weather_now_SZ = weather_json_SZ['now']['text']
    print(weather_now_SZ,end=' ')
    weather_temp_SZ = weather_json_SZ['now']['temp']
    print(weather_temp_SZ,end='  ')
    weather_time_SZ = weather_json_SZ['updateTime']
    print(weather_time_SZ)
    weather_humidity_SZ = weather_json_SZ['now']['humidity']
    print(weather_humidity_SZ)
    weather_pressure_SZ = weather_json_SZ['now']['pressure']
    print(weather_pressure_SZ)
    if(weather_now_SZ == "晴" ):
        SZ_code = 0
    elif(weather_now_SZ == "多云" ):
        SZ_code = 1
    elif(weather_now_SZ == "阴" ):
        SZ_code = 2
    elif(weather_now_SZ == "雨" or "大雨" or "小雨" or "中雨" or "暴雨" ):
        SZ_code = 3
    else:
        SZ_code = 0
    print(SZ_code)



    w = 3
    get_XM = 0
    while get_XM == 0:
        print('厦门')
        print ('Start Get Weather info from seniverse')
        uart.write(http[w] + '\r\n')
        t=utime.ticks_ms()
        while (utime.ticks_ms()-t) < 10000:
            re=uart.read()
            if(re != None):
                recv = str(re.decode())
                
                if(recv.find('OK') >=0 ):
                    print ('Data Getted!')
        r = 135
        for i in range(35):
            r += 1
            re = '+HTTPCLIENT:'+str(r)+','
            recv = recv.replace(str(re),'')
        print(recv)
        time.sleep(0.01)
        str_start = recv.find('{')
        print(str_start)
        print(recv.find('{"code"'))
        str_end = recv.find(']}')
        print(str_end)
        if recv.find('{"code"') == -1 or recv.find(']}') == -1:
            get_XM = 0
        else:
            get_XM = 1
    weatherInfo_str = recv[str_start:str_end+2]
    print(weatherInfo_str)
    time.sleep(0.3)
    weather_json_XM = ujson.loads(weatherInfo_str)
    weather_now_XM = weather_json_XM['now']['text']
    print(weather_now_XM,end=' ')
    weather_temp_XM = weather_json_XM['now']['temp']
    print(weather_temp_XM,end='  ')
    weather_time_XM = weather_json_XM['updateTime']
    print(weather_time_XM)
    weather_humidity_XM = weather_json_XM['now']['humidity']
    print(weather_humidity_XM)
    weather_pressure_XM = weather_json_XM['now']['pressure']
    print(weather_pressure_XM)
    if(weather_now_XM == "晴" ):
        XM_code = 0
    elif(weather_now_XM == "多云" ):
        XM_code = 1
    elif(weather_now_XM == "阴" ):
        XM_code = 2
    elif(weather_now_XM == "雨" or "大雨" or "小雨" or "中雨" or "暴雨" ):
        XM_code = 3
    else:
        XM_code = 0
    print(XM_code)


    w = 4
    get_SH = 0
    while get_SH == 0:
        print('上海')
        print ('Start Get Weather info from seniverse')
        uart.write(http[w] + '\r\n')
        t=utime.ticks_ms()
        while (utime.ticks_ms()-t) < 10000:
            re=uart.read()
            if(re != None):
                recv = str(re.decode())
                
                if(recv.find('OK') >=0 ):
                    print ('Data Getted!')
        r = 135
        for i in range(35):
            r += 1
            re = '+HTTPCLIENT:'+str(r)+','
            recv = recv.replace(str(re),'')
        print(recv)
        time.sleep(0.01)
        str_start = recv.find('{')
        print(str_start)
        print(recv.find('{"code"'))
        str_end = recv.find(']}')
        print(str_end)
        if recv.find('{"code"') == -1 or recv.find(']}') == -1:
            get_SH = 0
        else:
            get_SH = 1
    weatherInfo_str = recv[str_start:str_end+2]
    print(weatherInfo_str)
    time.sleep(0.3)
    weather_json_SH = ujson.loads(weatherInfo_str)
    weather_now_SH = weather_json_SH['now']['text']
    print(weather_now_SH,end=' ')
    weather_temp_SH = weather_json_SH['now']['temp']
    print(weather_temp_SH,end='  ')
    weather_time_SH = weather_json_SH['updateTime']
    print(weather_time_SH)
    weather_humidity_SH = weather_json_SH['now']['humidity']
    print(weather_humidity_SH)
    weather_pressure_SH = weather_json_SH['now']['pressure']
    print(weather_pressure_SH)
    if(weather_now_SH == "晴" ):
        SH_code = 0
    elif(weather_now_SH == "多云" ):
        SH_code = 1
    elif(weather_now_SH == "阴" ):
        SH_code = 2
    elif(weather_now_SH == "雨" or "大雨" or "小雨" or "中雨" or "暴雨" ):
        SH_code = 3
    else:
        SH_code = 0
    print(SH_code)
    over = 1
    print("over")
    display.fill(st7789.BLACK)
    display.text_gb32(font3,128, "按下A键或", 40, 60)
    display.text_gb32(font3,128, "推动摇杆查", 40, 100)
    display.text_gb32(font3,128, "看天气信息", 40, 140)
    lock.release()
    time.sleep(600)

六、遇到的问题及解决方法

RP2040需要使用micropython进行编写(在Linux系统上能用C语言进行编写,难度太大且教程太少劝退了),对于从未使用过python的我来说,做这个项目就需要多学一门语言,毫无疑问这是最大的难题,不过python的上手难度比C语言容易很多,这使得我不需要很长时间就入门了。

这次项目是初次使用RP2040和esp32-s2,走了很多弯路所以产生了许多问题,问题都不大,但确实困扰了我很久。

1.首先就是esp32-s2的问题。在学校使用过esp8266,以为和esp8266同样的方法使用它,插上数据线烧录程序发现esp32一直处于无响应状态,试了各种方法,发现esp32进入BootLoader模式是不能烧录程序的,但是不进入这个模式PC就看不到串口,最后才知道这种板不能用数据线直接烧录程序,需要用TTL转USB的下载线,才能直接烧录程序。

2.对esp32发送关于HTTP的AT指令,让esp32发送HTTP请求,返回的数据一直都不完整,后来看了硬禾学堂的直播,用了里面老师的方法,用一个while循环重复读取返回的数值,但是有时候还是会读取不完整,后面对JSON的解析报错,导致整条程序停止运行,最后我又加了一条循环,直到获取完整数据才会跳出循环。

3.这个项目最开始切换5个城市的思路是每次按下按钮就发送一个城市的http请求,然后再把获取的数据处理显示在显示屏上,由于python的运行速度较慢,这种方法在每次切换城市的时候都需要等待很长一段时间。后来知道了能用多线程的方式实现边获取数据边显示天气信息。

4.对我来说,在这块LCD屏上显示中文也是一大难题。一开始就发现st7789官方库并不能显示中文。后来知道要在st7789库里添加三个方法,自己在建立一个汉字库,就能显示中文了。

5.最后要说一个使用和风天气的坑,我最开始是使用心知天气获取天气的,但是心知天气免费版能获取的信息很少,只有付费版才能获取湿度气压等。后来知道和风天气免费版能获取的数据有很多基本能满足大多数需求,不过和风天气在浏览器测试的数据都正常,用代码获取会变成一堆乱码,检查代码没问题后重新查看和风天气开发文档才发现,是和风天气默认对API接口进行gzip方式压缩,只要在原来的url上添加一个&gzip=n,就不会出现乱码了。

七、未来的计划

虽然对于RP2040来说,我已经上手了,但是里面还是有很多模块的工作原理我还是不清楚的,在以后应该会更深入的学习microPython,使用RP2040做出更多项目。

附件下载

2代码2.rar

团队介绍

魏琳浩-集美大学诚毅学院
团队成员
Austin

评论

0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号