亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? 實戰串行通訊.txt

?? 串行通訊 本文不是全面的講述如何編寫串行通訊程序
?? TXT
?? 第 1 頁 / 共 3 頁
字號:
實戰串行通訊
by 羅云彬,2001.1


--------------------------------------------------------------------------------
    
很長時間沒有寫編程文章了,最近為了編一個串行通訊的終端程序忙了近一個月,發現了在 Win32 的通訊 API 中有不少的問題,還有許多在其他串行通訊文章中沒有談到的問題,在這里準備集中談一下,大家請下載我這一個月的“成果”:迷你終端測試一下,看看還有沒有什么問題。有關串行通訊方面的基礎文章,可以參考《Serial communications in Microsoft Win32》和《串行通訊編程點滴》。本文不是全面的講述如何編寫串行通訊程序,而是討論一些實際遇到的問題。

1 選擇通訊方式 -- 同步還是非同步

正如在《Serial communications in Microsoft Win32》等文章中提到的,同步(NonOverLapped)方式是比較簡單的一種方式,編寫起來代碼的長度要明顯少于異步(OverLapped)方式,我開始用同步方式編寫了整個子程序,在 Windows98 下工作正常,但后來在 Windows2000下測試,發現接收正常,但一發送數據,程序就會停在那里,原因應該在于同步方式下如果有一個通訊 Api 在操作中,另一個會阻塞直到上一個操作完成,所以當讀數據的線程停留在 WaitCommEvent 的時候,WriteFile 就停在那里。我又測試了我手上所有有關串行通訊的例子程序,發現所有使用同步方式的程序在 Windows 2000 下全部工作不正常,對這個問題我一直找不到解決的辦法,后來在 Iczelion 站點上發現一篇文章提到 NT 下對串行通訊的處理和 9x 有些不同,根本不要指望在 NT 或 Windows 2000 下用同步方式同時收發數據,我只好又用異步方式把整個通訊子程序重新寫了一遍。

所以對于這個問題的建議是:如果程序只打算工作在 Win9x 下,為了簡單起見,可以用同步方式寫程序,如果程序打算在 NT 下也可以工作的話,就必須用異步方式寫。

2 Win32 通訊 API Bug 之一 --- CommConfigDialog

CommConfigDialog 是彈出系統內置串口設置對話框的 API,我們在設備管理器中設置串口參數的對話框就是這個,使用這個 API 時不用先打開端口,它并不針對一個已打開的端口,而是僅僅是把 DCB 的內容填寫到對話框中,當按了 OK 后把輸入的結果存回到 DCB 數據結構中,至于什么時候把結果設置到串口上,那就是你自己要做的事情了。

CommCinfigDialog 的定義如下:

BOOL CommConfigDialog(

LPTSTR lpszName, // pointer to device name string
HWND hWnd, // handle to window
LPCOMMCONFIG lpCC // pointer to comm. configuration structure
);

但在使用中發現,對話框有時能出來,有時出不來,最后總結的經驗是問題出在 COMMCONFIG 結構的 dwSize 字段上,COMMCONFIG 的定義如下:

typedef struct _COMM_CONFIG {
DWORD dwSize;
WORD wVersion; 
WORD wReserved;
DCB dcb;
DWORD dwProviderSubType;
DWORD dwProviderOffset;
DWORD dwProviderSize;
WCHAR wcProviderData[1];
} COMMCONFIG, *LPCOMMCONFIG;

在參數中,wVersion 要填 100h,dwProviderSubType 要填 1,但 dwSize 就不能填 sizeof COMMCONFIG 了,我發現好象一定要把 dwSize 設置為比 sizeof COMMCONFIG 對話框才能出來,所以我用的代碼中定義了一個足夠大的緩沖區作為結構的地址:

_CommConfigDialog proc
local @stCC[256]:BYTE

pushad
invoke RtlZeroMemory,addr @stCC,sizeof @stCC
mov (COMMCONFIG ptr @stCC).dwSize,256
mov (COMMCONFIG ptr @stCC).wVersion,100h
mov (COMMCONFIG ptr @stCC).dwProviderSubType,1
invoke CommConfigDialog,addr [esi].szPortName,[esi].hWnd,addr @stCC
popad
ret

_CommConfigDialog endp

3 Win32 通訊 API Bug 之二--- BuildCommDCB

BuildCommDCB 的功能是把一個字符串如 com1:9600,n,8,1 這樣的轉換到具體的數據填寫到 DCB 中,但使用中也存在問題,我發現我用它轉換象 com1:9600,e,7,1 之類的帶校驗位的字符串,它總是無法把這個 e 給我轉換過去,設置好串口一看,成了 9600,n,7,1,而上面提到的 CommConfigDialog 返回的結果用來設置串口卻是正確的,經過比較,發現問題出在 DCB.fbits.fParity 這個 bit 上,只有把這個 bit 置 1,校驗位才是有效的,而 BuildCommDCB 恰恰是漏了這個 bit,所有如果你要使用 BuildCommDCB,別忘了補充把 DCB.fbits.fParity 設置回去,我用的代碼是:

_BuildCommDCB proc _lpszPara,_lpstDCB

pushad
mov esi,_lpstDCB
assume esi:ptr DCB

invoke RtlZeroMemory,esi,sizeof DCB
invoke BuildCommDCB,_lpszPara,esi
;********************************************************************
; 根據校驗位補充設置 DCB 中的 DCB.fbits.fParity 字段
;********************************************************************
mov dword ptr [esi].fbits,0010b

cld
@@:
lodsb
or al,al
jz @F
cmp al,'='
jz _BCD_Check
cmp al,','
jnz @B
_BCD_Check:
lodsb
or al,al
jz @F
or al,20h
cmp al,'n'
jnz @B
;********************************************************************
; 掃描到 =n 或 ,n 則取消校驗位
;********************************************************************
mov esi,_lpstDCB
and dword ptr [esi].fbits,not 0010b
@@:
popad
ret

_BuildCommDCB endp

4 Win32 通訊編程的一般流程

由于同步方式相對比較簡單,在這里講述的是異步方式的流程,在其他的很多文章里提到了 Windows 通訊 API 有二十多個,它們是:

BuildCommDCB
BuildCommDCBAndTimeouts
ClearCommBreak
ClearCommError
CommConfigDialog
EscapeCommFunction
GetCommConfig
GetCommMask
GetCommModemStatus
GetCommProperties
GetCommState
GetCommTimeouts
GetDefaultCommConfig
PurgeComm
SetCommBreak
SetCommConfig
SetCommMask
SetCommState
SetCommTimeouts
SetDefaultCommConfig
SetupComm
TransmitCommChar
WaitCommEvent 

我剛看到這些 API 的時候,都不知道如何使用它們,但并不是所有這些 API 都是必須用的,比如說你要檢測當前串口的設置可以只用 SetCommState 而不用 GetCommProperties 和 GetCommConfig,雖然它們返回的信息可能更多。同樣,如果有些值你想用缺省的,比如緩沖區的大小和超時的時間等等,那么 SetupComm 和 BuildCommDCBAndTimeouts、SetCommTimeouts 也可以不用,TransmitCommChar 是馬上在發送序列中優先插入發送一個字符用的,平時也很少用到,下面講的是必須用到的 API 和使用步驟:

建立 Event -- 用 CreateEvent

invoke CreateEvent,NULL,TRUE,FALSE,NULL
用異步方式操作串口必須要定義 OVERLAPPED 結構,其中的 hEvent 必須自己建立,你要定義兩個 OVERLAPPED 結構,一個用于讀一個用于寫,當然也必須建立兩個 Event,把它們放入 OVERLAPPED.hEvent


打開串口 -- 用 CreateFile

invoke CreateFile,addr szPortName,GENERIC_READ or GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL
注意用異步方式必須指定 FILE_FLAG_OVERLAPPED,而文件方式必須 OPEN_EXISTING,讀寫必須是 GENERIC_READ or GENERIC_WRITE


設置串口參數 -- 用 SetCommState

invoke SetCommState,hCom,addr dcbx
hCom 是前面打開成功后返回的句柄,dcbx 是數據結構 DCB,里面包括了通訊的具體參數,至于這個參數的建立,你可以自己填寫,也可以用前面提到的 BuildCommDCB 或 CommConfigDialog 填寫


建立讀數據的線程

到這里,就可以開始讀數據了,一般我們是在主線程中寫數據,因為寫是我們可以控制的,而讀的時候我們不知道數據什么時候會到,所以要建立一個線程專門用來讀數據,在這個線程中,我們循環地用 ReadFile 讀串口,同時用 WaitCommEvent 檢測線路狀態。


如果要檢測通訊狀態,如 CTS 信號,RingIn 等等 -- 用 SetCommMask、WaitCommEvent、ClearCommError、GetCommModemStatus

invoke SetCommMask,hCom,EV_BREAK or EV_CTS or EV_DSR or EV_ERR or EV_RING or EV_RLSD or EV_RXCHAR or EV_RXFLAG or EV_TXEMPTY
SetCommMask 指定 WaitCommEvent 要等待的事件名稱,具體的參數請查手冊

invoke WaitCommEvent,hCom,addr dwEvent,NULL
WaitCommEvent 等待一直到 SetCommMask 指定事件之一發生

invoke ClearCommError,hCom,addr dwError,addr stComStat
在 WaitCommEvent 以后,要用 ClearCommError 清除事件的 Flag,以便進行下一輪 WaitCommEvent,同時這個 API 可以獲得更詳細的事件信息

invoke GetCommModemStatus,hCom,addr dwModemStatus
同樣,GetCommModemStatus 是用來獲得串口線路狀態的,如 CTS、RING 等等,當 WaitCommEvent 返回時,只是指出了如 CTS 等等狀態有變化,但具體是變成 On 還是 Off 了還要靠這個 API 去取得更詳細的信息


讀數據 -- 用 ReadFile

invoke ReadFile,hCom,addr szBuffer,sizeof szBuffer,addr dwBytesRead,addr stReadState
最后一個參數是開頭定義的 OVERLAPPED 結構的地址,指定了它就表示是用異步方式的讀方式,這個 API 會馬上返回,接下去要用

invoke GetOverlappedResult,hCom,addr stReadState,addr dwBytesRead,FALSE
將其余的數據讀完


結束時關閉端口 -- 停止 WaitCommEvent 的等待以及關閉端口 CloseHandle

平時程序會停留在 WaitCommEvent 的等待中,當要終止線程的時候,必須是程序從 WaitCommEvent 中退出來,這時候要用

按照 Win32 手冊上的說明,參數為 NULL 的 SetCommMask 會使另一個線程中的 WaitCommEvent 馬上返回,然后就是用 CloseHandle 關閉端口
invoke CloseHandle,hCom 
5 Win32 通訊 API Bug 之二--- SetCommMask 和 WaitCommEvent

嚴格的說這不應該是 Bug,而是偶然的情況,我發現有些時候我的讀線程無法結束,跟蹤發現是停在了 WaitCommEvent 上,這說明有時候 invoke SetCommMask,hCom,NULL 并不能使 WaitCommEvent 退出,我最后使用的辦法是: 在 SetCommMask 以后再執行 invoke SetEvent,stReadState.hEvent,把讀的 OVERLAPPED 結構中的 Event 置位,讓 WaitCommEvent 認為有 Event 發生,它就會馬上返回,也許這并不是普遍的情況,但如果你的程序也是停在了 WaitCommEvent 的地方,不妨一試。

6 如何編寫讀線程中的循環


按照《Serial communications in Microsoft Win32》一文中的例程,讀循環可以用:

#define READ_TIMEOUT 500 // milliseconds

DWORD dwRes;
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 == 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.
else
fWaitingOnRead = TRUE;
}
else { 
// read completed immediately
HandleASuccessfulRead(lpBuf, dwRead);
}
}


if (fWaitingOnRead) {
dwRes = WaitForSingleObject(osReader.hEvent, READ_TIMEOUT);

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
51精品久久久久久久蜜臀| 欧洲一区在线观看| 麻豆精品一区二区| 青青草国产成人99久久| 日韩成人av影视| 欧美aⅴ一区二区三区视频| 日韩av成人高清| 日产精品久久久久久久性色| 免费成人美女在线观看| 久久 天天综合| 狠狠狠色丁香婷婷综合久久五月| 麻豆91免费看| 国产激情偷乱视频一区二区三区| 精品一区二区三区在线播放| 韩国中文字幕2020精品| 国产成人综合自拍| 色偷偷88欧美精品久久久| 欧美影院精品一区| 日韩视频免费直播| 日本一区二区在线不卡| 一区二区三区精品久久久| 免费在线欧美视频| 国产福利视频一区二区三区| 成人午夜免费电影| 欧美亚洲国产一区二区三区| 日韩一区二区三区四区| 亚洲国产精品ⅴa在线观看| 中文字幕综合网| 男男gaygay亚洲| 成人性生交大片免费看在线播放| 欧美伊人久久久久久午夜久久久久| 欧美人xxxx| 国产亚洲欧美色| 亚洲国产综合91精品麻豆| 激情五月婷婷综合| 日本道免费精品一区二区三区| 欧美丰满美乳xxx高潮www| 国产午夜精品理论片a级大结局| 亚洲欧美一区二区不卡| 免费成人av资源网| 在线观看日韩高清av| 久久久久久久久久久久久久久99| 国产精品美女一区二区| 日本亚洲免费观看| 色综合久久综合网| 国产视频亚洲色图| 日本三级亚洲精品| 在线欧美日韩精品| 中文av字幕一区| 国产乱一区二区| 欧美精品国产精品| 亚洲狠狠丁香婷婷综合久久久| 国产一区二区三区电影在线观看| 欧美亚洲免费在线一区| 国产精品视频一二| 国产露脸91国语对白| 日韩三级视频在线观看| 亚洲成人福利片| 欧美三级蜜桃2在线观看| 1024成人网| 97se亚洲国产综合自在线不卡| 精品国产一区二区精华| 日韩中文字幕一区二区三区| 欧美影院午夜播放| 一区二区三区精品视频| 一本色道久久综合精品竹菊| 亚洲国产精品激情在线观看| 国产精品白丝jk黑袜喷水| 精品国产3级a| 国产精品综合av一区二区国产馆| 日韩精品专区在线| 激情图片小说一区| 精品国产乱码久久| 国精品**一区二区三区在线蜜桃| 欧美一卡2卡三卡4卡5免费| 天天操天天色综合| 这里只有精品电影| 精品中文字幕一区二区小辣椒 | 亚洲一区二区成人在线观看| 不卡在线视频中文字幕| 亚洲天堂免费在线观看视频| 波多野结衣在线一区| 中文字幕中文在线不卡住| 9i看片成人免费高清| 亚洲综合偷拍欧美一区色| 欧美午夜视频网站| 日韩av在线免费观看不卡| 日韩欧美国产麻豆| 国产成人丝袜美腿| 亚洲欧洲精品一区二区精品久久久| 95精品视频在线| 亚洲一区二区视频在线观看| 在线播放亚洲一区| 国产一区二区免费看| 国产精品久久二区二区| 欧美三级电影在线看| 久久国产精品99精品国产| 国产欧美视频一区二区| 成人福利视频在线看| 亚洲电影在线播放| 日韩欧美一区二区视频| 成人h版在线观看| 亚洲成人久久影院| 欧美精品一区视频| 色综合久久久久| 久久精品国产网站| 国产精品视频你懂的| 欧美福利电影网| 成人av在线一区二区三区| 日韩主播视频在线| 日本一区二区三区免费乱视频| 91久久精品国产91性色tv| 美女视频网站久久| 亚洲乱码国产乱码精品精可以看 | 国产午夜亚洲精品羞羞网站| 91色在线porny| 麻豆成人久久精品二区三区红 | 有坂深雪av一区二区精品| 69堂精品视频| 91麻豆免费观看| 久久99精品国产麻豆不卡| 亚洲激情自拍偷拍| 日本一区二区三区高清不卡| 欧美丰满少妇xxxxx高潮对白| 丁香一区二区三区| 精品一区二区日韩| 亚洲狠狠爱一区二区三区| 中文字幕在线观看不卡| 欧美成人一级视频| 在线不卡免费av| 欧美亚洲另类激情小说| 91一区二区在线| 韩国v欧美v亚洲v日本v| 蜜臀精品久久久久久蜜臀 | 国产精品一二三四区| 午夜激情一区二区| 一二三区精品视频| 亚洲欧洲国产日韩| 国产精品成人一区二区艾草 | 成人高清在线视频| 韩国三级中文字幕hd久久精品| 亚洲chinese男男1069| 亚洲男帅同性gay1069| 国产精品美女久久久久久久久久久| 日韩精品一区二区三区视频| 欧美日韩不卡在线| 欧美日韩激情一区| 欧美在线观看一区二区| 日本高清不卡aⅴ免费网站| 成年人国产精品| 99精品热视频| 91麻豆免费观看| 色婷婷狠狠综合| 色狠狠av一区二区三区| 色哟哟一区二区| 在线精品国精品国产尤物884a| 91亚洲大成网污www| 99久久国产综合精品女不卡 | 亚洲国产视频网站| 免费在线视频一区| 狠狠色丁香九九婷婷综合五月| 免费看欧美美女黄的网站| 天天影视色香欲综合网老头| 日韩在线a电影| 毛片av中文字幕一区二区| 久久 天天综合| 国产精品羞羞答答xxdd| 成人久久久精品乱码一区二区三区| 国产传媒日韩欧美成人| 91小视频在线| 欧美色偷偷大香| 精品久久久久久无| 国产精品欧美一区喷水| 亚洲精品第一国产综合野| 五月天亚洲婷婷| 国产在线精品一区二区三区不卡| 国产福利91精品一区二区三区| 成人高清视频在线观看| 欧美日韩高清不卡| 久久久蜜桃精品| 一区二区三区中文字幕| 日韩二区三区在线观看| 成人性生交大片免费看视频在线| 91麻豆文化传媒在线观看| 在线播放欧美女士性生活| 精品福利在线导航| 一区二区三区美女| 国产精品一二三在| 91精品福利在线| 久久免费的精品国产v∧| 亚洲乱码日产精品bd | 国产精品欧美一区喷水| 亚洲v精品v日韩v欧美v专区| 国产自产2019最新不卡| 91视频观看免费| 国产婷婷色一区二区三区四区| 亚洲一二三区不卡| 国产成人免费在线观看| 337p亚洲精品色噜噜噜| 亚洲欧美电影一区二区|