(中煤科工集團(tuán)重慶研究院有限公司,重慶 400039)
工業(yè)領(lǐng)域中,設(shè)備儀器儀表采用RS485通信協(xié)議進(jìn)行通信時(shí),報(bào)文大致可以分為三類,通信握手類、指令類和數(shù)據(jù)類。通信握手報(bào)文一般用于診斷設(shè)備是否在線,獲取設(shè)備當(dāng)前的狀態(tài)等。而指令類報(bào)文則包含讀、寫(xiě)兩種指令,一般通過(guò)上位機(jī)發(fā)出,讓設(shè)備完成相應(yīng)的動(dòng)作。數(shù)據(jù)類報(bào)文則包括關(guān)鍵的數(shù)據(jù)信息,如加氣機(jī)的加氣交易等等信息。數(shù)據(jù)類報(bào)文在以上三種報(bào)文中長(zhǎng)度最長(zhǎng),優(yōu)先級(jí)最高,傳輸中所占用的資源也最多。
加氣機(jī)完整的離線交易信息包括交易流水號(hào)、IC卡卡號(hào)、氣品種類(CNG/LNG)、加氣槍號(hào)、加氣時(shí)長(zhǎng)、加氣氣量、單價(jià)、金額、折扣等信息。離線狀態(tài)下,加氣機(jī)加完一筆氣將會(huì)存儲(chǔ)以下信息如表1所示,交易信息是消費(fèi)、記賬、扣款的唯一依據(jù),所以必須保證所有記錄在加氣機(jī)恢復(fù)通訊后立即上傳至后臺(tái)。
當(dāng)鏈路恢復(fù)之后,主機(jī)PC會(huì)下發(fā)索取離線交易的命令,如表2所示。
由于交易流水號(hào)必須保證唯一性,所以這里引入了交易計(jì)數(shù)器的概念,是為了合理的利用存儲(chǔ)區(qū)資源并且進(jìn)行離線交易的管理。
以基于STM32處理器的加氣機(jī)主板為例,用鐵電保存交易計(jì)數(shù)器的值, 將W25的存儲(chǔ)區(qū)按照交易數(shù)據(jù)的大小等量劃分為1萬(wàn)個(gè)存儲(chǔ)區(qū),每個(gè)存儲(chǔ)區(qū)存儲(chǔ)1組如上表2中的交易信息,編號(hào)從0~9999,用NextRecord/SendRecord標(biāo)識(shí)。NextRecord的值表示下一條交易緩存區(qū)的編號(hào),而SendRecord的值表示未上傳交易緩存區(qū)的位置。
表1 加氣機(jī)離線交易格式
表2 PC機(jī)獲取加氣機(jī)離線交易格式
未有交易產(chǎn)生時(shí),NextRecord/SendRecord初始化為0。當(dāng)?shù)谝粭l交易記錄產(chǎn)生后,NextRecord的值為1,當(dāng)此條交易記錄上傳至加氣機(jī)后,NoSdRecord的值加1遞增,表示第0個(gè)緩存區(qū)的記錄已經(jīng)上傳,第1個(gè)緩沖區(qū)的記錄還未上傳。第二個(gè)交易產(chǎn)生后NextRecord++,上傳PC成功后NoSdRecord++,以此類推,待數(shù)值達(dá)到10000時(shí)歸零,以前的交易將被覆蓋,存儲(chǔ)區(qū)循環(huán)利用。
這樣當(dāng)離線交易產(chǎn)生時(shí),NextRecord會(huì)持續(xù)累加,而NoSdRecord會(huì)保持不變,所以離線交易數(shù)目N可以用如下公式計(jì)算出來(lái)。
N=|NextRecord - NoSdRecord|
這里NextRecord+1 ≠ NoSdRecord,若相等表示緩存區(qū)已滿,必須停止加氣交易,待交易記錄上傳,緩存區(qū)騰出空間后,才能繼續(xù)存儲(chǔ)交易記錄。
以一臺(tái)加氣機(jī)存儲(chǔ)的最多離線交易記錄條數(shù)(2萬(wàn)條)為例,RS485通信中常規(guī)的波特率是9600 bps,那么傳輸萬(wàn)2萬(wàn)條離線交易的時(shí)間大約為1個(gè)小時(shí)。
以上是信道滿負(fù)荷最優(yōu)情況下理論計(jì)算出的數(shù)據(jù)傳輸時(shí)間,最優(yōu)是指單個(gè)設(shè)備與單個(gè)主機(jī)進(jìn)行通訊,設(shè)備持續(xù)發(fā)送,主機(jī)持續(xù)接收,無(wú)錯(cuò)誤報(bào)文出現(xiàn)。
而實(shí)際設(shè)備與主機(jī)進(jìn)行通信時(shí),為了保障數(shù)據(jù)的有效傳輸,往往引入了應(yīng)答機(jī)制。也就是主機(jī)每次正確接收設(shè)備傳輸來(lái)的數(shù)據(jù)后,都要回復(fù)ACK應(yīng)答包,設(shè)備收到了主機(jī)傳輸來(lái)的ACK應(yīng)答包后,才開(kāi)始下一個(gè)報(bào)文的上送。
圖1 RS485數(shù)據(jù)傳輸應(yīng)答示例
按照上文所述加氣機(jī)2萬(wàn)條交易記錄為例,傳輸所占的時(shí)長(zhǎng)大約為2個(gè)小時(shí),信道的利用率(不含ACK應(yīng)答)約為50%。所以,當(dāng)批量傳輸數(shù)據(jù)的時(shí)候,RS485的這種簡(jiǎn)單詢問(wèn)應(yīng)答的傳輸機(jī)制會(huì)產(chǎn)生大量的時(shí)間成本,嚴(yán)重影響系統(tǒng)的實(shí)時(shí)性和可靠性。然而,TCP的滑動(dòng)窗口技術(shù)能有效的解決數(shù)據(jù)傳輸中的時(shí)間冗余,提高信道的利用率。
滑動(dòng)窗口協(xié)議,是TCP使用的一種流量控制方法。該協(xié)議允許發(fā)送方在停止并等待確認(rèn)前可以連續(xù)發(fā)送多個(gè)分組。發(fā)送方不必每發(fā)一個(gè)分組就停下來(lái)等待確認(rèn)[1]?;瑒?dòng)窗口協(xié)議具有加速數(shù)據(jù)傳輸、糾錯(cuò)控制和流量控制功能。
滑動(dòng)窗口協(xié)議的基本原理就是在任意時(shí)刻,發(fā)送方都維持了一個(gè)連續(xù)的允許發(fā)送的幀的序號(hào),稱為發(fā)送窗口;同時(shí),接收方也維持了一個(gè)連續(xù)的允許接收的幀的序號(hào),稱為接收窗口[2]。發(fā)送窗口和接收窗口的序號(hào)的上下界不一定要一樣,甚至大小也可以不同。不同的滑動(dòng)窗口協(xié)議窗口大小一般不同。發(fā)送方窗口內(nèi)的序列號(hào)代表了那些已經(jīng)被發(fā)送,但是還沒(méi)有被確認(rèn)的幀,或者是那些可以被發(fā)送的幀[6]。
TCP是全雙工協(xié)議,發(fā)送方和接收方是對(duì)等的。對(duì)于TCP會(huì)話的發(fā)送方,任何時(shí)候在其發(fā)送緩存內(nèi)的數(shù)據(jù)都可以分為4類[3]:
(1)已經(jīng)發(fā)送并得到對(duì)方ACK的數(shù)據(jù)包;
(2)已經(jīng)發(fā)送但還未收到對(duì)方ACK的數(shù)據(jù)包;
(3)未發(fā)送但對(duì)方允許發(fā)送的數(shù)據(jù)包;
(4)未發(fā)送且對(duì)方不允許發(fā)送的數(shù)據(jù)包。
已經(jīng)發(fā)送但還未收到對(duì)方ACK的數(shù)據(jù)包和未發(fā)送但對(duì)方允許發(fā)送的數(shù)據(jù)包這兩部分?jǐn)?shù)據(jù)稱之為發(fā)送窗口。
TCP建立連接的初始,接收方會(huì)告訴發(fā)送方自己接收窗口大小,比如10。
圖3 TCP滑動(dòng)窗口數(shù)據(jù)收到正序的數(shù)據(jù)
如圖3所示,滑動(dòng)窗口包含已發(fā)送但未收到確認(rèn)的字節(jié)和允許發(fā)送但尚未發(fā)送的字節(jié)[4]。當(dāng)上圖中紅色的區(qū)域數(shù)據(jù)都被接收到之后,那么滑動(dòng)窗口將會(huì)向右移動(dòng)。窗口兩個(gè)邊沿的相對(duì)運(yùn)動(dòng)增加或減少窗口的大小從而讓網(wǎng)絡(luò)數(shù)據(jù)傳輸避免了擁堵。
數(shù)據(jù)的接收可以分為正序或者亂序,正序是指接收方按發(fā)送方正常的發(fā)送序列接收到數(shù)據(jù),而亂序是指接收方?jīng)]有按照發(fā)送方正常的發(fā)送序列接收數(shù)據(jù),也就是存在丟包[5]。對(duì)于丟包的亂序數(shù)據(jù),接收方暫時(shí)存儲(chǔ)起來(lái),避免網(wǎng)絡(luò)重復(fù)傳輸。
圖4 TCP滑動(dòng)窗口收到亂序的數(shù)據(jù)
如圖4所示,字節(jié)(序號(hào)6、7)比字節(jié)(序號(hào)5)先收到接收方的確認(rèn),那么待字節(jié)5收到接收方的確認(rèn)后,滑動(dòng)窗口才會(huì)右移。
圖5 RS485 OSI模型結(jié)構(gòu)圖
RS485協(xié)議的網(wǎng)絡(luò)層和傳輸層是開(kāi)放式的,沒(méi)有統(tǒng)一的標(biāo)準(zhǔn),需要根據(jù)實(shí)際的情況自定義。由于傳輸是PC和加氣機(jī)點(diǎn)對(duì)點(diǎn)的通信,網(wǎng)絡(luò)層和數(shù)據(jù)鏈路層比較簡(jiǎn)單。同時(shí)針對(duì)加氣機(jī)離線交易數(shù)據(jù)量大,占用時(shí)間多的實(shí)際情況,將TCP滑動(dòng)窗口的協(xié)議引入了RS485的傳輸層,主要是基于提高數(shù)據(jù)傳輸速率,保障數(shù)據(jù)傳輸可靠性的考慮。
在傳統(tǒng)RS485通信協(xié)議中,物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層遠(yuǎn)沒(méi)有TCP強(qiáng)大,因?yàn)闆](méi)有強(qiáng)大的底層協(xié)議做支撐,RS485一般在傳輸層實(shí)現(xiàn)簡(jiǎn)單的單次數(shù)據(jù)包發(fā)送的停等協(xié)議。
如上圖1所示,PC機(jī)索取加氣機(jī)離線交易,加氣機(jī)上傳單條離線交易后隨即進(jìn)入等待PC機(jī)發(fā)回確認(rèn)ACK包的狀態(tài)。
對(duì)比TCP協(xié)議中的滑動(dòng)窗口,RS485發(fā)送方和接收方同時(shí)維護(hù)了一個(gè)發(fā)送緩存和接收緩存,窗口大小可以看作為1,代表1個(gè)數(shù)據(jù)包。由于發(fā)送方接收到第N個(gè)數(shù)據(jù)包的響應(yīng)后,才開(kāi)始第N+1個(gè)數(shù)據(jù)包的發(fā)送,那么接收方接收到的數(shù)據(jù)包必定是正序的。為了提高數(shù)據(jù)的傳輸速率,減少停止等待的時(shí)間浪費(fèi),有必要提高窗口的大小。
假設(shè)RS485應(yīng)用層的數(shù)據(jù)傳輸協(xié)議采用TCP滑動(dòng)窗口的方式,窗口的大小調(diào)整為N,與TCP 不同的是這里的N指的是N個(gè)數(shù)據(jù)包,而非字節(jié)數(shù)。
圖6 RS485數(shù)據(jù)傳輸采用TCP滑動(dòng)窗口模式
還以加氣機(jī)離線交易數(shù)據(jù)上傳為例,假設(shè)在通信效率很高的情況下,也就是主機(jī)發(fā)出的數(shù)據(jù)包,設(shè)備都能夠有效響應(yīng),并且響應(yīng)一次主機(jī)就能收到ACK。
圖6(1)中是設(shè)備連續(xù)收到N包數(shù)據(jù)后,回復(fù)N個(gè)ACK的示例。由于RS485常用的是半雙工的通信方式,所以圖6(1)中,主機(jī)在收到設(shè)備的離線交易數(shù)據(jù)之后,設(shè)備線程必須停止發(fā)送數(shù)據(jù)等待主機(jī)下發(fā)的ACK響應(yīng),這種模式與圖2提到的發(fā)送應(yīng)答模式在效率上并無(wú)多大區(qū)別。
實(shí)際的ACK應(yīng)答包很短,有效數(shù)據(jù)很少,所以完全可以用一個(gè)ACK應(yīng)答包來(lái)涵蓋Data(0)至Data(N-1)N包數(shù)據(jù)的應(yīng)答響應(yīng),如圖5中(2)所示。這種模式下ACK響應(yīng)的數(shù)量從N個(gè)減為1個(gè),效率大大提高了[8]。
表1 RS485 采用TCP滑動(dòng)窗口模式ACK報(bào)文格式包頭主機(jī)ID設(shè)備IDACK(0), ACK(1),…,ACK(8)ACK(N-1)包尾。
設(shè)備在發(fā)送N個(gè)數(shù)據(jù)包至主機(jī)后,立即啟動(dòng)定時(shí)器等待主機(jī)返回的ACK,在定時(shí)器超時(shí)之前接收到ACK組合后便對(duì)ACK包進(jìn)行解析。假設(shè)N個(gè)數(shù)據(jù)包的ACK全部收到,則滑動(dòng)窗口右移,進(jìn)行下一組數(shù)據(jù)包的發(fā)送。如果N個(gè)數(shù)據(jù)包中,有個(gè)別數(shù)據(jù)包沒(méi)有收到,則發(fā)送相應(yīng)的數(shù)據(jù)包,并啟動(dòng)定時(shí)器接收主機(jī)發(fā)送的下一個(gè)ACK組合。
同時(shí)為了保證RS485數(shù)據(jù)傳輸?shù)目煽啃?,引入流控、糾錯(cuò)的機(jī)制。
圖7 RS485數(shù)據(jù)傳輸采用的糾錯(cuò)和流控機(jī)
RS485數(shù)據(jù)傳輸受環(huán)境因素(閃電、電磁干擾)等的影響,傳輸過(guò)程中會(huì)出現(xiàn)錯(cuò)包、丟包現(xiàn)象,為了保障數(shù)據(jù)的完整性引入錯(cuò)誤重傳機(jī)制即糾錯(cuò)機(jī)制。如果窗口較大,同時(shí)有多個(gè)加氣機(jī)上傳離線交易,PC機(jī)疲于應(yīng)付的情況下,則有必要進(jìn)行流量的控制。
圖7(a)為本文所闡述的RS485數(shù)據(jù)傳輸?shù)募m錯(cuò)原理圖,主機(jī)和設(shè)備同時(shí)維護(hù)一個(gè)數(shù)據(jù)包為N的窗口。
(1)主機(jī)請(qǐng)求設(shè)備上送數(shù)據(jù),發(fā)出Req(Req包含當(dāng)前窗口序列號(hào)Q,窗口大小N,需要設(shè)備發(fā)送的數(shù)據(jù)包序列號(hào)0…N-1等),當(dāng)Req發(fā)出后立即啟動(dòng)數(shù)據(jù)接收超時(shí)定時(shí)器,當(dāng)定時(shí)器超時(shí)時(shí)觸發(fā)數(shù)據(jù)包接收機(jī)制,接收機(jī)制用來(lái)統(tǒng)計(jì)接收到的有效數(shù)據(jù)包的個(gè)數(shù)[7]。
(2)主機(jī)接收機(jī)制判斷當(dāng)前的窗口Q未接收到完整的數(shù)據(jù)包,丟失了其中D(N-2)、D(N-1)兩個(gè)數(shù)據(jù)包,立即啟動(dòng)重傳機(jī)制再次發(fā)出Req(此時(shí)的Req僅包含需要重傳的數(shù)據(jù)包D(N-2)、D(N-1))。
(3)當(dāng)主機(jī)收到當(dāng)前窗口Q所有的數(shù)據(jù)包后,發(fā)出Ack(ALL)指令,表明當(dāng)前的數(shù)據(jù)包全部被有效接收,此時(shí)當(dāng)前的窗口傳輸完成。
PC端和DEVICE同時(shí)維護(hù)一個(gè)值相同的Receive_map和Send_map[9],PC端不斷查詢Receive_map并把值發(fā)給DEVICE端,DEVICE端查詢接收到的Receive_map(這里等于Send_map),并發(fā)送給DEVICE端[10]。當(dāng)所有bitmap里面代表的當(dāng)前窗口的數(shù)據(jù)包發(fā)送完成后,當(dāng)次數(shù)據(jù)傳輸完成。為了方便起見(jiàn),本例的bitmap設(shè)置為0xFFFFFFFF,每位代表一個(gè)數(shù)據(jù)包,共標(biāo)志32個(gè)數(shù)據(jù)包的發(fā)送接收狀態(tài)。此時(shí)的窗口大小也為32。
圖7(b)為流量控制機(jī)制,當(dāng)主機(jī)收到加氣機(jī)發(fā)送的三個(gè)離線數(shù)據(jù)包后,出現(xiàn)了網(wǎng)絡(luò)擁堵的緊急情況,主機(jī)立即發(fā)出Flow(4)流控包讓對(duì)應(yīng)的加氣機(jī)停止上傳離線交易數(shù)據(jù),待網(wǎng)絡(luò)恢復(fù)之后,重新發(fā)送請(qǐng)求報(bào)Req恢復(fù)離線交易的上傳。
為了更好地闡述RS485應(yīng)用滑動(dòng)窗口的思想,用狀態(tài)機(jī)表示以上的算法如圖8所示。
圖8 狀態(tài)機(jī)表示RS485滑動(dòng)窗口技術(shù)
這樣傳輸N個(gè)數(shù)據(jù)包,只有1個(gè)ACK總應(yīng)答包,在通信良好的情況下,信道的利用率大大提高了[11]。主機(jī)接收從機(jī)發(fā)送數(shù)據(jù)等待的時(shí)間大大減少了。并且該機(jī)制引入了糾錯(cuò)以及流控機(jī)制,有效避免了差錯(cuò)引起的擁堵以及冗余時(shí)間成本的浪費(fèi)[12]。
RS485采用滑動(dòng)窗口模式上傳離線交易的協(xié)議與傳統(tǒng)單數(shù)據(jù)包的停等協(xié)議相比,在效率上具有較大的優(yōu)勢(shì),且滑動(dòng)窗口越大效率愈發(fā)明顯。
滑動(dòng)窗口大小為Wn,數(shù)據(jù)包大小為S(字節(jié)),波特率為Boud(字節(jié)/秒)。如圖9所示:
T1:主機(jī)發(fā)送數(shù)據(jù)包的等待時(shí)間
T2:數(shù)據(jù)包的傳輸時(shí)間
T3:數(shù)據(jù)包ACK的發(fā)送準(zhǔn)備時(shí)間
T4:設(shè)備應(yīng)答ACK的傳輸時(shí)間
按照?qǐng)D9(a)傳統(tǒng)停等協(xié)議下,發(fā)送N個(gè)數(shù)據(jù)包,所需要的時(shí)間為:
TL=N*(T1+T2+T3+T4)
(1)
其中:T1遠(yuǎn)小于T2,而T3又遠(yuǎn)小于T4。T2和T4按照實(shí)際傳輸?shù)淖止?jié)數(shù)計(jì)算時(shí)間。9 600 bps波特率下,1秒鐘傳輸1200字節(jié)數(shù)據(jù)。
按照?qǐng)D9(b)滑動(dòng)窗口模式下,發(fā)送N個(gè)數(shù)據(jù)包所需要的時(shí)間為:
圖9 兩種模式離線交易上傳時(shí)間統(tǒng)計(jì)
TH=N*(T1+T2) +T3'+T4'
(2)
其中:T1遠(yuǎn)小于T2,而T3又遠(yuǎn)小于T4',隨著窗口的增大,由于T4'包含了窗口所有數(shù)據(jù)包的ACK,所以T4'將會(huì)遠(yuǎn)大于T2。
RS485信道優(yōu)良的理想情況下(傳輸無(wú)錯(cuò)包或者丟包),滑動(dòng)窗口模式與傳統(tǒng)停等應(yīng)答模式對(duì)比,節(jié)省的時(shí)間大約T' =TH-TL:
T'=N*(T3+T4)-(T3'+T4')
(3)
單片機(jī)一個(gè)while(1)大循環(huán)約為12 ms,每次大循環(huán)都發(fā)送一次離線交易(數(shù)據(jù)通過(guò)DMA傳送)且系統(tǒng)其他部件需要占用的時(shí)間至少為10 ms,等待ACK占用的時(shí)間大約為10 ms。那么T3至少應(yīng)該為20 ms。
在滑動(dòng)窗口模式下,無(wú)需等待ACK響應(yīng),系統(tǒng)可以以最快的速度發(fā)送數(shù)據(jù)包,省去了中間ACK的響應(yīng)時(shí)間,最后一個(gè)ACK響應(yīng)包包含了之前所有的數(shù)據(jù)包的響應(yīng)。
由于波特率較低,RS485的數(shù)據(jù)包一般不易過(guò)長(zhǎng),過(guò)長(zhǎng)在傳輸中勢(shì)必影響整個(gè)系統(tǒng)的可靠性,離線交易每條大約120字節(jié),傳輸時(shí)間為100 ms。傳輸數(shù)據(jù)包的個(gè)數(shù)N與節(jié)省的時(shí)間T'函數(shù)曲線如圖10所示。
圖10 傳輸數(shù)據(jù)包個(gè)數(shù)N與節(jié)省時(shí)間T'坐標(biāo)圖
如圖10所示,T'≈0.8 N,每發(fā)送一個(gè)數(shù)據(jù)包節(jié)省大概8 ms 的時(shí)間(DMA緩存開(kāi)的足夠大),可見(jiàn)數(shù)據(jù)包個(gè)數(shù)越多系統(tǒng)的效率就越高。
綜上所述,可見(jiàn)工業(yè)設(shè)備數(shù)據(jù)通信領(lǐng)域,特別是RS485協(xié)議上層應(yīng)用借鑒TCP滑動(dòng)窗口協(xié)議可以極大地提高數(shù)據(jù)傳輸效率,有效的解決因通信速率低引起的數(shù)據(jù)堵塞,數(shù)據(jù)冗余,以及傳輸時(shí)間成本過(guò)高的問(wèn)題。本文在TCP滑動(dòng)窗口協(xié)議的基礎(chǔ)上將糾錯(cuò)流控機(jī)制加入到RS485的傳輸協(xié)議當(dāng)中,可以有效的提高數(shù)據(jù)傳輸?shù)目煽啃砸约皩?shí)時(shí)性。