2016-12-28 69 views
0

我正在C#中构建一个程序,以便在我的大学课程中使用它来演示异步连接如何使用RS-232和两台连接在一起的计算机工作。我的课程不是关于编程,而是数据网络,所以我正在寻找连接。如何知道串口的输入缓冲区有信息,在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. 我想你应该附上您SerialDataReceivedEventHandler之前 调用_PuertoSerial.Open()。

    它可能没有任何作用,因为事件处理程序通常可以动态启用/禁用,但我基于以下来自MSDN上用于SerialPort的.NET源代码的评论。

    //所有的魔法都发生在对实例的.Open()方法的调用中。

    //在内部,SerialStream构造函数打开文件句柄,设置设备控制块和关联的Win32结构,并开始观察事件周期。

  2. “对象引用”错误可能通过从DataReceivedHandler中删除 静态修饰符来解决。如果不是,或者由于某种原因需要使用静态修改器,那么txtRecieve控件可能有一个专用修饰符,需要将其修改为内部或公共。您应该能够使用Visual Studio 调试模式进入InitializeComponent()方法,并参见 其中正在实例化txtRecieve。

+0

感谢您的帮助! – DonPandon

0

嗯,我相信我需要阅读更多。这是我如何解决了这个问题(如果这不是真正的解决办法,至少是工作现在):

  1. 我感动_PuertoSerial.open前的“SerialDataReceivedEventHandler”行();

  2. 我跟着从这篇文章的建议:

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 +一个新的)是这样的:

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(); 
     } 
    } 

现在看来工作正常。当我连接另一个终端并看到程序正在互相交互时,最终的测试就会到来。