Android车载——串口通信学习

串口简介

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

串口参数

**波特率:**串口传输速率,用来衡量数据传输的快慢,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。波特率与距离成反比,波特率越大传输距离相应的就越短。

**数据位:**这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。如何设置取决于你想传送的信息。

**停止位:**用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

**校验位:**在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。

串口地址

如下表不同操作系统的串口地址,Android是基于Linux的所以一般情况下使用Android系统的设备串口地址为/dev/ttyS0…

串行通讯特点

  • 数据位的传送,按位顺序进行,最少只需一根传输线即可完成;
  • 成本低但传送速度慢。串行通讯的距离可以从几米到几千米;
  • 根据信息的传送方向,串行通讯可以进一步分为单工、半双工和全双工三种。

UART包含TTL电平的串口和RS232电平的串口。

  • TTL电平是3.3V的
  • RS232是负逻辑电平,它定义+5至+12V为低电平,而-12值-5V为高电平,MDS2710、MDS SD4、EL805等是RS232接口,EL806有TTL接口。

通信基本格式

  • 字段 描述 长度(字节)
  • 起始符 0F,十六进制码 1
  • 信息类型 一个字节,十六进制码(0F,F0,FF等保留码不用)1
  • 信息长度 是信息内容的长度,ASCII码表示(09,AF,最大长度为256)(例如长为11个,十六进制是0B,则两个字节就写0x30 0x42)。

注:因为最大长度256不能满足有些指令的要求,所以对长度做了扩展,下面是扩展说明:

如果第一个字节的最高位为1,则表示扩展长度。在扩展长度状态下,其他15个字节通过16进制大端模式来保存长度。

比如:0x80 0x12表示长度为0x001 2,0x81 0x12表示长度为0x0112。

  • 2信息内容 一组十六进制码 N
  • 校验 一个字节,十六进制码,是自信息类型起至对象号止所有码的异或。
  • 1结束符 F0,一个字节,十六进制码 (为了保证可靠性,车机下发的结束符为F0 FF)1

Android实战蓝牙串口通讯

连接蓝牙设备——蓝牙客户端:

Android手机一般以客户端的角色主动连接SPP协议设备(接上蓝牙模块的数字传感器),客户端连接流程是:

1.使用registerReceiver注册BroadcastReceiver来获取蓝牙状态、搜索设备等消息;

  **private** BroadcastReceiver searchDevices = **new** BroadcastReceiver() {
    
     

    **public** **void** onReceive(Context context, Intent intent) {
    
    

      String action = intent.getAction();

      Bundle b = intent.getExtras();

      Object[] lstName = b.keySet().toArray(); 

      // 显示所有收到的消息及其细节

     **for** (**int** i = 0; i < lstName.length; i++) {
    
    

      String keyName = lstName[i].toString();

       Log.*e*(keyName, String.*valueOf*(b.get(keyName)));

      }

      //搜索设备时,取得设备的MAC地址

      **if** (BluetoothDevice.*ACTION_FOUND*.equals(action)) {
    
    

       BluetoothDevice device = intent

          .getParcelableExtra(BluetoothDevice.*EXTRA_DEVICE*);

       String str= device.getName() + "|" + device.getAddress();

       

       **if** (lstDevices.indexOf(str) == -1)// 防止重复添加

        lstDevices.add(str); // 获取设备名称和mac地址

      adtDevices.notifyDataSetChanged();

      }

    }

  };

2.使用BlueAdatper的搜索:btAdapt.startDiscovery();

3.在BroadcastReceiver的onReceive()里取得搜索所得的蓝牙设备信息(如名称,MAC,RSSI);

4.通过设备的MAC地址来建立一个BluetoothDevice对象;

5.由BluetoothDevice衍生出BluetoothSocket,准备SOCKET来读写设备;

6.通过BluetoothSocket的createRfcommSocketToServiceRecord()方法来选择连接的协议/服务,这里用的 是SPP(UUID:00001101-0000-1000-8000-00805F9B34FB);

**try** {
    
       

    *btSocket* = btDev.createRfcommSocketToServiceRecord(uuid);

  } **catch** (IOException e) {
    
    

  // **TODO** Auto-generated catch block

    Log.*e*(*TAG*, "Low: Connection failed.", e);   

  }

成功后进行连接:

**try** {
    
    

  *btSocket*.connect();      

  Log.*e*(*TAG*, " BT connection established, data transfer link open.");

  mangeConnectedSocket(btSocket);//自定义函数进行蓝牙通信处理

} **catch** (IOException e) {
    
    

  Log.*e*(*TAG*, " Connection failed.", e); 

  setTitle("连接失败..");

} 

7.Connect之后(如果还没配对则系统自动提示),使用

BluetoothSocket的getInputStream()和getOutputStream()来读写蓝牙设备。

读写可以归到一个独立线程去实现_~ 注意:读时必须一直循环读取串口缓冲区,写可以不需要。_

按以上7步逐次走过后,你就会发现Android蓝牙模块是多么的坑爹了。

出现问题:

在第6步一般初学者都会报错: 执行.connect()发生异常Connection refused

此时执行不下去咯,怎么办怎么办呢?

于是边debug边网上找攻略,总算在Google出老外的一些做法,尝试了下,貌似还可行。也即把 btSocket的建立方法采用另一种方法替代,这里都使用端口1

Method m;

**try** {
    
    

  m = btDev.getClass().getMethod("createRfcommSocket", **new** Class[] {
    
    **int**.**class**});

  *btSocket* = (BluetoothSocket) m.invoke(btDev, Integer.*valueOf*(1));

       } **catch** (SecurityException e1) {
    
    

         // **TODO** Auto-generated catch block

         e1.printStackTrace();

       } **catch** (NoSuchMethodException e1) {
    
    

         // **TODO** Auto-generated catch block

         e1.printStackTrace();

       } **catch** (IllegalArgumentException e) {
    
    

         // **TODO** Auto-generated catch block

         e.printStackTrace();

       } **catch** (IllegalAccessException e) {
    
    

         // **TODO** Auto-generated catch block

         e.printStackTrace();

      } **catch** (InvocationTargetException e) {
    
    

        // **TODO** Auto-generated catch block

         e.printStackTrace();

      } 

至此,这个问题貌似倒也解决了,程序继续往下跑。

但这里请记住之前的异常,先别急着抛开~人家不一定一直都是异常哦。

接下来的任务是,让手机通过蓝牙跟单片机的蓝牙模块通信,并发送数据,通过电脑串口调试助手显示出来。具体实现,在mangeConnectedSocket(btSocket)方法中实现,里面通过启动另一个Activity实现。不是重点,略过。

直到这里,我们都只是把手机蓝牙模块充当客户端来使用,那什么时候会用到服务端呢?其实,之前手机蓝牙与单片机蓝牙模块的通信,单片机蓝牙模块就充当了服务端(处于监听状态,被手机蓝牙连接)。为了更好地搞清楚Android蓝牙通信,我们接下来使用2个手机的蓝牙进行通信。简单地说,就是做一个“手机蓝牙扣扣”,⊙﹏⊙b汗

一开始就想天真地把之前的程序同时烧到2部手机中,发现只有一部手机能正常建立socket连接(主动连接的那台),而另一部却迟迟没有响应。原因很简单,服务端的程序还没有编写!

于是,开始服务端程序:开辟一个新的线程实现

连接蓝牙设备——蓝牙服务端:

  **class** AcceptThread **extends** Thread {
    
    

  **private** **final** BluetoothServerSocket serverSocket;

  **public** AcceptThread() {
    
    

    // Use a temporary object that is later assigned to mmServerSocket,

    // because mmServerSocket is final 

  BluetoothServerSocket tmp=**null**;

  **try** {
    
    

//tmp = btAdapt.listenUsingRfcommWithServiceRecord("MyBluetoothApp", uuid);

  Log.*e*(*TAG*, "++BluetoothServerSocket established!++");

 Method listenMethod =     btAdapt.getClass().getMethod("listenUsingRfcommOn",

  **new**  Class[]{
    
    **int**.**class**});

  tmp = ( BluetoothServerSocket) listenMethod.invoke(btAdapt,                          Integer.*valueOf*( 1));

    

    } **catch** (SecurityException e) {
    
    

      // **TODO** Auto-generated catch block

      e.printStackTrace();

   } **catch** (IllegalArgumentException e) {
    
    

     // **TODO** Auto-generated catch block

      e.printStackTrace();

    } **catch** (NoSuchMethodException e) {
    
    

      // **TODO** Auto-generated catch block

      e.printStackTrace();

   } **catch** (IllegalAccessException e) {
    
    

     // **TODO** Auto-generated catch block

      e.printStackTrace();

   } **catch** (InvocationTargetException e) {
    
    

      // **TODO** Auto-generated catch block

     e.printStackTrace();

   }

    serverSocket=tmp;

  }  

  **public** **void** run() {
    
    

    

    // Keep listening until exception occurs or a socket is returned

     //mState!=STATE_CONNECTED

  **while**(**true**) {
    
    //这里是一直循环监听,也可以设置mState来判断

    **try** {
    
    

      *socket* = serverSocket.accept();

      Log.*e*(*TAG*, "++BluetoothSocket established! DataLink open.++");

      } **catch** (IOException e) {
    
    

        **break**;

      }

      // If a connection was accepted

      **if** (*socket* != **null**) {
    
    

        // Do work to manage the connection (in a separate thread)

        manageConnectedSocket();  

        **try** {
    
    

         serverSocket.close();

       } **catch** (IOException e) {
    
    

         // **TODO** Auto-generated catch block

        e.printStackTrace();

       }

        **break**;

      }

    }    

}

  **public** **void** cancel() {
    
    

    **try** {
    
    

      serverSocket.close();

    } **catch** (IOException e) {
    
     }

  }

}

**安装测试:**当2部手机都装上并打开同样的程序后,通过蓝牙检索并连接,经测试可以成功连接上,双双进入“聊天界面”,嘿嘿

注意,这时候重新拾回之前那个异常,把socket连接建立的方法重新改为

*btSocket* = btDev.createRfcommSocketToServiceRecord(uuid);//客户端

对应的服务端程序:

*tmp* = btAdapt.listenUsingRfcommWithServiceRecord("MyBluetoothApp", *uuid*);//服务端

这样继续重新运行安装测试,在2部手机上运行发现之前那个bug消失了~2部手机又双双进入聊天界面。

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓

猜你喜欢

转载自blog.csdn.net/YoungOne2333/article/details/130031777