2017-09-15 303 views
0

我需要複製/移植設置,以便使用SerialPort類將從C++示例中的一個硬件接口連接到C#。由於我不是很熟悉的COM端口設置的詳細信息,我的問題是如何將這些設置映射到這些SerialPort類的:如何將這些DCB結構設置從C映射到C#SerialPort類

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:

我以爲我會嘗試和保持控制的類型晦澀,但真的有ISN '沒有任何理由:

這是來自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

Martin是C#。當看到數據閾值時,我知道使用了DataReceived事件。它不能正常工作 –

+0

它使用的握手非常不尋常,並且不受SerialPort支持。它使用的緩衝區大小過小,這可能是一個原因。 C#代碼根本沒有設置它,這是一個非常嚴重的錯誤,至少你必須使用Handshake.None。不是對長期不穩定的解釋。它使用* no *超時,但C#代碼確實會發生這種錯誤,但TimeoutException不可能錯過。一定不要吞下去。使用ReceivedBytesThreshold是導致不穩定性的極好方法。您必須使用ErrorReceived事件來檢測數據丟失。 –

回答

0

我是C#初學者,但寫了使用串行端口一些代碼(例如VCP)。不幸的是,簡單的方法(DataReceived事件...)不起作用。爲了使其工作,您需要編寫自己的後臺工作人員從流中獲取數據,或者在他們到達時從串口讀取數據。即使是第二種方法 - 我已經在Windows 8M數據速率上測試了大約兩週,沒有任何問題。