首頁 > 文章中心 > 正文

      小議Windows通信編程思考

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

      小議Windows通信編程思考

      一、windows通信機制

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

      Windows3.1通信函數主要有:

      OpenComm

      打開一通信設備

      BuildCimmDCB將一設備定義字符串轉變為DCB數據結構

      EnableCommNotification使能或禁止傳送WM_COMMNOTIFY消

      SetCommState設置通信設備狀態

      SetCommEventMask設置通信事件掩碼

      ReadComm從通信設備讀字符

      WriteComm向通信設備寫字符

      FlushComm清除一發送或接收隊列

      GetCommEventMask返回通信事件掩碼

      GetCommState返回設備控制塊(DCB)

      GetCommError恢復通信設備狀態

      CloseComm關閉一通信設備

      DCB數據結構、其它通信函數及各函數的具體用法請參見有關資料。

      一般Windows通信編程應包括兩部分:設備初始化及WM_COMMNOTIF

      Y消息處理。

      設備初始化典型流程如圖1。

      圖1

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

      圖2

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

      設備初始化及WM_COMMNOTIFY消息處理兩部分密切相關。所有類型WM_COMMNOTIFY消息的傳送都是因為在初始化函數中進行了相應的設置。

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

      二、Windows通信疑難探討

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

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

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

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

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

      2.接收數據為何"丟失"?

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

      經檢查,"丟失"現象是由于接收數據超時引起的,當通信對方時鐘頻率較低時,規定時間內收不到cbWriteNotify指定的數據量,即所謂"超時",Windows照樣向應用程序發送帶CN_RECEIVE標志的WM_COMMNOTI

      FY消息。然后,在應用程序輸入隊列數據讀出之前,Windows不再發送該類消息。

      解決的方法是減小cbWriteNotify的設定值直到不再發生"超時"現象。

      發送數據時同樣應正確設定cbOutQue值,以免產生"超時"現象。

      如果將cbWriteNotify或cbOutQue設為-1,則Windows不傳送帶CN_RECEIVE或CN_TRANSMIT標志的WM_COMMNOTIFY消息。

      3.怎樣合理使用FlushComm與GetCommError函數?

      FlushComm函數的功能是清除指定設備接收或發送隊列。GetCommError函數的功能是返回指定設備最近錯誤碼和當前狀態,更重要的是"解鎖"功能:當出現通信錯誤時,Windows會鎖死通信端口直到調用GetCommError。

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

      為了合理調用FlushComm和GetCommError函數,建議在事件掩碼中包含EV_ERR與EV_BREAK。

      4.Windows多串口通信

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

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

      三、Windows通信實例

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

      編程環境為中文Windows3

      2、BorlandC++3.1OWL。

      #include<windows.h>

      #include<owl.h>

      #include<window.h>

      #include<string.h>

      intCOM=1;//串口號

      unsignedcharReceiveBuff〔11〕;//接收數據緩存

      _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();//設置Windows不支持的波特率

      virtualBOOLWMCommNotify(TMessage&Mg)=〔WM_FIRST+

      WM_COMMNOTIFY〕;

      virtualvoidSetupWindow();

      };

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

      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;//設備控制塊

      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://有事件掩碼中定義的事件發生

      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);//向對方回0x0f

      }

      break;

      caseCN_RECEIVE://接收到了規定個字符或超時

      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);//向對方回0x0f

      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;}

      亚洲av永久无码精品秋霞电影秋| 亚洲高清资源在线观看| 亚洲国产精品线观看不卡| 亚洲v高清理论电影| 亚洲AV日韩AV天堂久久| 亚洲成av人片天堂网| 亚洲精品中文字幕无码蜜桃| 国产亚洲午夜高清国产拍精品| 久久久久无码专区亚洲av| 久久久久亚洲AV成人网人人软件| 国产午夜亚洲精品理论片不卡 | 国产AⅤ无码专区亚洲AV| 久久亚洲AV永久无码精品| 亚洲综合色自拍一区| 亚洲日韩v无码中文字幕| 久久久久久久综合日本亚洲| 久久精品九九亚洲精品天堂| 久热综合在线亚洲精品| 精品无码一区二区三区亚洲桃色| 亚洲精品亚洲人成在线麻豆| 亚洲一卡2卡4卡5卡6卡残暴在线| 亚洲日本国产综合高清| 亚洲av永久无码天堂网| 亚洲高清无码专区视频| 老司机亚洲精品影视www| 国产精一品亚洲二区在线播放| 亚洲精品夜夜夜妓女网| 亚洲国产成人私人影院| 亚洲麻豆精品果冻传媒| 亚洲综合偷自成人网第页色| 色欲色欲天天天www亚洲伊| 亚洲乱码日产精品a级毛片久久| 伊人久久大香线蕉亚洲| 久久精品亚洲综合一品| 亚洲小说图片视频| 亚洲av午夜国产精品无码中文字| 亚洲国产精品激情在线观看| 亚洲精品蜜桃久久久久久| 亚洲黄色免费在线观看| 亚洲国产视频久久| 午夜亚洲国产成人不卡在线|