[Android] 智能硬件应用串口开发 (Intelligent Hardware Application Serial Port Development)

Posted by xiuyuantech on 2024-09-23

智能硬件是继智能手机之后的一个科技概念,通过软硬件结合的方式,对传统设备进行改造,进而让其拥有智能化的功能。
智能硬件的应用领域非常广泛,包括智能家居、智能穿戴、智能办公、智能医疗、智能汽车等。
随着物联网技术的发展,智能硬件在未来的发展中将扮演越来越重要的角色。它将万物共联,成为物联网中的核心主体。
智能硬件的发展趋势包括更高的智能化、更广泛的应用场景、更强的数据处理能力等。它在提高生活质量、推动产业发展、促进技术创新等方面具有重要意义。

Android智能硬件的关键——串口通信(Serial Port)

串口认知

串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。
串行接口(Serial Interface)是指数据一位一位地顺序传送。其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。
异步串行是指UART(Universal Asynchronous Receiver/Transmitter),通用异步接收/发送。 UART包含TTL电平的串口和RS232、RS485电平的串口!

UART串口有三种工作方式:单工、半双工、全双工。

1、单工通信

单工通信只有一根数据线,通信只在一个方向上进行,这种方式的应用实例有:监视器、打印机、电视机等。

2、半双工通信

半双工通信也只有一根数据线,它也单工的区别是这根数据线既可作发送又可作发接收,虽然数据可在两个方向上传送,但通信双方不能同时收发数据。

3、全双工通信

数据的发送和接收用两根不同的数据线,通信双方在同一时刻都能进行发送和接收,这一工作方式称为全双工通信。在这种方式下,通信双方都有发送器和接收器,发送和接收可同时进行,没有时间延迟。

串口配置

常见的串口通讯设置的界面如下所示:
串口通讯设置

主要有下列几个参数:

  • Speed(baud) 波特率

  • Data bits 数据位

  • Stop bits 停止位

  • Parity 奇偶校验位

  • Flow Control 流控

我们的设置基本都是8位数据位,1位停止位,无校验无流控。对于程序开发而言,主要关注的参数就是波特率。

另外,需要注意的是比特率、成波特率两者之间是有区别的。 波特率表示每秒钟传送的码元符号的个数,是衡量数据传送速率的指标,它用单位时间内载波调制状态改变的次数来表示。 在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数称为码元传输速率,简称波特率。

串口接线

  • 笔记本电脑通过TTL电平与单片机通信,TX发送线(端口)数据输入引脚,数据接受; RX接收线 (端口)数据发送引脚,数据发送;
    USB转TTL,使用CH340通信

  • 串口接线方式如下图所示:
    电路图

  • 蓝牙模块(接线与串口一致,都为交叉接线)一般用串口测试完毕,再用蓝牙模块开发。

串口库

如果通过Android USB开发,推荐使用usb-serial-for-android

如果通过COM串口开发,推荐使用android-serialport-api

如果通过蓝牙开发,推荐使用androidx.bluetooth或者FastBle(支持Android4.3以上)

Demo示例

在Android平台上进行串口通信,可以使用第三方库如usb-serial-for-android库。以下是使用该库进行串口通信的基本步骤和示例代码:
1、添加依赖到你的build.gradle文件:

1
2
3
dependencies {
implementation 'com.hoho.android:usb-serial-for-android:x.y.z'
}

2、确保你的应用有足够的权限来访问USB设备:

1
2
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

3、在你的Activity中,找到并打开串口设备:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbSerialProber prober = new UsbSerialProber(usbManager);
List<UsbSerialDriver> availableDrivers = prober.findAllDrivers();

if (availableDrivers.isEmpty()) {
// 没有找到串口设备
} else {
UsbSerialDriver driver = availableDrivers.get(0); // 选择第一个设备
UsbDeviceConnection connection = usbManager.openDevice(driver.getDevice());
if (connection == null) {
// 设备无法打开
} else {
try {
UsbSerialPort port = driver.getPorts().get(0); // 选择第一个端口
int baudrate = 9600; // 设置波特率
port.open(connection);
port.setParameters(baudrate, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);

// 读取数据
byte buffer[] = new byte[16];
int timeout = 0; // 毫秒
int bytesRead = port.read(buffer, timeout);

// 写入数据
String dataToWrite = "Hello serial port!";
port.write(dataToWrite.getBytes(), timeout);

// 关闭端口和连接
port.close();
connection.close();
} catch (IOException e) {
// 处理异常
}
}
}

避坑指南

  • 权限问题:确保你的应用有读/写串口的权限
  • 串口不存在或路径错误
  • 超时问题:设置正确的串口读写超时时间
  • 波特率不匹配:确保串口通信的波特率设置与外设一致
  • 串口被占用:如果应用程序尝试打开已经被其他应用程序打开的串口,将会失败。确保串口在同一时间只被一个应用程序使用
  • 缓冲区溢出问题:确保读写缓冲区大小合理,避免数据溢出
  • 无线通信:发送消息接受不到,确保无线信道是否发错
  • 通信协议变异:发送和收到的消息异常不匹配,确保外设和主机所有硬件和电路正常
  • 数据分割:轮询判断流中数据大小,如果有数据则拼接至已有的Bytes数组中