简体   繁体   English

从C#到Arduino读写串口数据

[英]Writing and reading serial data from C# to Arduino

I have a .net app in Visual Studio that communicates with an Arduino Uno.我在 Visual Studio 中有一个 .net 应用程序,它与 Arduino Uno 通信。 The Uno is connected to a pressure sensor. Uno 连接到压力传感器。 I want to send a message from my .net app to the Arduino via serial, asking for pressure data.我想通过串口从我的 .net 应用程序向 Arduino 发送一条消息,询问压力数据。 Then I want the Arduino to respond with the latest data point, and send it via serial back to my .net app which then plots it and stores the data.然后我希望 Arduino 响应最新的数据点,并通过串行将其发送回我的 .net 应用程序,然后绘制它并存储数据。

I can send a stream of data continously from my Uno and the app registers the entire stream. But this creates significant lag.我可以从我的 Uno 连续发送 stream 的数据,应用程序会注册整个 stream。但这会产生明显的延迟。 I have also tried to use a timer to send the message to my Uno, but this only works if I use a threadsleep of at least 2500ms, which is way too much for my purpose.我还尝试使用计时器将消息发送到我的 Uno,但这仅在我使用至少 2500 毫秒的线程休眠时有效,这对我的目的来说太长了。

My problem is that I can not find a way to continuously send requests from the .net app.我的问题是我找不到从 .net 应用程序连续发送请求的方法。 I can, for example, add a button that sends the command to the Arduino and I get the correct respons.例如,我可以添加一个按钮,将命令发送到 Arduino,然后我得到正确的响应。 But I want to do this at a high frequency in a continuous manner.但我想以连续的方式高频地做这件事。

Here are the relevant parts of my code:以下是我的代码的相关部分:

public void Read() //Reads sensor values from Uno
{
    while (port.IsOpen)
    {
        try
        {
            if (port.BytesToRead > 0)
            {
                string message = port.ReadLine();
                this.SetText(message);
            }
        }
        catch (TimeoutException) { }
    }
}

    private void SetText(string text)
    {
        if (this.labelPressure.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] {text});
        }
        else
        {
            this.labelPressure.Text = text;

            chart1.ChartAreas["ChartArea1"].AxisX.LabelStyle.Enabled = false;
            chart1.Invoke((MethodInvoker)(() => chart1.Series["Pressure"].Points.AddXY(DateTime.Now.ToLongTimeString(), text)));

            if (chart1.Series[0].Points.Count > 20)
            {
                chart1.Series[0].Points.RemoveAt(0);
                chart1.ChartAreas[0].AxisX.Maximum = 0;
                chart1.ChartAreas[0].AxisX.Maximum = 20;
                chart1.ChartAreas[0].AxisY.Maximum = 10;
                chart1.ChartAreas[0].AxisY.Minimum = -90;
                chart1.ChartAreas[0].AxisY.Interval = 10;
            }
        }

    }

This part of the code works for reading the entire data stream. The message I would like to send to the Uno is这部分代码用于读取整个数据 stream。我想发送给 Uno 的消息是

           string d2 = "M";
           port.Write(d2);

But I have no idead how to continously and with high frequency send this message to my Uno and then recieve the answer.但我不知道如何持续、高频地向我的 Uno 发送此消息,然后收到答复。 Does anyone have a solution?有没有人有办法解决吗?

The best algorithm would be that, you open the connection, send the measuring request and wait for the answer and start from the beginning.最好的算法是,您打开连接,发送测量请求并等待答案并从头开始。

There is a DataReceived event, you can use that instead of continuously polling the data in a while loop.有一个DataReceived事件,您可以使用它而不是在 while 循环中连续轮询数据。

using System;
using System.IO.Ports;

class PortDataReceived
{
    public static void Main()
    {
        SerialPort mySerialPort = new SerialPort("COM1");

        mySerialPort.BaudRate = 9600;
        mySerialPort.Parity = Parity.None;
        mySerialPort.StopBits = StopBits.One;
        mySerialPort.DataBits = 8;
        mySerialPort.Handshake = Handshake.None;
        mySerialPort.RtsEnable = true;

        mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

        mySerialPort.Open();
        mySerialPort.Write("M"); // initiate the query
        
        Console.ReadKey();
        mySerialPort.Close();
    }

    private static void DataReceivedHandler(
                        object sender,
                        SerialDataReceivedEventArgs e)
    {
        var sp = (SerialPort)sender;
        var indata = sp.ReadLine();
        //process your message (here you refresh your controls in GUI app )
        /* process data on the GUI thread
        Application.Current.Dispatcher.Invoke(new Action(() => {
            this.labelPressure.Text = indata;
        }));
        */
        Console.WriteLine(indata);
        mySerialPort.Write("M"); // send message request again (it is a bit recursive solution, but maybe this is enough for your use case)
    }
}

Try this first in a command line solution, and if you are satisfied with the data frequency, you implement it in your solution (Delete the Console.* lines, uncomment the commented code and everything should work).首先在命令行解决方案中尝试此操作,如果您对数据频率感到满意,则在您的解决方案中实施它(删除 Console.* 行,取消注释注释代码,一切都应该有效)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM