Serial Communication (C# Windows Forms) - c#

Okay so I'm trying to do a two-way communication from C# to Arduino (using FTDI232) and viceversa, from Arduino to C#.
Here's the code:
public partial class Form1 : Form
{
public SerialPort myPort;
private DateTime dateTime;
private string inData;
const string com = "COM8";
public Form1()
{
InitializeComponent();
}
private void start_btn_Click(object sender, EventArgs e) // TURN ON LED
{
myPort = new SerialPort();
myPort.BaudRate = 9600;
myPort.PortName = com;
try
{
myPort.Open();
myPort.WriteLine("A");
myPort.Close();
error_tb.Text = "";
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Errore");
}
}
private void stop_btn_Click(object sender, EventArgs e) // TURN OFF LED
{
myPort = new SerialPort();
myPort.BaudRate = 9600;
myPort.PortName = com;
try
{
myPort.Open();
myPort.WriteLine("B");
myPort.Close();
error_tb.Text = "";
}
catch (Exception exc2)
{
MessageBox.Show(exc2.Message, "Error");
}
}
void MyPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
inData = myPort.ReadLine();
this.Invoke(new EventHandler(displayData_event));
}
private void displayData_event(object sender, EventArgs e)
{
dateTime = DateTime.Now;
string time = dateTime.Hour + ":" + dateTime.Minute + ":" + dateTime.Second;
values_tb.Text = time + "\t\t\t\t\t" + inData;
}
private void Form1_Load(object sender, EventArgs e) // PRESS PHYSICAL BUTTON TO SEND DATA
{
myPort = new SerialPort();
myPort.BaudRate = 9600;
myPort.PortName = com;
myPort.Parity = Parity.None;
myPort.DataBits = 8;
myPort.StopBits = StopBits.One;
myPort.DataReceived += MyPort_DataReceived;
try
{
myPort.Open();
values_tb.Text = "";
}
catch (Exception exc3)
{
MessageBox.Show(exc3.Message, "Error");
}
}
private void exit_btn_Click(object sender, EventArgs e) // Exit from Application
{
Application.Exit();
}
private void button2_Click(object sender, EventArgs e)
{
try
{
myPort.Close();
}
catch (Exception exc4)
{
MessageBox.Show(exc4.Message, "Error");
}
}
}
I have three problems. One is when I want to close the application, I want the Serial Communication to turn off, because I made it automatically open using Form1_Load, as soon as you start the debug, it also opens Serial Communication, and it remains on, but I don't want to use a button that I have to click first to close the application. I need to close Serial Communication automatically after I close the application.
The second problem is with the Serial Port that denies the communication, what I mean is that I need to switch from Receiving Data to Sending Data. Here's a picture of what it looks like: Application Image
The the third problem is the LED one. Well its similar to the second one, but this time when I click the button OFF, I want it to switch back to Receiving Data. Here's the picture:
Application Image 2
EDIT : This code is only temporary. I needed it to turn off the Serial Communication
private void button2_Click(object sender, EventArgs e)
{
try
{
myPort.Close();
}
catch (Exception exc4)
{
MessageBox.Show(exc4.Message, "Error");
}
}

You are initializing and opening the port many times. This is not allowed. Use a single initialization and keep the member. This makes the code much smoother, too.
public partial class Form1 : Form
{
public SerialPort myPort;
private DateTime dateTime;
const string com = "COM8";
public Form1()
{
InitializeComponent();
}
private void start_btn_Click(object sender, EventArgs e) // TURN ON LED
{
try
{
myPort.WriteLine("A");
error_tb.Text = "";
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Errore");
}
}
private void stop_btn_Click(object sender, EventArgs e) // TURN OFF LED
{
try
{
myPort.WriteLine("B");
error_tb.Text = "";
}
catch (Exception exc2)
{
MessageBox.Show(exc2.Message, "Error");
}
}
void MyPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var inData = myPort.ReadLine(); // Use local variable
Invoke(new Action<string>(displayData_event), inData);
}
private void displayData_event(string data)
{
dateTime = DateTime.Now;
string time = dateTime.Hour + ":" + dateTime.Minute + ":" + dateTime.Second;
values_tb.Text = time + "\t\t\t\t\t" + data;
}
private void Form1_Load(object sender, EventArgs e) // PRESS PHYSICAL BUTTON TO SEND DATA
{
myPort = new SerialPort();
myPort.BaudRate = 9600;
myPort.PortName = com;
myPort.Parity = Parity.None;
myPort.DataBits = 8;
myPort.StopBits = StopBits.One;
myPort.DataReceived += MyPort_DataReceived;
try
{
myPort.Open();
values_tb.Text = "";
}
catch (Exception exc3)
{
MessageBox.Show(exc3.Message, "Error");
}
}
private void exit_btn_Click(object sender, EventArgs e) // Exit from Application
{
Application.Exit();
}
private void button2_Click(object sender, EventArgs e)
{
try
{
myPort.Close();
myPort = null;
}
catch (Exception exc4)
{
MessageBox.Show(exc4.Message, "Error");
}
}
}
I think I also fixed your event handling. One handler that gets the data and then forwards the received text is enough. You would also not really require the exception handling around WriteLine now, since that cannot really fail.

Related

How to read specific characters from RS232 serial port data

I am trying to retrieve weight data from a weight indicator which sends data through the RS232 com port ( Converted through USB)
following is the application I designed to receive data
enter image description here
the problem is it shows all the data which is sent from the indicator but the real weight reading is 15,000.
How can I achieve this?
Thank you
Data sheet of the indicator is as follows
Code is as follows
namespace Weight_Test
{
public partial class Form1 : Form
{
string dataIN;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
cbComPort.Items.AddRange(ports);
btnOpen.Enabled = true;
btnClose.Enabled = false;
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
dataIN = serialPort1.ReadExisting();
this.Invoke(new EventHandler(ShowData));
}
private void ShowData(object sender, EventArgs e)
{
txtWeight.Text = dataIN;
}
private void btnOpen_Click(object sender, EventArgs e)
{
try
{
serialPort1.PortName = cbComPort.Text;
serialPort1.BaudRate = Convert.ToInt32(9600);
serialPort1.DataBits = Convert.ToInt32(8);
serialPort1.StopBits = (StopBits)Enum.Parse(typeof(StopBits), "One");
serialPort1.Parity = (Parity)Enum.Parse(typeof(Parity), "None");
serialPort1.Open();
btnOpen.Enabled = false;
btnClose.Enabled = true;
}
catch (Exception err)
{
MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
btnOpen.Enabled = true;
btnClose.Enabled = false;
}
}
private void btnClose_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
btnOpen.Enabled = true;
btnClose.Enabled = false;
}
}
}
}
It all seems to work properly. All you need is processing of received data.
You said that your result should be 15,000.
Depends on what sensor you use, it can supply specified resolution, accuracy. Please edit your post and give us some information from datasheet about sending data.
Since you got "+01500001F🥹", it looks like you have 15,000.01, which very is good, but of course I can't be sure.
All you have to do is to process these data. If you have it in string format, you should use Substring method to get rid of decimal places.
For example, with:
string receivedText = DataIN.Substring(0,7);
You'll get "+015000", which you can easily convert to Int32 value, using:
int receivedValue = Convert.ToInt32(receivedText);
And you'll finally get your 15000 as integer.

C# - Change format of Data received from Serial Port

I am making a C# form application that receives data from an instrument communicating at Baud Rate 2400, parity None, 8 bit data, 1 stop bit.
The data is coming in a continuous string line in the form [000000][000000][000000]. For example if during a procedure the reading on the instrument is varying like 0.50,0.49,0.72,0.61,0.48 then the string of received data would be [000050][000049][000072][000061][000048], which is how it is currently being displayed in the textbox.
I need to display the Maximum value reached during a procedure into the textbox and in the correct format, like in this case it should be 0.72. I am at a loss about what would be the code for that.
Below is my current code for serial port communication.
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void Main_Load(object sender, EventArgs e)
{
}
//this is the button to open port.
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
button2.Enabled = true;
try
{
serialPort1.PortName = comboBox1.Text;
serialPort1.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
//Event handler for data received.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Regex rx = new Regex(#"\[(\d+)\]");
double.TryParse(richTextBox2.Text, out double max);
foreach (Match match in rx.Matches(indata))
{
double val = int.Parse(match.Groups[1].Value) / 100.0;
if (val > max)
max = val;
}
richTextBox2.Text = max.ToString();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
//this is the button to close port
private void button2_Click(object sender, EventArgs e)
{
button1.Enabled = true;
button2.Enabled = false;
try
{
serialPort1.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void button3_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.DataReceived += DataReceivedHandler;
}
else
{
MessageBox.Show("Error : Port needs to be open or wrong port selected!");
}
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
if (serialPort1.IsOpen)
serialPort1.Close();
}
private void button4_Click(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
comboBox1.Items.AddRange(ports);
comboBox1.SelectedIndex = 0;
button2.Enabled = false;
}
So you want to process data every time there is data to process right?
If you are using the "System.IO.Ports", and your serialPort1 is of the type SerialPort, you have the "DataReceived" event available. So after you instantiate the serialPort1 you can:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
button2.Enabled = true;
try
{
//check and set the settings of your device
serialPort1 = new SerialPort
{
PortName = comboBox1.Text,
BaudRate = 2400,
Parity = Parity.None,
StopBits = StopBits.Odd,
DataBits = 8,
Handshake = Handshake.None,
RtsEnable = true
};
serialPort1.DataReceived += DataReceivedHandler;
serialPort1.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Then you just need to declare the event handler, something like this:
private void DataReceivedHandler(object sender,SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Regex rx = new Regex(#"\[(\d+)\]");
double.TryParse(textBox13.Text, out double max);
foreach (Match match in rx.Matches(indata))
{
double val = int.Parse(match.Groups[1].Value) / 100.0;
if (val > max)
max = val;
}
textBox13.Text = max .ToString();
}
This will compare the values received and the current value in the textbox.
If I understand you're formatting requirement correctly you basically want to remove zeros at the front from each of the numbers and then compare them to find the max value and display them in the format of x.xx If that's the case create a separate method to handle it like this:
private decimal GetMaxReading(string rawReadingData)
{
decimal maxReading = 0;
var readings = rawReadingData.Split('[',).ToList();
foreach (var reading in readings)
{
var readingString = reading.TrimStart('0')
.TrimEnd(']');
var isInt = int.TryParse(readingString, out int readingValue);
var value = isInt ? (decimal)readingValue / 100 : 0;
maxReading = value > maxReading ? value : maxReading;
}
return maxReading;
}

Scoreboard data transfer Serial Port c#

There's some outdated software that's used to control the scoreboard at my local athletics track and I've been tasked with creating a new advanced one. However, I cannot seem to get the scoreboard to do what I ask it to do.
I've installed the original software to the my laptop and it works fine, however, when I run my test software that sends data to the board through the serial port, it isn't doing what I want.
I have the "Scoreboard Data Protocol" supplied by the manufacturer and I've been following this. I will supply the code to my test program that I've been using to see if I can get it to work and I will also supply the Data Protocol.
In the text box, I type 010D0201SPAIN and 003C630 and send it to the board and this doesn't work.
public partial class Form1 : Form
{
private SerialPort m_port;
public Form1()
{
InitializeComponent();
m_list.Items.AddRange(SerialPort.GetPortNames()); // Adds ports to combobox
m_port = new SerialPort();
m_port.BaudRate = 9600;
m_port.DataBits = 8;
m_port.Parity = Parity.Even;
m_port.StopBits = StopBits.One;
//m_port.Handshake = Handshake.None;
m_port.Encoding = new ASCIIEncoding();
m_port.RtsEnable = true;
m_port.DtrEnable = true;
m_port.ReceivedBytesThreshold = 1;
m_port.DataReceived += DataReceivedEvent;
}
private void button1_Click(object sender, EventArgs e)
{
m_port.Close();
m_port.PortName = (string)m_list.SelectedItem;
try
{
m_port.Open();
m_sendbutton.Enabled = true;
button2.Enabled = true;
}catch(UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message);
}
}
private void m_sendbutton_Click(object sender, EventArgs e)
{
m_port.Write(m_textbox.Text);
}
private void DataReceivedEvent(object sender, SerialDataReceivedEventArgs args)
{
Invoke(new EventHandler(DoUpdate));
}
private void DoUpdate(object s, EventArgs e)
{
label1.Text += m_port.ReadLine();
}
private void button2_Click(object sender, EventArgs e)
{
byte[] r_bytes = Encoding.ASCII.GetBytes(m_textbox.Text);
m_port.Write(r_bytes, 0, r_bytes.Length);
}
}
}
Scoreboard Data Protocol
Code: https://hastebin.com/epirobuduv.cs
Here's how to add STX and ETX around your message, in a byte array.
private void button2_Click(object sender, EventArgs e)
{
var msg = Encoding.ASCII.GetBytes(m_textbox.Text).ToList();
msg.Insert(0, 0x02); // STX at the start
msg.Add(0x03); // ETX at the end
m_port.Write(msg.ToArray(), 0, msg.Count);
}

Arduino Microcontrollers interfacing C#

I'm working on project and I need to create a program that gets data from an Arduino to determine the status all sensors values. I've researched that the best way to send these data is to send them in one line through the serial port and then parse it in Visual Studio. The problem is I don't know how to parse the said data in order for them to show in different text boxes in the program. Any help would be much appreciated...in one textbox am already showing the data but I want to show all sensors values in different textboxes.
namespace Arduino_Data
{
public partial class Form1 : Form
{
private SerialPort myport;
private DateTime datetime;
private string in_data;
public Form1()
{
InitializeComponent();
}
// private void label3_Click(object sender, EventArgs e)
// {
// }
private void satrt_btn_Click(object sender, EventArgs e)
{
myport = new SerialPort();
myport.BaudRate = 9600;
myport.PortName = port_name_tb.Text;
myport.Parity = Parity.None;
myport.DataBits = 8;
myport.StopBits = StopBits.One;
myport.DataReceived += myport_DataReceived;
try{
myport.Open();
data_tb.Text = "";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message , "Error");
}
}
void myport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//throw new NotImplementedException();
in_data = myport.ReadLine();
this.Invoke(new EventHandler(displaydata_event));
}
private void displaydata_event(object sender, EventArgs e)
{
// throw new NotImplementedException();
datetime = DateTime.Now;
string time = datetime.Hour + ":" + datetime.Minute + ":" + datetime.Second;
data_tb.AppendText( time + "\t\t\t"+in_data+"\n");
int data_value = Convert.ToInt32(in_data);
pb_value.Value = data_value;
pb_value.Minimum = 0;
pb_value.Maximum = 1023;
}
private void stop_btn_Click(object sender, EventArgs e)
{
try
{
myport.Close();
}
catch (Exception ex2)
{
MessageBox.Show(ex2.Message, "Error");
}
}
private void save_btn_Click(object sender, EventArgs e)
{
try {
string pathfile = #"C:\Users\irtaz\Desktop\DATA";
string filename = "arduino_data.txt";
System.IO.File.WriteAllText(pathfile + filename, data_tb.Text);
MessageBox.Show("Data has been saved to" + pathfile, "Save File");
}
catch(Exception ex3)
{
MessageBox.Show(ex3.Message, "Error");
}
}
}
}

Reading from SerialPort; Error when I close and then open application

I created application for reading from Serial Port and it works just fine. But the problem occure when I close the application and run it again. Suddenly reading from Serial port stops working. I have to disconnect and connect USB to fix that.
This is my code:
namespace Serial
{
public partial class Main : Form
{
SerialPort mainSerialPort = new SerialPort();
public Main()
{
InitializeComponent();
}
delegate void SetTextCallback(string text);
private void buttonOpen_Click(object sender, EventArgs e)
{
mainSerialPort.PortName = "COM" + numericPort.Value.ToString();
mainSerialPort.BaudRate = 115200;
mainSerialPort.Parity = Parity.None;
mainSerialPort.StopBits = StopBits.One;
mainSerialPort.DataBits = 8;
mainSerialPort.Handshake = Handshake.None;
mainSerialPort.DataReceived += DataReceived_Read;
try{
mainSerialPort.Open();
}catch (Exception ex){
labelStatus.Text = ex.GetType().ToString();
}
if (mainSerialPort.IsOpen == true){
numericPort.BackColor = Color.Green;
labelStatus.Text = "Port je otevřen!";
}else{
numericPort.BackColor = Color.Red;
}
}
private void DataReceived_Read(object sender, SerialDataReceivedEventArgs e)
{
SerialPort mySerial = (SerialPort)sender;
if (this.InvokeRequired){
listBoxRead.Invoke(new MethodInvoker(delegate {
listBoxRead.Items.Add(mySerial.ReadExisting());
listBoxRead.SelectedIndex = listBoxRead.Items.Count - 1;
}));
}
}
private void Main_FormClosed(object sender, FormClosedEventArgs e)
{
mainSerialPort.DataReceived -= DataReceived_Read;
mainSerialPort.Close();
}
}
}
USB and serial ports are unmanaged ressources. You have to dispose it!. A simple "Close" on FormClosed will not do the same.
I think it has to do with some resources not properly freed up. Try calling Dispose method
mainSerialPort.Close();
mainSerialPort.Dispose();

Categories