项目 2:模拟室内照明电路
🎯 项目目标
构建一个电灯开关模拟:
- 使用按键切换电灯开/关
- 控制全彩 LED 在"开"时发出白光
- 在屏幕上显示当前开关状态
📋 所需硬件
| 组件 | 数量 | 连接 |
|---|---|---|
| Steamania JoyKit V2 | 1 | 主控制器 |
| 按键模块 | 1 | 数字输入引脚 |
| WS2812B 全彩 LED | 1 | 板载或外部 |
🔧 电路设置
- 按键:连接到数字输入引脚之一(如 DI0)
- WS2812B LED:使用板载 LED 或连接到专用引脚
💡 核心任务
任务 1:配置按键为数字输入
- 使用指令
0x10配置 IO 引脚 - 设置适当的引脚为数字输入
任务 2:实现切换逻辑
- 检测按键按下(从高到低或从低到高的跳变)
- 切换状态变量(0 = 关,1 = 开)
- 实现去抖动以避免误触发
任务 3:控制 LED 状态
- 开关为"开"时 LED 发白光(0xFFFFFF)
- 开关为"关"时 LED 关闭(0x000000)
任务 4:显示状态
- 在屏幕上显示"ON"或"OFF"文本
- 可选显示当前状态指示器
📝 参考方案
程序代码(优化版本)
000 C7 0001 0000 ; 启用 WS2812B LED 控制
001 10 0025 00F0 ; 配置 IO 引脚:低 4 位为输入,高 4 位为输出
002 10 0020 0000 ; R20 = 灯状态(0=关,1=开)
003 10 0021 0001 ; R21 = 上一个按键状态(1=松开)
004 10 0028 FFFF ; 设置文本颜色为白色
005 0E 0000 0010 ; 跳转到主循环
; 主循环
010 14 0000 0000 ; 读取数字输入到 R00
011 17 0000 0001 ; R00 = R00 AND 0x01(仅检查 DI0)
012 06 0001 0020 ; 如果按键松开(1),跳转到 020
013 06 0001 0020 ; 如果上一个状态也是松开,跳过切换
; 按键按下时切换状态
014 12 0020 0001 ; R20 = R20 + 1(切换)
015 04 0001 0017 ; 如果 R20 > 1,跳转到重置
016 0E 0000 0018 ; 跳转到更新
017 10 0020 0000 ; 重置:R20 = 0
; 更新 LED 和显示
018 04 0000 001A ; 如果 R20 > 0,打开 LED
019 E4 0000 0000 ; LED 关
01A 55 0A00 0000 ; 显示"OFF"
01B 0E 0000 001D ; 跳转到结束
01C E4 00FF FFFF ; LED 开(白色)
01D 55 0A00 0001 ; 显示"ON"
; 结束循环
01E 11 0021 0000 ; R21 = R00(保存按键状态)
01F 02 0096 0000 ; 延时 150 毫秒(去抖动)
020 0E 0000 0010 ; 跳转回第 010 行
🔍 详细解释
初始化(第 000-005 行)
第 000 行:C7 0001 0000
- 启用 WS2812B 全彩 LED 控制模块
- 使用指令
0xE4前必须启用
第 001 行:10 0025 00F0
- 配置 IO 引脚方向
R25= IO 配置寄存器00F0= 二进制11110000= 低 4 引脚为输入,高 4 引脚为输出
第 002 行:10 0020 0000
- 初始化灯状态变量
R20为 0(关) R20将在 0(关)和 1(开)之间切换
第 003 行:10 0021 0001
- 初始化上一个按键状态
R21为 1(松开) - 用于边沿检测
第 004 行:10 0028 FFFF
- 设置前景色为白色(
0xFFFF,RGB565 格式) - 用于文本显示
第 005 行:0E 0000 0010
- 跳转到主循环第
010行
按键检测和切换(第 010-017 行)
第 010 行:14 0000 0000
- 读取数字输入值到
R00 - 每个位代表一个 DI 引脚状态
第 011 行:17 0000 0001
R00 = R00 AND 0x01- 仅检查 DI0(位 0)
- 结果:
R00= 0(按下)或 1(松开)
第 012 行:06 0001 0020
- 如果
R00 == 1(按键松开),跳转到020 - 按键未按下时跳过切换逻辑
第 013 行:06 0001 0020
- 如果上一个状态也是松开,跳过
- 这创建了边沿检测(仅在按下时切换,而不是按住)
第 014 行:12 0020 0001
- 切换灯状态:
R20 = R20 + 1 - 在 0 和 1 之间交替
第 015 行:04 0001 0017
- 如果
R20 > 1,跳转到重置行017 - 确保
R20保持在 0-1 范围内
第 016 行:0E 0000 0018
- 跳转到 LED 更新部分
第 017 行:10 0020 0000
- 重置
R20为 0(从 2 绕回 0)
LED 控制(第 018-01D 行)
第 018 行:04 0000 001A
- 如果
R20 > 0(灯开),跳转到01A
第 019 行:E4 0000 0000
- 关闭 LED
- RGB = (0, 0, 0) = 黑色
第 01A 行:55 0A00 0000
- 在位置 (10, 0) 显示"OFF"文本
- 值
0000代表"关"状态
第 01B 行:0E 0000 001D
- 跳转到循环结束
第 01C 行:E4 00FF FFFF
- 打开 LED
- RGB = (255, 255, 255) = 白色
第 01D 行:55 0A00 0001
- 在位置 (10, 0) 显示"ON"文本
循环管理(第 01E-020 行)
第 01E 行:11 0021 0000
- 保存当前按键状态到
R21 R21 = R00(为下一次迭代保存)
第 01F 行:02 0096 0000
- 延时 150 毫秒
0096= 十进制 150- 提供去抖动以防止误触发
第 020 行:0E 0000 0010
- 跳转回第
010行 - 创建无限循环以持续监测
🎨 状态转换表
| 当前状态 | 按键按下 | 新状态 | LED 动作 |
|---|---|---|---|
| 关 (0) | 按下 | 开 (1) | 打开(白色) |
| 开 (1) | 按下 | 关 (0) | 关闭(黑色) |
| 关 (0) | 未按下 | 关 (0) | 无变化 |
| 开 (1) | 未按下 | 开 (1) | 无变化 |
🔍 关键学习点
- 数字输入读取:如何从 IO 引脚读取按键状态
- 边沿检测:检测按键按下与按住的区别
- 切换逻辑:实现开/关状态机
- 去抖动:使用延时防止误触发
- 条件控制:使用比较进行决策
- RGB 颜色:为不同状态设置 LED 颜色
🧪 测试清单
- 按键正确配置为数字输入
- 按键按下时 LED 打开(白色)
- 再次按下按键时 LED 关闭
- 显示显示正确的"ON"或"OFF"状态
- 按键去抖动工作(无误触发)
- 系统对重复按下响应可靠
💡 扩展挑战
- 添加调光:使用按住按键调节 LED 亮度
- 多种颜色:循环不同颜色而不是简单的开/关
- 双按键系统:添加独立的开和关按键
- 自动关闭定时器:5 分钟后自动关闭
- 状态指示器:添加第二个 LED 显示电源状态
- 远程控制:使用红外或蓝牙进行无线控制
🐛 常见问题和解决方案
问题 1:LED 快速闪烁
原因:没有去抖动或延时不足 解决方案:增加第 01F 行的延时到 200-300ms
问题 2:按键无响应
原因:IO 配置不正确 解决方案:验证第 001 行设置正确的引脚为输入
问题 3:LED 多次切换
原因:按键抖动或延时太短 解决方案:增加去抖动延时或添加额外滤波
问题 4:显示显示错误文本
原因:状态变量或比较不正确
解决方案:检查 R20 值和比较逻辑
📚 相关文档
本项目使用的指令
| 操作码 | 名称 | 描述 | 文档链接 |
|---|---|---|---|
0x02 | 延时 | 设置毫秒级延时时间 | 延时 |
0x04 | 大于跳转 | 如果 R00 > 立即数则跳转 | 条件跳转 |
0x06 | 等于跳转 | 如果 R00 == 立即数则跳转 | 条件跳转 |
0x0E | 无条件跳转 | 跳转到指定行号 | 无条件跳转 |
0x10 | 写入寄存器 | 将立即数写入寄存器 | 寄存器操作 |
0x11 | 复制寄存器 | 将一个寄存器的值复制到另一个 | 寄存器操作 |
0x12 | 加立即数 | 将立即数加到寄存器 | 寄存器操作 |
0x14 | 读 DI | 读取数字输入引脚到 R00 | 数字 I/O |
0x17 | 与寄存器 | 按位与运算 | 位运算 |
0x55 | 显示文本 | 在屏幕上显示寄存器值 | 文本输出 |
0xCB | 启用 WS2812B | 启用 LED 控制模块 | 外部设备 |
0xE4 | 设置 LED 颜色 | 为指定 LED 设置 RGB 颜色 | 彩灯与音乐 |
额外参考
- IO 配置寄存器 (R25) - 引脚方向控制
- 寄存器映射 - 完整寄存器文档
- 指令集概览 - 完整指令集总览
- 条件跳转