手机串口调试助手:USB OTG 收发文本与十六进制、定时发送(附 .aia 源码)

串口调试助手:手机通过 OTG 线接 USB 转串口模块,像电脑上的串口助手一样收发数据。

下载 SerialAssistant.aia 返回搜索需求专题

这一篇回答的搜索:appinventor 串口通信、串口组件打开串口怎么用、读取串口、接收串口、制作串口调试 APP、串口连接程序、串口外部扩展、用 App Inventor 做 USB 调试工具。

界面

串口调试助手界面布局预览

图为由最终 .aia 生成的布局预览(接收区内容为示例),不是真机截图。

怎么用

器材:支持 OTG 的安卓手机、OTG 转接头、USB 转 TTL 串口模块(CH340 / CP2102 / FT232 / PL2303 均可),或者直接接 Arduino 开发板的 USB 口。

  1. 打开串口:选波特率(与设备一致,Arduino 常用 9600 或 115200),点「打开串口」。第一次会弹出 USB 授权框,点「确定」后再点一次打开。
    中途验证:标题栏变成「已打开 115200」,按钮变红色「关闭串口」。
  2. 接收:设备发来的数据实时出现在黑色接收区,右上角统计收发字节数。打开「HEX 显示」看原始字节,「暂停接收」时只计数不刷新。
    中途验证:Arduino 里 Serial.println("hello"),接收区每次多一行 hello。
  3. 发送:输入框写指令,行尾选 \r\n(AT 指令要求)、\n 或「无」,点「发送」。打开「HEX 发送」可以发 01 03 00 00 00 01 这样的 Modbus 指令。
  4. 定时发送 / 快捷指令:打开「定时发送」按间隔(≥50 毫秒)重复发送输入框内容;三个快捷按钮点一下就发,长按把输入框内容存到这个按钮上。
  5. 保存:「保存并分享」把接收区存成 txt 文件(App 专属目录,不需要存储权限),写完直接弹出分享。

核心代码

打开串口并轮询接收

串口通信器没有收到数据的事件,要用计时器定时调用 ReadBytes:没有数据时返回空列表,不会卡住。打开前要先 InitializeSerial,波特率在打开前设置。

when 按钮_打开.Click() {
  if not (串口通信器1.IsInitialized) {
    串口通信器1.InitializeSerial()
  }
  串口通信器1.BaudRate = 下拉框_波特率.Selection
  if 串口通信器1.OpenSerial() {
    计时器_接收.TimerEnabled = true
    标签_串口状态.Text = join("已打开 ", 串口通信器1.BaudRate)
  } else {
    标签_串口状态.Text = "打开失败:检查 OTG 线,并在 USB 授权框里点确定"
  }
}

when 计时器_接收.Timer() {
  if 串口通信器1.IsOpen {
    var 字节 = 串口通信器1.ReadBytes()
    if length(字节) > 0 {
      标签_接收.Text = join(标签_接收.Text, 字节转文本(字节))
    }
  }
}

function 字节转文本(字节列表) {
  return Web客户端1.UriDecode(拼百分号(字节列表, 1))
}

function 拼百分号(字节列表, 起点) {
  return choose(起点 > length(字节列表), "", join("%", segment("0123456789ABCDEF", floor(字节列表[起点] / 16) + 1, 1), segment("0123456789ABCDEF", 字节列表[起点] % 16 + 1, 1), 拼百分号(字节列表, 起点 + 1)))
}

ReadSerial 也能直接读成文本,但它按缓冲区一次读出、遇到半个中文字符会出乱码;读字节再统一转换更可控,还能随时切换成 HEX 显示。拼百分号 用递归把每个字节变成 %E4 这样的两位十六进制,交给 UriDecode 按 UTF-8 还原。

发送:文本 + 行尾、十六进制

ai2-blocks 字符串里写不出回车符 \r,所以行尾用字节补发:\r\n 就是 [13, 10]。

when 按钮_发送.Click() {
  串口通信器1.WriteSerial(文本输入框_发送.Text)
  if 下拉框_行尾.SelectionIndex == 2 {
    串口通信器1.WriteBytes([10])
  } else if 下拉框_行尾.SelectionIndex == 3 {
    串口通信器1.WriteBytes([13, 10])
  }
}

十六进制发送与 BLE 调试助手里的解析方法完全相同,解析成字节列表后调用 串口通信器1.WriteBytes(字节)。

定时发送与快捷指令

when 开关_定时.Changed() {
  if 开关_定时.On and isnumber(文本输入框_间隔.Text) and 文本输入框_间隔.Text >= 50 {
    计时器_定时.TimerInterval = 文本输入框_间隔.Text
    计时器_定时.TimerEnabled = true
  } else {
    开关_定时.On = false
    计时器_定时.TimerEnabled = false
  }
}

when 计时器_定时.Timer() {
  串口通信器1.WriteSerial(文本输入框_发送.Text)
}

when 按钮_快捷1.LongClick() {
  按钮_快捷1.Text = 文本输入框_发送.Text
  微数据库1.StoreValue("quick1", 文本输入框_发送.Text)
}

when 按钮_快捷1.Click() {
  串口通信器1.WriteSerial(按钮_快捷1.Text)
}

常见问题

现象 原因与处理
点「打开串口」一直失败 ① 手机不支持 OTG 或没打开 OTG 开关(部分手机在设置里,10 分钟不用会自动关);② 第一次要在 USB 授权框里点「确定」,然后再点一次打开;③ 数据线是只能充电的线。
能打开,但收不到数据 波特率不一致(最常见);TX/RX 没交叉接(模块 TX 接设备 RX);没共地(GND 要相连);设备是 3.3V 电平而模块是 5V,或反过来。
收到乱码 先打开「HEX 显示」看原始字节:字节对但文字乱,是设备按 GBK 发中文,改成 UTF-8;字节本身就乱,是波特率不对或电平不匹配。
AT 指令没回复 行尾选 \r\n。ESP8266/ESP32 AT 固件、蓝牙模块 AT 模式都要求以回车换行结尾。
接收区数据断成几截 串口是字节流,一次读到的可能是半帧或多帧。按协议里的帧尾(如换行)在自己的变量里拼接后再解析,可参考 串口设备运行记录 的拆帧写法。
拔掉线后 App 报错 读取失败会触发 Screen1.ErrorOccurred,成品在里面自动关闭串口并停止定时发送,重新插好后再点「打开串口」。
鸿蒙手机能用吗 本成品只验证了 Android 编译;鸿蒙版串口组件能力以 鸿蒙组件文档 为准。

用到的组件

相关教程:串口通信教程 · 十六进制与字节转换 · 浮点数与字节互转

验证范围

最终 .aia 已通过:正式编辑器载入与保存重开 0 错误、后台导入、Android APK 编译,并用替身串口执行了真实积木的 16 项业务检查(打开失败提示、按波特率打开、UTF-8 中文还原、HEX 显示、暂停计数、接收区截断、\r\n 行尾、HEX 发送、定时发送下限、快捷指令保存、保存后分享、拔线出错处理、重启恢复设置)。未接真实 USB 串口设备联调,不同 USB 芯片的驱动兼容性以实测为准。详见验证记录。

文档反馈