串行通信在后台运行时(如浏览硬盘)会得到错误的答案
本文关键字:错误 答案 硬盘 浏览 通信 后台 运行时 | 更新日期: 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)
}