由于项目需要,最近用CH340芯片做了一款Android设备上的OTG产品,技术含量不大,但是为了以后查阅方便,同时希望帮助其他人,现总结如下,想到哪里就写到哪里,请大家勿怪。
注意:
1、Android系统版本必须是3.1以上,3.1版本及以上才支持USB HOST协议;
2、Android设备如手机、平板等的Micro-USB的ID是悬空的,所以OTG的从设备的ID必须接地;
3、打开OTG设备之前,必须先允许设备,否则会产生运行时错误;
4、先打开OTG设备,在进行串口配置;切更改串口配置时候,不需要close->open->config流程,直接config即可;
5、官方驱动下载地址:http://download.csdn.net/detail/wuhenyouyuyouyu/9678373
该驱动包包括:1、驱动库; 2、驱动库说明; 3、官方DEMO源码,Android studio v2.2.2版本; 4、一款官方APP调试工具;
一、添加官方驱动包CH34xUARTDriver.jar
1、把官方驱动包拷贝到:xxx\app\libs;
2、把驱动包加入到工程中:
二、添加xml文件
1、新建xml资源文件夹:
res->右键 new->Android resource directory
选择xml,点击OK。
2、将device_filter.xml文件拷贝到:xxx\app\src\main\res\xml\内;
三、修改Mainfest.xml文件
1、添加:
<!-- USB权限 -->
<uses-feature android:name="android.hardware.usb.host" />
<uses-sdk
android:minSdkVersion="12"
android:targetSdkVersion="19" />
2、在activity属性内添加
<intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
四、判断设备是否支持USB HOST
public boolean myOTG_CheckHOST(final Activity activity,boolean isShow) { if (!MyOTGApplication.driver.UsbFeatureSupported())// 判断系统是否支持USB HOST { if(isShow) { Dialog dialog = new AlertDialog.Builder(activity) .setTitle("提示") .setMessage("您的手机不支持USB HOST,请更换其他手机再试!") .setPositiveButton("确认", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { System.exit(0); } }).create(); dialog.setCanceledOnTouchOutside(false); dialog.show(); } return false; } //activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);// 保持常亮的屏幕的状态 return true; }五、打开设备
private boolean myOTG_Open(final Activity activity,boolean isShow){ if (!MyOTGApplication.driver.ResumeUsbList())// ResumeUsbList方法用于枚举CH34X设备以及打开相关设备 { if(isShow) { Toast.makeText(activity, "打开设备失败!", Toast.LENGTH_SHORT).show(); } MyOTGApplication.driver.CloseDevice(); return false; } else { if (!MyOTGApplication.driver.UartInit()) {//对串口设备进行初始化操作 if(isShow) { Toast.makeText(activity, "设备初始化失败!", Toast.LENGTH_SHORT).show(); Toast.makeText(activity, "打开" + "设备失败!", Toast.LENGTH_SHORT).show(); } return false; } if(isShow) { Toast.makeText(activity, "打开设备成功!", Toast.LENGTH_SHORT).show(); } isOpen = true; new readThread().start();//开启读线程读取串口接收的数据 return true; } }六、配置
//配置串口,先打开OTG,再配置串口; //重新配置串口时候,不需要Close->open->config,直接Config即可 private boolean myOTG_SetConfig(final Activity activity,boolean isShow){ if (MyOTGApplication.driver.SetConfig(baudRate, dataBit, stopBit, parity, flowControl)) {//配置串口波特率,函数说明可参照编程手册 if(isShow) { Toast.makeText(activity, "串口设置成功!", Toast.LENGTH_SHORT).show(); } return true; } else { if(isShow) { Toast.makeText(activity, "串口设置失败!", Toast.LENGTH_SHORT).show(); } return false; } }七、关闭
public void myOTG_Close(){ isOpen = false; MyOTGApplication.driver.CloseDevice(); myMath.showToast(myOTG_activity,"串口关闭成功!",200); }八、读
private class readThread extends Thread { public void run() { byte[] buffer = new byte[64]; int length =0; while (true) { Message msg = Message.obtain(); if (!isOpen) { break; } length = MyOTGApplication.driver.ReadData(buffer, 64); if (length > 0) { //String recv = myMath.toHexString(buffer, length); msg.what=3;//OTG接收线程 msg.arg1=length; msg.obj = buffer; OTGHandler.sendMessage(msg); length=0; } } } }九、写
public boolean myOTG_writeBuffer(byte[] to_send){ //byte[] to_send = toByteArray(writeText.getText().toString()); if(null != writeData){//正在发送,请等待 return false; } int retval = MyOTGApplication.driver.WriteData(to_send, to_send.length);//写数据,第一个参数为需要发送的字节数组,第二个参数为需要发送的字节长度,返回实际发送的字节长度 if (retval < 0) { return false; } return true; }十、注册USB消息,并监听USB设备插拔
public void startListen(Context context) //USB枚举消息注册函数 { IntentFilter usbDeviceStateFilter = new IntentFilter(); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); usbDeviceStateFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); context.registerReceiver(mUsbReceiver, usbDeviceStateFilter); } /*********************************************************************** * 问题: * 1、收到OTG插拔消息后,应该进行PID和VID检查,在进行操作; * 2、 **********************************************************************/ private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { // call your method that cleans up and closes communication with the device if(isOpen){ myOTG_Close(); } } }else{ if(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)){ UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (device != null) { // call your method that cleans up and closes communication with the device if(!isOpen){ myOTG_Open(true); } } } } } };十一、读取XML文件
private boolean UsbDeviceFilter(DeviceFilter inDevice) throws XmlPullParserException, IOException { Resources myResources = myOTG_activity.getResources(); XmlResourceParser parser = myResources.getXml(R.xml.device_filter); int eventType = parser.getEventType(); // 获取事件类型 while (eventType != XmlPullParser.END_DOCUMENT) { String tagName = parser.getName(); if ("usb-device".equals(tagName) && parser.getEventType() == XmlPullParser.START_TAG) { DeviceFilter findDevice = new DeviceFilter(-1,-1,-1,-1,-1); findDevice.readXML(parser); if( (inDevice.mVendorId == findDevice.mVendorId) && (inDevice.mProductId == findDevice.mProductId) && (inDevice.mVendorId != -1)){ return true; } } eventType = parser.next(); } return false; }