久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

WinXP與WinCE串口的運行機制之比較

 wfsy1983 2011-01-13
WinXP與WinCE串口的運行機制之比較
//========================================================================
//TITLE:
//    WinXP與WinCE串口的運行機制之比較
//AUTHOR:
//    norains
//DATE:
//    Saturday  11-November-2006
//Passed Environment:
//    PC:WinXP+VC6.0
//    CE:WinCE4.2+EVC4.0
//========================================================================
    查看微軟相關(guān)的串口通信文檔,可以發(fā)現(xiàn)在桌面操作系統(tǒng)中,串口通信分為兩種模式:同步和異步.而WinCE只有一種,但文檔中卻沒標明歸屬哪種模式.實際上,WinCE的串口通信模式更像介于同步和異步之間.
    在此先簡要地介紹何為同步和異步.所謂的同步,指得是對同一個設(shè)備或文件(在文中只的是串口COM1)的讀或?qū)懖僮鞅仨氁却弦粋€操作完成才能進行.比如說,調(diào)用ReadFile()函數(shù)讀取串口,但由于上一個WriteFile()操作沒完成,ReadFile()的操作就被阻塞,直到WriteFile()完成后才能運行.而異步,則無論上一個操作是否完成,都會執(zhí)行目前調(diào)用的操作.還是拿前面舉的例子,在異步模式下,即使WriteFile()沒有執(zhí)行完成,ReadFile()也會立刻執(zhí)行.
   
   
1.CreateFile()參數(shù)的差異
    首先說明一下WinCE和WinXP打開串口時參數(shù)的差異.以打開串口COM1為例子,WinCE下的名字為"COM1:",而WinXP為"COM1",兩者的唯一區(qū)別僅僅在于WinCE下多個分號.
    例如:
    HANDLE hd = CreateFile(TEXT("COM1:"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinCE
    HANDLE hd = CreateFile(TEXT("COM1"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinXP
    在這稍微多說一下,在默認的環(huán)境下,TEXT宏在WinCE下會編譯為雙字節(jié),而WinXP為單字節(jié).換句話說,TEXT("COM1")在WinCE下相當于L"COM1",而WinXP則為"COM1".
   
   
2.單線程比較
   還是用代碼做例子來說明比較形象.這是一段單線程的代碼,先對串口進行寫操作,然后再讀.對于WinXP來說,這是同步模式.(與主題無關(guān)的代碼省略)  
   int WINAPI WinMain( HINSTANCE hInstance,
     HINSTANCE hPrevInstance,
     LPTSTR    lpCmdLine,
     int       nCmdShow)
   {
     ...     
      HANDLE hCom = CreateFile(TEXT("COM1:"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinCE
      //HANDLE Com = CreateFile(TEXT("COM1"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinXP
     
      ...
      DWORD dwBytes;
      if(WriteFile(hCom,TEXT("COM1:"),5,&dwBytes,NULL) == FALSE) //WinCE
      //if(WriteFile(hCom,TEXT("COM1"),5,&dwBytes,NULL) == FALSE) //WinXP
      {
        return 0x05;
      }
     
      ...
      DWORD dwRead;
      char szBuf[MAX_READ_BUFFER];
      if(ReadFile(hCom,szBuf,MAX_READ_BUFFER,&dwRead,NULL) == FALSE)
      {
        return 0x10;
      }
     
      ...
   }
    經(jīng)過實驗,可以發(fā)現(xiàn)這段代碼在WinCE和WinXP下都能正常工作,并且其表現(xiàn)也相同,都是在WriteFile()函數(shù)返回后才執(zhí)行ReadFile().
    由于異步模式在單線程中也能正常運作,唯一的不同只是在執(zhí)行WriteFile()時可能也會執(zhí)行ReadFile()(依WriteFile()函數(shù)執(zhí)行的時間而定),所在此不表.
  
3.多線程比較
    單線程兩者表現(xiàn)相同,那多線程呢?下面這段代碼采用多線程,先是創(chuàng)建一個讀的線程,用來監(jiān)控串口是否有新數(shù)據(jù)到達,然后在主線程中對串口寫出數(shù)據(jù).
    這里假設(shè)是這么一個情況,有兩臺設(shè)備,分別為A和B,下面的代碼運行于設(shè)備A,設(shè)備B僅僅只是應答而已.換句話說,只有A向B發(fā)送數(shù)據(jù),B才會返回應答信號.
    //主線程
    int WINAPI WinMain( HINSTANCE hInstance,
     HINSTANCE hPrevInstance,
     LPTSTR    lpCmdLine,
     int       nCmdShow)
    {
      ...
      CreateThread(NULL,0,ReadThread,0,0,&dwThrdID); //創(chuàng)建一個讀的線程.
   
      ...     
      HANDLE hCom = CreateFile(TEXT("COM1:"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinCE
      //HANDLE Com = CreateFile(TEXT("COM1"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); //WinXP
     
      ...
      DWORD dwBytes;
      if(WriteFile(hCom,"AT\r\n",4,&dwBytes,NULL) == FALSE) //WinCE
      //if(WriteFile(hCom,"AT\r\n",5,&dwBytes,NULL) == FALSE) //WinXP
      {
        return 0x05;
      }
     
      ...
   
    }
   
    //讀線程
    DWORD WINAPI ReadThread()
    {
      ...
      SetCommMask(hCom),EV_RXCHAR);
      DWORD dwCommStatus = 0;
    if(WaitCommEvent(hCom),&dwCommStatus,NULL) == FALSE)
    {
     //Clear the error flag
     DWORD dwErrors;
     COMSTAT comStat;
     memset(&comStat,0,sizeof(comStat));
     ClearCommError(hCom,&dwErrors,&comStat);
     return 0x15;
    }
   
    ...
    char szBuf[MAX_READ_BUFFER]={0};
    DWORD dwRead;
    if(ReadFile(hCom),szBuf,MAX_READ_BUFFER,&dwRead,NULL) == FALSE || dwRead == 0)
   {
    return 0x20;
   }
  
   ...
    }
   
    這段代碼在WinCE下運行完全正常,讀線程在監(jiān)聽收到的數(shù)據(jù)的同時,主線程順利地往外發(fā)數(shù)據(jù).
    然而同樣的代碼,在WinXP下則根本無法完成工作.運行此代碼,我們將發(fā)現(xiàn)CPU的占用率高達99%.通過單步調(diào)試,發(fā)現(xiàn)兩個線程分別卡在WaitCommEvent()和WriteFile()函數(shù)中.因為根據(jù)同步模式的定義,當前對設(shè)備的操作必須要等待上一個操作完畢方可執(zhí)行.在以上代碼中,因為設(shè)備B沒接到設(shè)備A的命令而不會向設(shè)備A發(fā)送應答,故WaitCommEvent()函數(shù)因為沒有檢測到接受數(shù)據(jù)而一直在占用串口;而WaitCommEvent()一直占據(jù)串口使得WriteFile()沒有得到串口資源而處于阻塞狀態(tài),這就造成了死鎖.
    而這種情況沒有在WinCE上出現(xiàn),只要WaitCommEvent()和WriteFile()不在同一個線程,就可以正常工作.這應該和系統(tǒng)的調(diào)度方式有關(guān).
   
    如果要在PC上同時進行WaitCommEvent()和WriteFile()操作,需要把串口的模式改寫為異步模式.
    更改后的代碼如下:
   
    //主線程
    int WINAPI WinMain( HINSTANCE hInstance,
     HINSTANCE hPrevInstance,
     LPTSTR    lpCmdLine,
     int       nCmdShow)
    {
      ...
      CreateThread(NULL,0,ReadThread,0,0,&dwThrdID); //創(chuàng)建一個讀的線程.
   
      ...     
      HANDLE Com = CreateFile(TEXT("COM1"),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,FILE_FLAG_OVERLAPPED);
     
      ...
      OVERLAPPED olWrite;
     memset(&olWrite,0,sizeof(m_olWrite));
     olWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
 
      DWORD dwBytes; 
     if(WriteFile(hCom,"AT\r\n",4,&dwBytes,&olWrite) == FALSE)
     {
      if(GetLastError() != ERROR_IO_PENDING)
      {
       return 0x20;
      }
     }
     if(GetOverlappedResult(hCom,&olWrite,&dwBytes,TRUE) == FALSE)
     {
      return 0x25;
     }
      ...
   
    }
   
    //讀線程
    DWORD WINAPI ReadThread()
    {
      ...    
     memset(&olWaite,0,sizeof(olWaite)); 
     olWaite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);     
      SetCommMask(hCom),EV_RXCHAR);
      DWORD dwCommStatus = 0;
    WaitCommEvent(hCom,&dwCommStatus,olWaite);
    DWORD dwByte; //norains:It is only suitable for the GetOverlappedResult(),not undefined here.
    if(GetOverlappedResult(hCom,olWaite,&dwByte,TRUE) == FALSE)
    {
     if(GetLastError() != ERROR_IO_PENDING)
     {
      return 0x30;
     }
     //Clear the error flag
     DWORD dwErrors;
     COMSTAT comStat;
     memset(&comStat,0,sizeof(comStat));
     ClearCommError(hCom,&dwErrors,&comStat);
     return 0x35;
    }
   
    ...
    memset(&olRead,0,sizeof(olRead));
    olRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
    char szBuf[MAX_READ_BUFFER]={0};
    DWORD dwRead;
    if(ReadFile(hCom,szBuf,MAX_READ_BUFFER,&dwRead,olRead) ==FALSE)
    {
     if(GetLastError() != ERROR_IO_PENDING)
     {
      return 0x40;
     }
     if(GetOverlappedResult(hCom,olRead,&dwRead,TRUE) == FALSE)
     {
      return 0x45;
     }
     if(dwRead == 0)
     {
      return 0x50;
     }
    }
  
   ...
    }
   
    測試經(jīng)過更改后的代碼,可以發(fā)現(xiàn)在WinXP下終于可以同時調(diào)用WaitCommEvent()和WriteFile()而不造成死鎖.
    在這里可以發(fā)現(xiàn)WinCE和WinXP的串口調(diào)度的差異性:單線程中,WinCE的串口工作方式和WinXP串口的同步工作模式相符;而多線程中,WinCE串口工作方式卻又和WinXP的異步方式吻合.雖然無法確切比較WinCE的單一串口模式是否比WinXP的雙模式更為優(yōu)越,但可以確認的是,WinCE的這種串口調(diào)用方式給程序員帶來了極大的便利.
   
   
4.WinXP異步模式兩種判斷操作是否成功的方法
    因為在WinXP的異步模式中,WriteFile(),ReadFile()和WaitCommEvent()大部分情況下都是未操作完畢就返回,所以不能簡單地判斷返回值是否為TRUE或FALSE來判斷.
    以ReadFile()函數(shù)做例子.
    一種是上文所用的方法:
    if(ReadFile(hCom,szBuf,MAX_READ_BUFFER,&dwRead,olRead) ==FALSE)
    {
     if(GetLastError() != ERROR_IO_PENDING)
     {
      return 0x40;
     }
     if(GetOverlappedResult(hCom,olRead,&dwRead,TRUE) == FALSE)
     {
      return 0x45;
     }
     if(dwRead == 0)
     {
      return 0x50;
     }
    }
    如果ReadFile()返回為TRUE,則表明讀文件已經(jīng)完成.但這種情況幾乎不會出現(xiàn),因為對外設(shè)的讀寫相對于內(nèi)存的讀寫來說非常慢,所以一般在ReadFile()函數(shù)還沒執(zhí)行完畢,程序已經(jīng)執(zhí)行到下一個語句.
    當ReadFile()返回為FALSE時,需要采用GetLastError()函數(shù)判斷讀操作是否在后臺進行.如果在后臺進行,則調(diào)用GetOverlappedResult()函數(shù)獲取ReadFile()函數(shù)的結(jié)果.在這里要注意的是,GetOverlappedResult()函數(shù)的最后一個參數(shù)必須設(shè)置為TRUE,表明要等ReadFile()函數(shù)在后臺運行完畢才返回.如果最后一個參數(shù)設(shè)置為FALSE,則即使ReadFile()還在后臺執(zhí)行,GetOverlappedResult()函數(shù)也會立刻返回,從而造成判斷錯誤.
   
    另一種是調(diào)用WaitForSingleObject函數(shù)達到此目的:
    if(ReadFile(hCom,szBuf,MAX_READ_BUFFER,&dwRead,olRead) ==FALSE)
    {
     if(GetLastError() != ERROR_IO_PENDING)
     {
      return 0x40;
     }
     if(WaitForSingleObject(olRead.hEvent,INFINITE) != WAIT_OBJECT_0)
    {
     return 0x55;
    }
     if(GetOverlappedResult(hCom,olRead,&dwRead,FALSE) == FALSE)
     {
      return 0x45;
     }
     if(dwRead == 0)
     {
      return 0x50;
     }
    }
    因為ReadFile()在后臺執(zhí)行完畢以后,會發(fā)送一個event,所以在這里可以調(diào)用WaitForSingleObject()等待ReadFile()執(zhí)行完畢,然后再調(diào)用GetOverlappedResult()獲取ReadFile()的最終結(jié)果.在這里需要注意的是,GetOverlappedResult()的最后一個參數(shù)一定要設(shè)置為FALSE,因為WaitForSingleObject()已經(jīng)捕獲了ReadFile()發(fā)出的event,再也沒有event傳遞到GetOverlappedResult()函數(shù).如果此時GetOverlappedResult()最后一個參數(shù)設(shè)置為TRUE,則線程會一直停留在GetOverlappedResult()函數(shù)而不往下執(zhí)行.
--------------------------------------------------------------------------------
eVC中串口編程思路和VC大致相同,但是有幾點要注意:
1) Windows CE是Unicode編碼,,讀取字符時候,要注意字節(jié)數(shù)的確定,。
2) eVC不支持重疊I/O,所有的函數(shù)中與OVERLAPPED結(jié)構(gòu)有關(guān)的參數(shù)都必須置為 NULL,。
3) eVC不支持BuildCommDCB(),,GetOverlappedResult()。
4) eVC中串口的寫法和一般VC中的寫法不同,,如串口1,,要寫為“COM1:”而不能寫為“COM1”。

本文來自CSDN博客,,轉(zhuǎn)載請標明出處:http://blog.csdn.net/ceFighter/archive/2010/04/27/5532878.aspx

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多