2017-09-15 4 views
0

SerialPort 클래스를 사용하여 C++의 예제에서 하드웨어와 인터페이스하기위한 설정을 복제/포트해야합니다. 내가 COM 포트 설정의 세부 사항에 익숙하지 않다 때문에, 내 질문은 SerialPort 클래스의 자에게 이러한 설정을 매핑하는 방법입니다 :C에서 C# SerialPort 클래스로이 DCB 구조 설정을 매핑하는 방법

HANDLE OpenRS232(const char* ComName, DWORD BaudRate) 
{ 
    HANDLE ComHandle; 
    DCB CommDCB; 
    COMMTIMEOUTS CommTimeouts; 

    ComHandle=CreateFile(ComName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
    if(GetLastError()!=ERROR_SUCCESS) return INVALID_HANDLE_VALUE; 
    else 
    { 
     GetCommState(ComHandle, &CommDCB); 

     CommDCB.BaudRate=BaudRate; 
     CommDCB.Parity=NOPARITY; 
     CommDCB.StopBits=ONESTOPBIT; 
     CommDCB.ByteSize=8; 

     CommDCB.fBinary=1; //Binary Mode only 
     CommDCB.fParity=0; 
     CommDCB.fOutxCtsFlow=0; 
     CommDCB.fOutxDsrFlow=0; 
     CommDCB.fDtrControl=0; 
     CommDCB.fDsrSensitivity=0; 
     CommDCB.fTXContinueOnXoff=0; 
     CommDCB.fOutX=0; 
     CommDCB.fInX=0; 
     CommDCB.fErrorChar=0; 
     CommDCB.fNull=0; 
     CommDCB.fRtsControl=RTS_CONTROL_TOGGLE; 
     CommDCB.fAbortOnError=0; 

     SetCommState(ComHandle, &CommDCB); 

     //Set buffer size 
     SetupComm(ComHandle, 100, 100); 

     //Set up timeout values (very important, as otherwise the program will be very slow) 
     GetCommTimeouts(ComHandle, &CommTimeouts); 

     CommTimeouts.ReadIntervalTimeout=MAXDWORD; 
     CommTimeouts.ReadTotalTimeoutMultiplier=0; 
     CommTimeouts.ReadTotalTimeoutConstant=0; 

     SetCommTimeouts(ComHandle, &CommTimeouts); 

     return ComHandle; 
    } 
} 
나는 통신을위한 작품을 가지고있는 현재

,하지만 실행 하드웨어와의 통신은 오랜 내구성/안정성 테스트에서 불안정합니다. 여기에 직렬 포트를 설정하는 하드웨어 컨트롤러 공장에서 발췌 한 것입니다 :

private static SerialPort _serialPort = new SerialPort(); 
    private string portName = "COM23"; 
    private int baudRate = 9600; 
    private Parity portParity = Parity.None; 
    private int dataBits = 8; 
    private StopBits stopBits = StopBits.One; 
    int serialPortReceiveTimeout = 30000; 
    static private int TxRxBufferLength = 9; 

    public ControllerFactory() 
    { 
     _serialPort = new SerialPort(); 
     _serialPort.PortName = portName; 
     _serialPort.BaudRate = baudRate; 
     _serialPort.Parity = portParity; 
     _serialPort.DataBits = dataBits; 
     _serialPort.StopBits = stopBits; 
     _serialPort.ReadTimeout = serialPortReceiveTimeout; 
     _serialPort.ReceivedBytesThreshold = TxRxBufferLength; 

     try 
     { 
      _serialPort.Open(); 
      _serialPort.DiscardOutBuffer(); 
      _serialPort.DiscardInBuffer(); 
      Controller = new Controller(_serialPort, Address, TxRxBufferLength, ControllerClockFrequency); 
     } catch { } 

UPDATE :

내가 시도하고 모호한 컨트롤러의 유형을 유지하는 거라고 생각하지만, 정말이 외설 어떤 이유 :

Trinamics의 TMCM-3110이며 펌웨어 설명서 here을 찾을 수 있습니다. 또한 코드 예제는 here이며 코드 예제 here에서 연결됩니다. Trinamics의 지원에 아직 연락하지 않았습니다. 안정성 문제가 잘못된 COM 설정으로 인해 발생했을 가능성이 높다는 것을 깨달았습니다. 이러한 안정성 문제에 관한

: 나는 인해 데이터의 일부에 소프트웨어 충돌이 제대로 수신하지 바이트 것을 의미 실속

. 이로 인해 체크섬 값이 올바르지 않은 문제가 발생하고 (계산에 대한 자세한 내용은 예제 코드를 참조하십시오) 또한 직렬 포트 시간 초과로 이어 지므로 결국 프로세스가 중단됩니다. 불행하게도 문제가 어디서 발생했는지는 아직 정확히 알 수 없었지만 잘못된 직렬 포트 설정이라고 생각합니다.

다음은 TMCM 컨트롤러와의 통신을 처리하는 데 사용하는 C# 코드입니다. 그것이 당신이 볼 수 있듯이 더 많거나 적은 C++ 코드에서 1 대 1 포트 :

static readonly object locker = new object(); 
    private int sendCmdAndCheckResult(byte Address, byte Command, byte CommandType, byte MotorNr, int Value) 
    { 
     lock (locker) // this part needs to finish with out another thread interrupting, so that the sent value and the return value belong to the same command from the same thread. See firmware manual. 
     { 
      sendCmd(Address, Command, CommandType, MotorNr, Value); 
      readReturnMessageToBuffer(); 
      checkReturnedStatus(); 
      Thread.Sleep(10); 
      return getReturnedValue(); 
     } 
    } 

    private void sendCmd(byte Address, byte Command, byte CommandType, byte MotorNr, int Value) 
    { 
     TxBuffer[0] = Address; 
     TxBuffer[1] = (byte)Command; 
     TxBuffer[2] = (byte)CommandType; 
     TxBuffer[3] = (byte)MotorNr; 
     TxBuffer[4] = (byte)(Value >> 24); 
     TxBuffer[5] = (byte)(Value >> 16); 
     TxBuffer[6] = (byte)(Value >> 8); 
     TxBuffer[7] = (byte)(Value & 0xff); 
     TxBuffer[8] = 0; 
     for (int i = 0; i < 8; i++) 
      TxBuffer[8] += TxBuffer[i]; 

     Log($"TmclController: Sending COM-Port Buffer: {ByteArrayToString(TxBuffer)}"); 

     if (ComPort.IsOpen) 
      ComPort.Write(TxBuffer, 0, TxRxBufferLength); 
    } 

    private void readReturnMessageToBuffer() 
    { 
     byte Checksum = 0; 
     for (int i = 0; i < TxRxBufferLength; i++) 
     { 
      if(ComPort.IsOpen) 
      RxBuffer[i] = (byte) ComPort.ReadByte(); // read byte for byte synchronously; ReadByte() is block and returns only, when it has read a byte; this method is inefficient, but the easiest way to achieve a blocking read of the returned message; a better way would be to use asychronous reading of serial ports using e.g. the SerialPort.ReceivedBytesThreshold Property and SerialPort.DataReceived Event 
     } 
     for (int i = 0; i < 8; i++) 
      Checksum += RxBuffer[i]; 

     Log($"TmclController: Received COM-Port Buffer: {ByteArrayToString(RxBuffer)}"); 

     if (Checksum != RxBuffer[8]) 
     { 
      InvalidOperationException er = new InvalidOperationException("Returned Checksum from TMCL controller is incorrect."); 
      throw er; 
     } 
    } 

    private int getReturnedValue() 
    { 
     return (int)((RxBuffer[4] << 24) | (RxBuffer[5] << 16) | (RxBuffer[6] << 8) | RxBuffer[7]); 
    } 
+0

'가 불안정 해지고 하드웨어 스톨과의 통신이 좀 더 구체적 일 수 있습니까? 그것은 매점에서 전혀 회복합니까? 어떤 응용 프로그램 수준의 직렬 프로토콜을 사용하고 있습니까? –

+0

마틴 그것은 C#입니다. 데이터 임계 값을 볼 때 나는 DataReceived 이벤트가 사용된다는 것을 안다. 그것은 불행히도 제대로 작동하지 않습니다 –

+0

그것은 사용하는 핸드 셰이 킹 매우 독특하고 SerialPort에 의해 지원되지 않습니다. 버퍼 크기가 너무 작아서 그 이유 중 하나 일 수 있습니다. C# 코드는 전혀 설정하지 않으며 매우 심각한 실수입니다. 최소한 Handshake.None을 사용해야합니다. 장기간의 불안정성에 대한 설명은 그렇지 않습니다. 그것은 * no * timeout을 사용하지만 C# 코드는 잘못되었지만 TimeoutException은 놓치기가 불가능합니다. 그것을 삼키지 않도록하십시오. ReceivedBytesThreshold를 사용하면 불안정성을 유발할 수있는 좋은 방법입니다. 데이터 손실을 감지하려면 ErrorReceived 이벤트를 사용해야합니다. –

답변

0

나는 C#에서 초보자입니다 만 (예를 들어 시리얼 포트를 사용하여 몇 가지 코드를 썼다는 오실로스코프 응용 프로그램을 통해 통신 VCP). 불행히도 쉬운 방법 (DataReceived 이벤트 ...)이 작동하지 않습니다. 작동 시키려면 스트림에서 데이터를 가져 오는 자신의 백그라운드 작업자를 작성하거나 직렬 포트에서 데이터가 도착하면이를 읽어야합니다. 두 번째 접근법조차도 작동합니다. - 문제없이 Windows 8M 데이터 속도를 약 2 주 동안 테스트했습니다.