Android 串口通信编程及串口协议分析
Android串口通信编程:嵌入式编程和可穿戴设备及智能设备都会用到串口,这里就带大家分析下,
一,android串口通信
串口通信采用一个第三方开源项目,实现串口数据收发。
1.使用了http://code.google.com/p/android-serialport-api/的项目的serialportapi和jni;
2.支持4串口同时收发,有定时自动发送功能,收发模式可选Txt或Hex模式;
3. n,8,1,没得选;
4.为减轻界面卡顿的情况,接收区的刷新采用单独的线程进行定时刷新;
5.发送区的数据以及一些设置项,在程序关闭时会自动保存,打开时自动载入;
6.jni使用最新的NDKr8b重新编译了一下
简单编写步骤:
1.新建一个项目,自己起个名字
2.直接复制serialportapi和jni文件夹到新建的工程,如果不想自己编译jni,就连libs文件夹也一起复制
3.去android官方网站下载NDK,解压,在CMD中转到jni目录,并执行绝对路径\ndk-build
4.自己再封装一个工具类或直接使用SerialPort类都行,举个直接使用的例:
直接剽窃原项目的SerialPortActivity.java,并稍微改一下,重点改这里
mSerialPort=mApplication.getSerialPort();
这里可以改成
newSerialPort(newFile("/dev/s3c2410_serial0"),9600,0);//COM0,波特率9600
5.SerialPortFinder的使用就没什么好讲的了,实例化后用.getAllDevicesPath()就能获取到所有设备了。
其它如数据转换等请参考源码
源码可以参考谷歌android-serialport-api例子
http://code.google.com/p/android-serialport-api/source/checkout
svncheckouthttp://android-serialport-api.googlecode.com/svn/trunk
二,串口通信协议解析
1.通信基本格式
字段描述长度(字节)
起始符0F,十六进制码 1
信息类型一个字节,十六进制码(0F,F0,FF等保留码不用)1
信息长度是信息内容的长度,ASCII码表示(0~9,A~F,最大长度为256)(例如长为11个,十六进制是0B,则两个字节就写0x300x42)。
注:因为最大长度256不能满足有些指令的要求,所以对长度做了扩展,下面是扩展说明:
如果第一个字节的最高位为1,则表示扩展长度。在扩展长度状态下,其他15个字节通过16进制大端模式来保存长度。比如:0x800x12表示长度为0x0012,0x810x12表示长度为0x0112。2
信息内容一组十六进制码 N
校验一个字节,十六进制码,是自信息类型起至对象号止所有码的异或。1
结束符F0,一个字节,十六进制码(为了保证可靠性,车机下发的结束符为F0FF)1
2.协议解析
/**
*读取终端设备数据
*@authorAdministrator
*/
privateclassReadThreadextendsThread{
@Override
publicvoidrun(){
super.run();
//定义一个包的最大长度
intmaxLength=2048;
byte[]buffer=newbyte[maxLength];
//每次收到实际长度
intavailable=0;
//当前已经收到包的总长度
intcurrentLength=0;
//协议头长度4个字节(开始符1,类型1,长度2)
intheaderLength=4;
while(!isInterrupted()){
try{
available=mInputStream.available();
if(available>0){
//防止超出数组最大长度导致溢出
if(available>maxLength-currentLength){
available=maxLength-currentLength;
}
mInputStream.read(buffer,currentLength,available);
currentLength+=available;
}
}
catch(Exceptione){
e.printStackTrace();
}
intcursor=0;
//如果当前收到包大于头的长度,则解析当前包
while(currentLength>=headerLength){
//取到头部第一个字节
if(buffer[cursor]!=0x0F){
--currentLength;
++cursor;
continue;
}
intcontentLenght=parseLen(buffer,cursor,headerLength);
//如果内容包的长度大于最大内容长度或者小于等于0,则说明这个包有问题,丢弃
if(contentLenght<=0||contentLenght>maxLength-5){
currentLength=0;
break;
}
//如果当前获取到长度小于整个包的长度,则跳出循环等待继续接收数据
intfactPackLen=contentLenght+5;
if(currentLength<contentLenght+5){
break;
}
//一个完整包即产生
//proceOnePacket(buffer,i,factPackLen);
onDataReceived(buffer,cursor,factPackLen);
currentLength-=factPackLen;
cursor+=factPackLen;
}
//残留字节移到缓冲区首
if(currentLength>0&&cursor>0){
System.arraycopy(buffer,cursor,buffer,0,currentLength);
}
}
}
}
/**
*获取协议内容长度
*@paramheader
*@return
*/
publicintparseLen(bytebuffer[],intindex,intheaderLength){
//if(buffer.length-index<headerLength){return0;}
bytea=buffer[index+2];
byteb=buffer[index+3];
intrlt=0;
if(((a>>7)&0x1)==0x1){
rlt=(((a&0x7f)<<8)|b);
}
else{
char[]tmp=newchar[2];
tmp[0]=(char)a;
tmp[1]=(char)b;
Strings=newString(tmp,0,2);
rlt=Integer.parseInt(s,16);
}
returnrlt;
}
protectedvoidonDataReceived(finalbyte[]buffer,finalintindex,finalintpacklen){
System.out.println("收到信息");
byte[]buf=newbyte[packlen];
System.arraycopy(buffer,index,buf,0,packlen);
ProtocolAnalyze.getInstance(myHandler).analyze(buf);
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!