1 引言
?
STM32 是意法半导体(STMicroelectronics)基于ARMCortex-M3 内核推出的专门用于高性能、低成本、低功耗嵌入式领域的32 位微处理器系列。根据微处理器性能的不同STM32系列又分为基本型、增强型、互联型等几个子系列,可用于不同性能要求的产品上。
?
Android 是一种基于Linux 的自由及开放源代码的操作系统,其源代码以Apache 开源许可证的授权方式,主要应用于移动设备,如智能手机和平板电脑。Android 操作系统因其良好的开放性而得到很好的发展。
?
2 Android 设备与STM32 单片机通信方式
?
2.1 音频通信
?
绝大部分的Android 设备上都拥有耳机插孔,一般情况下耳机插孔是用来输出音频信号到耳机, 或者输入从麦克风采集到的音频信号。
?
根据耳机接口定义,可以利用左声道L(或右声道R)作为Android 设备输出信号到单片机的通信线,MIC 作为单片机输出信号到Android 设备的通信线。音频信号属于模拟信号,为了实现数字通信,需对数字信号进行调制。常见的调制方式有调幅(AM)、调频(FM)和调相(PM)三种,调幅的实现最简单,但是抗干扰能力比较弱,因此一般采用调频或调相,如FSK、DTMF、PSK 等。值得一提的是DTMF 作为一种应用比较广泛的音频调制方式,已经有很多成熟的编解码芯片,借助于这些现成的编解码芯片能够大大的简化单片机端的开发工作。
?
由于耳机接口有左右声道,而从Android 设备输出的信号只需使用其中的一路, 因而如果外接的硬件设备功耗很低的话可以直接使用未使用的一路作为供电。其原理是另外一路始终输出幅度很大的声音信号, 外部通过整流和稳压之后提供供电。
?
音频通信的难点在于信号的调制和解调, 单片机端可以借助于现成的芯片对信号进行硬件调制和解调,但Android 端的调制和解调(尤其是解调)大部分工作都得自行实现。此外,音频信号的上限为20kHz, 因而决定了音频通信的速率也会太高。以DTMF 音频信号为例,典型的DTMF 信号频率范围为700~1700Hz, 带宽为1000Hz, 根据奈奎斯特公式可计算出DTMF 的通信速率上限为8000bps,即1KB/s。因而这种方式只适用于对通信速率要求不高的场景,如手持式刷卡机。
?
2.2 串口通信
?
串口通信是嵌入式系统中最为常用的一种通信方式,它具有简单方便的特点。在STM32 单片机上的开发工作量和难度都不大, 单片机在上电后初始化串口通信相关的引脚、设置通信波特率、设置串口中断函数、使能串口并开启中断之后就可以正常使用串口进行通信。
?
Android 设备并没有直接支持串口通信功能,但大部分的Android 设备(尤其是平板电脑)都支持OTG(On-The-Go)功能,可以将Android 设备作为USB 主机,通过USB 转串口芯片(如PL2303、CP2102/CP2103、FT232RL 等)让Android 设备具有虚拟串口的功能。在Android 的上层应用中,只需要通过调用虚拟串口驱动就能够和单片机进行串口通信。Android 系统中上层应用使用虚拟串口主要有以下两种方式:
?
(1)直接使用Linux 层串口驱动。Android 是基于Linux 操作系统的,它具有大部分Linux 的特性,因而可以借鉴Linux下虚拟串口通信的方式与单片机进行通信。
?
(2)在应用层实现虚拟串口驱动。从Android 3.1 开始,Android 官方提供了一整套访问USB 的API 可以直接使用Java 语言对Android 设备的USBHost 功能进行开发。
?
与直接在Linux 层上使用虚拟串口相比,应用层由于经过Dalvik 虚拟机(Dalvik VM)抽象并屏蔽了底层硬件之间的差异而更具有通用性。但是,大部分USB 转串口芯片厂商并没有把他们的通信协议对外公布,也很少对外提供Java 封装的驱动程序。因而这种方式虽然使用封装好的类库时比较容易,但在前期使用Java 语言对虚拟串口的访问进行封装的工作量和难道都比较大。
?
无论从成本还是研发难度上考虑, 串口通信方式对于低速的传输场景比较适用, 但在需要高速传输数据时就并不是十分适合了,这主要有两方面的原因:首先是单片机并不支持高速串口传输, 很多单片机的串口通信波特率最高只到115200bps(该值也是RS-232 的理论传输速率上限值);另外,USB 转串口芯片也会有限制, 如PL2303 芯片的上限为256000bps。
?
2.3 蓝牙通信
?
STM32 系列单片机并没有直接支持蓝牙功能, 但借助现成的串口转蓝牙模块,可以很容易让STM32 单片机具有蓝牙通信的功能。只需将蓝牙模块的串口波特率和单片机的串口波特率设置一致, 之后单片机从串口发出的数据便能够通过蓝牙模块发送出去, 而蓝牙模块收到的数据也能够通过串口发送给单片机。
?
Android 操作系统对蓝牙传输协议具有很好的支持,自Android 2.1 (APIlevel7)开始就提供了BlueZ 的RFCOMM 协议封装,利用该协议可完成Android 设备与蓝牙设备之间的串口通信。使用蓝牙通信需在Android Manifest.xml 文件中申明”android. Permission. BLUETOOTH” 和”android. Permission.BLUETOOTH_ADMIN”权限。Android 上的蓝牙应用开发主要是使用android. bluetooth 包下蓝牙通信相关的类库来实现。
?
2.4 USB2.0 通信
?
STM32 系列增强型(STM32F103xx)和互联型(STM32F105、STM32F107) 微处理器都支持USB2.0 全速接口, 因此这部分STM32 单片机还可以选择USB 的方式与Android 设备进行通信。
?
在单片机电路设计方面,STM32 的USB 部分电路设计并不复杂, 需注意的是, 如果使用全速传输模式的话, 须将USB_DP 上拉至3.3V, 表示该USB 设备为全速设备。
?
USB 的设备类别有很多,如常见的HID(Human InterfaceDevice)或者CDC(Communication Device Class)。HID 类的设备也比较多,如:USB 键盘、USB 鼠标、USB 手写笔、等等。包括Android 在内的大部分操作系统都自带有了HID 类的驱动程序,因而HID 设备可以直接连到Android 设备上。HID 的最大传输速度有限,特别是低速和全速的时候。低速模式每秒最多传输800 个字节, 高速模式时每一秒最多也只能传输64000个字节,即传输速度不超过64K/s。
?
为提高传输速率, 一般使用CDC 类来完成Android 设备与STM32 单片机之间的USB 通信。如果传输过程不涉及复杂控制功能,只需要为CDC 类添加一个数据接口类,并且为数据接口添加一对批量传输模式(Bulk Transfer)的输入端点和输出端点就能够完成基本的数据收发功能。如需要对设备进行复杂的管理和控制,那么可以再为CDC 类设备添加一个通信接口类。
?
Android 的SDK 中并没有针对CDC 类提供特定的API,但提供了USB 相关的操作,如设备的枚举、设备的打开、接口操作、端口操作以及批量传输等基本的方法。基于这些操作已经可以完成CDC 类的数据批量传输模式, 实现Android 设备与STM32 单片机的直接进行USB 通信。Android 上使用USB进行通信的一般步骤:
?
(1)枚举挂接到系统上的USB 设备;
?
(2) 根据厂商ID(Vendor-ID) 和产品ID(Product-ID) 过
?
滤,得到对应USB 设备;
?
(3)请求用户授予USB 设备的访问权限;
?
(4)使用UsbManager.openDevice 方法打开设备;
?
(5)使用UsbDevice.getInterface 方法获取接口,并进行配置;
?
(6)使用UsbInterface.getEndpoint 方法打开通信端点;
?
(7)使用UsbDeviceConnection.bulkTransfer 方法与STM32进行通信;
?
(8)使用完毕,关闭USB 设备。
?
为了便于使用, 一般需要将USB 通信过程进行封装,只需要向上层提供透明的输入输出流, 而不是让上层直接去操作bulkTransfer 方法。同时这样做也利于代码的分层和复用,不同类型的产品只需要通过产品ID(Product-ID)就能够识别出USB 设备,避免了重复代码的重复编写。
?
3 结论
?
不同的通信方式适用于不同的场景, 音频通信适用于对通信速率要求不高的场景,为了保证可靠性,需要增加校验纠错机制, 使用现成的调制解调芯片, 可以简化单片机端的开发。串口通信和蓝牙通信在传输速率上没有明显的区别,一般采用串口通信,如果需要无线传输则考虑采用蓝牙通信。USB通信一般用于高速通信场景,如数据的高速采集,但USB 通信的底层封装工作比其他几种通信方式复杂, 建议一次实现然后在多个产品中复用底层封装,从而均摊研发成本。本文虽然仅针对Android 设备与STM32 单片机的通信进行讨论和实验,但单片机之间具有很多相似性,因而本文的讨论以及大部分结论都具有普遍性,可以推广至Android 设备与一般单片机之间的通信问题上。