706|2

108

帖子

25

TA的资源

一粒金砂(高级)

楼主
 

【得捷电子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)
 
 

最新回复

原来显示中文也可通过显示图片的方式,这个之前没有用过的   详情 回复 发表于 2023-10-2 09:26
点赞 关注
 
 

回复
举报

6450

帖子

10

TA的资源

版主

沙发
 

这个幻彩灯相当不错,十一也不好好休息一下啊,都是在奋斗的人

个人签名

在爱好的道路上不断前进,在生活的迷雾中播撒光引

 
 
 

回复

6802

帖子

0

TA的资源

五彩晶圆(高级)

板凳
 

原来显示中文也可通过显示图片的方式,这个之前没有用过的

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

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

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