MFC操作串口,詳細


/*******************************************************************
*******函數功能:打開串口設備鏈接
*******函數名稱:OpenComm
*******輸入參數:無
*******輸出參數:無
*******返 回 值:TRUE -- 打開串口成功
                FALSE -- 打開窗口失敗
*******************************************************************/
BOOL CSerial::OpenComm( OPEN_COMM_PARA openCommPara)
{
    if (m_bOpened)
    {
        return FALSE;
    }
    char szPort[15] = {0};
    char szComParams[50] = {0};
    DCB dcb;
    wsprintf( szPort, "\\\\.\\COM%d", openCommPara.comPort);
    m_hIDComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );//
    if( m_hIDComDev == NULL ) return( FALSE );

    memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
    memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );

    COMMTIMEOUTS CommTimeOuts;
    CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
    CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
    CommTimeOuts.ReadTotalTimeoutConstant = 0;
    CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
    CommTimeOuts.WriteTotalTimeoutConstant = 5000;
    SetCommTimeouts( m_hIDComDev, &CommTimeOuts );

    m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

    GetCommState(m_hIDComDev,&dcb);
    dcb.DCBlength = sizeof(DCB);
    dcb.BaudRate = openCommPara.nBaud;
    dcb.ByteSize = openCommPara.nBit;
    dcb.fRtsControl = RTS_CONTROL_DISABLE;
    dcb.fDtrControl = DTR_CONTROL_DISABLE;

    if( !SetCommState( m_hIDComDev, &dcb ) || !SetupComm( m_hIDComDev, 10000, 10000 ) 
     || m_OverlappedRead.hEvent == NULL || m_OverlappedWrite.hEvent == NULL ) { DWORD dwError = GetLastError(); if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent ); if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent ); CloseHandle( m_hIDComDev ); return( FALSE ); } m_bOpened = TRUE; return(TRUE); }

 

1、win32下對串口的操作可以通過兩種方式: ActiveX控件和 Windows API函數,第一種程序簡單但是欠缺靈活,第二種自由靈活編程不易。
無論哪一種方式都需要完成四個步驟:
一、打開串口;
二、配置串口;
三、讀寫串口;
四、關閉串口。

2、win32下對文件的概念進行了擴展,無論是文件、通信設備、命名管道、郵槽、磁盤還是控制台都是用API函數CreateFile打開或者創建。

HANDLE CreateFile(  

LPCTSTR lpFileName,     //串口號,支持CString,Fomat轉換進來

DWORD dwDesiredAccess,   //訪問模式(寫 / 讀),一般設為:GENERIC_READ | GENERIC_WRITE

DWORD dwShareMode,     //共享屬性,一般設為0

LPSECURITY_ATTRIBUTES lpSecurityAttributes,   //指向安全屬性的指針 ,一般設為:NULL

DWORD dwCreationDispostion ,   //如何創建,必須設為:OPEN_EXISTING

DWORD dwFlagsAndAttributes,    //文件屬性,一般設為:FILE_FLAG_OVERLAPPED(允許對文件進行重疊操作) |  FILE_ATTRIBUTE_NORMAL(默認屬性)
HANDLE hTemplateFile       //用於復制文件句柄,對於串口而言必須設為NULL );
lpfilename:是將要打開的 串口邏輯名
dwDesiredAccess:指定串口訪問類型;
dwsharemoude:指定共享屬性 ,串口的屬性必須為0;
lpsecurityattributes:引用安全性屬性結構,缺省值為NULL;
dwcreationdistribution:創建標識,對串口操作該參數必須設置為OPEN_EXISTING;
dwflagsandattributes:屬性描述,改制為FILE_FLAG_OVERLAPPED時表示使用異步的I/O,為0是表示使用同步的I/O操作;
htemplatefile:對串口而言參數必須為NULL。

使用同步方式打開的代碼:

HANDLE hCOM;  
hCOM=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);  
if(hCOM==(HANDLE)-1) { MessageBox("打開COM失敗!"); return FALSE; } return TRUE;

使用重疊方式(非阻塞式)打開串口的方法:

HANDLE hCOM;  
hCOM=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED);  
if(hCOM==INVALID_HANDLE_VALUE) { MessageBox("打開COM失敗!"); return FALSE; } return TRUE;
3、串口的配置需要采用 DCB結構進行,這個結構體中包含了諸如 波特率、數據位數、奇偶校驗和停止位數等信息。在查詢和配置串口屬性時,都要用DCB結構作為緩沖區。

一般采用CreateFile打開串口之后,調用GetCommState函數來獲取串口的初始配置,要修改串口的配置,應該先修改DCB結構,然后再調用SetCommState函數設置串口。

BOOL GetCommState
(  
  HANDLE hFile,  // 通訊設備的句柄 
  LPDCB lpDCB    // 設備控制塊,指向一個DCB結構的指針  
);  
BOOL SetCommState(  
HANDLE hFile,  //通訊設備的句柄
LPDCB lpDCB    //設備控制塊,指向一個DCB結構的指針 
);

除了在BCD中的設置外,程序一般還需要設置I/O緩沖區的大小和超時,Windows用I/O緩沖區來緩存串口輸入和輸出的數據。如果通信的速率較高,應該設置較大的緩沖區。調用SetupComm函數可以設置串行口的輸入和輸出緩沖區的大小。

BOOL SetupComm(  
HANDLE hFile,   
DWORD dwInQueue,//設置輸入緩沖區的大小(字節數)   
DWORD dwOutQueue//設置輸出緩沖區的大小  
);   

在用ReadFile和WriteFile讀寫串口時,需要考慮超時問題。超時的作用是在指定的時間內沒有讀入或發送指定數量的字符,ReadFile和WriteFile的操作依然會結束。要查詢當前的超時設置應調用GetCommTimeout函數,該函數會填充一個COMMTIMEOUTS結構,調用SetCommTimeout可以用某一個COMMTIMEOUTS結構的內容來設置超時。讀寫串口的超時包括間隔超時和總超時,間隔超時是指在接收時兩個字符之間的最大時延,總超時是指讀寫操作總共話費的最大時間。寫操作只支持總超時,讀操作支持兩種超時。

typedefstruct _COMMTIMEOUTS 
{   
DWORD ReadIntervalTimeout;         //讀間隔超時  
DWORD ReadTotalTimeoutMultiplier;       //讀時間系數  
DWORD ReadTotalTimeoutConstant;   //讀時間常數  
DWORD WriteTotalTimeoutMultiplier;   //寫時間系數  
DWORD WriteTotalTimeoutConstant;  //寫時間常量  
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;

簡單定義示范:

    COMMTIMEOUTS CommTimeOuts;    //創建一個實例
    CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;//讀取間隔一直讀取
    CommTimeOuts.ReadTotalTimeoutMultiplier = 0;//讀時間系數
    CommTimeOuts.ReadTotalTimeoutConstant = 0;//讀時間常數
    CommTimeOuts.WriteTotalTimeoutMultiplier = 0;//寫時間系數
    CommTimeOuts.WriteTotalTimeoutConstant = 5000;//寫時間常量

 

COMMTIMEOUTS結構的成員都以毫秒為單位,總超時的計算方式是:

總超時=時間系數*要求讀/寫的字符數+時間常量

如果所有寫超時系數都為0,就不適用寫超時,如果ReadIntervalTimeOut為0,就不適用讀間隔超時,如果ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都為0,則不使用讀總超時

4、串口的讀寫采用ReadFile和WriteFile函數,其同步還是異步都由CreateFile函數決定,如果在CreateFile創建句柄時制定了FILE_FLAG_OVERLAPPED標志,就調用ReadFile和WriteFile函數是重疊的,如果未指定重疊標志,則讀寫操作應該是同步的。如果操作成功,這兩個函數都返回TRUE,當都返回FALSE時也不一定就是失敗的,應該調用GetLastError函數分析返回的結果,如果返回值是ERROR_IO_PENDING,說明重疊操作未完成

5、串行通信傳輸方式分為信號傳輸方式和線路傳輸方式兩類。信號傳輸方式是按信號原樣傳輸的基波傳輸或是利用原信號調制成高頻載波的載波傳輸;線路傳輸方式是指通信雙方設備的線路可以選擇單工、半雙工、全雙工和多雙工傳輸。

2、RS232,RS485等均采用信號傳輸方式,這種方式實現簡單,但是通信距離有限制。遠距離傳輸時一般采用Modem,通過Modem可以將原信號調制成高頻的模擬信號,然后通過電話網絡,進行遠距離通信。線路傳輸方式一般分成單工、半雙工和全雙工、多工四種方式,其中半雙工采用一條傳輸線,全雙工采用兩根線可以同時對發,多工傳輸方式采用復用技術將一個信道划分為若干個頻帶或時間片,從而使多路信號同時共享信道,這就是多工傳輸方式。使用復用器和集中器可以降低成本,提高通信網的傳輸效率。

3、在高級通信控制程序中一般采用循環冗余代碼CRC校驗以自動糾錯方式發送。

4、波特率:1波特=1bit/s,波特率是衡量通信線路基本電信號發送率的一種量度,它僅僅是電學上的度量單位,不是信息的度量單位,代表通信線路上的電脈沖速率

5、發送器在發送時鍾的有效沿(下降沿)作用下將移位寄存器的數據按位移位串行輸出,在接收數據時,接收器在接收時鍾的有效沿(上升沿)作用下對接收數據按位采樣,發送/接收時鍾頻率=1/16/64*發送/接收波特率。

6、串行傳輸協議一般有兩類:異步通信同步通信。異步傳輸格式也成為起止式異步協議,特點是通信雙方以一個字符作為數據傳輸單位,且發送方傳送字符的間隔時間是不定的。在傳輸一個字符時總是以起始位開始,以停止位結束。起始位恆為0,長度1,停止位恆為1,長度1、1.5、2可選,起始位和停止位及其中間內容稱為一幀。

7、異步傳輸的錯誤檢測:接收方能檢測到的錯誤一般有:奇偶錯超越錯(也成為溢出錯)和幀格式錯(因為時鍾不匹配或者不穩定未能按照協議裝配成一個完整的字符幀等)。

8、面向字符的同步傳輸協議:SYN控制字,是同步字符,每一幀開始都有SYN,加一個SYN的稱為單同步,加兩個SYN的稱為雙同步,同步字符的作用是為了聯絡。SOH是序始字符,它表示標題的開始,標題中包括源地址、目標地址和路由指示等信息。STX是文始字符,標志着傳送的正文的開始,數據塊是被傳送的正文內容,由多個字符組成。數據塊后面是ETB組終字符或ETX文終字符,在對很長的文段分段發送時每個分數據塊后面用組終字符ETB,最后一個分數據塊后面用文終字符ETX。在幀的最后是校驗碼,它對從SOH開始直到ETX或ETB字段進行校驗。面向字符的傳輸有未解決的問題,需要在數據字符前加轉義字符DLE,這樣的實現比較麻煩,所以出現了面向比特的同步傳輸協議。

9、面向比特的同步傳輸協議:又稱為二進制同步傳輸,協議包括三種:同步數據鏈路控制規程SDLC;高級數據鏈路控制規程HDLC;先進數據通信規程ADCCP。

10、SDLC/HDLC協議規定所有信息傳輸必須以一個標志符開始,且以同一個標識符結束。這個標識符是01111110,稱為標志場。所有的信息都是以幀的形式發送的,而標志字符提供了每一幀的邊界,接收端可以通過搜索01111110確定幀的開始和結束。

11、常用的通信標准:一是計算機與外設之間的物理接口標准,屬於七層模型中的物理層。二是按接口標准設置計算機與外設之間進行串行通信的接口電路。

DCE:數據通信設備,該設備和其與通信網絡的連接構成了網絡終端的用戶網絡接口。它提供了到網絡的一條物理連接、轉發業務量,並且提供了一個用於同步DCE設備和DTE設備之間數據傳輸的時鍾信號。調制解調器和接口卡都是DCE設備的例子。:

DTE:數據終端設備,指的是位於用戶網絡接口用戶端的設備,它能夠作為信源、信宿或同時為二者。數據終端設備通過數據通信設備(例如,調制解調器)連接到一個數據網絡上,並且通常使用數據通信設備產生的時鍾信號。數據終端設備包括計算機、協議翻譯器以及多路分解器等設備

標准指出DTE應該擁有一個插頭(針輸出)DCE擁有一個插座(孔輸出)。

常用的接口電路:一RS-232C(15m)標准,采用負邏輯,-15~-3V為邏輯1,+3~+15為邏輯0.

DTE和DCE之間的連接直連即可,兩台DTE之間的連接需要用到硬件握手信號。

二、RS-423A(1.2),RS-422A(1.2),RS-485(1.2-1.5)。RS-423A采用差分非平衡傳輸,RS-422A采用差分平衡傳輸,用兩根信號線,RS-485采用差分平衡傳輸,並擴展了RS-422A的功能,在RS-422A中只允許電路有一個發送器,而RS-485標准允許電路中有多個發送器。他們的主要區別在於RS-485只能工作在半雙工方式,RS-422A卻可以工作在全雙工方式。

三、USB接口標准。USB通用串行總線,是一種應用於PC領域的接口技術,在工業領域太麻煩--!!

12、握手處理:在半雙工方式下的握手信號可以通過硬件握手處理或軟件握手處理兩種方式完成。其中硬件握手處理即使用專門的導線來作為握手聯絡信號,握手信號和數據信號不在同一條線路上流通;軟件握手處理不使用專門的握手導線,而是與數據信號一起在同一條導線上傳輸,它通過在數據線上傳送特定的字符來作為握手的專用信號。

RS-232C支持硬件握手和軟件握手。硬件握手使用DTR/DCR/RTS/CTS四個信號,DTE設備通過TxD向DCE設備發送數據的條件是:DTR/DCR/RTS/CTS四個信號引腳電壓必須都為正電壓。

13、串口調試的注意事項:

一、DTE和DCE的區別,若連接兩個DTE,必須要將2號線和3號線交叉連接;

二、決不能帶電拔插串口。在連接和拔下串口時,一定要保證至少有一端是不帶電的,否則容易燒壞計算機或設備中的串口通信芯片。

17、使用MSComm控件的OnComm事件中接收數據:

 

voidCTTYDlg::OnOnCommMscomm1()   
{  
// TODO: 在此處添加控件通知處理程序代碼  
    VARIANT input1;  
    BYTE rxdata[2048],aa1;  
    long len1,k;  
    COleSafeArray safearray1;  
    CString strDis;  
    switch(mycomm.GetCommEvent())  
    {  
        case2:  
        input1=mycomm.GetInput();  
        safearray1=input1;  
        len1=safearray1.GetOneDimSize();  
        for(k=0;k<len1;k++)  
        {  
            safearray1.GetElement(&k,rxdata+k);  
        }  
        for(k=0;k<len1;k++)  
        {  
            if(rxdata[k]==13)  
            {  
            m_edit.SetSel(100000,100000);  
            m_edit.ReplaceSel("\15\12");  
            UpdateData(FALSE);  
            }  
            else  
            {  
                if(rxdata[k]<=126&& rxdata[k]>=32)  
                {  
                    strDis+=rxdata[k];  
                    m_edit.SetSel(100000,100000);  
                    m_edit.ReplaceSel(strDis);  
                    strDis="";  
                    UpdateData(FALSE);  
                }  
            }  
        }  
    }  
}  
18、對於這么一種情況:使用MSComm控件在單文檔程序中進行通訊,因為單文檔中並沒有可以拖動添加控件的窗口,所以需要使用程序來創建CMSComm類的實例。為使創建的實例在整個程序中都能訪問到,一般創建在CMainFrame中。其過程包括:
一、在主框架頭文件 MainFrame.h中添加代碼;
二、在主框架實現文件 MainFrm.cpp中添加代碼;
三、在手工定義資源文件中添加ID,名稱為 myID.
一、在引用區添加: #include "mscomm.h"

在類聲明中添加:

classCMainFrame:publicCFrameWnd  
{  
    protected:  
    CMSComm mycomm;//聲明類對象  
    afx_msg voidOnCommMscomm();//聲明響應函數  
    DECLARE_EVENTSINK_MAP();//聲明事件引用宏  
}  

在cpp中添加:

BEGIN_EVENTSINK_MAP(CMainFrame,CFrameWnd)  
ON_EVENT(CMainFrame,myID,1,OnCommMscomm,VTS_NONE)  
END_EVENTSINK_MAP()  

在主框架類成員函數OnCreate函數中添加代碼:

intCMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{  
    DWORD style=WS_VISIBLE|WS_CHILD;  
    if(!myComm.Create(NULL,style,CRect(0,0,0,0),this,myID))  
    {  
        Afx~~~  
    }  
}  

添加OnCommMscomm成員函數,實現對控件事件的響應。

voidCMainFrame::OnCommMscomm()  
{  
    //事件響應代碼                                                                                              
}  
由控件拖動產生的代碼,編譯器會自動在對話框的成員函數OnInitDialog()中自動生成創建控件實例的代碼,初始化及打開串口的操作可以放在該創建代碼之后;而對手動創建的CMSComm類可以在創建時候后添加 初始化代碼(Afx~~處)。當然在剛才編過的程序里初始化什么的顯得離散的原因,你知道的,是因為按鈕和選擇功能的分開就是了。
19、首先知道一點:對於CEditView類,在MFC的創建向導的6 of step6選擇,錯過的話就 無法具備文本編輯功能
20、使用API編程時可以采用同步方式和重疊的異步方式。 異步方式采用多線程。因為API中串口被當做是一個文件,可以進行文件的操作。所以可以采用CreateFile()函數打開串口,該函數返回一個串口句柄,使用該句柄初始化串口參數。然后使用WriteFile()發送串行數據,使用ReadFile()可以從串口讀取串行數據。操作完畢之后,使用closeHandle()函數關閉串口。
21、創建串口:在串口打開函數CreateFile中,lpFileName是串口號如"COM2"等,dwFlagsAndAttributes在重疊時是FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL,不重疊時為FILE_ATTRIBUTE_NORMAOL。
SetupCommState函數可以設置串口參數,hFile指向一個串口設備的句柄,該句柄由CreateFile()函數返回。dwInQueue,dwOutQueue是緩沖區大小,以字節為單位。
22、關閉串口:只用采用CloseHandle即可。
BOOL CloseHandle(HANDLE hObject);
23、發送數據:使用WriteFile函數
24、接收數據:使用ReadFile函數。
25、定時接收數據,需要將相應函數語句寫在定時器響應函數中:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM