我正在编写一个程序,它从serialPort读取每一秒数据并将其保存在文本文件中/在GUI上显示。阅读以按钮点击开始和结束。
我尝试了一些不同的计时器来解决这个问题,但每个计时器都会带来一些麻烦(见下文)。
我的试用:
serialPort1.ReadTimeout = 2000;
System.Timers.Timer:
private void timer1_Tick(object sender, EventArgs e)
{
if (!serialPort1.isOpen)
{
serialPort1.Open();
}
serialPort1.WriteLine("INFO"); //Send data command
string data = serialPort1.ReadLine();
serialPort.Close();
editData(data); //Method for GUI update and textfile log
}
可以使用timer1.Start()和timer1.Stop()轻松启动和停止。问题是,System.Timers.Timer在GUI Threard上运行并在调用serialPort.read和serialPort.Close()时冻结GUI。
BackgroundWorker的:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (backgroundWorker1.CancellationPending == false)
{
if (!serialPort1.isOpen)
{
serialPort1.Open();
}
serialPort1.WriteLine("INFO");
string data = serialPort1.ReadLine();
serialPort.Close();
Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
}
}
异步运行。我需要每秒运行一次程序。
System.Timers.Timer调用Backgroundworker:
private void timer1_Tick(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (!serialPort1.isOpen)
{
serialPort1.Open();
}
serialPort1.WriteLine("INFO");
string data = serialPort1.ReadLine();
serialPort.Close();
Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
}
这样可以正常工作,直到数据读取过程花费更长时间或发生serialPort.readTimeout。 Backgroundworker只能运行一次。所以我认为这不是一个选择。
System.Threading.Timers:
System.Threading.Timer timer;
timer = new System.Threading.Timer(_ => readSerialPort(), null, 0, 950);
private void readSerialPort()
{
if (!serialPort1.isOpen)
{
serialPort1.Open();
}
serialPort1.WriteLine("INFO");
string data = serialPort1.ReadLine();
serialPort.Close();
Invoke((MethodInvoker)(() => editData(data)); //Method for GUI update and textfile log
}
这很好但问题是,我无法停止并重新开始阅读。
有谁知道在这种情况下我应该使用哪个计时器?
答案 0 :(得分:1)
关于System.Threading.Timer
var timer = new System.Threading.Timer(cb, null, 1000, 1000); // init
timer.Change(Timeout.Infinite, Timeout.Infinite); // stop
timer.Change(0, 1000); // start
P.S。别忘了处理计时器
答案 1 :(得分:1)
您可以使用线程实现此逻辑。元代码如下:
var stopEvent = new ManualResetEvent(false);
var thread = new Thread(() => {
if (!serialPort1.isOpen)
{
serialPort1.Open();
}
try
{
while (!stopEvent.WaitOne(0))
{
try
{
serialPort1.WriteLine("INFO");
string data = serialPort1.ReadLine();
Invoke((MethodInvoker)(() => editData(data)));
}
catch (Exception)
{
// Handle exception, e.g. a reading timeout
}
stopEvent.WaitOne(1000); //Thread.Sleep(1000);
}
} finally
{
serialPort.Close();
}
});
thread.Start();
//call it to stop the loop.
stopEvent.Set();
}
您可以实现更复杂的逻辑,例如停止和恢复读数。只需使用更多活动。如果您不熟悉事件,可以使用布尔变量但定义它们是volatile
。