C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[74420] Re:Re:Re:Re:Re:통신문제 고수님들 도와주세요 ㅜㅜ
송신영 [palindrome] 104 읽음    2017-06-14 17:29
시리얼 통신 수신 처리 부의 여러 가지 방법 중에
간단한 방식 하나만 참고 하시라고 올려드립니다.
주석 잘 읽어 보시면 조금 도움이 될겁니다.
(온도 컨트롤러와 통신할 때 사용한 소스입니다.)

STX 12345 ETX
STX 12345 ETX STX 12345 ETX
STX 12345 ETX STX 123
STX 123
2345 ETX
2345 ETX STX 123
2345 ETX STX 12345 ETX

시리얼 통신에서는 위와같이 이런 저런 모든 경우를 처리할 수 있는 코드를 작성해야합니다.
중간에 끈겨서 들어왔다고 무조건 버리면 안되고 차곡차곡 모아서 프로토콜과 맞는 상태가
될 때 까지 계속 비교해 봐야 합니다.

//---------------------------------------------------------------------------
// *.h 파일  
// 수신 버퍼는 데이터가 여러번 잘린 상태로 들어올 수 있으니 멤버 변수나 글로벌로 잡아
AnsiString m_sTEMP_RECEIVE_BUFFER ; 야함. 

// *.cpp 파일. 
//---------------------------------------------------------------------------
void __fastcall TfmMain::ComPortRxChar(TObject *Sender, int Count)
{
    String     szStrTemp;

    char cBCC;
    char cCalBCC;
    int  nSTXIndex;
    int  nETXIndex;
    int  nStrLen;

    ComPort->ReadStr(szStrTemp, Count);

    AnsiString sReadBuffer = szStrTemp;
    
    try {
        // 수신 데이터 처리 하는 도중 다음 데이터가 들어올 경우를 대비하여 크리티컬섹션으로 잡고 작업을 진행 해야 함.  
        EnterCriticalSection(&m_SyncTempComPort);  

        m_sTEMP_RECEIVE_BUFFER = m_sTEMP_RECEIVE_BUFFER + szStrTemp;

        while(1) {
            // STX 시작 위치 찾기 (1부터 시작)
            nSTXIndex = m_sTEMP_RECEIVE_BUFFER.AnsiPos(sSTX);

            if(nSTXIndex > 0) {
                
                // STX 앞부분 잘라내기 (STX앞부분은 이전에 처리된 값이거나 쓰래기 값이기 때문에 삭제한다. )
                if(nSTXIndex > 1) {
                    szStrTemp = m_sTEMP_RECEIVE_BUFFER.SubString(nSTXIndex, m_sTEMP_RECEIVE_BUFFER.Length());
                    m_sTEMP_RECEIVE_BUFFER = szStrTemp;
                    szStrTemp = "";
                }

                // ETX 위치 찾기 (1부터 시작)
                nETXIndex = m_sTEMP_RECEIVE_BUFFER.AnsiPos(sETX);

                // 데이터 크기 구하기 
                // BCC 값은 0x00 즉 문자로 보면 NULL일 경우도 있다. 
                // 그러므로 일반 char 배열로 받으면 처리가 곤란해 진다. 
                // 그래서 수신 버퍼를 AnsiString 으로 사용하면 NULL 문자도 .Length()에 
                // 포함되기 때문에 효과적이다.                 
                nStrLen = m_sTEMP_RECEIVE_BUFFER.Length();
    			
                if(nETXIndex > 1 && (nStrLen >= (nETXIndex+1))) { // ETX 위치 유효한지 확인, BCC 수신 확인.
                    AnsiString sCommand;        // STX - ETX 까지 (BCC를 다시 계산하여 수신된 BCC와 비교하기 위해)
                    AnsiString sFullMessage;    // STX - BCC 까지 

                    // 수신한 데이터에서 STX-ETX까지(완전한 문장 하나)의 데이터만 일단 복사. 
                    sCommand = m_sTEMP_RECEIVE_BUFFER.SubString(1, nETXIndex);

                    sFullMessage = m_sTEMP_RECEIVE_BUFFER.SubString(1, nETXIndex+1);
                    
                    // BCC 얻어온다.
                    cBCC = m_sTEMP_RECEIVE_BUFFER.c_str()[nETXIndex];


                    // 위에서 얻어온 데이터까지 수신 버퍼에서 삭제한다. 
                    if(m_sTEMP_RECEIVE_BUFFER.Length() == nETXIndex +1){
                        // BCC 뒤에 더이상 값이 없을 경우 변수 초기화.
                        m_sTEMP_RECEIVE_BUFFER = "";
                    }  	
                    else {
                        // BCC 뒤에 값이 더 있을 경우 뒷부분만 남기고 앞부분 삭제.
                        szStrTemp = m_sTEMP_RECEIVE_BUFFER.SubString(nETXIndex+2, 
                                           (m_sTEMP_RECEIVE_BUFFER.Length()-(nETXIndex+1)));
                        m_sTEMP_RECEIVE_BUFFER = "";
                        m_sTEMP_RECEIVE_BUFFER = szStrTemp;
                        szStrTemp = "";
                    }
                                    
                    // 수신한 데이터의 BCC를 계산한다. 
                    cCalBCC = MakeBCC(sCommand, false, true); // BCC 계산에서 STX제외. ETX는 포함


                    // 수신한 BCC와 계산한 BCC확인하여 동일하지 않은 경우 노이즈를 탄것이니 그냥 무시하고 다음을 기다린다. 
                    if(cCalBCC != cBCC){
                        // TODO: BCC 오류 발생 시 사용자게에 알려주는 코드를 삽입한다. (현재는 그냥 무시)
                    }
                    else if(sCommand.Length() > 0) {

                        // 수신 데이터 처리 루틴..... 
                        
                    }
                }
                else {
                    break;
                }
            }
            else {
                // STX가 없을 경우 현재까지 받은 모든 데이터는 필요 없는 데이터 이니 수신 버퍼 초기화. 
                m_sTEMP_RECEIVE_BUFFER = "";
                break;
            }
        }
    }
    __finally {
        LeaveCriticalSection(&m_SyncTempComPort);
    }
    
}




님이 쓰신 글 :
: 아아 무슨 말씀이신지는 이해 됬어요!
:
: rxchar 에서 rx버퍼에 데이터를 받을때
:
: rx_buf[rx_pt++] = ch;
: if (ch==_STX)
: {
:     rx_buf[0] = ch;
:     rx_pt = 1;
: }
: else if (ch==_ETX)
: {
:     rx_buf[rx_pt++] = '\0';
:     rx_pt = 0;
:     break;
: }
: 이렇게 stx가 들어오면 0에 넣고 1부터 데이터를 받게 했는데
: 한번 어긋나고 나서 정상적인 데이터가 들어오기까지 상당히 시간이 걸리네요
: 초보인데 혼자 하느라 넘 어렵네요ㅜㅜ
:
: 답변 감사드립니다!
:
:
: Intotheblue 님이 쓰신 글 :
: : 그런식으로 처리하며 안된다고요.
: :
: : stx 1 2 3 4 etx
: : 이런게 항상 들어오는게 아니라는 말입니다.
: :
: : stx 1 2
: : 3 4 etx
: :
: : 이런식으로 두번으로 나눠서 수신될경우
: : 두번째 수신 내용에는 님 글처럼 버퍼 0 에 stx 가 없으니 다음으로 넘어가질 않죠
: :
: :  님이 쓰신 글 :
: : : 답변 감사드립니다.
: : :
: : : 음 제가 잘 이해가 안되는데요 ㅜㅜ
: : :
: : : 버퍼0에 stx가 들어오는걸 확인하고 다음으로 넘어가는데
: : :
: : : 정작 stx가 들어오질 안아서 다음으로 넘어가질 않고 있어요.. 그래서 계속 쳌섬에서 걸리기도 하고
: : :
: : :  
: : :
: : : Intotheblue 님이 쓰신 글 :
: : : :
: : : : 통신에서는
: : : : 모든 데이터가 함께 들어온다고 생각해서는 안됩니다.
: : : :
: : : : 따라서 수신 버터의 내용을 또다른 버퍼에 넣고 ..
: : : : 원하는 부분만 짤라서 써야 하고..
: : : : (stx ~ etx 까지 내용만 추출)
: : : :
: : : : 간혹 일부 데이터가 안오거나 ..
: : : : 노이즈 등의 영향으로 변조된 데이터가 들어 오는 경우도 있기 때문에..
: : : :
: : : : 이런 경우에 대한 처리도 들어가야 합니다.
: : : :
: : : : 이지형 님이 쓰신 글 :
: : : : : 안녕하세요 이제 막 C빌더 배우고 있는 신생아 입니다.
: : : : :
: : : : : C빌더6을 사용하고 Cport264 입니다.
: : : : :
: : : : : 제가 마이컴에서 rs232로 데이터를 받아서 스트링 그리드로 데이터 표시하는 프로그램을 만들고 있는데
: : : : :
: : : : : 통신쪽에 문제가 생겨서 질문드려요
: : : : :
: : : : : 마이컴에서 200ms 마다 송신을 하는데 버퍼 맨앞에 stx 보내고'1' 'D' 'A' 'T' 문자열 보내고 그다음 데이터를 보내서
: : : : :
: : : : : 앞에 stx와1 D A T를 확인하고 그다음 버퍼부터 데이터를 스트링 그리드에 표시하게 했는데요
: : : : :
: : : : : 문제는 데스크탑 PC에서는 몇시간동안 해도 잘 되는데
: : : : :
: : : : : 노트북에서 해보니 짧게는 1분 길어도 2~3분만에 스트링 그리드에 표시가 안되더라구요
: : : : :
: : : : : 그래서 데이터 표시가 안될때 rx 버퍼를 확인해보니 수신이 되긴 하는데
: : : : :
: : : : : 버퍼 맨앞에 stx가 아니더라구요..맨앞이 'D' 일때도 있고  '1' 일때도 있고..
: : : : :
: : : : : 포트를 끊었다가 다시 하면 또 되다가 2~3분 후에 똑같은 현상이 나옵니다
: : : : :
: : : : : C빌더에서는 rx char 에서 버퍼에 데이터 받고
: : : : :
: : : : : 타이머를 이용하여 프로세싱 하게 했고 타이머 인터발은 1 입니다.
: : : : :
: : : : : 데스크탑에서는 잘 되는데 노트북에서 저런현상이 나오는게 원인을 잘 모르겠네요 ㅜㅜ
: : : : :
: : : : : 고수님들의 조언 부탁드립니다.
: : : : :
: : : : :

+ -

관련 글 리스트
74413 통신문제 고수님들 도와주세요 ㅜㅜ 이지형 92 2017-06-14
74417     Re:통신문제 고수님들 도와주세요 ㅜㅜ 라스코니 81 2017-06-14
74419         Re:Re:통신문제 고수님들 도와주세요 ㅜㅜ 87 2017-06-14
74414     Re:통신문제 고수님들 도와주세요 ㅜㅜ Intotheblue 75 2017-06-14
74415         Re:Re:통신문제 고수님들 도와주세요 ㅜㅜ 70 2017-06-14
74416             Re:Re:Re:통신문제 고수님들 도와주세요 ㅜㅜ Intotheblue 99 2017-06-14
74418                 Re:Re:Re:Re:통신문제 고수님들 도와주세요 ㅜㅜ 83 2017-06-14
74421                     Re:Re:Re:Re:Re:통신문제 고수님들 도와주세요 ㅜㅜ 라스코니 97 2017-06-14
74420                     Re:Re:Re:Re:Re:통신문제 고수님들 도와주세요 ㅜㅜ 송신영 104 2017-06-14
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.