超碰爆乳超爆乳中文字幕版_亚洲中字第二区av_欧洲熟女又乱又伦_中文字幕av网址

  •  作者:admin
  •  積分:2705
  •  等級(jí):專(zhuān)家教授
  •  2013/05/08 10:22:44
  •  
  • 樓主(閱讀:6053/回復(fù):0)API串口通信

    API串口通信
    串行端口是系統(tǒng)資源的一部分,其本質(zhì)是作為CPU和串行設(shè)備間的編碼轉(zhuǎn)換器。當(dāng)數(shù)據(jù)從 CPU經(jīng)過(guò)串行端口發(fā)送出去時(shí),字節(jié)數(shù)據(jù)轉(zhuǎn)換為串行的位(Bit); 接收數(shù)據(jù)時(shí),串行的位被轉(zhuǎn)換為字節(jié)數(shù)據(jù)。應(yīng)用程序要使用串口進(jìn)行通信,必須在使用之前向操作系統(tǒng)提出資源申請(qǐng)要求(即打開(kāi)串口),通信完成后再釋放資源(即關(guān)閉串口)。

    串行通信一般可以分為同步和異步兩種操作方式。所謂同步方式是指在串口的接收緩沖區(qū)中讀取規(guī)定數(shù)目的數(shù)據(jù),直到規(guī)定數(shù)目的數(shù)據(jù)全部被讀出或設(shè)定的超時(shí)時(shí)間已到才返回。如果規(guī)定的待讀取數(shù)據(jù)量大且設(shè)定的超時(shí)時(shí)間也較長(zhǎng),而接收緩沖區(qū)較小,則可能引起線程阻塞。而異步方式是利用Windows的多線程結(jié)構(gòu),讓串口的讀寫(xiě)操作在后臺(tái)進(jìn)行,而應(yīng)用程序的其他部分在前臺(tái)執(zhí)行。
    如果按驅(qū)動(dòng)方式分,串口通信也可分為查詢(xún)和事件驅(qū)動(dòng)兩種操作類(lèi)型。所謂查詢(xún)方式是指一個(gè)進(jìn)程中的某一線程定時(shí)查詢(xún)串口的接收緩沖區(qū),如果緩沖區(qū)中有數(shù)據(jù),就讀取數(shù)據(jù);若緩沖區(qū)中沒(méi)有數(shù)據(jù),該線程將繼續(xù)執(zhí)行。查詢(xún)方式會(huì)占用大量的CPU時(shí)間,它實(shí)際上是同步方式的一種派生。查詢(xún)方式是一種最直接的讀串口方式,但定時(shí)查詢(xún)可能發(fā)生得過(guò)早或過(guò)晚,在數(shù)據(jù)變化較快的情況下,特別是主控計(jì)算機(jī)的串口通過(guò)擴(kuò)展板擴(kuò)展至多個(gè)時(shí),容易發(fā)生數(shù)據(jù)的丟失。雖然指定時(shí)間隔越小,數(shù)據(jù)的實(shí)時(shí)性越高,但系統(tǒng)的資源也被占去越多。而事件驅(qū)動(dòng)方式則是一種高效的串口讀寫(xiě)方式,通過(guò)設(shè)置事件來(lái)通知系統(tǒng)工作,即當(dāng)所希望的事件發(fā)生時(shí),Windows發(fā)出該事件已發(fā)生的通知,系統(tǒng)才進(jìn)行相應(yīng)處理,避免了數(shù)據(jù)丟失,與DOS環(huán)境下的中斷方式很相似,實(shí)時(shí)性較高。Windows中提供文件讀寫(xiě)的異步方式,主要是針對(duì)文件I/O相對(duì)較慢的特點(diǎn)而進(jìn)行的改進(jìn),它利用了Windows的多線程結(jié)構(gòu)。雖然在Windows中沒(méi)有實(shí)現(xiàn)任何對(duì)文件I/O的異步操作,但它卻能對(duì)串口進(jìn)行異步操作,因此可以提高系統(tǒng)的整體性能。
    通過(guò)Visual C++的標(biāo)準(zhǔn)通信函數(shù)_inp和_outp可直接通過(guò)串口輸入和輸出數(shù)據(jù)。一般來(lái)說(shuō),在Visual C++中開(kāi)發(fā)串口通信程序主要有調(diào)用API函數(shù)和使用ActiveX控件技術(shù)兩種方式。基本步驟為:打開(kāi)串口設(shè)備,設(shè)置串口通信屬性,進(jìn)行串口讀寫(xiě)操作,關(guān)閉串口。下面將較為詳細(xì)地討論在VC中實(shí)現(xiàn)串口通信的上述兩種方法。

    使用Win32的API

    API是附帶在Windows內(nèi)部的一個(gè)極其重要的組成部分。Windows的32位API主要是一系列復(fù)雜的函數(shù)和消息集合,可以看做是Windows系統(tǒng)為其下運(yùn)行的各種開(kāi)發(fā)系統(tǒng)提供的開(kāi)放式通用功能增強(qiáng)接口。Windows環(huán)境下對(duì)串行端口進(jìn)行操作,是把它作為文件來(lái)處理的,其中涉及到大量API函數(shù),操作起來(lái)比較復(fù)雜,可以概括為以下的幾個(gè)操作步驟:
    1. 打開(kāi)串行通信設(shè)備。在VC中使用CreateFile函數(shù)打開(kāi)串口,CreateFile將返回串口的句柄。該句柄將被用于后續(xù)的通信操作,并貫穿整個(gè)通信過(guò)程。當(dāng)采用異步方式時(shí),CreateFile函數(shù)的參數(shù)fdwAttrsAndFlags必須設(shè)為FILE_FLAG_ OVERLAPPED,如:
    m_hComFile =CreateFile(“COM1”,
    //HANDLE m_hComFile,全局變量
    GENERIC_READ | GENERIC_WRITE,
    // 允許讀寫(xiě)操作
    0, // 此項(xiàng)必須為0
    NULL, // 安全設(shè)置
    OPEN_EXISTING, //設(shè)置打開(kāi)方式
    FILE_FLAG_OVERLAPPED,
    //使用異步通信標(biāo)志
    NULL );
    2. 指定并初始化讀寫(xiě)緩沖區(qū)。程序通過(guò)調(diào)用SetupComm函數(shù)來(lái)指定讀寫(xiě)緩沖區(qū)的大小,并執(zhí)行重新分配內(nèi)部輸入和輸出緩沖的任務(wù),用PurgeComm函數(shù)對(duì)輸入和輸出緩沖進(jìn)行初始化,如:
    SetCommMask(m_hComFile, EV_RXCHAR | EV_TXEMPTY ); //設(shè)置事件驅(qū)動(dòng)的類(lèi)型
    SetupComm(m_hComFile, 1024,1024) ;
    //設(shè)置輸入、輸出緩沖區(qū)的大小
    PurgeComm(m_hComFile,
    PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
    //清空輸入、輸出緩沖區(qū)
    3.設(shè)置串口屬性,配置DCB結(jié)構(gòu)。當(dāng)用CreateFile函數(shù)完成串口打開(kāi)操作時(shí),默認(rèn)繼承設(shè)備控制塊(DCB結(jié)構(gòu))設(shè)置。通過(guò)調(diào)用GetCommState函數(shù)讀取當(dāng)前串口設(shè)備控制塊DCB設(shè)置,修改后通過(guò)SetCommState函數(shù)將其寫(xiě)入。也可以使用GetCommProperties獲取COMMPROP結(jié)構(gòu),其中記載了系統(tǒng)支持的各項(xiàng)設(shè)置,包括當(dāng)前所使用的串行設(shè)備、數(shù)據(jù)傳輸波特率、輸入輸出緩沖區(qū)大小等。例如:
    DCB dcb ;
    //定義設(shè)備控制塊結(jié)構(gòu)
    GetCommState(m_hComFile, &dcb ) ;
    //讀取串口原來(lái)的參數(shù)設(shè)置
    dcb.BaudRate =9600;
    dcb.ByteSize =8;
    dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT ;
    dcb.fBinary = TRUE ;
    dcb.fParity = FALSE;
    SetCommState(m_hComFile, &dcb ) ;
    //串口參數(shù)配置
    4. 設(shè)置超時(shí)值。串口打開(kāi)后,I/O操作的超時(shí)值采用默認(rèn)值。超時(shí)值的設(shè)置與結(jié)構(gòu)COMMTIMEOUTS及函數(shù)GetCommTimeouts和SetCommTimeouts有關(guān)。用GetCommTimeouts函數(shù)可以獲得當(dāng)前I/O操作的超時(shí)值配置,而調(diào)用SetCommTimeouts函數(shù)可以修改此配置,如:
    COMMTIMEOUTS timeouts ;
    //定義超時(shí)結(jié)構(gòu),并填寫(xiě)該結(jié)構(gòu)
    timeouts.ReadIntervalTimeout = 500;
    timeouts.ReadTotalTimeoutMultiplier = 1;
    timeouts.ReadTotalTimeoutConstant = 1000;
    timeouts.WriteTotalTimeoutMultiplier = 1;
    timeouts.WriteTotalTimeoutConstant = 1000;  SetCommTimeouts(m_hComFile,&timeouts );
    //設(shè)置讀寫(xiě)操作所允許的超時(shí)
    其中,區(qū)間超時(shí)(ReadIntervalTimeout)指的是在讀取兩個(gè)字符之間的時(shí)間間隔,它僅對(duì)從端口中讀取數(shù)據(jù)有效;總超時(shí)指的是當(dāng)讀或?qū)懱囟ǖ淖止?jié)數(shù)需要的總時(shí)間超過(guò)某一閾值時(shí),超時(shí)觸發(fā)。超時(shí)的計(jì)算公式如下:
    ReadTotalTimeout= (ReadTotalTimeoutMultiplier * bytes_to_read)+ ReadToTaltimeoutConstant
    WriteTotalTimeout = (WriteTotalTimeoutMuliplier * bytes_to_write) + WritetoTotalTimeoutConstant
    5. 進(jìn)行串行數(shù)據(jù)通信。調(diào)用函數(shù)ReadFile和WriteFile讀寫(xiě)串口。若采用異步通信方式,兩函數(shù)中最后一個(gè)參數(shù)為指向OVERLAPPED結(jié)構(gòu)的非空指針,在讀寫(xiě)函數(shù)返回值為FALSE的情況下,調(diào)用GetLastError函數(shù),返回值為ERROR_IO_PENDING,表明I/O操作懸掛,即操作轉(zhuǎn)入后臺(tái)繼續(xù)執(zhí)行。此時(shí),可以用WaitForSingleObject函數(shù)來(lái)等待結(jié)束信號(hào)并設(shè)置最長(zhǎng)等待時(shí)間。下面的例子中,在主線程中發(fā)送命令,用一個(gè)輔助線程來(lái)監(jiān)視串口,有數(shù)據(jù)到達(dá)時(shí)依靠事件驅(qū)動(dòng)讀入數(shù)據(jù)并向主線程報(bào)告。
    下面的代碼實(shí)現(xiàn)在主線程中準(zhǔn)備并發(fā)送數(shù)據(jù):
    BOOL  fWriteStat ;
    char sndBuffer[count];
    ...... // sndBuffer[]中存放待發(fā)送的數(shù)據(jù)
    OVERLAPPED overwrite;
    //設(shè)置用于異步操作的OVERLAPPED結(jié)構(gòu)
    overwrite. hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
    fWriteStat = WriteFile(m_hComFile, sndBuffer, dwBytesToWrite, &dwBytesWritten, &overwrite); //寫(xiě)數(shù)據(jù)
    if (!fWriteStat){
       if (GetLastError() == ERROR_IO_PENDING) {……}
    } 
    創(chuàng)建輔助線程:
    hReadThread=CreateThread( (LPSECURITY_ATTRIBUTES) NULL,
    //安全屬性
    0, //初始化線程棧的大小,缺省為與主線程大小相同
    (LPTHREAD_START_ROUTINE) CommReadProc, //線程函數(shù)
    GetSafeHwnd(), //此處傳入主框架的句柄
    0, (LPDWORD)lpThreadID );
    在輔助線程中監(jiān)視串口并接收數(shù)據(jù):
    UINT CommReadProc(HWND hSendWnd){
      DWORD dwEvtMask=0 ;
      SetCommMask(m_hComFile, EV_RXCHAR|EV_TXEMPTY );
    //設(shè)置串口事件驅(qū)動(dòng)
      WaitCommEvent(m_hComFile, &dwEvtMask, os ); //等待串口事件
      if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR){ //緩沖區(qū)中有數(shù)據(jù)到達(dá)  
    DWORD dwLength = ComStat.cbInQue ;
    //輸入緩沖區(qū)數(shù)據(jù)長(zhǎng)度
    COMSTAT ComStat ;
    ClearCommError(m_hComFile, &dwErrorFlags, &ComStat ) ;
    OVERLAPPED overread;
    overread. hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
    if (dwLength > 0) {
    BOOL fReadStat = ReadFile(m_hComFile, lpBuffer,dwLength, &dwBytesRead,&overread);
    //讀數(shù)據(jù)
    if (!fReadStat){
       if (GetLastError() == ERROR_IO_PENDING){
         ……}
    }            
    ::PostMessage((HWND)hSendWnd,
    WM_NOTIFYPROCESS,0,0);
    //通知主線程,串口收到數(shù)據(jù)
    }
    6. 關(guān)閉串行端口。調(diào)用函數(shù)CloseHandle即可。
    總體說(shuō)來(lái),調(diào)用API 函數(shù)實(shí)現(xiàn)串行通信,程序更為復(fù)雜,但應(yīng)用更加靈活。在API串口通信中可以將串口的屬性設(shè)置和操作封裝成一個(gè)專(zhuān)用的串口類(lèi),同時(shí)結(jié)合Windows非阻塞通信、多線程、動(dòng)態(tài)鏈接庫(kù)等手段,編寫(xiě)出高質(zhì)量的通信程序,特別是在CPU處理任務(wù)比較繁重、與外圍設(shè)備中有大量的通信數(shù)據(jù)時(shí),更具實(shí)際意義。

    歡迎使用串口論壇
    波仕與您暢游RS232/RS485串口的世界


    目前不允許游客回復(fù),請(qǐng) 登錄 注冊(cè) 發(fā)表言論。