Read Uno Serial via C# Program

Sorry if this is a little basic folks, I’ve only had my Uno a week.

What I’m trying to do is just write a simple interface in C# to read Serial output from the Uno and display it live on the PC.

My Uno’s sketch is very simple; it looks like this-

void setup()
{
   pinMode(A0, INPUT);
   Serial.begin(115200);
}

void loop()
{
   Serial.println(map(analogRead(A0),0,1023,0,5000),DEC);
   delay(200);
}

I have a single axis accelerometer which reads anything from 2000 to 3000 (2 to 3 V) depending on which way I tip it, and farther towards 0 and 5 V if I shake it. When I use the code from http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.aspx, the values come through fine on the command prompt (they read 2000 to 3000).

When I tried to create my own display in a Windows Form, though, my chart doesn’t display and I keep getting TimeOut errors on the ReadLine command shown in the code below. Before you read it, yes I know that there are some silly things in there but I want to just get a proof of concept working before I clean it up.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Windows.Forms.DataVisualization.Charting;

namespace ArduinoCommsForm
{
    public partial class DisplayForm : Form
    {
        static SerialPort Arduino = new SerialPort();

        public DisplayForm()
        {
            InitializeComponent();

            DisplayChart.Series.RemoveAt(0);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {

            string message; string tempVal;

            Arduino.PortName = "COM3";
            Arduino.BaudRate = 115200;
            Arduino.Parity = Parity.None;
            Arduino.DataBits = 8;
            Arduino.StopBits = StopBits.One;
            Arduino.Handshake = Handshake.None;

            Arduino.ReadTimeout = 500;

            Series ChartBar = DisplayChart.Series.Add("Voltage");
            ChartBar.Points.AddXY(1, 1);
            
            Arduino.Open();

            for (int i = 0; i < 10000; i++)
            {
                tempVal = Arduino.ReadLine();
                if (tempVal.Length >= 6)
                {
                    message = tempVal.Substring(0, 4);
                    Single VoltValue = Convert.ToSingle(message) / 1000;
                    //ChartBar.Points.RemoveAt(0);
                    //ChartBar.Points.AddXY(1, Convert.ToDouble(VoltValue));
                    //DisplayChart.Show();
                    textBox1.Text = Convert.ToString(VoltValue);
                }
                Arduino.DiscardInBuffer();
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            Arduino.Close();
        }
    }
}

Anyone know what I’m doing wrong?

I have C# code that communicates quite reliably with my Arduino. I use:

            port = new System.IO.Ports.SerialPort(components);
            port.PortName = comPort.SelectedItem.ToString();
            port.BaudRate = Int32.Parse(baudRate.SelectedItem.ToString());
            port.DtrEnable = true;
            port.ReadTimeout = 5000;
            port.WriteTimeout = 500;
            port.Open();

I think your read timeout value is too low, considering that the Arduino sits on its butt for 40% of that time.

Changing the ReadTimeout to 5000 does seem to get rid of my timeout errors, but I'm not sure why. With the Sketch I have in the Uno, I should be sending Serial data at 5 Hz (which I confirmed with MSDN Terminal code linked to above).

Even when I have no timeout errors, my Form still doesn't show the updates. I think I'll try the Threading code used by the MSDN folks....

I think I'll try the Threading code used by the MSDN folks....

Only if you want it to actually work.

Well I rearranged my code to this (includes Threading now)-

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Windows.Forms.DataVisualization.Charting;
using System.Threading;

namespace ArduinoCommsForm
{
    public partial class DisplayForm : Form
    {
        static SerialPort Arduino = new SerialPort();

        public DisplayForm()
        {
            InitializeComponent();

            DisplayChart.Series.RemoveAt(0);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            Arduino.PortName = "COM3";
            Arduino.BaudRate = 115200;
            Arduino.Parity = Parity.None;
            Arduino.DataBits = 8;
            Arduino.StopBits = StopBits.One;
            Arduino.Handshake = Handshake.None;
            Arduino.DtrEnable = true;

            Arduino.ReadTimeout = 5000;

            Series ChartBar = DisplayChart.Series.Add("Voltage");
            ChartBar.Points.AddXY(1, 1);

            Thread readThread = new Thread(() => ReadAndUpdate(ChartBar, DisplayChart, textBox1));

            Arduino.Open();

            readThread.Start();
        }

        public static void ReadAndUpdate(Series ChartVal, Chart DisplayChart, TextBox box)
        {
            while (true)
            {
                try
                {
                    Arduino.Open();
                }
                catch
                {
                    break;
                }

                string message; string tempVal;

                tempVal = Arduino.ReadLine();
                if (tempVal.Length >= 6)
                {
                    message = tempVal.Substring(0, 4);
                    Single VoltValue = Convert.ToSingle(message) / 1000;
                    ChartVal.Points.RemoveAt(0);
                    ChartVal.Points.AddXY(1, Convert.ToDouble(VoltValue));
                    DisplayChart.Show();
                    box.Text = Convert.ToString(VoltValue);
                }
                Arduino.DiscardInBuffer();
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            Arduino.Close();
        }
    }
}

The form doesn't lock up anymore, I can freely move it around while my thread is running; unfortunately, it also doesn't update (neither the box or the chart). At this point, its more of a C# question than an Arduino question but just figured I'd follow up here.

The port should be opened by the main thread, not the IO thread. The data should be read from the serial port in the try block.

The IO thread can not manipulate the form except through an Invoke method.

If you PM me, with an e-mail address, I'll send you the C# application that I have, and you can adapt it to your needs - threads, background workers, delegates, and all. Best of all, it works.

For those that happen upon this thread, I’ve attached the code that completed this issue.

This is 90% PaulS’ code, I have simply modified it to use a single textbox and bar chart for display. From this point, the end user should be able to modify the visual portion any way they like (i.e. change Volts to G’s/degrees/etc or change the bar chart to any other style the Chart control can support).

Sensor Comms.zip (81.8 KB)