본문으로 바로가기
반응형

안녕하세요

모드버스 시리얼 통신에 대해 소스 요청이 많아 테스트로 작성한 코드입니다.

 

블로그에 기존에 작성된 소스를 기반으로 작성했으며

클래스를 상속하여 오버라이딩한 부분도 같습니다.

 

주석을 조금 자세히 추가하였으며 궁금한 점은 댓글로 여쭤봐주시면 감사하겠습니다.

 

CRC 계산하는 클래스와 리시브한 데이터를 컨버전하는 클래스는 따로 사용하지 않았습니다.

 

Sendbuff 는 통신 장비에 따라 얼마든지 바뀔 수 있습니다.

함수번호와 아이디는 대부분 0x01 ~ 0x02 , 0x03 ~ 0x04 일 확률이 높습니다.

 

MainConnect.cs (통신 연결을 도와주는 메인 클래스)

 

전체 파일 요청은  댓글로 부탁드려요

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TEST_RTU
{
    //cSerialPort 함수 상속(오버라이딩을 하기위함)
    class MainConnect : cSerialPort
    {
        //CRC 계산 함수(현재 쓰지 않음)
        //cModbusRTU RtuCRC = new cModbusRTU();

        //컨버젼 클래스(데이터 컨버전)  
        //cConversion conv = new cConversion();
        cLog log = new cLog();
        cWaitBuff WaitBuff = new cWaitBuff();
        // 시리얼 통신시 쓰레기 값 자르기
        public int COM_READtail;
        private int ilen;

        //요청버퍼 
        public static byte[] Sendbuff =
        {
             0x01,        //ID
             0x04,        //FunctionCode
             0x0B, 0xB8,  //시작주소 
             0x00, 0x40,  //데이터 길이(64)  ///(63) //0x00 0x3F 0x32 0x1B
             0x73, 0xFB   //CRC
         };


        private byte[] ReadBuff = new byte[1024];
        public static byte[] CopyReadBuff = new byte[1024];
    //================================================================================================
    //================================================================================================//

        //==============================
        //시리얼 포트 오픈 함수 오버라이딩 
        //iret 값이 1이면 오픈 / -1이면 에러
        //==============================//
        public int SerialPort_Open()
        {
            int iret = 0;
            iret = fn_Open(DataReceived);
            return iret;
        }

        //=====================================
        // 시리얼 포트 닫기 함수 오버라이딩 
        // 포트가 오픈되어있는 경우 CLOSE
        //=====================================//
        public void SerialPort_Close()
        {
            if (serialport.IsOpen == true)
            {
                fn_Close(DataReceived);
                serialport.DataReceived -= DataReceived;
            }
        }
        //=====================================
        // 데이터를 받기위한 함수(리시브)
        // 시리얼포트 오픈시 바로 데이터 수신
        //=====================================//
        private void DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            try
            {
                ilen = serialport.BytesToRead;

                // 받은 데이터 길이(바이트)가 200 이상일 경우 COM_READtail 변수 초기화
                if (ilen > 200 || COM_READtail > 200) COM_READtail = 0;

                /* 통신을 통해 읽은 데이터(바이트 수) 만큼 
                 * ReadBuff에 복사 
                 * (COM_READtail 0 일시 ReadBuff 0 번째 부터 복사)
                 * (COM_READtail 1 일시 ReadBuff 1 번째 부터 복사) */
                serialport.BaseStream.Read(ReadBuff, COM_READtail, ilen);
                COM_READtail += ilen;

                //로그 함수를 이용한 데이터 확인용 로그만들기 //
                log.fn_LogWrite("수신한 바이트 수 : " + COM_READtail);

                // 읽은 데이터 길이가 133개, 함수번호가 0x04, 장치번호가 0x00 일 경우에
                // 알맞은 데이터가 수신된 것으로 확인
                // (보내기(요청) 버퍼에 따라 수신되는 길이와 함수번호 장치번호는 다를 수 있음
                
                if (COM_READtail == 133 && ReadBuff[1] == 0x04)
                {
                    log.fn_LogWrite("알맞은 데이터를 수신함");
                    //ReadBuff의 값을 CopyReadBuff 0번째 부터 128 데이터의 길이를 복사
                    //앞 시작주소, 함수번호, 장비번호를 제외한 실질 데이터를 구분하기 위함
                    Array.Copy(ReadBuff, 3, CopyReadBuff, 0, 128);
                    //COM_READtail = 0;
                }
                else COM_READtail = 0;
            }catch (Exception ex)
            {
                log.fn_LogWrite("DataRecived 함수 에러 : " + ex.Message.ToString());
            }
        }


        //===========================================
        //쓰레드 타이머를 이용하여 데이터 요청(Send)
        //===========================================
        public void CallbackData(object o)
        {
            try
            {
                //웨이트 버퍼의 큐에 카운트가 0일 시 데이터 요청
                //웨이트 버퍼의 큐에 카운트가 있을 시는(다른 데이터 요청이 있을경우)
                //Dequeue 함수를 통해 다른 데이터 요청 버퍼 처리
                if (WaitBuff.queue_WAITBUFF.Count == 0) fn_Send(Sendbuff, 0, 8);
                else if(WaitBuff.queue_WAITBUFF.Count > 0)
                {
                    byte[] SenBuff = new byte[8];
                    SenBuff = WaitBuff.queue_WAITBUFF.Dequeue();
                    fn_Send(SenBuff, 0, 8);
                }
            }
            catch (Exception e)
            {
                log.fn_LogWrite("CallBackData 함수 에러 : " + e.Message.ToString());
            }
        }

    }
}

[C#] - C# 모드버스 RTU 시리얼통신 구현 폼 (주석 추가, 소스 공개)

 

C# 모드버스 RTU 시리얼통신 구현 폼 (주석 추가, 소스 공개)

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using Syste..

dodo1054.tistory.com

[C#] - C# 모드버스 RTU 시리얼통신 구현하기(주석 추가, 소스 공개)

 

C# 모드버스 RTU 시리얼통신 구현하기(주석 추가, 소스 공개)

메인 클래스에서 참조(상속)하고 있는 시리얼통신을 위한 기본소스(중요) using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO.Ports; using System.Threadi..

dodo1054.tistory.com

[C#] - C# 모드버스 RTU 시리얼통신 구현 소스 파일 첨부

 

C# 모드버스 RTU 시리얼통신 구현 소스 파일 첨부

>>> 구성요소 <<< MainConnect.cs Form.cs <공용으로 쓰는 lib> cConversion.cs (데이터 컨버전 클래스) cLog.cs (로그 생성 클래스) cModbusRTU.cs (CRC 생성) cSerialProt.cs (통신 함수) ~ 기타 ~ (2개)

dodo1054.tistory.com

[C#] - C# 모드버스 RTU 시리얼통신 구현하기

[C#] - C# 모드버스 RTU 시리얼통신 구현하기2

[C#] - C# Modbus RTU CRC 구하기

반응형