[作品提交] 【得捷电子Follow me第2期】+提交帖:任务1~4以及联网万年历和天气显示

艾嘉西斯之铠   2023-11-17 21:46 楼主

    很高兴能参加本次的得捷电子Follow me第2期的活动,因为本人此前仅使用过51单片机和STM32,当时编程用的也是C语言,几乎没有接触过Python,再加上过去几个月主要在忙保研事宜,前一阵子刚上手面向对象的CircuitPython时一头雾水,不过幸好有国庆几天假期,鼠鼠我赶紧粗略地补充了一下Python知识(幸好这几个任务用到的不复杂),再看了看论坛里各位大佬们的项目讲解和示例,我才慢慢上手,所以也非常感谢各位大佬在论坛里的详细说明!

第一部分:演示视频

    内容主要包括硬件介绍还有任务1~4的完成展示(任务4我选择分任务1:日历与时钟)

任务展示视频


第二部分:项目总结报告

    下面我将把每个任务分开介绍:

 

任务1:控制屏幕显示中文

image.png  

    这个任务需要导入一个2Mb的字库文件(当然也可以仅仅导入几个字模),放在code.py所在目录下就行,这个大小的文件在我以前使用过的不加存储扩展的单片机中是难以想象的。
    在这个任务中,只需要调用adafruit_display_text、adafruit_bitmap_font两个外部库就可以,使用adafruit_bitmap_font的bitmap_font下的load_font方法即可得到font。显示文字则要使用adafruit_display_text的Lable类创建实例,第一个输入参数为之前的font,其余参数是关键字参数,可先不输入,之后更改实例属性也行,最后使用board.DISPLAY.show()显示。
    以下是我循环显示三条中文的代码。
import board
import terminalio
import time
from adafruit_display_text import bitmap_label
from adafruit_bitmap_font import bitmap_font

font = bitmap_font.load_font("wenquanyi_9pt.pcf")

display = board.DISPLAY

color = {
        "black" : 0x000000,
        "white" : 0xFFFFFF,
        "red" : 0xFF0000,
        "green" : 0x00FF00,
        "blue" : 0x0000FF,
        "yellow" : 0xFFFF00,
        }

txt = "你好"
txtCollection = ["Hello,World!","这里是zzu何同学的任务1展示","用户名:艾嘉西斯之铠"]
scaleCollection = [3,1,2]

text_area = bitmap_label.Label(font,color=color["white"])
text_area.scale = 3
text_area.x = 0
text_area.y = 60

display.show(text_area)

while True:
    for i in range(3):
        text_area.text = txtCollection[i]
        text_area.scale = scaleCollection[i]
        display.show(text_area)
        time.sleep(1)

 

任务2:网络功能使用

    该开发板的WIFI连接和开启热点同样只需要简单的调用现成的wifi库可以了(不得不说真的方便嗷),以下只贴出了板子连接我手机热点的效果图

 
图4.jpg
图5.jpg
    这里我并没有考虑第一次没连上wifi的情况,如果上电后你设置的wifi没有打开,那就再也不尝试连接了,实际应用时候肯定不能这么写,任务4会完善一下的。
import board
import terminalio
import os
import wifi
from adafruit_display_text import bitmap_label
from adafruit_bitmap_font import bitmap_font

font = bitmap_font.load_font("wenquanyi_9pt.pcf")

display = board.DISPLAY

#=========================================================
#开启热点
#wifi.radio.start_ap('艾嘉西斯之铠', '1234567890')
#print("wifi start !!")

#=========================================================
#连接wifi(注意换成自己的wifi名称和密码)
wifi.radio.connect('你的wifi名称', 'your_password')					
txt = "IP地址" + str(wifi.radio.ipv4_address)

text_area = bitmap_label.Label(font,text=txt)
text_area.scale = 2
text_area.x = 0
text_area.y = 60

display.show(text_area)
#=========================================================

while True:
    pass

 

任务3:控制WS2812B

    事实上,这个任务还是调库,什么?你说你想做点有创意的动画效果?不好意思,常见的LED动画效果也已经有库可以使用了(有一说一,Python太方便了)。找到adafruit_led_animation库文件夹,其中的animation文件夹包含了好几种动画效果,你可以选择一个LED灯条,也可以直接使用这个板子自带的neopixel,我这里选择并调用的是blink(闪烁)和colorcycle(色彩循环)两种动画效果,为了省事,colorcycle直接带有‘rainbow’的循环模式,连颜色都不用自己选了。可以设置动画速度(说起来是speed,其实是一个动画的周期,单位是秒)、亮度等等。

    为了控制LED,还需要按键,我这里使用的是自带的boot按键,RST是复位按键,不能当普通按键使用。按键控制的电平通过io口读取,所以要调用digitalio库,使用DigitalInOut(board.BOOT0)获得boot按键对应io口的实例,并用direction属性控制输入(Direction.INPUT)或是输出,用pull属性设置输入模式是上拉(Pull.UP)或下拉(Pull.DOWN),IO口输入的电平值可以使用buttom.value来获取。

任务3演示

 

    以下是我的代码,三种显示模式:翡翠色快闪,蕾丝白慢闪和彩虹色循环,按一次键变一次。

import board
import time
import neopixel
from digitalio import DigitalInOut,Direction,Pull
from adafruit_led_animation.animation.blink import Blink
from adafruit_led_animation.animation.colorcycle import ColorCycle
#从adafruit_led_animation.color库导入五种颜色定义
from adafruit_led_animation.color import JADE, BLACK, ORANGE, GOLD, OLD_LACE

#初始化像素灯
pixel_pin = board.NEOPIXEL
pixel_num = 1
pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=0.1, auto_write=False, pixel_order=neopixel.GRB)

#初始化按键BOOT0
buttom = DigitalInOut(board.BOOT0)
buttom.direction = Direction.INPUT
buttom.pull = Pull.UP

#LED模式状态指示物
pixel_modeflag = 0
blink = Blink(pixels, speed=0.5, color=BLACK)
colorcycle = ColorCycle(pixels, speed=0.5)

#主循环
while True:
    if not buttom.value:
        pixel_modeflag = pixel_modeflag + 1
        if (pixel_modeflag % 3 == 1):
            blink = Blink(pixels, speed=0.2, color=JADE)
            print("LED is Blink in JADE")
        elif (pixel_modeflag % 3 == 2):
            blink = Blink(pixels, speed=1, color=OLD_LACE)
            print("LED is Blink in OLD_LACE")
        elif (pixel_modeflag % 3 == 0):
            colorcycle = ColorCycle(pixels, speed=0.1)
            print("LED is ColorCycle in RAINBOW")
    else:
        pass
    time.sleep(0.2)
        
    if (pixel_modeflag % 3 == 0):
        colorcycle.animate()
    else:
        blink.animate()

 

任务4:分任务1:日历&时钟

    除了调库,还是调库。这次的任务需要用到任务1和任务2的内容,而且用单片机从网络上获取数据我还是第一次做,所以我对获取到的json print出来,先看看结构是怎么样的!

串口时间数据.png
获取当前时间
image.png  
获取当地天气等信息
    可以看出,获得的内容是一个大的字典,键值对中的值也可能是数组,所以要看清结构之后再调用。
    此外,使用网站获取天气信息,需要查询你们当地的城市编码,可以从这里找 https://github.com/LS-KR/China-Citycode/blob/main/citycode.json
    我实现的万年历效果是,先在while中连接wifi,如果wifi.radio.connected为0,那么就是没连接上(不管你是连接出错、还是没有这个wifi)过两秒重新尝试连接,否则不进行后续活动,连接成功后每隔60s更新一次时间和天气。详细代码如下
import board
import os, wifi
import time
import ssl
import socketpool
import adafruit_requests

from adafruit_display_text import bitmap_label
from adafruit_bitmap_font import bitmap_font

#获取数据,返回str
def get_date():
    try:
        response = requests.get(JSON_TIME_URL)
        print(response.json())
    except ConnectionError as e:
        print("Connection Error:",e)
        print("Retrying in 60 seconds")
    time_date = response.json()

    city_code = "101180901"
    url = JSON_WEATHER_URL.format(city_code)
    try:
        response = requests.get(url)
        print(response.json())
    except ConnectionError as e:
        print("Connection Error:",e)
        print("Retrying in 60 seconds")
    city_date = response.json()   
     
    City_Name = city_date['cityInfo']['parent']+'省 '+city_date['cityInfo']['city']
    City_Weather = city_date['data']
    City_Forecast = City_Weather['forecast']
    CurrentTime = time_date['sysTime2'] + '  ' + City_Forecast[0]['week']
    TotalStr = City_Name
    TotalStr += "\n时间:" + CurrentTime
    TotalStr += "\n空气质量:" + City_Weather['quality']
    TotalStr += "\n温度:" + City_Weather['wendu'] + '℃'
    TotalStr += "\n湿度:" + City_Weather['shidu']
    print(type(TotalStr))
    return TotalStr

#屏幕显示,输入字符串
def screen_display(text):
    text_area = bitmap_label.Label(font,color=color["white"])
    text_area.scale = 1
    text_area.x = 0
    text_area.y = 5
    text_area.text = text
    display.show(text_area)

#显示屏显示初始化
font = bitmap_font.load_font("wenquanyi_9pt.pcf")
display = board.DISPLAY
color = {
        "black" : 0x000000,
        "white" : 0xFFFFFF,
        "red" : 0xFF0000,
        "green" : 0x00FF00,
        "blue" : 0x0000FF,
        "yellow" : 0xFFFF00,
        }

#wifi连接
while not wifi.radio.connected:
    try:
        wifi.radio.connect('你的wifi名称','1234567890')
    except ConnectionError as e:
        print("Wifi connect error:{},wait for retry".format(e))
    time.sleep(2)

print(f"IP Address:{wifi.radio.ipv4_address}" )

#请求获取JSON
JSON_TIME_URL = "http://quan.suning.com/getSysTime.do"
JSON_WEATHER_URL = "http://t.weather.sojson.com/api/weather/city/{}"

pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())


while True:       
    screen_display(get_date())
    time.sleep(60)

最终效果如下

image.png  

 

第三部分:程序源码

我已经把四个任务的程序源码打包上传,各自分成一个文件夹,下载链接如下:

download.eeworld.com.cn/detail/艾嘉西斯之铠/629322?type__2276=n4%2BxcD9DRD0DuDAhi7D%2FjeeY5mhhDUxD5ii45x&alichlgref=http%3A%2F%2Fbbs.eeworld.com.cn%2Fmy%2Fhome.php%3Fcur%3Dmyhome%26act%3Ddownload

 

心得体会

此次Followme活动让我第一次接触到了CircuitPython,不得不感慨,用Python写单片机真的简单了不只一星半点,再加上CircuitPython有着还算详细的说明手册。
以上这些优点让我有信心用这块开发板加上CircuitPython语言完成我们专业的寻迹小车课程设计。事实上我确实完成了寻迹、避障、终点识别、路程时间图像显示的任务,而且是仅在code.py文件里写了300行代码就实现了,用STM32的话我都不敢想要多少行。但是这个语言也有很大的短板:不支持中断...不管是定时器中断还是外部中断,我都没找到使用说明或者例程,网上说CircuitPython就是没有这个功能...唉,只用if else做寻迹小车,在实现某些功能的时候也确实是够不方便的。
总而言之,这个开发板是真不错,我也很喜欢,但是CircuitPython还是给初学者用吧...

回复评论 (2)

保研是大事整好了吧

点赞 (1) 2023-11-18 10:31

楼主辛苦了,为楼主的辛苦劳动和无私奉献点赞,顶起

点赞 (1) 2023-11-18 21:02
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复