Android 串口通信編程及串口協(xié)議分析
Android 串口通信編程:嵌入式編程和可穿戴設(shè)備及智能設(shè)備都會用到串口,這里就帶大家分析下,
一,android串口通信
串口通信采用一個第三方開源項目,實現(xiàn)串口數(shù)據(jù)收發(fā)。
1. 使用了http://code.google.com/p/android-serialport-api/的項目的serialport api和jni;
2. 支持4串口同時收發(fā),有定時自動發(fā)送功能,收發(fā)模式可選Txt或Hex模式;
3. n,8,1,沒得選;
4. 為減輕界面卡頓的情況,接收區(qū)的刷新采用單獨的線程進行定時刷新;
5. 發(fā)送區(qū)的數(shù)據(jù)以及一些設(shè)置項,在程序關(guān)閉時會自動保存,打開時自動載入;
6. jni使用最新的NDKr8b重新編譯了一下
簡單編寫步驟:
1.新建一個項目,自己起個名字
2.直接復制serialport api和jni文件夾到新建的工程,如果不想自己編譯jni,就連libs文件夾也一起復制
3.去android官方網(wǎng)站下載NDK,解壓,在CMD中轉(zhuǎn)到j(luò)ni目錄,并執(zhí)行 絕對路徑\ndk-build
4.自己再封裝一個工具類或直接使用SerialPort類都行,舉個直接使用的例:
直接剽竊原項目的SerialPortActivity.java,并稍微改一下,重點改這里
mSerialPort = mApplication.getSerialPort();
這里可以改成
new SerialPort(new File("/dev/s3c2410_serial0"), 9600, 0);//COM0,波特率9600
5. SerialPortFinder的使用就沒什么好講的了,實例化后用.getAllDevicesPath()就能獲取到所有設(shè)備了。
其它如數(shù)據(jù)轉(zhuǎn)換等請參考源碼
源碼可以參考谷歌android-serialport-api例子
http://code.google.com/p/android-serialport-api/source/checkout
svn checkout http://android-serialport-api.googlecode.com/svn/trunk
二,串口通信協(xié)議解析
1.通信基本格式
字段 描述 長度(字節(jié))
起始符 0F,十六進制碼 1
信息類型 一個字節(jié),十六進制碼(0F,F0,FF等保留碼不用)1
信息長度 是信息內(nèi)容的長度,ASCII碼表示(0~9,A~F,最大長度為256)(例如長為11個,十六進制是0B,則兩個字節(jié)就寫0x30 0x42)。
注:因為最大長度256不能滿足有些指令的要求,所以對長度做了擴展,下面是擴展說明:
如果第一個字節(jié)的最高位為1,則表示擴展長度。在擴展長度狀態(tài)下,其他15個字節(jié)通過16進制大端模式來保存長度。比如:0x80 0x12表示長度為0x001 2,0x81 0x12表示長度為0x0112。2
信息內(nèi)容 一組十六進制碼 N
校驗 一個字節(jié),十六進制碼,是自信息類型起至對象號止所有碼的異或。1
結(jié)束符 F0,一個字節(jié),十六進制碼 (為了保證可靠性,車機下發(fā)的結(jié)束符為F0 FF)1
2.協(xié)議解析
/**
* 讀取終端設(shè)備數(shù)據(jù)
* @author Administrator
*/
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
// 定義一個包的最大長度
int maxLength = 2048;
byte[] buffer = new byte[maxLength];
// 每次收到實際長度
int available = 0;
// 當前已經(jīng)收到包的總長度
int currentLength = 0;
// 協(xié)議頭長度4個字節(jié)(開始符1,類型1,長度2)
int headerLength = 4;
while (!isInterrupted()) {
try {
available = mInputStream.available();
if (available > 0) {
// 防止超出數(shù)組最大長度導致溢出
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) {
// 取到頭部第一個字節(jié)
if (buffer[cursor] != 0x0F) {
--currentLength;
++cursor;
continue;
}
int contentLenght = parseLen(buffer, cursor, headerLength);
// 如果內(nèi)容包的長度大于最大內(nèi)容長度或者小于等于0,則說明這個包有問題,丟棄
if (contentLenght <= 0 || contentLenght > maxLength - 5) {
currentLength = 0;
break;
}
// 如果當前獲取到長度小于整個包的長度,則跳出循環(huán)等待繼續(xù)接收數(shù)據(jù)
int factPackLen = contentLenght + 5;
if (currentLength < contentLenght + 5) {
break;
}
// 一個完整包即產(chǎn)生
// proceOnePacket(buffer,i,factPackLen);
onDataReceived(buffer, cursor, factPackLen);
currentLength -= factPackLen;
cursor += factPackLen;
}
// 殘留字節(jié)移到緩沖區(qū)首
if (currentLength > 0 && cursor > 0) {
System.arraycopy(buffer, cursor, buffer, 0, currentLength);
}
}
}
}
/**
* 獲取協(xié)議內(nèi)容長度
* @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);
}
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Android中RecycleView與ViewPager沖突的解決方法及原理
這篇文章主要給大家介紹了關(guān)于Android中RecycleView與ViewPager沖突的解決方法及原理的相關(guān)資料,以及ViewPager嵌套RecycleView卡頓問題的處理方法,文中通過示例代碼介紹的非常狎昵,需要的朋友可以參考下2018-07-07
關(guān)于Android?Webview?設(shè)置Cookie問題詳解
大家好,本篇文章是關(guān)于Android?Webview?設(shè)置Cookie問題詳解,感興趣的同學可以看看,希望對你起到幫助,有用的話記得收藏,方便下次瀏覽2021-11-11
Android開發(fā)之Activity管理工具類完整示例
這篇文章主要介紹了Android開發(fā)之Activity管理工具類,集合完整實例形式分析了Android操作Activity創(chuàng)建、添加、獲取、移除等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01
Android 獲取屏幕高度,標題高度,狀態(tài)欄高度(實例代碼)
getWindow().findViewById(Window.ID_ANDROID_CONTENT)這個方法獲取到的view就是程序不包括標題欄的部分,然后就可以知道標題欄的高度了2013-11-11
Android 通過網(wǎng)絡(luò)圖片路徑查看圖片實例詳解
這篇文章主要介紹了Android 通過網(wǎng)絡(luò)圖片路徑查看圖片實例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android 實現(xiàn)背景圖和狀態(tài)欄融合方法
下面小編就為大家分享一篇Android 實現(xiàn)背景圖和狀態(tài)欄融合方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01

