[作品提交] 【得捷电子Follow me第1期】基于树莓派Pico W的简易网络天气时钟

xinmeng_wit   2023-7-2 21:41 楼主

视频演示


 

项目介绍

本项目的名称是"基于树莓派Pico W的简易网络天气时钟",以树莓派Pico W为主控板为核心,结合相关的模块实现对应的功能。

项目用到的主要模块有:

1、Pico W主控板

2、蜂鸣器模块

3、OLED显示模块

4、GPS模块

5、按键模块

 

项目中实现的主要功能有:

1、实时时钟显示,上电自动NTP网络对时

2、闹钟功能,闹钟时间随意设置,蜂鸣器响铃

3、GPS位置信息显示

4、天气信息显示,通过网络获取所在地区的天气状态和温度

5、LED指示程序运行状态

 

硬件接口如下:

    Pico引脚 备注
LED - - 内部引脚
蜂鸣器 Data GPIO16 GPIO控制
GPS TX GPIO5 Pico UART1的接收引脚
RX GPIO4 Pico UART1的发送引脚
OLED SCL GPIO9 IIC时钟
DAT GPIO8 IIC数据
按键模块 MID键 GPIO28 功能选择和OLED界面切换
UP键 GPIO21 闹钟小时调节(+)
DOWN键 GPIO20 闹钟小时调节(-)
LEFT键 GPIO19 闹钟分钟调节(-)
RIGHT键 GPIO18 闹钟分钟调节(+)

 

以上模块除了按键模块是制备模块以外,其它模块都是本次follow me第一期指定的模块。

树莓派Pico W使用MicroPython进行开发,MicroPyhton继承了Python语言的特点:简单易学、高级语言、解释型语言、可移植性、面向对象、强大的功能丰富的库等。

另外,在对字符串的处理上MicroPython也非常灵活和便捷,特别是对于OLED这种显示类的设备来说,非常方便。

 

本项目根据功能进行了模块化的编程,每个功能都有自己对应的.py文件,方便管理。

1.jpg

alarm.py主要实现了闹钟检测和处理函数

button.py主要实现按键按压和松手检测,并做了防抖处理,非常有效地避免了按键的误触发

main.py是主程序,实现所有功能的有序调度

mgps.py主要实现对gps数据的读取

micropyGPS.py是GPS数据采集的开源库

mtimer.py主要实现了2个定时器,一个是30ms的定时周期,用于按键的检测和防抖,即30ms检测一次按键,连续检测多次,根据实测连续检测4次就能很好的做到防抖和快速响应。另外一个定时器是1s周期,用来获取实时时间,并更新到OLED,还有一些需要周期调度的功能也是通过该定时器实现的。

ssd1306.py是OLED的开源库,不做过多说明

ufont.py是字体开源库

wifi.py主要实现了wifi联网,网络对时,天气信息的获取等与网络相关的功能。

 

下面分别详细展示关键功能及部分关键代码

 

主任务

主程序main.py实现所有模块的初始化和任务有序调度:

import time
from machine import Pin, UART
import wifi
import mtimer
import oled
import button
import mgps
import alarm

if __name__ == '__main__':
    oled.oled_init()           # oled初始化
    oled.oled_display(32,25,"初始化...\n")
    #uart_dbg = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1)) # uart0
    #mgps.gps_init()            # gps初始化
    wifi.wifi_connect()
    wifi.time_sync()
    mtimer.timer_init()        # timer初始化
    while True:
        #mgps.gps_data_update()
        if button.get_button_status() != 3:
            wifi.clear_weather_dis_state()
            
        if button.get_button_status() == 1:   # 闹钟
            alarm.alarm_display()
        elif button.get_button_status() == 2: # GPS
             mgps.gps_data_update()
        elif button.get_button_status() == 3: # 天气
            wifi.get_weather()
            
        alarm.alarm_check(wifi.get_now_hour(), wifi.get_now_min())    

wifi联网

wifi联网单独做成了一个函数,该函数在mian.py里被调用,在初始化阶段就会被调用。

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

def wifi_connect():

    # wait for connect or fail
    max_wait = 10
    while max_wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        max_wait -= 1
        print('waiting for connection...')
        time.sleep(1)
        
    # Handle connection error
    if wlan.status() != 3:
        raise RuntimeError('network connection failed')
    else:
        print('connected')
        status = wlan.ifconfig()
        print('ip = ' + status[0])
        print(rp2.country())

天气信息获取

天气信息是获取的心知天气的实时天气信息,因为是免费用户,所有获取到的信息非常有限,只包含天气状态和温度,还有更新时间,其它的都是收费项目。因此 本次也只能显示这些信息。

url = 'https://api.seniverse.com/v3/weather/now.json?key={}&location={}&language=zh-Hans&unit=c'
key = '******'  #心知天气的密钥,换成自自己的
city = 'shanghai'

weather_dis_state = 0

def get_weather():
    global weather_dis_state
    
    if weather_dis_state == 0:
        result1=urequests.get(url.format(key, city))
        j1=ujson.loads(result1.text)
        city_name = "城市:" + j1['results'][0]['location']['name'] + "\n"
        weather = "天气:" + j1['results'][0]['now']['text'] + "\n"
        temp = "温度:" + j1['results'][0]['now']['temperature'] + "℃"
    
        oled.oled_display(0,10, city_name + weather + temp, True)
        weather_dis_state = 1
        print(weather_dis_state)

周期定时器

本项目使用到了2个定时器,一个是用于按键检测和防抖,另外一个是用于时间获取和显示和任务调度。

from machine import Timer, Pin
import button
import wifi
import oled
import mgps
import alarm

led = Pin("LED", Pin.OUT, value = 0)  # led on board

tim1 = Timer(period=5000, mode=Timer.ONE_SHOT, callback = None)
tim2 = Timer(period=5000, mode=Timer.ONE_SHOT, callback = None)

def timer_init():
    global tim1
    global tim2
    
    tim1.init(period=30, mode=Timer.PERIODIC, callback=lambda t:cb_button_check())
    tim2.init(period=1000, mode=Timer.PERIODIC, callback=lambda t:cb_time_update())

def cb_button_check():
    button.button_state_check()        # ok键检测
    button.button_right_state_check()  # 右键检测
    button.button_left_state_check()   # 左键检测
    button.button_down_state_check()   # 下键检测
    button.button_up_state_check()     # 上键检测
    
def cb_time_update():
     global led
     
     date_time_now = wifi.get_time()
     if button.get_button_status() == 0:   # 时间显示
         #date_time_now = wifi.get_time()
         date_now, time_now = date_time_now.split(' ')
         
         if alarm.get_alarm_status() == 'ON':
             oled.oled_display(20,10, date_now + '\n ' + time_now + '\n ' + 'Alarm ' + 'On', True)
         else:
             oled.oled_display(20,10, date_now + '\n ' + time_now + '\n ' + 'Alarm ' + 'Off', True)
    
     if alarm.alarm_is_active() == True and alarm.get_alarm_status() == 'ON':
         if alarm.buzzer_get_pin() == 1:
             alarm.buzzer_drv(0)
         else:
             alarm.buzzer_drv(1)
     # 翻转led         
     if led.value() == 0:
        led.value(1)
     else:
        led.value(0)

 

GPS位置信息获取

gps位置信息使用了开源库,mgps.py里面又对开源库做了一次封装。


from micropyGPS import MicropyGPS
from machine import Pin, UART
import oled
import button

uart_gps = UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5)) # uart1
gps = MicropyGPS()         #GPS

def gps_init():
    global uart_gps
    global gps
    
    uart_gps = UART(1, baudrate=9600, tx=Pin(4), rx=Pin(5)) # uart1
    gps = MicropyGPS()         #GPS
    
def gps_data_update():
    global uart_gps
    global gps
    
    if uart_gps.any() > 0:
        try:
            status = gps.update(uart_gps.read(1).decode("ascii"))
            if status:
                oled.oled_display(0,0, gps.latitude_string() + "\n" + gps.longitude_string(), True)
        except:
            print('gps error')

 

OLED显示

OLED也是使用开源库,oled.py也是对开源库做了一次封装。

"""
演示硬件:
    SSD1306(OLED 128*64 IIC)
    RP2040 Pico W
所需文件:
    ufont.py
    unifont-14-12917-16.v3.bmf
    ssd1306.py
链接引脚:
    SCL = 9
    SDA = 8
使用字体: unifont-14-12917-16.v3.bmf
"""
from machine import I2C
from machine import Pin
import ufont
import ssd1306
import time

i2c = None
display = None
font = None

def wait(info, _t=5):
    print(info)
    time.sleep(_t)
    
def oled_init():
    global i2c
    global display
    global font
    
    # 请修改为对应 FootPrint
    i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq = 400000)
    display = ssd1306.SSD1306_I2C(128, 64, i2c)

    # 载入字体
    #   使用字体制作工具:https://github.com/AntonVanke/MicroPython_BitMap_Tools
    font = ufont.BMFont("unifont-14-12917-16.v3.bmf")
    
def oled_display(x_pos, y_pos, text_str, clr = False):
    global font
    global display
    
    font.text(display, text_str, x_pos, y_pos, font_size=16, show=True, clear=clr, auto_wrap=True)

IMG_20230702_213735.jpg IMG_20230702_213804.jpg IMG_20230702_213826.jpg

项目总结

通过本次follow me活动,我学习到了很多之前没有学习到的知识。

第一次使用MicroPython进行项目开发,第一次使用树莓派Pico,第一次使用MicroPython开发环境Thonny,第一次使用GPS模块等。

通过这次项目开发,深深地体会到了Python的便捷性,特别是在字符串的处理上,比C语言开发不知道强多少。另外就是Python的库太好用了,获取天气信息并解析json格式也是比C语言开发简单许多,居然几行代码就搞定了,大大提高了开发效率,实在是佩服。

另外,开发过程中也遇到了不少的问题,但是都一一解决了,解决问题的过程中也促使我对MicroPython有了更加深入的了解。

总而言之,非常感谢这次follow me的活动,收获太多,期待下一期。

 

RP2040.zip (269.11 KB)
(下载次数: 4, 2023-7-2 21:33 上传)

 

之前发布帖子

【得捷电子Follow me第1期】任务1:熟悉micropython的基本语法

【得捷电子Follow me第1期】任务2:驱动外设

【得捷电子Follow me第1期】任务3:获取网络时间

【得捷电子Follow me第1期】任务4:实现定位功能

本帖最后由 xinmeng_wit 于 2023-7-3 12:59 编辑

回复评论 (1)

原视频有点问题,现在补充录制了一份,如下:


 

点赞  2023-7-6 06:37
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复