把玩arduino UNO MOUSE
整体分析
一千多行的代码,一个完整的arduino uno DIY
这是一个为 Arduino Uno 设计的完整项目,名为 UNO MOUSE v0.1,它实现了一个基于 TVout 视频输出与 PS2 键盘输入的 交互式编程环境,支持一种名为 MOUSE 的极小栈式编程语言,并内置图形绘制功能。

📌 程序总体功能
UNO_MOUSE 是一个 迷你图形解释器和代码编辑器,集成了:
TV 输出:通过 TVout 库输出图形/文本。
PS2 键盘输入:使用 PS2uartKeyboard。
命令行交互和解释执行。
栈式语言解释器,支持自定义命令、宏定义、嵌套结构等。
EEPROM 存储程序行与宏地址,实现断电保存。
图形绘制:点、线、圆、矩形、三角形(可填充)。
特殊命令处理(循环、跳转、宏等)。
系统命令支持:SAV, ERS, RUN, TEST, RST, FREERAM
📂 结构概览
| 模块 | 内容 |
|---|---|
| 自定义函数 | my_isdigit, my_itoa, my_strlen_P 等,为节省资源做优化替代。 |
| 全局常量 | 屏幕设置、EEPROM 地址、栈/宏参数等常量定义。 |
| 解释器核心 | 栈结构 stack[]、变量表 vars[]、调用栈、fill 标志等执行核心。 |
| 命令实现 | 算术操作、变量处理、输入输出控制、图形绘制等命令实现。 |
| 辅助功能 | 音效控制、光标闪烁、程序加载、EEPROM 读写等增强功能。 |
| 主逻辑 | setup() 初始化显示与键盘,loop() 实现命令行编辑器与程序执行逻辑。 |
🧠 程序流程简述
setup() 初始化流程:
初始化 TV 输出(128×96,NTSC,font4x6)。
显示欢迎界面:UNO MOUSE + “Press Any Key...”。
等待用户按键或超时 30 秒。
播放欢迎音,载入 EEPROM 中的当前行数据。
loop() 主循环逻辑:
如果不是运行状态(flags.running == 0),执行光标闪烁。
接收并解析 PS2 键盘输入,处理:
文本插入/删除(编辑器功能)。
上/下/左/右移动。
回车执行命令:
RUN:运行当前 EEPROM 中的程序。
TEST:加载内置测试程序。
SAV / ERS:保存/清除 EEPROM。
FREERAM:显示剩余内存。
RST:软复位。
否则保存当前行,跳转到下一行。
runProgram() 执行解释器:
初始化栈、变量、fill 标志。
扫描宏定义(以 $A ~ $Z 标识)。
按行从 EEPROM 加载,逐字符解释执行:
操作数压栈。
执行内置命令(如 +, *, C, L, F, E, T 等图形指令)。
控制结构:[, ], (, ), ^, #A(宏调用),@(返回)。
字符串显示("text")、输出(!)、输入(?)等。
程序结束后输出栈和提示,等待按键。
🔢 支持的 MOUSE 语言命令(部分)
| 字符 | 含义 |
|---|---|
+ - * / \ |
算术运算(使用栈顶两项) |
= |
变量赋值(使用两个栈值:变量索引和值) |
. |
变量读取(变量索引压栈) |
! |
输出栈顶整数 |
? |
输入整数入栈 |
C, L, R, P, T |
圆、线、矩形、点、三角形绘制 |
F |
设置是否填充图形(0=不填充) |
E |
清屏 |
[ ] |
条件分支(条件≤0 时跳过中间部分) |
( ) ^ |
循环结构 |
$A |
宏定义标记 |
#A |
宏调用 |
@ |
返回 |
$$ |
程序结束 |
🧪 内置测试程序(TEST)
测试程序内容:
E ; 清屏
30 40 25 C ; 空心圆
10 15 10 50 40 50 T ; 内部三角形
60 20 40 40 R ; 外部正方形
1 F 70 30 20 20 R ; 内部填充正方形
110 10 110 70 L ; 5 条垂直线
...
$$ ; 结束
RUN
### 💡 总结亮点
- 完整的解释器+代码编辑器。
- 支持 MOUSE 栈语言、宏、控制结构。
- 支持绘图、交互、输入输出。
- 自定义函数优化内存和速度。
- 可作为 Arduino 上的极简“终端语言实验平台”。
🖥️ UNO MOUSE 使用手册 & 入门教程
版本:v0.1(2025-05-20) 作者:Ivan Svarkovsky 平台:Arduino UNO + TVout + PS2 键盘
📦 一、硬件准备
| 模块 | 说明 |
|---|---|
| Arduino UNO | 主控板 |
| TVout 模块 | 视频输出:Pin 7 = Video, Pin 9 = Sync |
| PS2 键盘 | 接入软串口输入 |
| 有源蜂鸣器(可选) | 用于按键/提示音 |
| Micro SD 卡模块(可选) | 未来扩展 |
🧭 二、上电启动流程
- 上电后会显示欢迎界面:
UNO MOUSE
---------
PRESS ANY KEY...
- 按任意键进入主界面(或等待30秒自动进入)。
✍️ 三、界面说明
编辑区:每次显示 16 行,可输入指令或程序代码。
光标闪烁:表示当前位置,按键输入将在此插入字符。
命令行缓冲区:单行最多输入 30 个字符。
🎮 四、键盘操作
⌨️ 键盘功能说明
| 键 | 功能 |
|---|---|
| 上下左右 | 移动光标 / 切换行 |
| ENTER | 执行当前行命令或运行程序 |
| BACKSPACE / DEL | 删除字符 |
| HOME / END | 快速到行首 / 行末 |
| 英文字母 / 数字 / 符号 | 直接输入指令或代码 |
🧪 五、内置命令一览(编辑器命令)
在编辑区输入如下指令,然后回车:
| 指令 | 功能 |
|---|---|
| RUN | 运行 EEPROM 中保存的程序 |
| TEST | 加载内置图形测试程序并运行 |
| SAV | 保存所有编辑行到 EEPROM |
| ERS | 清空 EEPROM 中保存的程序 |
| FREERAM | 显示可用 SRAM |
| RST | 软复位(重启)Arduino |
🧠 六、MOUSE 栈语言指令一览
基本规则: 栈式语言:先将数据入栈,再执行操作符。
每行命令用空格分隔,支持括号、跳转、宏。
📌 操作类命令
🔣 运算与输入输出符号说明
| 符号 | 功能 |
|---|---|
+ - * / \ |
栈顶两个数进行运算 |
= |
赋值:变量名(0=A, 25=Z)和值 |
. |
读取变量值压栈 |
< > |
比较,结果压栈 |
! |
打印栈顶值 |
? |
输入一个整数压栈 |
📌 图形命令(单位:像素)
| 命令 | 参数 | 描述 |
|---|---|---|
| E | 无 | 清屏 |
| F | 1 / 0 | 设置是否填充图形 |
| C | x y r | 画圆 |
| R | x y w h | 矩形 |
| L | x1 y1 x2 y2 | 画线 |
| P | x y | 画点 |
| T | x1 y1 x2 y2 x3 y3 | 三角形(用线连接) |
📌 控制结构
| 符号 | 功能 |
|---|---|
| [ ] | 条件分支:若条件<=0 跳过中间内容 |
| ( ) + ^ | 循环结构 |
| $$ | 程序结束标记 |
| ' | 注释行,忽略 |
| "string" | 显示字符串 |
📌 宏与跳转
| 语法 | 含义 |
|---|---|
$A ~ $Z |
定义宏位置 |
#A ~ #Z |
跳转调用宏 |
@ |
从宏或括号返回 |
🧪 七、示例程序:画图案
在程序中输入:
E
30 40 25 C
10 15 10 50 40 50 T
60 20 40 40 R
1 F 70 30 20 20 R
110 10 110 70 L
112 10 112 70 L
$$
RUN
按 ENTER 运行,即可显示图形图案。
🧰 八、调试功能
! 可随时打印当前值。
{ 开启追踪栈变化,} 关闭。
出现语法错误时,会显示错误行。
🧼 九、清空/恢复
使用 ERS 清除所有程序行。
使用 TEST 重新加载测试程序。
📚 十、进阶建议
用 $A ... 定义函数,#A 调用。
用 [ ] 和 ^ 实现 IF/WHILE 结构。
利用变量 0~25 进行临时存储。
编写宏库(如画十字、对称图形)提升复用性。
🧾 十一、附录:符号说明速查表
| 符号 | 说明 |
|---|---|
| + - * / \ | 算术 |
| = . | 变量赋值/读取 |
| < > | 比较 |
| ! ? | 输出/输入 |
| E R C L P T | 图形 |
| [ ] ( ) ^ | 控制结构 |
| #A $A | 宏调用/定义 |
| @ | 返回 |
| "str" | 输出字符串 |
| ' | 注释 |
| $$ | 结束 |
上机练习入门例子
🟢 示例1:打印 Hello 字样
"HELLO"!
$$
📌说明:
使用 "..." 输出字符串。
! 会输出换行。
$$ 结束程序。
🔢 示例2:输入两个数并输出和
"ENTER FIRST NUM:"
?
"ENTER SECOND NUM:"
?
"SUM IS: "
+ !
$$
📌说明:
? 输入值,两个压栈。
- 求和。
! 打印结果。
🧪 例: 用户输入 3 和 5,输出:
8
📐 示例3:画一个空心矩形
E
20 20 60 30 R
$$
📌说明:
E 清屏。
R 参数为:x y 宽 高。
🔄 示例4:循环打印 0~9
0 A =
(
A . " " !
A . 10 < ^
A A . 1 + =
)
$$
📌说明:
A 是变量 0(0=A, 25=Z)。
= 给 A 赋值。
() 是条件分支,判断是否继续。
. 获取变量值,压栈。
! 打印栈顶。
🧪 输出:
0
1
2
...
9
⭕ 示例5:画一个圆并打印半径
E
40 40 20 C
20 !
$$
📌说明:
40 40 20 是圆心和半径。
C 画圆。
! 打印半径(20)。
🎨 示例6:画一个填充矩形
1 F
30 30 40 20 R
$$
📌说明:
F 设置填充标志(1=填充,0=空心)。
R 使用填充绘制。
🔺 示例7:画三角形
E
10 10 60 10 35 50 T
$$
📌说明:
T 指令绘制三角形。
参数:x1 y1 x2 y2 x3 y3
📈 示例8:画垂直柱状图
E
10 70 10 30 L
20 70 20 40 L
30 70 30 20 L
40 70 40 50 L
$$
📌说明:
多条竖线模拟柱状图。
- L:画线,x1 y1 x2 y2。
🧠 示例9:变量赋值与比较
10 A =
5 B =
A . ! B . ! A . B . > !
$$
📌说明:
赋值 A=10, B=5
分别打印 A 和 B
比较 A > B,结果为 1(true)
💾 示例10:定义宏并调用
$A
"IN MACRO A"!
@
"START"!
#A
"END"!
$$
📌说明:
$A:定义宏 A 开始位置。
@:从宏返回。
A:调用宏 A。
🧪 输出:
START
IN MACRO A
END
✅ 小技巧: 变量:A 是 0,B 是 1,依此类推到 Z(25)。
可以写注释:以 ' 开头。
字符串中可以用 ! 换行,如 "HELLO!WORLD"!
F 填充标志影响 C/R 图形绘制。
所有数字/变量都通过栈传递!

评论