由于近日在做关于用安卓手机端用串口配置调试底层设备,底层设备的通信接口为RS485通信方式,严格遵从modebus协议。此为大前提,如何通过安卓手机端完成这一工作,首先有两种方式: 1、OTG功能与底层连接; 2、无需OTG功能; 根据现在的安卓机中带有OTG功能手机所占的份额不是很大,因此,本项目选择无需OTG的通信方式。项目选择的设备为FT311D芯片的力特Z-TEK的android转RS232的设备为硬件通信设备。安卓端编程如下:首先将这个驱动芯片的类导入到工程
- <span style="background-color: rgb(255, 255, 255); ">public UsbManager usbmanager;</span>
复制代码
这里有几个对象要注意下,这是usb通信中用到的对象,然后定义输入输出流,定义各种缓存数组,这里的maxnumbytes = 65536是最大字节数,是用于限制数据中最大不能超过2的16次方。下面注意的一点是在构造函数中要将USB通信挂起,这必须要在构造函数完成,先获取usb服务,用PendingIntent对象中的getBroadcast 的方法去注册我们定义的服务。然后判断usb是否连接,这里当usb设备拔出的时候会抛出一个action值为UsbManager.ACTION_USB_DEVICE_DETACHE,注册一个广播接收即可,同理当我们插入usb的时候也会自动的识别,然后输入输出流初始化为空。
- /*********************** USB 处理 ******************************************/
- usbmanager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
- mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(
- ACTION_USB_PERMISSION), 0);
- IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
- filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
- context.registerReceiver(mUsbReceiver, filter);
- inputstream = null;
- outputstream = null;
复制代码
- </blockquote></div> 编写串口通信的基本配置函数,如下<div class="blockcode"><blockquote>public void SetConfig(int baud, byte dataBits, byte stopBits, byte parity,
- byte flowControl) {
-
- /* 准备波特率缓冲区 */
- writeusbdata[0] = (byte) baud;
- writeusbdata[1] = (byte) (baud >> 8);
- writeusbdata[2] = (byte) (baud >> 16);
- writeusbdata[3] = (byte) (baud >> 24);
- /* 数据位 */
- writeusbdata[4] = dataBits;
- /* 停止位 */
- writeusbdata[5] = stopBits;
- /* 校验位 */
- writeusbdata[6] = parity;
- /* 流控制 */
- writeusbdata[7] = flowControl;
- /* 发送UART配置包 */
- SendPacket((int) 8);
- Log.v(TGA, baud + "," + dataBits + "," + stopBits + "," + parity + ","
- + flowControl);
- }
复制代码
这里的形参(int baud, byte dataBits, byte stopBits, byte parity,byte flowControl )分别代表串口的波特率、数据位、停止位、校验位、流控制。下面我简要说一下这几个参数: 1、波特率,代表通信过程中的传输速率,单位为bit/s,顾名思义也就是每秒钟传输多少位; 2、数据位,代表一次通信过程中传输的数据有多少个位(也可称一帧数据中数据位),一般分为两种7位或者8位,以8位用的最多; 3、停止位,就是我们所说的帧尾,这一位用于表示数据的截止,通信中一般用一位,但是对网络媒体通信中也可出现两位; 4、校验位,是将我们的一帧数据做校验,有无、奇校验、偶校验、MARK校验、SPACE校验几种; 5、流控制,指的是通信中的数据流,一般选择无即默认情况,但是在硬件的控制流中也会出现RTS/CTS流模式;
- /* 发送函数 */
- public byte SendData(int numBytes, byte[] buffer) {
- /* 状态标志 */
- status = 0x00; /* 默认情况为成功 */
- /*
- * 如果超过最大限度num字节
- */
- if (numBytes < 1) {
- /* 返回的状态错误的命令 */
- return status;
- }
-
- /* 检查最大字节限制 */
- if (numBytes > 256) {
- numBytes = 256;
- }
-
- /* 准备要发送的数据包 */
- for (int count = 0; count < numBytes; count++) {
- writeusbdata[count] = buffer[count];
- }
-
- if (numBytes != 64) {
- SendPacket(numBytes);
- } else {
- byte temp = writeusbdata[63];
- SendPacket(63);
- writeusbdata[0] = temp;
- SendPacket(1);
- }
-
- return status;
- }
复制代码
发送函数,这里就是用于数据的发送,故就不详细说明了。下面是接受函数也不做说明了,
- /* 读取数据 */
- public byte ReadData(int numBytes, byte[] buffer, int[] actualNumBytes) {
- status = 0x00; /* 默认情况下成功 */
-
- /* 至少读取一个字节数据 */
- if ((numBytes < 1) || (totalBytes == 0)) {
- actualNumBytes[0] = 0;
- status = 0x01;
- return status;
- }
-
- /* 检查最大字节限制 */
- if (numBytes > totalBytes)
- numBytes = totalBytes;
-
- /* 更新可用的字节数 */
- totalBytes -= numBytes;
-
- actualNumBytes[0] = numBytes;
-
- /* 复制到用户缓冲区 */
- for (int count = 0; count < numBytes; count++) {
- buffer[count] = readBuffer[readIndex];
- readIndex++;
- /*
- * 拷贝到用户读取缓冲区,看是否超过什么 所以没有需要去检查溢出
- */
- readIndex %= maxnumbytes;
- }
- return status;
- }
复制代码
然后就是usb的广播函数,在前面我们注册的,这里的功能就是告诉安卓设备让不让我注册usb通信,让就在调试那里把允许调试打开,然后将自己电脑的调试指纹发送到手机中,我们会看到安卓设备会弹出一个界面。一堆指纹问你允不允许,这里想要通信的我建议允许,哈哈
- /*********** USB广播接收器 *******************************************/
- private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (ACTION_USB_PERMISSION.equals(action)) {
- synchronized (this) {
- UsbAccessory accessory = (UsbAccessory) intent
- .getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
- if (intent.getBooleanExtra(
- UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
- Toast.makeText(global_context, "允许USB许可",
- Toast.LENGTH_SHORT).show();
- OpenAccessory(accessory);
- } else {
- Toast.makeText(global_context, "否认USB许可",
- Toast.LENGTH_SHORT).show();
- Log.d("LED", "permission denied for accessory "
- + accessory);
-
- }
- mPermissionRequestPending = false;
- }
- } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
- saveDetachPreference();
- DestroyAccessory(true);
-
- } else {
- Log.d("LED", "....");
- }
- }
- };
复制代码
然后就是我们的DestroyAccessory(true);函数就是注销函数如下所示:
- /* 注销 */
- public void DestroyAccessory(boolean bConfiged) {
-
- if (true == bConfiged) {
- READ_ENABLE = false; // 设置错误条件handler_thread退出等待数据循环
- writeusbdata[0] = 0;
- SendPacket(1);
- } else {
- SetConfig(9600, (byte) 1, (byte) 8, (byte) 0, (byte) 0); // 发送默认设置数据配置
-
- try {
- Thread.sleep(10);
- } catch (Exception e) {
- }
-
- READ_ENABLE = false; // 设置错误条件handler_thread退出等待数据循环
- writeusbdata[0] = 0; // send dummy data for instream.read going
- SendPacket(1);
- if (true == accessory_attached) {
- saveDefaultPreference();
- }
- }
-
- try {
- Thread.sleep(10);
- } catch (Exception e) {
- }
- CloseAccessory();
- }
复制代码
最后开辟一个线程用于处理usb通信
- /* usb输入数据处理程序 */
- private class read_thread extends Thread {
- FileInputStream instream;
-
- read_thread(FileInputStream stream) {
- instream = stream;
- this.setPriority(Thread.MAX_PRIORITY);
- }
-
- public void run() {
- while (READ_ENABLE == true) {
- while (totalBytes > (maxnumbytes - 1024)) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- try {
- if (instream != null) {
- readcount = instream.read(usbdata, 0, 1024);
- if (readcount > 0) {
- for (int count = 0; count < readcount; count++) {
- readBuffer[writeIndex] = usbdata[count];
- writeIndex++;
- writeIndex %= maxnumbytes;
- }
-
- if (writeIndex >= readIndex)
- totalBytes = writeIndex - readIndex;
- else
- totalBytes = (maxnumbytes - readIndex)
- + writeIndex;
-
- // Log.e(">>@@","totalBytes:"+totalBytes);
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
复制代码
这个类先讲到这里,还有很多类,光它不会通信的(*^__^*) 嘻嘻……。下次我会继续讲解下面我们要在怎么做了,我会将它做成一个系列告诉大家一步一步的完成我现在做的这个项目后面更精彩哦!本人是开发者交流版块的版主看到排名下降,希望亲们感觉不错多多支持我们的版块哦。谢谢亲们 ~小轩,对了先附几张我软件的界面图吧,让大家了解一下~~~ |