安卓串口通信!可移植!
demo地址
安卓串口实在太难调了
去网上参考了好多demo,才完成了串口调试的小app
而且亲自试了一下移植,是可以成功的
大体思路如下:
1.导入.so文件
什么是.so文件:
.so文件是Unix的动态连接库,本身是二进制文件,是由C/C++编译而来的。
Android调用.so文件的过程也就是所谓的JNI了。在Android中想要调用C/C++中的API的话,也就是调用.so文件了。
2.下面的两个类封装了查找设备端口以及打开/关闭串口的方法,都是谷歌官方代码,其中:
SerialPort类的作用为,JNI的调用,用来加载.so文件,获取串口输入输出流,通过操作IO流,达到能够利用串口接收数据和发送数据的目的
SerialPortFinder这个类是用来获取串口物理地址的,其实一般是用不到这个类的,因为硬件设备上串口的物理地址,在硬件上都是有具体标识的,你直接使用就可以了,我这里安卓pad的串口物理地址是:“dev/ttyMT3”
这里也附上串口物理地址获取代码:
获取串口物理地址:
//获取所有串口名字
//String[]devices=newSerialPortFinder().getDevices();
获取所用串口地址
//String[]devicesPath=newSerialPortFinder().getDevicesPaths();
for(Stringpath:devicesPath){
Log.e("tag",path);
}
for(Stringdevice:devices){
Log.e("tag",device);
}
jni文件夹下有它们需要用到的c文件源码
3.对串口收到的数据进行类型转换的类
4.串口操作类:
其中SerialPortBuilder是设置串口初始化各项参数的类
SerialPortService是设置串口收发数据逻辑的类
效果如下:
电脑端:
将串口部分移植到其他工程的步骤如下:
1.在需要移植的项目上如下操作:将serialportLibrary项目作为库引入此项目
2.文件管理中找到此工程下的serialportLibrary文件夹的位置,点击finish(此处因为我以经引入了所以提示module已经存在)
3.设定引入的包:
Build gradle文件dependicies中加入:
4.在对应的显示activity里面加入以下代码:
引入包:
import com.serialportlibrary.service.impl.SerialPortBuilder;
import com.serialportlibrary.service.impl.SerialPortService;
activity内部变量声明:
public static boolean sendFlag ;
SerialPort myPort=new SerialPort();
onCreate()方法中加入:
myPort.startPort();
myPort.sendMessage();
myPort.receiveMessage();
或者自己写按钮来启动,我是这样写的:
@Override
public void onClick(View v) {
if(v==open){
myPort.startPort();
myPort.receiveMesage();
}
if (v==send){
sendFlag=true;
String str=sendtext.getText().toString();
myPort.sendMessage(str);
}
if(v==close){
sendFlag=false;
myPort.closePort();
}
}
Activity 内部类:
class SerialPort {
private byte[] mBuffer;
private Handler handler;
SerialPortService serialPortService;
//开启串口
public void startPort(){
serialPortService = new SerialPortBuilder()
.setTimeOut(100L)
.setBaudrate(115200)
.setDevicePath("dev/ttyMT3")
.createService();
serialPortService.isOutputLog(true);}
public void sendMessage(final String receiveString){
//发数据的线程
new Thread(new Runnable() {
@Override
public void run() {
if (sendFlag){
byte[] sendData = receiveString.getBytes();
serialPortService.sendData(sendData);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public void receiveMesage(){
handler = new Handler(); //创建主线程的handler 用于接收数据时更新UI
serialPortService.setOnDataReceiveListener(new SerialPortService.OnDataReceiveListener() {
@Override
public void onDataReceive(byte[] buffer, int size) {
Log.d("tag", "进入数据监听事件 "+new String(buffer));
mBuffer = buffer;
handler.post(runnable);//利用handler将数据传递到主线程
}
//开线程更新UI
Runnable runnable = new Runnable() {
@Override
public void run() {
//串口数据里面实际上存的是二进制数据
//String mString=ByteStringUtil.byteArrayToHexStr(mBuffer);
String myString=new String(mBuffer);
//String myStrings=ByteStringUtil.convertbyteToASCII(mBuffer);
byte[] myByte=new byte[]{0x6,'2'};
//如果byte[]里面是十六进制数,则会转化成十进制,如果是字符则会转成十进制的ASCII码的值,其实都是二进制保存的
Log.e("tag", Arrays.toString(myByte)+myByte.length);
Log.e("tag", Arrays.toString(mBuffer)+mBuffer.length);//遍历打印:[35, 52, 69],打印的是10进制数据
//也就是如果按照这个值转成字符串的话,会对应着转成这个值的ascii码对应的字符
receivetext.setText("size:"+ (mBuffer.length-1)+"\n"+"数据监听:"+ myString);
}
};
});
}
public void closePort(){
serialPortService.close();
}
}
移植的时候可能会出现以下错误:
网上的解释如下:(实际上是android 7.0 加载system.loadLibrary崩溃事件解决–.so文件缺失——实际上是因为so文件冲突)
由于引入的库中有多个平台的.so文件,而和本地自己的工程编译进去的平台个数和种类不一样,根据jni的规则,平台文件夹下的so文件,必须是一一对应的,不能少,简单粗暴的办法是,删除掉不需要平台的so、或者补全其他平台的so文件。
解决方法:查看自己的工程所依赖的平台然后对应的引入的库里面的libs里只留下一个:(比如可以只留下armeabi-v7a)