【问题标题】:serialport continuous real time data c#serialport 连续实时数据 c#
【发布时间】:2013-05-28 11:27:54
【问题描述】:

您好,我正在尝试编写一个简单的 C# WPF,它通过计时系统在虚拟记分板上实时显示时间信息。我对编程相当陌生,因此将不胜感激。

我创建了一个新线程来处理来自 COM 端口的传入数据,并且随着应用程序的开发,这些数据将被解释。现在我只想将来自计时器的原始信息(十六进制)显示到文本框中。这有效,但不符合预期。我收到了大量重复的信息,我唯一的解释是我读取数据太慢或者它一遍又一遍地读取相同的字节。我想要做的是取出每个字节并显示它们,所有这些都由一个开始/停止按钮控制。

可能的解决方案包括将整个缓冲区存储在我还不太确定的列表或数组中,我不想添加太多线程以致程序冻结所有内容。

这是我到目前为止的代码(我对这里编写的几乎所有代码都是新手,所以如果有什么不好的做法,请告诉我):

public partial class MainWindow : Window
{
    SerialPort comms;
    Thread commThread;

    bool flag;
    string message;


    public MainWindow()
    {
        InitializeComponent();
        comms = new SerialPort();
    }

    private void PortControl_Click(object sender, RoutedEventArgs e)
    {
        if (!comms.IsOpen)
        {
            PortControl.Content = "Stop";
            comms.PortName = "COM1";
            comms.BaudRate = 9600;
            comms.DataBits = 8;
            comms.StopBits = StopBits.One;
            comms.Parity = Parity.Even;
            comms.ReadTimeout = 500;
            comms.ReceivedBytesThreshold = 1;

            commThread = new Thread(new ThreadStart(Handle));

            comms.Open();

            comms.DataReceived += new SerialDataReceivedEventHandler(ReadIn);
        }
        else
        {
            PortControl.Content = "Start";
            flag = false;
            comms.DataReceived -= ReadIn;

            commThread.Join();
            comms.Close();
        }
    }

    private void ReadIn(object sender, SerialDataReceivedEventArgs e)
    {
        if (!commThread.IsAlive)
        {
            flag = true;
            commThread.Start();
        }
    }

      private void Handle()
      {
          while (flag)
          {
              if (comms.IsOpen)
              {
                  try
                  {
                      message = comms.ReadByte().ToString("X2");

                      Dispatcher.BeginInvoke((Action)(() =>
                      {
                          ConsoleBox.Text += message + " ";
                      }));
                  }
                  catch (Exception ex)
                  {
                      MessageBox.Show(ex.ToString());
                  }
              }
          }
      }


}

【问题讨论】:

  • ConsoleBox 是 GUI 控件吗(TextEdit?)请注意,与通常的处理器任务相比,GUI 绘制,尤其是像您所做的那样更新文本内容非常慢。一个简单的解决方法确实是使用 stringbuffer 并仅在单独的 timer.event 上显示它。
  • 是的,抱歉,ConsoleBox 是一个 TextBox,我不知道为什么我把它命名为这个。这个 Timer Event 是什么,它需要在另一个线程上进行吗?线程是否必须在双核 CPU 上交换而我会丢失数据?
  • 只需使用一个简单的计时器控件并将其间隔设置为一秒,然后在计时器事件期间将字符串缓冲区的内容写入文本框。当然你是对的:你必须执行这个访问线程安全,例如使用 beginInvoke,就像你在上面的代码中所做的那样。
  • 对不起,你在 wpf 而不是 winforms 世界!请使用 DispatcherTimer,如下所示:stackoverflow.com/questions/5410430/…
  • 我以前使用过 winforms 计时器,它看起来像是一种类似的方法。感谢您的帮助!

标签: c# wpf multithreading serial-port real-time


【解决方案1】:

这是一种解决方案。

串口在自己的线程中接收数据,你应该在数据接收处理程序中读取传入的字节。

我建议读取数据并将其添加到数据接收处理程序中的线程安全FIFO列表中,并在主线程中从列表中读取数据。

在帖子Serial port reading + Threads or something better?中查看我的解决方案

【讨论】:

  • 您好,感谢您的回复。我尝试使用您的想法并且它在一定程度上起作用,我实现了一个计时器来显示数据,但是它只显示我的第一个刻度的数据,然后当我尝试停止它时,应用程序冻结。我得到的十六进制看起来是正确的。
  • 当您进入计时器滴答处理程序时,在调用例程清空队列之前停止计时器。当队列为空且例程返回时,再次启用计时器。我这样做是为了确保不会过早调用计时器滴答事件。
  • 谢谢!通过将所有内容从队列中取出并将其放入另一个中间数组以防止死锁,然后使用 stringbuilder 显示数据,我能够使其顺利运行。进入下一步!
  • 太棒了!对于从微控制器接收数据的应用程序,我每 10 毫秒有一个计时器事件。串行端口设置为 9600 波特,队列永远不会变得非常大,但是我将一个结构体与接收到的字符而不是一次一个字符排队,这样可以更有效地出队。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-13
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
相关资源
最近更新 更多