2017-09-15 304 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数据速率上测试了大约两周,没有任何问题。