zoukankan      html  css  js  c++  java
  • 串行通讯之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 HostUSB AccessoryUSB 附件)。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

    这是如何实现的呢?请查看UARTLoopbackAndroidManifest.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)被执行。

    总结:

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

    2onEvent函数是被多线程调用的,更新主界面请使用HandlersendEmptyMessage

    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转串口。

  • 相关阅读:
    匹配域名
    异步加载js文件
    Python3.X BeautifulSoup([your markup], "lxml") markup_type=markup_type))的解决方案
    CSDNmarkdown编辑器直接写代码的小效果(一生愿)
    JAVA_OA(十四)番外:JAVAWEB防止表单重复提交的方法整合(包括集群部署)
    JAVA_OA(十四):SSM练手项目bug-Oracle分页web页面无法转到下一页
    JAVA_OA(十四):SSM练手项目bug-JSP页面传递参数的编码问题
    JAVA_OA(八):springMVC对JDBC的操作小项目b
    完全卸载oracle11g教程、Oracle11g的卸载方法和步骤
    JAVA_OA(八):springMVC对JDBC的操作小项目a
  • 原文地址:https://www.cnblogs.com/hanford/p/6078463.html
Copyright © 2011-2022 走看看