Android 串口通信编程及串口协议分析
android 串口通信编程:嵌入式编程和可穿戴设备及智能设备都会用到串口,这里就带大家分析下,
一,android串口通信
串口通信采用一个第三方开源项目,实现串口数据收发。
1. 使用了http://code.google.com/p/android-serialport-api/的项目的serialport api和jni;
2. 支持4串口同时收发,有定时自动发送功能,收发模式可选txt或hex模式;
3. n,8,1,没得选;
4. 为减轻界面卡顿的情况,接收区的刷新采用单独的线程进行定时刷新;
5. 发送区的数据以及一些设置项,在程序关闭时会自动保存,打开时自动载入;
6. jni使用最新的ndkr8b重新编译了一下
简单编写步骤:
1.新建一个项目,自己起个名字
2.直接复制serialport api和jni文件夹到新建的工程,如果不想自己编译jni,就连libs文件夹也一起复制
3.去android官方网站下载ndk,解压,在cmd中转到jni目录,并执行 绝对路径\ndk-build
4.自己再封装一个工具类或直接使用serialport类都行,举个直接使用的例:
直接剽窃原项目的serialportactivity.java,并稍微改一下,重点改这里
mserialport = mapplication.getserialport();
这里可以改成
new serialport(new file("/dev/s3c2410_serial0"), 9600, 0);//com0,波特率9600
5. serialportfinder的使用就没什么好讲的了,实例化后用.getalldevicespath()就能获取到所有设备了。
其它如数据转换等请参考源码
源码可以参考谷歌android-serialport-api例子
http://code.google.com/p/android-serialport-api/source/checkout
svn checkout http://android-serialport-api.googlecode.com/svn/trunk
二,串口通信协议解析
1.通信基本格式
字段 描述 长度(字节)
起始符 0f,十六进制码 1
信息类型 一个字节,十六进制码(0f,f0,ff等保留码不用)1
信息长度 是信息内容的长度,ascii码表示(0~9,a~f,最大长度为256)(例如长为11个,十六进制是0b,则两个字节就写0x30 0x42)。
注:因为最大长度256不能满足有些指令的要求,所以对长度做了扩展,下面是扩展说明:
如果第一个字节的最高位为1,则表示扩展长度。在扩展长度状态下,其他15个字节通过16进制大端模式来保存长度。比如:0x80 0x12表示长度为0x001 2,0x81 0x12表示长度为0x0112。2
信息内容 一组十六进制码 n
校验 一个字节,十六进制码,是自信息类型起至对象号止所有码的异或。1
结束符 f0,一个字节,十六进制码 (为了保证可靠性,车机下发的结束符为f0 ff)1
2.协议解析
/** * 读取终端设备数据 * @author administrator */ private class readthread extends thread { @override public void run() { super.run(); // 定义一个包的最大长度 int maxlength = 2048; byte[] buffer = new byte[maxlength]; // 每次收到实际长度 int available = 0; // 当前已经收到包的总长度 int currentlength = 0; // 协议头长度4个字节(开始符1,类型1,长度2) int headerlength = 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 (exception e) { e.printstacktrace(); } int cursor = 0; // 如果当前收到包大于头的长度,则解析当前包 while (currentlength >= headerlength) { // 取到头部第一个字节 if (buffer[cursor] != 0x0f) { --currentlength; ++cursor; continue; } int contentlenght = parselen(buffer, cursor, headerlength); // 如果内容包的长度大于最大内容长度或者小于等于0,则说明这个包有问题,丢弃 if (contentlenght <= 0 || contentlenght > maxlength - 5) { currentlength = 0; break; } // 如果当前获取到长度小于整个包的长度,则跳出循环等待继续接收数据 int factpacklen = 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); } } } } /** * 获取协议内容长度 * @param header * @return */ public int parselen(byte buffer[], int index, int headerlength) { // if (buffer.length - index < headerlength) { return 0; } byte a = buffer[index + 2]; byte b = buffer[index + 3]; int rlt = 0; if (((a >> 7) & 0x1) == 0x1) { rlt = (((a & 0x7f) << 8) | b); } else { char[] tmp = new char[2]; tmp[0] = (char) a; tmp[1] = (char) b; string s = new string(tmp, 0, 2); rlt = integer.parseint(s, 16); } return rlt; } protected void ondatareceived(final byte[] buffer, final int index, final int packlen) { system.out.println("收到信息"); byte[] buf = new byte[packlen]; system.arraycopy(buffer, index, buf, 0, packlen); protocolanalyze.getinstance(myhandler).analyze(buf); }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!