C# C-后台工作人员通过串行通信不断从Arduino获取数据

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 {

我有一个C应用程序,它从Arduino获取6个变量的值。最初我使用了一个计时器,它每100毫秒调用一次读取函数,但它挂起了我的UI,响应有点沉重。我想使用一个backgroundworker来连续读取这些变量。我将这些读取调用放在DoWork方法中,将值放在C中的变量中,并将它们分配到标签或其他东西中。但它不起作用。对不起,我的英语不好

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种方法。毕竟,不停地做后台工作可能是个坏主意。