Tweet

Introduction

A couple of weeks ago I got an Arduino Uno. Suffice to say I’m now a little bit obsessed with it.

I know nothing about electronics, but found the idea that I could write code to control electronic components absolutely fascinating!

I bought the Vilros Arduino Ultimate Starter Kit, which is awesome and had everything I needed to get started right away. It includes a great little guide book that steps you through some basic circuits (or sketches I guess they are called).

Of course, me being me, I couldn’t quite make it through the entire guide before I started going off on my own (note to self: go finish the last few samples!)

One of the tutorials uses a temperature sensor and some code that reads the temperature and outputs it to the serial communications port. As soon as I saw that I could write to the COM port, I knew I had to create something that could receive commands and output results, which I could then integrate with a C#.NET application. And hence this project began…

The Goal

The aim here was to expand on the temperature sample and have it output the current temperature to the COM port when asked to by receiving a “command” (again, through the COM port).

Arduino

Circuit

Overview

This was a really simple circuit to build. It just has a temperature sensor connected to positive and ground and a wire that takes the output to the Arduino analog in port.

Components

Amount Part Type Properties 1 Arduino Uno (Rev3) type Arduino UNO (Rev3) 1 LM35 Temperature Sensor package TO92 [THT]; type LM35

This list of components was generated using the Fritzing application.

The Finished Circuit

Here is a photo of my finished circuit:

Breadboard View

I used the Fritzing application to document this. This was my first attempt at using the tool, but it was super simple and took less than 5 minutes. It hopefully gives you a simple enough view in case you want to follow along.

Schematic View

Code

I used the sample code included in the Arduino IDE as a starting point for this (Examples > 04.Communication > SerialEvent).

A basic Arduino program will have a setup() method that gets run when the board is powered up and a loop() method that is repeatedly called, this is where you would generally write code to check for input changes (check for button presses, read sensor values, etc.…).

Before the setup() method we declare a variable to contain the command string received through the serial port. We also define a constant pin number that we connected the temperature sensor to on the Arduino board (I used analog 0), just for easy reading in the code.

String cmdString; const int tempPin = 0;

The setup method starts the reading on the serial port, using a baud rate of 9600. Later on we will create C# code to communicate with this at the same rate.

It also defines the cmString variable to allow 200 characters.

void setup() { // initialize serial: Serial.begin(9600); // reserve 200 bytes for the input command string: cmdString.reserve(200); }

In this example we do not need to use the loop() method. Rather we are going to subscribe to the serial event using the serialEvent() method. This will be called by the Arduino every time data is received by the serial port.

void loop() { }

void serialEvent() { cmdString = Serial.readString(); if(cmdString == "cmdGetTempF") { float temperatureVoltage = getVoltage(tempPin); float temperatureF = getTemperatureDegreesF(temperatureVoltage); Serial.println(cmdString + " result:"); Serial.println(temperatureF); } else if (cmdString == "cmdGetTempC") { float temperatureVoltage = getVoltage(tempPin); float temperatureC = getTemperatureDegreesC(temperatureVoltage); Serial.println(cmdString + " result:"); Serial.println(temperatureC); } else{ Serial.println(cmdString + " unsupported command."); } }

We use the Serial.readString() mthod to read data from the serial port. We parse this to see if it is a recognized command. For now I’ve just setup “cmdGetTempF” and “cmdGetTempF” to read the Fahrenheit or Centigrade temperature from the sensor. This could of course be expanded to add extra sensors, inputs or outputs to the Arduino and allow control of them through additional commands.

We can see this working by connecting the Arduino and uploaded the code. Initially nothing happens, but we can use the Serial Monitor IDE window to send and receive serial data.

So if we enter “cmdGetTempF” and send it to the Arduino then our SerialEvent code kicks in, works out what to do based on the command text and then outputs a result, which we can see in the serial window.

C# Application

I was already pretty (ok, very) excited about this. But then I wanted to try to send and receive this serial data through a C# application. For simplicity I chose a windows forms application.

I created a simple application that allows you to send text to the serial port and then reads the result out and displays it:

I achieved this by using the System.IO.Ports.SerialPort class.

The code below opens the port named “COM3” (which is where my Arduino is connected via the USB cable) and specifies 9600 as the baud rate.

It sets an event handler to be run when data is receiverecieved on that serial port.

It then sends some text to the Arduino by writing to the serial port.

private const int _portBaudRate = 9600; private const string _portName = "COM3"; private void cmdSendCommand_Click(object sender, System.EventArgs e) { var serialPort = new SerialPort(_portName, _portBaudRate); serialPort.Open(); serialPort.DataReceived += serialPort_DataReceived; serialPort.Write(txtCommand.Text); } void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string indata = sp.ReadLine(); if (indata.Contains("result")) { indata = indata + Environment.NewLine + sp.ReadLine(); } txtResponse.Invoke(this._OutputResultDelegate, new Object[] { indata }); sp.Close(); }

When data is returned by the Arduino, it is simply read line by line. If the text contains “result” (in my case the Arduino code outputs this when it successfully runs a command), then I read the next line which gives me the result (in this case the temperature) and display that in a text box on the form.

Note that I had to use the .Invoke method passing a delegate in order to output to the form UI thread-safely.

public delegate void OutputResultDelegate(String myString); public OutputResultDelegate _OutputResultDelegate; private void frmCommandHub_Load(object sender, EventArgs e) { _OutputResultDelegate = new OutputResultDelegate(OutputResult); } public void OutputResult(String result) { txtResponse.AppendText(Environment.NewLine + result); }

Chart

This was neat, and achieved my learning goal of figuring out how to communicate with Arduino with C#. But I decided to expand a little further by continually sending commands to Arduino (within a Timer) and displaying the temperature graphically.

For this example I used a Telerik RadRadialGauge control:

The code below shows a very similar setup as before, but this time a timer causes a write to the serial port every second and the resulting temperature is set in the chart.

public delegate void DisplayTempChartDelegate(float temperature); public DisplayTempChartDelegate _DisplayTempChart; private Timer _timer; private void frmCommandHub_Load(object sender, EventArgs e) { _DisplayTempChart = new DisplayTempChartDelegate(DisplayTempChart); } private void cmdStartChart_Click(object sender, EventArgs e) { radRadialGaugeTemp.Visible = true; _timer = new Timer(); _timer.Interval = 1000; _timer.Tick += _timer_Tick; _timer.Start(); } void _timer_Tick(object sender, EventArgs e) { _timer.Stop(); var serialPortTempChart = new SerialPort(_portName, _portBaudRate); serialPortTempChart.Open(); serialPortTempChart.DataReceived += SerialPortTempChartOnDataReceived; serialPortTempChart.Write("cmdGetTempF"); } private void SerialPortTempChartOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs) { var result = ""; SerialPort sp = (SerialPort)sender; string indata = sp.ReadLine(); if (indata.Contains("result")) { result =sp.ReadLine(); } sp.Close(); var tempF = float.Parse(result.Replace("F", "")); radRadialGaugeTemp.Invoke(this._DisplayTempChart, new Object[] { tempF }); } public void DisplayTempChart(float temperature) { AnimatedPropertySetting setting = new AnimatedPropertySetting(RadRadialGaugeElement.ValueProperty, radRadialGaugeTemp.Value, temperature, 12, 40); setting.ApplyEasingType = RadEasingType.OutBounce; setting.ApplyValue(radRadialGaugeTemp.GaugeElement); lblTemp.Text = temperature.ToString() + " F"; _timer.Start(); }