LabVIEW串口通信詳解
電子工程專輯
【原文地址】http://t.cn/EK86Qo3

串口可以說是我們最容易見到,也最容易接觸到的一種總線,臺式機上一般都有二個,而現(xiàn)在很多下位機、儀器等很多都還是使用串口通信的
1,串口擴展的問題
先說一下串口的擴展問題,一般的臺式機或工控機上都至少有二個串口,一般都是夠用的,但是現(xiàn)在市場上已經(jīng)很難找到帶串口的筆記本了,而有時候在外出調(diào)試時需要在筆記本中使用到串口的,這時一般是使用USB-RS232的轉(zhuǎn)接線,價格從十幾到一百多都有,很多朋友反應(yīng)在使用價格低的轉(zhuǎn)接線時會出現(xiàn)亂七八糟的問題,而貴一點的線就很少聽說有其它問題的,所以大家在使用便宜的USB-RS232轉(zhuǎn)接線時要特別注意線的質(zhì)量,遇到一些奇怪的問題時先考慮換一根好一點的線。PCI-RS232擴展卡也同理,便宜的卡也容易出問題,盡量買好一點的,以免因小失大。PCI-RS232一般至少能擴展2個串口,有些BT一點的可以擴展到8-16個,一堆線和接頭。轉(zhuǎn)接線和擴展卡一般是要裝驅(qū)動的。
2,串口功能的確認
在使用串口之前,最好先確認一下串口是否正常,特別是使用轉(zhuǎn)換接或擴展卡的。檢查的方法很簡單,就是將串口的2、3腳短接起來,腳是發(fā)送數(shù)據(jù),2腳接收數(shù)據(jù),就是這個串口自發(fā)自收。電腦上的串口軟件一般是用串口調(diào)試助手,很出名的,也好用。
3,串口線的檢查
檢查好串口后,一般也要注意一下使用的串口線,標(biāo)準(zhǔn)的串口線是9根線都是用上的,但有一些是只使用了三根線的:2、3、5。第3個腳管是發(fā)送,第2個管腳接收,另一個5是地線,這里叫它簡化的串口線,簡化的串口線能用上的地方,標(biāo)準(zhǔn)的串口線也肯定能用上,因為標(biāo)準(zhǔn)線的9根線已經(jīng)包括了簡化串口線中的3根線,但標(biāo)準(zhǔn)串口線能用上的地方,簡化串口線就不一定能用上,所以在使用串口線之間一定要確定好串口線的類型,一般買的串口線都是標(biāo)準(zhǔn)線,但自制的串口線因為應(yīng)用場合不同就要先確定一下。串口線還有一個地方需要注意一下的,就是2、3腳的接法,標(biāo)準(zhǔn)接法中是2、3腳交叉的,即這邊的2接另一邊的3,這邊的3接另一邊的2,扭了一下,所以叫交叉線,因為正常使用時,這邊第二腳是發(fā)送數(shù)據(jù),另一邊第三腳是接收數(shù)據(jù),所以要將這二個管腳連接起來,這樣才能正常使用。但是有些情況下,2、3是直連的,即這邊的第2腳連接另一邊的第2腳,第3腳連接第3腳,這種叫直連線,這種線一般是用于延長串口的,比如需要將工控機的串口接頭引到機柜表面上時,就使用這種線,這樣機柜表面的串口線的定義還是跟電腦接出來的一樣,外面的那一根串口線再使用交叉線。從電腦主板上將串口引到主機后面板上的線就是這樣的直連線。購買串口線的時候一般也會問你買直連的還是交叉的,要區(qū)別對待。串口線還有一個要稍微注意一下的就是DB頭,因為電腦上接出來的一般是公頭(針),要跟電腦接的話要母頭(孔),一般儀器的串口也是公頭,所以二邊都是母頭的串口線比較常見。串口的接頭一般是DB9的,也有DB25的,但比較少用,有些比較BT的儀器廠家居然用RJ11(水晶頭那種)作為串口頭,讓人不爽總之,使用串口前一定要先確定好硬件沒問題,不然很浪費時間的。
4,串口參數(shù)設(shè)置
在LabVIEW中使用串口時,有幾個參數(shù)比較重要,需要先說明一下的。一個是串口初始化這個節(jié)點的“終止符”和“禁用終止符?”這二個輸入端,這二個輸入端是相互作用的,“終止符”默認值為10,它的十六進制是“0x0A”,這是一個ASCII碼,是一個換行符,可以從LabVIEW中的字符串的不同顯示形式看出來,如下圖:

左邊是字符串的正常顯示,中間是十六進制顯示,右邊是“\代碼顯示”,這三個字符串的值都是一樣的。終止符是10,表示在接收數(shù)據(jù)時,遇到ASCII碼為10的字符(即換行符)時就停止接收數(shù)據(jù),后面會有例子進行說明。而“禁用終止符?”的默認值是FALSE,即啟用終止符,啟用終止符會有什么效果呢?終止符的意思就是當(dāng)程序接收到這個字符時,就認為已經(jīng)到了所有數(shù)據(jù)的未端了,從而停止接收,不管后面還有沒有數(shù)據(jù)。終止符是10,表示在接收數(shù)據(jù)時,遇到ASCII碼為10的字符(即換行符)時就停止接收數(shù)據(jù)。?
可以做一個很簡單的試驗,先短接串口2、3腳,然后將終止符設(shè)置為“0x33”,0x33是字符“3”的ASCII碼,然后發(fā)送字符串“123456”,可以看到接收回來的數(shù)據(jù)中只有“12”,即“3”被認為是字符串的未端了,它后面的數(shù)據(jù)就不再接收了。很多朋友就是因為!這里設(shè)置錯誤,導(dǎo)致接收數(shù)據(jù)時有時候只收到一半就沒有了,特別是在連續(xù)接收數(shù)據(jù)時,但又不是每次都只能收到一半,有時候也能接收齊全的,就是因為發(fā)送的數(shù)據(jù)中可能包含了終止符而使串口認為到了最后一個字符了。一般是將這個終止符禁用掉,即將“禁用終止符?”這一端輸入為TRUE即可。另外還有一個比較重要的設(shè)置,就是VISA READ的“讀取字節(jié)數(shù)”這個輸入,由于在串口通信中,如果指定讀取100個串口緩沖區(qū)的字節(jié)數(shù),如果當(dāng)前緩沖區(qū)的數(shù)據(jù)量不足100個時,程序會一直停在VISA READ這個節(jié)點上,如果在超時的時間(默認是10秒)內(nèi)還沒有湊足/100個數(shù)據(jù)的話,程序就會報“Time out”的錯誤,如果超時時間設(shè)置得太長,有可能導(dǎo)致程序很長時間停止在VISA READ這個節(jié)點上。解決的辦法是使用“Bytes at Port”這個串口的屬性節(jié)點,在VISA>>Serial>>advance下,也可以在VISA資源線上右鍵>>創(chuàng)建>>屬性節(jié)點>>串口設(shè)置>>Bytes at Port,如下圖:

這個屬性節(jié)點讀取當(dāng)前串口緩沖區(qū)有字節(jié)數(shù),然后將它的輸出連接到VISA READ的“讀取字節(jié)數(shù)”這個輸入端上即可,這樣當(dāng)前緩沖區(qū)中有多少個字節(jié)就讀回多少個,不會有任何等待。
5,在LabVIEW中使用串口
目前串口的應(yīng)用一般有二種類型的(以我接觸到的來分類,不嚴(yán)格),一種是儀器控制類型的,一般是上位機發(fā)送一個指令,然后下位機作出響應(yīng),返回數(shù)據(jù)給上位機,上位機再讀取出來,完成一次通信,即一問一答;另一類是被動接收形的,即下位機會一直發(fā)送數(shù)據(jù)上來。這二種類型的串口通信在處理上會不太一樣。
5.1 儀器控制類型
由于在儀器控制時一般都是這種一問一答的方式,所以叫它儀器控制類型。以儀器控制為例來說一下需要注意的事項。首先是要確認儀器選擇的通信模式是串口通信模式?,F(xiàn)在的儀器一般都至少有二種通信模式,一種是RS232,一種是GPIB,如果儀器是設(shè)置為GPIB通信的話,RS232是不可能通信上的,所以要先確認一下,方法一般是在儀器面板上選擇設(shè)置>>遠程控制>>GPIB/RS232,各個儀器稍微不同,可以查儀器手冊看一下。 然后就是確認串口的通信參數(shù)的配置,包括波特率、數(shù)據(jù)長度、校驗方法等,有些儀器的某些參數(shù)是固定的,比如校驗方法固定為奇校驗,不能修改,只能在電腦上跟儀器設(shè)置為一樣的。波特率一般是可以修改的。這些參數(shù)的配置一定要根據(jù)儀器手冊上的來設(shè)置。如果參數(shù)設(shè)置不正確,也能收到一些數(shù)據(jù),但一般是亂碼,如果收到的數(shù)據(jù)都是亂碼的話,就要先檢查一下串口參數(shù)設(shè)置是否正確了。只有電腦和儀器二邊的串口參數(shù)完全一致時才能收到正確的數(shù)據(jù)。接著是要注意發(fā)送指令和讀回數(shù)據(jù)之間要有一定的延時,即VISA WRITE和VISA READ之間要有一定的延時,一般200毫秒即可,因為'串口是底層硬件,數(shù)據(jù)從軟件到串口上要一點點時間,然后儀器對指令作出響應(yīng)也要一點點時間,這些時間加起來肯定比軟件運行二個節(jié)點的時間要短,所以延時是一定要加的。在調(diào)試時如果發(fā)現(xiàn)正常運行時不能收到數(shù)據(jù),但高亮運行就能收到數(shù)據(jù),就很有可能是沒有加延時的原因,或者是發(fā)一個查詢指令,但返回的是上一條查詢指令的結(jié)果,也可能是因為沒有延時或延時不夠。
5.2被動接收類型
被動接收形的串口通信稍微麻煩一點,由于上位機是被動接收的,上位機不知道什么時候開始下位機就已經(jīng)有數(shù)據(jù)上來了,很有可能下位機發(fā)送到一半時,上位機剛好開始接收數(shù)據(jù),這時只能接收到后面一半的數(shù)據(jù)了,所以對于這種通信,一般是采用數(shù)據(jù)幀的方式進行通信。這種數(shù)據(jù)幀的通信方式至少由三部分數(shù)據(jù)組成:幀頭、數(shù)據(jù)、幀尾(如果數(shù)據(jù)是固定長度的話,似乎幀尾也可以省掉)。幀頭是為了告訴上位機:從這以后的數(shù)據(jù)就是有用的數(shù)據(jù)了,相當(dāng)于約定好的暗號,一般幀頭至少會用二個以上字節(jié),如果只用一個字節(jié)的話,萬一數(shù)據(jù)中的數(shù)據(jù)跟這個幀頭一樣了就會誤以為這個數(shù)據(jù)是幀頭從而導(dǎo)致解析數(shù)據(jù)出錯,幀尾的作用也差不多,告訴上位機從這之前的數(shù)據(jù)才是有用的數(shù)據(jù)。但實際上一般的數(shù)據(jù)幀遠不止這幾個部分,還會加上一些校驗字節(jié)、時間信息、幀計數(shù)器之類的東東在上面。其中校驗字節(jié)是為了檢查數(shù)據(jù)在傳輸過程中有沒有出錯的,跟串口的校驗位要區(qū)分清楚,校驗位也是檢查數(shù)據(jù)傳輸時有沒有出錯的,但由底層硬件來實現(xiàn),校驗方法由標(biāo)準(zhǔn)規(guī)定好,但有幾種可以選擇,只有一個位(Bit,只能是0或1),校驗字節(jié)是由軟件層來實現(xiàn)的,至少有一個字節(jié)(Byte,有8個位),而且校驗方式由用戶定義,非常靈活。由于被動方式中串口的緩沖區(qū)中一直會有數(shù)據(jù)在,為了保持數(shù)據(jù)的連續(xù)性,在讀取數(shù)據(jù)時跟第一種儀器控制類型不一樣。而是采取將讀取的所有的串口數(shù)據(jù)都保存在移位寄存器中,在軟件上處理完這些數(shù)據(jù)后再將它們從移位寄存器中刪除。由于VISA READ的輸出是字符串,所以一般使用“連接字符串”這個函數(shù)將它們連接起來,然后接到循環(huán)結(jié)構(gòu)中的移位寄存器中進行保存,當(dāng)移位寄存器中的數(shù)據(jù)量達到一定時或滿足數(shù)據(jù)處理的條件時,才停止這個循環(huán)輸出讀取到的數(shù)據(jù)。一般如下圖所示

在接收下位機發(fā)送的幀數(shù)據(jù)時,一定要先了解幀格式,這樣才能正確解析出幀里面的數(shù)據(jù)來。 下面以例子來說明數(shù)據(jù)幀格式的通信。設(shè)定通信數(shù)據(jù)幀每7個字節(jié)為一幀數(shù)據(jù),其中以0xAC、0x96二個字節(jié)作為數(shù)據(jù)幀頭,第三、四個幀頭為幀計數(shù)器,最大值為0xFFFF,到達最大值后重新從0開始計數(shù),第4、5、6三個字節(jié)是數(shù)據(jù)信息,分別代表數(shù)據(jù)的高中低位,第7位為狀態(tài)標(biāo)志字節(jié),它的第一位為1時表示下位機出錯,為0時表示功能正常。由于LabVIEW中接收到的數(shù)據(jù)都是以字符串的形式顯示出來的,所以需要將字符串轉(zhuǎn)換為ASCII碼,一般可以直接使用“轉(zhuǎn)換為U8數(shù)組”這個函數(shù),如下圖所示:

轉(zhuǎn)換為U8字節(jié)后,得到的是所傳輸字符的ASCII碼,我們就很容易進行數(shù)據(jù)幀的判斷了,現(xiàn)收到以下的字符串?dāng)?shù)據(jù):

圖 6 實際接收到的字符串
上圖中下半部分顯示的數(shù)組是使用“字符串轉(zhuǎn)換為U8數(shù)組”的函數(shù)轉(zhuǎn)換之后得到的數(shù)組,一個是十六進制顯示,另一個為十進制顯示。對照定義的數(shù)據(jù)幀格式,就很容易得到我們需要的數(shù)據(jù)了。首先是要看從哪里開始才是完整的第一幀,從上面十六進制顯示的數(shù)組中我們可以看到,并不是第一個字節(jié)就是我們需要的幀頭,因為下位機是一直處于發(fā)送數(shù)據(jù)的狀態(tài),很可能在串口發(fā)送一幀數(shù)據(jù)的過程中串口就被初始化或者被清空了一次緩沖區(qū),那么這一幀數(shù)據(jù)的前面部分數(shù)據(jù)可能就會丟失,只留下后面一部分數(shù)據(jù),以上圖為例子,第一二個字節(jié)為0x32、0x22,顯示不是我們要的幀頭,我們要的幀頭是在第6、7個字節(jié),以程序來實現(xiàn)的話就是先查找第一個幀頭,使用“搜索字符串”,如果找到則判斷它下一個字節(jié)是否是第二個幀頭,如果是,表明已經(jīng)找到幀頭,輸出幀頭的位置;如果它下一個字節(jié)不是第二個幀頭,說明這里不是真正的幀頭,繼續(xù)查找下一個幀頭,直到找到幀頭或搜索完整個字符串都找不到幀頭。這是一個程序的算法問題,具體實現(xiàn)的程序如下圖所示:

圖7、幀頭查找程序
幀頭查找到以后,再找數(shù)據(jù)就容易了,根據(jù)之前的定義,第4、5、6個字節(jié)是才是我們要的數(shù)據(jù),所以直接使用索引號進行索引輸出即可。?

一般情況下,如果是用三個字節(jié)表示一個數(shù)據(jù)的話,那么這三個字節(jié)分別表示為一個數(shù)據(jù)的高中低字節(jié),即高字節(jié)要乘以25536再加上中字節(jié)乘以256再加上低字節(jié)的,這樣定義后可表示的數(shù)據(jù)的范圍就會擴大很多,但這里為了說明問題,直接認為三個字節(jié)的數(shù)據(jù)相加就是我們要的實際數(shù)據(jù),在實際使用過程中應(yīng)該根據(jù)幀格式的字義來解析這個數(shù)據(jù)。另外幀格式中定義了最后一個字節(jié)為狀態(tài)標(biāo)志位,所以提取數(shù)據(jù)前還要檢查一下這個標(biāo)志位是否正常,不正常時要進行相應(yīng)的處理,這里不再詳細描述。至此完成一次數(shù)據(jù)幀的提取。如果是沒什么特殊的要求的話,這里應(yīng)該也算到一段落了,有一些對測試時間有要求的地方,就會要求在最短的時間內(nèi)得到最多的信息,從圖6中我們可以看到,接收到的數(shù)據(jù)幀中,除了中間一個完整的幀之外,頭尾還有一些無用的數(shù)據(jù),其實這些數(shù)據(jù)中也包含了有用的信息/的,比如我們可以從0xAC、0x96這二個幀的位置中推斷中它前面的0x22、0x2A、0x38這三個字節(jié)也是我們想要的數(shù)據(jù)字節(jié),但是由于沒有接收到它的幀頭,所以程序沒能提取出來,但我們可以從后一幀的幀頭推算出前面那一幀的數(shù)據(jù)字節(jié)是哪些,即使沒收到前面那一幀的幀頭。這里只給出一個流程,不再給出具體的程序。另外有可能接收的數(shù)據(jù)長度比較長,可能就不止包含了一幀的數(shù)據(jù)在里面,所以在程序中也要判斷一下剩下的數(shù)據(jù)還夠不夠一幀的數(shù)據(jù)長度,如果夠則可以根據(jù)上一次查找的幀頭位置+數(shù)據(jù)幀長度來確定下一個數(shù)據(jù)幀的幀頭位置了,不需要使用搜索的方法。也可能存在處理完一幀數(shù)據(jù)后,剩下的數(shù)據(jù)不夠一個幀的,這時可以將這些剩下的數(shù)據(jù)保留起來,將它添加到下一次接收到的數(shù)據(jù)前面,組成新的數(shù)據(jù)再進行處理。去掉已經(jīng)處理的數(shù)據(jù)可以使用“刪除數(shù)組元素”這個函數(shù)來實現(xiàn)。這里也不再給出具體的程序。
6,串口數(shù)據(jù)類型的轉(zhuǎn)換
由于LabVIEW中VISA Read/Write這二個函數(shù)都是只能讀取/寫入字符串類型的數(shù)據(jù)的,而有時候需要接收/寫入的數(shù)據(jù)類型不一定是字符串,導(dǎo)致在剛開始接觸的時候會有一點困惑。 在進行數(shù)據(jù)轉(zhuǎn)換時,只要記住計算機中所有數(shù)據(jù)都是以二進制保存這個原則就容易解決問題了。串口線上傳輸?shù)囊彩歉叩?,串口接收到的也是二進制數(shù)據(jù),只是到LabVIEW后被轉(zhuǎn)換為字符串格式了。還是以例子進行解釋。假設(shè)LabVIEW從串口接收到的數(shù)據(jù)為“1234”(正常顯示模式下),那么這個數(shù)據(jù)在串口底層的時候其實是這樣的二進制數(shù)據(jù):00110001 00110010 00110011 00110100"只是在LabVIEW中,這些二進制數(shù)據(jù)是以字符串形式顯示出來的,它們的實質(zhì)還是二進制數(shù)據(jù),這幾個二進制數(shù)據(jù)轉(zhuǎn)換為十進制數(shù)據(jù)分別是“49,50,51,52”,由于字符串都是以ASCII碼形式保存在計算機中的,那么49,50,51,52這幾個數(shù)在ASCII表中就表示是字符串“1,2,3,4”。所以這幾個數(shù)據(jù)在LabVIEW中就顯示為字符串的1,2,3,4了。 如果明白這里面的轉(zhuǎn)換關(guān)系,那么要進行數(shù)據(jù)轉(zhuǎn)換時就很容易了,比如上面的例子中,如果LabVIEW中接收到的是字符串“1234”,而原本下位機傳送的是數(shù)值型數(shù)據(jù),只需要將“1234”字符串轉(zhuǎn)換為對應(yīng)的ASCII值就是實際上下位機傳上來的數(shù)據(jù)了,就是“49,50,51,52”。LabVIEW中將字符串轉(zhuǎn)換為對應(yīng)的ASCII值的函數(shù)是“字符串至字節(jié)數(shù)組轉(zhuǎn)換”這個函數(shù)::

圖 9 字符串轉(zhuǎn)換為字節(jié)數(shù)組
上面說的是下位機發(fā)送的是數(shù)值類型的數(shù)據(jù)的,使用“字符串至字節(jié)數(shù)組轉(zhuǎn)換”這個函數(shù),如果是下位面發(fā)送的是字符串類型的數(shù)據(jù),那么LabVIEW已經(jīng)直接轉(zhuǎn)換好了。還有一個問題是使用LabVIEW發(fā)送數(shù)據(jù)的問題,如果下位機接收的是字符串?dāng)?shù)據(jù)類型的話,直接用VISA寫入對應(yīng)的字符串就行了,現(xiàn)在的儀器一般都是接收字符串的,所以可以直接使用VISA發(fā)送而不需要轉(zhuǎn)換。如果下位機接收的是數(shù)值型數(shù)據(jù)的話,就需要轉(zhuǎn)換一下,其中數(shù)值型又是十進制和十六進制二種用得比較多,這二種數(shù)據(jù)間相互轉(zhuǎn)換一下就行了,其實是一樣的。由于在LabVIEW中字符串直接有十六進制的顯示方式,所以發(fā)送十六進制的數(shù)據(jù)比較方便,比如要發(fā)送十六進制數(shù)值類型的“0xAF”,那么在VISA Write的寫入緩沖區(qū)字符串常量上右鍵>>十六進制顯示,如圖1,直接輸入“AF”即可,那么下位機接收到的就是正確的數(shù)據(jù)(十六進制數(shù)值類型)了。但實際使用過程中,一般都是需要將某個子VI輸出一個動態(tài)的字符串通過VISA Write發(fā)送到下位機的,這時候就需要對數(shù)據(jù)進行轉(zhuǎn)換一下,這個轉(zhuǎn)換過程描述起來就是:將字符串A轉(zhuǎn)換為字符串B,使得正常顯示的字符串A跟十六進制顯示的字符串B是一樣的。由于轉(zhuǎn)換目標(biāo)(十六進制顯示的字符串)的數(shù)據(jù)類型是十六進制,要想十六進制顯示的字符串跟正常顯示的字符串一樣,這個正常顯示的字符串必須都是十六進制的字符,即只能由0-9,A-F這十六個字母中的字母組合而成。否則就沒辦法使二種顯示方式的字符串一致了。這個轉(zhuǎn)換過程首先將字符串轉(zhuǎn)換為十六進制數(shù)值型,然后再通過將這個十六進制數(shù)值創(chuàng)建為一個數(shù)組,最后再使用“字節(jié)數(shù)組至字符串轉(zhuǎn)換”這個函數(shù)轉(zhuǎn)換為字符串即可,實際上就是圖5字符串轉(zhuǎn)換為U8字節(jié)的反向操作,只不過是這個十六進制的值初始類型是十六進制,

圖 10 正常顯示字符串轉(zhuǎn)換為相同的十六進制顯示的字符串
由于十六進制數(shù)據(jù)由二個字節(jié)構(gòu)成,而字符只有一個字符,所以每二個字符表示一個十六進制數(shù)據(jù),如果字符多于二個的話要先進行截取,每二個字符轉(zhuǎn)換為一個十六進制數(shù)據(jù)。也可以用空格將正常顯示的字符串每二個字符用一個空格斷開,然后先將這個字符串以空格為分隔符轉(zhuǎn)換為一個字符串?dāng)?shù)組,再轉(zhuǎn)換為十六進制數(shù)值再轉(zhuǎn)換為字符串。需要注意一下的是如果正常顯示的字符串并不是2的整數(shù)倍,那么上圖的轉(zhuǎn)換程序就會少轉(zhuǎn)換一個字符,可以用程序動態(tài)判斷一下這個字符串的長度,如果是奇數(shù)的話在它最左邊補一個“0”再使用上面的程序就正常了。

「本人無意侵犯版權(quán)」,如有侵權(quán),請來信告知即刻撤除。?
內(nèi)容不代表本人觀點,如有不實或其它問題,請按地址聯(lián)系原作者。