- 2024-11-07
-
回复了主题帖:
【得捷电子Follow me第1期】+ 提交贴
damiaa 发表于 2024-11-6 08:46
不知道这个室内效果如何。
不太行,至少得放窗边
- 2024-08-01
-
回复了主题帖:
【瑞萨RA8D1板卡】 修复板卡按键
nmg 发表于 2024-8-1 08:59
看你接线那里,似乎没有焊盘?
最后是用什么补焊上脱落地方的,没看明白
应该连走线上了,绿油刮掉就行
- 2024-05-29
-
回复了主题帖:
【FireBeetle 2 ESP32 C6 开发板】+ 显示天气和万年历
wangerxian 发表于 2024-5-29 11:35
json的好用,每天能获取多少次?
今天上去看了眼是每天 1000 次
-
回复了主题帖:
【FireBeetle 2 ESP32 C6 开发板】+ 显示天气和万年历
wangerxian 发表于 2024-5-28 19:00
和风天气这个API好像很多人获取天气信息都在用。
api 内容相对完备一下,而且提供字体库、天气图标等。就是现在改了返回格式,强制 gzip,以前是可选 json 的,蛋疼
- 2024-05-28
-
发表了主题帖:
【FireBeetle 2 ESP32 C6 开发板】+ 显示天气和万年历
本帖最后由 ID.LODA 于 2024-5-28 16:55 编辑
## Previously
1. [【FireBeetle 2 ESP32 C6】+ 开箱及更新 Circuitpy 固件](https://bbs.eeworld.com.cn/thread-1281496-1-1.html)
1. [【FireBeetle 2 ESP32 C6 开发板】+ 使用 Web Workflow 开发](https://bbs.eeworld.com.cn/thread-1281597-1-1.html)
1. [【FireBeetle 2 ESP32 C6 开发板】+ 测试使用板载 core modules](https://bbs.eeworld.com.cn/thread-1282655-1-1.html)
1. [【FireBeetle 2 ESP32 C6 开发板】+ 驱动 DFR0664](https://bbs.eeworld.com.cn/thread-1282718-1-1.html)
# 显示万年历和天气
## NTP 网络授时
### 导入 cpy 库
需要从 adafruit-circuitpython-bundle 获取驱动库 adafruit_ntp.mpy, 导入至板卡的 lib 目录
### 示例代码
服务器选择了 `ntp.aliyun.com`
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
import board
import digitalio
import rtc
import time
import wifi
import socketpool
import adafruit_ntp
UTC_OFFSET = 8
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
# code handler
while not wifi.radio.ipv4_address:
try:
print("Connecting to WiFi")
# connect to your SSID
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
except ConnectionError as e:
print("connect error:{}, retry in 2s".format(e))
time.sleep(2)
pool = socketpool.SocketPool(wifi.radio)
def ntp_sync_time():
print("Local time before synchronization:%s" % str(time.localtime()))
try:
# ntp = adafruit_ntp.NTP(pool, tz_offset=UTC_OFFSET)
ntp = adafruit_ntp.NTP(pool, server='ntp.aliyun.com', tz_offset=UTC_OFFSET)
# ntp = adafruit_ntp.NTP(pool, server='ntp.ntsc.ac.cn', tz_offset=UTC_OFFSET)
# NOTE: This changes the system time so make sure you aren't assuming that time
# doesn't jump.
rtc.RTC().datetime = ntp.datetime
print("Local time after synchronization: %s" % str(time.localtime()))
except OSError as e:
print("ntp error:{}".format(e))
ntp_sync_time()
while True:
time.sleep(0.5)
led.value = not led.value
```
### 效果展示
## 获取天气
天气服务器使用的是和风天气,调用的 [实时天气接口](https://dev.qweather.com/docs/api/weather/weather-now/),需要注意的是返回结果是 gzip 格式,可以使用自带的 ``zlib`` 模块进行解密
返回数据格式如下:
### 示例代码
在和风天气官网注册申请 Key,替换代码中的 **QWEATHER_KEY**
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
import board
import digitalio
import time
import wifi
import socketpool
import ssl
import adafruit_requests
import zlib
import json
QWEATHER_KEY = "Your-Key"
CITYID = '101020100'
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
# code handler
while not wifi.radio.ipv4_address:
try:
print("Connecting to WiFi")
# connect to your SSID
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
except ConnectionError as e:
print("connect error:{}, retry in 2s".format(e))
time.sleep(2)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
def qweather_decompress(data):
FTEXT = 1
FHCRC = 2
FEXTRA = 4
FNAME = 8
FCOMMENT = 16
assert data[0] == 0x1f and data[1] == 0x8b
assert data[2] == 8
flg = data[3]
assert flg & 0xe0 == 0
i = 10
if flg & FEXTRA:
i += data[11] = 2:
current_line = ""
break
else:
current_line += char
current_length += char_length
# 添加最后一行
if current_line:
result.append(current_line)
return "\n".join(result)
def display_update_laohuangli(info):
text_yi = split_text(info['yi'], 50)
text_ji = split_text(info['ji'], 50)
lable_laohuangli.text = "农历 {}\n宜 {}\n忌 {}".format(
info['yinli'], text_yi, text_ji)
ntp_sync_time()
display_update_time()
qweather_now_info = qweather_weather_now()
display_update_weather(qweather_now_info)
laohuangli_info = juhe_loahuangli()
display_update_laohuangli(laohuangli_info)
time_update_start = time.time()
# Loop forever so you can enjoy your image
while True:
time.sleep(0.5)
time_current = time.time()
# sync ntp and weather
if time_current - time_update_start >= 2 * 60 * 60:
time_start = time.time_current
ntp_sync_time()
weather_info = qweather_weather_now()
display_update_weather(weather_info)
laohuangli_info = juhe_loahuangli()
display_update_laohuangli(laohuangli_info)
gc.collect()
display_update_time()
# led.value = not led.value
```
### 效果展示
## 总结
circuitpython 提供的 http 请求库 adafruit_requests 使用非常方便,配合内置的 zlib 和 json 模块,对于网络数据的解析非常友好。
-
回复了主题帖:
【FireBeetle 2 ESP32 C6 开发板】+ 驱动 DFR0664 IPS LCD
Jacktang 发表于 2024-5-24 07:24
应该是可以玩玩从 SD 卡中读取字体库和图片来显示的东西了
可以玩,circuitpython 的库还是比较完善的,我最后示例就是用的 sd 库的图片和字库,很方便
-
回复了主题帖:
【FireBeetle 2 ESP32 C6 开发板】+ 驱动 DFR0664 IPS LCD
chejm 发表于 2024-5-24 12:26
楼主分享的技术内容非常详实,开阔了眼界,有机会一定实践下
可以,circuitpython 的库还是比较好上手的
- 2024-05-23
-
发表了主题帖:
【FireBeetle 2 ESP32 C6 开发板】+ 驱动 DFR0664 IPS LCD
## Previously
1. [【FireBeetle 2 ESP32 C6】+ 开箱及更新 Circuitpy 固件](https://bbs.eeworld.com.cn/thread-1281496-1-1.html)
1. [【FireBeetle 2 ESP32 C6 开发板】+ 使用 Web Workflow 开发](https://bbs.eeworld.com.cn/thread-1281597-1-1.html)
1. [【FireBeetle 2 ESP32 C6 开发板】+ 测试使用板载 core modules](https://bbs.eeworld.com.cn/thread-1282655-1-1.html)
# 驱动 DFR0664 TFT 显示屏
[DFR0664 显示屏](https://wiki.dfrobot.com.cn/_SKU_DFR0664_2.0_240x320_LCD) 采用 ST7789V 驱动芯片,其分辨率为320x240,采用 SPI 通信方式,并板载 SD 卡槽,可以轻松的从 SD 卡中读取全彩色位图。模块提供了两种接线方式,一种为普通排针接线方式;另一种为GDI(General Display interface)接口
## 引脚说明
| 标号 | 名称 | 功能描述 |
| ------------ | ------------ | ------------ |
| 1 | VCC | 电源正极 |
| 2 | GND | 电源负极 |
| 3 | SCLK | 时钟 |
| 4 | MOSI | 数据(主机发送从机接收) |
| 5 | MISO | 数据(主机接收从机发送 |
| 6 | CS | 屏幕片选 |
| 7 | RES | 复位 |
| 8 | DC | 数据/命令 |
| 9 | BL | 背光。背光设定了默认值,用户不用连接背光引脚也可点亮;此外,连接背光引脚,输入高电平(1)是将背光亮度调到最大,输入低电平(0)是关闭背光 |
| 10 | SDCS | SD卡片选 |
## CircuitPython Displayio Quickstart
### 导入 cpy 库
需要从 adafruit-circuitpython-bundle 获取驱动库 `adafruit_st7789.mpy` 和 显示库(整个目录) `adafruit_display_text`,导入至板卡的 lib 目录,具体步骤可以参考上一章
### 示例代码
实现了背景及上层画布的绘制和文本的显示。
> 引脚说明
> rst 引脚我没有赋值,因为 GDI 接口连到了板卡的 IO14 引脚,但是 circuitpython 并没有初始化该引脚,所以无法使用
> bl 引脚在 GDI 接口中连到了板卡的 IO15 引脚,和板载 LED 脚位共用,后续使用需要注意一下
```python
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
This test will initialize the display using displayio and draw a solid green
background, a smaller purple rectangle, and some yellow text.
"""
import board
import busio
import terminalio
import displayio
# Starting in CircuitPython 9.x fourwire will be a seperate internal library
# rather than a component of the displayio library
try:
from fourwire import FourWire
except ImportError:
from displayio import FourWire
from adafruit_display_text import label
from adafruit_st7789 import ST7789
# led = digitalio.DigitalInOut(board.LED)
# led.direction = digitalio.Direction.OUTPUT
# Release any resources currently in use for the displays
displayio.release_displays()
# spi = board.SPI()
spi = busio.SPI(board.D23, MOSI=board.D22, MISO=board.D21)
tft_cs = board.D1
tft_dc = board.D8
display_bus = FourWire(spi, command=tft_dc, chip_select=tft_cs""", reset=board.D14""")
display = ST7789(display_bus, width=320, height=240, rotation=90)
# Make the display context
splash = displayio.Group()
display.root_group = splash
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00 # Bright Green
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)
# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(280, 200, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0xAA0088 # Purple
inner_sprite = displayio.TileGrid(inner_bitmap, pixel_shader=inner_palette, x=20, y=20)
splash.append(inner_sprite)
# Draw a label
text_group = displayio.Group(scale=3, x=57, y=120)
text = "Hello World!"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFF00)
text_group.append(text_area) # Subgroup for text scaling
splash.append(text_group)
while True:
pass
```
### 效果展示
## 驱动 SD 卡
DFR0664 板载了 SD 卡槽,和 LCD 共用 SPI 驱动
### 导入 cpy 库
需要从 adafruit-circuitpython-bundle 获取驱动库 `adafruit_sdcard.mpy
`,并导入至板卡的 lib 目录
### 示例代码
挂在 SDCard 到 /sd 目录,遍历打印该目录文件
```python
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
This test will initialize the display using displayio and draw a solid green
background, a smaller purple rectangle, and some yellow text.
"""
import os
import time
import board
import digitalio
import displayio
import busio
import sdcardio
import storage
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
displayio.release_displays()
spi = busio.SPI(board.D23, MOSI=board.D22, MISO=board.D21)
sdcard = sdcardio.SDCard(spi, board.D18)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
def print_directory(path, tabs=0):
for file in os.listdir(path):
stats = os.stat(path + "/" + file)
filesize = stats[6]
isdir = stats[0] & 0x4000
if filesize < 1000:
sizestr = str(filesize) + " by"
elif filesize < 1000000:
sizestr = "%0.1f KB" % (filesize / 1000)
else:
sizestr = "%0.1f MB" % (filesize / 1000000)
prettyprintname = ""
for _ in range(tabs):
prettyprintname += " "
prettyprintname += file
if isdir:
prettyprintname += "/"
print('{0:10}'.format(prettyprintname, sizestr))
# recursively print directory contents
if isdir:
print_directory(path + "/" + file, tabs + 1)
print("Files on filesystem:")
print("====================")
print_directory("/sd")
while True:
time.sleep(0.5)
led.value = not led.value
```
### 显示效果
运行之后可以直接通过 web workflow 的文件目录访问,非常方便
## sd 卡导入字库和图片显示
### 导入 cpy 库
需要从 adafruit-circuitpython-bundle 获取图片库 `adafruit_imageload`,字体库 `adafruit_bitmap_font`,并导入至板卡的 lib 目录
### 示例代码
从 sd 卡导入字体库和图片,显示
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
import board
import busio
import digitalio
import displayio
import sdcardio
import storage
import terminalio
import time
# Starting in CircuitPython 9.x fourwire will be a seperate internal library
# rather than a component of the displayio library
try:
from fourwire import FourWire
except ImportError:
from displayio import FourWire
from adafruit_display_text import label
from adafruit_st7789 import ST7789
from adafruit_bitmap_font import bitmap_font
import adafruit_imageload
# Release any resources currently in use for the displays
displayio.release_displays()
spi1_bus = busio.SPI(board.D23, MOSI=board.D22, MISO=board.D21)
display_bus = FourWire(spi1_bus, command=board.D8, chip_select=board.D1)
display = ST7789(display_bus, width=320, height=240, rotation=90)
sdcard = sdcardio.SDCard(spi1_bus, board.D18)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
# Make the display context
splash = displayio.Group()
display.root_group = splash
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000 # 0xF8F8FF # Ghost White
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)
# 180 * 125
with open("/sd/resources/pic/test_image.png", "rb") as f:
blinka_bitmap, blinka_palette = adafruit_imageload.load(f, bitmap=displayio.Bitmap, palette=displayio.Palette)
blinka_sprite = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_palette, x=140, y=115)
splash.append(blinka_sprite)
# 160 * 56
with open("/sd/resources/pic/ee.bmp", "rb") as f:
eeworld_bitmap, eeworld_palette = adafruit_imageload.load(f, bitmap=displayio.Bitmap, palette=displayio.Palette)
eeworld_sprite = displayio.TileGrid(eeworld_bitmap, pixel_shader=eeworld_palette, x=0, y=20)
splash.append(eeworld_sprite)
# Set text, font, and color
font = bitmap_font.load_font("/sd/resources/font/opposans_m_12.pcf")
# Create the text label
lable_area_fw = label.Label(
font, x=10, y=96, text="FireBeetle 2 ESP32 C6", scale=1, color= 0x191970
)
lable_area_id = label.Label(
font, x=10, y=128, text="ID.LODA", scale=1, color=(0, 191, 255)
)
splash.append(lable_area_fw)
splash.append(lable_area_id)
while True:
time.sleep(0.5)
# led.value = not led.value
```
### 运行效果
# 总结
circuitpython 提供了比较丰富的库,可以方便的绘制转换需要的资源。但是没有继承类似与 emwin、lvgl 等成熟的图形库。
-
发表了主题帖:
【FireBeetle 2 ESP32 C6 开发板】+ 测试使用板载 core modules
本帖最后由 ID.LODA 于 2024-5-23 15:05 编辑
# Core Modules 的测试、使用
记上一章使用 Web Workflow 之后开发稳定性提高很多,今天来学习下 circuitpython core modules 的使用
## 查看板载支持的 modules
可以在 repl 或者 code.py 中输入 ``help("modules")`` 即可查看
## microcontroller
处理器模块的接口介绍可以查看以下章节 [microcontroller](https://docs.circuitpython.org/en/latest/shared-bindings/microcontroller/index.html),包含了 unique id、cpu、frequency、temperature 等参数的获取,以及终端复位等的控制
### 示例演示
实现了 cpu 基础信息的获取
```python
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
This test will initialize the display using displayio and draw a solid green
background, a smaller purple rectangle, and some yellow text.
"""
import os
import time
import board
import digitalio
import microcontroller
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
cpu = microcontroller.cpu
print("cpu uid: ", [hex(i) for i in cpu.uid])
print("cpu frequency: ", cpu.frequency)
print("cpu temperature: ", cpu.temperature)
print("cpu voltage: ", cpu.voltage)
print("cpu reset reason: ", cpu.reset_reason)
while True:
time.sleep(0.5)
led.value = not led.value
microcontroller.reset()
```
#### 结果展示
## WIFI
wifi 模块的接口介绍可以查看以下章节 [wifi](https://docs.circuitpython.org/en/latest/shared-bindings/wifi/index.html),该模块为管理 wifi 连接提供了必要的底层功能,以及使用套接字池通过网络进行通信。
### 基础示例
实现了 WIFI 的连接,socket pool 的创建,域名解析以及 ping 包的实现
#### 示例代码
介于我在 settings.toml 里设置了 `CIRCUITPY_WIFI_SSID`、`CIRCUITPY_WIFI_PASSWORD`,通过 os.getenv 可以很方便的获取对应的数据
```python
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
This test will initialize the display using displayio and draw a solid green
background, a smaller purple rectangle, and some yellow text.
"""
import os
import time
import board
import digitalio
import socketpool
import wifi
import ipaddress
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
# code handler
while not wifi.radio.ipv4_address:
try:
print("Connecting to WiFi")
# connect to your SSID
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
except ConnectionError as e:
print("connect error:{}, retry in 2s".format(e))
time.sleep(2)
pool = socketpool.SocketPool(wifi.radio)
# prints IP address to REPL
print("My IP address is", wifi.radio.ipv4_address)
# prints MAC address to REPL
print("My MAC addr:", [hex(i) for i in wifi.radio.mac_address])
# pings eeworld
ip_address = pool.getaddrinfo("eeworld.com.cn", 80)[0][-1][0]
ipv4 = ipaddress.ip_address(ip_address)
print("Ping eeworld.com: %f ms" % (wifi.radio.ping(ipv4)*1000))
while True:
time.sleep(0.5)
led.value = not led.value
```
#### 运行结果
### http 请求示例
进行 http 请求依赖第三方库,可以在 [library 官网](https://circuitpython.org/libraries) 根据对应的版本下载示例包,我这边使用的是 9.x,所以下载的 9.x 版本
#### 导入库
依赖 adafruit_connection_manager.mpy、adafruit_requests.mpy 库,将其导入 lib 目录即可
#### 示例代码
通过请求 https://www.adafruit.com/api/quotes.php,获取网页的内容,并打印
```python
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import os
import time
import ssl
import wifi
import socketpool
import microcontroller
import adafruit_requests
# adafruit quotes URL
quotes_url = "https://www.adafruit.com/api/quotes.php"
# connect to SSID
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
while True:
try:
# pings adafruit quotes
print("Fetching text from %s" % quotes_url)
# gets the quote from adafruit quotes
response = requests.get(quotes_url)
print("-" * 40)
# prints the response to the REPL
print("Text Response: ", response.text)
print("-" * 40)
response.close()
# delays for 1 minute
time.sleep(60)
# pylint: disable=broad-except
except Exception as e:
print("Error:\n", str(e))
print("Resetting microcontroller in 10 seconds")
time.sleep(10)
microcontroller.reset()
```
#### 运行结果
# 总结
circuitpython 内置了很多功能模块,官网也提供了对应的接口文档,相对还是比较上手使用
- 2024-05-11
-
发表了主题帖:
【FireBeetle 2 ESP32 C6 开发板】+ 使用 Web Workflow 开发
# 搭建 Web Workflow 开发环境
介于 thonny ide 用 repl 连接不是很稳定,尝试使用 Web Workflow 在线开发
## 配置需求
根据官网介绍,将 settings.toml 的文件添加到 CircuitPython 文件系统的根文件夹时,就会启用 Web 工作流,此文件需要包含本地wifi 信息和其他设置。[点击此处了解更多信息](https://docs.circuitpython.org/en/latest/docs/workflows.html#web)。
settings.toml 文件的基本内容如下:
```python
CIRCUITPY_WIFI_SSID = "wifissid"
CIRCUITPY_WIFI_PASSWORD = "wifipassword"
CIRCUITPY_WEB_API_PASSWORD= "webpassword"
```
> 说明
> wifissid 替换为本地 wifi 网络名称
> wifipassword 替换为本地 wifi 网络密码
> webpassword 通过网络浏览器连接到板时使用,设置为任意值
## 导入配置
1. 借助 thonny 工具,连接板卡
1. 打开文件视图,修改 setting.toml 文件
1.
[官网](https://learn.adafruit.com/circuitpython-with-esp32-quick-start/setting-up-web-workflow) 还介绍了通过 repl 的方式,通过命令行写入文件即可。感兴趣的小伙伴可以关注下。
```json
f = open('settings.toml', 'w')
f.write('CIRCUITPY_WIFI_SSID = "wifissid"\n')
f.write('CIRCUITPY_WIFI_PASSWORD = "wifipassword"\n')
f.write('CIRCUITPY_WEB_API_PASSWORD = "webpassword"\n')
f.close()
```
1. 重启看到 ip 地址之后,打开浏览器,使用 MDNS 地址 ``circuitpython.local`` 连接板卡,可以看到欢迎信息,包含了板卡的名称、版本等信息。失败时可以尝试使用 IP 地址打开
1. 点击欢迎页面的 ``full code editer`` 跳转至代码编辑页面,输入 settings.toml 设置的 CIRCUITPY_WEB_API_PASSWORD 密码即可,忽略用户名
1. 现在已经在线编辑器界面,打开文件进行编码
```python
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""Example for ESP32-C6. Blinks the built-in LED."""
import time
import board
import digitalio
import wifi
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
print("My MAC addr: %02X:%02X:%02X:%02X:%02X:%02X" % tuple(wifi.radio.mac_address))
print("My IP address is", wifi.radio.ipv4_address)
while True:
led.value = True
time.sleep(0.5)
led.value = False
time.sleep(0.5)
```
1. 保存看到设备打印信息,板载 LED 间断闪烁
# 总结
web workflow 环境配置不是很复杂, 只需在 settings.toml 添加几项内容。而且相比 thonny 来看,修改、保存文件要更加稳定一些,是个不错的选择。
-
发表了主题帖:
【FireBeetle 2 ESP32 C6】+ 开箱及更新 Circuitpy 固件
# 开箱
板卡的包装和之前的 FireBeetle 类型一样比较简单,包含了板卡和排针
正反面
# 简介
FireBeetle 2 ESP32-C6是一款基于ESP32-C6芯片设计的低功耗物联网开发板,适用于智能家居项目。ESP32-C6搭载160MHz的高性能RISC-V 32位处理器,支持Wi-Fi 6、Bluetooth 5、Zigbee 3.0、Thread 1.3通讯协议,可接入多种通讯协议的物联网网络。FireBeetle 2 ESP32-C6支持Type-C、5V DC、太阳能对锂电池进行充电,部署时有更多的供电方式选择。
- 多种传输协议支持,扩展无线连接性
- 支持Wi-Fi 6,实现超低功耗物联网设备
- 优秀的电源系统,设备供电更方便
板卡的详细资源和入门文档可以在 [dfrobot 官方 wiki](https://wiki.dfrobot.com.cn/_SKU_DFR1075_FireBeetle_2_Board_ESP32_C6) 上找到。
![引脚示意图](https://img.dfrobot.com.cn/wiki/5d57611a3416442fa39bffca/b9ef4c5ab7be64cd085be9cd424c87b2.png)
# 更新 CircuitPython 固件
1. 下载 circuitpython 固件 [adafruit_feather_esp32c6_4mbflash_nopsram](https://circuitpython.org/board/adafruit_feather_esp32c6_4mbflash_nopsram) , 选择 adafruit_feather_esp32c6_4mbflash_nopsram 板卡的固件,因为和 FireBeetle 2 ESP32-C6 配置是一致的,除开引脚有一些区别,但是不影响
1. [点击下载 esptool Flash 烧录工具](https://www.espressif.com.cn/sites/default/files/tools/flash_download_tool_3.9.6_0.zip)
1. 运行 flash_download_tool_3.9.6.exe
1. 通过 USB 线连接电脑,选择 ESP32-C6 主控,然后按住 BOOT,点击 RST
1. 选择下载的固件,擦除flash后烧录固件
## 指令方式更新
# 搭建 circuitpython 环境
1. 烧录完成之后,复位芯片即可,和其他芯片不同的是,因为 ESP32 不支持 native USB,所以不会弹 CIRCUITPY 的驱动,只能借助其他工具用 REPL 去开发
1. 下载安装 [thonny](https://thonny.org/)
1. 运行 thonny.exe
1. 输入测试指令
# 编写 circuitpython 代码
1. circuitpython 启动时自动运行 code.py,我们在 code.py 编写自己的代码
> 注意事项
> 这边我没找到 adafruit_feather_esp32c6 的原理图,其实不知道引脚的定义情况,好在用 board.led 能点亮FireBeetle_2_Board_ESP32_C6 的灯。后续测试下其他外设引脚。
> 查看板卡支持引脚,可以使用 print(dir(board)) 输出
# 总结
esp32-c6 因为自身 USB 的问题,运行 circuitpython 固件没有 CIRCUITPY 磁盘,需要借助其他工具,这点比较麻烦,而且个人使用下来感觉 thonny 连接不是很稳定,尬住了
- 2024-04-18
-
回复了主题帖:
测评入围:FireBeetle 2 ESP32 C6开发板
个人信息无误,确认可以完成评测计划
- 2024-03-29
-
回复了主题帖:
【EEWorld发奖礼品--获奖名单】STM32 Summit全球在线大会
好久没中奖了,该轮到我了
- 2024-02-25
-
发表了主题帖:
【得捷电子Follow me第4期】项目总结报告
# 项目介绍
本次项目使用核心板 W5500-EVB-Pico,学习了网络相关的知识,熟悉了网络开发基础 API 的使用,配合 LCD 扩展版和按键控制器扩展板,使用 circuitpython 开发完成如下任务:
1. 入门任务:开发环境搭建,BLINK,驱动液晶显示器进行显示(没有则串口HelloWorld)
1. 基础任务一:完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。
1. 基础任务二:主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作)
1. 进阶任务:从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送显示屏(串口)显示。
1. 终极任务: 使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件。
## 功能实现
1. 驱动 W5500 网络控制器,并连接 NTP 服务器进行网络授时,实现简易 TCP 服务器及 FTP 服务器
1. 驱动 SD 卡,导入 LCD 显示的字体和背景图片,并为 FTP 服务器提供文件存储空间
1. 驱动 LCD 显示本地时间,网络相关参数及调试信息
1. 驱动按键控制器,进行服务器的切换
## 演示视频
[演示视频](https://training.eeworld.com.cn/video/39302 "演示视频")
# 任务/项目总结报告
本次活动,使用的硬件为:
1. 控制器:[W5500-EVB-Pico](https://www.digikey.cn/zh/products/detail/wiznet/W5500-EVB-PICO/16515824 "W5500-EVB-Pico")
W5500-EVB-Pico 是基于 Raspberry Pi RP2040 和完全硬连线 TCP/IP控制器 W5500 的微控制器评估板,其工作原理与Raspberry Pi Pico 板基本相同,但通过 W5500 增加了以太网。具体介绍参考 [wiki](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico)
![w5500-evb-pico](https://docs.wiznet.io/assets/images/w5500-evb-pico-pinout-fe942a8c8d6e9d591c0ae8bc7312d592.png)
1. 显示屏:[DFR0664 2.0 320x240 IPS TFT LCD Display with MicroSD Card (Breakout)](https://www.digikey.cn/zh/products/detail/dfrobot/DFR0664/13166503)
具体介绍参考 [wiki](https://wiki.dfrobot.com.cn/_SKU_DFR0664_2.0_240x320_LCD)
![DFR0664](https://img.dfrobot.com.cn/wiki/none/bbc55593d232a10fced56ab97637f646.jpg)
1. 键盘控制器:[MINI I2C GAMEPAD WITH SEESAW](https://www.digikey.cn/zh/products/detail/adafruit-industries-llc/5743/20370632)
具体介绍参考 [wiki](https://learn.adafruit.com/gamepad-qt)
![gamepad-qt](https://cdn-learn.adafruit.com/assets/assets/000/122/121/medium800/adafruit_products_GPQT_top.jpg?1687817547)
## 入门任务:开发环境搭建,BLINK,驱动液晶显示器进行显示(没有则串口HelloWorld)
开发语言选择的是 circuit python,具体资料可以前往 adafruit 的 [circuit python 官网](https://learn.adafruit.com/welcome-to-circuitpython) 学习
### circuit python 安装
1. 前往 [circuit python 板卡中心](https://circuitpython.org/downloads) 找到控制板 [W5500-EVB-PICO](https://circuitpython.org/board/wiznet_w5500_evb_pico/),下载对应的 UF2 固件
1. 按下 BOOT 按键不松手,上电模块之后松手即可进入下载模式
1. 打开电脑新增的驱动器,将上一步下载的 UF2 固件复制进 U 盘,指示灯应再次闪烁,启动将消失,并且您的计算机上将显示一个名为 CIRCUITPY 的新驱动器,此时已成功安装或更新 CircuitPython!
1. 打开新的驱动器,编辑 code.py 文件进行编程
1. circuit python 的库文件可以在 [libraries 官网](https://circuitpython.org/libraries) 找到,本节任务使用了 SPI 总线,LCD 显示器及 SD 卡,需要导入如下库文件进新的驱动器的 lib 目录
``` bash
adafruit_bus_device/
adafruit_display_text/
adafruit_bitmap_font/
adafruit_imageload/
adafruit_sdcard.mpy
adafruit_st7789.mpy
```
circuitpython 驱动 st7789 LCD 的参考资料 https://learn.adafruit.com/2-0-inch-320-x-240-color-ips-tft-display
驱动 sd 卡的参考资料 https://learn.adafruit.com/micropython-hardware-sd-cards
### 任务代码
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
import board
import busio
import digitalio
import displayio
import sdcardio
import storage
import terminalio
import time
# Starting in CircuitPython 9.x fourwire will be a seperate internal library
# rather than a component of the displayio library
try:
from fourwire import FourWire
except ImportError:
from displayio import FourWire
from adafruit_display_text import label
from adafruit_st7789 import ST7789
from adafruit_bitmap_font import bitmap_font
import adafruit_imageload
# SPI1 for tft
SPI1_SCK = board.GP10
SPI1_TX = board.GP11
SPI1_RX = board.GP12
# tft lcd io
TFT_CSn = board.GP13
TFT_RSTn = board.GP14
TFT_DC = board.GP15
# sdcard io
SD_CSn = board.GP9
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
# Release any resources currently in use for the displays
displayio.release_displays()
spi1_bus = busio.SPI(SPI1_SCK, MOSI=SPI1_TX, MISO=SPI1_RX)
display_bus = FourWire(spi1_bus, command=TFT_DC, chip_select=TFT_CSn, reset=TFT_RSTn)
display = ST7789(display_bus, width=320, height=240, rotation=90)
sdcard = sdcardio.SDCard(spi1_bus, SD_CSn)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
# Make the display context
splash = displayio.Group()
display.root_group = splash
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000 # 0xF8F8FF # Ghost White
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)
# 160 * 29
with open("/sd/resources/pic/dk.bmp", "rb") as f:
digikey_bitmap, digikey_palette = adafruit_imageload.load(f, bitmap=displayio.Bitmap, palette=displayio.Palette)
digikey_sprite = displayio.TileGrid(digikey_bitmap, pixel_shader=digikey_palette, x=0, y=34)
splash.append(digikey_sprite)
# 160 * 56
with open("/sd/resources/pic/ee.bmp", "rb") as f:
eeworld_bitmap, eeworld_palette = adafruit_imageload.load(f, bitmap=displayio.Bitmap, palette=displayio.Palette)
eeworld_sprite = displayio.TileGrid(eeworld_bitmap, pixel_shader=eeworld_palette, x=160, y=20)
splash.append(eeworld_sprite)
# Set text, font, and color
font = bitmap_font.load_font("/sd/resources/font/opposans_m_12.pcf")
# Create the text label
lable_area_fw = label.Label(
font, x=10, y=120, text="Follow me 第四期!", scale=2, color=0xF8F8FF # 0x191970
)
lable_area_id = label.Label(
font, x=20, y=160, text="ID.LODA", scale=2, color=(0, 191, 255)
)
splash.append(lable_area_fw)
splash.append(lable_area_id)
while True:
time.sleep(0.5)
led.value = not led.value
```
### 任务效果
从 SD 卡导入字体库和背景图片,并通过 LCD 进行显示
## 基础任务一:完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。
### 实现步骤
1. 完成该任务需要导入 Wiznet5K 系列的库文件 `adafruit_wiznet5k/`, 参考文档 https://learn.adafruit.com/ethernet-for-circuitpython
1. 安装 wireshake 抓包工具
1. 程序运行之后,启动wireshake 抓取板卡 ip
1. windows 端打开控制台 ping 板卡
### 任务代码
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
import board
import busio
import digitalio
import displayio
import sdcardio
import storage
import terminalio
import time
# Starting in CircuitPython 9.x fourwire will be a seperate internal library
# rather than a component of the displayio library
try:
from fourwire import FourWire
except ImportError:
from displayio import FourWire
from adafruit_display_text import label
from adafruit_st7789 import ST7789
from adafruit_bitmap_font import bitmap_font
import adafruit_imageload
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
# SPI0 for w5x00
SPI0_SCK = board.GP18
SPI0_TX = board.GP19
SPI0_RX = board.GP16
SPI0_CSn = board.GP17
## w5x00 reset
W5x00_RSTn = board.GP20
# SPI1 for tft
SPI1_SCK = board.GP10
SPI1_TX = board.GP11
SPI1_RX = board.GP12
# tft lcd io
TFT_CSn = board.GP13
TFT_RSTn = board.GP14
TFT_DC = board.GP15
# sdcard io
SD_CSn = board.GP9
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
# Release any resources currently in use for the displays
displayio.release_displays()
spi1_bus = busio.SPI(SPI1_SCK, MOSI=SPI1_TX, MISO=SPI1_RX)
display_bus = FourWire(spi1_bus, command=TFT_DC, chip_select=TFT_CSn, reset=TFT_RSTn)
display = ST7789(display_bus, width=320, height=240, rotation=90)
sdcard = sdcardio.SDCard(spi1_bus, SD_CSn)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
# Make the display context
splash = displayio.Group()
display.root_group = splash
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000 # 0xF8F8FF # Ghost White
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)
# 180 * 125
with open("/sd/resources/pic/test_image.png", "rb") as f:
blinka_bitmap, blinka_palette = adafruit_imageload.load(f, bitmap=displayio.Bitmap, palette=displayio.Palette)
blinka_sprite = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_palette, x=140, y=115)
splash.append(blinka_sprite)
text_group = displayio.Group(scale=1, x=10, y=10)
text_area = label.Label(terminalio.FONT, text="", color=0xFFFF00)
text_group.append(text_area) # Subgroup for text scaling
splash.append(text_group)
# code handler
eth_rst = digitalio.DigitalInOut(W5x00_RSTn)
eth_rst.direction = digitalio.Direction.OUTPUT
eth_cs = digitalio.DigitalInOut(SPI0_CSn)
spi0_bus = busio.SPI(SPI0_SCK, MOSI=SPI0_TX, MISO=SPI0_RX)
# Reset W5500 first
eth_rst.value = False
time.sleep(1)
eth_rst.value = True
# Initialize ethernet interface with DHCP
# eth = WIZNET5K(spi_bus, cs)
# Initialize ethernet interface without DHCP
eth = WIZNET5K(spi0_bus, eth_cs, is_dhcp=False)
# Setup your network configuration below
IP_ADDRESS = (192, 168, 0, 3) #(10, 38, 180, 221)
SUBNET_MASK = (255, 255, 255, 0) # (255, 255, 254, 0)
GATEWAY_ADDRESS = (192, 168, 0, 1) # (10, 38, 180, 1)
DNS_SERVER = (211, 136, 150, 66) # (10, 38, 116, 23)
# IP_ADDRESS = (10, 38, 180, 221)
# SUBNET_MASK = (255, 255, 254, 0)
# GATEWAY_ADDRESS = (10, 38, 180, 1)
# DNS_SERVER = (10, 38, 116, 23)
eth.ifconfig = (IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER)
ifconfig = eth.ifconfig
text_area.text = text_area.text + "mac addr: {}\n".format(eth.pretty_mac(eth.mac_address))
text_area.text = text_area.text + "ip4 addr: {}\n".format(eth.pretty_ip(ifconfig[0]))
text_area.text = text_area.text + "subnet addr: {}\n".format(eth.pretty_ip(ifconfig[1]))
text_area.text = text_area.text + "gateway addr: {}\n".format(eth.pretty_ip(ifconfig[2]))
text_area.text = text_area.text + "dns addr: {}\n".format(eth.pretty_ip(ifconfig[3]))
domain_address = eth.get_host_by_name("eeworld.com.cn")
text_area.text = text_area.text + "eeworld addr: {}\n".format(eth.pretty_ip(domain_address))
domain_address = eth.get_host_by_name("digikey.cn")
text_area.text = text_area.text + "digikey addr: {}\n".format(eth.pretty_ip(domain_address))
domain_address = eth.get_host_by_name("adafruit.com")
text_area.text = text_area.text + "adafruit addr: {}\n".format(eth.pretty_ip(domain_address))
print(text_area.text)
while True:
time.sleep(0.5)
led.value = not led.value
print("Done!")
```
### 任务效果
驱动 W5500 控制器完成网络的初始化,并配置 ip、gateway、subnet、dns 等参数
- 显示界面
- ping 包流程
- ping 包解析
## 基础任务二:主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作)
### 实现步骤
1. 基于上一节任务的基础,完成 TCP Server 的代码搭建
1. 打开 wireshake 进行抓包
1. 打开网络调试工具,建立 tcp 连接,并通讯
### 任务代码
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
import board
import busio
import digitalio
import displayio
import sdcardio
import storage
import terminalio
import time
# Starting in CircuitPython 9.x fourwire will be a seperate internal library
# rather than a component of the displayio library
try:
from fourwire import FourWire
except ImportError:
from displayio import FourWire
from adafruit_display_text import label
from adafruit_st7789 import ST7789
from adafruit_bitmap_font import bitmap_font
import adafruit_imageload
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket
# SPI0 for w5x00
SPI0_SCK = board.GP18
SPI0_TX = board.GP19
SPI0_RX = board.GP16
SPI0_CSn = board.GP17
# w5x00 reset
W5x00_RSTn = board.GP20
# SPI1 for tft
SPI1_SCK = board.GP10
SPI1_TX = board.GP11
SPI1_RX = board.GP12
# tft lcd io
TFT_CSn = board.GP13
TFT_RSTn = board.GP14
TFT_DC = board.GP15
# sdcard io
SD_CSn = board.GP9
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
# Release any resources currently in use for the displays
displayio.release_displays()
spi1_bus = busio.SPI(SPI1_SCK, MOSI=SPI1_TX, MISO=SPI1_RX)
display_bus = FourWire(spi1_bus, command=TFT_DC, chip_select=TFT_CSn, reset=TFT_RSTn)
display = ST7789(display_bus, width=320, height=240, rotation=90)
sdcard = sdcardio.SDCard(spi1_bus, SD_CSn)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
# Make the display context
splash = displayio.Group()
display.root_group = splash
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000 # 0xF8F8FF # Ghost White
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)
# 180 * 125
with open("/sd/resources/pic/test_image.png", "rb") as f:
blinka_bitmap, blinka_palette = adafruit_imageload.load(f, bitmap=displayio.Bitmap, palette=displayio.Palette)
blinka_sprite = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_palette, x=140, y=115)
splash.append(blinka_sprite)
text_group = displayio.Group(scale=1, x=10, y=10)
text_area = label.Label(terminalio.FONT, text="", color=0xFFFF00)
text_group.append(text_area) # Subgroup for text scaling
splash.append(text_group)
# code handler
eth_rst = digitalio.DigitalInOut(W5x00_RSTn)
eth_rst.direction = digitalio.Direction.OUTPUT
eth_cs = digitalio.DigitalInOut(SPI0_CSn)
spi0_bus = busio.SPI(SPI0_SCK, MOSI=SPI0_TX, MISO=SPI0_RX)
# Reset W5500 first
eth_rst.value = False
time.sleep(1)
eth_rst.value = True
# Initialize ethernet interface with DHCP
# eth = WIZNET5K(spi0_bus, eth_cs)
# Initialize ethernet interface without DHCP
eth = WIZNET5K(spi0_bus, eth_cs, is_dhcp=False)
# # Setup your network configuration below
IP_ADDRESS = (192, 168, 0, 3) #(10, 38, 180, 221)
SUBNET_MASK = (255, 255, 255, 0) # (255, 255, 254, 0)
GATEWAY_ADDRESS = (192, 168, 0, 1) # (10, 38, 180, 1)
DNS_SERVER = (211, 136, 150, 66) # (10, 38, 116, 23)
eth.ifconfig = (IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER)
ifconfig = eth.ifconfig
text_area.text = text_area.text + "mac addr: {}\n".format(eth.pretty_mac(eth.mac_address))
text_area.text = text_area.text + "ip4 addr: {}\n".format(eth.pretty_ip(ifconfig[0]))
text_area.text = text_area.text + "subnet addr: {}\n".format(eth.pretty_ip(ifconfig[1]))
text_area.text = text_area.text + "gateway addr: {}\n".format(eth.pretty_ip(ifconfig[2]))
text_area.text = text_area.text + "dns addr: {}\n".format(eth.pretty_ip(ifconfig[3]))
print(text_area.text)
# Initialize a socket for our server
socket.set_interface(eth)
# socket.setdefaulttimeout(50)
server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # Allocate socket for the server
server_ip = eth.pretty_ip(eth.ip_address) # IP address of server
server_port = 5000 # Port to listen on
server.bind((server_ip, server_port)) # Bind to IP and Port
server.listen() # Begin listening for incoming clients
while True:
print(f"Accepting connections on {server_ip}:{server_port}")
text_area.text = text_area.text + "Accepting connections on {}:{}\n".format(server_ip, server_port)
conn, addr = server.accept() # Wait for a connection from a client.
led.value = True
print(f"Connection accepted from {addr}, reading exactly 1024 bytes from client")
text_area.text = text_area.text + "Connection accepted from {}\n".format(addr)
conn.settimeout(100)
conn.send("Welcome to w5500 evb pico's tcp server")
with conn:
buffer = bytearray(1024)
length = conn.recv_into(buffer, len(buffer))
if length > 0:
data = str(buffer[0:length], "utf-8"))
print(f"recv: {data}")
text_area.text = text_area.text + f"recv data: {data}\n"
conn.send(data)
# data = str(conn.recv(1024), "utf-8")
# if data: # Wait for receiving data
# cplog(f"recv: {data}")
# conn.send(data) # Echo message back to client
led.value = False
print("Connection closed")
print("Done!")
```
### 任务效果
- 显示界面
- 网络调试助手 tcp 连接
- wireshark 抓包分析
## 进阶任务:从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送显示屏(串口)显示。
### 实现步骤
1. 本节任务需要添加 ntp 库 `adafruit_ntp.mpy`
### 任务代码
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
import board
import busio
import digitalio
import displayio
import sdcardio
import storage
import rtc
import terminalio
import time
# Starting in CircuitPython 9.x fourwire will be a seperate internal library
# rather than a component of the displayio library
try:
from fourwire import FourWire
except ImportError:
from displayio import FourWire
from adafruit_display_text import label
from adafruit_st7789 import ST7789
from adafruit_bitmap_font import bitmap_font
import adafruit_imageload
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket
import adafruit_ntp
UTC_OFFSET = 8
WEEK = ['一', '二', '三', '四', '五', '六', '日']
# SPI0 for w5x00
SPI0_SCK = board.GP18
SPI0_TX = board.GP19
SPI0_RX = board.GP16
SPI0_CSn = board.GP17
## w5x00 reset
W5x00_RSTn = board.GP20
# SPI1 for tft
SPI1_SCK = board.GP10
SPI1_TX = board.GP11
SPI1_RX = board.GP12
# tft lcd io
TFT_CSn = board.GP13
TFT_RSTn = board.GP14
TFT_DC = board.GP15
# sdcard io
SD_CSn = board.GP9
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
# Release any resources currently in use for the displays
displayio.release_displays()
spi1_bus = busio.SPI(SPI1_SCK, MOSI=SPI1_TX, MISO=SPI1_RX)
display_bus = FourWire(spi1_bus, command=TFT_DC, chip_select=TFT_CSn, reset=TFT_RSTn)
display = ST7789(display_bus, width=320, height=240, rotation=90)
sdcard = sdcardio.SDCard(spi1_bus, SD_CSn)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
# Make the display context
splash = displayio.Group()
display.root_group = splash
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000 # 0xF8F8FF # Ghost White
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)
# 180 * 125
with open("/sd/resources/pic/test_image.png", "rb") as f:
blinka_bitmap, blinka_palette = adafruit_imageload.load(f, bitmap=displayio.Bitmap, palette=displayio.Palette)
blinka_sprite = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_palette, x=140, y=115)
splash.append(blinka_sprite)
text_group = displayio.Group() # (scale=1, x=10, y=10)
font = bitmap_font.load_font("/sd/resources/font/opposans_m_12.pcf")
time_area = label.Label(font, x=10, y=12, text='', scale=1, color=0x00BFFF)
text_area = label.Label(terminalio.FONT, x=10, y=30, text="", scale=1, color=0xFFFF00)
text_group.append(time_area)
text_group.append(text_area) # Subgroup for text scaling
splash.append(text_group)
# code handler
eth_rst = digitalio.DigitalInOut(W5x00_RSTn)
eth_rst.direction = digitalio.Direction.OUTPUT
eth_cs = digitalio.DigitalInOut(SPI0_CSn)
spi0_bus = busio.SPI(SPI0_SCK, MOSI=SPI0_TX, MISO=SPI0_RX)
# Reset W5500 first
eth_rst.value = False
time.sleep(1)
eth_rst.value = True
# Initialize ethernet interface with DHCP
# eth = WIZNET5K(spi0_bus, eth_cs)
# Initialize ethernet interface without DHCP
eth = WIZNET5K(spi0_bus, eth_cs, is_dhcp=False)
# # Setup your network configuration below
IP_ADDRESS = (192, 168, 0, 3) #(10, 38, 180, 221)
SUBNET_MASK = (255, 255, 255, 0) # (255, 255, 254, 0)
GATEWAY_ADDRESS = (192, 168, 0, 1) # (10, 38, 180, 1)
DNS_SERVER = (211, 136, 150, 66) # (10, 38, 116, 23)
eth.ifconfig = (IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER)
ifconfig = eth.ifconfig
text_area.text = text_area.text + "mac addr: {}\n".format(eth.pretty_mac(eth.mac_address))
text_area.text = text_area.text + "ip4 addr: {}\n".format(eth.pretty_ip(ifconfig[0]))
text_area.text = text_area.text + "subnet addr: {}\n".format(eth.pretty_ip(ifconfig[1]))
text_area.text = text_area.text + "gateway addr: {}\n".format(eth.pretty_ip(ifconfig[2]))
text_area.text = text_area.text + "dns addr: {}\n".format(eth.pretty_ip(ifconfig[3]))
print(text_area.text)
# Initialize a socket for our server
socket.set_interface(eth)
def ntp_sync_time():
print("Local time before synchronization:%s" % str(time.localtime()))
try:
# ntp = adafruit_ntp.NTP(pool, tz_offset=UTC_OFFSET)
ntp = adafruit_ntp.NTP(socket, server='ntp.aliyun.com', tz_offset=UTC_OFFSET)
# NOTE: This changes the system time so make sure you aren't assuming that time
# doesn't jump.
rtc.RTC().datetime = ntp.datetime
print("Local time after synchronization: %s" % str(time.localtime()))
except OSError as e:
print("ntp error:{}".format(e))
ntp_sync_time()
counter = 0
while True:
if counter % 2 == 0:
date = time.localtime()
# time_area.text = f"{date[0]}/{date[1]}/{date[2]} {date[3]}:{date[4]}:{date[5]} 星期{WEEK[date[6]]}"
time_area.text = "{}/{:0>2}/{:0>2} {:0>2}:{:0>2}:{:0>2} 星期{}".format(date[0], date[1], date[2], date[3], date[4], date[5], WEEK[date[6]])
led.value = not led.value
time.sleep(0.5)
counter += 1
print("Done!")
```
### 任务效果
## 终极任务二:使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件。
### 实现步骤
1. FTP 的代码实现参考了 github 上基于 esp32 micropython 的 [uftpd](https://github.com/robert-hh/FTP-Server-for-ESP8266-ESP32-and-PYBD)库,进行了 circuit python 的适配,总体差别不大,主要是 wifi 和 w5500 的网络接口差异,造成了比较大的困扰
1. 打开 FTP 客户端,这边我使用的 FlashFXP,连接板卡即可
### 任务代码
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
# from os import listdir, remove, getcwd, chdir, stat, mkdir, rmdir, rename
import os
import gc
import board
import busio
import digitalio
import displayio
import sdcardio
import storage
import rtc
import terminalio
import time
# Starting in CircuitPython 9.x fourwire will be a seperate internal library
# rather than a component of the displayio library
try:
from fourwire import FourWire
except ImportError:
from displayio import FourWire
from adafruit_display_text import label
from adafruit_st7789 import ST7789
from adafruit_bitmap_font import bitmap_font
import adafruit_imageload
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket
import adafruit_ntp
UTC_OFFSET = 8
WEEK = ["一", "二", "三", "四", "五", "六", "日"]
MONTH = [
"",
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
]
BUTTON_X = const(6)
BUTTON_Y = const(2)
BUTTON_A = const(5)
BUTTON_B = const(1)
BUTTON_SELECT = const(0)
BUTTON_START = const(16)
button_mask = const(
(1 > 8, DATA_PORT % 256
)
)
dataclient, data_addr = datasocket.accept()
dataclient.settimeout(1)
cplog(f"FTP Data connection from:{data_addr}")
elif command == "PORT":
items = payload.split(",")
if len(items) >= 6:
data_addr = ".".join(items[:4])
if data_addr == "127.0.1.1":
# replace by command session addr
data_addr = remote_addr
DATA_PORT = int(items[4]) * 256 + int(items[5])
cl.send("200 OK\r\n")
else:
cl.send("504 Fail\r\n")
elif command == "LIST" or command == "NLST":
if not payload.startswith("-"):
place = path
else:
place = cwd
try:
cl.send("150 Here comes the directory listing.\r\n")
send_list_data(
place, dataclient, command == "LIST" or payload == "-l"
)
cl.send("226 Listed.\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
if dataclient is not None:
# dataclient.close()
dataclient._disconnect()
dataclient = None
elif command == "RETR":
try:
cl.send("150 Opening data connection.\r\n")
send_file_data(path, dataclient)
cl.send("226 Transfer complete.\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
if dataclient is not None:
# dataclient.close()
dataclient._disconnect()
dataclient = None
elif command == "STOR":
try:
cl.send("150 Ok to send data.\r\n")
save_file_data(path, dataclient, "w")
cl.send("226 Transfer complete.\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
if dataclient is not None:
# dataclient.close()
dataclient._disconnect()
dataclient = None
elif command == "APPE":
try:
cl.send("150 Ok to send data.\r\n")
save_file_data(path, dataclient, "a")
cl.send("226 Transfer complete.\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
if dataclient is not None:
# dataclient.close()
dataclient._disconnect()
dataclient = None
elif command == "DELE":
try:
os.remove(path)
cl.send(msg_250_OK)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
elif command == "RMD" or command == "XRMD":
try:
os.rmdir(path)
cl.send(msg_250_OK)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
elif command == "MKD" or command == "XMKD":
try:
os.mkdir(path)
cl.send(msg_250_OK)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
elif command == "RNFR":
fromname = path
cl.send("350 Rename from\r\n")
elif command == "RNTO":
if fromname is not None:
try:
os.rename(fromname, path)
cl.send(msg_250_OK)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
else:
cl.send(msg_550_fail)
fromname = None
elif command == "MDTM":
try:
tm = time.localtime(os.stat(path)[8])
cl.send(
"213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n".format(
*tm[0:6]
)
)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send("550 Fail\r\n")
elif command == "STAT":
if payload == "":
cl.send(
"211-Connected to ({})\r\n"
" Data address ({})\r\n"
"211 TYPE: Binary STRU: File MODE:"
" Stream\r\n".format(remote_addr[0], addr)
)
else:
cl.send("213-Directory listing:\r\n")
send_list_data(path, cl, True)
cl.send("213 Done.\r\n")
elif command == "SITE":
try:
# exec(payload.replace("\0", "\n"))
cl.send("250 OK\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send("550 Fail\r\n")
else:
cl.send("502 Unsupported command.\r\n")
print(
"Unsupported command {} with payload {}".format(
command, payload
)
)
except Exception as err:
cplog(f"err:{err}")
finally:
cl.close()
cl = None
break
finally:
datasocket.close()
ftpsocket.close()
if dataclient is not None:
dataclient.close()
# send_list_data("/", None, True)
ftpserver(
netif=eth,
socketpool=socket,
ipaddr=eth.pretty_ip(eth.ip_address),
timeout=500,
)
cplog_clear()
print("Done!")
```
### 任务效果
## 演示任务
### 实现步骤
1. 增加了按键控制器的库 `adafruit_seesaw`, 通过按键触发不同服务器的使能
### 任务代码
```python
# SPDX-FileCopyrightText: 2024 id.loda
# SPDX-License-Identifier: MIT
# from os import listdir, remove, getcwd, chdir, stat, mkdir, rmdir, rename
import os
import gc
import board
import busio
import digitalio
import displayio
import sdcardio
import storage
import rtc
import terminalio
import time
# Starting in CircuitPython 9.x fourwire will be a seperate internal library
# rather than a component of the displayio library
try:
from fourwire import FourWire
except ImportError:
from displayio import FourWire
from adafruit_display_text import label
from adafruit_st7789 import ST7789
from adafruit_bitmap_font import bitmap_font
import adafruit_imageload
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket
import adafruit_ntp
from adafruit_seesaw.seesaw import Seesaw
UTC_OFFSET = 8
WEEK = ["一", "二", "三", "四", "五", "六", "日"]
MONTH = [
"",
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
]
BUTTON_X = const(6)
BUTTON_Y = const(2)
BUTTON_A = const(5)
BUTTON_B = const(1)
BUTTON_SELECT = const(0)
BUTTON_START = const(16)
button_mask = const(
(1 > 8, DATA_PORT % 256
)
)
dataclient, data_addr = datasocket.accept()
dataclient.settimeout(1)
cplog(f"FTP Data connection from:{data_addr}")
elif command == "PORT":
items = payload.split(",")
if len(items) >= 6:
data_addr = ".".join(items[:4])
if data_addr == "127.0.1.1":
# replace by command session addr
data_addr = remote_addr
DATA_PORT = int(items[4]) * 256 + int(items[5])
cl.send("200 OK\r\n")
else:
cl.send("504 Fail\r\n")
elif command == "LIST" or command == "NLST":
if not payload.startswith("-"):
place = path
else:
place = cwd
try:
cl.send("150 Here comes the directory listing.\r\n")
send_list_data(
place, dataclient, command == "LIST" or payload == "-l"
)
cl.send("226 Listed.\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
if dataclient is not None:
dataclient._disconnect()
dataclient.close()
dataclient = None
elif command == "RETR":
try:
cl.send("150 Opening data connection.\r\n")
send_file_data(path, dataclient)
cl.send("226 Transfer complete.\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
if dataclient is not None:
dataclient._disconnect()
dataclient.close()
dataclient = None
elif command == "STOR":
try:
cl.send("150 Ok to send data.\r\n")
save_file_data(path, dataclient, "w")
cl.send("226 Transfer complete.\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
if dataclient is not None:
dataclient._disconnect()
dataclient.close()
dataclient = None
elif command == "APPE":
try:
cl.send("150 Ok to send data.\r\n")
save_file_data(path, dataclient, "a")
cl.send("226 Transfer complete.\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
if dataclient is not None:
dataclient._disconnect()
dataclient.close()
dataclient = None
elif command == "DELE":
try:
os.remove(path)
cl.send(msg_250_OK)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
elif command == "RMD" or command == "XRMD":
try:
os.rmdir(path)
cl.send(msg_250_OK)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
elif command == "MKD" or command == "XMKD":
try:
os.mkdir(path)
cl.send(msg_250_OK)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
elif command == "RNFR":
fromname = path
cl.send("350 Rename from\r\n")
elif command == "RNTO":
if fromname is not None:
try:
os.rename(fromname, path)
cl.send(msg_250_OK)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send(msg_550_fail)
else:
cl.send(msg_550_fail)
fromname = None
elif command == "MDTM":
try:
tm = time.localtime(os.stat(path)[8])
cl.send(
"213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n".format(
*tm[0:6]
)
)
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send("550 Fail\r\n")
elif command == "STAT":
if payload == "":
cl.send(
"211-Connected to ({})\r\n"
" Data address ({})\r\n"
"211 TYPE: Binary STRU: File MODE:"
" Stream\r\n".format(remote_addr[0], addr)
)
else:
cl.send("213-Directory listing:\r\n")
send_list_data(path, cl, True)
cl.send("213 Done.\r\n")
elif command == "SITE":
try:
# exec(payload.replace("\0", "\n"))
cl.send("250 OK\r\n")
except Exception as err:
cplog(f"command {command} err:{err}")
cl.send("550 Fail\r\n")
else:
cl.send("502 Unsupported command.\r\n")
print(
"Unsupported command {} with payload {}".format(
command, payload
)
)
except Exception as err:
cplog(f"err:{err}")
finally:
cl.close()
cl = None
break
finally:
datasocket.close()
ftpsocket.close()
if dataclient is not None:
dataclient.close()
# send_list_data("/", None, True)
def tcpserver(socketpool, ipaddr, port):
server = socketpool.socket(
socketpool.AF_INET, socketpool.SOCK_DGRAM
) # Allocate socket for the server
server_ip = ipaddr # IP address of server
server_port = port # Port to listen on
server.bind((server_ip, server_port)) # Bind to IP and Port
server.listen() # Begin listening for incoming clients
while True:
cplog(f"Accepting connections on {server_ip}:{server_port}")
conn, addr = server.accept() # Wait for a connection from a client.
led.value = True
cplog(
f"Connection accepted from {addr}, reading exactly 1024 bytes from client"
)
conn.settimeout(100)
conn.send("Welcome to w5500 evb pico's tcp server")
with conn:
buffer = bytearray(1024)
length = conn.recv_into(buffer, len(buffer))
if length > 0:
cplog(str(buffer[0:length], "utf-8"))
conn.send(buffer[0:length])
# data = str(conn.recv(1024), "utf-8")
# if data: # Wait for receiving data
# cplog(f"recv: {data}")
# conn.send(data) # Echo message back to client
led.value = False
cplog("Connection closed")
break
counter = 0
while True:
buttons = seesaw.digital_read_bulk(button_mask)
if not buttons & (1
- 2024-02-22
-
加入了学习《【得捷Follow me第4期】项目任务提交》,观看 视频
- 2024-02-19
-
回复了主题帖:
2024开工大吉,你期待测评中心,能有哪些板卡或书籍等?
牛的,大金主
许愿一个 STM32U5A9J-DK,正好刚接触穿戴,学习下
- 2024-02-01
-
加入了学习《【得捷电子Follow me第3期】项目总结报告》,观看 【得捷Follow me第3期】项目总结报告
- 2024-01-18
-
回复了主题帖:
领取审核名单(第五批): 辞旧,年底清仓,100+板卡来袭,有缘来领
个人信息无误,已知晓需自己支付邮费
谢谢
- 2024-01-11
-
回复了主题帖:
辞旧:年底清仓,100+板卡来袭,有缘来领
申请板卡:37 四色板组合式开发平台 Kinetis MCU 套件
领取理由:四色板的概念其实比较早了,后面一直没有更新比较可惜,用的芯片型号其实也已经是时代的弃儿了,但是胜在模块化的结构,带有非常丰富的外设资源,支持其他芯片进行 DIY,之前也是一直没有机会使用,借此机会玩一下。
计划是简单了解下 Kinetis 芯片的资料,根据板卡的外设硬件,学习下,I2C、SPI、ADC、CAN等相关外设的驱动,后续看下如何 DIY 下适配到主流的芯片上,或者 ESP32 这个适合 DIY 的小模块上