張欣然
(中國石油大港油田分公司信息中心,天津 300280)
隨著企業(yè)信息化進(jìn)程的推進(jìn),無論是哪個(gè)管理相關(guān)部門,都希望從工作的現(xiàn)場得到最新的數(shù)據(jù),并對這些新的數(shù)據(jù)進(jìn)行綜合的分析。然而,不同的控制器來自不同的廠商,通過不同的標(biāo)準(zhǔn),組成各自需要的系統(tǒng),并進(jìn)行控制,各個(gè)控制系統(tǒng)形成了互不相連的自動(dòng)化孤島,因?yàn)楹芏鄶?shù)據(jù)無法整體的采集到并進(jìn)行整體的分析與研究。從而更無法建立統(tǒng)一的生產(chǎn)過程數(shù)據(jù)平臺(tái),難以實(shí)現(xiàn)管理控制的一體化。
GPS數(shù)據(jù)提取方法分為兩個(gè)步驟:第一步,GPS數(shù)據(jù)的捕獲;第二步,GPS數(shù)據(jù)的解析。前者采用串口通信的方式把GPS接口與主機(jī)相連接,利用VC++的MSComm控件實(shí)現(xiàn)對串口編程,捕獲GPS接收機(jī)所發(fā)送的數(shù)據(jù);后者根據(jù)捕獲的GPS數(shù)據(jù)幀格式中的幀頭確定要給哪個(gè)數(shù)據(jù)幀進(jìn)行數(shù)據(jù)的解析,然后根據(jù)數(shù)據(jù)幀結(jié)構(gòu)中的內(nèi)容提取所需要的信息。
VC++6.0提供的MSComm控件可以通過串行端口捕獲GPS信號(hào)接受機(jī)所發(fā)送過來的數(shù)據(jù),為應(yīng)用程序提供串行通信的功能。MSComm控件串口通信編程的基本流程如圖1所示:
現(xiàn)以”$GPRMC”數(shù)據(jù)幀解析為例,首先針對串口通信下捕獲的GPS數(shù)據(jù),判定幀頭是”$GPRMC”,其次根據(jù)所需要的信息(例如經(jīng)緯度、時(shí)間、速度等)確定需要提取該幀頭后的數(shù)據(jù)幀中哪些字段的內(nèi)容,最后對所提取出來的內(nèi)容進(jìn)行恰當(dāng)?shù)淖儞Q,服務(wù)于后續(xù)的具體應(yīng)用。
Linux系統(tǒng)將設(shè)備和文件的操作都作為對文件的處理,所以對設(shè)備的操作,內(nèi)核會(huì)返回一個(gè)文件描述符,需要將其作為參數(shù)傳給相對應(yīng)的函數(shù)。Linux中所有的設(shè)備文件都放在“/dev”目錄下,通過“ttyS+編號(hào)”命名相應(yīng)的串口資源,所以對應(yīng)路徑是“/devttyS*”。因而可以相對文件讀寫那樣訪問一個(gè)串口設(shè)備。
首先要對串口進(jìn)行設(shè)置,在termios.h完成對波特率等的設(shè)置。
struct termios
{tcflag t c iflag;
tcflag t c oflag;
tcflag t c cflag;
tcflag t c lflag;
cc t c cc[NCCS];
};
open() 函 數(shù) :int fd=open(“/dev/ttyS *”,O RDWR|O NOCTTY|O NDELA Y);
然后調(diào)用read()和write()函數(shù)讀寫端口,返回實(shí)際讀寫的字節(jié)數(shù),如果有錯(cuò)誤發(fā)生則返回-1。
讀取串口結(jié)束后,首先恢復(fù)串口原始屬性,然后才可以關(guān)閉串口并退出程序。
下面給出通過串口控制攝像頭函數(shù)的一部分結(jié)構(gòu):
void sendMsg(int pan,int tilt)
{struct timeval timeout;
static char *driver=”/dev/ttyS1”;
timeout.tv_sec=0;
timeout.tv_usec=0;
formCmd(buf,pan,tilt);
fd=uart_open(driver,B9600);
write(fd,buf,16);
close(fd);
}
在Win32中,串口和其他通信設(shè)備均被作為文件處理,串口的創(chuàng)建、打開、關(guān)閉和讀寫等操作所用的API函數(shù)與操作文件的函數(shù)相同??赏ㄟ^CreateFile()函數(shù)創(chuàng)建或打開串口,并通過CloseFile()函數(shù)關(guān)閉串口,此外還可以設(shè)置串口狀態(tài)。
部分源程序代碼實(shí)現(xiàn)如下:
HANDLEhPort=INVALID_HANDLE_VAL2UE;//端口句柄
DCBPortDCB;
hPort=CreateFile(“COM7”,GENERIC_READ|
GENERIC_WRITE,0,NULL,OPEN_EXISTING,F(xiàn)ILE_ATTRIBUTE_NORMAL,NULL);//打開COM7
SetupComm(hPort,512/3讀緩沖3/,512/3寫緩沖3/);//初始化通訊設(shè)備參數(shù)
if(!::GetCommState(hPort,&PortDCB))//獲取串口當(dāng)前屬性參數(shù)
returnfalse;
PortDCB.BaudRate=4800;//設(shè)置波特率
PortDCB.StopBits=ONESTOPBIT;//設(shè)置停止位
PortDCB.Parity=NOPARITY;//設(shè)置奇偶校驗(yàn)位
…
if( ::SetCommState(hPort,&PortDCB)==0)//重設(shè)端口參數(shù)
returnfalse;
COMMTIMEOUTSCommTimeOuts;
CommTimeOuts.ReadIntervalTimeout=MAX2DWORD;//接 收兩連續(xù)字節(jié)的最大時(shí)間間隔
CommTimeOuts.ReadTotalTimeoutMultiplier=10;//接收每字節(jié)的平均允許時(shí)間
CommTimeOuts.ReadTotalTimeoutConstant=1000;//接 收 時(shí) 間常數(shù)
SetCommTimeouts(hPort,&CommTimeOuts);//設(shè)置串口讀寫時(shí)間
PurgeComm(hPort,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);//對I/O進(jìn)行設(shè)置
在讀取函數(shù)中可采取輪詢串口和事件觸發(fā)兩種方式對數(shù)據(jù)進(jìn)行接收處理。本文在此采取效率比較高的事件觸發(fā)方式進(jìn)行接收處理,通過指定端口監(jiān)測并等待EV_RXCHAR事件的發(fā)生來啟動(dòng)ReadFile函數(shù)完成對GPS定位信息的接收任務(wù)。利用該函數(shù)從串口接收緩沖區(qū)中讀取數(shù)據(jù),通過一個(gè)循環(huán)使之不斷讀取GPS數(shù)據(jù)、寫入文件直至讀取結(jié)束或用戶終止。在整個(gè)應(yīng)用程序結(jié)束時(shí),將串行設(shè)備關(guān)閉。部分源程序代碼實(shí)現(xiàn)如下:
BYTEInByte;
DWORDBytesTransferred;DWORDfdwCommMask;
if(WaitCommEvent(hPort,&fdwCommMask,0))
SetCommMask(hPort,EV_RXCHAR);
bStopRead=false;
if(fdwCommMask&EV_RXCHAR){do
{ReadFile(hPort,&InByte,1,&BytesTransferred,0);
if(BytesTransferred==1)
ReadNMEA0183(InByte);//對串口讀出數(shù)據(jù)進(jìn)行解碼
}while(!bStopRead&&1==BytesTrans2ferred);}
WindowsCE不支持重疊I/O,I/O操作函數(shù)在I/O操作結(jié)束前不能返回,這將掛起調(diào)用線程,直到I/O操作結(jié)束。使用多線程可以充分利用CPU資源,提高傳輸速度。在實(shí)現(xiàn)的過程中,對串口的讀寫可以定義在一個(gè)讀線程函數(shù)中:
DWORDWINAPIReadThread(LPVOIDpvarg)。
本文介紹的GPS與PDA的串口通信軟件可以嵌入到大部分的Palm OS的程序中,很好地完成現(xiàn)串口通信的基本任務(wù)。該串口通信軟件現(xiàn)已集成在一家國外公司的自動(dòng)售卡機(jī)產(chǎn)品中,且已投入使用。