【得捷电子Follow me第2期】+基于CircuitPython的任务总结 【修改调整版】
[复制链接]
本帖最后由 手下败酱 于 2023-12-13 11:20 编辑
//内容一:3-5分钟短视频//
上传视频:【得捷电子Follow me第2期】任务项目简-【得捷电子Follow me第2期】任务项目简介-EEWORLD大学堂
//内容二: 任务/项目总结报告//
项目介绍
使用 Adafruit ESP32-S3 TFT Feather 这块MINI的开发板上的资源和一些模块在基于CircuitPython来实现以下几个项目任务的功能:
1、任务1:控制屏幕显示中文(必做任务)
完成屏幕的控制,并且能显示中文
2、任务2:网络功能使用(必做任务)
完成网络功能的使用,能够创建热点和连接到WiFi
3、任务3:控制WS2812B(必做任务)
使用按键控制板载Neopixel LED的显示和颜色切换
4、任务4:日历&时钟
完成一个可通过互联网更新的万年历时钟,并显示当地的天气信息
各任务功能对应的主要代码片段及说明&&各任务功能展示及说明
任务1:控制屏幕显示中文
效果图
任务功能对应的主要代码片段及说明
准备工作: Adafruit ESP32-S3 TFT Feather 板子 拿到板子之后把下载到的包(adafruit-circuitpython-adafruit_feather_esp32s3_tft-en_US-8.2.6.uf2)拖到电脑显示的U盘里面
还需要有几个工具,因为要显示的中文字,在库里面没有哦,所以需要自己生成或者使用别人整理好的字库文件,当然使用自己喜欢的字体是多么美好的一件事情啦。 FontSmaller_2.0 FontSmaller 字体文件子集化工具
u8g2_fontmaker
这两个就是我生成bdf的字库的工具了,使用方法也非常简单
在自己电脑路径找一下自己喜欢的字体 C:\Windows\Fonts 打开FontSmaller_2.0 直接选中喜欢的字体,再出入自己需要显示的
字
点击 OK 选择生成路径,这样字库就好了
再用u8g2_fontmaker转bdf一下就好了 具体用法去看一下reade me 就知道了 其实就是修改这个文件就行了,对了别忘记把刚刚转的字体文件放进 font 文件
最后把生成的bdf文件拖进自己放字体的文件夹 听说把bdf转成pdf 加载速度会更快些 网站我也丢这里了
BDFtopCF字体转换器 (adafruit.github.io)
以下为code.py 中的源代码说明
这段主要是导入相关的模块有板子自带的,也有存放在板子U盘中
#导入自带模块
import board
import displayio
#导入显示图片、显示位图字体模块等其他的
import adafruit_imageload
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.scrolling_label import ScrollingLabel
from adafruit_display_text import label
from adafruit_st7789 import ST7789
一些TFT屏幕的初始化,还有一些定义
# 使用固件自带的屏幕设备,不需要另行初始化屏幕参数
display = board.DISPLAY
# 创建本例程里的唯一图像组
group = displayio.Group()
# 加载字体并定义字体颜色为黑色
font = bitmap_font.load_font("/font/Jay_Chou-16.bdf")
nun_font = bitmap_font.load_font("/font/UPO-48.bdf")
color = 0xFFFFFF
这段主要是对label的处理,先把显示的内容存放,再调用label函数 第一个函数是字体 第二个是显示的文本 第三个是显示的颜色 第四个是显示的背景颜色,最后一个是最大宽度,在设置一下ScrollingLabel函数实现滚动 最后显示图像数组,最后在主循环中循环滚动
############################显示##########################################
date = label.Label(font, text=" 晴天 \n – 周杰伦 (Jay Chou)", color=color)
date.x = 10
date.y = 10
group.append(date)
text1 = "\n 故事的小黄花\n 从出生那年就飘着\n 童年的荡秋千\n 随记忆一直晃到现在\n Re So So Si Do Si La\n So La Si Si Si Si La Si La So\n 吹着前奏望着天空\n 我想起花瓣试着掉落\n "
text_area = label.Label(font, text=text1, color=0x0000FF, background_color=0xFFAA00,max_characters=20)
#max_characters 显示的长度 animate_time 滚动的速度
text_area =ScrollingLabel(font,text=text1, max_characters=80, animate_time=0.26)
text_area.x = 10
text_area.y = 68
group.append(text_area)
###############################################################################
# 显示修改后的图像组
display.show(group)
#循环
while True:
text_area.update()
这里是整个工程的文件
任务1_中文显示.rar
这是效果是视频
中文显示
任务2:网络功能使用(必做任务)
效果图
注:上图最上面显示的IP地址是已连接到WIFI,给分配的IP 最下面打印的那两行是创建的热点,WIFI名称以及WIFI密码 手机可以搜索到
任务功能对应的主要代码片段及说明
首先是创建热点,这也非常简单,导入 import wifi 这个库
然后再调用 start_ap 这个函数,填入你的热点名称和密码 即可
也可以把创建的name 、password以及IP add 打印到屏幕上去,这里我只把 name 、password显示出来了,以下是全部代码
import os
import time
import ssl
import wifi
import socketpool
import microcontroller
import adafruit_requests
wifi.radio.start_ap("adafruit_wifi", "12345678")
print(f"NtworkName: adafruit_wifi")
print(f"Password: 12345678")
while True:
pass
连接WIFI 配置下面这个文件就可以了
这是源码
任务3:控制WS2812B(必做任务)
大概思路:
先处理LED引脚的定义和LED 驱动
再去处理按键的一些定义和按键处理逻辑,还有屏幕的初始化
最后在主循环中一直循环判断哪一个按键按下
再去执行LED和TFT的效果
任务功能对应的主要代码片段及说明
关于导入的相关库
# 导入board内置库
import board
# 导入neopixel内置库
import neopixel
import digitalio,terminalio,displayio
# 导入time内置库
import time
import key
from adafruit_display_text import label
# 从digitalio内置库导入DigitalInOut, Direction, Pull
from digitalio import DigitalInOut, Direction, Pull
# 从adafruit_led_animation.color库导入五种颜色定义
from adafruit_led_animation.color import JADE,BLACK, ORANGE, GOLD, OLD_LACE
先去处理关于LED相关的引脚以及LED的驱动,这里我使用了两个引脚来驱动 WS2812
#关于LED的定义**************************************************************************
led_io = digitalio.DigitalInOut(board.NEOPIXEL_POWER)
led_io.direction = digitalio.Direction.OUTPUT
led_io.value = True
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
# 亮度
pixel.brightness = 0.1
pixe2 = neopixel.NeoPixel(board.A0, 16)
# 亮度
pixe2.brightness = 0.1
这里就是我单独写的一个按键处理的文件。定义了5个按键都是独立按键
# 初始化btn按钮对象
btn = DigitalInOut(board.BOOT0)
# 设置btn引脚为输入
btn.direction = Direction.INPUT
# 设置btn引脚为上拉
btn.pull = Pull.UP
......
......
btn4 = DigitalInOut(board.A4)
# 设置btn1引脚为输入
btn4.direction = Direction.INPUT
# 设置btn引脚为上拉
btn4.pull = Pull.UP
def key():
time.sleep(0.1) # sleep for debounce
if btn.value==0:
time.sleep(0.1) # sleep for debounce
if btn.value==0:
return 1
elif btn1.value==0:
return 2
elif btn2.value==0:
return 3
elif btn3.value==0:
return 4
elif btn4.value==0:
return 5
else :
return 0
配置屏幕的参数,这里直接调用封装号的配置处理
#屏幕的基础配置
display= board.DISPLAY
下面就是主循环了:
# 进入while循环
while True:
#进入循环先一直判断按键按下
key_value=key.key()
# 判断按键是否按下
if key_value!=0:
# 若按键按下,则根据余数指定led颜色
time.sleep(0.1) #这里就是按键消抖
print(key_value) #打印哪一个按键按下
if key_value == 1: #按键1按下了,执行里面的程序
pixel.fill((JADE))# 玉色
pixe2.fill((JADE))# 玉色
text ="JADE"
text_area =label.Label(terminalio.FONT,text=text, color=JADE,x=10,y=30)
text_group=displayio.Group(scale=2 ,x=0,y=0)
text_group.append(text_area)
display.show(text_group)
elif key_value == 2:
pixel.fill((ORANGE))# 橙色
pixe2.fill((ORANGE))# 橙色
text ="ORANGE"
text_area =label.Label(terminalio.FONT,text=text, color=ORANGE,x=10,y=30)
text_group=displayio.Group(scale=2 ,x=0,y=0)
text_group.append(text_area)
display.show(text_group)
elif key_value == 3:
pixel.fill((GOLD))# 金色
pixe2.fill((GOLD))# 金色
text ="GOLD"
text_area =label.Label(terminalio.FONT,text=text, color=GOLD,x=10,y=30)
text_group=displayio.Group(scale=2 ,x=0,y=0)
text_group.append(text_area)
display.show(text_group)
elif key_value == 4:
pixel.fill((OLD_LACE))#
pixe2.fill((OLD_LACE))#
text ="OLD_LACE"
text_area =label.Label(terminalio.FONT,text=text, color=OLD_LACE,x=10,y=30)
text_group=displayio.Group(scale=2 ,x=0,y=0)
text_group.append(text_area)
display.show(text_group)
elif key_value == 5:
pixel.fill((BLACK))# 黑色
pixe2.fill((BLACK))# 黑色
text ="BLACK"
text_area =label.Label(terminalio.FONT,text=text, color=BLACK,x=10,y=30)
text_group=displayio.Group(scale=2 ,x=0,y=0)
text_group.append(text_area)
display.show(text_group)
else:
# 空
pass
任务4:日历&时钟——完成一个可通过互联网更新的万年历时钟,并显示当地的天气信息
完成一个可通过互联网更新的万年历时钟,并显示当地的天气信息
效果图
首先把界面给弄好,文字显示位置,以及图片大小,文字大小都需要考虑,这些我都在 Pixso 上处理的
主要思路:
先是处理界面根据在Pixso 上处理的图片,显示在TFT屏幕上面
# 使用固件自带的屏幕设备,不需要另行初始化屏幕参数
display = board.DISPLAY
############################图片显示##########################################
# 创建本例程里的唯一图像组
group = displayio.Group()
# 加载图片
image, palette = adafruit_imageload.load("/PIC/beijing.png")
# 是否开启透明
palette.make_transparent(1)
# 创建图片布局
grid = displayio.TileGrid(image, pixel_shader=palette)
# 将图片布局添加到图像组,由于是第一个添加的,默认是最下层
group.append(grid)
# 显示当前图像组
display.show(group)
###############################################################################
# 加载字体并定义字体颜色为黑色
font = bitmap_font.load_font("/font/MYout-24.bdf")
nun_font = bitmap_font.load_font("/font/UPO-48.bdf")
color = 0x000000
date = label.Label(font, text="10月 31日", color=color)
date.x = 25
date.y = 18
group.append(date)
# 初始化星期标签并设置x,y轴绘图坐标,然后将标签添加到图像组
week = label.Label(font, text="周六", color=color)
week.x = 179
week.y = 8
group.append(week)
# 初始化时间标签并设置x,y轴绘图坐标,然后将标签添加到图像组
time = label.Label(nun_font, text="22:59", color=0xF2C3BD)
# time.x = 20
# time.y = 60
time.x = 29
time.y = 65
group.append(time)
# 初始化天气标签并设置x,y轴绘图坐标,然后将标签添加到图像组
tempzh = label.Label(font, text="23°~34° 晴", color=color)
tempzh.x = 25
tempzh.y = 101
group.append(tempzh)
再处理网络时间更新,调用RTC函数来更新时间 , 再去处理高德API接收的值,这里分别接收了 温度和天气信息
pool = socketpool.SocketPool(wifi.radio)
ntp = adafruit_ntp.NTP(pool, tz_offset=8, server="ntp.aliyun.com")
# 使用ntp时间更新系统时间
rtc.RTC().datetime = ntp.datetime
# 初始化requests对象
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
def get_weather():
# 设置城市id
city = "410702"
# 这个函数使用的是高德API,使用该API需要先去注册相关账户,申请key。
key = "7121e4b427fa6f27704655b62db83d61"
# 拼接天气链接url
getweather_url = "https://restapi.amap.com/v3/weather/weatherInfo?city=" + city + "&key=" + key
# 获取天气json数据
response = requests.get(getweather_url)
json_resp = response.json()
# 关闭连接
response.close()
# 解析json数据,并返回温度和天气信息
for da in json_resp["lives"]:
#print(da["temperature"])
return da["temperature"], da["weather"]
# 先创建一个status变量,用来在设备启动时获取天气信息
status = "boot"
接下来就是不断在循环里面获取时间,以及天气信息
# 主循环
while True:
# 每秒获取一次本地RTC时间
t = time.localtime()
# 首次启动或者本地RTC时间的分钟属性为0时,更新日期标签和天气标签
if (status == "boot" or t.tm_sec == 0):
# 更新日期标签
date.text = "%d月%d日" % (t.tm_mon, t.tm_mday)
week.text = get_wday(t.tm_wday)
# 获取天气信息
str_t, str_tz = get_weather()
# 更新温度标签
temp.text = "%s°" % (str_t)
# 更新天气标签
tempzh.text = str_tz
status = "updated"
print(ssid)
print(str(wifi.radio.ipv4_address) )
# 每隔1秒 更新一次时钟标签,用于动态显示
if (t.tm_sec % 2 == 0):
timel_s.text = ":%02d" % ( t.tm_sec)
else:
timel.text = "%02d:%02d" % ( t.tm_hour, t.tm_min)
timel_s.text = ":%02d" % ( t.tm_sec)
key_value=key.key()
# 判断按键是否按下
if key_value!=0:
# 若按键按下,则对led_color求余数,根据余数指定led颜色
time.sleep(0.1)
print(key_value)
if key_value == 1:
pixel.fill((JADE))# 玉色
pixe2.fill((JADE))# 玉色
timel_s.color = JADE
timel.color = JADE
elif key_value == 2:
pixel.fill((ORANGE))# 橙色
pixe2.fill((ORANGE))# 橙色
timel_s.color = ORANGE
timel.color = ORANGE
elif key_value == 3:
pixel.fill((GOLD))# 金色
pixe2.fill((GOLD))# 金色
timel_s.color = GOLD
timel.color = GOLD
elif key_value == 4:
pixel.fill((PINK))#
pixe2.fill((PINK))#
timel_s.color = PINK
timel.color = PINK
elif key_value == 5:
pixel.fill((BLACK))# 黑色
pixe2.fill((BLACK))# 黑色
timel_s.color = BLACK
timel.color = BLACK
else:
pass# 空
# 刷新屏幕
display.show(group)
其他:LTR—329光传感器模块&MCP9808温度传感器
温度传感器(MCP9808)
这款 I2C 数字温度传感器是我们见过的准确度更高的传感器之一,在传感器的 -40°C 至 +125°C 范围内的典型精度为 ±0.25°C,精度为 +0.0625°C。 它们适用于任何使用标准 i2c 的微控制器。有 3 个地址引脚,因此您最多可以将 8 个地址引脚连接到单个 I2C 总线,而不会发生地址冲突。最重要的是,宽电压范围使2.7V至5.5V电压可用!
引脚说明:
- VIN (仅接头版本的 VDD) - 这是正电源和逻辑电平引脚。它可以是2.7-5.5VDC,因此适合与3或5V逻辑一起使用。电源 VIN (VDD),具有您计划在 i2c 线路上使用的任何逻辑电平。
- GND - 这是接地电源和逻辑参考引脚。
- SCL - 这是 I2C 时钟引脚。板上已经有一个 10K 上拉,因此请将其直接连接到微控制器上的 i2c 主时钟引脚
- SDA - 这是 I2C 数据引脚。板上已经有一个 10K 上拉,因此请将其直接连接到微控制器上的 i2c 主数据引脚
- Alert - 这是来自MCP9808的中断/警报引脚。芯片具有一定的功能,可以在芯片温度高于或低于设定量时“提醒”您。可以触发此输出以告知你。它是集电极开路,因此如果要从该引脚读取信号,则需要使用上拉电阻。
- A0(以及 A1 和 A2)- 这些是地址选择引脚。由于在 i2c 总线上只能有一个具有给定地址的设备,因此如果要在共享 i2c 总线上放置多个MCP9808,则必须有一种方法来调整地址。A0/A1/A2引脚设置i2c地址的底部三位。电路板上有下拉电阻,因此将它们连接到VDD以将位设置为“1”。它们在通电时读取,因此解除电源并重新通电以重置地址
默认地址0x18,地址可以通过将 A0/A1/A2 “添加”到0x18
A0 设置值为 1 的最低位,A1 设置值为 2 的中间位,A2 设置值为 4 的高位。最终地址是 0x18 + A2 + A1 + A0。
因此,例如,如果 A2 与 VDD 绑定,A0 与 VDD 绑定,则地址为 0x18 + 4 + 1 = 0x1D。
如果只有 A0 绑定到 VDD,则地址为 0x18 + 1 = 0x19
如果只有 A1 绑定到 VDD,则地址为 0x18 + 2 = 0x1A
如果只有 A2 绑定到 VDD,则地址为 0x18 + 4 = 0x1C
接线方式:
那接下来就是代码了
import time #导入延时库
import board #导入板子的资源库
import adafruit_mcp9808 #导入模块的库
i2c = board.I2C() # 使用板载的SDA和SCL
mcp = adafruit_mcp9808.MCP9808(i2c) # 使用默认地址进行初始化:
while True:
tempC = mcp.temperature
tempF = tempC * 9 / 5 + 32 #转换成 F
print("Temperature: {} C {} F ".format(tempC, tempF))
time.sleep(4)
那如果把它添加到我的天气时钟上面呢:由于我往上面哈气,温度飙到了30多°
光传感器(LTR-329)
LTR-329 光传感器是一款简单且流行的低成本 I2C 数字光传感器,易于集成到您的项目中,以实现可靠和广泛的光测量。
LTR-329ALS-01 规格:
- I2C 接口,最高快速模式 @ 400kbit/s,地址0x29(无法更改)
- 超小型芯片LED封装
- 内置温度补偿电路
- 待机模式下的低有功功耗
- 工作温度范围为 -30 C 至 +70 C
- 符合 RoHS 和无卤素标准
- 接近人眼光谱响应的光传感器
- 对红外/紫外线光源的抗扰度
- 自动抑制 50 / 60 Hz 灯光闪烁
- 6 种动态范围,从 0.01 勒克斯到 64k 勒克斯
- 16 位有效分辨率
尺寸:25.4 毫米 x 17.7 毫米 x 4.6 毫米 / 1.0“ x 0.7” x 0.2”
引脚说明
- VIN - 这是电源引脚。要为电路板供电,请为其提供与微控制器逻辑电平相同的功率 - 使用5V。
- 3V - 这是稳压器的 3.3V 输出,如果您愿意,您可以从中获取高达 100mA 的电流。
- GND - GND
- SCL - I2C 时钟引脚,连接到微控制器 I2C 时钟线。该引脚经过电平转换,因此可以使用 3-5V 逻辑,并且该引脚上有一个 10K 上拉。
- SDA - I2C 数据引脚,连接到您的微控制器 I2C 数据线。该引脚经过电平转换,因此可以使用 3-5V 逻辑,并且该引脚上有一个 10K 上拉。
它的使用方法也非常简单
调用LTR329的库,再显示到TFT屏上
import time
import board
from adafruit_ltr329_ltr303 import LTR329 #导入外部库
import displayio
# 导入外部库adafruit_display_text里的lable,用于显示标签
from adafruit_display_text import label
# 导入外部库adafruit_bitmap_font里的lable
from adafruit_bitmap_font import bitmap_font
i2c = board.I2C() # 使用板载的SDA和SCL
time.sleep(0.1) # 传感器需要100毫秒才能“启动”上电
ltr329 = LTR329(i2c)
#使用封装好的TFT驱动
display = board.DISPLAY
#创建显示组
group = displayio.Group()
#加载字体
font = bitmap_font.load_font("/font/MYout-24.bdf")
#用于显示 光强度的参数
Visible_ = label.Label(font, text="00", color=0xFF0707)
Visible_.x = 5
Visible_.y = 18
group.append(Visible_)
#用于显示 红外线的参数
Infrared_ = label.Label(font, text="00", color=0xFF07C5)
Infrared_.x = 5
Infrared_.y = 68
group.append(Infrared_)
while True:
Visible= ltr329.visible_plus_ir_light
Infrared=ltr329.ir_light
Visible_.text="Visible: %d" %(Visible)
Infrared_.text="Infrared: %d" %(Infrared)
print("Visible + IR:", ltr329.visible_plus_ir_light)
print("Infrared :", ltr329.ir_light)
print()
display.show(group)
time.sleep(0.5) # sleep0.5 S
对本活动的心得体会
非常荣幸参见本次活动,也非常感谢得捷对这次活动的支持,通过这次任务的学习,也让我从一个Python小白,成功了入了门,通过实践的效果,也有了更加深刻的印象,我非常认为这样的活动非常不错,最起码,自己也是亲手操作了,期间我自己也遇到 了不少问题,通过观看,直播教学,还有大佬们的相关教程,也解决了不少问题,也可以说顺利结束了本次活动,这次是第二期活动,现在我已经期待着第三期活动了,最后还是要感谢得捷平台,还有一些大佬的教程
//内容三:可编译下载的代码//
任务源文件:https://download.eeworld.com.cn/detail/%E6%89%8B%E4%B8%8B%E8%B4%A5%E9%85%B1/629595#related
|