Android 串口開(kāi)發(fā)知識(shí)總結(jié)(未完待續(xù))

一 、Android與串口設(shè)備通信的四種方案

  1. 直接用SDK的BluetoothSocket類(lèi)來(lái)進(jìn)行藍(lán)牙通信,外部設(shè)備再用藍(lán)牙轉(zhuǎn)串口進(jìn)行控制。這種方式有較高延時(shí),藍(lán)牙模塊需要供電,低帶寬。
  2. 使用USB轉(zhuǎn)RS232方式(使用內(nèi)核驅(qū)動(dòng)和使用Android驅(qū)動(dòng)兩種方式),這種方式不需要硬件改動(dòng),不需要另外的供電,延時(shí)很小且有較高帶寬。但是Android設(shè)備需要硬件上支持USB Host接口(一般Android平板支持,Android手機(jī)一般是沒(méi)有的),另外可能需要root以改變/dev/ttyUSB0文件權(quán)限來(lái)加載一個(gè)內(nèi)核模塊。開(kāi)發(fā)需要使用android_serialport_api。
  3. 第三種是最容易的方案,串口直接進(jìn)行連接,但是這種方式兼容性不好,只有少數(shù)設(shè)備支持,而且串口不支持流控制(由Android提供的USB Host API決定的)。使用時(shí)也用android_serialport_api。
  4. 第四種是將Android作為USB從機(jī),外部設(shè)備作為USB主機(jī)與之通信,這種方式幾乎與所有Android設(shè)備兼容(一般都有USB從口),無(wú)需root,低延遲,高帶寬。

目前項(xiàng)目中所用的平板設(shè)備,其串口的本質(zhì)還是USB轉(zhuǎn)串口(文件):ttyUSB


==串口通信無(wú)需root==

個(gè)人使用總結(jié):

  1. 實(shí)際項(xiàng)目中采用第二種方案,未root平板(USB口)接串口(RS232)設(shè)備
  2. 平板架構(gòu)為X86
  3. 串口設(shè)置通過(guò)SharedPreference類(lèi)保存 后續(xù)未采用

二、串口通信基礎(chǔ)知識(shí)

參考文章

  1. 串口參數(shù)的具體含義及程序配置 主要是C語(yǔ)言,程序如何配置參數(shù)
  2. 串口參數(shù)詳解:波特率,數(shù)據(jù)位,停止位,奇偶校驗(yàn)位 幫助了解概念
  3. General Terminal Interface
  4. 比特率 波特率 數(shù)據(jù)傳輸速率 區(qū)別 對(duì)串口基礎(chǔ)概念講解的很清楚,重點(diǎn)參考

串口通信的概念非常簡(jiǎn)單,串口按位(bit)發(fā)送和接收字節(jié)。

RS232是要用在近距離傳輸上最大距離為30M

RS485用在長(zhǎng)距離傳輸最大距離1200M

串口(SerialPort)重要的參數(shù)。
  • 串口通信模式:異步通信和同步通信

    異步通信:按字符傳送

  • 傳輸過(guò)程:程序編碼以包為單位發(fā)送,一包為一個(gè)字節(jié)。在串口編碼時(shí),起始位、停止位、奇偶校驗(yàn)、波特率都是串口打開(kāi)前設(shè)置好的,配置好串口文件就可以,個(gè)人理解:底層協(xié)議會(huì)將發(fā)送的數(shù)據(jù)位信息按照配置參數(shù)分好包再發(fā)送,所以實(shí)際編程配置好參數(shù),做好數(shù)據(jù)位信息(byte)的處理就可以了。無(wú)需關(guān)心起始位和停止位、奇偶校驗(yàn)位的發(fā)送問(wèn)題。

  • :起始位+數(shù)據(jù)位+停止位+(奇偶校驗(yàn)位)

  • 比特率(Bit rate):傳信率、信息傳輸速率(簡(jiǎn)稱(chēng)信息速率,information rate)。其定義是:通信線路(或系統(tǒng))單位時(shí)間(每秒)內(nèi)傳輸?shù)男畔⒘?,即每秒能傳輸?shù)亩M(jìn)制位數(shù),通常用Rb表示,其單位是比特/秒(bit/s或b/s,英文縮略語(yǔ)為bps)。

在二進(jìn)制系統(tǒng)中,信息速率(比特率)與信號(hào)速率(波特率)相等.在無(wú)調(diào)制的情況下,比特率等于波特率;采用調(diào)相技術(shù)時(shí),比特率不等于波特率。通信系統(tǒng)的發(fā)送設(shè)備和接收設(shè)備必須在相同的波特率下工作,否則會(huì)出現(xiàn)幀同步錯(cuò)誤。

  • 波特率(Baud rate):又稱(chēng)傳碼率、碼元傳輸速率(簡(jiǎn)稱(chēng)碼元速率)、信號(hào)傳輸速率(簡(jiǎn)稱(chēng)信號(hào)速率,signaling rate)或調(diào)制速率。其定義是:通信線路(或系統(tǒng))單位時(shí)間(每秒)內(nèi)傳輸?shù)拇a元(脈沖)個(gè)數(shù);或者表示信號(hào)調(diào)制過(guò)程中,單位時(shí)間內(nèi)調(diào)制信號(hào)波形的變換次數(shù),通常用RB表示,單位是波特(Bd或Baud,前者規(guī)范)。如果每秒傳輸1個(gè)碼元就稱(chēng)為1Bd;如果1碼元的時(shí)間長(zhǎng)短為200ms,則每秒可傳輸5個(gè)碼元,那么碼元速率(波特率)就是5Bd。

波特率(碼元速率)并沒(méi)有限定是何種進(jìn)制的碼元,所以給出波特率時(shí)必須說(shuō)明這個(gè)碼元的進(jìn)制。
對(duì)于M進(jìn)制碼元,比特率(信息速率)Rb波特率(碼元速率)RB的關(guān)系式為

Rb=RB·lbM
式中:lbM=log2M,表示M的以2為底的對(duì)數(shù)。

顯然,對(duì)于二進(jìn)制碼元,由于lb2=1,所以Rb=RB,即波特率與比特率在數(shù)值上相等,但單位不同,也即二者代表的意義不同。
例如,波特率為600Bd,則在二進(jìn)制時(shí),比特率也為600bit/s;在四進(jìn)制時(shí),由于lb4=2,所以比特率為1200bit/s??梢?jiàn),在一個(gè)碼元中可以傳送多個(gè)比特。

  • 數(shù)據(jù)傳輸速率(data transfer rate):又稱(chēng)數(shù)據(jù)傳輸速率、數(shù)據(jù)傳送率。其定義是:通信線路(或系統(tǒng))單位時(shí)間(每秒)內(nèi)傳輸?shù)淖址麄€(gè)數(shù);或者單位時(shí)間(每秒)內(nèi)傳輸?shù)拇a組(字塊)數(shù)或比特?cái)?shù)。其單位是字符/秒;或者碼組/秒、比特/秒(可見(jiàn),當(dāng)數(shù)據(jù)傳輸率用“bit/s”作單位時(shí),即等于比特率)。

例如,在某計(jì)算機(jī)異步串行通信系統(tǒng)中,數(shù)據(jù)傳輸率為960字符/s,每個(gè)字符包括1個(gè)起始位、8個(gè)數(shù)據(jù)位、1個(gè)停止位,則對(duì)應(yīng)的比特率為10×960位/s=9600位/s=9600bit/s;因?yàn)槭嵌M(jìn)制編碼,所以對(duì)應(yīng)的波特率也為9600Bd。

  • 波特,碼元,比特

波特(Bd)是計(jì)量單位,用于量度調(diào)制解調(diào)器等設(shè)備每秒信號(hào)變化次數(shù)的多少,即表示每秒時(shí)間內(nèi)通信線路狀態(tài)改變的次數(shù),而不代表傳輸數(shù)據(jù)的多少?!安ㄌ亍币辉~源于一位法國(guó)人的名字——Baudot。他于1877年為法國(guó)電報(bào)系統(tǒng)開(kāi)發(fā)了一種編碼方案。如果每1次信號(hào)改變,調(diào)制解調(diào)器傳送1bit(位)數(shù)據(jù),那么該系統(tǒng)的比特率(信息速率)與波特率(碼元速率)相同。但是采用編碼技術(shù)后,能使1Bd(1次信號(hào)改變)表示2bit或更多的比特(位)。每波特表示2bit(位)稱(chēng)作雙位編碼,每波特表示3bit(位)稱(chēng)作三位編碼。也就是說(shuō),1次電壓(或電流)波形的變化可能包括了幾位數(shù)據(jù),因此,不能把波特率和比特率混為一談;前者指電壓(或電流)變化次數(shù)(變化量),后者指?jìng)鬏敂?shù)據(jù)量的多少。

碼元(code cell)是攜帶信息的數(shù)字單位,是指在數(shù)字信道中傳送數(shù)字信號(hào)的一個(gè)波形符號(hào),也即“時(shí)間軸上的一個(gè)信號(hào)編碼單元”。碼元可能是二進(jìn)制的,也可能是多進(jìn)制的。

比特(bit)是“信息量”的計(jì)量單位,1位二進(jìn)制數(shù)所攜帶的信息量即為1bit(比特),例如,10010110是8位二進(jìn)制數(shù)字,所攜帶的信息量為8bit。

  • 起始位、停止位:起始位,0(低電平);停止位:1(高電平)。無(wú)信息傳輸,串口空閑時(shí),串口線一直為高電平,一直為1,所以是根據(jù)0起始位判斷是否有數(shù)據(jù)的。

  • 奇偶校驗(yàn)位:有四種檢錯(cuò)方式:偶、奇、高和低。當(dāng)然沒(méi)有校驗(yàn)位也是可以的。對(duì)于偶和奇校驗(yàn)的情況,串口會(huì)設(shè)置校驗(yàn)位(數(shù)據(jù)位后面的一位),用一個(gè)值確保傳輸?shù)臄?shù)據(jù)有偶個(gè)或者奇?zhèn)€邏輯高位。例如,如果數(shù)據(jù)是011,那么對(duì)于偶校驗(yàn),校驗(yàn)位為0,保證邏輯高的位數(shù)是偶數(shù)個(gè)。如果是奇校驗(yàn),校驗(yàn)位為1,這樣就有3個(gè)邏輯高位。高位和低位不是真正的檢查數(shù)據(jù),簡(jiǎn)單置位邏輯高或者邏輯低校驗(yàn)。這樣使得接收設(shè)備能夠知道一個(gè)位的狀態(tài),有機(jī)會(huì)判斷是否有噪聲干擾了通信或者是否傳輸和接收數(shù)據(jù)是否不同步。==奇偶校驗(yàn)概念需繼續(xù)了解,不是很明白==

  • 數(shù)據(jù)位:TODO 待編輯

三、串口編程

1. Android

Android是基于Linux內(nèi)核的系統(tǒng),對(duì)串口的操作與Linux無(wú)多大區(qū)別。

==串口編程實(shí)際上是對(duì)串口文件的操作。==

在Android開(kāi)發(fā)中,對(duì)串口數(shù)據(jù)的讀取和寫(xiě)入,實(shí)際上是是通過(guò)I/O流讀取、寫(xiě)入文件數(shù)據(jù)。
串口用完記得關(guān)閉(文件關(guān)閉)。 串口關(guān)閉,即是文件流關(guān)閉。

在串口開(kāi)發(fā)中的簡(jiǎn)要操作流程:

graph LR
打開(kāi)串口文件-->配置串口參數(shù)
配置串口參數(shù)-->寫(xiě)入/讀取
寫(xiě)入/讀取-->關(guān)閉

通俗易懂 編程基礎(chǔ)教程 :
Android串口通信 抱歉,學(xué)會(huì)它真的可以為所欲為
源文章

入門(mén)指南:原文地址-上半年最好的Android串口開(kāi)發(fā)入門(mén)指南
上半年最好的Android串口開(kāi)發(fā)入門(mén)指南 這是保存的有道筆記

導(dǎo)入Google SerialPort項(xiàng)目,CMake進(jìn)行JNI開(kāi)發(fā)
// TODO 待后續(xù)更新 另一個(gè)項(xiàng)目 音頻編解碼開(kāi)發(fā)中也用到CMake,待更新

串口數(shù)據(jù)的讀取/寫(xiě)入方法

a. FileInputStream(read)和FileOutputStream(write)

通過(guò)JNI獲取串口文件的FileDescriptor,對(duì)FileInputStream/FileOutputStream初始化,通過(guò)操作FileInputStream/FileOutputStream來(lái)操作串口。

b. 通過(guò)操作底層的read/write方法來(lái) 讀取/寫(xiě)入 串口數(shù)據(jù)

串口數(shù)據(jù)的處理

波特率不同(比特率)寫(xiě)入串口的數(shù)據(jù)需要的時(shí)間不同。如果讀取數(shù)據(jù)的緩沖區(qū)較大,讀取頻繁,那么有可能每次讀取的有效數(shù)據(jù)長(zhǎng)度不一致。對(duì)于需要的完整信息(有頭尾的一幀數(shù)據(jù))有可能每次都被截?cái)?。?duì)于后續(xù)的業(yè)務(wù)處理會(huì)造成不便。根據(jù)實(shí)際業(yè)務(wù)情況可做兩種處理:
讀取時(shí)間其實(shí)由有業(yè)務(wù)處理層所耗時(shí)間決定。如果不做處理,串口會(huì)頻繁讀取。

a. 讀取數(shù)據(jù)不頻繁

給出一個(gè)簡(jiǎn)單的計(jì)算公式:

一個(gè)字節(jié)(數(shù)據(jù)位)的傳輸時(shí)間。如前面所提,串口一個(gè)包的數(shù)據(jù)包括:
起始位+數(shù)據(jù)位+停止位+(奇偶校驗(yàn))= 10 | 11位
以不包含奇偶校驗(yàn)位為例:

t(ms/byte) = 1/bitRate * 10 * 1000

以115200波特率為例,一個(gè)字節(jié)的傳輸(寫(xiě)入時(shí)間:1/115200 * 8 *1000 = 0.086 ms
假設(shè)需要的有效信息幀為100個(gè)字節(jié),為了每次保包含一個(gè)完整的信息幀,緩沖區(qū)需要至少設(shè)置為200個(gè)字節(jié),需要讀200個(gè)字節(jié)。寫(xiě)入200個(gè)字節(jié)的時(shí)間為0.086 * 200 = 17ms左右。

如果業(yè)務(wù)數(shù)據(jù)的處理時(shí)間較大于17ms,保證了每次讀取的有效字節(jié)>=200,那么可以按照字節(jié)讀取,在提取其中的有效信息。否則,會(huì)造成讀取的信息幀丟失,造成業(yè)務(wù)損失。

b.讀取較為頻繁(業(yè)務(wù)處理較快)

這種情況還是按照字節(jié)讀取較為穩(wěn)妥,每次進(jìn)行字節(jié)判斷,根據(jù)信息幀的頭尾提取有效字節(jié),再進(jìn)行組裝。

串口開(kāi)發(fā)遇到的問(wèn)題、思考點(diǎn)

1.串口讀寫(xiě)數(shù)據(jù)分離,在兩個(gè)線程中操作,需要同步鎖。

2.串口突然斷開(kāi)(異常)怎么辦? 表現(xiàn):讀取數(shù)據(jù)位-1,報(bào)異常。需要進(jìn)行軟件處理。
關(guān)閉串口,提示用戶,再次打開(kāi)串口。

3.發(fā)送信息的頻率/周期

4.數(shù)據(jù)信息緩存,消息隊(duì)列格式,要求:后進(jìn)先出,隊(duì)列滿,從隊(duì)列頭依次剔除隊(duì)列數(shù)據(jù)
目前可將收發(fā)線程放在通過(guò)一個(gè)Activity中,通過(guò)鎖對(duì)象(隊(duì)列)實(shí)現(xiàn) 讀寫(xiě)分離鎖

5.串口意外斷開(kāi)處理方法 思路

1.根據(jù)FileInputStream的read讀取的數(shù)據(jù)-1次數(shù),達(dá)到閾值判定串口異常,關(guān)閉串口,并重新連接

2.采用JNI原生方法read()讀取數(shù)據(jù),在Linux 串口c_cc定義了控制字符,包含以下內(nèi)容:包含VTIME超時(shí)變量??稍O(shè)定讀取超時(shí)時(shí)間。

6. 項(xiàng)目中采用的平板遇到的串口問(wèn)題
只是針對(duì)項(xiàng)目機(jī)型,其他設(shè)備不一定出現(xiàn),但也作為記錄
Android 5.1 系統(tǒng)。
1. 本設(shè)備的串口其實(shí)內(nèi)部還是USB轉(zhuǎn)串口(ttyUSB),所以打開(kāi)串口的時(shí)候需要注意,非ttySn串口
2. 項(xiàng)目設(shè)備的U口不能帶串口設(shè)備啟動(dòng),否則會(huì)造成該U口占用其串口文件,造成其硬件COM口的串口號(hào)變動(dòng),例:設(shè)備出廠的串口號(hào)是ttyUSB1,U口的串口號(hào)是ttyUSB0;如果U口帶串口線(或串口設(shè)備啟動(dòng)),可能造成U口的串口號(hào)變?yōu)閠tyUSB1,COM口的串口號(hào)變?yōu)閠tyUSB0。COM口帶串口線(設(shè)備)無(wú)此問(wèn)題。

  1. Android系統(tǒng)能否與Windows系統(tǒng)一樣,能夠判斷出是哪個(gè)串口設(shè)備已接入,這樣對(duì)于Android端的串口調(diào)試助手來(lái)說(shuō),不需要列出無(wú)用的串口號(hào)。(未解決)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容