【得捷电子Follow me第2期】Neopixel灯环控制器
[复制链接]
大家好,很高兴参加这次得捷Follow me活动,经过这次活动,了解了circuit python的基本操作,也用开发板实现了一些功能,在此也向大家分享一下学习过程。
一、视频内容
二、总结报告
因为以前没有接触过circuit python,开发板到了后先学习了一下开发板开发环境搭建和固件更新。
Adafruit为此开发板提供了非常详细的入门指南,网址为:https://learn.adafruit.com/adafruit-esp32-s3-tft-feather/overview
首先是固件更新,此开发板固件下载地址为:https://circuitpython.org/board/adafruit_feather_esp32s2_tft/
更新方式为双击RST按键,弹出开发板硬盘,将下载的固件拖入硬盘,开发板会自动重启。
开发环境我选的是Mu Editor,下载地址为:https://codewith.mu/en/download
点Mode选择CircuitPython
点Load打开开发板的code.py文件。
点Serial可以看log。
复制官方Blink代码,保存后开发板会自动运行,可以看到开发板红灯闪烁。
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
# SPDX-License-Identifier: MIT
"""CircuitPython Blink Example - the CircuitPython 'Hello, World!'"""
import time
import board
import digitalio
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)
8ff495db5556c7b58f95147fda90ec03
1、控制屏幕显示中文
首先驱动TFT屏幕。下载CircuitPython的包,里面包含库和一些例程,地址为:
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import board
import time
import terminalio
from adafruit_display_text import label
text = "Hello world"
text1 = "EEWorld"
boolValue = True
while True:
if boolValue == True:
text_area = label.Label(terminalio.FONT, text=text)
else:
text_area = label.Label(terminalio.FONT, text=text1)
boolValue = not boolValue
text_area.x = 10
text_area.y = 10
board.DISPLAY.show(text_area)
time.sleep(1)
pass
下载完成后的运行效果为:
71a47e41442f2fedb7081f7f9469b3ab
显示中文可以用两种方式实现,一种是通过加入中文字库来显示中文,这种方式需要找中文字库或者自己做字库,另一种是通过显示图片的方式显示中文,接下来分别用两种方式实现显示中文。
首先是中文字库的方式,需要找合适的中文字库,通过学习坛友的帖子,找到字库下载链接:
78294cdc3e61ceb5cea77a3dd01a0cdc
显示图片的方式显示中文,不是所有的图片都能在开发板显示,需要下载图片转换工具对图片进行转换,这次用的转换工具是GIMP,下载地址为:https://www.gimp.org/downloads/
软件使用非常简单,打开图片后直接导出为,命名时加上文件类型.bmp即可,转换的图片最好不要png图片,因为图片有色彩配置。导出后把转换好的文件复制到开发板根目录即可。
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import board
import time
import displayio
import adafruit_imageload
image, palette = adafruit_imageload.load("eeworld.bmp")
tile_grid = displayio.TileGrid(image, pixel_shader=palette)
group = displayio.Group()
group.append(tile_grid)
board.DISPLAY.show(group)
while True:
pass
2、网络功能使用
首先找到CircuitPython Internet Test的介绍页面,学习如何使用网络,地址为:
https://learn.adafruit.com/adafruit-esp32-s3-tft-feather/circuitpython-internet-test
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import ipaddress
import ssl
import wifi
import socketpool
import adafruit_requests
# URLs to fetch from
TEXT_URL = "http://wifitest.adafruit.com/testwifi/index.html"
JSON_QUOTES_URL = "https://www.adafruit.com/api/quotes.php"
JSON_STARS_URL = "https://api.github.com/repos/adafruit/circuitpython"
print("ESP32-S2 WebClient 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('CIRCUITPY_WIFI_SSID')}")
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}")
print(f"My IP address: {wifi.radio.ipv4_address}")
ping_ip = ipaddress.IPv4Address("8.8.8.8")
ping = wifi.radio.ping(ip=ping_ip)
# retry once if timed out
if ping is None:
ping = wifi.radio.ping(ip=ping_ip)
if ping is None:
print("Couldn't ping 'google.com' successfully")
else:
# convert s to ms
print(f"Pinging 'google.com' took: {ping * 1000} ms")
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
print(f"Fetching text from {TEXT_URL}")
response = requests.get(TEXT_URL)
print("-" * 40)
print(response.text)
print("-" * 40)
print(f"Fetching json from {JSON_QUOTES_URL}")
response = requests.get(JSON_QUOTES_URL)
print("-" * 40)
print(response.json())
print("-" * 40)
print()
print(f"Fetching and parsing json from {JSON_STARS_URL}")
response = requests.get(JSON_STARS_URL)
print("-" * 40)
print(f"CircuitPython GitHub Stars: {response.json()['stargazers_count']}")
print("-" * 40)
print("Done")
修改开发板文件settings.toml,将自己的WiFi名和密码填进去。
# SPDX-FileCopyrightText: 2023 Adafruit Industries
#
# SPDX-License-Identifier: MIT
# This is where you store the credentials necessary for your code.
# The associated demo only requires WiFi, but you can include any
# credentials here, such as Adafruit IO username and key, etc.
CIRCUITPY_WIFI_SSID = ".."
CIRCUITPY_WIFI_PASSWORD = "........"
运行结果为:
WiFi AP功能只需要加入star_ap指令就行,
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import ipaddress
import ssl
import wifi
import socketpool
import adafruit_requests
print("ESP32-S2 WebClient Test")
print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}")
print(f"Connecting to {os.getenv('CIRCUITPY_WIFI_SSID')}")
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}")
print(f"My IP address: {wifi.radio.ipv4_address}")
ping_ip = ipaddress.IPv4Address("8.8.8.8")
ping = wifi.radio.ping(ip=ping_ip)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
wifi.radio.start_ap('MyTestAP', 'test123456')
while True:
pass
3、控制WS2812B
首先找到NeoPixel LED的介绍页面,学习如何控制NeoPixel LED,地址为:
https://learn.adafruit.com/adafruit-esp32-s3-tft-feather/neopixel-led
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
# SPDX-License-Identifier: MIT
"""CircuitPython status NeoPixel red, green, blue example."""
import time
import board
import neopixel
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
pixel.brightness = 0.3
while True:
pixel.fill((255, 0, 0))
time.sleep(0.5)
pixel.fill((0, 255, 0))
time.sleep(0.5)
pixel.fill((0, 0, 255))
time.sleep(0.5)
831fe46299dd98e3a36a9e6399d4c310
添加颜色渐变效果
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
# SPDX-License-Identifier: MIT
"""CircuitPython status NeoPixel rainbow example."""
import time
import board
from rainbowio import colorwheel
import neopixel
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
pixel.brightness = 0.3
def rainbow(delay):
for color_value in range(255):
pixel[0] = colorwheel(color_value)
time.sleep(delay)
while True:
rainbow(0.02)
WeChat_20230930173127
4-1、日历&时钟
参考网上例子通过Adafruit ESP32-S3 TFT Feather获取天气,链接为:
https://blog.csdn.net/freemote/article/details/105313171
注册账号使用API。
(代码需要把API改为自己的地址)
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import ipaddress
import ssl
import json
import wifi
import socketpool
import adafruit_requests
print("ESP32-S2 WebClient Test")
print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}")
print(f"Connecting to {os.getenv('CIRCUITPY_WIFI_SSID')}")
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}")
print(f"My IP address: {wifi.radio.ipv4_address}")
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
result1=requests.get('https://api.seniverse.com/v3/weather/...')
j1=json.loads(result1.text)
print(j1['results'][0]['location']['name'],end=' ')
print(j1['results'][0]['now']['text'],end=' ')
print(j1['results'][0]['now']['temperature'],end='℃ ')
print(j1['results'][0]['last_update'])
print()
while True:
pass
运行效果为
可以看到这个API需要输入地址才能查到天气,所以想办法通过API先通过IP获取本地地址,再把地址加入到获取天气API中。这个API决定就用百度地图的。
(代码需要把API改为自己的地址)
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import ipaddress
import ssl
import json
import wifi
import socketpool
import adafruit_requests
print("ESP32-S2 WebClient Test")
print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}")
print(f"Connecting to {os.getenv('CIRCUITPY_WIFI_SSID')}")
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}")
print(f"My IP address: {wifi.radio.ipv4_address}")
pool = socketpool.SocketPool(wifi.radio)
stations = adafruit_requests.Session(pool, ssl.create_default_context())
result2=stations.get('https://api.map.baidu.com/location/...')
j2=json.loads(result2.text)
myLocal = j2['content']['address']
urlStr = "https://api.seniverse.com/v3/weather/..."
str_list = list(urlStr)
str_list.insert(77, myLocal)
urlStrList = ''.join(str_list)
print(urlStrList)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
result1=requests.get(urlStrList)
j1=json.loads(result1.text)
print(j1['results'][0]['location']['name'],end=' ')
print(j1['results'][0]['now']['text'],end=' ')
print(j1['results'][0]['now']['temperature'],end='℃ ')
print(j1['results'][0]['last_update'])
while True:
pass
效果为:
这个时钟天气最好加上ntp,要不然每次需要联网才能获得时间。并且通过实验,发现每次不能获得超过4个套接字,暂时没有找到解决办法。
(代码需要把API改为自己的地址)
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import ipaddress
import ssl
import json
import wifi
import socketpool
import adafruit_requests
import adafruit_ntp
print("ESP32-S2 WebClient Test")
print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}")
print(f"Connecting to {os.getenv('CIRCUITPY_WIFI_SSID')}")
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}")
print(f"My IP address: {wifi.radio.ipv4_address}")
pool = socketpool.SocketPool(wifi.radio)
ntp = adafruit_ntp.NTP(pool, tz_offset=8)
print(ntp.datetime)
pool = socketpool.SocketPool(wifi.radio)
stations = adafruit_requests.Session(pool, ssl.create_default_context())
result2=stations.get('https://api.map.baidu.com/location/...')
j2=json.loads(result2.text)
myLocal = j2['content']['address']
urlStr = "https://api.seniverse.com/v3/weather/..."
str_list = list(urlStr)
str_list.insert(77, myLocal)
urlStrList = ''.join(str_list)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
result1=requests.get(urlStrList)
j1=json.loads(result1.text)
print(j1['results'][0]['location']['name'],end=' ')
print(j1['results'][0]['now']['text'],end=' ')
print(j1['results'][0]['now']['temperature'],end='℃ ')
print(j1['results'][0]['last_update'])
while True:
pass
最后是显示,将前面学习的TFT屏幕的使用结合在一起即可。
(代码需要把API改为自己的地址)
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import ipaddress
import ssl
import json
import wifi
import socketpool
import adafruit_requests
import adafruit_ntp
import time
import rtc
import board
import displayio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label
print(f"Connecting to {os.getenv('CIRCUITPY_WIFI_SSID')}")
wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print(f"Connected to {os.getenv('CIRCUITPY_WIFI_SSID')}")
print(f"My IP address: {wifi.radio.ipv4_address}")
pool = socketpool.SocketPool(wifi.radio)
ntp = adafruit_ntp.NTP(pool,server="ntp.aliyun.com", tz_offset=8)
rtc.RTC().datetime = ntp.datetime
now = time.localtime()
print(ntp.datetime)
stations = adafruit_requests.Session(pool, ssl.create_default_context())
result2=stations.get('https://api.map.baidu.com/location/...')
j2=json.loads(result2.text)
myLocal = j2['content']['address']
urlStr = "https://api.seniverse.com/v3/weather/..."
str_list = list(urlStr)
str_list.insert(77, myLocal)
urlStrList = ''.join(str_list)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
result1=requests.get(urlStrList)
j1=json.loads(result1.text)
print(j1['results'][0]['location']['name'],end=' ')
print(j1['results'][0]['now']['text'],end=' ')
print(j1['results'][0]['now']['temperature'],end='℃ ')
print(j1['results'][0]['last_update'])
locaStr = j1['results'][0]['location']['name']
tempStr = j1['results'][0]['now']['temperature']
texStr = j1['results'][0]['now']['text']
#display
display = board.DISPLAY
board.DISPLAY.brightness = 0.5
board.DISPLAY.rotation = 0
font = bitmap_font.load_font("wenquanyi_13px.pcf")
color = 0xFFFFFF
while True:
now = time.localtime()
print(now)
print(f'{now[0]}-{now[1]:02d}-{now[2]:02d} {now[3]:02d}:{now[4]:02d}:{now[5]:02d}')
display_str = f'{now[0]}-{now[1]:02d}-{now[2]:02d}' + '\n' +f'{now[3]:02d}:{now[4]:02d}:{now[5]:02d}'\
+ '\n' + locaStr + '\n' + tempStr + '℃\n' + texStr
text_group = displayio.Group()
text_area = label.Label(font, text=display_str, color=color)
text_area.x = 10
text_area.y = 10
text_group.append(text_area)
display.show(text_group)
time.sleep(1)
WeChat_20230930173807
4-2、WS2812B效果控制
这个功能可以参考开发板的文档,网址为:
https://learn.adafruit.com/adafruit-esp32-s3-tft-feather/multitasking-with-asyncio
不过代码需要经过少些修改以适应我的开发工具。
# SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2022 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
CircuitPython asyncio example for two NeoPixel rings and one button.
"""
import asyncio
import board
import neopixel
import keypad
from rainbowio import colorwheel
button_pin = board.BUTTON # The pin the button is connected to.
num_pixels = 16 # The number of NeoPixels on a single ring.
brightness = 0.2 # The LED brightness.
# Set up NeoPixel rings.
ring_one = neopixel.NeoPixel(board.A1, num_pixels, brightness=brightness, auto_write=False)
ring_two = neopixel.NeoPixel(board.A2, num_pixels, brightness=brightness, auto_write=False)
class AnimationControls:
"""The controls to allow you to vary the rainbow and blink animations."""
def __init__(self):
self.reverse = False
self.wait = 0.0
self.delay = 0.5
async def rainbow_cycle(controls):
"""Rainbow cycle animation on ring one."""
while True:
if(controls.reverse == False):
print('rainbow_cycle')
for j in range(255, -1, -1) if controls.reverse else range(0, 256, 1):
for i in range(num_pixels):
rc_index = (i * 256 // num_pixels) + j
ring_two[i] = colorwheel(rc_index & 255)
ring_two.show()
await asyncio.sleep(controls.wait)
await asyncio.sleep(controls.wait)
async def blink(controls):
"""Blink animation on ring two."""
while True:
if(controls.reverse == True):
print('blink')
ring_two.fill((0, 0, 255))
ring_two.show()
await asyncio.sleep(controls.delay)
ring_two.fill((0, 0, 0))
ring_two.show()
await asyncio.sleep(controls.delay)
await asyncio.sleep(controls.wait)
await asyncio.sleep(controls.wait)
async def monitor_button(button, controls):
"""Monitor button that reverses rainbow direction and changes blink speed.
Assume button is active low.
"""
with keypad.Keys((button,), value_when_pressed=False, pull=True) as key:
while True:
key_event = key.events.get()
if key_event:
print('key_event')
if key_event.pressed:
controls.reverse = not controls.reverse
controls.delay = 0.6
await asyncio.sleep(0)
async def main():
animation_controls = AnimationControls()
button_task = asyncio.create_task(monitor_button(button_pin, animation_controls))
animation_task = asyncio.create_task(rainbow_cycle(animation_controls))
blink_task = asyncio.create_task(blink(animation_controls))
# This will run forever, because no tasks ever finish.
await asyncio.gather(button_task, animation_task, blink_task)
asyncio.run(main())
WeChat_20230930173954
参与心得
非常感谢eeworld和得捷举办follow me第二期活动,能让大家更好的接触circuit python,体验新事物。因为有follow me第一期活动的参考,对比起micropython来说circuit python有很多新功能还没实现,比如蓝牙相关的功能实现在网上搜索了很久都没有找到在esp32 s3上实现的案例,并且在调试网络相关的功能的时候还遇上了每次最多只能有五次网络包请求,确实不应该。新生事务还需时间来完善,希望circuit python能发展的越来越好,给电子爱好者更多选择。
三、可编译下载的代码
code12.py
(2.95 KB, 下载次数: 1)
code11_c.py
(2.33 KB, 下载次数: 1)
code10_c.py
(1.48 KB, 下载次数: 1)
code9_c.py
(1.37 KB, 下载次数: 1)
code8_c.py
(1.02 KB, 下载次数: 1)
code7.py
(474 Bytes, 下载次数: 1)
code6.py
(448 Bytes, 下载次数: 1)
code5.py
(854 Bytes, 下载次数: 1)
code4.py
(2 KB, 下载次数: 1)
code3.py
(394 Bytes, 下载次数: 1)
code2.py
(768 Bytes, 下载次数: 1)
code1.py
(563 Bytes, 下载次数: 1)
Blink.py
(407 Bytes, 下载次数: 1)
|