跳到主要内容

编程技巧总结

本页总结基于本系统的编程最佳实践和高级技巧。核心思想:主程序做调度,子程做执行。


⚙️ 系统特性回顾​

关键指令​

指令助记符功能
01JT数字输出:写值到 GPIO 引脚
09DZ条件跳转:寄存器值 > 某值则跳
0EZY无条件跳转
0CDY调用子程(记返回地址,嵌套最多16层)
0DFH从子程返回
0FJS停机
10FZ赋值:写入寄存器
11JFZ条件跳转:寄存器值 ≠ 某值则跳
15(循环移位)位操作/循环移位
00(空/NOP)未写的行默认为 00 0000 0000,不做任何事

指令格式说明​

每行指令的格式:行号 操作码 P-0 P-1

  • P-0:第一个四位 HEX 数
  • P-1:第二个四位 HEX 数

跳转/调用类指令的目标地址位置:

指令目标地址位置说明
DYP-0调用子程,目标地址写在第一个四位 HEX
ZYP-1无条件跳转,目标地址写在第二个四位 HEX
FH不需要系统自动记录返回地址

正确写法:DY 0060 0000(调用 060 行子程,目标在 P-0)

正确写法:ZY 0000 0005(跳转到行 005,目标在 P-1)

输入信号汇总​

系统可用的输入信号及对应寄存器/指令:

信号类型寄存器/指令用途说明取值范围
按钮R3E按钮状态寄存器0000 = 未按下,0001 = 按下
温度R2E温度传感器读数0 ~ 65535(需按实际传感器换算)
颜色传感器R31红色分量值0 ~ 255
R32绿色分量值0 ~ 255
R33蓝色分量值0 ~ 255
模拟输入 (ADC)AD 指令电阻类传感器(光敏、声音等)AD 0000 XXXX 读通道0到寄存器
例如:声音传感器、光敏电阻、电位器0 ~ 最大值(依硬件而定)
数字输入 (GPIO)14 指令数字引脚电平读取0000 = 低电平,0001 = 高电平

输出信号 / 模块汇总​

系统可控制的输出及对应指令/寄存器。下面是按实际硬件分类的详细说明:

输出类型指令/寄存器用途说明示例
数字输出 (GPIO)JT (01)控制 LED、蜂鸣器、继电器等简单外设JT 00FF 00FF 所有引脚置高
PWM 控制R2A, R2B, R2C, R2DPWM 占空比寄存器(0~03E8 对应 0%~100%),控制 LED 亮度、电机转速写入 0000 ~ 03E8 调整占空比(最大 03E8=100%)
WS2812B LEDCD (E4)设置全彩 LED 颜色,格式 CD 00RR GGBBCD 00FF 0000 红色全亮
延时控制YS (02)程序延时等待YS 03E8 0000 延时 1 秒
寄存器到输出SS (13)寄存器值直接输出到数字引脚用于复杂模式的批量输出

硬件模块详细说明​

🔊 蜂鸣器(IO 控制,非音调)​

用一个 GPIO 引脚接蜂鸣器,通过高低电平切换发声:

引脚状态效果寄存器值
持续高电平持续发声0001
持续低电平不发声0000
快速高低切换连续脉冲声在程序里循环翻转
; 蜂鸣器短"嘀"一声(接在某一位 GPIO 上)
000 JT 0001 0000 ; 蜂鸣器低电平 = 发声(假设是低电平触发)
001 YS 0064 0000 ; 延时 100ms
002 JT 0001 0001 ; 关闭蜂鸣器
003 FH 0000 0000 ; 返回

🌬️ 小风扇(L9110H 双路 H 桥驱动)​

L9110H 需要 2 个引脚控制一路风扇(A-IA 控制速度/方向,A-IB 控制方向):

A-IAA-IB电机状态说明
PWM 高低正转(可调速)把速度值写入 A-IA 的 PWM 寄存器
低PWM 高反转(可调速)把速度值写入 A-IB 的 PWM 寄存器
低低滑行停止电机自由减速
高高制动停止快速刹车
; 风扇正转,速度 = 50%(假设接 R2A=A-IA, R2B=A-IB)
000 FZ 002A 01F4 ; R2A = 50% (01F4) 占空比 → A-IA 输出 PWM
001 FZ 002B 0000 ; R2B = 0 → A-IB 保持低电平
002 FH 0000 0000 ; 结果:风扇正转,约半速

; 风扇反转,速度 = 80%
010 FZ 002A 0000 ; R2A = 0 → A-IA 低电平
011 FZ 002B 0320 ; R2B = 80% (0320) 占空比 → A-IB 输出 PWM
012 FH 0000 0000 ; 结果:风扇反转,约八成速

; 风扇停止(滑行)
020 FZ 002A 0000 ; 两路都为 0
021 FZ 002B 0000
022 FH 0000 0000

小提示:L9110H 一个芯片可以驱动 2 路独立电机(A 路和 B 路),所以如果要控制两个风扇,需要 4 个 PWM 引脚。

🌈 外置 RGB LED(3 个引脚,IO 或 PWM 控制)​

用 3 个独立引脚 分别控制红、绿、蓝三色:

控制方式接线方法效果
纯 IO 控制R/G/B 各接一个 GPIO只能显示 8 种颜色(红/绿/蓝/黄/青/紫/白/灭)
PWM 控制R/G/B 各接一个 PWM 引脚可以混合出 1600 万种颜色
; 外置 RGB 显示红色(R 引脚接 R2A, G 接 R2B, B 接 R2C)
000 FZ 002A 03E8 ; 红色 = 最大亮度
001 FZ 002B 0000 ; 绿色 = 灭
002 FZ 002C 0000 ; 蓝色 = 灭
003 FH 0000 0000 ; 结果:显示纯红色

; 显示青色(绿+蓝混合)
010 FZ 002A 0000 ; 红 = 灭
011 FZ 002B 03E8 ; 绿 = 最亮
012 FZ 002C 03E8 ; 蓝 = 最亮
013 FH 0000 0000 ; 结果:青色

; 渐变色呼吸灯效果(红色从暗到亮再到暗)
020 FZ 0025 0000 ; R25 = 亮度计数器,从 0 开始
021 FZ 002A 0000 ; 先把红色设为 0
022 XDZ 0025 0032 ; 亮度 + 50(每次微调)
023 FZ 002A 0025 ; 把当前亮度值写入 R2A(红色 PWM)
024 YS 0019 0000 ; 延时 25ms
025 DYZ 0025 03E8 ; 还没到最大亮度(03E8=100%)?
026 ZY 0000 022 ; 是 → 继续增加
027 ZY 0000 020 ; 否 → 从头开始

🦾 舵机(PCA9685 模块驱动)​

PCA9685 是 I²C 接口的 16 路 PWM 扩展芯片,只用 2 根线(SDA 数据 / SCL 时钟)就能控制 16 个舵机。

特性说明
通信方式I²C(2 根线)
可驱动舵机数一个模块 16 路,可级联最多 62 个 → 992 路
PWM 分辨率12 位(4096 级)
典型舵机频率50Hz(周期 20ms)
舵机脉冲宽度1ms = 0°,1.5ms = 90°(中位),2ms = 180°
; 用 PCA9685 控制舵机角度
; 假设系统已有 I²C 驱动函数,通过写入 PCA9685 的寄存器来设置舵机角度
; 舵机角度 → PWM 占空比的换算:
; 0° → 脉宽 1.0ms → 在 50Hz 下约占 5% 占空比
; 90° → 脉宽 1.5ms → 在 50Hz 下约占 7.5% 占空比
; 180° → 脉宽 2.0ms → 在 50Hz 下约占 10% 占空比

; 舵机转到 90°(中位)
; 子程 0E0:设置通道 0 的舵机角度 = 参数 R20
; 这里展示的是逻辑流程:通过 I²C 发送配置数据到 PCA9685
0E0 FZ 0026 0040 ; PCA9685 的 I²C 地址 = 0x40(默认)
0E1 FZ 0027 0006 ; 通道 0 的寄存器起始地址 = 0x06
0E2 FZ 0028 0000 ; PWM ON 时刻 = 0(从周期开始就拉高)
0E3 FZ 0029 0180 ; PWM OFF 时刻 = 对应 1.5ms 的计数值(90°)
0E4 FH 0000 0000 ; 通过 I²C 写寄存器完成

为什么用 PCA9685? 普通 MCU 的 PWM 通道数量有限(通常 4~8 路),而 PCA9685 用 2 根线就能扩展 16 路 PWM,非常适合多舵机的机器人项目。舵机本身只需要 PWM 信号作为位置指令,不需要持续的 CPU 干预。

引脚资源占用一览​

模块所需引脚数引脚类型
单路蜂鸣器1GPIO
1 个风扇(L9110H)2PWM × 2
2 个风扇(L9110H)4PWM × 4
1 个外置 RGB LED3GPIO 或 PWM × 3
1 个舵机(通过 PCA9685)0(占用 I²C 的 2 根总线)I²C 共享
16 个舵机(通过 1 个 PCA9685)0(仍只占用 I²C 的 2 根总线)I²C 共享

核心能力​

  • 嵌套深度 16 层:子程可以调用子程,最多 16 层
  • 支持递归:子程可以调用自己
  • 空行默认 00:未写的行不是"空",而是 00 0000 0000,程序会按顺序执行并穿过它

📐 核心原则:三条铁律​

规则说明
① 子程入口只做一件事每个子程从第一行开始就是逻辑,不要让"返回点"之后还能掉到其他子程
② 每条逻辑路径都必须以 FH/ZY/JS 结尾子程内部无论走哪条分支,最终都要碰到 FH/ZY/JS 之一
③ 子程之间不要连续两个子程之间保留缓冲空间(默认的 00 行即可),方便未来扩展

🏗️ 架构一:分层设计​

把行号空间分成三层,像"图书馆"一样分类存放。

建议分区​

000 ~ 01F  →  主程序层  (控制流程、决策、调用子程)
020 ~ 07F → 原子操作层 (频繁调用的短子程,每件只做一件事)
080 ~ 0FF → 功能模块层 (完整功能模块,可以调用原子层)

为什么要分层?​

好处说明
主程序一眼看懂000-03F 只有"调用谁、跳到哪",逻辑一目了然
修改一处,全局生效改进"延时子程",所有用到它的地方都自动受益
空间不足时可替换某段功能用不上了,可以直接覆盖重写,不影响其他模块
预留扩展空间每层之间留空行,后加新功能不需要挪动已有代码

📚 架构二:原子操作库(020-07F)​

把最常用的操作写成"单行/几行"的子程。这些是你的"标准库函数"。

示例:LED 控制子程​

040  CD  0000  0000   ; 子程040:LED全灭
041 FH 0000 0000 ; 返回

048 CD 00FF FFFF ; 子程048:LED全亮
049 FH 0000 0000

050 FZ 002A 0080 ; 子程050:设置PWM默认值
051 FZ 002B 0080
052 FZ 002C 0080
053 FH 0000 0000

示例:延时子程​

060  YS  03E8  0000   ; 子程060:长延时(约1秒)
061 FH 0000 0000

068 YS 000A 0000 ; 子程068:短延时(约40ms)
069 FH 0000 0000

使用原子库后,主程序变得极简​

005  DY  0048  0000   ; LED全亮(目标地址写在P-0)
006 DY 0060 0000 ; 等1秒
007 DY 0040 0000 ; LED全灭
008 DY 0060 0000 ; 等1秒
009 ZY 0000 0005 ; 循环(ZY的目标地址在P-1)

📝 技巧三:参数寄存器约定​

这是让子程真正强大的关键。约定某些寄存器专门用来传递参数,调用前先写参数,子程去读。

建议约定(可自己调整)​

**R20** = 延时参数     调用前写入,子程用它决定延多久
**R21** = 显示模式 0=正常,1=报警,2=闪烁
**R22** = 目标寄存器 子程操作哪个寄存器
**R23** = 目标值 写入/比较的值

通用延时子程示例​

; 主程序
005 FZ 0020 01F4 ; 先写参数:R20 = 500ms
006 DY 0060 0000 ; 调用延时子程

010 FZ 0020 07D0 ; 换个参数:R20 = 2秒
011 DY 0060 0000 ; 同一个子程!效果不同

核心思想:子程不需要知道"为什么延时",只负责"按约定位置的值去做"。你改的是参数,不是子程代码。


🔄 技巧四:递归编程(16 层深度)​

既然支持递归(子程可以调用自己)且有 16 层嵌套深度,可以实现真正的递归算法。

示例:递归闪烁 N 次​

; 主程序
000 FZ 0020 0005 ; R20 = 闪烁5次(递归计数器)
001 DY 0010 0000 ; 调用"闪烁"子程
002 JS 0000 0000

; 子程010:递归闪烁(R20为剩余次数)
010 DYZ 0020 0000 ; 如果 R20 > 0,继续执行
011 ZY 0000 0020 ; 否则跳020(不做事直接返回)

012 CD 00FF FFFF ; 点亮LED
013 YS 01F4 0000 ; 延时
014 CD 0000 0000 ; 熄灭
015 YS 01F4 0000 ; 延时
016 XDZ 0020 0001 ; R20 = R20 - 1(次数-1)
017 DY 0010 0000 ; ← 自己调用自己!递归
018 FH 0000 0000

020 FH 0000 0000 ; 递归终止:返回

执行流程(当 R20=5 时)​

调用栈深度变化:

0层: 主程序 → DY 010
1层: 010 → 检查 5>0 → 亮灭一次 → R20=4 → DY 010
2层: 010 → 检查 4>0 → 亮灭一次 → R20=3 → DY 010
3层: 010 → 检查 3>0 → 亮灭一次 → R20=2 → DY 010
4层: 010 → 检查 2>0 → 亮灭一次 → R20=1 → DY 010
5层: 010 → 检查 1>0 → 亮灭一次 → R20=0 → DY 010
6层: 010 → 检查 0=0 → 跳020 → FH 返回
← 逐层返回:5层FH→4层FH→...→1层FH→主程序

只要计数器值不超过 15,就不会超嵌套深度。


🛡️ 技巧五:子程"防溜"防护​

最常见的 bug:子程返回后,程序按顺序"溜"进下一段代码,导致意外执行。

反面教材(有 bug)​

010  DY  0015  0000   ; 子程010:调用015(目标地址P-0)
; ← 没有FH!返回后到011,然后顺着溜下去
011 00 0000 0000 ; 空行(默认00)
...
015 15 1101 0001 ; ← 会被执行两次!
016 FH 0000 0000

正面教材(正确写法)​

010  DY  0015  0000   ; 子程010:调用015
011 FH 0000 0000 ; ← 必须以FH/ZY/JS结尾!
; 012 以后的代码不会被"正常路径"走到

015 15 1101 0001 ; 子程015
016 FH 0000 0000 ; ← 必须以FH/ZY/JS结尾!

保险杠写法(更安全)​

010  DY  0015  0000
011 FH 0000 0000 ; 正常返回
012 JS 0000 0000 ; ← 保险杠:万一走到这里,直接停
013 JS 0000 0000
014 JS 0000 0000

015 15 1101 0001
016 FH 0000 0000
017 JS 0000 0000 ; ← 保险杠

📊 综合示例:完整架构​

把以上所有技巧结合起来的完整程序。

主程序层(000-01F)​

000  FZ  0020  0000   ; 初始化状态寄存器
001 FZ 0021 0001 ; 方向寄存器:1=正向

010 DY 0080 0000 ; 调用"读取传感器"子程
011 DY 00A0 0000 ; 调用"显示当前状态"子程
012 DY 00C0 0000 ; 调用"判断是否报警"子程
013 DY 0060 0000 ; 调用"延时"子程
014 ZY 0000 0010 ; 循环

01F JS 0000 0000 ; 冗余停机(永远走不到,但放一个更安心)

原子操作库(040-07F)​

040  CD  0000  0000   ; 子程040:清LED
041 FH 0000 0000

048 CD 00FF FFFF ; 子程048:点亮LED(白色全亮)
049 FH 0000 0000

050 CD 00FF 0000 ; 子程050:报警LED(闪红光)
051 YS 00FF 0000
052 CD 0000 0000
053 YS 00FF 0000
054 FH 0000 0000

060 FZ 0020 03E8 ; 子程060:延时(R20控制时长)
061 YS (R20) 0000
062 FH 0000 0000

功能模块层(080-0FF)​

080  AD  0000  0010   ; 子程080:读取传感器,结果存R10
081 FH 0000 0000

0A0 AD 0000 0010 ; 子程0A0:根据R10的值显示
0A1 JT 00FF (R10)
0A2 FH 0000 0000

0C0 DYZ 0010 0032 ; 子程0C0:R10 > 50 则报警
0C1 DY 0050 0000 ; 是 → 调用报警子程
0C2 FH 0000 0000
0C3 DY 0048 0000 ; 否 → 正常显示
0C4 FH 0000 0000

💡 进阶:条件前置 vs 条件后置​

两种把子程结合条件判断的写法,各有优势。

写法A:条件前置(传统写法)​

; 主程序里判断,判断完了才调用
010 DYZ 0010 0032 ; 主程序先判断:R10>50?
011 DY 0050 0000 ; 是 → 调用报警
012 ZY 0000 0014 ; 跳过正常分支
013 DY 0048 0000 ; 否 → 调用正常显示
014 ...

特点:主程序要操心"判断逻辑",代码分散。

写法B:条件后置(子程封装,推荐)​

; 主程序只管调用,判断放在子程内部
010 DY 00C0 0000 ; 调用"智能显示"子程
011 ...

; 子程0C0:自己判断该怎么显示
0C0 DYZ 0010 0032 ; 子程内部先判断条件
0C1 ZY 0000 00C4 ; >50 跳报警分支
0C2 DY 0048 0000 ; 否则正常显示
0C3 FH 0000 0000 ; ← 返回
0C4 DY 0050 0000 ; 报警分支
0C5 FH 0000 0000

特点:主程序永远干净。判断逻辑藏在子程里,修改判断条件时主程序不动。这是大型程序推荐的写法。


📋 快速检查表​

写完代码后,对照以下项目自查:

检查项说明没问题打勾
每个子程最后一行是 FH/ZY/JS 吗?防止程序"溜"进下一段☐
主程序是不是只剩 DY/ZY/JS?主程序应该是"调用清单"☐
计数器(递归深度)不超过 15 吗?嵌套最多16层,1层留给主程序☐
用到的寄存器有没有约定用途?避免两个子程用同一个寄存器存不同东西☐
子程之间有缓冲行吗?默认的 00 行就是缓冲☐
DY 的目标地址写在 P-0,ZY 的目标地址写在 P-1 吗?DY=P-0,ZY=P-1,FH/JT 不需要目标地址☐

🎯 最终目标​

当你把代码写成下面这个样子时,就完全掌握这套架构了:

; 主程序(一眼看懂整个程序在做什么)
000 DY 0080 0000 ; 初始化(DY目标地址在P-0)
001 DY 0090 0000 ; 读输入
002 DY 00A0 0000 ; 做决策
003 DY 00B0 0000 ; 输出结果
004 DY 00C0 0000 ; 延时
005 ZY 0000 0001 ; 循环(ZY目标地址在P-1)

; ↓ 具体怎么实现,全部藏在子程里

主程序变成了"配置清单",你写的不是代码,而是"调用哪些功能"的目录。三个月后回来看,仍然一眼就能看懂整个程序的意图。


🌟 综合范例:智能环境监测系统​

以下是一个完整的综合范例,结合多种输入(温度、声音、按钮)和多种输出(外置 RGB LED、L9110H 小风扇、IO 蜂鸣器、PCA9685 舵机),展示如何用分层架构实现一个"智能房间环境监测系统"。

功能描述​

功能触发条件执行动作
温度监测R2E > 阈值1(如 30°C)启动小风扇(L9110H)+ RGB LED 显示红色
温度报警R2E > 阈值2(如 40°C)风扇全速 + IO 蜂鸣器"嘀嘀"报警
环境亮度模拟输入(ADC通道0)< 阈值外置 RGB LED 显示暖白色(R2A/R2B/R2C 三路 PWM)
按钮控制按下按钮(R3E = 0001)切换手动/自动模式 + 舵机转 90° 打开窗帘
噪音提示模拟输入(ADC通道1)> 阈值RGB LED 快速蓝色闪烁一次

硬件接线约定​

; PWM 引脚分配(R2A-R2D 分别接不同外设):
; R2A → 外置 RGB LED 的 R 通道(PWM 调光)
; R2B → 外置 RGB LED 的 G 通道(PWM 调光)
; R2C → 外置 RGB LED 的 B 通道(PWM 调光)
; R2D → 备用(可接其他 PWM 设备)
;
; L9110H 风扇驱动(2 个 PWM 引脚):
; GPIO 位0 (A-IA) → 风扇正转速度(通过 PWM 占空比控制)
; GPIO 位1 (A-IB) → 风扇反转速度(本示例只用正转,所以固定为 0)
;
; 蜂鸣器:
; GPIO 位2 → IO 控制蜂鸣器(高低切换发声)
;
; PCA9685 舵机(通过 I²C,不占用额外 GPIO 引脚):
; 通道0 → 窗帘舵机,0°=关闭,90°=打开

参数寄存器约定​

R20 = 温度低阈值(如 30°C 对应值)
R21 = 温度高阈值(如 40°C 对应值)
R22 = 亮度低阈值(ADC通道0)
R23 = 噪音阈值(ADC通道1)
R24 = 运行模式(0=自动,1=手动)
R25 = 临时存储 / 状态标志

完整程序(助记符形式)​

主程序层(000-01F):只做调度​

000  DY  0080  0000   ; 初始化:设置参数默认值
001 DY 0085 0000 ; 读取所有传感器
002 DY 0090 0000 ; 根据传感器值做决策
003 DY 00A0 0000 ; 执行输出动作
004 DY 00C0 0000 ; 延时等待
005 ZY 0000 0001 ; 回到 001,循环监测

初始化子程(080-084)​

080  FZ  0020  1E00   ; 温度低阈值 = 0x1E00(约30°C)
081 FZ 0021 2800 ; 温度高阈值 = 0x2800(约40°C)
082 FZ 0022 0500 ; 亮度低阈值 = 0x0500
083 FZ 0023 0A00 ; 噪音阈值 = 0x0A00
084 FH 0000 0000 ; 返回

读取传感器子程(085-08F)​

; 读模拟输入通道0(亮度/光敏),结果存到R2A
085 AD 0000 002A ; ADC通道0 → R2A

; 读模拟输入通道1(声音),结果存到R2B
086 AD 0001 002B ; ADC通道1 → R2B

; 复制温度值(R2E)到R2C,方便比较
087 JFZ 002C 002E ; R2C = R2E(温度)

; 复制按钮状态(R3E)到R25
088 JFZ 0025 003E ; R25 = R3E(按钮)

089 FH 0000 0000 ; 返回

决策逻辑子程(090-09F):条件后置模式​

; 检查按钮是否按下 → 切换模式
090 DYZ 0025 0001 ; R25(按钮) > 0 ?
091 ZY 0000 093 ; 未按下 → 跳过切换
092 XDZ 0024 0001 ; 按下 → R24 = 1 - R24(翻转)
093 XDZ 0025 0001 ; 清按钮标志,避免重复触发

; 检查温度 → 决定风扇状态
094 DYZ 002C 0020 ; 温度 > 低阈值 ?
095 DY 00B0 0000 ; 是 → 开风扇处理
096 DY 00B5 0000 ; 否 → 关风扇处理

; 检查亮度 → 决定灯光
097 DYZ 0022 002A ; 阈值 > 亮度读数 ?(即环境太暗)
098 DY 00BA 0000 ; 是 → 开灯
099 DY 00BF 0000 ; 否 → 关灯

; 检查噪音 → 闪烁提示
09A DYZ 002B 0023 ; 声音 > 噪音阈值 ?
09B DY 00C5 0000 ; 是 → 闪烁提示
09C FH 0000 0000 ; 否 → 返回

输出动作子程(0A0-0DF)​

; ===== 温度相关(0B0-0B9)=====
; 说明:风扇用 L9110H 驱动,A-IA=GPIO位0(PWM调速),A-IB=GPIO位1(方向)
; 本示例只用正转,所以 A-IB 始终为 0

0B0 DYZ 002C 0021 ; 温度 > 高阈值 ?(严重过热)
0B1 ZY 0000 0B4 ; 是 → 跳到严重报警
0B2 FZ 002A 01F4 ; 否 → 风扇半速(PWM=50%),通过调整 R2A(最大 03E8=100%)输出占空比
0B3 FH 0000 0000 ; 返回
0B4 FZ 002A 03E8 ; 严重:风扇全速
0B5 DY 00D0 0000 ; 调用蜂鸣器报警子程
0B6 FH 0000 0000 ; 返回

0B7 FZ 002A 0000 ; 温度不高:关闭风扇
0B8 FH 0000 0000 ; 返回

; ===== 灯光相关(0BA-0C1)=====
; 说明:外置 RGB LED 用 R2A(R)/R2B(G)/R2C(B) 三路 PWM 控制颜色亮度

0BA FZ 002A 03E8 ; R 通道 = 最亮(暖白色:红+绿,蓝稍暗)
0BB FZ 002B 03E8 ; G 通道 = 最亮
0BC FZ 002C 0320 ; B 通道 = 约80%(让光偏暖)
0BD FH 0000 0000 ; 返回

0BE FZ 002A 0000 ; 关灯:三路 PWM 全部归零
0BF FZ 002B 0000
0C0 FZ 002C 0000
0C1 FH 0000 0000 ; 返回

; ===== 噪音提示(0C2-0C9)=====

0C2 FZ 002A 0000 ; R = 灭
0C3 FZ 002B 0000 ; G = 灭
0C4 FZ 002C 03E8 ; B = 最亮 → 蓝色闪烁
0C5 YS 0100 0000 ; 延时约250ms
0C6 FZ 002C 0000 ; 蓝 = 灭
0C7 YS 0100 0000 ; 再等一下
0C8 FH 0000 0000 ; 返回

; ===== 通用延时(0C9-0CD)=====

0C9 YS 01F4 0000 ; 主循环延时约 500ms
0CA FH 0000 0000 ; 返回

; ===== 蜂鸣器报警(0D0-0DB)=====
; 说明:IO 蜂鸣器接 GPIO 位2,低电平发声。连续"嘀嘀嘀"三声

0D0 JT 00FF 0004 ; GPIO位2 = 低 → 蜂鸣器响
0D1 YS 0032 0000 ; 响 50ms
0D2 JT 00FF 0000 ; GPIO位2 = 高 → 停
0D3 YS 0064 0000 ; 间隔 100ms
0D4 JT 00FF 0004 ; 第二声
0D5 YS 0032 0000
0D6 JT 00FF 0000
0D7 YS 0064 0000
0D8 JT 00FF 0004 ; 第三声
0D9 YS 0032 0000
0DA JT 00FF 0000
0DB FH 0000 0000 ; 报警完毕,返回

架构解读​

上面这段代码展示了以下关键技巧:

  1. 主程序极简(000-005):只有 6 行,一眼看懂整个系统在做什么
  2. 条件后置:子程内部自己判断是否需要执行(如 094-09C),主程序不用操心
  3. 模块化分层:每个功能有独立的子程,修改一处不影响其他
  4. 参数寄存器约定:R20-R25 全部用于参数传递,子程之间不需要"重新读一次"
  5. 清晰的行号分区:080-084=初始化、085-089=读传感器、090+=决策输出
  6. 多种硬件灵活控制:L9110H 风扇用 PWM 调速、RGB LED 用三路 PWM 混色、蜂鸣器用 IO 翻转发声、舵机用 PCA9685 的 I²C 扩展

精简版(实际可运行的紧凑代码)​

如果硬件资源有限,可以写成下面这种更紧凑的版本(保留核心架构):

; 主程序
000 DY 0080 0000 ; 初始化
001 AD 0000 002A ; 读亮度 → R2A
002 AD 0001 002B ; 读声音 → R2B
003 JFZ 002C 002E ; 读温度 → R2C
004 DY 0090 0000 ; 决策与输出
005 YS 03E8 0000 ; 延时1秒
006 ZY 0000 001 ; 循环

; 初始化
080 FZ 0020 1E00 ; 温度阈值1
081 FZ 0021 2800 ; 温度阈值2
082 FZ 0022 0500 ; 亮度阈值
083 FH 0000 0000 ; 返回

; 决策与输出(条件后置,全都写在一起)
090 DYZ 002C 0020 ; 温度 > 阈值1 ?
091 FZ 002A 01F4 ; 是 → 风扇半速(PWM 50%)
092 DYZ 0022 002A ; 太暗 ?
093 FZ 002B 03E8 ; 是 → 绿灯亮(环境照明)
094 FZ 002B 0000 ; 否 → 绿灯灭
095 FH 0000 0000 ; 返回主程序