티스토리 뷰

목차

    시리얼 통신 프로그램 중 포트 관련 파일 2개 올립니다. 그냥 가져다 쓰시면 됩니다.

     

    mfc는 이미 기술적 발전이 끊겼으므로, 90년대 200년대 초반에 만들어진 거 아무거나 쓰세요.

     

    생활정보

     경기패스 K패스 신청하기

     1인가구 지원금 3가지 알아보기

     

     

    MFC 시리얼 통신 프로그램 소스

     

    port.cpp
    다운로드
    port.h
    다운로드

     

    파일은 위에 2개 쓰시면 됩니다.

     

    C/C++ 시리얼 통신 소스 전체 내용과 주석은 아래 글을 참조해 주세요.

     

    mfc c++ 시리얼 통신 프로그램
    C/C++ 시리얼 통신 프로그램 소스

     

    ◆ SERIAL PORT 헤더 파일

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include <windows.h>
    #include <stdio.h>
    #include <string.h>
     
    class Port
    {
    public:
     
        char port_name[20];
        
        HANDLE idComDev;        // 포트 핸들
        
        // 포트 상태 관련
        BOOL    fConnected, fXonXoff, fLocalEcho, fNewLine, fAutoWrap,
                fUseCNReceive, fDisplayErrors;
        BYTE    bByteSize, bFlowCtrl, bParity, bStopBits ;
        DWORD   dwBaudRate ;
     
        HANDLE        hWatchThread;    // 쓰레드 핸들
        DWORD       dwThreadID ;    // 쓰레드 ID
        OVERLAPPED  osWrite, osRead ;    // Overlapped I/O를 위한 구조체
        
        // member function
        BOOL OpenPort(long port_number,long baud_rate_select=6);
        BOOL SetupConnection(void);
     
        long ReadCommBlock(LPSTR lpszBlock, long nMaxLength );
        BOOL WriteCommBlock(LPSTR lpByte , DWORD dwBytesToWrite);
     
        BOOL ClosePort(void);
    };
    cs

     

    ◆ #define

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #include <stdafx.h>
     
    #include "Port.h"
    #include "resource.h"
     
    #define MAXBLOCK        80
     
    DWORD BAUD_RATE_TABLE[] = {    CBR_110,CBR_300,CBR_600,CBR_1200,CBR_2400,CBR_4800,CBR_9600,CBR_14400,
                                CBR_19200,CBR_38400,CBR_56000,CBR_57600,CBR_115200,230400,460800,921600,0};
     
    // Flow control flags
    #define FC_DTRDSR       0x01   //데이터 단말기(DTR) 대기,데이터 세트(DSR) 대기를 위한 신호
    #define FC_RTSCTS       0x02
    #define FC_XONXOFF      0x04
     
    // ascii definitions
    #define ASCII_BEL       0x07
    #define ASCII_BS        0x08
    #define ASCII_LF        0x0A
    #define ASCII_CR        0x0D
    #define ASCII_XON       0x11
    #define ASCII_XOFF      0x13
     
    // Event Watch용 쓰레드 함수
    DWORD CommWatchProc( LPSTR lpData );
    cs

     

    mfc 시리얼 통신 프로그램 소스, serial 예제
    C/C++ 시리얼 통신 프로그램 소스

     

    ◆ 연결할 MFC 시리얼 포트 설정 SetupConnection

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    BOOL Port::SetupConnection(void)
    {
        // DCB 구조체를 이용하여 포트를 셋팅한다
        BYTE       bSet ;
        DCB        dcb ;
        
        dcb.DCBlength = sizeof( DCB ) ;
        
        GetCommState( idComDev, &dcb ) ;
        
        dcb.BaudRate = dwBaudRate ;
        dcb.ByteSize = bByteSize;
        dcb.Parity = bParity;
        dcb.StopBits = bStopBits;
        
        // setup hardware flow control
        
        bSet = (BYTE) ((bFlowCtrl & FC_DTRDSR) != 0) ;
        dcb.fOutxDsrFlow = bSet ;
        if (bSet)
            dcb.fDtrControl = DTR_CONTROL_HANDSHAKE ;
        else
            dcb.fDtrControl = DTR_CONTROL_ENABLE ;
        
        bSet = (BYTE) ((bFlowCtrl & FC_RTSCTS) != 0) ;
        dcb.fOutxCtsFlow = bSet ;
        if (bSet)
            dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ;
        else
            dcb.fRtsControl = RTS_CONTROL_ENABLE ;
        
        // setup software flow control
        
        bSet = (BYTE) ((bFlowCtrl & FC_XONXOFF) != 0) ;
        
        dcb.fInX = dcb.fOutX = bSet ;
        dcb.XonChar = ASCII_XON ;
        dcb.XoffChar = ASCII_XOFF ;
        dcb.XonLim = 100 ;
        dcb.XoffLim = 100 ;
        
        // other various settings
        
        dcb.fBinary = TRUE ;
        dcb.fParity = TRUE ;
        
        return SetCommState( idComDev, &dcb ) ;
    }
    cs

     

    ◆ serial 포트 열기 OpenPort

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    BOOL Port::OpenPort(long port_number,long baud_rate_select)
    {
     
        // 포트 상태 관련 변수들을 초기화 한다
        idComDev                =0 ;
        fConnected                = FALSE ;
        fLocalEcho                = FALSE ;
        fAutoWrap                = TRUE ;
        dwBaudRate                = BAUD_RATE_TABLE[baud_rate_select];
        bByteSize                = 8 ;
        bFlowCtrl                = FC_XONXOFF ;
        bParity                    = NOPARITY ;
        bStopBits                = ONESTOPBIT ;
        fXonXoff                = FALSE ;
        fUseCNReceive            = TRUE ;
        fDisplayErrors            = TRUE ;
        osWrite.Offset            = 0 ;
        osWrite.OffsetHigh        = 0 ;
        osRead.Offset            = 0 ;
        osRead.OffsetHigh        = 0 ;
        
        // Overlapped I/O에 쓰이는 Event 객체들을 생성
        // Read를 위한 Event 객체 생성
        osRead.hEvent = CreateEvent(
            NULL,    
            TRUE,    
            FALSE,   
            NULL ) ;
        if (osRead.hEvent==NULL)
        {
            return FALSE ;
        }
        
        // Write를 위한 Event 객체 생성
        osWrite.hEvent = CreateEvent(
            NULL,   
            TRUE,   
            FALSE,  
            NULL ) ;
        
        if (osWrite.hEvent==NULL)
        {
            CloseHandle( osRead.hEvent ) ;
            return FALSE;
        }
     
        
        // 포트를 생성한다
        char temp[20];
        strcpy(temp,"\\\\.\\");
        wsprintf(port_name,"COM%d",port_number);
        strcat(temp,port_name);
        idComDev = CreateFile(temp,
            GENERIC_READ | GENERIC_WRITE,
            0,                            
            NULL,                        
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,    // Overlapped I/O
            NULL);
        
        if (idComDev == INVALID_HANDLE_VALUE)
        {
            CloseHandle(osRead.hEvent);
            CloseHandle(osWrite.hEvent);
            return FALSE;
        }
        
        SetCommMask( idComDev, EV_RXCHAR ) ;
        SetupComm( idComDev, 40964096 ) ;    // 버퍼 설정
        PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |
            PURGE_TXCLEAR | PURGE_RXCLEAR ) ;    // 버퍼의 모든 데이타를 지운다
        
        // Overlapped I/O를 위한 Time Out 설정
        COMMTIMEOUTS  CommTimeOuts ;
        CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ;
        CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ;
        CommTimeOuts.ReadTotalTimeoutConstant = 1000 ;
        CommTimeOuts.WriteTotalTimeoutMultiplier = 2*CBR_9600/dwBaudRate ; // CBR_9600 기준 ms당 바이트를 두배까지 설정
        CommTimeOuts.WriteTotalTimeoutConstant = 0 ;
        SetCommTimeouts( idComDev, &CommTimeOuts ) ;
        
        // 포트를 사용가능 상태로 만들고 Event를 감시할 쓰레드를 생성한다
        if(SetupConnection()==TRUE)
        {
            fConnected = TRUE ;    
            
            // 쓰레드 생성
            hWatchThread = CreateThread(
                (LPSECURITY_ATTRIBUTES) NULL,
                0,
                (LPTHREAD_START_ROUTINE) CommWatchProc,
                (LPVOID)this,
                0,
                &dwThreadID );
     
            if(hWatchThread==NULL)    // 쓰레드 생성 실패
            {
                fConnected = FALSE ;
     
                CloseHandle(osRead.hEvent);
                CloseHandle(osWrite.hEvent);
                CloseHandle( idComDev ) ;
                return FALSE;
            }
            else
            {
                // 장치에 DTR(Data-Terminal-Ready)을 알린다
                EscapeCommFunction( idComDev, SETDTR ) ;
            }
        }
        else
        {
            fConnected = FALSE ;
     
            CloseHandle(osRead.hEvent);
            CloseHandle(osWrite.hEvent);
            CloseHandle( idComDev ) ;
            return FALSE;
        }
        return TRUE;
    }
    cs
     

    ◆ 시리얼 통신 - 읽기 ReadCommBlock

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    long Port::ReadCommBlock(LPSTR lpszBlock, long nMaxLength )
    {
        BOOL       fReadStat ;
        COMSTAT    ComStat ;
        DWORD      dwErrorFlags;
        DWORD      dwLength;
        DWORD      dwError;
        char       szError[ 10 ] ;
        
        // 큐에서 읽어야 할 데이타 크기를 가져온다
        ClearCommError( idComDev, &dwErrorFlags, &ComStat ) ;
        dwLength = min( (DWORD) nMaxLength, ComStat.cbInQue ) ;
        
        if (dwLength > 0)    // 읽어야 할 데이타가 있는 경우
        {
            // 데이타를 읽는다. Overlapped I/O임을 주의.
            fReadStat = ReadFile( idComDev, lpszBlock,
                dwLength, &dwLength, &osRead) ;
     
            if (!fReadStat)    // 읽어야 할 바이트를 다 읽지 못했다
            {
                if (GetLastError() == ERROR_IO_PENDING)    // I/O Pending에 의해 다 읽지 못한 경우
                {
                    // I/O가 완료되기를 기다린다.
                    while(!GetOverlappedResult( idComDev,
                        &osRead, &dwLength, TRUE ))
                    {
                        dwError = GetLastError();
                        if(dwError == ERROR_IO_INCOMPLETE)    // I/O가 아직 끝나지 않았다
                            continue;
                        else    // 에러 발생
                        {
                            wsprintf( szError, "<CE-%u>\n\r", dwError ) ;
                            printf(szError);
                            // 에러를 클리어 하고 다른 I/O가 가능하도록 한다
                            ClearCommError(idComDev, &dwErrorFlags, &ComStat ) ;
                            break;
                        }
                    }
                }
                else // I/O Pending이 아닌 다른 에러가 발생한 경우
                {
                    dwLength = 0 ;
                    // 에러를 클리어 하고 다른 I/O가 가능하도록 한다
                    ClearCommError( idComDev, &dwErrorFlags, &ComStat ) ;
                }
            }
        }
        
        return ( dwLength ) ;
    }
    cs

     

    ◆ 시리얼 통신 - 보내기 (쓰기) WriteCommBlock

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    BOOL Port::WriteCommBlock(LPSTR lpByte , DWORD dwBytesToWrite)
    {
        BOOL        fWriteStat ;
        DWORD       dwBytesWritten ;
        DWORD       dwErrorFlags;
        DWORD       dwError;
        DWORD       dwBytesSent=0;
        COMSTAT     ComStat;
        char        szError[ 128 ] ;
        
        fWriteStat = WriteFile( idComDev, lpByte, dwBytesToWrite,
            &dwBytesWritten, &osWrite) ;
        
        if (!fWriteStat)    // 써야할 바이트를 다 쓰지 못했다
        {
            if(GetLastError() == ERROR_IO_PENDING)    // I/O Pending에 의한 경우
            {
                // I/O가 완료되기를 기다린다
                while(!GetOverlappedResult( idComDev,
                    &osWrite, &dwBytesWritten, TRUE ))
                {
                    dwError = GetLastError();
                    if(dwError == ERROR_IO_INCOMPLETE)
                    {
                        // 보낸 전체 바이트 수를 체크
                        dwBytesSent += dwBytesWritten;
                        continue;
                    }
                    else
                    {
                        // 에러 발생
                        wsprintf( szError, "<CE-%u>", dwError ) ;
                        printf("%s\r\n",szError);
                        //WriteTTYBlock( hWnd, szError, lstrlen( szError ) ) ;
                        ClearCommError( idComDev, &dwErrorFlags, &ComStat ) ;
                        break;
                    }
                }
                
                dwBytesSent += dwBytesWritten;
                
                if( dwBytesSent != dwBytesToWrite )    // 보내야 할 바이트와 보낸 바이트가 일치하지 않는 경우
                    wsprintf(szError,"\nProbable Write Timeout: Total of %ld bytes sent", dwBytesSent);
                else    // 성공적으로 모두 보낸 경우
                    wsprintf(szError,"\n%ld bytes written", dwBytesSent);
                
                OutputDebugString(szError);
            }
            else // I/O Pending 외의 다른 에러
            {
                ClearCommError(idComDev, &dwErrorFlags, &ComStat ) ;
                return FALSE;
            }
        }
     
        return TRUE;
    }
    cs

     

    ◆ MFC 시리얼 통신 포트 닫기 (연결 끊기) ClosePort

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    BOOL Port::ClosePort(void)
    {
        fConnected = FALSE ;
     
        // 이벤트 발생을 중지한다
        SetCommMask(idComDev, 0 ) ;
        
        // Event Watch 쓰레드가 중지되기를 기다린다
        while(dwThreadID != 0);
        
        // DTR(Data-Terminal-Ready) 시그널을 Clear 한다
        EscapeCommFunction( idComDev, CLRDTR ) ;
        
        // 대기중인 모든 데이타를 지운다    
        PurgeComm( idComDev, PURGE_TXABORT | PURGE_RXABORT |
            PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
     
        // 핸들을 반환한다
        CloseHandle(osRead.hEvent);
        CloseHandle(osWrite.hEvent);
        CloseHandle( idComDev) ;
        
        return TRUE;
    }
    cs
     

     

    ◆ 이벤트 부분 (48번에 MFC 코드 작성은 마음대로)

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // Event Watch 쓰레드
    DWORD CommWatchProc( LPSTR lpData )
    {
        DWORD       dwEvtMask ;
        Port        *pp=(Port *)lpData;
        OVERLAPPED  os ;
        long        nLength ;
        BYTE       abIn[ MAXBLOCK + 1] ;
        
        memset( &os, 0sizeof( OVERLAPPED ) ) ;
        
        // Event 객체 생성
        os.hEvent = CreateEvent(
            NULL,    
            TRUE,    
            FALSE,   
            NULL ) ; 
        
        if (os.hEvent == NULL)
            return FALSE;
        
        if (!SetCommMask( pp->idComDev, EV_RXCHAR ))
        {
            CloseHandle(os.hEvent);
            return FALSE;
        }
        
        while ( pp->fConnected )
        {
            dwEvtMask = 0 ;
     
            // Event가 발생할 때 까지 블럭
            WaitCommEvent( pp->idComDev, &dwEvtMask, NULL );
            // MSDN 상의 설명과는 달리 WaitCommEvent의 마지막 매개 변수가 NULL이다
            // 설명에 의하면 FILE_FLAG_OVERLAPPED로 생성된 경우 반드시 NULL이 아닌 Overlapped
            // 구조체를 사용해야 한다고 되어있으나 몇몇 샘플을 검토한 결과 오히려 Code 87 에러가
            // 발생한다
            // 이런 이유로 os의 Event 객체는 별 의미가 없다
            // 또한 이런 이유로 멀티 쓰레드가 아닌 단일 쓰레드에서는 Overlapped I/O를 사용하는
            // 의미가 없을 것 같다 ( Polling 시 블럭되기 때문)
     
            if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
            {
                do
                {
                    if (nLength = pp->ReadCommBlock((LPSTR) abIn, MAXBLOCK ))
                    {
                        // 여기서 어떤 작업, 예외처리
                    }
                }
                while ( nLength > 0 ) ;
            }
            else
            {
                printf("<Other Event>\r\n");
            }
        }
        
        CloseHandle( os.hEvent ) ;
        
        pp->dwThreadID = 0 ;
        pp->hWatchThread = NULL ;
        
        return TRUE;    
    }
    cs

     

    시리얼 통신 프로그램 serial c++
    C/C++ 시리얼 통신 프로그램 소스

     

    mfc 시리얼 통신 프로그램 소스 중 포트 부분

     

    port.cpp
    다운로드
    port.h
    다운로드

     


    관련 글

     

    [임베디드 리눅스] 시리얼 통신 안 될 때 확인 방법, stty speed

     

    시리얼 통신, 폴링 소스 [C++ Serial COM Poll 예제]

     

    C/C++ 시리얼 통신 timeout 해결, MFC 시리얼 read write 통신 공통


     

    ⓒ written by vicddory