Android 车载串口开发笔记:UART、RS232、RS485、串口配置与数据通信

Android 车载串口开发笔记:UART、RS232、RS485、串口配置与数据通信

Android 工控机、车载终端、RK 系列开发板和嵌入式设备经常通过串口连接 PLC、传感器、仪表、控制器等设备。串口开发主要涉及:UART + TTL/RS232/RS485 + 设备节点 + 波特率 + 数据位 + 停止位 + 校验位 + 收发方向 + 数据协议。

典型链路:Android 应用 → 串口驱动 → UART → RS232/RS485 收发器 → 外部设备。

UART

UART(Universal Asynchronous Receiver/Transmitter)负责异步串行数据传输,常见信号为 TX + RX + GND。通信双方需要保持 波特率 + 数据位 + 停止位 + 校验位 一致。

常见配置 9600 8N1 表示:9600 波特率 + 8bit 数据位 + 无校验 + 1bit 停止位。

UART 描述的是串行数据传输方式,不等于 RS232,也不等于 RS485。常见硬件关系:UART + TTL、UART + RS232 收发器、UART + RS485 收发器。

TTL 串口

TTL UART 常见于开发板内部接口,典型接线:TX → RX + RX → TX + GND → GND。常见逻辑电平为 3.3V 和 5V,不同 IO 电平不能默认直接连接。

TTL UART 与 RS232 使用的电气电平不同,不能把普通 TTL UART 直接连接标准 RS232 接口。

RS232

RS232 是串行通信的电气接口标准,常见信号为 TX + RX + GND,使用单端传输,主要用于点对点通信。

可以简单区分为:UART:串行数据传输,RS232:单端物理接口。

设备内部常见链路:CPU UART → RS232 收发器 → RS232 接口。

因此 Android 上操作的通常仍然是 UART,RS232 收发芯片负责完成电平转换。

RS485

RS485 是差分串行通信接口,常见线路为 A + B,部分设备同时提供 GND。相比 RS232,更适合 较长距离 + 工业现场 + 多设备总线。

典型链路:CPU UART → RS485 收发器 → A/B 总线。

RS485 只定义物理层,不定义数据内容。Modbus RTU + 厂商私有协议 + 自定义二进制协议 + ASCII 协议 都可以运行在 RS485 上。

对于 Android 应用,两者在软件层可能没有明显区别。例如开发板把 RS232 和 RS485 分别映射到 /dev/ttyS1 和 /dev/ttyS3,应用仍然操作串口设备节点,差异主要位于 UART 后面的收发电路。

RS485 半双工

常见两线 RS485 使用半双工,发送和接收共用 A/B,总线上同一时间通常只有一个节点发送。

RS485 收发器通常存在 DE(Driver Enable) 和 RE(Receiver Enable),典型收发流程:切换发送模式 → 发送数据 → 等待发送完成 → 切换接收模式。

部分 Android 工控板已经在 Linux 驱动或硬件层实现自动方向控制,应用只负责正常发送和接收数据。部分设备则需要通过 RTS + GPIO + ioctl + 厂商 API 控制 RS485 收发方向。

是否需要手动控制方向需要查看开发板硬件说明和串口驱动实现。

Android 串口设备节点

Android 底层基于 Linux,板载 UART 通常表现为字符设备。常见设备节点:/dev/ttyS0 + /dev/ttyS1 + /dev/ttyS2 + /dev/ttyS3 + /dev/ttyAMA*。

常见含义:/dev/ttyS*:SoC UART 或传统串口,/dev/ttyAMA*:部分 ARM 平台 UART,/dev/ttyUSB*:USB 转串口设备,/dev/ttyACM*:USB CDC ACM 设备。

可以通过:

bash 复制代码
ls /dev/tty*

查看系统当前存在的串口设备,但具体哪个设备节点对应 RS232、RS485,需要以开发板原理图、设备树或厂商文档为准。

例如某块 Android 工控板可能定义:/dev/ttyS1 → RS232,/dev/ttyS3 → RS485。更换设备后这个对应关系可能完全不同。

串口权限

设备节点存在不代表 Android 应用一定可以访问。访问 /dev/ttyS* 同时受 Linux 文件权限 + SELinux 限制。

查看权限:

bash 复制代码
ls -l /dev/ttyS3

没有设备权限时常见错误:

复制代码
Permission denied

开发调试阶段可以临时修改:

bash 复制代码
chmod 666 /dev/ttyS3

正式设备通常通过 ueventd.rc + init.rc + SELinux Policy + 系统应用权限 + 厂商系统配置 处理。

串口权限与 AndroidManifest 中普通的运行时权限不是同一个问题。

串口配置

串口通信双方至少需要确认:Port + Baud Rate + Data Bits + Stop Bits + Parity + Flow Control。

例如:

yaml 复制代码
Port: /dev/ttyS3
Baud Rate: 9600
Data Bits: 8
Stop Bits: 1
Parity: None
Flow Control: None

也可以直接记录为:

bash 复制代码
/dev/ttyS3 9600 8N1

串口开发出现无法通信时,设备节点和这些参数应该先于业务协议检查。

波特率

常见波特率:1200 + 2400 + 4800 + 9600 + 19200 + 38400 + 57600 + 115200 + 460800 + 921600。

工业设备常见:9600 + 19200 + 115200。

双方波特率不一致时常见现象:乱码 + 字节缺失 + 数据长度异常 + CRC 错误 + 完全无法解析。

波特率不是越高越好。线缆长度、现场干扰、收发器性能和硬件设计都会影响可稳定使用的速率。

数据位、校验位、停止位

数据位常见 7bit + 8bit,二进制设备协议基本使用 8bit。

校验位常见:N:None、E:Even、O:Odd。

停止位常见:1bit + 2bit。

因此会看到:8N1 + 8E1 + 8O1 等配置。

9600 8N1 和 9600 8E1 即使波特率相同,也不是相同的串口配置。

流控

常见流控:None + RTS/CTS + XON/XOFF。

普通 RS232、RS485 工业设备多数使用 None。

部分 RS485 实现会借用 RTS 控制 DE/RE,因此看到 RTS 时还需要确认它属于普通硬件流控还是 RS485 方向控制。

串口收发数据

串口最终传输的是字节。ASCII 协议可能表现为:

复制代码
AT+VERSION?\r\n

二进制协议可能表现为:

复制代码
01 03 00 00 00 02 C4 0B

实际项目中串口 API 只需要完成两件事:发送 byte[] + 接收 byte[]。

对于二进制协议,调试日志统一使用 HEX 更方便,例如:

makefile 复制代码
TX: 01 03 00 00 00 02 C4 0B
RX: 01 03 04 00 01 00 02 2A 32

业务层再按照具体协议解析收到的数据。

串口没有数据包边界

串口传输的是连续字节流,不存在 TCP/UDP 那种由 API 保证的数据包概念。

假设设备发送:

复制代码
01 03 04 00 01 00 02 2A 32

应用可能一次收到完整数据,也可能分成:01 03 04、00 01 00 02、2A 32,还可能一次收到当前帧和下一帧。

因此:一次串口回调 ≠ 一帧协议数据。

数据帧边界应该由上层协议确定。

数据分帧

常见协议使用这些方式确定完整数据帧:固定长度 + 帧头/帧尾 + 长度字段 + 功能码 + 时间间隔 + CRC。

自定义协议例如:

objectivec 复制代码
AA 55 | LEN | CMD | DATA | CRC

解析过程:接收字节 → 写入缓存 → 查找帧头 → 获取长度 → 判断完整帧 → CRC 校验 → 解析命令和数据。

串口层负责收发字节,协议层负责分帧和解释数据。

拆包与粘包

拆包:一个完整协议帧被分多次收到。

粘包:多个协议帧在一次接收中返回。

例如设备连续发送:

复制代码
AA 55 03 01 02 03
AA 55 02 04 05

应用可能一次收到:

复制代码
AA 55 03 01 02 03 AA 55 02 04 05

这不是串口异常,而是字节流读取的正常情况。处理位置应放在协议解析层:缓存 + 分帧 + 校验 + 数据解析。

ASCII 与二进制协议

ASCII 协议直接使用可显示字符,例如:

复制代码
AT+VERSION?

二进制协议直接定义每个字节,例如:

复制代码
01 03 00 00 00 02 C4 0B

串口本身不关心数据属于字符串、整数还是设备状态,只负责传输字节。

判断协议时需要查看设备通信文档,而不是根据 RS232 或 RS485 接口判断。

大小端

多字节数值需要确认字节序。

数值 0x1234:

复制代码
大端:12 34
小端:34 12

大小端属于上层协议,不属于 UART、RS232 或 RS485 的规定。

同一个 RS485 接口上的不同设备可以使用完全不同的数据格式和字节序。

CRC

工业串口协议经常使用 CRC 检查数据完整性。

以 Modbus RTU 为例,数据结构通常可以记录为:

从站地址 + 功能码 + 数据 + CRC16

Modbus CRC16 在线路上的发送顺序为:CRC Low + CRC High。

CRC 校验失败不一定代表 CRC 算法有问题,还需要检查:串口参数 + 数据是否完整 + 分帧是否正确 + 是否丢字节 + 线路干扰。

Modbus RTU

Modbus RTU 是 RS485 场景中常见的上层协议,但 RS485 并不要求使用 Modbus。

例如:

复制代码
01 03 00 00 00 02 C4 0B

可以拆成:01:从站地址,03:读取保持寄存器,00 00:起始寄存器,00 02:读取两个寄存器,C4 0B:CRC16。

完整关系:Android → UART → RS485 → Modbus RTU 数据帧 → 从站设备。

其中 UART/RS485 负责数据传输,Modbus RTU 负责定义数据内容。

RS485 多设备通信

RS485 支持在一条总线上连接多个节点,但设备地址并不是 RS485 自己定义的。

例如 Modbus RTU:

erlang 复制代码
01 03 ...
02 03 ...
03 03 ...

分别表示访问不同从站。

因此:RS485 提供多点总线能力 + 上层协议提供设备寻址方式。

使用私有协议时,同样需要协议自己定义设备地址或设备 ID。

RS485 A/B

RS485 最常见的接线问题是 A/B 命名不统一。

不同芯片和不同厂商可能使用:A/B、D+/D-、485+/485- 等名称,而且部分厂商对 A/B 的标识习惯可能相反。

出现完全无法通信时,可以结合设备文档、收发器芯片型号和现场测试确认极性,不能只依赖 A/B 字母名称。

RS485 GND

RS485 使用差分信号,但这不代表任何情况下都不需要 GND。

设备之间存在较大地电位差时,只连接 A/B 可能产生共模电压问题。工业设备通常需要结合接口设计判断是否连接信号地、是否使用隔离收发器以及是否存在保护电路。

因此 RS485 接线不能简单理解成永远只需要两根线。

RS485 终端电阻

RS485 总线较长或者速率较高时需要考虑终端匹配,常见终端电阻为 120Ω,一般放在总线两端。

是否需要终端电阻与 线缆长度 + 波特率 + 拓扑 + 收发器 + 现场干扰 有关。

终端电阻属于物理层问题,协议代码无法解决反射造成的通信异常。

RS485 总线拓扑

RS485 更适合总线型连接:

主干 → 节点 → 节点 → 节点

应尽量减少长距离星形分支。

现场出现 短距离正常 + 拉长线后异常 + 某些节点加入后 CRC 错误增加 时,需要同时检查总线拓扑、终端匹配、偏置、电源隔离和接地,而不只是修改 Android 代码。

串口调试

串口调试至少记录:设备节点 + 串口配置 + 发送 HEX + 接收 HEX + 时间。

例如:

yaml 复制代码
Port: /dev/ttyS3
Config: 9600 8N1
TX: 01 03 00 00 00 02 C4 0B
RX: 01 03 04 00 01 00 02 2A 32

调试链路通常可以组合:Android 日志 + PC 串口调试助手 + USB 转串口 + 协议文档 + 示波器/逻辑分析仪。

PC 串口助手可以正常通信而 Android 不能通信时,重点比较:波特率 + 数据位 + 校验位 + 停止位 + 实际发送字节 + RS485 方向控制。

完全收不到数据

重点检查:串口设备节点 + 权限 + 波特率 + 数据位 + 停止位 + 校验位 + TX/RX + RS485 A/B + RS485 DE/RE + 目标设备地址 + 设备是否需要先发送查询命令。

收到乱码

重点检查:波特率 + 数据位 + 校验位 + 停止位 + ASCII/二进制协议判断 + 实际接收 HEX。

二进制数据直接作为字符串显示,本身也可能表现为乱码,因此排查时先查看原始 HEX。

只能发送不能接收

RS485 场景重点检查:收发方向控制 + DE/RE + RTS/GPIO + 驱动自动方向控制 + A/B 接线 + 从站是否真正返回数据。

RS232 场景重点检查:TX/RX 是否交叉 + GND + 对端发送条件。

偶尔 CRC 错误

重点检查:接收帧是否完整 + 拆包粘包处理 + 串口参数 + 丢字节 + RS485 方向切换时机 + 总线终端电阻 + 拓扑 + 接地 + 干扰。

如果同一条指令大多数时间正确、偶尔 CRC 错误,不能只检查 CRC 计算代码。

在 ADB Shell 中直接排查串口问题

Android 串口出现无法通信、乱码、收不到数据等问题时,可以直接在 Shell 环境中检查设备节点、串口参数和原始收发数据。可以先排除 Android 业务代码影响,确认 设备节点 + UART 配置 + RS232/RS485 硬件链路 + 外部设备 是否能够正常通信。

查看串口设备

bash 复制代码
ls -l /dev/tty*

常见设备节点:/dev/ttyS*:板载 UART,/dev/ttyAMA*:部分 ARM UART,/dev/ttyUSB*:USB 转串口,/dev/ttyACM*:USB CDC ACM。

查看内核中的串口信息:

perl 复制代码
dmesg | grep -i -E "tty|uart|serial|rs485"

查看串口配置

bash 复制代码
stty -F /dev/ttyS3 -a

-F /dev/ttyS3 表示指定需要操作的串口设备。stty 中常见参数含义:speed:波特率,cs5/cs6/cs7/cs8:数据位,parenb:启用校验,-parenb:关闭校验,parodd:奇校验,-parodd:偶校验,cstopb:2 个停止位,-cstopb:1 个停止位,crtscts:启用 RTS/CTS 硬件流控,-crtscts:关闭 RTS/CTS 硬件流控,ixon/ixoff:启用 XON/XOFF 软件流控,-ixon -ixoff:关闭软件流控,raw:原始模式,echo:开启回显,-echo:关闭回显。

常见配置命令结构:

xml 复制代码
stty -F /dev/ttyS3 <波特率> <数据位> <校验> <停止位> <流控> raw -echo

8N1 对应:cs8 + -parenb + -cstopb。配置后可以再次执行 stty -F /dev/ttyS3 -a 确认实际参数。

查看串口接收数据

文本协议可以直接读取:

bash 复制代码
cat /dev/ttyS3

二进制协议更适合直接显示为十六进制:

bash 复制代码
od -An -tx1 -v < /dev/ttyS3

参数含义:-A n:不显示地址偏移,-t x1:每个字节以十六进制显示,-v:不省略重复数据。

如果系统包含 hexdump:

bash 复制代码
hexdump -C /dev/ttyS3

-C 表示以十六进制和 ASCII 对照格式显示数据。串口协议排查时优先查看原始 HEX,不要先转换成字符串。

发送串口数据

发送 ASCII:

bash 复制代码
printf 'COMMAND\r\n' > /dev/ttyS3

发送二进制数据:

bash 复制代码
printf '\x01\x02\x03\x04' > /dev/ttyS3

printf 可以直接控制 \r、\n 等字符,\xNN 表示发送一个十六进制字节。printf '01' 发送的是字符 0 和 1,printf '\x01' 发送的才是实际的 0x01 字节。

查看串口权限

bash 复制代码
ls -l /dev/ttyS3

没有设备节点访问权限时通常会出现 Permission denied。调试阶段可以临时修改:

bash 复制代码
chmod 666 /dev/ttyS3

正式系统仍应通过 ueventd.rc + SELinux Policy + 系统权限 配置串口访问权限。

相关推荐
千里马学框架5 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台5 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone5 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc5 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo5 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077005 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼5 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone5 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen5 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone5 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui