C# C-后台工作人员通过串行通信不断从Arduino获取数据
我有一个C应用程序,它从Arduino获取6个变量的值。最初我使用了一个计时器,它每100毫秒调用一次读取函数,但它挂起了我的UI,响应有点沉重。我想使用一个backgroundworker来连续读取这些变量。我将这些读取调用放在DoWork方法中,将值放在C中的变量中,并将它们分配到标签或其他东西中。但它不起作用。对不起,我的英语不好C# C-后台工作人员通过串行通信不断从Arduino获取数据,c#,serial-port,arduino,backgroundworker,C#,Serial Port,Arduino,Backgroundworker,我有一个C应用程序,它从Arduino获取6个变量的值。最初我使用了一个计时器,它每100毫秒调用一次读取函数,但它挂起了我的UI,响应有点沉重。我想使用一个backgroundworker来连续读取这些变量。我将这些读取调用放在DoWork方法中,将值放在C中的变量中,并将它们分配到标签或其他东西中。但它不起作用。对不起,我的英语不好 namespace testtemp { public partial class tempreaderform : Form {
namespace testtemp
{
public partial class tempreaderform : Form
{
public tempreaderform()
{
InitializeComponent();
}
communicator comport = new communicator();
Boolean portConnection = false;
String red_light1;
private void button1_Click(object sender, EventArgs e)
{
if (comport.connect(57600, "I'M ARDUINO", 4, 8, 16))
{
label1.Text = "Connection Successful - Connected to "+comport.port;
portConnection = true;
backgroundWorker1.RunWorkerAsync(); // I am not sure if here I should start the backgroundworker.
}
else
{
label1.Text = "Not connected . . . ";
portConnection = false;
}
}
private void groupBox1_Paint(object sender, PaintEventArgs e)
{
Graphics ellipse1 = groupBox1.CreateGraphics();
Brush red_on = new SolidBrush(Color.Red);
Brush red_off = new SolidBrush(Color.DarkRed);
label2.Text = "Red : " + red_light1; //Here is a label which I want to show "1" if "red_light1" is "1" and "0" if "red_light1" is "0"
if (red_light1 == "1") ellipse1.FillEllipse(red_on, 250, 133, 24, 24);
else ellipse1.FillEllipse(red_off, 250, 133, 24, 24); // Here is what I really want to do (the label.Text part was only to see the value) I want to color a ellipse depending on "red_light1" value.
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
red_light1 = comport.message(4, 8, 32);
}
}
}
}
}
注意:我在DoWork方法中尝试了这个label1.Text=red_light1,但它说我不能给在另一个线程中创建的变量赋值,类似这样的情况。问题是backgroundworker使用另一个线程,而您正试图在UI线程中使用。信息在那里没有被传达 有三种选择: 要使用RunWorkerCompleted事件:必须使用计时器每X毫秒运行一次backgroundworker
private void timer1_Tick(object sender, EventArgs e) {
this.backgroundworker.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
e.Result = comport.message(4, 8, 32);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
label2.Text = e.Result.ToString();
}
使用BeginInvoke设置文本
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
this.BeginInvoke((Action)(() => { label2.Text = comport.message(4, 8, 32); });
// add some delay here as well...
}
}
使用Task而不是backgroundworker,并在计时器中调用它
private void timer1_Tick(object sender, EventArgs e) {
Task.Run(() => {
this.BeginInvoke((Action)(() => { label2.Text = comport.message(4, 8, 32); });
});
}
您可以使用ReportProgress事件: 将WorkerReportsProgress设置为true 编写事件处理程序:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
String mytext = e.UserState as String;
myLabel.Text = mytext;
}
调用dowork中的函数
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bgw = sender as BackgroundWorker;
String receivedtext;
while (true)
{
myreceivedtext = comport.message(4, 8, 32);
bgw.ReportProgress(0, myreceivedtext);
System.Threading.Thread.Sleep(100);
}
}
你把背景工作放在另一个线程中了吗?我不确定我是否理解你。我第一次这么做。我相信我放在DoWork方法中的代码将在另一个线程中自动工作。这个while循环将永远不会结束,因此它将永远卡在那里。请看这里:。非常感谢您的解释。我会选择第一个选项,但我有6个或更多的变量。我应该这样做6次,因此将是6个线程。我还尝试了你的2选项,我的电脑几乎爆炸了,只是开玩笑,但我必须切断电源。我不知道是什么问题。我认为第三种选择也会起到同样的作用。请给我建议。我会选择第三个选项,因为它很轻。2号的问题是我猜你没有添加任何延迟。请看代码中的注释,它一直在影响处理器。我在DoWork方法中添加了延迟,但我不确定它是否正确。虽然为true{this.BeginInvokeAction=>{label2.Text=comport.message4,8,32;};Thread.Sleep200;}但是通过这种方式,UI比没有backgroundworker时慢。我将延迟时间提高到5亿秒,但通过这种方式,UI的工作方式与没有backgroundworker时相同。我需要更快的读数,比如说200毫秒就足够了。但是,如果线程延迟200ms会导致UI响应沉重,请尝试使用第3种方法。毕竟,不停地做后台工作可能是个坏主意。