2017-09-15 33 views
0

ハードウェアとのインターフェイスの設定をSerialPortクラスを使用してC++の例から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:

私は、試してみて、あいまいなコントローラのタイプを維持するために思っていたが、実際にそこに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

マーティンC#です。データのしきい値を見ると、DataReceivedイベントが使用されていることがわかります。それは残念ながら正しく動作しません –

+0

それが使用するハンドシェイクは非常に珍しく、SerialPortでサポートされていません。バッファサイズが小さすぎると、それが原因の1つになります。 C#コードはそれを全く設定せず、それは非常に深刻な間違いです。少なくとも、Handshake.Noneを使用する必要があります。そうでなければ、長期的な不安定性についての説明はない。 * no * timeoutを使用していますが、C#コードでは間違っているのは良くありませんが、TimeoutExceptionは見逃せません。それを飲み込まないようにしてください。 ReceivedBytesThresholdを使用すると、不安定になる優れた方法です。データ損失を検出するには、ErrorReceivedイベントを使用する必要があります。 –

答えて

0

私はC#での初心者ですが、例えば(シリアルポートを使用していくつかのコードを書いたが、オシロスコープのアプリケーション上で通信しますVCP)。残念ながら、簡単な方法(DataReceivedイベント...)は機能しません。それを動作させるには、ストリームからデータを取得する独自のバックグラウンドワーカーを作成するか、シリアルポートからデータを読み込むだけです。 2番目のアプローチでもうまくいきます - 私は約8週間Windows 8Mのデータレートで問題なくテストしました。

関連する問題