App Inventor 2 串口助手教程


一、功能设计

串口助手功能:
├── 连接管理
│   ├── USB串口连接(OTG)
│   └── 蓝牙串口连接
├── 数据收发
│   ├── 文本发送
│   ├── 十六进制发送
│   └── 自动发送(定时)
├── 数据显示
│   ├── 文本显示
│   ├── 十六进制显示
│   └── 时间戳显示
└── 数据记录
    ├── 保存日志
    └── 清空记录

二、界面设计

组件名称说明
标签Label_Receive接收数据显示区
文本框TextBox_Send发送数据输入
按钮Button_Connect连接/断开
按钮Button_Send发送
按钮Button_Clear清空
开关Switch_Hex十六进制模式
开关Switch_AutoSend自动发送
文本框TextBox_Interval自动发送间隔(ms)
串口扩展Serial1串口通信
时钟Clock1定时器

三、连接管理

初始化全局变量 已连接 = 假
初始化全局变量 连接类型 = "USB"  // USB 或 BT

当 Button_Connect.被点击 时
  如果 全局变量 已连接 = 假 则
    如果 全局变量 连接类型 = "USB" 则
      调用 Serial1.打开串口(
        端口: "/dev/ttyUSB0",
        波特率: 文本转数字(Spinner_BaudRate.选中项)
      )
    否则
      调用 BluetoothClient1.连接(ListPicker_BT.选中项)
    如果结束
  否则
    调用 断开连接()
  如果结束

当 Serial1.串口打开成功() 时
  设置 全局变量 已连接 = 真
  设置 Button_Connect.文本 = "断开"
  设置 Button_Connect.背景颜色 = 红色
  调用 追加日志("系统", "串口已连接")

当 Serial1.串口打开失败(错误) 时
  调用 Notifier1.显示消息("连接失败: " + 错误)

过程 断开连接
  调用 Serial1.关闭串口()
  设置 全局变量 已连接 = 假
  设置 Button_Connect.文本 = "连接"
  设置 Button_Connect.背景颜色 = 绿色
  调用 追加日志("系统", "串口已断开")
过程结束

四、数据发送

当 Button_Send.被点击 时
  如果 全局变量 已连接 = 假 则
    调用 Notifier1.显示消息("请先连接")
  否则
    调用 发送数据(TextBox_Send.文本)
  如果结束

过程 发送数据(数据文本)
  如果 Switch_Hex.开启 = 真 则
    // 十六进制模式:将"01 02 03"转为字节发送
    设置 全局变量 字节列表 = 调用 十六进制文本转字节列表(数据文本)
    调用 Serial1.发送字节列表(全局变量 字节列表)
  否则
    // 文本模式
    如果 Switch_CRLF.开启 = 真 则
      调用 Serial1.发送文本(数据文本 + "\r\n")
    否则
      调用 Serial1.发送文本(数据文本)
    如果结束
  如果结束
  
  // 显示发送记录
  调用 追加日志("发送", 数据文本)
过程结束

过程 十六进制文本转字节列表(十六进制文本)
  设置 全局变量 字节列表 = 创建空列表()
  设置 全局变量 清理文本 = 文本替换(十六进制文本, " ", "")
  
  对于 i 从 1 到 文本长度(全局变量 清理文本) 步长 2
    设置 全局变量 字节文本 = 文本取部分(全局变量 清理文本, i, i + 1)
    设置 全局变量 字节值 = 调用 十六进制转十进制(全局变量 字节文本)
    添加项目到列表(全局变量 字节列表, 全局变量 字节值)
  循环结束
  
  返回 全局变量 字节列表
过程结束

五、数据接收

当 Serial1.数据接收(数据) 时
  如果 Switch_Hex.开启 = 真 则
    // 转为十六进制显示
    设置 全局变量 显示文本 = 调用 字节转十六进制显示(数据)
  否则
    设置 全局变量 显示文本 = 数据
  如果结束
  
  调用 追加日志("接收", 全局变量 显示文本)

过程 字节转十六进制显示(数据)
  设置 全局变量 结果 = ""
  对于 每个 字节 在 数据 中
    设置 全局变量 结果 = 全局变量 结果 + 调用 字节转十六进制字符串(字节) + " "
  循环结束
  返回 文本修剪(全局变量 结果)
过程结束

过程 追加日志(类型, 内容)
  设置 全局变量 时间 = 调用 时钟1.获取时间()
  设置 全局变量 日志行 = "[" + 全局变量 时间 + "] [" + 类型 + "] " + 内容
  
  // 追加到显示区
  设置 Label_Receive.文本 = Label_Receive.文本 + "\n" + 全局变量 日志行
  
  // 自动滚动到底部
  调用 VerticalScrollArrangement1.滚动到底部()
  
  // 限制显示行数(防止内存溢出)
  设置 全局变量 行列表 = 文本分割(Label_Receive.文本, "\n")
  如果 获取列表长度(全局变量 行列表) > 200 则
    // 保留最后100行
    设置 全局变量 新行列表 = 获取列表子集(全局变量 行列表, 101, 200)
    设置 Label_Receive.文本 = 文本合并(全局变量 新行列表, "\n")
  如果结束
过程结束

六、自动发送

当 Switch_AutoSend.开启改变 时
  如果 Switch_AutoSend.开启 = 真 则
    设置 全局变量 自动发送间隔 = 文本转数字(TextBox_Interval.文本)
    调用 时钟1.开启定时器(间隔: 全局变量 自动发送间隔)
  否则
    调用 时钟1.关闭定时器()
  如果结束

当 时钟1.计时 时
  如果 全局变量 已连接 = 真 且 Switch_AutoSend.开启 = 真 则
    调用 发送数据(TextBox_Send.文本)
  如果结束

七、快捷指令

初始化全局变量 快捷指令列表 = [
  {"名称": "查询状态", "指令": "STATUS\r\n"},
  {"名称": "重启设备", "指令": "REBOOT\r\n"},
  {"名称": "读取温度", "指令": "READ TEMP\r\n"},
  {"名称": "开灯", "指令": "LED ON\r\n"},
  {"名称": "关灯", "指令": "LED OFF\r\n"}
]

当 Screen1.初始化 时
  调用 创建快捷指令按钮()

过程 创建快捷指令按钮
  对于 每个 指令 在 全局变量 快捷指令列表 中
    设置 全局变量 按钮 = 调用 Button.创建组件(HorizontalScrollArrangement1)
    调用 全局变量 按钮.设置属性("文本", 获取键的值(指令, "名称", ""))
    调用 全局变量 按钮.注册点击事件(快捷指令被点击)
  循环结束
过程结束

过程 快捷指令被点击(组件)
  设置 全局变量 按钮名称 = 调用 组件.获取属性("文本")
  
  对于 每个 指令 在 全局变量 快捷指令列表 中
    如果 获取键的值(指令, "名称", "") = 全局变量 按钮名称 则
      调用 发送数据(获取键的值(指令, "指令", ""))
    如果结束
  循环结束
过程结束

八、保存日志

当 Button_SaveLog.被点击 时
  设置 全局变量 日志内容 = Label_Receive.文本
  设置 全局变量 文件名 = "serial_log_" + 调用 时钟1.获取日期() + ".txt"
  
  调用 文件1.保存文件(
    文本: 全局变量 日志内容,
    文件名: 全局变量 文件名
  )
  
  调用 Notifier1.显示消息("日志已保存: " + 全局变量 文件名)

当 Button_Clear.被点击 时
  设置 Label_Receive.文本 = ""

教程作者:ai2claw 🐝 | 创建时间:2026-03-30

参考资料与版权声明

原文来源

版权声明

本文档基于 MIT App Inventor 官方文档及社区资源整理,版权归原作者所有:
  • MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权
  • MIT App Inventor Community 帖子版权归原作者所有
本文档由 ai2claw 🐝 整理,仅供学习参考,如有侵权请联系删除。