1

我在串行请求方面遇到了一些大麻烦。

我想要的描述:

  • 建立串行连接,向 6 个温度传感器一个接一个发送串行请求(每 0.5 秒循环一次)

  • 问题和答案目标存储在 List 数组中

  • 每个请求都在单独的线程中启动,因此在程序等待传感器硬件回答时 gui 不会出错

我的问题:

连接和请求工作正常,但如果我在本地硬盘驱动器上浏览数据,来自传感器单元的答案会被破坏(负代数符号或来自其他传感器的值或简单的错误值)。这是怎么发生的,或者我该如何解决?

我猜问题可能出在哪里:

  • 在类 SerialCommunication 的私有 void ReceiveThread() 中

这是我的代码:


类通信数组:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Hardwarecommunication
{
    public class CommunicationArray
    {
        public string request { get; set; }
        public object myObject { get; set; }
        public string objectType { get; set; }
    }
}

类串行通信

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using System.IO.Ports;
using System.Windows.Forms;

namespace Hardwarecommunication
{
    class SerialCommunication
    {
        Thread t2;
        Thread t;
        private SerialPort serialPort = new SerialPort("COM2", 115200, Parity.Even, 8, StopBits.One);
        string serialAnswer = "";
        private volatile bool _shouldStop;
        private int counter;

        List<CommunicationArray> ar = new List<CommunicationArray>();

        object[] o = new object[3];


        public void addListener(string request, object myObject, string objectType)
        {
            CommunicationArray sa = new CommunicationArray();

            sa.request = request;
            sa.myObject = myObject;
            sa.objectType = objectType;
            ar.Add(sa);
        }

        public void startListen()
        {
            t2 = new Thread(() => writeSerialPortThread());
            t2.Start();
        }



        public void startSerialPort2()
        {

            try
            {
                serialPort.Open();
                //MessageBox.Show("Connection opend!");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
        }

        public void stopSerialPort2()
        {
            try
            {
                if (serialPort.IsOpen == true)
                    // Connection  closed
                    serialPort.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


        private void writeSerialPortThread()
        {
            string request = "";

            for (int i = 0; i < ar.Count(); i++)
            {
                request = ar[i].request;
                //request = ((object[])ar[0])[0].ToString();
                //if (!t.IsAlive)
                //{
                try
                {
                    t = new Thread(ReceiveThread);
                    _shouldStop = false;
                    //MessageBox.Show("start thread");
                    t.Start();
                    serialPort.Write(request);
                    Thread.Sleep(50);
                    _shouldStop = true;
                    t.Join();
                }
                catch
                {
                }
                Label tmpLabelObject = (Label)ar[i].myObject;
                serialAnswer = serialAnswer.Replace("=", "");
                if (tmpLabelObject.InvokeRequired)
                {
                    MethodInvoker UpdateLabel = delegate
                    {
                        tmpLabelObject.Text = serialAnswer;
                    };
                    try
                    {
                        tmpLabelObject.Invoke(UpdateLabel);
                    }
                    catch
                    {
                    }
                }
            }
        }

        private void ReceiveThread()
        {
            //MessageBox.Show("in thread");
            while (!_shouldStop)
            {
                serialAnswer = "";
                try           
                {
                    //MessageBox.Show("in thread");
                    serialAnswer = serialPort.ReadTo("\r");
                    if (serialAnswer != "")
                    {
                    }
                    return;
                }
                catch (TimeoutException) { }
            }
        }
    }
}

Class Form1 //建立连接并启动Sensor请求

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;

namespace Hardwarecommunication
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private SerialCommunication serialCommunication1 = new SerialCommunication();

        private void Form1_Load(object sender, EventArgs e)
        {
            //start up serial connection
            serialCommunication1.startSerialPort2();
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            timerRecord.Enabled = true;
            if (this.buttonStart.Text == "Start")
                this.buttonStart.Text = "Stop";
            else
                this.buttonStart.Text = "Start";            
        }

        private void timerRecord_Tick(object sender, EventArgs e)
        {
            if (this.buttonStart.Text == "Stop")
            {
                this.serialCommunication1.startListen();
            }
        }

        private void buttonFillRequestArray_Click(object sender, EventArgs e)
        {         
            this.serialCommunication1.addListener("$0BR00\r" + "\r", this.labelResult0, "label0"); //request to the hardware
            this.serialCommunication1.addListener("$0BR01\r" + "\r", this.labelResult1, "label1");
            this.serialCommunication1.addListener("$01R00\r" + "\r", this.labelResult2, "label2");
            this.serialCommunication1.addListener("$01R01\r" + "\r", this.labelResult3, "label3");
            this.serialCommunication1.addListener("$01R02\r" + "\r", this.labelResult4, "label4");          
        }
    }
}

我会很高兴任何尝试解决这个问题。我也可以将解决方案上传为 .zip,但您根本无法对其进行测试,因为您没有传感器硬件。

4

1 回答 1

1

注意:serialPort.Write(string)是一个非阻塞存储到输出缓冲区。

这意味着以下内容不能保证您在停止侦听响应之前已经完成了请求的编写:

serialPort.Write(request);
Thread.Sleep(50);
_shouldStop = true;

您可以添加:

while( serialPort.BytesToWrite > 0 ) Thread.Sleep(1); // force blocking

但这是不明智的。

我想知道的一件事。这里只有一个串口。当您可以使用单个线程管理整个串行端口交互时,为什么还要使用许多不同的线程?(或者更糟糕的是,1 个线程用于输入 1 个线程用于输出)

对我来说,将请求存储到某种队列中然后将它们一次剥离一个以在单个线程中处理更有意义。响应可以类似地排队或作为事件返回给调用者。

编辑:如果您不介意一次读/写一个周期,您可以尝试:

string response;
lock(serialPort) {
    // serialPort.DiscardInBuffer(); // only if garbage in buffer.
    serialPort.Write(request);
    response = serialPort.ReadTo("\r"); // this call will block till \r is read.
                                        // be sure \r ends response (only 1)
}
于 2013-07-16T18:46:55.270 回答