【得捷电子Follow me第2期】任务1-4提交
[复制链接]
先放最终图片:
第一部分 视频
https://training.eeworld.com.cn/video/38561
第二部分 总结报告
任务1 汉字显示
使用了文泉驿点阵宋体12px,保证屏幕能容纳更多的信息。ttf字体先导入FontForge,再以常用汉字和ASCII字符在 bdftopcf font converter (gitee.io) 生成一个python脚本,在FontForge中直接执行,就能筛选出需要保留的字符,删去其余字符并保存为pcf格式后,字体文件尽占用309KB
代码:
text_group = displayio.Group(scale=1, x=0, y=0)
text_chinese_test = label.Label(
font_cn, text="汉字显示", color=0xFFFFFF, x=0, y=1 * LINE_HEIGHT
)
任务2 联网
直接使用CircuitPython的wifi库连接AP并获取IP地址,将其显示在OLED屏幕上
代码:
wifi.radio.connect(WIFI_SSID, WIFI_PASSWORD)
wifi_ip = wifi.radio.ipv4_address
......
text_wifi_ssid = label.Label(
font_cn, text=f"SSID: {WIFI_SSID}", color=0xFFFFFF, x=0, y=2 * LINE_HEIGHT
)
text_wifi_ip = label.Label(
font_cn, text=f"IP: {wifi_ip}", color=0xFFFFFF, x=0, y=3 * LINE_HEIGHT
)
任务3 控制板载Neopixel LED
使用adafruit包内的neopixel库,初始化灯珠,在主循环内轮询检测按键触发,触发案件后将灯珠颜色进行红-绿-蓝循环,并将当前灯珠状态显示在屏幕上
代码:
neopixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
neopixel.brightness = 0.1
button = digitalio.DigitalInOut(board.BUTTON)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP
......
if button.value == False:
neopixel_status += 1
neopixel_status = neopixel_status % 3
neopixel.fill(
(
0xFF << ((neopixel_status) * 8) & 0xFF,
0xFF << ((neopixel_status) * 8) >> 8 & 0xFF,
0xFF << ((neopixel_status) * 8) >> 16 & 0xFF,
)
)
text_neopixel_status = label.Label(
font_cn,
text=f"Color: { {0: 'Red', 1: 'Green', 2: 'Blue'}.get(neopixel_status, 'Unknown') }",
color=0xFFFFFF,
x=0,
y=4 * LINE_HEIGHT,
)
自选任务:天气时钟
因为和风天气API强制使用gzip压缩,使用了高德天气API以省去一些处理过程。使用adafruit_request库发送https请求,并解析校验返回的json数据。并根据设定的时间间隔刷新数据
时间方面,使用ntp对时,并将时间存储在由rtc库实现的内置rtc中,在主循环内轮询更新时间
代码:
def get_weather(data) -> bool:
requests = adafruit_requests.Session(
socketpool.SocketPool(wifi.radio), ssl.create_default_context()
)
data.update(
requests.get(
"https://restapi.amap.com/v3/weather/weatherInfo?key=%s&city=%s"
% (AMAP_WEATHER_KEY, AMAP_CITY_CODE)
).json()
)
# print(data)
if not data["infocode"] or data["infocode"] != "10000":
return False
data.update(data["lives"][0])
return True
rtc.RTC().datetime = adafruit_ntp.NTP(
socketpool.SocketPool(wifi.radio),
tz_offset=8,
server="ntp.aliyun.com",
socket_timeout=20,
).datetime
text_datetime = label.Label(
font_cn,
text="%04d-%02d-%02d %02d:%02d:%02d"
% (
time.localtime().tm_year,
time.localtime().tm_mon,
time.localtime().tm_mday,
time.localtime().tm_hour,
time.localtime().tm_min,
time.localtime().tm_sec,
),
color=0xFFFFFF,
x=0,
y=5 * LINE_HEIGHT,
)
text_weekday = label.Label(
font_cn,
text=f"{ {0: '周一', 1: '周二', 2: '周三', 3: '周四', 4: '周五', 5: '周六', 6: '周日'}.get(time.localtime().tm_wday) }",
color=0xFFFFFF,
x=0,
y=6 * LINE_HEIGHT,
)
if weather_last_update_time < time.monotonic() - WEATHER_INTERVAL:
weather_last_update_time = time.monotonic()
get_weather(weather_data)
text_weather = label.Label(
font_cn,
text=f"{weather_data['weather']} 气温{weather_data['temperature']}度",
color=0xFFFFFF,
x=0,
y=7 * LINE_HEIGHT,
)
最后,整合了以上四个任务的完整代码如下:
import board
import displayio
import time
import wifi
import neopixel
import digitalio
import rtc
import socketpool
import ssl
import adafruit_requests
import adafruit_ntp
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
WIFI_SSID = ""
WIFI_PASSWORD = ""
LINE_HEIGHT = 12
AMAP_WEATHER_KEY = ""
AMAP_CITY_CODE = ""
WEATHER_INTERVAL = 300
display = board.DISPLAY
neopixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
neopixel.brightness = 0.1
button = digitalio.DigitalInOut(board.BUTTON)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP
font_cn_file = "fonts/WenQuanYiBitmapSongmedium-12.pcf"
font_cn = bitmap_font.load_font(font_cn_file)
def get_weather(data) -> bool:
requests = adafruit_requests.Session(
socketpool.SocketPool(wifi.radio), ssl.create_default_context()
)
data.update(
requests.get(
"https://restapi.amap.com/v3/weather/weatherInfo?key=%s&city=%s"
% (AMAP_WEATHER_KEY, AMAP_CITY_CODE)
).json()
)
# print(data)
if not data["infocode"] or data["infocode"] != "10000":
return False
data.update(data["lives"][0])
return True
def main():
neopixel_status = 4
weather_data = {}
weather_last_update_time = 0
wifi.radio.connect(WIFI_SSID, WIFI_PASSWORD)
wifi_ip = wifi.radio.ipv4_address
rtc.RTC().datetime = adafruit_ntp.NTP(
socketpool.SocketPool(wifi.radio),
tz_offset=8,
server="ntp.aliyun.com",
socket_timeout=20,
).datetime
while True:
text_group = displayio.Group(scale=1, x=0, y=0)
text_chinese_test = label.Label(
font_cn, text="汉字显示", color=0xFFFFFF, x=0, y=1 * LINE_HEIGHT
)
text_wifi_ssid = label.Label(
font_cn, text=f"SSID: {WIFI_SSID}", color=0xFFFFFF, x=0, y=2 * LINE_HEIGHT
)
text_wifi_ip = label.Label(
font_cn, text=f"IP: {wifi_ip}", color=0xFFFFFF, x=0, y=3 * LINE_HEIGHT
)
if button.value == False:
neopixel_status += 1
neopixel_status = neopixel_status % 3
neopixel.fill(
(
0xFF << ((neopixel_status) * 8) & 0xFF,
0xFF << ((neopixel_status) * 8) >> 8 & 0xFF,
0xFF << ((neopixel_status) * 8) >> 16 & 0xFF,
)
)
text_neopixel_status = label.Label(
font_cn,
text=f"Color: { {0: 'Red', 1: 'Green', 2: 'Blue'}.get(neopixel_status, 'Unknown') }",
color=0xFFFFFF,
x=0,
y=4 * LINE_HEIGHT,
)
text_datetime = label.Label(
font_cn,
text="%04d-%02d-%02d %02d:%02d:%02d"
% (
time.localtime().tm_year,
time.localtime().tm_mon,
time.localtime().tm_mday,
time.localtime().tm_hour,
time.localtime().tm_min,
time.localtime().tm_sec,
),
color=0xFFFFFF,
x=0,
y=5 * LINE_HEIGHT,
)
text_weekday = label.Label(
font_cn,
text=f"{ {0: '周一', 1: '周二', 2: '周三', 3: '周四', 4: '周五', 5: '周六', 6: '周日'}.get(time.localtime().tm_wday) }",
color=0xFFFFFF,
x=0,
y=6 * LINE_HEIGHT,
)
if weather_last_update_time < time.monotonic() - WEATHER_INTERVAL:
weather_last_update_time = time.monotonic()
get_weather(weather_data)
text_weather = label.Label(
font_cn,
text=f"{weather_data['weather']} 气温{weather_data['temperature']}度",
color=0xFFFFFF,
x=0,
y=7 * LINE_HEIGHT,
)
text_group.append(text_chinese_test)
text_group.append(text_wifi_ssid)
text_group.append(text_wifi_ip)
text_group.append(text_neopixel_status)
text_group.append(text_datetime)
text_group.append(text_weekday)
text_group.append(text_weather)
display.show(text_group)
time.sleep(1)
if __name__ == "__main__":
main()
第三部分 代码汇总
代码压缩包在此处:https://download.eeworld.com.cn/detail/eew_zfsM67/629919
心得体验
Adafruit的板子确实设计的很棒,在一些细节的处理上做的很到位,果然贵有贵的道理。CircuitPython这个开发模式确实简单且易于上手,对于刚接触嵌入式开发的新人来说应该是一个很好的入门途径。与Arduino框架相比,Adafruit移植的扩展库包高度封装,风格较为统一,也涵盖了绝大部分常用的外设。Python的编写和独特的程序写入方式以及REPL对新手来说也都是很不错的简化。
最后,仍然感谢Digikey举办本次活动,为广大开发者送上免费的开发板以及配件
|