Android串口通信
1. 解析SerialPort API 串口通信例子
首先分析一下例子中的类结构 :
通过类结构可知,最主要的还是在SerialPortJNI.java 类 ,该类写了一些Native 方法处理打开与关闭 串口 接收 发送的
SerialPort.Java 代码如下 :
packagecom.dwin.navy.serialportapi;
importjava.io.FileDescriptor;
importandroid.util.Log;
/**
*串口JNI
*
*@authordwin
*
*/
publicclassSerialPortJNI{
static{
Log.i("NativeClass","beforeloadlibrary");
System.loadLibrary("serialport");
Log.i("NativeClass","afterloadlibrary");
}
publicFileDescriptormFd;
publicStringmDevNum;
publicintmSpeed;
publicintmDataBits;
publicintmStopBits;
publicintmParity;
publicintRS485ModFp=-1;
publicstaticintRS485Read=0;
publicstaticintRS485Write=1;
publicnativeintsetSpeed(FileDescriptorfd,intspeed);
publicnativeintsetParity(FileDescriptorfd,intdataBits,intstopBits,
intparity);
publicnativeFileDescriptoropenDev(StringdevNum);
publicnativeFileDescriptoropen485Dev(StringdevNum);
publicnativeintcloseDev(FileDescriptorfd);
publicnativeintclose485Dev(FileDescriptorfd);
publicnativeintreadBytes(FileDescriptorfd,byte[]buffer,intlength);
publicnativebooleanwriteBytes(FileDescriptorfd,byte[]buffer,
intlength);
publicnativeintset485mod(intmode);
}
红色区域 先申明一个static 静态域 加载.so 动态库文件 .so通过JNI方式生成 保存在libs目录下 ,由于本例子使用的cpu为 mips(默认为arm) 所以 .so库文件 将存入mips文件夹下
还有打开串口,关闭串口,485模式下开关方式 ,接收 与发送 byte
1> SerialPort API 处理了接收与发送 文本与十六进制 两种模式下接收与发送数据
UI布局如下 :
2>在电脑中插入usb转串口工具 ,然后在app中打开串口
SerialPortOpt.java 继承了 SerialPortJNI.Java 类 调用相应的JNI接口
SerialPortOpt.java 类大致如下 :
packagecom.dwin.navy.serialportapi;
importjava.io.FileDescriptor;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.io.InputStream;
importjava.io.OutputStream;
importandroid.util.Log;
/**
*调用JNI的串口
*
*@authordwin
*
*/
publicclassSerailPortOptextendsSerialPortJNI{
privatestaticfinalStringTAG="SerialPort";
privateFileInputStreammFileInputStream;
privateFileOutputStreammFileOutputStream;
publicFileDescriptoropenDev(StringdevNum){
super.mFd=super.openDev(devNum);
if(super.mFd==null){
Log.e(TAG,"nativeopenreturnsnull");
returnnull;
}
mFileInputStream=newFileInputStream(super.mFd);
mFileOutputStream=newFileOutputStream(super.mFd);
returnsuper.mFd;
}
publicFileDescriptoropen485Dev(StringdevNum){
super.mFd=super.open485Dev(devNum);
if(super.mFd==null){
Log.e(TAG,"nativeopenreturnsnull");
returnnull;
}
mFileInputStream=newFileInputStream(super.mFd);
mFileOutputStream=newFileOutputStream(super.mFd);
returnsuper.mFd;
}
publicInputStreamgetInputStream(){
returnmFileInputStream;
}
publicOutputStreamgetOutputStream(){
returnmFileOutputStream;
}
publicintsetSpeed(FileDescriptoroptFd,intspeed){
returnsuper.setSpeed(optFd,speed);
}
publicintsetParity(FileDescriptoroptFd,intdatabits,intstopbits,
intparity){
returnsuper.setParity(optFd,databits,stopbits,parity);
}
publicintcloseDev(FileDescriptoroptFd){
intretStatus;
retStatus=super.closeDev(optFd);
super.mFd=null;
returnretStatus;
}
publicintclose485Dev(FileDescriptoroptFd){
intretStatus;
retStatus=super.close485Dev(optFd);
super.mFd=null;
returnretStatus;
}
publicintreadBytes(FileDescriptorfd,byte[]buffer,intlength){
returnsuper.readBytes(fd,buffer,length);
}
publicbooleanwriteBytes(FileDescriptorfd,byte[]buffer,intlength){
returnsuper.writeBytes(fd,buffer,length);
}
publicintreadBytes(FileDescriptorfd,byte[]buffer){
returnsuper.readBytes(fd,buffer,buffer.length);
}
publicbooleanwriteBytes(FileDescriptorfd,byte[]buffer){
returnsuper.writeBytes(fd,buffer,buffer.length);
}
publicintreadBytes(byte[]buffer){
returnsuper.readBytes(mFd,buffer,buffer.length);
}
publicbooleanwriteBytes(byte[]buffer){
returnsuper.writeBytes(mFd,buffer,buffer.length);
}
publicintread485Bytes(FileDescriptorfd,byte[]buffer,intlength){
returnsuper.readBytes(fd,buffer,length);
}
publicbooleanwrite485Bytes(FileDescriptorfd,byte[]buffer,intlength){
booleanret;
super.set485mod(RS485Write);
ret=super.writeBytes(fd,buffer,length);
super.set485mod(RS485Read);
returnret;
}
publicintread485Bytes(FileDescriptorfd,byte[]buffer){
returnsuper.readBytes(fd,buffer,buffer.length);
}
publicbooleanwrite485Bytes(FileDescriptorfd,byte[]buffer){
booleanret;
super.set485mod(RS485Write);
ret=super.writeBytes(fd,buffer,buffer.length);
super.set485mod(RS485Read);
returnret;
}
publicintread485Bytes(byte[]buffer){
returnsuper.readBytes(mFd,buffer,buffer.length);
}
publicbooleanwrite485Bytes(byte[]buffer){
booleanret;
super.set485mod(RS485Write);
ret=super.writeBytes(mFd,buffer,buffer.length);
super.set485mod(RS485Read);
returnret;
}
}
在openDev(String str)方法中调用父类的方法 ,将返回一个文件描述对象FileDescriptor ,然后初始化FileInputStream,FileOutputStream 输入输出IO流对象 ,
还有读写byte字节数组的方法
3>申明或者实例化一个类用来调用和实现 这些方法 前两个类只是申明 相应的方法并没有实现相应的方法体
定义一个SerialPort 类
SerialPort.Java :
packagecom.dwin.dwinapi;
importjava.io.FileDescriptor;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.UnsupportedEncodingException;
importcom.dwin.navy.serialportapi.SerailPortOpt;
importandroid.content.Context;
importandroid.util.Log;
/**
*自定义串口对象
*
*@authorF
*
*/
publicclassSerialPort{
Contextcontext;
/**
*自定义串口对象
*/
privatestaticSerialPortserialPort;
/**
*调用JNI的串口
*/
privateSerailPortOptserialportopt;
/**
*读取数据线程
*/
/**
*串口接收到的流
*/
privateInputStreammInputStream;
/**
*用来判断串口是否已打开
*/
publicbooleanisOpen=false;
/*
*接收到的数据
*/
Stringdata;
/**
*实例化并打开串口对象
*
*@paramdevNum
*串口号S0,S1,S2,S3,S4
*@paramdataBits
*数据位
*@paramspeed
*波特率
*@paramstopBits
*停止位
*@paramparity
*校验位
*/
publicSerialPort(StringdevNum,intspeed,intdataBits,intstopBits,
intparity){
serialportopt=newSerailPortOpt();
openSerial(devNum,speed,dataBits,stopBits,parity);
}
/**
*打开串口时传入参数,可以指定打开某个串口,并设置相应的参数
*
*@paramdevNum
*串口号COM0,COM1,COM2,COM3,COM4
*@paramdataBits
*数据位
*@paramspeed
*波特率
*@paramstopBits
*停止位
*@paramparity
*校验位
*@return
*/
privatebooleanopenSerial(StringdevNum,intspeed,intdataBits,
intstopBits,intparity){
serialportopt.mDevNum=devNum;
serialportopt.mDataBits=dataBits;
serialportopt.mSpeed=speed;
serialportopt.mStopBits=stopBits;
serialportopt.mParity=parity;
//打开串口
FileDescriptorfd=serialportopt.openDev(serialportopt.mDevNum);
if(fd==null){
returnfalse;//串口打开失败
}else{
//设置串口参数
serialportopt.setSpeed(fd,speed);
serialportopt.setParity(fd,dataBits,stopBits,parity);
mInputStream=serialportopt.getInputStream();
isOpen=true;
returntrue;
}
}
/**
*关闭串口
*/
publicvoidcloseSerial(){
if(serialportopt.mFd!=null){
serialportopt.closeDev(serialportopt.mFd);
isOpen=false;
}
}
/**
*发送数据
*
*@paramdata
*数据内容
*/
publicvoidsendData(Stringdata,Stringtype){
try{
serialportopt.writeBytes(type.equals("HEX")?HexString2Bytes(data
.length()%2==1?data+="0":data.replace("",""))
:HexString2Bytes(toHexString(data)));
}catch(Exceptione){
}
}
/**
*接收数据
*
*@param收发数据类型
*@return接收到的字符串
*/
publicStringreceiveData(Stringtype){
byte[]buf=newbyte[1024];
intsize;
if(mInputStream==null){
returnnull;
}
size=serialportopt.readBytes(buf);
if(size>0){
try{
data=type.equals("HEX")?bytesToHexString(buf,size)
:newString(buf,0,size,"gb2312").trim().toString();
}catch(UnsupportedEncodingExceptione){
e.printStackTrace();
}
returndata;
}else{
returnnull;
}
}
/**
*转化字符串为十六进制编码
*
*@params
*@return
*/
privateStringtoHexString(Strings){
Stringstr="";
for(inti=0;i<s.length();i++){
intch=(int)s.charAt(i);
Strings4=Integer.toHexString(ch);
str=str+s4;
}
returnstr;
}
/**
*将指定字符串src,以每两个字符分割转换为16进制形式如:"2B44EFD9"-->byte[]{0x2B,0x44,0xEF,
*0xD9}
*
*@paramsrc
*String
*@returnbyte[]
*/
privatestaticbyte[]HexString2Bytes(Stringsrc){
byte[]ret=newbyte[src.length()/2];
byte[]tmp=src.getBytes();
for(inti=0;i<tmp.length/2;i++){
ret[i]=uniteBytes(tmp[i*2],tmp[i*2+1]);
}
returnret;
}
/**
*将Hex数组转换为Hex字符串
*
*@paramsrc
*@paramsize
*@return
*/
publicstaticStringbytesToHexString(byte[]src,intsize){
Stringret="";
if(src==null||size<=0){
returnnull;
}
for(inti=0;i<size;i++){
Stringhex=Integer.toHexString(src[i]&0xFF);
if(hex.length()<2){
hex="0"+hex;
}
hex+="";
ret+=hex;
}
returnret.toUpperCase();
}
/**
*将两个ASCII字符合成一个字节;如:"EF"-->0xEF
*
*@paramsrc0
*byte
*@paramsrc1
*byte
*@returnbyte
*/
privatestaticbyteuniteBytes(bytesrc0,bytesrc1){
byte_b0=Byte.decode("0x"+newString(newbyte[]{src0}))
.byteValue();
_b0=(byte)(_b0<<4);
byte_b1=Byte.decode("0x"+newString(newbyte[]{src1}))
.byteValue();
byteret=(byte)(_b0^_b1);
returnret;
}
}
剩下的就是MainActivty中 ,打开串口 创建两个线程,ReceiverThread,SendThread 先 ,Handler 异步更新UI
privateHandlermHandler=newHandler(){
publicvoidhandleMessage(android.os.Messagemsg){
switch(msg.what){
case1:
Datedate=newDate();
eTextShowMsg.append("["+date.getMinutes()+":"
+date.getSeconds()+"]"+(CharSequence)msg.obj);
break;
default:
break;
}
};
};
/**
*接收数据线程
*/
classReceiveThreadextendsThread{
publicvoidrun(){
while(serialPort.isOpen){
if(isReceive){
Stringtype=togBtnShowDataType.getText().toString()
.trim();
Stringdata=serialPort.receiveData(type);
if(data!=null){
Messagemsg=newMessage();
msg.what=1;
msg.obj=data;
System.out.println(data+"<<<<<<<<==========data");
mHandler.sendMessage(msg);
}
}
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
当串口接收到数据每一秒更新一次UI,根据需求可转换为十六进制与字符
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。