2016-12-28 6 views
0

비동기 연결이 RS-232 및 두 대의 컴퓨터를 함께 사용하여 작동하는 방식을 보여주기 위해 대학에서 강의하는 데 사용되는 프로그램을 C#으로 작성합니다. 내 과정은 프로그래밍에 관한 것이 아니고 데이터 네트워크이므로 연결성이 내가 원하는 것입니다. 내 프로그램에서 구현하려는 기능의직렬 포트의 입력 버퍼를 아는 방법은 C#에서 정보가 있습니까?

picture 1 - sample layout of GUI using Visual Studio 2015

하나가 표시되는 방법을 마스터 - 슬레이브, 단순 연결 작업 (즉, 키보드에서 입력을 보낼 수있는 마스터하고 선택할 수있는 프로그램, 또는 슬레이브 만 정보를 받고 텍스트 상자에 인쇄).

이미 특성 (전송 속도, 데이터 비트, 정지 비트 등)이있는 직렬 포트를 초기화 할 수있는 기능이 있습니다. 이 기능은 GUI의 콤보 상자를 사용하여 선택되며 사용자가 "포트 열기"버튼을 클릭 할 때 포트에 할당됩니다.

내가 모르는 것은 프로그램의 "노예"부분을 만드는 방법입니다. 내가 할 수있는 일에 대한 나의 생각은 프로그램을 "노예"로 선택하면 입력 버퍼에 데이터가 저장 될 때 트리거 할 일종의 플래그 나 이벤트를 기다리는 포트를 열게된다는 것입니다.

저는 여러 포럼을 읽고 있었고 필요한만큼 비슷한 것을 찾을 수 없었습니다. 그러나 나는 믿을 수있는 여러 가지 대안을 테스트하여 내가 원하는 결과에 거의 도달하지 못하게 할 것입니다. 나는 내가 잘못하고있는 일에 대한 아이디어 나이 문제를 해결할 방법에 대한 제안을 구하러 왔습니다. 문제가있는 줄은 굵은 (또는 2 별 (*))은 다음과 같습니다

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 System.Windows.Forms; 
using System.IO.Ports; 

namespace SerialCommTester 
{ 
public partial class frmSerialComm : Form 
{ 
    static SerialPort _PuertoSerial; 

    public frmSerialComm() 
    { 
     InitializeComponent(); 
     getAvailablePorts(); 
    } 

    //---------------------------------my functions-------------------------------------- 
    void getAvailablePorts() 
    { 
     string[] ports = SerialPort.GetPortNames(); 
     cmbPortList.Items.AddRange(ports); 
    } 

    void activatePort() 
    { 
    //Note that all the combo boxes are named somewhat accordingly to what the information they are meant to display. 
     if (cmbPortList.Text != "" && cmbBaudRate.Text != "" && cmbParity.Text != "" && cmbStopBits.Text != "") 
     { 
      _PuertoSerial.PortName = cmbPortList.Text; 
      _PuertoSerial.BaudRate = Convert.ToInt32(cmbBaudRate.Text); 
      _PuertoSerial.RtsEnable = true; 
      _PuertoSerial.DtrEnable = true; 

      _PuertoSerial.DataBits = Convert.ToInt32(cmbDataBits.Text); 

      if (cmbParity.Text == "Even") { _PuertoSerial.Parity = Parity.Even; } 
      else if (cmbParity.Text == "Odd") { _PuertoSerial.Parity = Parity.Odd; } 
      else if (cmbParity.Text == "Space") { _PuertoSerial.Parity = Parity.Space; } 
      else if (cmbParity.Text == "Mark") { _PuertoSerial.Parity = Parity.Mark; } 
      else { _PuertoSerial.Parity = Parity.None; } 

      if (cmbStopBits.Text =="2") { _PuertoSerial.StopBits = StopBits.Two; } 
      else if (cmbStopBits.Text == "1.5") { _PuertoSerial.StopBits = StopBits.OnePointFive; } 
      else { _PuertoSerial.StopBits = StopBits.One; } 

      if (cmbHandShake.Text == "Software Flow Control") { _PuertoSerial.Handshake = Handshake.XOnXOff; } 
      else if (cmbHandShake.Text == "Hardware Flow Control") { _PuertoSerial.Handshake = Handshake.RequestToSend; } 
      else { _PuertoSerial.Handshake = Handshake.None; } 

      _PuertoSerial.ReadTimeout = 500; 
      _PuertoSerial.WriteTimeout = 500; 

      _PuertoSerial.Open(); 
//in my understanding, this line of code is needed to handle data being received. Does it trigger a flag or something? 
      **_PuertoSerial.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);** 
     } 
     else 
     { 
      txtRecieve.Text = "Input selection missing 1 or more characteristics"; 
     } 
    } 

    ** 
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
    { 
     SerialPort testing = (SerialPort)sender; 
     txtRecieve.AppendText(testing.ReadExisting()); //txtRecieve cannot be reached within this function. It indicates the following error: "An object reference is required for the non-static field, method, or property 'frmSerialComm.txtRecieve' 
    } 
    ** 

    void enableDisableGUI(bool[] input) 
    { 
     grpConnection.Enabled = input[0]; 
     grpCharacteristics.Enabled = input[1]; 
     btnOpenPort.Enabled = input[2]; 
     btnClosePort.Enabled = input[3]; 
     txtSend.Enabled = ((cmbControlMasterSlave.Text == "Slave") ? false : true); 
    } 

    //----------------------------C# objects/functions-------------------------------------- 
    private void btnOpenPort_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      _PuertoSerial = new SerialPort(); 
      activatePort(); 
     } 
     catch(Exception ex) 
     { 
      MessageBox.Show(ex.Message, "Message ", MessageBoxButtons.OK, MessageBoxIcon.Error); 
     } 

     bool[] format = { false, false, false, true}; 
     enableDisableGUI(format); 
    } 

    private void btnClosePort_Click(object sender, EventArgs e) 
    { 
     _PuertoSerial.Close(); 
     bool[] format = { true, true, true, false}; 
     enableDisableGUI(format); 
    } 

    private void txtSend_KeyPress(object sender, KeyPressEventArgs e) 
    { 
     _PuertoSerial.Write(e.KeyChar.ToString()); //this is how I send data through the serial port. 
    } 

    private void btnClearTxts_Click(object sender, EventArgs e) 
    { 
     txtRecieve.Clear(); 
     txtSend.Clear(); 
    } 

} //class closes 
} //program closes 

난 그냥 내 학생들을위한 유용한 뭔가를 만들려면, 숙련 된 프로그래머가 아닙니다. 어떤 건설적인 비판도 높게 평가 될 것입니다.

답변

0

확실한 답이 없습니다. 두 가지 가능한 글리치를 초과하면 필요한 코드를 제공해야합니다.

  1. 나는 당신이() _PuertoSerial.Open를 호출하면 전에 당신의 SerialDataReceivedEventHandler를 첨부한다고 생각합니다.

    이벤트 핸들러는 일반적으로 동적으로 활성화/비활성화 될 수 있기 때문에 아무런 효과가 없지만 MSDN의 .Net 소스 코드에서 가져온 다음 주석에 기반하여 조언합니다.

    // 모든 마법은 인스턴스의 .Open() 메서드 호출에서 발생합니다.

    // 내부적으로 SerialStream 생성자는 파일 핸들을 열고 장치 제어 블록 및 관련 Win32 구조를 설정하고 이벤트 감시주기를 시작합니다.

  2. DataReceivedHandler에서 정적 수정자를 제거하면 "개체 참조"오류가 해결 될 수 있습니다. 그렇지 않은 경우 또는 정적 수정자가 필요한 이유가있는 경우 txtRecieve 컨트롤에 개인 수정자가 있으므로 을 내부 또는 공용으로 변경해야합니다. 디버그 모드에서 Visual Studio를 사용하여 InitializeComponent() 메서드로 들어가서 txtRecieve가 인스턴스화되는 을 볼 수 있어야합니다.

+0

도움을 주셔서 감사합니다! – DonPandon

0

글쎄, 나는 더 많이 읽을 필요가 있다고 생각한다. (이 적어도 지금 노력하고, 실제 솔루션이 아닌 경우) 이것은 내가 문제를 해결하는 방법입니다

  1. 내가 _PuertoSerial.open 전에 "SerialDataReceivedEventHandler"라인을 이동(); 지금 것 들어

    void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
        { 
         printReceivedText(_PuertoSerial.ReadExisting()); 
        } 
    
        private void printReceivedText(string text) 
        { 
         if (this.txtSend.InvokeRequired) 
         { 
          SetTextCallback d = new SetTextCallback(printReceivedText); 
          this.Invoke(d, new object[] { text }); 
         } 
         else 
         { 
          this.txtRecieve.AppendText(text); 
          _PuertoSerial.DiscardInBuffer(); 
         } 
        } 
    

    을 :

https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(EHInvalidOperation.WinForms.IllegalCrossThreadCall);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-csharp)&rd=true

그래서 내 funtions (한 existings + 새) 같이 :

  • 나는이 문서의 제안을 따라 잘 작동하고 있습니다. 마지막 테스트는 내가 다른 터미널을 연결하고 프로그램이 서로 상호 작용하는 것을 볼 때 올 것이다.