0

So I'm creating a Windows Forms app that's gonna continously display updated sensor data from my Arduino microcontroller through serialport. I am also rather new to C# and even more so, Arduino. My issue is that when I try to display the updated sensor data through timers - the app crashes.

The arduino sends a string formatted like this 1;25 - where the first number 1 or 0, says whether or not the motion sensor has detected movement. The other number is the temperature.

class ArduinoComClass : SerialPort
{
    public string receivedData;
    private bool dataReady = false;
    public ArduinoComClass(string comport, int baudrate)
    {
        PortName = comport;
        BaudRate = baudrate;
        DataReceived += new SerialDataReceivedEventHandler(dataReceived);
        ReadTimeout = 2000;
        Open();
    }

    ~ArduinoComClass()
    {
        Close();
    }

    public void ConvertString(out string pirValue, out string tempValue)
    {
        string[] data = receivedData.Split(';');
        string string1 = data[0];
        if (string1 == "1")
        {
            pirValue = "Movement detected!";
        }
        else
        {
            pirValue = "No movement detected";
        }
        string string2 = data[1];
        tempValue = string2;
    }

    public bool DataReady
    {
        get
        {
            return dataReady;
        }
        set
        {
            dataReady = value;
        }
    }
    public void dataReceived(object sender, SerialDataReceivedEventArgs earg)
    {
        try
        {
            receivedData = ReadLine();
            dataReady = true;
        }
        // catch(TimeoutException e)
        catch (Exception e)
        {
            MessageBox.Show(e.Message);
            dataReady = false;
        }
    }
}

Now this is the code for the form I want to display the data in. It is very messed up due to me trying and trying different things and just kept on making it worse. I've tried tasks/threading but I get an error due to the fact that receivedData is in another thread.

    static private ArduinoComClass ArduinoCom = new ArduinoComClass("COM3", 9600);
    private string pirValue;
    private string tempValue;

    public Main()
    {
        InitializeComponent();
        pirValue = "";
        tempValue = "";
        tmrAlarm.Start();
    }

    private void ShowSensorInfo()
    {
        while (true)
        {
            if (ArduinoCom.DataReady)
            {
                ArduinoCom.ConvertString(out pirValue, out tempValue);
                txtShowTemp.Text = tempValue;
                if (pirValue == "Movement detected!")
                {
                    picPIR.BackColor = Color.Red;
                }
                else
                {
                    picPIR.BackColor = Color.Lime;
                }

                //if (SystemInformation.PowerStatus.PowerLineStatus) <- Ignore for now
                ArduinoCom.DataReady = false;
            }
        }
    }

    private async void tmrAlarm_Tick(object sender, EventArgs e)
    {
        try
        {
            Task myTask = Task.Run(() => ShowSensorInfo());
            await myTask;
            myTask.Wait(2000);
        }
        catch (Exception error)
        {
            Console.WriteLine(error.Message);
        }
    }

So in short - how can I in an easy and effective way make my program show this live data without having the app crash?

domin8
  • 61
  • 6
  • Threading is the answer. You can update the UI from another Thread, you just need to use Dispatch.Invoke. For more details, see http://stackoverflow.com/questions/9602567/how-to-update-ui-from-another-thread-running-in-another-class – dbugger Mar 13 '16 at 02:04
  • I'm trying to understand the code, however, I struggle to figure out how I'd infuse that into my code, I have done very little threading. – domin8 Mar 13 '16 at 03:13
  • Any reason for polling data by Timer? It seems that listening the DataReceived event and updating UI by Control.Invoke method (Form.Invoke method in this case) when it fires would be enough. – emoacht Mar 13 '16 at 07:40
  • The only reason I'm trying it by Timer is basically because that was the only solution I knew of. I haven't heard of Invoke before. However I will check it out and see if I can make something out of it. – domin8 Mar 13 '16 at 10:37
  • I see. Using Timer.Tick event is one way to update UI because it is fired in UI thread. On the other hand, You can update UI by Control.Invoke method even if it is called from event fired in non-UI thread. – emoacht Mar 13 '16 at 13:39

0 Answers0