亚洲欧美第一页_禁久久精品乱码_粉嫩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一区二区三区免费野_久草精品视频
欧美三级韩国三级日本一级| 亚洲日本中文字幕区| 亚洲三级视频在线观看| 日韩精品视频网| 波波电影院一区二区三区| 欧美久久一二三四区| 国产精品天天摸av网| 日韩av在线播放中文字幕| av一区二区不卡| 精品国产sm最大网站| 亚洲chinese男男1069| 成人h版在线观看| 久久蜜臀精品av| 日韩高清欧美激情| 欧美性色黄大片| 亚洲同性同志一二三专区| 国产资源精品在线观看| 91麻豆精品国产91久久久久久| 亚洲欧美另类综合偷拍| 大陆成人av片| 国产蜜臀97一区二区三区| 国内精品写真在线观看| 欧美成人精精品一区二区频| 日日摸夜夜添夜夜添国产精品| 欧美色综合天天久久综合精品| 亚洲欧美日韩综合aⅴ视频| 国产福利一区在线| 精品国产露脸精彩对白 | 九九九精品视频| 欧美日韩一区 二区 三区 久久精品| 国产精品天干天干在线综合| 国产91精品精华液一区二区三区 | 欧美日韩大陆一区二区| 亚洲国产日韩av| 欧美日韩一区二区三区在线| 亚洲一区av在线| 7777精品伊人久久久大香线蕉超级流畅 | 天堂va蜜桃一区二区三区| 91久久精品网| 午夜影院久久久| 日韩欧美一区在线| 黄色小说综合网站| 国产欧美精品在线观看| 丁香一区二区三区| 成人免费一区二区三区在线观看| 99久久国产综合精品女不卡| 成人欧美一区二区三区小说| 色综合中文字幕国产| 亚洲欧美成aⅴ人在线观看| 91色|porny| 丝袜诱惑制服诱惑色一区在线观看 | 国产精品美女久久久久高潮| caoporen国产精品视频| 亚洲男人的天堂在线观看| 欧美日韩国产一级片| 麻豆成人免费电影| 欧美国产精品一区| 欧美日韩一级二级| 韩国女主播成人在线| 国产精品夫妻自拍| 91精品一区二区三区久久久久久| 黄网站免费久久| 一区二区高清在线| 日韩精品一区二区三区视频| 成人综合婷婷国产精品久久蜜臀| 一区二区三区日本| 日韩欧美视频一区| 91丨porny丨国产| 久久综合综合久久综合| 国产精品久久久久久久岛一牛影视| 欧美在线短视频| 狠狠色综合播放一区二区| 亚洲欧美一区二区不卡| 精品国产青草久久久久福利| 99久久精品国产一区| 久久99国产精品久久| 亚洲理论在线观看| 国产午夜精品在线观看| 在线成人免费视频| 波多野结衣在线aⅴ中文字幕不卡| 天天色图综合网| ●精品国产综合乱码久久久久| 欧美成人乱码一区二区三区| 色综合久久88色综合天天| 国产精品99久久久久久宅男| 亚洲成人中文在线| 自拍偷在线精品自拍偷无码专区| 精品国产麻豆免费人成网站| 欧美调教femdomvk| 色综合视频在线观看| 国产91露脸合集magnet| 男女男精品视频| 午夜国产不卡在线观看视频| 国产精品女同一区二区三区| 日韩免费看的电影| 欧美精品丝袜中出| 欧美视频精品在线观看| 91免费版在线| 99精品欧美一区二区三区综合在线| 国产主播一区二区| 麻豆国产精品官网| 蜜臀精品一区二区三区在线观看 | 国产精品久久久久aaaa樱花 | 国产剧情在线观看一区二区| 日韩avvvv在线播放| 亚洲国产综合在线| 亚洲一区自拍偷拍| 一区二区三区精品| 亚洲一区免费视频| 一区二区三区四区在线播放| 国产精品三级久久久久三级| 欧美激情一区二区三区全黄| 精品99一区二区三区| 欧美r级电影在线观看| 日韩一级欧美一级| 日韩视频一区在线观看| 7777精品伊人久久久大香线蕉经典版下载 | 欧美精品一区二区高清在线观看| 欧美日韩成人在线一区| 欧美久久免费观看| 日韩欧美一级精品久久| 日韩精品在线一区| 欧美精品一区二区三区四区| 精品国产人成亚洲区| 久久精品人人做人人综合| 久久精品在线免费观看| 国产欧美日韩亚州综合| 国产精品乱码久久久久久| 最新高清无码专区| 亚洲一区二区在线观看视频| 亚洲一区二区欧美激情| 日韩成人午夜电影| 狠狠狠色丁香婷婷综合久久五月| 国内精品国产成人| av亚洲精华国产精华精| 日本福利一区二区| 日韩西西人体444www| 久久亚洲一区二区三区明星换脸| 国产日本欧洲亚洲| 一区二区三区久久久| 午夜影院久久久| 国产精品自在在线| 在线精品视频小说1| 日韩一级大片在线观看| 国产精品污www在线观看| 亚洲永久精品国产| 韩国女主播一区二区三区| 99热这里都是精品| 日韩欧美高清dvd碟片| 国产精品剧情在线亚洲| 婷婷亚洲久悠悠色悠在线播放| 蜜臀久久99精品久久久画质超高清| 成人网页在线观看| 欧美喷潮久久久xxxxx| 国产欧美精品一区二区色综合| 亚洲国产中文字幕| 成人免费福利片| 91精品国产色综合久久ai换脸 | 日韩视频在线永久播放| 亚洲视频中文字幕| 国产一区二区不卡在线| 欧美日韩黄色影视| 国产精品欧美极品| 久久99精品久久久| 欧美午夜不卡视频| 中文字幕一区视频| 国产米奇在线777精品观看| 欧美日韩成人一区| 1区2区3区精品视频| 国产精品综合网| 日韩一区二区视频| 五月婷婷综合网| 91亚洲大成网污www| 亚洲精品一线二线三线| 午夜激情综合网| 欧美亚洲尤物久久| 亚洲情趣在线观看| 成人一级视频在线观看| 精品国产免费一区二区三区香蕉| 亚洲成人一二三| 日本乱码高清不卡字幕| 国产精品久久午夜| 国产一区二区电影| 精品99999| 久久国产精品72免费观看| 欧美卡1卡2卡| 视频一区二区欧美| 欧美精品一级二级| 亚洲午夜久久久久久久久电影网| 99久久久无码国产精品| 久久久久久亚洲综合影院红桃| 美美哒免费高清在线观看视频一区二区| 欧美亚洲综合网| 亚欧色一区w666天堂| 欧美午夜寂寞影院| 日韩专区在线视频| 91精品国产综合久久久久| 天天亚洲美女在线视频| 欧美一区二区在线观看| 日本va欧美va欧美va精品|