在线观看av毛片亚洲_伊人久久大香线蕉成人综合网_一级片黄色视频播放_日韩免费86av网址_亚洲av理论在线电影网_一区二区国产免费高清在线观看视频_亚洲国产精品久久99人人更爽_精品少妇人妻久久免费

首頁 > 文章中心 > 正文

小議Windows通信編程思考

前言:本站為你精心整理了小議Windows通信編程思考范文,希望能為你的創(chuàng)作提供參考價值,我們的客服老師可以幫助你提供個性化的參考范文,歡迎咨詢。

小議Windows通信編程思考

一、windows通信機制

Windows與DOS編程的重要差別在于Windows程序是消息驅(qū)動和設(shè)備統(tǒng)一管理。體現(xiàn)在通信方面,DOS中的寄存器直接讀寫、BIOS調(diào)用和通信中斷程序等編程方法都不能或不宜采用。Windows通過通信驅(qū)動程序COMM.DRV與硬件接口,向程序員提供了多達(dá)17個標(biāo)準(zhǔn)函數(shù),功能強大,但也增加了理解和編程的難度。

Windows3.1通信函數(shù)主要有:

OpenComm

打開一通信設(shè)備

BuildCimmDCB將一設(shè)備定義字符串轉(zhuǎn)變?yōu)镈CB數(shù)據(jù)結(jié)構(gòu)

EnableCommNotification使能或禁止傳送WM_COMMNOTIFY消

SetCommState設(shè)置通信設(shè)備狀態(tài)

SetCommEventMask設(shè)置通信事件掩碼

ReadComm從通信設(shè)備讀字符

WriteComm向通信設(shè)備寫字符

FlushComm清除一發(fā)送或接收隊列

GetCommEventMask返回通信事件掩碼

GetCommState返回設(shè)備控制塊(DCB)

GetCommError恢復(fù)通信設(shè)備狀態(tài)

CloseComm關(guān)閉一通信設(shè)備

DCB數(shù)據(jù)結(jié)構(gòu)、其它通信函數(shù)及各函數(shù)的具體用法請參見有關(guān)資料。

一般Windows通信編程應(yīng)包括兩部分:設(shè)備初始化及WM_COMMNOTIF

Y消息處理。

設(shè)備初始化典型流程如圖1。

圖1

WM_COMMNOTIFY消息處理典型流程如圖2。

圖2

對于大多數(shù)實際通信來說,可能只需要處理流程圖中的一部分。

設(shè)備初始化及WM_COMMNOTIFY消息處理兩部分密切相關(guān)。所有類型WM_COMMNOTIFY消息的傳送都是因為在初始化函數(shù)中進行了相應(yīng)的設(shè)置。

換言之,可以根據(jù)通信的實際情況有選擇地設(shè)置,控制Windows向應(yīng)用程序發(fā)送的WM_COMMNOTIFY消息的數(shù)量和類型,以期達(dá)到高效、可靠的通信。例如,對于固定長度消息型的通信可以在EnableCommNotification函數(shù)中設(shè)置cbWriteNotify和cbOutQueue參數(shù)為消息長度;對于以固定字符結(jié)尾的消息型通信可以在事件掩碼中包括EV_RXFLAG,將DCB數(shù)據(jù)結(jié)構(gòu)中的EvtChar變量置為結(jié)尾字符,然后調(diào)用SetCommState和SetCommEventMask函數(shù);對于遵循V.25bis之類協(xié)議的通信,由于用到了大量信號線來作握手信號,則事件掩碼中要包含EV_CTS、EV_DSR、EV_RSLD及EV_RING等;而對于文件傳送型的通信,則宜將OpenComm函數(shù)中的cbInQue和cbOutQue變量、EnablecCommNotification中的cbWriteNotify和cbOutQueue變量設(shè)置為較大值,以加快文件傳送速度。

二、Windows通信疑難探討

現(xiàn)將筆者在實際編程中遇到的疑難和解決辦法描述如下,希望對遇到類似問題的朋友有所啟發(fā)。

1.怎樣用Windows未提供的波特率通信?

Windows提供了由110bps至256000bps共十三種波特率,一般情況下已足夠使用。但在某種特定情況下,例如通信對方使用150bps、又無法要求對方改變波特率時,Windows通信就比較困難了。

首先想到的解決方法是直接調(diào)用BIOS中斷14H來設(shè)置波特率(DOS提供了150bps的波特率)。結(jié)果是Windows屏蔽了該中斷,嘗試失敗。

最后的是采用"蒙混過關(guān)"的辦法解決問題的:首先,以任一Windows支持的波特率(例如300bps)構(gòu)造通信參數(shù)字符串,調(diào)用BuildCommDCB產(chǎn)生DCB數(shù)據(jù)結(jié)構(gòu);然后調(diào)用SetCommState設(shè)置通信參數(shù);最后再調(diào)用自編函數(shù)直接修改串口通信寄存器的值。經(jīng)實驗,設(shè)置成功,且對Windows程序運行無任何不良影響。

2.接收數(shù)據(jù)為何"丟失"?

通過設(shè)置EnableCommNotification函數(shù)中的cbWriteNotify參數(shù)(在發(fā)送WM_COMMNOTIFY消息之前,通信設(shè)備驅(qū)動程序必須向應(yīng)用程序出入隊列中寫入的字節(jié)數(shù)),可以使系統(tǒng)每收到固定個字符發(fā)出一WM_COMMNOTIFY消息,這對于固定長度消息型的通信是很方便的。但實際應(yīng)用時有時會發(fā)生接收數(shù)據(jù)"丟失"現(xiàn)象,即收到WM_COMMNOTIFY消息后從接收隊列讀出cbNotify個數(shù)據(jù)時,發(fā)現(xiàn)只有前面部分?jǐn)?shù)據(jù)正確。

經(jīng)檢查,"丟失"現(xiàn)象是由于接收數(shù)據(jù)超時引起的,當(dāng)通信對方時鐘頻率較低時,規(guī)定時間內(nèi)收不到cbWriteNotify指定的數(shù)據(jù)量,即所謂"超時",Windows照樣向應(yīng)用程序發(fā)送帶CN_RECEIVE標(biāo)志的WM_COMMNOTI

FY消息。然后,在應(yīng)用程序輸入隊列數(shù)據(jù)讀出之前,Windows不再發(fā)送該類消息。

解決的方法是減小cbWriteNotify的設(shè)定值直到不再發(fā)生"超時"現(xiàn)象。

發(fā)送數(shù)據(jù)時同樣應(yīng)正確設(shè)定cbOutQue值,以免產(chǎn)生"超時"現(xiàn)象。

如果將cbWriteNotify或cbOutQue設(shè)為-1,則Windows不傳送帶CN_RECEIVE或CN_TRANSMIT標(biāo)志的WM_COMMNOTIFY消息。

3.怎樣合理使用FlushComm與GetCommError函數(shù)?

FlushComm函數(shù)的功能是清除指定設(shè)備接收或發(fā)送隊列。GetCommError函數(shù)的功能是返回指定設(shè)備最近錯誤碼和當(dāng)前狀態(tài),更重要的是"解鎖"功能:當(dāng)出現(xiàn)通信錯誤時,Windows會鎖死通信端口直到調(diào)用GetCommError。

調(diào)用FlushComm的時機很重要,如果通信端口發(fā)生錯誤,不調(diào)用該函數(shù)就有可能會使接收隊列包含不期望的數(shù)據(jù);若隨便調(diào)用該函數(shù),也有可能造成尚未讀入或發(fā)出的數(shù)據(jù)丟失??傊?調(diào)用該函數(shù)要做到"心中有數(shù)"。

為了合理調(diào)用FlushComm和GetCommError函數(shù),建議在事件掩碼中包含EV_ERR與EV_BREAK。

4.Windows多串口通信

Windows最多可支持四個串口的通信,但對于ISA總線的PC,由于其COM1與COM3、COM2與COM4分別共用IRQ3和IRQ4,所以只能同時使用兩個串口。MCA、EISA總線系統(tǒng)沒有此限制。

如果需要使用的端口不止四個,可以在PC護展槽中加插多用戶卡,如美國的Comtrol、臺灣的Moxa(摩莎)等,就可以支持幾個到幾十個串口,加上隨卡提供的Windows驅(qū)動程序,就可以進行多串口通信。具體用法請參閱擴展卡說明書。

三、Windows通信實例

實例的通信環(huán)境為:本方COMPAQ4/50微機,安裝中文Windows3.2;對方為8031單片機。通信參數(shù)設(shè)置:波特率150bps,數(shù)據(jù)位8,停止位1,無校驗。通信協(xié)議是:對方發(fā)FF,本方收到后回0F,對方收到0F后發(fā)一條十字節(jié)的消息,本方回0F,結(jié)束一次通信。

編程環(huán)境為中文Windows3

2、BorlandC++3.1OWL。

#include<windows.h>

#include<owl.h>

#include<window.h>

#include<string.h>

intCOM=1;//串口號

unsignedcharReceiveBuff〔11〕;//接收數(shù)據(jù)緩存

_CLASSDEF(TCommApp)

classTCommApp:publicTapplication

{

public:

TCommApp(LPSTRAName,HINSTANCEhInstance,HINSTANCE

HPrevInstance,LPSTR1p

CmdLine,intnCmdshow)

:TApplication(AName,hInstance,hPrevInstance,1pCmd

Line,nCmdShow){};

virtualvoidInitMainWindow();

};

_CLASSDEF(TCommWin)//主窗口類

classTCommWin:publicTWindow

{

public:

TCommWin(PTWindowsObjectAParent,LPSTRATitle):

TWindow(AParent,Atitle){}

intInitCom();

voidSetBaud();//設(shè)置Windows不支持的波特率

virtualBOOLWMCommNotify(TMessage&Mg)=〔WM_FIRST+

WM_COMMNOTIFY〕;

virtualvoidSetupWindow();

};

//該函數(shù)設(shè)置串口2的波特率為150bps,若用Windows提//供的波特率通信,則無須該函數(shù)

VoidTCommWin::SetBaud()

{

asmcli;

asmmovdx,2fbh;

asmmoval,80h;

asmoutdx,al;

asmmovdx,2f8h;

asmmoval,00h;

asmoutdx,al;

asmmovdx,2f9h;

asmmoval,3;

asmoutdx,al;

asmmovdx,2fbh;

asmmoval,03;

asmoutdx,al;

asmmovdx,2fch;

asmmoval,0bh;

asmoutdx,al;

asmmovdx,2f9h;

asmmoval,0fh;

asmoutdx,al;

asmmoval,20h;

asmout21h,al;

asmsti;

}

intTCommWin::InitCom()

{

charstr〔20〕,s〔2〕;

intCOMid,err;

DCBdcb;//設(shè)備控制塊

UINTMask=EV_BREAK|EV_ERR|EV_RXFLAG;//事件掩碼

strcpy(str,"COM");

strcat(str,itoa(COM+1,s,10));

COMid=OpenComm(str,128,1);

if(COMid<0)returnCOMid;

strcat(str,":300,n,8,1");

err=BuildCommDCB(str,&dcb);

dcb.EvtChar=-1;//事件字符0xff

err=SetCommState(&dcb);

SetBaud();

if(err>0)returnerr;

FlushComm(COMid,1);

if(!EnableComunNotification(COMid,HWindow,10,-1))

return-1;

SetCommEventMask(COMid,Mask);

returnCOMid;

}

voidTCommWin::SetupWindow()

{

TWindow::SetupWindow();

InitCom();

}

BOOLTCommWin::WMCommNotify(TMessage&Mg)

{

UINTflag=0;

intid;

COMSTATstat;

unsignedcharSendChar;

staticunsignedchar

*p=ReceiveBuff;

staticnum=0;

intret;

id=Mg.WParam;

switch(Mg.LP.Lo)

{

caseCN_EVENT://有事件掩碼中定義的事件發(fā)生

flag=GetCommEventMask(id,EV_BREAK);

if(flag&EV_BREAK)

FlushComm(id,1);

flag=GetCommEventMask(id,EV_RXFLAG);

if(flag&EV_ERR)

FlushComm(id,1);

flag=GetCommEventMask(id,EV_RXFLAG);

if(flag&EV_RXFLAG)//收到了事件字符0xff

{

SendChar=0x0f;

WriteComm(id,&SendChar,1);//向?qū)Ψ交?x0f

}

break;

caseCN_RECEIVE://接收到了規(guī)定個字符或超時

do

{

ret=ReadComm(id,p,1);

if(ret>0)

{

p++;

num++;

}

}while((ret>0)&(num<10));

if(num>=10)//接收完一條消息

{

num=0;

//此處處理接收到的消息

p=ReceiveBuff;

SendChar=0x0f;

WriteComm(id,&SendChar,1);//向?qū)Ψ交?x0f

FlushComm(id,1);

}break;

}

flag=GetCommError(id,&stat);//消除錯誤(若有)

return1;

}

voidTCommApp::InitMainWindow()

{

MainWindow=newTCommWin(NULL,"Windows通信示例");

}

intPASCALWinMain(HINSTANCEhInstance,HINSTANCEhPrevI

nstance,LPSTR1pCmdLine,

intnCmdShow)

{

TCommAppCommApp("通信",hInstance,hPrevInstance,1pC

mdLine,nCmdShow);

CommApp.Run();

returnCommApp.Status;}

天柱县| 勐海县| 调兵山市| 海丰县| 论坛| 蛟河市| 沛县| 望谟县| 许昌县| 武宣县| 宾川县| 阿合奇县| 遂宁市| 织金县| 阳山县| 竹溪县| 吉首市| 双峰县| 长丰县| 四川省| 六枝特区| 桃江县| 灵武市| 赤城县| 三台县| 河北省| 石阡县| 浦东新区| 玉山县| 蓝田县| 余庆县| 广河县| 杭锦后旗| 开化县| 乐业县| 鹤庆县| 万荣县| 邹城市| 中宁县| 南丰县| 福安市|