我在网上也看了很多的文章,慢慢摸索然后就也做出来了吧。那我就说说如何做的吧。
官方是给出了Android 驱动ch340的jar ,我们只需要下载如何放到lib下面,然后使用它。 下载链接
之后就是包的使用了
使用它我们是用的usb口子,还要手机硬件支持otg 或者usb host 。如何看手机支持不支持这个 在包里面有接口 UsbFeatureSupported() 判断是否支持这个功能
备注:如果你没用普通的Android转otg的线的话你可以自己做一个。当然如果你是Android开发板就不需要了。DIY otg线 链接
有的手机需要在设置里面手动打开otg功能
在AndroidManifest.xml 文件 添加下面代码 添加在你的usb转ttl(can)插入Android系统的时候打开的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" />
device_filter文件在res下的xml 如果没有你创建一个,文件内容为
<?xml version="1.0" encoding="UTF-8"?>
<resource>
<usb-device product-id="29987" vendor-id="6790" />
<usb-device product-id="21795" vendor-id="6790" />
<usb-device product-id="21778" vendor-id="6790" />
</resource>
然后申明权限
判断Android 能否使用otg功能(在这个之前一定要把权限给app)
String ACTION_USB_PERMISSION = "cn.wch.wchusbdriver.USB_PERMISSION";
USB.driver =new CH34xUARTDriver((UsbManager)getSystemService(Context.USB_SERVICE), LoginActivity.this,ACTION_USB_PERMISSION);
if (!USB.driver.UsbFeatureSupported())// 判断系统是否支持USB HOST
{
Toast.makeText(LoginActivity.this,"你的手机不支持USB HOST,请换手机",Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(LoginActivity.this,"完美支持USB HOST",Toast.LENGTH_SHORT).show();
usb_ch340_can usb_ch340_can =new usb_ch340_can();
usb_ch340_can.init();
}
如果你手机支持otg功能的话接下就初始化ch340
int retval = USB.driver.ResumeUsbList();
if (retval==-1)
System.out.println("串口错误1");
else if (retval==0){
if (!USB.driver.UartInit())
System.out.println("串口错误2");
else if( USB.driver.SetConfig(9600,(byte) 1,(byte)8,(byte)0,(byte)0))//波特率 停止位 数据位 parity flowControl
{
System.out.println("串口成功打开");
Message msg=new Message();
msg.obj="串口成功打开";
LoginActivity.msg.sendMessage(msg);
flag=1;
}
else System.out.println("串口错误3");
}
说一下 如果你不知道,这里的USB.driver 是什么 ,那我贴出来一下,知道就不用看这一步
这里是我们的CH34xUARTDriver使用 以后都从这里拿,当然你也可以不这么写
import cn.wch.ch34xuartdriver.CH34xUARTDriver;
/**
* Created by Dear yg on 2019/11/28 23:30.
*/
public class USB extends Application {
public static CH34xUARTDriver driver;//帮助类的生命周期与整个应用程序的生命周期是相同的
}
api简单说明 (来自官方api文档)
EnumerateDevice:枚举 CH34x 设备
函数原型 :public UsbDevice EnumerateDevice()
返回枚举到的 CH34x 的设备,若无设备则返回 null
OpenDevice:打开 CH34x 设备
函数原型 :public void OpenDevice(UsbDevice mDevice)
mDevice :需要打开的 CH34x 设备
ResumeUsbList:枚举并打开 CH34x 设备,这个函数包含了 EnumerateDevice,OpenDevice 操作
函数原型 :public int ResumeUsbList()
返回 0 则成功,否则失败
UartInit:设置初始化 CH34x 芯片
函数原型 :public boolean UartInit()
若初始化失败,则返回 false,成功返回 true
Android Host
CH34x UART
Applications
User Layout
CH34xDriver.jar(lib)
CH34x 串口 Android 程序开发说明 3
SetConfig:设置 UART 接口的波特率、数据位、停止位、奇偶校验位以及流控
函数原型 :public boolean SetConfig(int baudRate, byte dataBit, byte stopBit, byte
parity, byte flowControl)
baudRate :波特率:300,600,1200、2400、4800、9600、19200、38400、57600、115200、
230400、460800、921600,默认:9600
dataBits :5 个数据位、6 个数据位、7 个数据位、8 个数据位,默认:8 个数据位
stopBits :0:1 个停止位,1:2 个停止位,默认:1 个停止位
parity :0:none,1:add,2:even,3:mark 和 4:space,默认:none
flowControl :0:none,1:cts/rts,默认:none
若设置失败,则返回 false,成功返回 true
WriteData:发送数据
函数原型 :public int WriteData(byte[] buf, int length)
buf :发送缓冲区
length :发送的字节数
返回值为写成功的字节数
ReadData:读取数据
函数原型 :public int ReadData(char[] data, int length)
data :接收缓冲区,数据类型为 char
length :读取的字节数
返回实际读取的字节数
函数原型 :public int ReadData(byte[] data, int length)
data :接收缓冲区
length :读取的字节数
返回实际读取的字节数
CloseDevice:关闭串口。
函数原型 :public void CloseDevice()
isConnected:判断设备是否已经连接到 Android 系统
函数原型 :public boolean isConnected()
返回为 false 时表示设备未连接到系统,true 表示设备已连接
除了上述提供的接口 API,用户还可以根据自己的设备来设置读写超时时间:
函数原型:public boolean SetTimeOut(int WriteTimeOut, int ReadTimeOut)
WriteTimeOut:设置写超时时间,默认为 10000ms
ReadTimeOut :设置读超时时间,默认为 10000ms
如果你到这里都没问题 那么可以进行数据的发送测试了。更具api文档说明
使用WriteData()就可以了
public static void WriteData(final String arg){
new Thread(){
@Override
public void run() {
if (flag==1){
//flag_dend=1;
//byte[] to_send = toByteArray(arg+"\n"); //以16进制发送
int retval = USB.driver.WriteData((arg).getBytes(), (arg).getBytes().length);
if (retval < 0)
System.out.println("Write failed!");
else
System.out.println("retval:"+retval+" 发送成功 "+arg);
flag_dend=0;
}
}
}.start();
}
public static void WriteDatabyte(final byte[] data){
new Thread(){
@Override
public void run() {
if (flag==1){
int retval = USB.driver.WriteData(data,data.length);
if (retval < 0)
System.out.println("Write failed!");
else
System.out.println("retval:"+retval+" 发送成功 ");
flag_dend=0;
}
}
}.start();
}
接收
private void ReadData(){
new Thread(){
@Override
public void run() {
if (flag==1){
byte[] buffer = new byte[4096];
while (true) {
if (flag_dend==0){
int length = USB.driver.ReadData(buffer, 4096);
if (length > 0) {
String recv1 = toHexString(buffer, length); //以16进制输出
String recv = new String(buffer, 0, length); //以字符串形式输出
System.out.println(" hex:"+recv1+" arg:"+recv);
// Message msg = new Message();
// msg.obj = recv;
// LoginActivity.msg.sendMessage(msg);
}
}
}
}
}
}.start();
}
在上面串口实验成功之后 我们可以进行can实验了
我买的can模块是维特智能的usb转can 他也是用的ch340 所以在上面的实验成功之后。我们就可以进行can实验了
更具官方给的上位机软件可以看出他是用的AT指令控制(上位机软件怎么来,你再淘宝找一找就可以找到。这里不贴链接)
然后就进行can初始化
private void CAN_init(){
new Thread(){
@Override
public void run() {
if (flag==1){
try {
WriteData("AT+CG\r\n");
Thread.sleep(200);
WriteData("AT+CAN_MODE=0\r\n");
Thread.sleep(200);
WriteData("AT+CAN_FRAMEFORMAT=1,0,1,0\r\n");
Thread.sleep(200);
//WriteData("AT+CAN_FILTER0=1,0,-2097152,-2097152\r\n");//AT+CAN_FILTER0=0,0,-2097152,-2097152
WriteData("AT+CAN_FILTER0=0,0,-2097152,-2097152\r\n");//AT+CAN_FILTER0=0,0,-2097152,-2097152
Thread.sleep(200);
WriteData("AT+CAN_BAUD=125000\r\n");
Thread.sleep(200);
WriteData("AT+ET\r\n");
Thread.sleep(200);
WriteData("AT+AT\r\n");
Thread.sleep(200);
}catch (Exception e){
}
}
}
}.start();
}
这一些AT指令官方没有给出 当时我们在用上位机的时候,你每一次操作他都把指令打印出来的,你使用上位机就可以看到AT指令。
can工作方式不解释 因为太多了
在我们进入数据模式之后,使用WriteDatabyte()方法就可以了
public static void WriteDatabyte(final byte[] data){
new Thread(){
@Override
public void run() {
if (flag==1){
int retval = USB.driver.WriteData(data,data.length);
if (retval < 0)
System.out.println("Write failed!");
else
System.out.println("retval:"+retval+" 发送成功 ");
flag_dend=0;
}
}
}.start();
}
如果能发送了那接收也就简单了。和串口一样。
因为csdn下载附件要币 所以文章展示代码。不多。
这一步你可以不用看
package com.yg.wsb.USB;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Message;
import android.widget.Toast;
import com.yg.wsb.activitys.LoginActivity;
import com.yg.wsb.activitys.MainActivity;
import cn.wch.ch34xuartdriver.CH34xUARTDriver;
/**
* Created by Dear yg on 2019/11/25 16:33.
*/
public class usb_ch340_can {
private static final String ACTION_USB_PERMISSION = "cn.wch.wchusbdriver.USB_PERMISSION";
private static int flag=0;
private static int flag_dend=0;
public void init(){
int retval = USB.driver.ResumeUsbList();
if (retval==-1)
System.out.println("串口错误1");
else if (retval==0){
if (!USB.driver.UartInit())
System.out.println("串口错误2");
else if( USB.driver.SetConfig(9600,(byte) 1,(byte)8,(byte)0,(byte)0))//波特率 停止位 数据位 parity flowControl
{
System.out.println("串口成功打开");
Message msg=new Message();
msg.obj="串口成功打开";
LoginActivity.msg.sendMessage(msg);
flag=1;
}
else System.out.println("串口错误3");
}
ReadData();
CAN_init();
}
public static void WriteData(final String arg){
new Thread(){
@Override
public void run() {
if (flag==1){
//flag_dend=1;
//byte[] to_send = toByteArray(arg+"\n"); //以16进制发送
int retval = USB.driver.WriteData((arg).getBytes(), (arg).getBytes().length);
if (retval < 0)
System.out.println("Write failed!");
else
System.out.println("retval:"+retval+" 发送成功 "+arg);
flag_dend=0;
}
}
}.start();
}
public static void WriteDatabyte(final byte[] data){
new Thread(){
@Override
public void run() {
if (flag==1){
int retval = USB.driver.WriteData(data,data.length);
if (retval < 0)
System.out.println("Write failed!");
else
System.out.println("retval:"+retval+" 发送成功 ");
flag_dend=0;
}
}
}.start();
}
private void CAN_init(){
new Thread(){
@Override
public void run() {
if (flag==1){
try {
WriteData("AT+CG\r\n");
Thread.sleep(200);
WriteData("AT+CAN_MODE=0\r\n");
Thread.sleep(200);
WriteData("AT+CAN_FRAMEFORMAT=1,0,1,0\r\n");
Thread.sleep(200);
//WriteData("AT+CAN_FILTER0=1,0,-2097152,-2097152\r\n");//AT+CAN_FILTER0=0,0,-2097152,-2097152
WriteData("AT+CAN_FILTER0=0,0,-2097152,-2097152\r\n");//AT+CAN_FILTER0=0,0,-2097152,-2097152
Thread.sleep(200);
WriteData("AT+CAN_BAUD=125000\r\n");
Thread.sleep(200);
WriteData("AT+ET\r\n");
Thread.sleep(200);
WriteData("AT+AT\r\n");
Thread.sleep(200);
}catch (Exception e){
}
}
}
}.start();
}
private void ReadData(){
new Thread(){
@Override
public void run() {
if (flag==1){
byte[] buffer = new byte[4096];
while (true) {
if (flag_dend==0){
int length = USB.driver.ReadData(buffer, 4096);
if (length > 0) {
String recv1 = toHexString(buffer, length); //以16进制输出
String recv = new String(buffer, 0, length); //以字符串形式输出
System.out.println(" hex:"+recv1+" arg:"+recv);
// Message msg = new Message();
// msg.obj = recv;
// LoginActivity.msg.sendMessage(msg);
}
}
}
}
}
}.start();
}
/**
* 将byte[]数组转化为String类型
* @param arg
* 需要转换的byte[]数组
* @param length
* 需要转换的数组长度
* @return 转换后的String队形
*/
private String toHexString(byte[] arg, int length) {
String result = new String();
if (arg != null) {
for (int i = 0; i < length; i++) {
result = result
+ (Integer.toHexString(
arg[i] < 0 ? arg[i] + 256 : arg[i]).length() == 1 ? "0"
+ Integer.toHexString(arg[i] < 0 ? arg[i] + 256
: arg[i])
: Integer.toHexString(arg[i] < 0 ? arg[i] + 256
: arg[i])) + " ";
}
return result;
}
return "";
}
/**
* 将String转化为byte[]数组
* @param arg
* 需要转换的String对象
* @return 转换后的byte[]数组
*/
private byte[] toByteArray(String arg) {
if (arg != null) {
/* 1.先去除String中的' ',然后将String转换为char数组 */
char[] NewArray = new char[1000];
char[] array = arg.toCharArray();
int length = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] != ' ') {
NewArray[length] = array[i];
length++;
}
}
/* 将char数组中的值转成一个实际的十进制数组 */
int EvenLength = (length % 2 == 0) ? length : length + 1;
if (EvenLength != 0) {
int[] data = new int[EvenLength];
data[EvenLength - 1] = 0;
for (int i = 0; i < length; i++) {
if (NewArray[i] >= '0' && NewArray[i] <= '9') {
data[i] = NewArray[i] - '0';
} else if (NewArray[i] >= 'a' && NewArray[i] <= 'f') {
data[i] = NewArray[i] - 'a' + 10;
} else if (NewArray[i] >= 'A' && NewArray[i] <= 'F') {
data[i] = NewArray[i] - 'A' + 10;
}
}
/* 将 每个char的值每两个组成一个16进制数据 */
byte[] byteArray = new byte[EvenLength / 2];
for (int i = 0; i < EvenLength / 2; i++) {
byteArray[i] = (byte) (data[i * 2] * 16 + data[i * 2 + 1]);
}
return byteArray;
}
}
return new byte[] {};
}
/**
* 将String转化为byte[]数组
* @param arg
* 需要转换的String对象
* @return 转换后的byte[]数组
*/
private byte[] toByteArray2(String arg) {
if (arg != null) {
/* 1.先去除String中的' ',然后将String转换为char数组 */
char[] NewArray = new char[1000];
char[] array = arg.toCharArray();
int length = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] != ' ') {
NewArray[length] = array[i];
length++;
}
}
NewArray[length] = 0x0D;
NewArray[length + 1] = 0x0A;
length += 2;
byte[] byteArray = new byte[length];
for (int i = 0; i < length; i++) {
byteArray[i] = (byte)NewArray[i];
}
return byteArray;
}
return new byte[] {};
}
/**
* 将String转化为byte[]数组
* @param arg
* 需要转换的String对象
* @return 转换后的byte[]数组
*/
private byte[] toByteArray3(String arg) {
if (arg != null) {
/* 1.先去除String中的' ',然后将String转换为char数组 */
char[] NewArray = new char[1000];
char[] array = arg.toCharArray();
int length = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] != ' ') {
NewArray[length] = array[i];
length++;
}
}
byte[] byteArray = new byte[length];
for (int i = 0; i < length; i++) {
byteArray[i] = (byte)NewArray[i];
}
return byteArray;
}
return new byte[] {};
}
//将byte截取
private byte[] subBytes(byte[] src, int begin, int count) {
byte[] bs = new byte[count];
System.arraycopy(src, begin, bs, 0, count);
return bs;
}
}
package com.yg.wsb.USB;
import android.app.Application;
import cn.wch.ch34xuartdriver.CH34xUARTDriver;
/**
* Created by Dear yg on 2019/11/28 23:30.
*/
public class USB extends Application {
public static CH34xUARTDriver driver;// 需要将CH34x的驱动类写在APP类下面,使得帮助类的生命周期与整个应用程序的生命周期是相同的
}