国庆节祝愿:祖国繁荣昌盛国泰民安福寿绵长
行空板 K10为祖国母亲庆祝生日
一、项目背景
1.1 需求来源
国庆假期中段,需要在行空板 K10 上做一个与国庆主题相关、能在课堂上当场演示的作品。这次想要一个有仪式感、能讲出故事的东西——于是选了「天安门升旗仪式」。
选择的理由:
| 候选方案 | 评估 |
|---|---|
| 天安门升旗仪式(选定) | 仪式感强,画面是静态为主 |
| 国庆烟花秀 | 最炫,但一帧画上百个粒子根本跑不动 |
| 国庆知识抢答 | 最快出成品,但几乎全是文字,交互体验一般 |
1.2 行空板K10介绍
行空板K10是一款专为信息科技课程中的编程学习、物联网及AI项目教学需求而开发的学习板。集摄像头、LCD彩屏、麦克风、扬声器、WiFi蓝牙模块、RGB指示灯及多种传感器和扩展接口于一体,无需额外设备即可实现传感器控制、物联网应用、图像检测、语音识别、语音合成等AI项目。
行空板 K10 集成了摄像头、LCD 彩屏、麦克风、扬声器、WiFi、蓝牙、RGB 指示灯及多种传感器。在教学过程中,无需额外连接其他设备,便可轻松实现传感器控制、物联网应用以及人脸识别、语音识别、语音合成等 AI 项目。
只是屏幕不支持触摸,最简输入只能用两个键解决,后期我们可以使用语音等高科技形式。
二、功能介绍
2.1 玩法
| 阶段 | 画面 | 行为 |
|---|---|---|
| 待机 | 清晨的天安门广场:朝霞天空、金色朝阳、左侧天安门城楼、中央旗杆,国旗停在旗杆底部 | 灯光按模式呼吸/流水,底部提示条显示操作 |
| 升旗 | 国旗匀速上升 | 每 25% 一声鼓点;3 颗 RGB 由暗红渐亮到金红;底部显示百分比 |
| 礼成 | 屏幕中部出现「祝伟大祖国生日快乐」「1949 - 2026 国庆快乐」+ 星光 | 礼成号角 + RGB 金红快闪; |
2.2 操作方式
| 操作 | 功能 |
|---|---|
| A 短按 | 开始升旗;礼成后再按一次=再来一次 |
| B 短按 | 循环切换灯光模式:关 → 常亮 → 呼吸 → 流水 |
| B 长按(> 0.62 s) | 音效开 / 关 |
| A+B 同按 1 秒 | 回到待机(国旗降回底部,祝福语清除) |
升旗过程中 B 短按不生效(避免在仪式中途误触改灯光),这是刻意的:
main()里用elif state != ST_RAISE挡掉。
2.4 状态机
+----------------------------+
| |
v A 短按 | pct >= 100
+---------+ --------> +---------+ --------> +---------+
| ST_IDLE| | ST_RAISE| | ST_DONE |
+---------+ <-------- +---------+ <-------- +---------+
^ A+B 1s A 短按
| (再来一次)
+--------------------------------------+
三、硬件清单
3.1 必需件
| 名称 | 规格 | 用途 |
|---|---|---|
| 行空板 K10 | ESP32-S3,2.8" 240×320 ILI9341 | 主控 + 显示 |
| USB Type-C 数据线 | 供电 + 下载 | — |
| 电脑 + Thonny(或 mpremote) | 上传 main.py 与 wav |
— |
3.2 用到的板载资源
| 资源 | 接口 | 本项目中的用途 |
|---|---|---|
| 屏幕 | screen.init(dir=2) → 竖屏 240×320 |
全部画面 |
| A / B 按键 | button(button.a) / button(button.b) |
升旗、灯光、音效、复位 |
| 3 颗 RGB 灯 | rgb.write(i, r, g, b) |
升旗渐变、礼成快闪、4 种灯光模式 |
| 扬声器 | speaker.play_sys_music("xxx.wav") |
号角、鼓点、礼成音 |
| Flash 文件系统 | open() / os.listdir() |
flag_cfg.txt 配置持久化 |
四、程序编写
赋值
把"会动的东西"和"不动的东西"分开,这是整个程序最关键的一条设计约束:
POLE_X, POLE_W = 138, 3 # 旗杆
FLAG_X = 142 # 国旗左边缘(紧贴旗杆右侧)
FLAG_W, FLAG_H = 90, 60 # 3:2
FLAG_Y_TOP = 48 # 升到顶时的 y
FLAG_Y_BOT = 240 # 起始 y(旗底 300, 正好在地平线上)
静物区域
| 静物 | 占位 | 与国旗区重叠? |
|---|---|---|
| 人民英雄纪念碑(近景主体) | x ∈ [26, 114],y ∈ [52, 300] | 否 |
| 天安门城楼(远景剪影) | x ∈ [4, 132],y ∈ [196, 272] | 否 |
| 朝阳 + 光晕 | x ∈ [4, 36],y ∈ [48, 80] | 否 |
| 标题 / 副标题 | y ∈ [6, 40] | 否(在旗顶 y=48 之上) |
绘制天空
def paint_sky(x, y, w, h):
"""只重绘与给定矩形相交的天空色带 —— 擦除国旗就靠它。"""
b0 = y // BAND_H
b1 = (y + h - 1) // BAND_H
for b in range(b0, b1 + 1):
ty0 = b * BAND_H
ty1 = ty0 + BAND_H
cy0 = ty0 if ty0 > y else y
cy1 = ty1 if ty1 < y + h else y + h
fill(x, cy0, w, cy1 - cy0, SKY_BANDS[b])
五角星画法
def star_offsets(R):
out = []
for i in range(10):
ang = -1.5707963 + i * 0.62831853 # -90° + i*36°
r = R if i % 2 == 0 else R * 0.382 # 标准五角星内外半径比
out.append((int(round(r * math.cos(ang))), int(round(r * math.sin(ang)))))
return out
改进后的程序
STAR_IDX5 = (0, 4, 8, 2, 6) # 一笔画顺序: 跳过一个外顶点
def draw_star(cx, cy, offs, color):
n = len(STAR_IDX5)
for i in range(n):
x1, y1 = offs[STAR_IDX5[i]]
x2, y2 = offs[STAR_IDX5[(i + 1) % n]]
screen.draw_line(cx + x1, cy + y1, cx + x2, cy + y2, color)
画四颗五角星
STAR_R_SMALL = 4 # 标准应为 3, 放大到 4 让星形一眼可辨
for sx, sy in STAR_SMALL:
px = FLAG_X + sx
py = y + sy
draw_star(px, py, STAR_S_OFF, C_STAR)
screen.draw_circle(x=px, y=py, r=1, bcolor=C_STAR, fcolor=C_STAR)
升旗循环
pct = el * 100 // RAISE_MS
ny = FLAG_Y_BOT - (FLAG_Y_BOT - FLAG_Y_TOP) * pct // 100
原本写成 p = el / float(RAISE_MS) 这种浮点写法,每帧都要分配 float 对象,反复分配会招来 GC。改成整数除法后,长帧从"偶发 367 ms"降到基本不出现。
灯光
升旗中按高度由暗红转金红(整数运算,避免 GC):
if pct >= 0:
v = 40 + 200 * pct // 100
rgb_all(v, v * 35 * pct // 10000, 0)
return
其余状态按 4 种模式走:关 / 常亮(暗红)/ 呼吸(正弦)/ 流水(3 颗轮流亮)。礼成时 light_flash() 金红交替快闪,每 160 ms 切一次。
主循环与按键边沿
while True:
now = time.ticks_ms()
a = bt_a.status()
b = bt_b.status()
if a and not last_a:
a_down_ms = now
if b and not last_b:
b_down_ms = now
if a and b:
if both_ms == 0:
both_ms = now
else:
both_ms = 0
if not a and last_a: # A 松手: 短按 = 升旗
if state != ST_RAISE and time.ticks_diff(now, a_down_ms) < LONG_MS:
start_raise(now)
if not b and last_b: # B 松手: 长按 = 音效, 短按 = 灯光
dur = time.ticks_diff(now, b_down_ms)
if dur >= LONG_MS:
snd_on = not snd_on
save_cfg()
last_foot = -1
elif state != ST_RAISE:
light_mode = (light_mode + 1) % 4
save_cfg()
last_foot = -1
if a and b and both_ms and time.ticks_diff(now, both_ms) >= BOTH_MS:
to_idle()
both_ms = 0
last_a = a
last_b = b
if state == ST_RAISE:
tick_raise(now)
elif state == ST_DONE:
tick_done(now)
else:
tick_idle(now)
time.sleep_ms(LOOP_MS) # 10 ms 轮询
五、效果查看
六、后续可改进方向
| 方向 | 做法 | 收益 |
|---|---|---|
| 加国歌 | 传一个完整的 anthem.wav(已留接口) |
仪式感拉满 |
| 国旗飘动 | 在旗面右侧加正弦摆动的短竖线 | 更生动,但每帧多几次 draw_line |
| 加日期倒计时 | 用 time + 手动设定日期,显示"距国庆还有 N 天" |
需先校时 |
最后祝愿祖国:




我建议可以把五角星的绘图优化一下,小星星的角对准大星星