串行通信與重疊IO_第1頁
串行通信與重疊IO_第2頁
串行通信與重疊IO_第3頁
串行通信與重疊IO_第4頁
串行通信與重疊IO_第5頁
已閱讀5頁,還剩9頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、串行通信與重疊I/OWin 32系統(tǒng)把文件的概念進(jìn)行了擴(kuò)展。無論是文件、通信設(shè)備、命名管道、郵件槽、磁盤、還是控制臺,都是用API函數(shù)CreateFile來打開或創(chuàng)建的。該函數(shù)的聲明為: HANDLE CreateFile( LPCTSTR lpFileName, / 文件名  DWORD dwDesiredAccess, / 訪問模式  DWORD dwShareMode, / 共享模式  LPSECURITY_ATTRIBUTES lpSecurityAttributes, / 通常為NULL DWORD dwCreationDi

2、stribution, / 創(chuàng)建方式  DWORD dwFlagsAndAttributes, / 文件屬性和標(biāo)志 HANDLE hTemplateFile / 臨時文件的句柄,通常為NULL  ); 如果調(diào)用成功,那么該函數(shù)返回文件的句柄,如果調(diào)用失敗,則函數(shù)返回INVALID_HANDLE_VALUE。 在打開通信設(shè)備句柄后,常常需要對串行口進(jìn)行一些初始化工作。這需要通過一個DCB結(jié)構(gòu)來進(jìn)行。DCB結(jié)構(gòu)包含了諸如波特率、每個字符的數(shù)據(jù)位數(shù)、奇偶校驗和停止位數(shù)等信息。在查詢或配置置串行口的屬性時,都要用DCB結(jié)構(gòu)來作為緩沖區(qū)。 調(diào)用GetCommSta

3、te函數(shù)可以獲得串口的配置,該函數(shù)把當(dāng)前配置填充到一個DCB結(jié)構(gòu)中。一般在用CreateFile打開串行口后,可以調(diào)用GetCommState函數(shù)來獲取串行口的初始配置。要修改串行口的配置,應(yīng)該先修改DCB結(jié)構(gòu),然后再調(diào)用SetCommState函數(shù)用指定的DCB結(jié)構(gòu)來設(shè)置串行口。 除了在DCB中的設(shè)置外,程序一般還需要設(shè)置I/O緩沖區(qū)的大小和超時。Windows用I/O緩沖區(qū)來暫存串行口輸入和輸出的數(shù)據(jù),如果通信的速率較高,則應(yīng)該設(shè)置較大的緩沖區(qū)。調(diào)用SetupComm函數(shù)可以設(shè)置串行口的輸入和輸出緩沖區(qū)的大小。 在用ReadFile和WriteFile讀寫串行口時,需要考慮超時問題。如果在

4、指定的時間內(nèi)沒有讀出或?qū)懭胫付〝?shù)量的字符,那么ReadFile或WriteFile的操作就會結(jié)束。要查詢當(dāng)前的超時設(shè)置應(yīng)調(diào)用GetCommTimeouts函數(shù),該函數(shù)會填充一個COMMTIMEOUTS結(jié)構(gòu)。調(diào)用SetCommTimeouts可以用某一個COMMTIMEOUTS結(jié)構(gòu)的內(nèi)容來設(shè)置超時。 有兩種超時:間隔超時和總超時。間隔超時是指在接收時兩個字符之間的最大時延,總超時是指讀寫操作總共花費的最大時間。寫操作只支持總超時,而讀操作兩種超時均支持。用COMMTIMEOUTS結(jié)構(gòu)可以規(guī)定讀/寫操作的超時,該結(jié)構(gòu)的定義為: typedef struct _COMMTIMEOUTS  

5、 DWORD ReadIntervalTimeout; / 讀間隔超時 DWORD ReadTotalTimeoutMultiplier; / 讀時間系數(shù) DWORD ReadTotalTimeoutConstant; / 讀時間常量 DWORD WriteTotalTimeoutMultiplier; / 寫時間系數(shù) DWORD WriteTotalTimeoutConstant; / 寫時間常量 COMMTIMEOUTS,*LPCOMMTIMEOUTS; COMMTIMEOUTS結(jié)構(gòu)的成員都以毫秒為單位??偝瑫r的計算公式是: 總超時=時間系數(shù)×要求讀/寫的字符數(shù) + 時

6、間常量 例如,如果要讀入10個字符,那么讀操作的總超時的計算公式為: 讀總超時ReadTotalTimeoutMultiplier×10 + ReadTotalTimeoutConstant 可以看出,間隔超時和總超時的設(shè)置是不相關(guān)的,這可以方便通信程序靈活地設(shè)置各種超時。 如果所有寫超時參數(shù)均為0,那么就不使用寫超時。如果ReadIntervalTimeout為0,那么就不使用讀間隔超時,如果ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都為0,則不使用讀總超時。如果讀間隔超時被設(shè)置成MAXDWORD并且兩個讀總超時為0,那么

7、在讀一次輸入緩沖區(qū)中的內(nèi)容后讀操作就立即完成,而不管是否讀入了要求的字符。 在用重疊方式讀寫串行口時,雖然ReadFile和WriteFile在完成操作以前就可能返回,但超時仍然是起作用的。在這種情況下,超時規(guī)定的是操作的完成時間,而不是ReadFile和WriteFile的返回時間。 在用ReadFile和WriteFile讀寫串行口時,既可以同步執(zhí)行,也可以重疊(異步)執(zhí)行。在同步執(zhí)行時,函數(shù)直到操作完成后才返回。這意味著在同步執(zhí)行時線程會被阻塞,從而導(dǎo)致效率下降。在重疊執(zhí)行時,即使操作還未完成,調(diào)用的函數(shù)也會立即返回。費時的I/O操作在后臺進(jìn)行,這樣線程就可以干別的事情。例如,線程可以在

8、不同的句柄上同時執(zhí)行I/O操作,甚至可以在同一句柄上同時進(jìn)行讀寫操作?!爸丿B”一詞的含義就在于此。 ReadFile函數(shù)只要在串行口輸入緩沖區(qū)中讀入指定數(shù)量的字符,就算完成操作。而WriteFile函數(shù)不但要把指定數(shù)量的字符拷入到輸出緩沖中,而且要等這些字符從串行口送出去后才算完成操作。 ReadFile和WriteFile函數(shù)是否為執(zhí)行重疊操作是由CreateFile函數(shù)決定的。如果在調(diào)用CreateFile創(chuàng)建句柄時指定了FILE_FLAG_OVERLAPPED標(biāo)志,那么調(diào)用ReadFile和WriteFile對該句柄進(jìn)行的讀寫操作就是重疊的,如果未指定重疊標(biāo)志,則讀寫操作是同步的。 函數(shù)

9、ReadFile和WriteFile的參數(shù)和返回值很相似。這里僅列出ReadFile函數(shù)的聲明: BOOL ReadFile( HANDLE hFile, / 文件句柄 LPVOID lpBuffer, / 讀緩沖區(qū) DWORD nNumberOfBytesToRead, / 要求讀入的字節(jié)數(shù)  LPDWORD lpNumberOfBytesRead, / 實際讀入的字節(jié)數(shù) LPOVERLAPPED lpOverlapped / 指向一個OVERLAPPED結(jié)構(gòu) ); /若返回TRUE則表明操作成功 需要注意的是如果該函數(shù)因為超時而返回,那么返回值是TRUE。參數(shù)lpOve

10、rlapped在重疊操作時應(yīng)該指向一個OVERLAPPED結(jié)構(gòu),如果該參數(shù)為NULL,那么函數(shù)將進(jìn)行同步操作,而不管句柄是否是由FILE_FLAG_OVERLAPPED標(biāo)志建立的。 當(dāng)ReadFile和WriteFile返回FALSE時,不一定就是操作失敗,線程應(yīng)該調(diào)用GetLastError函數(shù)分析返回的結(jié)果。例如,在重疊操作時如果操作還未完成函數(shù)就返回,那么函數(shù)就返回FALSE,而且GetLastError函數(shù)返回ERROR_IO_PENDING。 在使用重疊I/O時,線程需要創(chuàng)建OVERLAPPED結(jié)構(gòu)以供讀寫函數(shù)使用。OVERLAPPED結(jié)構(gòu)最重要的成員是hEvent,hEvent是一

11、個事件對象句柄,線程應(yīng)該用CreateEvent函數(shù)為hEvent成員創(chuàng)建一個手工重置事件,hEvent成員將作為線程的同步對象使用。如果讀寫函數(shù)未完成操作就返回,就那么把hEvent成員設(shè)置成無信號的。操作完成后(包括超時),hEvent會變成有信號的。 如果GetLastError函數(shù)返回ERROR_IO_PENDING,則說明重疊操作還為完成,線程可以等待操作完成。有兩種等待辦法:一種辦法是用象WaitForSingleObject這樣的等待函數(shù)來等待OVERLAPPED結(jié)構(gòu)的hEvent成員,可以規(guī)定等待的時間,在等待函數(shù)返回后,調(diào)用GetOverlappedResult。另一種辦法是

12、調(diào)用GetOverlappedResult函數(shù)等待,如果指定該函數(shù)的bWait參數(shù)為TRUE,那么該函數(shù)將等待OVERLAPPED結(jié)構(gòu)的hEvent 事件。GetOverlappedResult可以返回一個OVERLAPPED結(jié)構(gòu)來報告包括實際傳輸字節(jié)在內(nèi)的重疊操作結(jié)果。 如果規(guī)定了讀/寫操作的超時,那么當(dāng)超過規(guī)定時間后,hEvent成員會變成有信號的。因此,在超時發(fā)生后,WaitForSingleObject和GetOverlappedResult都會結(jié)束等待。WaitForSingleObject的dwMilliseconds參數(shù)會規(guī)定一個等待超時,該函數(shù)實際等待的時間是兩個超時的最小值。

13、注意GetOverlappedResult不能設(shè)置等待的時限,因此如果hEvent成員無信號,則該函數(shù)將一直等待下去。 在調(diào)用ReadFile和WriteFile之前,線程應(yīng)該調(diào)用ClearCommError函數(shù)清除錯誤標(biāo)志。該函數(shù)負(fù)責(zé)報告指定的錯誤和設(shè)備的當(dāng)前狀態(tài)。 調(diào)用PurgeComm函數(shù)可以終止正在進(jìn)行的讀寫操作,該函數(shù)還會清除輸入或輸出緩沖區(qū)中的內(nèi)容。/.2 調(diào)用Win32 API函數(shù)實現(xiàn)串行通信編程 Windows操作系統(tǒng)對系統(tǒng)底層操作采取了屏蔽的策略,禁止應(yīng)用程序直接訪問計算機(jī)I/O端口,而由設(shè)備驅(qū)動程序統(tǒng)一管理,Windows封裝了Windows的通信機(jī)制,這種方式稱為通信應(yīng)用

14、程序接口API(Application Programming Interfaces)。Windows 9x/NT/2000提供的API一般都支持32位的操作,又稱為Win32 API,程序員可以利用Win32 API的通信函數(shù)進(jìn)行編程,不用對硬件直接進(jìn)行操作,使得應(yīng)用程序的編制更加方便。 Win32 API常用通信函數(shù) 在進(jìn)行串口通信時,經(jīng)常需要用到下列一些API函數(shù):CreateFile():用于打開一個文件訪問串口;GetCommState():獲取串口的當(dāng)前配置,放入設(shè)備控制塊DCB中;SetCommState():根據(jù)DCB重新配置串口參數(shù);SetCommTimeouts():設(shè)置串

15、口讀寫操作的溢出時間;ReadFile():從串口的輸入緩沖區(qū)讀取數(shù)據(jù);WriteFile():向串口的輸出緩沖區(qū)寫入數(shù)據(jù);SetCommMask():監(jiān)視指定通信資源上的事件;WaitCommEvent():等待通信事件發(fā)生;CloseHandle():關(guān)閉由CreateFile函數(shù)打開的串口。 以上這些函數(shù)的原形可在參考文獻(xiàn)1中找到。1-在C+ Builder 6.0下基于api函數(shù)編寫串口通信程序簡介: 在dos/win95/win98的年代,操作系統(tǒng)對串口是不保護(hù)的,也就是說將串口的的資源完全開放給用戶,用戶可以用直接操作硬件的函數(shù)(比如說 TC2.0下的inport()和outpor

16、t()函數(shù)) 跟串口直接打交道,這時候用戶使用直接操作串口的函數(shù)怎樣"折磨"串口都是沒有問題的,操作系統(tǒng)根本就不管不問,對串口操作所造成的一切后果都是用戶一個 人承擔(dān)的,這時候用戶對串口具有高度自由的支配權(quán);但是,這種情況好景不長,從win2000操作系統(tǒng)開始,微軟為了"照顧好"計算機(jī)上的硬件,開始實施 了對硬件的保護(hù)策略,也就是說任何用戶在他的操作系統(tǒng)下企圖操縱串口時必須經(jīng)過他的同意方可進(jìn)行,其實也就是變相的將用戶往必須使用他的通信api函數(shù)才 能操作串口這條"羊腸小路"上趕(當(dāng)然也有別的方法操作串口,但那些并非我等普通用戶能研究明

17、白的),形象一點說就好像你想怎樣操作串口的意圖必須經(jīng)過 win2000的翻譯(其實是win2000的設(shè)備驅(qū)動程序)才能轉(zhuǎn)達(dá)給串口一樣,基于這一點我們說(其實是很多資料上說的)win2000下通過api 函數(shù)操作串口是具有"設(shè)備無關(guān)性的",什么意思呢?就是說你想怎樣操作串口就用相應(yīng)的api函數(shù)告訴操作系統(tǒng)你想對串口干什么,然后操作系統(tǒng)就把你的意思 轉(zhuǎn)告給串口讓其做出相應(yīng)的動作,相對于dos/win95/win98下來說,據(jù)我理解也就相當(dāng)于你原來寫的直接操作串口的函數(shù)在win2000下他替你 完成了,但是你必須用win2000通信api函數(shù)清楚地向操作系統(tǒng)表達(dá)清楚你到底想干什么

18、,所以說在這種情況下要想寫好串口驅(qū)動程序你就必須至少弄明白 win2000下的通信api函數(shù)都是干什么的方可,啰里啰唆嘮叨了這么多. .sorry, 還沒完呢,至少還有一件事我想說,原來在dos/win95/win98系統(tǒng)下有好多高手用c/c+對串口進(jìn)行直接操作是非常熟練的,尤其是dos時代 的turbo 2.0操作串口的高手他們寫的串口驅(qū)動程序直到win98的時候還用的非常洋洋得意,但是到了win2000的時候,他們的程序突然不好使了,而他們有的 可能還會因為知識結(jié)構(gòu)上的滯后始終弄不明白怎么回事兒,兄弟們,你們該明白了吧?閑話少敘,下面介紹筆者寫串口通信函數(shù)時用到的各個api函數(shù)- - 2-

19、CreateFile() 用途:打開串口 原型:HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); 參數(shù)說明: -lpFileName:要打開的文件名稱。對串口通信來說就是COM1或COM2。 -dwDesiredAccess:讀寫模式設(shè)置。

20、此處應(yīng)該用GENERIC_READ及GENERIC_WRITE。 -dwShareMode:串口共享模式。此處不允許其他應(yīng)用程序共享,應(yīng)為0。 -lpSecurityAttributes:串口的安全屬性,應(yīng)為0,表示該串口不可被子程序繼承。 -dwCreationDistribution:創(chuàng)建文件的性質(zhì),此處為OPEN_EXISTING. -dwFlagsAndAttributes:屬性及相關(guān)標(biāo)志,這里使用異步方式應(yīng)該用FILE_FLAG_OVERLAPPED。 -hTemplateFile:此處為0。 操作說明:若文件打開成功,串口即可使用了,該函數(shù)返回串口的句柄,以后對串口操作時 即可使用

21、該句柄。 舉例:HANDLE hComm; hComm=CreateFile("COM1", /串口號 GENERIC_READ|GENERIC_WRITE, /允許讀寫 0, /通訊設(shè)備必須以獨占方式打開 NULL, /無安全屬性 OPEN_EXISTING, /通訊設(shè)備已存在 FILE_FLAG_OVERLAPPED, /異步I/O 0); /通訊設(shè)備不能用模板打開 hComm即為函數(shù)返回的串口1的句柄。3-CloseHandle() 用途:關(guān)閉串口 原型:BOOL CloseHandle(HANDLE hObjedt) 參數(shù)說明: -hObjedt:串口句柄 操作說明

22、:成功關(guān)閉串口時返回true,否則返回false 舉例:CloseHandle(hComm); 4-GetCommState() 用途:取得串口當(dāng)前狀態(tài) 原型:BOOL GetCommState(HANDLE hFile, LPDCB lpDCB); 參數(shù)說明: -hFile:串口句柄 -lpDCB:設(shè)備控制塊(Device Control Block)結(jié)構(gòu)地址。此結(jié)構(gòu)中含有和設(shè)備相關(guān)的 參數(shù)。此處是與串口相關(guān)的參數(shù)。由于參數(shù)非常多,當(dāng)需要設(shè)置串口參數(shù) 時,通常是先取得串口的參數(shù)結(jié)構(gòu),修改部分參數(shù)后再將參數(shù)結(jié)構(gòu)寫入。 在此僅介紹少數(shù)的幾個常用的參數(shù): DWORD BaudRate:串口波特率

23、DWORD fParity:為1的話激活奇偶校驗檢查 DWORD Parity:校驗方式,值04分別對應(yīng)無校驗、奇校驗、偶校驗、校驗 置位、校驗清零 DWORD ByteSize:一個字節(jié)的數(shù)據(jù)位個數(shù),范圍是58 DWORD StopBits:停止位個數(shù),02分別對應(yīng)1位、1.5位、2位停止位 操作舉例:DCB ComDCB; /串口設(shè)備控制塊 GetCommState(hComm,&ComDCB); 5-SetCommState() 用途:設(shè)置串口狀態(tài),包括常用的更改串口號、波特率、奇偶校驗方式、數(shù)據(jù)位數(shù)等 原型:BOOL SetCommState(HANDLE hFile, LPD

24、CB lpDCB); 參數(shù)說明: -hFile:串口句柄 -lpDCB:設(shè)備控制塊(Device Control Block)結(jié)構(gòu)地址。要更改的串口參數(shù)包含在此結(jié)構(gòu)中。 操作舉例:DCB ComDCB; GetCommState(hComm,&ComDCB);/取得當(dāng)前串口狀態(tài) ComDCB.BaudRate=9600;/更改為9600bps,該值即為你要修改后的波特率 SetCommState(hComm,&ComDCB;/將更改后的參數(shù)寫入串口 6-WriteFile() 用途:向串口寫數(shù)據(jù) 原型:BOOL WriteFile(HANDLE hFile, LPCVOID l

25、pBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); 參數(shù)說明: -hFile:串口句柄 -lpBuffer:待寫入數(shù)據(jù)的首地址 -nNumberOfBytesToWrite:待寫入數(shù)據(jù)的字節(jié)數(shù)長度 -lpNumberOfBytesWritten:函數(shù)返回的實際寫入串口的數(shù)據(jù)個數(shù)的地址,利用此變量可判斷 實際寫入的字節(jié)數(shù)和準(zhǔn)備寫入的字節(jié)數(shù)是否相同。 -lpOverlapped:重疊I/O結(jié)構(gòu)的指針 操作舉例:DWORD BytesSent=0; unsi

26、gned char SendBytes5=1,2,3,4,5; OVERLAPPED ov_Write; ov_Write.Offset=0; ov_Write.OffsetHigh=0; WriteFile(hComm, /調(diào)用成功返回非零,失敗返回零 SendBytes, /輸出緩沖區(qū) 5, /準(zhǔn)備發(fā)送的字符長度 &BytesSent, /實際發(fā)出的字符數(shù) &ov_Write); /重疊結(jié)構(gòu) 如果函數(shù)執(zhí)行成功的話檢查BytesSent的值應(yīng)該為5,此函數(shù)是WriteFile函數(shù)執(zhí)行完畢后 自行填充的,利用此變量的填充值可以用來檢查該函數(shù)是否將所有的數(shù)據(jù)成功寫入串口7-Rea

27、dFile() 用途:讀串口數(shù)據(jù) 原型:BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); 參數(shù)說明: -hFile:串口句柄 -lpBuffer:存儲被讀出數(shù)據(jù)的首地址 -nNumberOfBytesToRead:準(zhǔn)備讀出的字節(jié)個數(shù) -NumberOfBytesRead:實際讀出的字節(jié)個數(shù) -lpOverlapped:異步I/O結(jié)構(gòu), 操作舉例:unsigned char ucRxBuff20; COMSTAT ComStat;

28、 DWORD dwError=0; DWORD BytesRead=0; OVERLAPPED ov_Read; ov_Read.hEvent=CreateEvent(NULL, true, false, NULL);/必須創(chuàng)建有效事件 ClearCommError(hComm,&dwError,&ComStat);/檢查串口接收緩沖區(qū)中的數(shù)據(jù)個數(shù) bResult=ReadFile(hComm, /串口句柄 ucRxBuff, /輸入緩沖區(qū)地址 ComStat.cbInQue, /想讀入的字符數(shù) &BytesRead, /實際讀出的字節(jié)數(shù)的變量指針 &ov_Re

29、ad); /重疊結(jié)構(gòu)指針 假如當(dāng)前串口中有5個字節(jié)數(shù)據(jù)的話,那么執(zhí)行完ClearCommError()函數(shù)后,ComStat 結(jié)構(gòu)中的ComStat.cbInQue將被填充為5,此值在ReadFile函數(shù)中可被直接利用。 8-ClearCommError() 用途:清除串口錯誤或者讀取串口現(xiàn)在的狀態(tài) 原型:BOOL ClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMATAT lpStat ); 參數(shù)說明: -hFile:串口句柄 -lpErrors:返回錯誤數(shù)值,錯誤常數(shù)如下: 1-CE_BREAK:檢測到中斷信號。意思是說檢測到某個字節(jié)數(shù)

30、據(jù)缺少合法的停止位。 2-CE_FRAME:硬件檢測到幀錯誤。 3-CE_IOE:通信設(shè)備發(fā)生輸入/輸出錯誤。 4-CE_MODE:設(shè)置模式錯誤,或是hFile值錯誤。 5-CE_OVERRUN:溢出錯誤,緩沖區(qū)容量不足,數(shù)據(jù)將丟失。 6-CE_RXOVER:溢出錯誤。 7-CE_RXPARITY:硬件檢查到校驗位錯誤。 8-CE_TXFULL:發(fā)送緩沖區(qū)已滿。 -lpStat:指向通信端口狀態(tài)的結(jié)構(gòu)變量,原型如下: typedef struct _COMSTAT . . DWORD cbInQue; /輸入緩沖區(qū)中的字節(jié)數(shù) DWORD cbOutQue;/輸出緩沖區(qū)中的字節(jié)數(shù) COMSTAT

31、,*LPCOMSTAT; 該結(jié)構(gòu)中對我們很重要的只有上面兩個參數(shù),其他的我們可以不用管。 操作舉例:COMSTAT ComStat; DWORD dwError=0; ClearCommError(hComm,&dwError,&ComStat); 上式執(zhí)行完后,ComStat.cbInQue就是串口中當(dāng)前含有的數(shù)據(jù)字節(jié)個數(shù),我們利用此 數(shù)值就可以用ReadFile()函數(shù)去讀串口中的數(shù)據(jù)了。9-PurgeComm() 用途:清除串口緩沖區(qū) 原型:BOOL PurgeComm(HANDLE hFile, DWORD dwFlags ); 參數(shù)說明: -hFile:串口句柄 -d

32、wFlags:指定串口執(zhí)行的動作,由以下參數(shù)組成: -PURGE_TXABORT:停止目前所有的傳輸工作立即返回不管是否完成傳輸動作。 -PURGE_RXABORT:停止目前所有的讀取工作立即返回不管是否完成讀取動作。 -PURGE_TXCLEAR:清除發(fā)送緩沖區(qū)的所有數(shù)據(jù)。 -PURGE_RXCLEAR:清除接收緩沖區(qū)的所有數(shù)據(jù)。 操作舉例:PurgeComm(hComm, PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT); 清除串口的所有操作。 10-SetCommMask() 用途:設(shè)置串口通信事件。 原型:BOOL Set

33、CommMask(HANDLE hFile, DWORD dwEvtMask ); 參數(shù)說明: -hFile:串口句柄 -dwEvtMask:準(zhǔn)備監(jiān)視的串口事件掩碼 注:在用api函數(shù)撰寫串口通信函數(shù)時大體上有兩種方法,一種是查尋法,另外一種是事件通知法。 這兩種方法的區(qū)別在于收串口數(shù)據(jù)時,前一種方法是主動的周期性的查詢串口中當(dāng)前有沒有 數(shù)據(jù);后一種方法是事先設(shè)置好需要監(jiān)視的串口通信事件,然后依靠單獨開設(shè)的輔助線程進(jìn)行 監(jiān)視該事件是否已發(fā)生,如果沒有發(fā)生的話該線程就一直不停的等待直到該事件發(fā)生后,將 該串口事件以消息的方式通知主窗體,然后主窗體收到該消息后依據(jù)不同的事件性質(zhì)進(jìn)行處理。 比如說當(dāng)

34、主窗體收到監(jiān)視線程發(fā)來的RX_CHAR(串口中有數(shù)據(jù))的消息后,就可以用ReadFile() 函數(shù)去讀串口。該參數(shù)有如下信息掩碼位值: EV_BREAK:收到BREAK信號 EV_CTS:CTS(clear to send)線路發(fā)生變化 EV_DSR:DST(Data Set Ready)線路發(fā)生變化 EV_ERR:線路狀態(tài)錯誤,包括了CE_FRAMECE_OVERRUNCE_RXPARITY 3鐘錯誤。 EV_RING:檢測到振鈴信號。 EV_RLSD:CD(Carrier Detect)線路信號發(fā)生變化。 EV_RXCHAR:輸入緩沖區(qū)中已收到數(shù)據(jù)。 EV_RXFLAG:使用SetComm

35、State()函數(shù)設(shè)置的DCB結(jié)構(gòu)中的等待字符已被傳入輸入緩沖區(qū)中。 EV_TXEMPTY:輸出緩沖區(qū)中的數(shù)據(jù)已被完全送出。 操作舉例:SetCommMask(hComm,EV_RXCHAR|EV_TXEMPTY); 上面函數(shù)執(zhí)行完畢后將監(jiān)視串口中有無數(shù)據(jù)和發(fā)送緩沖區(qū)中的數(shù)據(jù)是否全部發(fā)送完畢。 11-WaitCommEvent() 用途:用來判斷用SetCommMask()函數(shù)設(shè)置的串口通信事件是否已發(fā)生。 原型:BOOL WaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped ); 參數(shù)說明: -hFi

36、le:串口句柄 -lpEvtMask:函數(shù)執(zhí)行完后如果檢測到串口通信事件的話就將其寫入該參數(shù)中。 -lpOverlapped:異步結(jié)構(gòu),用來保存異步操作結(jié)果。 操作舉例:OVERLAPPED os; DWORD dwMask,dwTrans,dwError=0,err; memset(&os,0,sizeof(OVERLAPPED); os.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); if(!WaitCommEvent(hComm,&dwMask,&os) /如果異步操作不能立即完成的話,函數(shù)返回FALSE,并且調(diào)用GetLast

37、Error()函 /數(shù)分析錯誤原因后返回ERROR_IO_PENDING,指示異步操作正在后臺進(jìn)行.這種情 /況下,在函數(shù)返回之前系統(tǒng)設(shè)置OVERLAPPED結(jié)構(gòu)中的事件為無信號狀態(tài),該函數(shù) /等待用SetCommMask()函數(shù)設(shè)置的串口事件發(fā)生,共有9種事件可被監(jiān)視: /EV_BREAK,EV_CTS,EV_DSR,EV_ERR,EV_RING,EV_RLSD,EV_RXCHAR, /EV_RXFLAG,EV_TXEMPTY;當(dāng)其中一個事件發(fā)生或錯誤發(fā)生時,函數(shù)將 /OVERLAPPED結(jié)構(gòu)中的事件置為有信號狀態(tài),并將事件掩碼填充到dwMask參數(shù)中 if(GetLastError()=E

38、RROR_IO_PENDING) /*/ /*在此等待異步操作結(jié)果,直到異步操作結(jié)束時才返回.實際上此時 */ /*WaitCommEvent()函數(shù)一直在等待串口監(jiān)控的事件之一發(fā)生,當(dāng)事件發(fā)*/ /*生時該函數(shù)將OVERLAPPED結(jié)構(gòu)中的事件句柄置為有信號狀態(tài),此時 */ /*GetOverlappedResult()函數(shù)發(fā)現(xiàn)此事件有信號后馬上返回,然后下面*/ /*的程序馬上分析WaitCommEvent()函數(shù)等到的事件是被監(jiān)視的串口事 */ /*件中的哪一個,然后執(zhí)行相應(yīng)的動作并發(fā)出相應(yīng)消息. */ /*/ GetOverlappedResult(hComm,&os,&

39、;dwTrans,true); switch(dwMask) case EV_RXCHAR: PostMessage(Parent,WM_COMM_RXCHAR,0,0); break; case EV_TXEMPTY: PostMessage(Parent,WM_COMM_TXEMPTY,0,0); break; case EV_ERR: switch(dwError) case CE_FRAME: err=0; break; case CE_OVERRUN: err=1; break; case CE_RXPARITY: err=2; break; default:break; PostM

40、essage(Parent,WM_COMM_ERR,(WPARAM)0,(LPARAM)err); break; case EV_BREAK: PostMessage(Parent,WM_COMM_BREAK,0,0); break; case .:/其他用SetCommMask()函數(shù)設(shè)置的被監(jiān)視的串口通信事件。 . . break; default:break; /Win32串口編程金貝貝 一、基本知識 Win32下串口通信與16位串口通信有很大的區(qū)別。在Win32下,可以使用兩種編程方式實現(xiàn)串口通信,其一是調(diào)用的Windows的API函數(shù),其二是使用ActiveX控件。使用API 調(diào)用,

41、可以清楚地掌握串口通信的機(jī)制,熟悉各種配置和自由靈活采用不同的流控進(jìn)行串口通信。下面介紹串口操作的基本知識。 打開串口:使用CreateFile()函數(shù),可以打開串口。有兩種方法可以打開串口,一種是同步方式(NonOverlapped),另外一種異步方式(Overlapped)。使用Overlapped打開時,適當(dāng)?shù)姆椒ㄊ牵?HANDLE hComm;hComm = CreateFile( gszPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);if (hComm = INVALID_

42、HANDLE_VALUE)/ error opening port; abort配置串口: 1.DCB配置 DCB(Device Control Block)結(jié)構(gòu)定義了串口通信設(shè)備的控制設(shè)置。許多重要設(shè)置都是在DCB結(jié)構(gòu)中設(shè)置的,有三種方式可以初始化DCB。 (1)通過GetCommState()函數(shù)得DCB的初始值,其使用方式為: DCB dcb = 0;if (!GetCommState(hComm, dcb)/ Error getting current DCB settingselse/ DCB is ready for use.(2)用BuildCommDCB()函數(shù)初始化DCB結(jié)構(gòu)

43、,該函數(shù)填充 DCB的波特率、奇偶校驗類型、數(shù)據(jù)位、停止位。對于流控成員函數(shù)設(shè)置了缺省值。其用法是: DCB dcb;FillMemory(dcb, sizeof(dcb), 0);dcb.DCBlength = sizeof(dcb);if (!BuildCommDCB(“9600,n,8,1", dcb) / Couldn't build the DCB. Usually a problem/ with the communications specification string.return FALSE;else/ DCB is ready for use.(3)用S

44、etCommState()函數(shù)手動設(shè)置DCB初值。用法如下: DCB dcb;FillMemory(dcb, sizeof(dcb), 0);if (!GetCommState(hComm, dcb) / get current DCB/ Error in GetCommStatereturn FALSE;/ Update DCB rate.dcb.BaudRate = CBR_9600 ;/ Set new state.if (!SetCommState(hComm, dcb)/ Error in SetCommState. Possibly a problem with the commu

45、nications / port handle or a problem with the DCB structure itself.手動設(shè)置DCB值時,DCB的結(jié)構(gòu)的各成員的含義,可以參看MSDN幫助。 2.流控設(shè)置 硬件流控:串口通信中的硬件流控有兩種,DTE/DSR方式和RTS/CTS方式,這與DCB結(jié)構(gòu)的初始化有關(guān)系,DCB結(jié)構(gòu)中的OutxCtsFlow、 fOutxDsrFlow、fDsrSensitivity、fRtsControl、fDtrControl幾個成員的初始值很關(guān)鍵,不同的值代表不同流控,也可以自己設(shè)置流控,但建議采用標(biāo)準(zhǔn)流行的流控方式。采用硬件流控時,DTE、DSR、

46、RTS、CTS的邏輯位直接影響到數(shù)據(jù)的讀寫及收發(fā)數(shù)據(jù)的緩沖區(qū)控制。 軟件流控:串口通信中采用特殊字符XON和XOFF作為控制串口數(shù)據(jù)的收發(fā)。與此相關(guān)的DCB成員是:fOut、fInX、XoffChar、XonChar、 XoffLim和XonLim。具體含義參見MSDN幫助。 串口讀寫操作:串口讀寫有兩種方式:同步方式(NonOverlapped)和異步方式(Overlapped)。同步方式是指必須完成了讀寫操作,函數(shù)才返回,這可能造成程序死掉,因為如果在讀寫時發(fā)生了錯誤,永遠(yuǎn)不返回就會出錯,可能線程將永遠(yuǎn)等待在那兒。而異步方式則靈活得多,一旦讀寫不成功,就將讀寫掛起,函數(shù)直接返回,可以通過G

47、etLastError函數(shù)得知讀寫未成功的原因,所以常常采用異步方式操作。 讀操作:ReadFile()函數(shù)用于完成讀操作。異步方式的讀操作為: DWORD dwRead;BOOL fWaitingOnRead = FALSE;OVERLAPPED osReader = 0;/ Create the overlapped event. Must be closed before exiting/ to avoid a handle leak.osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);if (osReader.hEvent =

48、NULL)/ Error creating overlapped event; abort.if (!fWaitingOnRead) / Issue read operation.if (!ReadFile(hComm, lpBuf, READ_BUF_SIZE, dwRead, osReader) if (GetLastError() != ERROR_IO_PENDING)/ read not delayed?/ Error in communications; report it.elsefWaitingOnRead = TRUE;else / read completed immedi

49、atelyHandleASuccessfulRead(lpBuf, dwRead); 如果讀操作被掛起,可以調(diào)用WaitForSingleObject()函數(shù)或WaitForMuntilpleObjects()函數(shù)等待讀操作完成或者超時發(fā)生,再調(diào)用 GetOverlappedResult()得到想要的信息。 寫操作:與讀操作相似,故不詳述,調(diào)用的API函數(shù)是: WriteFile函數(shù)。 串口狀態(tài): (1)通信事件:用SetCommMask()函數(shù)設(shè)置想要得到的通信事件的掩碼,再調(diào)用WaitCommEvent()函數(shù)檢測通信事件的發(fā)生??稍O(shè)置的通信事件標(biāo)志(即SetCommMask()函數(shù)所設(shè)置

50、的掩碼)可以有EV_BREAK、EV_CTS、EV_DSR、 EV_ERR、EV_RING、EV_RLSD、EV_RXCHAR、EV_RXFLAG、EV_TXEMPTY。 注意:1對于EV_RING標(biāo)志的設(shè)置,WIN95是不會返回EV_RING事件的,因為WIN95不檢測該事件。2設(shè)置EV_RXCHAR,可以檢測到字符到達(dá),但是在綁定此事件和ReadFile()函數(shù)一起讀取串口接收數(shù)據(jù)時,可能會出現(xiàn)錯誤,造成少讀字節(jié)數(shù),具體原因查看MSDN幫助??梢圆捎醚h(huán)讀的辦法,另外一個比較好的解決辦法是調(diào)用ClearCommError()函數(shù),確定在一次讀操作中在緩沖區(qū)中等待被讀的字節(jié)數(shù)。 (2)錯誤處

51、理和通信狀態(tài):在串口通信中,可能會產(chǎn)生很多的錯誤,使用ClearCommError()函數(shù)可以檢測錯誤并且清除錯誤條件。 (3)Modem狀態(tài):用SetcommMask()可以包含很多事件標(biāo)志,但是這些事件標(biāo)志只指示在串口線路上的電壓變化情況。而調(diào)用 GetCommModemStatus()函數(shù)可以獲得線路上真正的電壓狀態(tài)。 擴(kuò)展函數(shù):如果應(yīng)用程序想用自己的流控,可以使用 EscapeCommFunction()函數(shù)設(shè)置DTR和RTS線路的電平。 通信超時:在通信中,超時是個很重要的考慮因素,因為如果在數(shù)據(jù)接收過程中由于某種原因突然中斷或停止,如果不采取超時控制機(jī)制,將會使得I/O線程被掛起或

52、無限阻塞。串口通信中的超時設(shè)置分為兩步,首先設(shè)置 COMMTIMEOUTS結(jié)構(gòu)的五個變量,然后調(diào)用SetcommTimeouts()設(shè)置超時值。對于使用異步方式讀寫的操作,如果操作掛起后,異步成功完成了讀寫,WaitForSingleObject()或 WaitForMultipleObjects()函數(shù)將返回WAIT_OBJECT_0,GetOverlappedResult()返回TRUE。其實還可以用GetCommTimeouts()得到系統(tǒng)初始值。 關(guān)閉串口:程序結(jié)束或需要釋放串口資源時,應(yīng)該正確關(guān)閉串口,關(guān)閉串口比較簡單,使用API調(diào)用CloseHandle()關(guān)閉串口的句柄就可以了。 調(diào)用方法為:CloseHandle(hComm); 但是值得注意的是在關(guān)閉串口之前必須保證讀寫串口線程已經(jīng)退出,否則會引起誤操作,一般采用的辦法是使用事件驅(qū)動機(jī)制,啟動一事件,通知串口讀寫線程強(qiáng)制退出,在線程退出之前,通知主線程可以關(guān)閉串口。 二、實現(xiàn)1.程序設(shè)計思路 對于不同的應(yīng)用程序,雖然界面不同,但是如果采用串口與主機(jī)之間的通信,對串口的處理方式大致相似,無非就是通過串口收發(fā)數(shù)據(jù),對于通過串口接收到的數(shù)據(jù),交給上層軟件處理顯示,對于上層要發(fā)給串口的數(shù)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論