880|4

7

帖子

2

TA的资源

一粒金砂(中级)

楼主
 

【得捷电子Follow me第2期】ESP32-S3 TFT Feather 实现一个日历&时钟 [复制链接]

  本帖最后由 ctrlshift12138 于 2023-11-15 23:48 编辑

第一部分

 

短视频


 

第二部分

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

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


import board
import displayio
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
import time

display = board.DISPLAY
group = displayio.Group()



oppo_sans_meduim = bitmap_font.load_font("font/OPlusSans3.0-Medium-20.bdf")     # 载入字体
green_color = 0x00CA39                                                          # 绿色

# 文本标签1
text_label_1 = label.Label(font = oppo_sans_meduim, text = "DigiKey得捷 × EEWorld", color = green_color)
text_label_1.x = 8
text_label_1.y = 19

# 文本标签2
text_label_2 = label.Label(font = oppo_sans_meduim, text = "Follow me", color = green_color)
text_label_2.x = 65
text_label_2.y = 55

# 文本标签3
text_label_3 = label.Label(font = oppo_sans_meduim, text = "任务1:控制屏幕显示中文", color = green_color)
text_label_3.x = 8
text_label_3.y = 93

# 显示文本标签
group.append(text_label_1)
group.append(text_label_2)
group.append(text_label_3)

display.show(group)

while True:
    pass

 

ESP32 S3 TFT Feather 原生只有英文字库。想要显示中文,需要调用 adafruit_bitmap_font 库,来显示点阵格式的中文。如何生成adafruit_bitmap_font支持的字体格式文件可以看上面的视频。

 

驱动屏幕:

display = board.DISPLAY

CircuitPython库函数十分强大,只需要一行代码即可控制屏幕。

 

显示汉字:

oppo_sans_meduim = bitmap_font.load_font("font/OPlusSans3.0-Medium-20.bdf")     # 载入字体
green_color = 0x00CA39                                                          # 绿色

# 文本标签1
text_label_1 = label.Label(font = oppo_sans_meduim, text = "DigiKey得捷 × EEWorld", color = green_color)
text_label_1.x = 8
text_label_1.y = 19

使用 bitmap_font.load_font 函数来载入字体文件,label.Label 创建一个文本标签,font、text、color、x、y分别代表文本标签的字体、文本内容、颜色、x坐标、y坐标属性。

 

group = displayio.Group()
group.append(text_label_1)
display.show(group)

displayio.Group() 表示创建一个显示group,

group.append(text_label_1),将文本标签 text_label_1 添加到显示 group,

display.show(group),在屏幕上将group中的内容显示出来

 

任务2:网络功能使用

创建热点

CircuitPython 创建热点十分简单,只需要一行代码就能搞定。

########################################################################
# 任务2:网络功能使用
# part1:创建热点
########################################################################

import board
import displayio
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font

import wifi


display = board.DISPLAY
group = displayio.Group()

my_ssid = "ESP32_S3"                                        # 热点 SSID
my_password = "12345678"                                    # 热点 password

wifi.radio.start_ap(ssid=my_ssid, password=my_password)     # 创建热点


# 载入字体
oppo_sans_meduim = bitmap_font.load_font("font/OPlusSans3.0-Medium-20.bdf")
green_color = 0x00CA39                                      # 绿色

# 文本标签1
text_label_1 = label.Label(font = oppo_sans_meduim, text = "任务2:网络功能使用", color = green_color)
text_label_1.x = 24
text_label_1.y = 14

# 文本标签2
text_label_2 = label.Label(font = oppo_sans_meduim, text = "创建热点", color = green_color)
text_label_2.x = 80
text_label_2.y = 40

# 文本标签3
text_label_3 = label.Label(font = oppo_sans_meduim, text = "SSID:"+my_ssid, color = green_color)
text_label_3.x = 47
text_label_3.y = 66

# 文本标签4
text_label_4 = label.Label(font = oppo_sans_meduim, text = "password:"+my_password, color = green_color)
text_label_4.x = 24
text_label_4.y = 92

# 显示文本标签
group.append(text_label_1)
group.append(text_label_2)
group.append(text_label_3)
group.append(text_label_4)

display.show(group)

while True:
    pass

 

 

 

wifi.radio.start_ap(ssid=my_ssid, password=my_password)

wifi.radio.start_ap()函数有两个入参,ssid是热点的名称,password是热点的密码。

 

连接WiFi

连接WiFi也十分简单,同样只需要一行代码就能搞定。

########################################################################
# 任务2:网络功能使用
# part1:连接WiFi
########################################################################


import board
import displayio
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
import time

import os
import wifi
import socketpool
import adafruit_requests


display = board.DISPLAY
group = displayio.Group()

# 使用 os.getenv 函数,从 setting.toml 文件里获取wifi ssid 、密码
my_ssid = os.getenv("CIRCUITPY_WIFI_SSID")                                  # 获取 WiFi 的 SSID
my_password = os.getenv("CIRCUITPY_WIFI_PASSWORD")                          # 获取 WiFi 的 password
wifi.radio.connect(ssid=my_ssid, password=my_password)                      # 连接WiFi



oppo_sans_meduim = bitmap_font.load_font("font/OPlusSans3.0-Medium-20.bdf") # 载入字体
green_color = 0x00CA39      # 绿色

# 文本标签1
text_label_1 = label.Label(font = oppo_sans_meduim, text = "任务2:网络功能使用", color = green_color)
text_label_1.x = 24
text_label_1.y = 14

# 文本标签2
text_label_2 = label.Label(font = oppo_sans_meduim, text = "连接到WiFi网络", color = green_color)
text_label_2.x = 47
text_label_2.y = 50

# 显示文本标签
group.append(text_label_1)
group.append(text_label_2)


# 获取 bing 首页的内容
url = "http://www.bing.com"
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(socket_pool=pool)


while True:
    try:
        print("Fetching text from %s" % url)
        response = requests.get(url)                # 获取网页内容
        print("-"*40)
        print("Text Response: ", response.text)     # 将网页内容通过串口打印出来
        print("-"*40)
        response.close()
        time.sleep(60)
    except Exception as e:
        print("Error:\n",str(e))
        time.sleep(10)
my_password = os.getenv("CIRCUITPY_WIFI_PASSWORD") 
my_ssid = os.getenv("CIRCUITPY_WIFI_SSID") 

os.getenv()函数是从根目录下的 setting.toml文件中获取配置参数。

 

setting.toml文件内容如下:

CIRCUITPY_WIFI_SSID = "1708"
CIRCUITPY_WIFI_PASSWORD = "tsl199725?"

 

任务3:控制WS2812B

########################################################################
# 任务3:控制WS2812B
########################################################################


import board
import displayio
import time
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
from digitalio import DigitalInOut, Direction,Pull
import neopixel
from adafruit_led_animation.animation.blink import Blink
from adafruit_led_animation.color import JADE, BLACK, ORANGE,GOLD,OLD_LACE,AQUA

display = board.DISPLAY
group = displayio.Group()

pixel_pin = board.NEOPIXEL                              # 初始化neopixel引脚
num_pixels = 1                                          # 设置灯珠数量为1
pixels = neopixel.NeoPixel(pin = pixel_pin,             # 初始化 neopixel
                           n=num_pixels,
                           brightness=0.2,
                           auto_write=False,
                           pixel_order=neopixel.GRB)
blink = Blink(pixel_object=pixels,
              speed=0.5,
              color=BLACK)                              # 初始化 Blink 效果,默认为黑色



oppo_sans_meduim = bitmap_font.load_font("font/OPlusSans3.0-Medium-20.bdf")# 载入字体
green_color = 0x00CA39                                  # 绿色

# 文本标签1
text_label_1 = label.Label(font = oppo_sans_meduim, text = "任务3:控制WS2812B", color = green_color)
text_label_1.x = 24
text_label_1.y = 14

# 文本标签2
text_label_2 = label.Label(font = oppo_sans_meduim)
text_label_2.text = "按BOOT键开始"
text_label_2.x = 47
text_label_2.y = 50

# 显示文本标签
group.append(text_label_1)
group.append(text_label_2)
display.show(group)

btn = DigitalInOut(board.BOOT0)                         # 初始化 BOOT0 按钮
btn.direction = Direction.INPUT                         # BOOT0 引脚设置为输入模式
btn.pull = Pull.UP                                      # BOOT0 引脚为上拉
index = 0                                               # 用于颜色切换


while True:
    if not btn.value:                                   # 按键被按下 value = 0
        index = index + 1
        if index % 5 == 0:
            index = 0                                   # index 置零
            blink = Blink(pixels, speed=0.5, color=JADE)
            text_label_2.color = JADE
            text_label_2.text = "LED is JADE"

        elif index % 5 == 1:
            blink = Blink(pixels, speed=0.5, color=ORANGE)
            text_label_2.color = ORANGE
            text_label_2.text = "LED is ORANGE"

        elif index % 5 == 2:
            blink = Blink(pixels, speed=0.5, color=GOLD)
            text_label_2.text = "LED is GOLD"
            text_label_2.color = GOLD
        elif index % 5 == 3:
            blink = Blink(pixels, speed=0.5, color=OLD_LACE)
            text_label_2.color = OLD_LACE
            text_label_2.text = "LED is OLD_LACE"

        elif index % 5 == 4:
            blink = Blink(pixels, speed=0.5, color=AQUA)
            text_label_2.color = AQUA
            text_label_2.text = "LED is AQUA"

        display.show(group)
        blink.animate()
        time.sleep(0.2)                                 # 按键防抖

    else:                                               # 按键未被按下
        pass

 

LED is AQUA!

 

 

WS2812B

ws2812是一种可编程控制的LED灯,pin脚如下:

 

除了VDD和VSS电源脚,它还有DIN、DOUT脚,数据传输协议采用单 NZR 通信,多个WS2812首尾相连,可以组成一个灯带。

CircuitPython可以使用 neopixel 库来驱动这颗WS2812。

 

按键

板子上有2个按键,RST和BOOT0。RST用作复位,BOOT0用作LED控制。

btn = DigitalInOut(board.BOOT0)
btn.direction = Direction.INPUT
btn.pull = Pull.UP

Direction.INPUT 将BOOT0 对应的引脚设置为输入模式,Pull.UP 将引脚状态设置为上拉,while循环内轮询BOOT0状态,等于0时候,说明按键被按下。

 

任务4:日历&时钟

########################################################################
# 任务4:日历&时钟
# 完成一个可通过互联网更新的万年历时钟,并显示当地的天气信息
########################################################################


import board
import displayio
import adafruit_imageload
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
import os
import rtc                                                  # RTC 库,实现 RTC 时钟
import wifi
import time

import ssl
import socketpool
import adafruit_ntp
import adafruit_requests

def get_city_code(key):
    """
    根据 IP 获取 城市的adcode编码
    """
    # key = "9985bb2816f45f621228e7afe61fc79d"                # 使用的是高德API,使用该API需要去注册账户,申请key。
    get_city_code_url = "https://restapi.amap.com/v3/ip?key=" + key
    response = requests.get(get_city_code_url)
    json_resp = response.json()
    response.close()
    print("city_code", json_resp["adcode"])
    return json_resp["adcode"]


def get_weather(key):
    """
    获取天气信息
    """
    city = get_city_code(key)                                # 设置城市id
    key = "9985bb2816f45f621228e7afe61fc79d"                # 使用的是高德API,使用该API需要去注册账户,申请key。
    get_weather_url = "https://restapi.amap.com/v3/weather/weatherInfo?city=" + city + "&key=" + key
    response = requests.get(get_weather_url)                # 获取天气数据
    json_resp = response.json()                             # 解析天气数据为 json 字典格式
    response.close()                                        # 关闭连接
    for da in json_resp["lives"]:
        return da["city"], da["weather"], da["windpower"], da["temperature"], da["humidity"]


def get_wday(wday):
    """
    根据时间结构体获取到的tm_wday属性,判断是星期几
    """
    if(wday == 0):
        return "周一"
    elif(wday == 1):
        return "周二"
    elif(wday == 2):
        return "周三"
    elif(wday == 3):
        return "周四"
    elif(wday == 4):
        return "周五"
    elif(wday == 5):
        return "周六"
    elif(wday == 6):
        return "周日"

display = board.DISPLAY
group = displayio.Group()


"""
===创建背景图片===
"""
bg_image, palette = adafruit_imageload.load(file_or_filename= "/pic/bg1.png")#加载图片
palette.make_transparent(100)                                               # 设置图片透明度
bg_image_grid = displayio.TileGrid(bitmap=bg_image, pixel_shader=palette)
group.append(bg_image_grid)
display.show(group)


"""
===创建文本标签以显示文字===
"""
oppo_sans_16 = bitmap_font.load_font("/font/OPlusSans3.0-Medium-16.bdf")    # 载入字体
oppo_sans_20 = bitmap_font.load_font("/font/OPlusSans3.0-Medium-20.bdf")
oppo_sans_64 = bitmap_font.load_font("/font/OPlusSans3.0-Medium-64.bdf")
black_color = 0x000000

date = label.Label(font=oppo_sans_20, color = black_color)                  # 日期标签
date.x = 17
date.y = 15


week = label.Label(font = oppo_sans_20, color = black_color)                # 星期标签
week.x = 30
week.y = 42

timeL = label.Label(font = oppo_sans_64, color = black_color)               # 时间标签
timeL.x = 80
timeL.y = 27

city = label.Label(font = oppo_sans_16, color = black_color)                # 城市标签
city.x = 29
city.y = 67

weather = label.Label(font = oppo_sans_16, color = black_color)             # 天气标签
weather.x = 29
weather.y = 98

wind = label.Label(font = oppo_sans_16, color = black_color)                # 风力标签
wind.x = 104
wind.y = 98

temp = label.Label(font = oppo_sans_16, color = black_color)                # 温度标签
temp.x = 29
temp.y = 123

humidity = label.Label(font = oppo_sans_16, color = black_color)            # 湿度标签
humidity.x = 104
humidity.y = 123


# 将标签添加到 group 中
group.append(date)
group.append(week)
group.append(timeL)
group.append(city)
group.append(weather)
group.append(wind)
group.append(temp)
group.append(humidity)
display.show(group)

# 使用 os.getenv 函数,从 setting.toml 文件里获取wifi ssid 、密码和 key
ssid = os.getenv("CIRCUITPY_WIFI_SSID")
password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
key = os.getenv("KEY")


# 连接 wifi
print("Conneccting to", ssid)
wifi.radio.connect(ssid, password, timeout = 10)
print("Connected to", ssid)


# 使用adafruit_ntp.NTP函数初始化ntp服务,第一个函数是确定网络连接端口,
# 使用阿里云的 NTP 服务器,时区是+8时区。
pool = socketpool.SocketPool(wifi.radio)
ntp = adafruit_ntp.NTP(socketpool= pool,
                       server= "ntp.aliyun.com",
                       port = 123,
                       tz_offset=8)
rtc.RTC().datetime = ntp.datetime                           # 使用ntp时间更新系统时间。


requests = adafruit_requests.Session(socket_pool=pool,      # 初始化 requests 对象
                                     ssl_context= ssl.create_default_context())

status = "boot"                                             # 先创建一个status变量,用来在设备启动时获取天气信息
flash_screen = False                                        # 刷新屏幕标志位
last_second = 61                                            # 记录上一秒的值,用来实现时间刷新

while True:
    t = time.localtime()                                    # 获取一次本地RTC时间

    # 首次启动或者每隔10分钟,更新日期标签和天气标签
    if (status == "boot" or t.tm_min%10 == 0):
        date.text = "%2d/%2d" % (t.tm_mon, t.tm_mday)       # 更新日期标签
        week.text = get_wday(t.tm_wday)                     # 更新星期标签

        city_str, weather_str, wind_str, temp_str, hunidity_str = get_weather(key)  # 获取天气信息

        city.text = city_str                                # 城市信息
        weather.text = weather_str                          # 天气信息
        wind.text = wind_str                                # 风力
        temp.text = "%s℃" % (temp_str)                     # 温度
        humidity.text = "%2s%%" % (hunidity_str)            # 湿度
        status = "updated"                                  # 更新 status 为 updated
        flash_screen = True                                 # 刷新屏幕标志位置位

    # 如果过了1秒,刷新屏幕
    if (t.tm_sec is not last_second):
        flash_screen = True                                 # 刷新屏幕标志位置位
        last_second = t.tm_sec                              # 更新last_second
        if (t.tm_sec %2 == 0):                              # 每隔1秒 更新一次时钟标签,用于动态显示
            timeL.text = "%02d:%02d" % (t.tm_hour, t.tm_min)
            timeL.color = 0x000000
        else:
            timeL.text = "%02d:%02d" % (t.tm_hour, t.tm_min)
            timeL.color = 0xD9D7C9
    if (flash_screen):
        display.show(group)                                 # 刷新屏幕
        flash_screen = False
    time.sleep(0.2)                                         # 休眠0.2秒

 

实现思路是这样的:

1、板子先连接上WiFi网络;

2、联网后,使用NTP协议,同步网络时间;
3、通过网络ip,获取所在的城市,再获取所在城市的天气状况;

4、把时间和天气信息输出到屏幕上。

 

同步网络时间

pool = socketpool.SocketPool(wifi.radio)
ntp = adafruit_ntp.NTP(socketpool= pool,
                       server= "ntp.aliyun.com",
                       port = 123,
                       tz_offset=8)
rtc.RTC().datetime = ntp.datetime

使用adafruit_ntp.NTP函数初始化ntp服务,socketpool是网络连接端口,server是NTP服务器的域名、port是端口号(一般是123)、tz_offset是时区偏移,我们在东八区,所以是8;

rtc.RTC().datetime = ntp.datetime,将NTP时间,赋值给芯片中的RTC时钟。

 

获取天气

def get_city_code(key):
    """
    根据 IP 获取 城市的adcode编码
    """
    # key = "9985bb2816f45f621228e7afe61fc79d"                # 使用的是高德API,使用该API需要去注册账户,申请key。
    get_city_code_url = "https://restapi.amap.com/v3/ip?key=" + key
    response = requests.get(get_city_code_url)
    json_resp = response.json()
    response.close()
    print("city_code", json_resp["adcode"])
    return json_resp["adcode"]


def get_weather(key):
    """
    获取天气信息
    """
    city = get_city_code(key)                                # 设置城市id
    key = "9985bb2816f45f621228e7afe61fc79d"                # 使用的是高德API,使用该API需要去注册账户,申请key。
    get_weather_url = "https://restapi.amap.com/v3/weather/weatherInfo?city=" + city + "&key=" + key
    response = requests.get(get_weather_url)                # 获取天气数据
    json_resp = response.json()                             # 解析天气数据为 json 字典格式
    response.close()                                        # 关闭连接
    for da in json_resp["lives"]:
        return da["city"], da["weather"], da["windpower"], da["temperature"], da["humidity"]

get_city_code()函数用来获取城市代码,get_weather()函数,根据get_city_code()的城市代码,获取本地的天气信息。两个函数都说调用的是高德API。

 

时间刷新

last_second = 61
flash_screen = False
while True:
    t = time.localtime()
    if (t.tm_sec is not last_second):
        flash_screen = True
        last_second = t.tm_sec

last_second 表示上一秒的秒数

flash_screen是刷新屏幕标志位,True表示需要刷新屏幕

 

while循环中,通过获取time.localtime()获取当前时间,if (t.tm_sec is not last_second)判断秒数t.tm_sec是否变化了,如果t.tm_sec与上一次不同,新屏幕标志位flash_screen置为True,并且last_second同步更新。

 

第三部分

 

源码

https://download.eeworld.com.cn/detail/ctrlshift12138/629892

 

【得捷电子Follow me第2期】代码合集.zip (415.49 KB, 下载次数: 2)

最新回复

这个厉害了,很详细  详情 回复 发表于 2023-11-20 10:03
点赞(1) 关注
 
 

回复
举报

6587

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

CircuitPython库函数十分强大,只需要一行代码即可控制屏幕,确实牛

 
 
 

回复

731

帖子

5

TA的资源

纯净的硅(高级)

板凳
 

楼主辛苦了,感谢楼主提供的这么好技术分享,顶起来

 
 
 

回复

6841

帖子

11

TA的资源

版主

4
 
大佬,这帖子确实不错,可能拿个大奖了。
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

5
 
这个厉害了,很详细
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表