当前位置: 首页 > news >正文

Android 串口底层基础:USB 串口、RS485/232 驱动识别、串口通信框架入门

Android 串口底层基础:USB 串口、RS485/232 驱动识别、串口通信框架入门

工控板子要跟传感器、继电器、PLC 对话,串口就是那根"嗓子"。搞不定串口,工控项目等于哑巴。

一、串口通信基础

串口通信是最经典的设备间通信方式,核心是UART(通用异步收发传输器)协议。数据按位(bit)逐个传输,不需要时钟线,双方靠约定的波特率同步。

1.1 UART 协议帧结构

一个完整的 UART 数据帧:

[空闲] [起始位] [D0 D1 D2 D3 D4 D5 D6 D7] [校验位] [停止位] 高电平 1bit 5~9bit数据 0/1bit 1/1.5/2bit
  • 起始位:1 个低电平,标志数据帧开始
  • 数据位:5/6/7/8/9 位,常用 8 位
  • 校验位:奇校验(Odd)、偶校验(Even)、无校验(None)
  • 停止位:1/1.5/2 位高电平,标志帧结束

1.2 RS232 vs RS485 区别

这是工控领域最常被问的问题,直接上对比表:

特性RS232RS485
传输方式全双工半双工
电平标准±3V~±15V(负逻辑)差分信号 ±2V~±6V
通信距离约 15 米约 1200 米
节点数1 对 11 对多(最多 32/128/256 节点)
抗干扰较弱强(差分传输)
典型接口DB9(9 针)两根线 A/B
工控用途近距离调试长距离组网、Modbus 总线

一句话记:RS232 适合桌面调试,RS485 才是工控现场的硬骨头。RS485 两根线走差分信号,抗干扰能力碾压 232,车间里几十个传感器挂一根线没问题。

1.3 串口核心参数

参数说明常见值
波特率每秒传输的 bit 数9600 / 19200 / 38400 / 115200
数据位每帧数据位数8
停止位帧结束标志1
校验位数据校验方式None
流控流量控制None / RTS/CTS

工控设备最经典的配置:9600, 8N1(波特率 9600,8 数据位,无校验,1 停止位)。碰到不确定的设备,先试这个。

二、Android 串口两种方案

Android 平台操作串口,主要有两条路线:

2.1 方案对比

方案原理适用场景优缺点
USB Host 模式通过 USB OTG 连接 USB 转串口模块平板/手机无原生串口通用性强,但需 USB 权限,延迟略高
ttyS 设备节点直接读写 /dev/ttySx 节点工控板自带 UART 引脚延迟低、性能好,需 root 或系统权限

简单说:用商用平板做项目选 USB Host 方案;用定制工控主板(如 RK3568、全志 A40i)选 ttyS 方案,性能更高。

三、USB 串口方案:USB Host API 与 usb-serial-for-android

3.1 USB Host API 基础

Android 3.1 引入 USB Host 支持,通过UsbManager管理连接的 USB 设备。流程如下:

  1. 获取UsbManager实例
  2. 枚举已连接的 USB 设备
  3. 申请 USB 权限
  4. 打开设备,获取UsbDeviceConnection
  5. 找到正确的UsbEndpoint(输入/输出端点)
  6. 通过bulkTransfer()收发数据

3.2 usb-serial-for-android 开源库

自己裸写 USB 协议太痛苦,社区有成熟的开源库usb-serial-for-android(GitHub: mik3y/usb-serial-for-android),支持主流 USB 转串口芯片:

芯片厂商常见模块
CH340沁恒CH340G、CH340C
CP210xSilicon LabsCP2102、CP2104
FTDIFTDIFT232RL
PL2303ProlificPL2303HX
CH9102沁恒CH9102F

引入依赖:

dependencies { implementation 'com.github.mik3y:usb-serial-for-android:3.4.6' }

3.3 完整代码示例

publicclassUsbSerialHelper{privatefinalContextmContext;privatefinalUsbManagermUsbManager;privateUsbSerialPortmSerialPort;privateSerialInputOutputManagermSerialIoManager;publicinterfaceSerialDataCallback{voidonDataReceived(byte[]data);voidonError(Exceptione);}privateSerialDataCallbackmCallback;publicUsbSerialHelper(Contextcontext,SerialDataCallbackcallback){this.mContext=context;this.mCallback=callback;this.mUsbManager=(UsbManager)context.getSystemService(Context.USB_SERVICE);}/** * 查找并打开第一个可用的USB串口设备 */publicbooleanopen(intbaudRate){// 1. 查找所有USB设备List<UsbSerialDriver>drivers=UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager);if(drivers.isEmpty()){Log.e("UsbSerial","未找到USB串口设备");returnfalse;}// 2. 取第一个驱动UsbSerialDriverdriver=drivers.get(0);UsbDevicedevice=driver.getDevice();// 3. 申请权限if(!mUsbManager.hasPermission(device)){PendingIntentpi=PendingIntent.getBroadcast(mContext,0,newIntent("com.android.example.USB_PERMISSION"),PendingIntent.FLAG_IMMUTABLE);mUsbManager.requestPermission(device,pi);returnfalse;}// 4. 打开连接UsbDeviceConnectionconnection=mUsbManager.openDevice(device);if(connection==null)returnfalse;mSerialPort=driver.getPorts().get(0);try{mSerialPort.open(connection);// 配置串口参数:9600, 8N1, 无流控mSerialPort.setParameters(baudRate,8,UsbSerialPort.STOPBITS_1,UsbSerialPort.PARITY_NONE);mSerialPort.setDTR(true);// 某些设备需要mSerialPort.setRTS(true);// 5. 启动收发管理器mSerialIoManager=newSerialInputOutputManager(mSerialPort,newSerialInputOutputManager.Listener(){@OverridepublicvoidonNewData(byte[]data){if(mCallback!=null){mCallback.onDataReceived(data);}}@OverridepublicvoidonRunError(Exceptione){if(mCallback!=null){mCallback.onError(e);}}});// 在独立线程中运行newThread(mSerialIoManager).start();returntrue;}catch(IOExceptione){mCallback.onError(e);returnfalse;}}/** * 发送数据 */publicvoidsend(byte[]data){if(mSerialPort!=null){try{mSerialPort.write(data,1000);// 超时1000ms}catch(IOExceptione){mCallback.onError(e);}}}/** * 关闭串口 */publicvoidclose(){if(mSerialIoManager!=null){mSerialIoManager.stop();mSerialIoManager=null;}try{if(mSerialPort!=null){mSerialPort.close();}}catch(IOExceptione){// ignore}mSerialPort=null;}}

四、ttyS 节点方案:JNI/Native 层直接操作

工控主板通常在/dev/下暴露串口设备节点,如/dev/ttyS1/dev/ttyS3/dev/ttyMT0等。这种方案需要通过JNI调用 C/C++ 层的open()/read()/write()系统调用。

4.1 C 层串口操作核心

#include<fcntl.h>#include<termios.h>#include<unistd.h>intopen_serial(constchar*device,intbaudrate){intfd=open(device,O_RDWR|O_NOCTTY|O_NDELAY);if(fd<0)return-1;structtermiosoptions;tcgetattr(fd,&options);// 设置波特率speed_tspeed;switch(baudrate){case9600:speed=B9600;break;case19200:speed=B19200;break;case115200:speed=B115200;break;default:speed=B9600;break;}cfsetispeed(&options,speed);cfsetospeed(&options,speed);// 8N1配置options.c_cflag&=~PARENB;// 无校验options.c_cflag&=~CSTOPB;// 1停止位options.c_cflag&=~CSIZE;options.c_cflag|=CS8;// 8数据位options.c_cflag|=(CLOCAL|CREAD);// 启用接收tcsetattr(fd,TCSANOW,&options);returnfd;}

4.2 权限处理

访问/dev/ttySx需要 root 或将 app 加入对应权限组。工控固件通常在init.rc中配置:

chmod666/dev/ttyS1

或在 SELinux 策略中放行。没有 root 的设备,USB Host 方案是唯一选择。

五、串口数据收发流程与协议帧解析

5.1 串口数据的"粘包"问题

串口是字节流,没有消息边界概念。一次read()可能收到半条数据,也可能收到两条半数据。必须靠自定义协议帧来解析。

5.2 典型协议帧结构

[帧头][设备地址][功能码][数据长度][数据][校验][帧尾] 0xAA 0x01 0x03 0x04 .... CRC 0x55

解析代码示例:

privatefinalByteArrayOutputStreammRecvBuffer=newByteArrayOutputStream();publicvoidhandleData(byte[]newData){mRecvBuffer.write(newData,0,newData.length);byte[]buf=mRecvBuffer.toByteArray();while(buf.length>=8){// 最小帧长8字节// 找帧头intstart=indexOf(buf,(byte)0xAA);if(start<0){mRecvBuffer.reset();return;}if(start>0){// 丢弃帧头前的脏数据mRecvBuffer.reset();mRecvBuffer.write(buf,start,buf.length-start);buf=mRecvBuffer.toByteArray();}// 读取数据长度intdataLen=buf[3]&0xFF;intframeLen=2+1+1+1+dataLen+1+1;// 头+地址+功能+长度+数据+校验+尾if(buf.length<frameLen){return;// 数据不够,等下一次}// 校验CRCbyte[]frame=newbyte[frameLen];System.arraycopy(buf,0,frame,0,frameLen);if(frame[frameLen-1]==(byte)0x55){// 完整帧,回调onFrameReceived(frame);}// 移除已解析的数据mRecvBuffer.reset();if(buf.length>frameLen){mRecvBuffer.write(buf,frameLen,buf.length-frameLen);}buf=mRecvBuffer.toByteArray();}}

协议帧解析是串口编程最容易出 bug 的地方。核心思路:缓冲区 + 找帧头 + 长度校验 + CRC 校验,四个步骤缺一不可。

六、工控场景常见串口设备

设备类型典型协议接口波特率
温湿度传感器Modbus RTURS4859600
继电器模块自定义 ASCII/HEXRS4859600
PLC(西门子/三菱)Modbus RTU / 自有协议RS4859600~19200
条码扫描枪串口透传RS232115200
RFID 读卡器Wiegand / 串口协议RS232/4859600
电磁流量计Modbus RTURS4859600
变频器Modbus RTURS48519200

串口通信是工控 Android 开发的基石。无论是 USB 方案还是 ttyS 方案,核心都是"正确配置参数 + 稳定收发数据 + 可靠解析协议帧"。把这三个环节吃透,对接任何串口设备都不慌。

http://www.jsqmd.com/news/1270531/

相关文章:

  • 别再手动整理纪要了!2024Q3起,监管新规要求AI生成内容必须嵌入可审计元数据
  • 谷歌财报技术解析:云原生与AI驱动业绩增长及开发者机遇
  • 从经典QSAR到AI药物设计:分子描述符的演进与应用
  • 写一个简单的sh脚本
  • 2026年 西安缝隙天线厂家:5G通信与车载天线专业定制供应商深度分析 - 卓企推荐
  • 2026年7月江苏省无锡市电信500M单宽带怎么安装? - 找卡家园
  • 2026高返点广告开户渠道合作模式大全及甄选攻略:正规渠道、费用核算与签约避坑全解析 - 商业大观
  • 提示词×产品描述实战指南:7步打造AI时代爆款文案,今天学会明天投产
  • 2026年7月四川省攀枝花市联通1000M融合宽带怎么安装 - 找卡家园
  • 移动端(非uniapp项目) PDA 扫码踩坑:input 聚焦屏蔽软键盘完整解决方案
  • BP神经网络优化永磁同步电机PI控制实践
  • 基于YOLOv13的建筑病害智能检测系统开发与实践
  • SolidWorks许可证预测优化:数据驱动降本增效
  • OpenClaw开源智能体网关:AI助手与即时通讯的完美融合
  • JMeter性能压测实战:如何配置业务请求比例模拟真实流量模型
  • 2026论文AI检测新规与降重工具实战指南
  • AI核心技术解析:RAG、MCP、Agent与Function Call实战指南
  • 2026年7月湖南省张家界市移动单宽带怎么选_新手避坑指南 - 找卡家园
  • 2026常州离婚律师服务能力深度对比:从财产分割到子女抚养,选谁更有把握? - 本地品牌推荐
  • 2026年7月江苏省无锡市电信1000M单宽带避坑与办理指南 - 找卡家园
  • UE5集成Entt ECS架构实战:万单位移动端性能优化与样条线路径系统
  • 湖南梵映教育科技有限公司课程紧跟行业变革,课程升级适配影视后期岗位新格局 - 资讯报道
  • 【关注可白嫖源码】---课程设计---毕业设计-- 基于springboot的宠物领养与救助平台 [编号:project64334] (案件分析)
  • 基于YOLOv10的水稻病害智能检测系统开发实践
  • AI大模型、AIGC与算力:核心技术解析与应用指南
  • 工业相机帧率与曝光深度解析|吃透时序制约原理、带宽阈值计算、动态静态调参策略、助力飞拍高速成像、精密质检稳定成像
  • 2026年7月湖南省长沙市移动300M单宽带避坑全攻略 - 找卡家园
  • opencode CLI 入口层源码拆解:effectCmd + InstanceStore + bootstrap 三层设计
  • 2026年7月浙江省嘉兴市电信500M宽带安装流程 - 找卡家园
  • 实时新闻地图:基于OpenAI嵌入与HNSWLib的新闻聚类可视化实战