串行通讯之UARTLoopback

目录

第1章串行通讯之UARTLoopback    2

1 USB转串口    2

2 USB Accessory    2

3 连入手机    3

4 代码改进    4

5 打开串口    4

6 写串口数据    4

7 主动读取串口数据    5

8 被动读取串口数据    5

9 关闭串口    6

第1章串行通讯之UARTLoopback

1 USB转串口

这两天在做Android手机上的串行通讯程序。手机没有串口,所以使用了USB转串口,如下图所示:

图1 USB转串口

上图中,红色的USB A型插头用来给此设备供电;黑色的Micro USB插头用来连接Android手机;粉红色的9针插头用来连接串口设备。

购买此产品时,附带了Java源代码,也就是工程UARTLoopback。本文对其进行说明及改进。

2 USB Accessory

USB设备分为两大类:USB Host、USB Accessory(USB 附件)。USB键盘、鼠标连入手机后,由手机给其供电,它们属于USB Host;上面的USB转串口连入手机后,会给自己、手机供电,它属于USB Accessory。

查看UARTLoopback的代码可知:访问USB转串口的实质是访问USB Accessory。

关于USB Accessory的更多信息请参考如下博客:

http://blog.csdn.net/yingzhao80/article/details/45511351

3 连入手机

Android 手机上安装UARTLoopbackActivity.apk后,将USB转串口接入手机,就会弹出如下界面:

图2

这是如何实现的呢?请查看UARTLoopback的AndroidManifest.xml文件。下面是精简后的内容,重点是红色字体部分:


... ... ...

<uses-feature android:name="android.hardware.usb.accessory"/>

... ... ...

<intent-filter>

<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>

</intent-filter>

<meta-data

android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"

android:resource="@xml/accessory_filter">

</meta-data>

... ... ...

4 代码改进

串行通讯的核心类就是FT311UARTInterface,笔者对其进行了改进。改进版的下载网址为:http://download.csdn.net/detail/hanford/9686781

下文的说明以改进版为准。

5 打开串口

打开串口的代码如下


com.UARTLoopback.FT311UARTInterface m_Comm = new com.UARTLoopback.FT311UARTInterface(this);

if(m_Comm.open(9600,‘N‘,8,1,0))

{//成功打开串口

}

else if(m_Comm.isExist())

{//打开串口失败,可能是权限不够,申请权限

m_Comm.requestPermission();

}

else

{//说明手机未连接USB转串口

}

m_Comm.open 用来打开串口

m_Comm.isExist 用来判断USB转串口是否已经插入手机

m_Comm.requestPermission 用来申请权限

打开串口的时候就设置通讯参数,为什么这么设计呢?因为:从USB转串口插入手机到拔出手机这段时间内,只能配置一次通讯参数。

6 写串口数据

请参考下面的代码


if(m_Comm.isOpen()) {

byte[] data = m_txtSend.getText().toString().getBytes();

m_Comm.write(data,data.length);

}

m_Comm.isOpen 判断串口是否已经打开

m_txtSend.getText().toString().getBytes() 获取文本框m_txtSend内的文本,然后转换为二进制数据

m_Comm.write 发送二进制数据

7 主动读取串口数据

请参考下面的代码


if(m_Comm.isOpen()) {

byte[] data = new byte[1024];

int nRead=m_Comm.read(data, data.length);

try {

m_txtRecv.setText(new String(data, 0, nRead, "UTF-8"));

} catch (UnsupportedEncodingException ex) {

}

}

m_Comm.read用来读取串口数据,返回读取到的字节数。接下来的代码,将读取到的二进制数据转换为字符串,并显示到文本框m_txtRecv里。

8 被动读取串口数据

被动读取串口数据,就是一旦获得了串口数据就通知程序。其代码有点多:


m_Comm.setEventDataReceived(m_EventDataReceived);

com.UARTLoopback.FT311UARTInterface.EventDataReceived m_EventDataReceived = new com.UARTLoopback.FT311UARTInterface.EventDataReceived(){

public void onEvent(byte[] data,int nBytes)

{//接收到串口数据,就调用此函数

try {

m_sRecv += new String(data, 0, nBytes, "UTF-8");

} catch (UnsupportedEncodingException ex) {

}

m_Handler.sendEmptyMessage(1); //更新界面显示

}

};

private Handler m_Handler = new Handler() {

public void handleMessage(Message msg) {

switch (msg.what) {

case 1: m_txtRecv.setText(m_sRecv); break;

}

super.handleMessage(msg);

}

};

代码m_Comm.setEventDataReceived(m_EventDataReceived);表示一旦接收到串口数据,马上调用m_EventDataReceived对象的onEvent函数。

onEvent函数中,将串口数据(保存在数组byte[] data里,字节数为 nBytes)转换为文本,然后加到字符串变量m_sRecv的右边。

因为onEvent函数不在主线程里,所以需要代码m_Handler.sendEmptyMessage(1);通知m_Handler更新主界面。其实就是handleMessage函数中的m_txtRecv.setText(m_sRecv)被执行。

总结:

1)m_Comm.setEventDataReceived指定事件处理对象,一旦读取到串口数据,将调用该对象的onEvent函数;

2)onEvent函数是被多线程调用的,更新主界面请使用Handler、sendEmptyMessage;

3)如果m_Comm.setEventDataReceived的参数不是null,那么就无法主动读取串口数据了。也就是说,此时m_Comm.read始终返回0。

9 关闭串口

关闭串口的代码很简单,如下所示:


m_Comm.close();

不过,它的问题最严重:

调用上述代码,读取串口数据的线程(FT311UARTInterface.ThreadRead.run)将被阻塞在如下代码行:


nRead = FileInputStream_read(m_InputStream,data,data.length);

上面的代码调用了FileInputStream.read函数,这是一个同步函数——没有读取到串口数据,就不会返回。这个时候,如果串口设备发送过来数据,线程将正常退出;如果串口设备一直未发送数据过来,那么这个线程将永远阻塞在这一行上。

线程ThreadRead阻塞后,m_Comm.open将无法再打开串口。解决办法就是:拔下USB转串口,重新插入。

总结:关闭串口会极大概率的导致一个僵尸线程的产生,不够完美的解决办法就是重新拔、插USB转串口。

时间: 2024-10-13 05:16:14

串行通讯之UARTLoopback的相关文章

COM口,串行通讯端口,RS-232接口 基础知识

COM口即串行通讯端口. COM口的接口标准规范和总线标准规范是RS-232,有时候也叫做RS-232口.电脑上的com口多为9针,最大速率115200bps.通常用于连接鼠标(串口)及通讯设备(如连接外置式MODEM进行数据通讯)等.但目前主流的主板一般都只带1个串口,甚至不带,慢慢会被USB 取代. 以前用于连接老式的COM口鼠标键盘,还有链接路由器,外置调制解调器等.现在很少使用. 什么是串口,串行通讯端口?-----------------------------------------

【Arduino】使用C#实现Arduino与电脑进行串行通讯

在给Arduino编程的时候,因为没有调试工具,经常要通过使用串口通讯的方式调用Serial.print和Serial.println输出Arduino运行过程中的相关信息,然后在电脑上用Arduino IDE的Serial Monitor来查看print出来的信息.Serial Monitor不仅可以接受Arduino发送到电脑的数据,还可以向Arduino发送数据,进行双向通讯.但是这种通讯方式太过于简陋,是纯粹的手工方式,只适合调试.如果需要在电脑上通过可视化界面与Arduino进行交互,

STM32学习笔记——SPI串行通讯(向原子哥学习)

一.SPI  简介 SPI是 Serial Peripheral interface 的缩写,就是串行外围设备接口.SPI 接口主要应用在  EEPROM, FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32 有 SPI 接口.下面是 SPI 的内部简明图:

串行通讯协议--起止式异步通讯协议(UART)

起止式异步通讯协议: 特点与格式: 起止式异步协议的特点是一个字符一个字符传输,并且传送一个字符总是以起始位开始,以停止位结束,字符之间没有固定的时间间隔要求.其格式如图3 所示.每一个字符的前面都有一位起始位(低电平,逻辑值0),字符本身有5-7位数据位组成,接着字符后面是一位校验位(也可以没有校验位),最后是一 位,或意味半,或二位停止位,停止位后面是不定长度的空闲位.停止位和空闲位都规定为高电平(逻辑值),这样就保证起始位开始处一定有一个下跳沿. 从图中可以看出,这种格式是靠起始位和停止位

串行通讯之.NET SerialPort异步写数据

目 录 第1章 说明    2 1 为什么需要异步写数据?    2 2 异步写数据的代码    2 3 源代码    4 第1章 说明 1 为什么需要异步写数据? 如下图所示,以波特率300打开一个串口. 图1 单击"同步发送"按钮,则数据未发送完之前写数据的函数不会返回.波特率300,每秒大概能发送25个字符,发送500个字符就需要20秒.这20秒之内,整个程序将处于假死状态. 单击"异步发送"按钮,就不会出现假死状态. 2 异步写数据的代码 异步写数据的代码如

C#委托的使用和串行通讯接收事件显示在指定控件

本实例演示定义委托,并利用委托把来自串口接收到的数据显示在文本框中!熟悉委托的定义和串行数据收发的简单功能! 本文源代码下载地址,可以酌情修改代码运行调试,串口端口我使用的COM11,你需要改成自己的才好用建议是COM1 http://download.csdn.net/detail/nieweiking/8245463 项目代码: <pre name="code" class="csharp">using System; using System.Co

上位机串行通讯的通用思路

先上代码: public class SerialPortServer { //字段 SerialPort SP = new SerialPort(); int DelayTime = 5000;//默认是5s string Info = ""; string SendStringBuffer = ""; string ReceiveStringBuffer = ""; //构造函数 public SerialPortServer(string

SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)

SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynchronous Receiver Transmitter:通用异步收发器) 第二,区别在电气信号线上: SPI总线由三条信号线组成:串行时钟(SCLK).串行数据输出(SDO).串行数据输入(SDI).SPI总线可以实现多个SPI设备互相连接.提供SPI串行时钟的SPI

单片微机原理P4:80C51串口与串行总线拓展

0. 串口通讯 0. 串口通讯的数据传输方式:单工(单向传输数据),半双工(非同时双向传输),全双工(同时,双向传输) 1. 根据通信方式的不同又分为同步通讯和异步通讯. 同步通讯:所有设备都使用同一个时钟,称为同步时钟.在数据传送时,以若干个数据字符(称为数据块)为单位进行传输,每个数据块包括同步字符.数据块和校验字符CRC. 异步通信是指在串行通信中,接收设备和发送设备有各自的时钟信号,异步通信以字符为单位进行数据传送,不过通信中这些时钟频率必须保持一致. 2. 波特率和比特率 波特率是每秒