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