【得捷电子Follow me第2期】玩转Adafruit ESP32-S3 TFT Feather (全流程综合贴)
[复制链接]
本帖最后由 QuaX_Chow 于 2023-10-14 16:18 编辑
2023.8.19(开始动工,存个草稿先)
2023.10.6
这次给大家带来的是Follow Me第二期任务的速通教学(鸽了很久
本次活动基本查阅查阅手册就可以通过
感谢主办方eeworld、得捷电子的支持,感谢各位提前发帖的大神坛友
内容一:3-5分钟短视频
内容二:本篇
内容三:本人整理的资料包(包含示例代码、任务代码、官方资料、部分外部库,打不开就是还没审核,可以先用老的资料包)
1、Quick Start
首先我们快速搭建一下我们所需的开发环境,本次使用的是官方推荐的Mu Editor编写CircuitPython。
使用数据线将开发板与电脑相连,并连按两次reset键(如下所示)
当Neo灯绿灯常亮,红色LED呼吸灯闪烁时,电脑就会显示连接到了一个新磁盘。将资料包-other中的adafruit-circuitpython-adafruit_feather_esp32s3_tft-en_US-8.2.3.uf2拖入新磁盘的根目录即可为开发板快速添加circuitpython支持包。
待文件移动完成后开发板屏幕上即会显示开发板信息和uid(如下图)同时出现一个新u盘
PS:circuitpython其实还有个中文包,但在屏幕上显示的是拼音。。(adafruit-circuitpython-adafruit_feather_esp32s3_tft-zh_Latn_pinyin-8.2.3.uf2如下所示)
再在电脑上安装好Mu Editor(下载地址),当然如thonny啥的也是可以的。
我们想要编辑代码的话,直接打开根目录(如下所示)下的code.py并编辑即可
首先我们先刷两个测试程序,程序都可以在手册或者对应库的示例代码里找到
第一个是可以直接使用的点灯程序,直接cv进code.py即可。
下载成功即可看见板载LED闪烁。
import board
import digitalio
import time
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
while True:
led.value = True
time.sleep(0.5)
led.value = False
time.sleep(0.5)
测试代码①
灯
第二个是图片显示代码,添加资料包中other-lib中的imageload库即可实现。
import board
import displayio
import adafruit_imageload
image, palette = adafruit_imageload.load(
"images/ysqd.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette
)
tile_grid = displayio.TileGrid(image, pixel_shader=palette)
group = displayio.Group()
group.append(tile_grid)
#显示
board.DISPLAY.show(group)
#
while True:
pass
测试代码②
添加外部库的方法:打开外部库的压缩包,将对应文件夹复制进开发板u盘根目录下的lib文件夹即可(如imageload库)
本代码需在根目录下创建image文件夹,并在该文件夹下粘贴下面这张已转格式的图片↓
测试图片
2、任务1:控制屏幕显示中文(必做任务)
我们想要控制屏幕显示中文的话,需要使用bitmap库将点阵字体加载到displayio中,可以使用bdf、pcf等格式,非常简单
import board
import displayio
from adafruit_display_text import label, wrap_text_to_lines
from adafruit_bitmap_font import bitmap_font
# 设置要显示的字符串
dis_str = "完成屏幕的控制并且能显示中文"
def screen_dispstr(str):
# 根据屏幕旋转角度确定每行显示的字符数
if board.DISPLAY.rotation % 180 == 0:
char_num = 23 # 横屏
else:
char_num = 13 # 竖屏
strbuf = ""
for i in range(len(str) / char_num):
# 将字符串按每行字符数拆分,并添加换行符
strbuf = strbuf + str[i * char_num:(i + 1) * char_num] + "\n"
return strbuf
# 初始化显示屏
display = board.DISPLAY
board.DISPLAY.brightness = 0.35
board.DISPLAY.rotation = 0
# 加载字体和设置颜色
font = bitmap_font.load_font("wenquanyi_10pt.pcf")
color = 0x00FFFF
# 创建显示文本的组和标签
text_group = displayio.Group()
text_area = label.Label(font, text=screen_dispstr(dis_str), color=color)
text_area.x = 2
text_area.y = 6
text_area.line_spacing = 0.8
text_area.scale = 1
text_group.append(text_area)
display.show(text_group)
# 持续显示
while True:
pass
- 初始化显示屏模块,并设置亮度和旋转角度
- 加载所需的字体文件
- 创建显示文本的组和标签对象,并设置文本内容、颜色、位置和缩放
- 将文本标签对象添加到显示文本的组中
- 使用display.show将显示文本的组添加到显示屏上进行显示
- 进入持续显示的循环,保持文本显示在屏幕上
3、任务2:网络功能使用(必做任务)
首先我们为开发板配置一下网络功能所需的信息。
在根目录下新建一个文本文档,命名为settings,保存后将后缀改为.toml(结果如下图)。
想要编辑的话以文本格式打开直接编辑或者有VS Code的话也可以直接编辑。
想实现Adafruit ESP32-S3 TFT Feather的网络功能也十分简单,参考手册P143(如下图所示)就行,但与手册方法不同的是,我们的配置信息存在了settings.toml文件中。
手册P143截图
我们先连接WiFi
在settings.toml中,配置你想要连接的WiFi的ID和密码。
PS:只支持2.4G频段,手机开个热点就行
具体如下:
WIFI_SSID = "HOMO"
WIFI_PASSWORD = "1145141919810"
配置完成后,直接在code.py中使用示例代码即可
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import wifi
print("ESP32-S3 Station Test")
print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}")
print("Available WiFi networks:")
for network in wifi.radio.start_scanning_networks():
print("\t%s\t\tRSSI: %d\tChannel: %d" % (str(network.ssid, "utf-8"),
network.rssi, network.channel))
wifi.radio.stop_scanning_networks()
print(f"Connecting to {os.getenv('WIFI_SSID')}")
wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
print(f"Connected to {os.getenv('WIFI_SSID')}")
print(f"My IP address: {wifi.radio.ipv4_address}")
连接WiFi
再创建热点
在settings.toml中,配置开发板AP的ID和密码。
具体如下:
AP_SSID = "HOMO"
AP_PASSWORD = "1145141919810"
以下代码基于自带的库
#创建热点
import os
import wifi
import adafruit_requests
print("ESP32-S3 Access Point Test")
print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}")
wifi.radio.start_ap(os.getenv("AP_SSID"), os.getenv("AP_PASSWORD"))
#显示网络信息
print(f"My SSID: {"HOMO"}")
print(f"My PASSWORD: {"1145141919810"}")
while True:
pass
创建热点
ap
4、任务3:控制WS2812B(必做任务)
要控制WS2812B,只需在lib中添加外部库neopixel.py(详见other-lib)
再再参考一下示例代码(笑
稍微改一下,用数组存储颜色信息
按钮直接用杜邦线代替,反正原理是一样的。同时添加软件消抖,效果不错
import time
import board
import digitalio
import neopixel
button_pin = board.D5
Color_Num = 0
# 彩虹数组
RAINBOW_COLORS = [
(255, 0, 0), # 红
(255, 165, 0), # 橙
(255, 255, 0), # 黄
(0, 255, 0), # 绿
(0, 0, 255), # 蓝
(75, 0, 130), # 靛蓝
(238, 130, 238) # 紫
]
#初始为红
Color = RAINBOW_COLORS[0]
button = digitalio.DigitalInOut(button_pin)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP
debounce_delay = 0.1 # 消抖延迟,单位为秒
button_pressed = False
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
pixel.brightness = 0.3
while True:
if not button.value and not button_pressed: # 按键被按下且之前未被按下
button_pressed = True
time.sleep(debounce_delay) # 延迟一段时间进行消抖
if not button.value: # 确认按键仍然被按下
Color = RAINBOW_COLORS[Color_Num]
# 设置led颜色
pixel.fill(Color)
Color_Num += 1
if Color_Num == 7:
Color_Num -= 7
elif button.value: # 按键未被按下
button_pressed = False
七彩循环:
5、任务4.1:日历&时钟(选做任务)
导入所需的库和模块,包括wifi、os、ssl、socketpool、adafruit_requests。
连接wifi,发送HTTP请求获取无锡的天气信息的JSON数据。
解析JSON数据,提取需要显示的天气信息,包括城市信息、当前时间、空气质量、温度范围、湿度、PM2.5等。
显示,结束(
##连接wifi --------------------------------------------------------------------------------------
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import wifi
print("ESP32-S3 Station Test")
print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}")
print("Available WiFi networks:")
for network in wifi.radio.start_scanning_networks():
print("\t%s\t\tRSSI: %d\tChannel: %d" % (str(network.ssid, "utf-8"),
network.rssi, network.channel))
wifi.radio.stop_scanning_networks()
print(f"Connecting to {os.getenv('WIFI_SSID')}")
wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
print(f"Connected to {os.getenv('WIFI_SSID')}")
print(f"My IP address: {wifi.radio.ipv4_address}")
## END连接wifi --------------------------------------------------------------------------------------
## 访问网络 --------------------------------------------------------------------------------------
import ssl
import socketpool
import adafruit_requests
# 请求获取JSON
## api http://t.weather.sojson.com/api/weather/city/101280601
JSON_TIME_URL = "http://t.weather.itboy.net/api/weather/city/101190201"
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
## END访问网络 --------------------------------------------------------------------------------------
## 读取解析Json ---------------------------------------------------------------------------------------
print(f"Fetching and parsing json from {JSON_TIME_URL}")
response = requests.get(JSON_TIME_URL)
print("-" * 40)
## print(f"Time: {response.json()['sysTime2']}")
print("-" * 40)
print(response.json())
weather = response.json()
cityInfo = weather['cityInfo']
city_weather = weather['data']
forecast = city_weather['forecast']
dis_str = ""+cityInfo['parent']+' '+cityInfo['city'] +' '+weather['time'][:11] + forecast[0]['week']
dis_str += '\n 空气质量:'+city_weather['quality'] +" " +forecast[0]['type']
dis_str += "\n 最"+forecast[0]['high']+' 最'+forecast[0]['low']
dis_str += "\n 湿度: "+city_weather['shidu']
dis_str += "\n PM2.5:"+str(city_weather['pm25']) +' PM10:'+str(city_weather['pm10'])
dis_str += "\n 注意!! "+forecast[0]['notice']
## END读取解析Json ---------------------------------------------------------------------------------------
## 显示天气信息 ---------------------------------------------------
import board
import displayio
from adafruit_display_text import label, wrap_text_to_lines
from adafruit_bitmap_font import bitmap_font
display = board.DISPLAY
board.DISPLAY.brightness = 0.9
board.DISPLAY.rotation = 0
font = bitmap_font.load_font("wenquanyi_10pt.pcf")
## 字体颜色
color = 0x9499CA
text_group = displayio.Group()
text_area = label.Label(font, text=dis_str, color=color)
text_area.x = 0
text_area.y = 10
text_area.line_spacing = 0.8
text_area.scale = 1
text_group.append(text_area)
display.show(text_group)
while True:
pass
## END显示天气信息 ---------------------------------------------------
- 使用WiFi模块连接到无线网络,SocketPool和Requests库访问API,获取天气预报的JSON数据
- 然后,解析JSON数据并提取所需的天气信息
- 使用Displayio库在TFT显示屏上显示天气信息
rili
6、任务4.2:WS2812B效果控制(选做任务)
先瞅一眼任务要求:
完成一个Neopixel(12灯珠或以上)控制器,通过按键和屏幕切换展示效果
凑巧上学期末整了块DFRobot 8*8的RGB灯板👇
硬件有了那直接开整
控制部分直接参考上面neo的程序就行
循环切换7个颜色
屏幕显示颜色只要在循环加个判断就行![](https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/funk1.gif)
#以下是一起动捏
import board
import digitalio
import time
import neopixel
led_pin = board.D13
button_pin = board.D5
# 设置LED数量和引脚
NUM_LEDS = 64
LED_PIN = board.D12
Color_Num = 0
# 初始化Neopixel对象
pixels = neopixel.NeoPixel(LED_PIN, NUM_LEDS, brightness=0.2, auto_write=False)
# 彩虹数组
RAINBOW_COLORS = [
(255, 0, 0), # 红
(255, 165, 0), # 橙
(255, 255, 0), # 黄
(0, 255, 0), # 绿
(0, 0, 255), # 蓝
(75, 0, 130), # 靛蓝
(238, 130, 238) # 紫
]
#初始为红
Color = RAINBOW_COLORS[0]
led = digitalio.DigitalInOut(led_pin)
led.direction = digitalio.Direction.OUTPUT
button = digitalio.DigitalInOut(button_pin)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP
debounce_delay = 0.1 # 消抖延迟,单位为秒
button_pressed = False
while True:
if not button.value and not button_pressed: # 按键被按下且之前未被按下
button_pressed = True
time.sleep(debounce_delay) # 延迟一段时间进行消抖
if not button.value: # 确认按键仍然被按下
led.value = not led.value
# 在每个LED上设置彩虹颜色
for i in range(NUM_LEDS):
Color = RAINBOW_COLORS[Color_Num]
pixels[i] = Color
pixels.show()
time.sleep(0.001)
Color_Num += 1
if Color_Num == 7:
Color_Num -= 7
elif button.value: # 按键未被按下
button_pressed = False
-
通过设置LED的数量和引脚,初始化Neopixel,定义彩虹颜色数组
-
DigitalInOut来控制LED和按钮的引脚。将LED引脚设置为输出模式,按钮引脚设置为输入模式,启用上拉电阻
-
使用time模块来进行延迟和消抖操作。在按键按下时延迟一段时间进行消抖,确保只有有效的按键触发
-
循环检测按钮状态。当按钮被按下时,切换LED的状态并设置Neopixel的像素颜色为彩虹颜色。每次按下按钮,彩虹颜色的索引加一,当达到最大索引时重新开始
8864
7、任务5:通过网络控制WS2812B(可选任务,非必做)
翻手册翻手册翻手册
官方手册P148
说实话,我还是第一次接触mqtt,但跟着例程走一遍也是没啥问题的
(后半段有所修改)
import time
import ssl
import os
from random import randint
import microcontroller
import socketpool
import wifi
import board
import neopixel
import displayio
import terminalio
import adafruit_minimqtt.adafruit_minimqtt as MQTT
from adafruit_io.adafruit_io import IO_MQTT
from adafruit_display_text import bitmap_label, label
# WiFi
try:
print("Connecting to %s" % os.getenv("WIFI_SSID"))
wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
print("Connected to %s!" % os.getenv("WIFI_SSID"))
# Wi-Fi connectivity fails with error messages, not specific errors, so this except is broad.
except Exception as e: # pylint: disable=broad-except
print("Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.")
time.sleep(30)
microcontroller.reset()
# Initialise NeoPixel
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3)
# Set up TFT display
display = board.DISPLAY
board.DISPLAY.brightness = 0.35
board.DISPLAY.rotation = 0
group = displayio.Group()
weather_color=0x00FF00
neopixel_area = label.Label(terminalio.FONT, text="NeoPixel", color=weather_color)
neopixel_area.x = 2
neopixel_area.y = 30
neopixel_area.line_spacing = 0.8
neopixel_area.scale = 1
main_group = displayio.Group()
main_group.append(group)
main_group.append(neopixel_area)
# Show the main group on the display
display.show(main_group)
# Define callback functions which will be called when certain events happen.
def connected(client):
print("Connected to Adafruit IO! Listening for NeoPixel changes...")
# Subscribe to Adafruit IO feed called "neopixel"
client.subscribe("neopixel")
def message(client, feed_id, payload): # pylint: disable=unused-argument
print("Feed {0} received new value: {1}".format(feed_id, payload))
#neopixel_area.text = "Feed {0} received new value: {1}".format(feed_id, payload)
if feed_id == "neopixel":
pixel.fill(int(payload[1:], 16))
# Create a socket pool
pool = socketpool.SocketPool(wifi.radio)
# Initialize a new MQTT Client object
mqtt_client = MQTT.MQTT(
broker="io.adafruit.com",
username=os.getenv("AIO_USERNAME"),
password=os.getenv("AIO_KEY"),
socket_pool=pool,
ssl_context=ssl.create_default_context(),
)
# Initialize Adafruit IO MQTT "helper"
io = IO_MQTT(mqtt_client)
# Set up the callback methods above
io.on_connect = connected
io.on_message = message
timestamp = 0
while True:
try:
# 如果Adafruit IO未连接...
if not io.is_connected:
# 连接到MQTT代理
print("Connecting to Adafruit IO...")
io.connect()
# 显示颜色信息
neopixel_area.text = "Color: #{:02X}{:02X}{:02X}".format(*pixel[0]) # 更新文本显示
# 显示更新后的屏幕
display.refresh()
# 显示延迟
# time.sleep(0.5)
# 显式处理消息循环
io.loop()
# 处理可能的失败
except Exception as e: # pylint: disable=broad-except
print("Failed to get or send data, or connect. Error:", e,
"\nBoard will hard reset in 30 seconds.")
time.sleep(30)
microcontroller.reset()
- 使用WiFi模块连接到无线网络,并在TFT显示屏上显示连接状态
- 使用MQTT协议连接到Adafruit IO,并订阅"neopixel"的feed
- 当接收到"neopixel" feed的新值时,更新NeoPixel的颜色,并在TFT显示屏上显示颜色信息
wlanneo
对本活动的心得体会
我觉得本次活动对我来说十分有意义,因为开发板+1因为新接触了一种语法,并且增加了自己的ddl![](https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/rolling-on-the-floor-laughing_1f923.png)
任务总体难度适中,且可查的中文资料较少,可以培养rtfm的好习惯![](https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/smiling-face-with-sunglasses_1f60e.png)
建议下次活动直接来块小Linux开发板![](https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/face-savouring-delicious-food_1f60b.png)
(完)2023/10/14
|