串行通信在后台运行时(如浏览硬盘)会得到错误的答案

本文关键字:错误 答案 硬盘 浏览 通信 后台 运行时 | 更新日期: 2023-09-27 18:22:41

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

我想要的描述:

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

  • 问答目的地存储在列表阵列中

  • 每个请求都在一个单独的线程中启动,这样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; }
    }
}

Class串行通信

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//以建立连接并启动传感器请求

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,但你根本无法测试它,因为你没有传感器硬件。

串行通信在后台运行时(如浏览硬盘)会得到错误的答案

注意: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)
}