I've asked this question earlier today, but have refined my code so am putting a new question up here.
This is the code I have at the moment:
Arduino Code:
void setup()
{
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
Serial.begin(9600);
}
void loop()
{
if(Serial.available() > 0)
{
char letter = Serial.read();
if (letter == 'A')
{
digitalWrite(13,HIGH);
Serial.println("THE LED IS ON");
}
else if (letter == 'B')
{
digitalWriter(13,LOW);
Serial.println("THE LED IS OFF");
}
}
}
I have a C# program with an onButton, offButton, and textboxInterface. This is the code I have in C#.
C# Code:
using System.IO.Ports;
public partial class Form1: Form
{
public static System.IO.Ports.SerialPort serialPort1;
private delegate void LineReceivedEvent(string line);
public Form1()
{
InitizlizeComponent();
System.ComponentModel.IContainer components = new System.ComponentModel.Container();
serialPort1 = new System.IO.Ports.SerialPort(components);
serialPort1.PortName = "COM7";
serialPort1.BaudRate = 9600;
serialPort1.DtrEnable = true;
serialPort1.Open();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
}
private static void serialPort1_DataReceived(object sender, SerialDataEventReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
textboxInterface.Text = indata;
}
I think that is mostly right (?), the only error I am getting is as the last textboxInterface with an error coming up saying: *An object reference is required for the non-static field, method, or property 'Arduino_Interface.Form1.textboxInterface'*
Can someone please show me what stupid thing I'm doing...
First, remove static from the declaration of serialPort1_DataReceived. You need access to the form's instance fields so it cannot be static.
Second, this event will be raised on a background thread and you cannot update the UI from that thread. You will need to marshal the call to UI thread to update the textbox. Something like this:
private void serialPort1_DataReceived(object sender, SerialDataEventReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
this.BeginInvoke(new Action(() => textboxInterface.Text = indata));
}
Related
I am trying to write a program that communicates with a controller. The controller is supposed to send a "welcome" message when a connection is successfully established and, in fact, it does when I connect using a communications software. However, using the .NET code below, I never see the welcome message. Beyond that, it works. How can I capture this message. It seems to be sent the moment the connection is established.
Again, I am able to communicate fine with the controller after connection but I simply cannot seem to get the welcome message that is sent a the moment the connection is opened.
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public delegate void AddDataDelegate(String myString);
public AddDataDelegate myDelegate;
SerialPort sp;
public Form1()
{
InitializeComponent();
}
public void AddDataMethod(String myString)
{
richTextBox1.AppendText(myString);
richTextBox1.SelectionStart = richTextBox1.Text.Length;
richTextBox1.ScrollToCaret();
}
private void button1_Click(object sender, EventArgs e)
{
try
{
sp = new SerialPort(comboBox1.SelectedItem.ToString(),Int32.Parse(comboBox2.SelectedItem.ToString()));
sp.DataReceived += SerialPort_OnDataReceived;
sp.Close();
sp.Open();
richTextBox1.AppendText("open\n");
button2.Enabled = true;
button3.Enabled = true;
}
catch (Exception ex)
{
richTextBox1.AppendText(ex.Message);
}
}
void SerialPort_OnDataReceived(object sender,SerialDataReceivedEventArgs args)
{
SerialPort sp = sender as SerialPort;
string s = sp.ReadExisting();
richTextBox1.Invoke(this.myDelegate, new Object[] { s });
}
private void button2_Click(object sender, EventArgs e)
{
sp.WriteLine(textBox1.Text);
textBox1.Text = "";
}
private void button3_Click(object sender, EventArgs e)
{
sp.DiscardOutBuffer();
sp.DiscardInBuffer();
sp.Close();
richTextBox1.AppendText("\nclosed\n");
}
private void Form1_Load_1(object sender, EventArgs e)
{
this.myDelegate = new AddDataDelegate(AddDataMethod);
string[] Ports = SerialPort.GetPortNames();
comboBox2.SelectedIndex = comboBox2.Items.Count - 1;
Array.Sort(Ports, (a, b) => string.Compare(a.Substring(3).PadLeft(3, '0'), b.Substring(3).PadLeft(3, '0')));
foreach (string port in Ports)
{
comboBox1.Items.Add(port);
}
comboBox1.SelectedIndex = 0;
}
}
}
I worked it out. Required a slight delay between connection and trying to pull data from the port.
I currently have a program made using VB6 code that uses the MSCOMM control to pull back data from the serial port. This manages to successfully receive the data from my serial port, in which a Denso BHT-904B device is connected.
I am now trying to move this code over to C# so it fits in with a new piece of software that i am developing. To do this i am using the SerialPort class. However, the issue is that when i open the port up the data received event only fires when the device fails to communicate (which im guessing is due to a timeout). The data then received in the event is '↑↑↑↑↑'.
My SerialPort control settings are the following:
DtrEnable = True
PortName = COM3
ReadBufferSize = 1024
WriteBufferSize = 512
The code that i am using behind my form control is:
namespace BHTTestingDotNet
{
public partial class Form1 : Form
{
private string rxString;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
serialPort.DtrEnable = true;
serialPort.Encoding = Encoding.Default;
serialPort.DataReceived += serialPort_DataReceived;
serialPort.ErrorReceived += serialPort_ErrorReceived;
serialPort.Open();
}
private void serialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
MessageBox.Show(e.ToString());
}
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
var serialPort = (SerialPort)sender;
var test = serialPort.BytesToRead;
SerialPort sr = (SerialPort)sender;
rxString = sr.ReadExisting();
this.BeginInvoke(new EventHandler(displayText));
}
private void displayText(object o, EventArgs e)
{
txtBHT.AppendText(rxString);
}
}
}
I have already tried to set both RtsEnable and DtrEnable to true but that didn't make any difference.
UPDATE - I have now changed to protocol settings on the device but i now only receive pipes and then a return symbol, for example like so:
|||||¬
I am using SerialPort class often and for my purposes I have made my own class
public class SerialPortDataSource : SerialPort
where SerialPort.DataReceived handler invoke this method:
private void SerialPortDataSource_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (BytesToRead > 0)
{
var buffor = new byte[BytesToRead];
Read(buffor, 0, buffor.Length);
_receivedBytes = buffor;
//wConsole.WriteLine(ArrayExtension.ToString(buffor));
var dataLogger = DataLogger;
if (dataLogger != null)
{
dataLogger.WriteLine("- DR - {0}", true, BitConverterExtension.ToHexString(buffor));
}
if (OnDataReceived != null)
{
OnDataReceived(this, buffor);
}
}
}
catch (InvalidOperationException)
{
// sometimes DataReceived event is invoked after port is closed which causes InvalidOperationException
}
}
This method is working for me in many applications with variety serial port settings.
Here the serial communication port shows error it cannot be accessed .....But the serial communication port works perfect in arduino, so it cant be the port problem, its not the driver problem either, the driver is updated and works well, so the problem can be in the code .....i am a newbie to C#.
public partial class Form1 : Form
{
private SerialPort myport;
private string in_data;
public Form1()
{
InitializeComponent();
}
private void Start_Click(object sender, EventArgs e)
{
myport = new SerialPort();
myport.BaudRate = 19200;
myport.PortName = pn.Text;
myport.Parity = Parity.None;
myport.DataBits = 8;
myport.StopBits = StopBits.One;
myport.DataReceived += myport_DataReceived;
try
{
myport.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error!!");
}
}
void myport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
*in_data = myport.ReadLine();***
this.Invoke(new EventHandler(displaydata_event));
}
private void displaydata_event(object sender, EventArgs e)
{
string[] newData = in_data.Split(',');
bv.Text = newData[0];
bi.Text = newData[1];
pv.Text = newData[2];
pi.Text = newData[3];
t.Text = newData[4];
}
}
it cannot be accessed
This may indicates that the port doesnt exists or is already in use.
Maybe another application is already listening on this port. (arduino?)
Comport.Open() Exceptions are descibed here:
MSDN SerialPort.Open Method
I have the following C# program with a button called GetForceButton and a multiline textbox called ForceTextbox. Here is the code I have at the moment:
public Form1()
{
InitializeComponent();
System.ComponentModel.IContainer components = new System.ComponentModel.Container();
serialPort1 = new System.IO.Ports.SerialPort(components);
serialPort1.PortName = "COM7";
serialPort1.BaudRate = 9600;
serialPort1.DtrEnable = true;
serialPort1.Open();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
bool buttonpressed = false;
public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadLine();
if (buttonpressed == true)
{
ForceTextbox.Text = indata + "\n";
}
else
{
ForceTextbox.Text = "No data received";
}
}
private void GetForceButton_Click(object sender, EventArgs e)
{
buttonpressed = true;
}
When I step through the code, indata is getting the value from the serialPort of "0.00\r" (including the speech brackets).
After stepping to the ForceTextbox.Text = indata + "\n"; line, an exception is being thrown up saying:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll. Additional information: Cross-thread operation not valid: Control 'ForceTextbox' accessed from a thread other than the thread it was created on.
What does that mean, or what am I doing wrong please?
You need to read this link.
The long and short of it is you need to make sure that you update GUI components on the same thread that started them. Mostly, this is done by the GUI thread.
You'll be using InvokeRequired as shown in that link.
You have to do this in C# all over the place unfortunately.
One other tutorial from Microsoft.
I have a system that sends an "at" command to a serial port and displays the return on a MessageBox.
But I needed to do this in all available serial ports. So I created a List and I'm adding all the ports on it.
I managed to send the command, but could not continue the rest of the code to catch the return because I am having trouble handling the lists. I am a beginner in C #.
Below is my current code.
The part that is commented out is what I'm struggling to continue.
This part belongs to the old code (when it was just one serial port).
public partial class Form1 : Form
{
List<SerialPort> serialPort = new List<SerialPort>();
// delegate is used to write to a UI control from a non-UI thread
private delegate void SetTextDeleg(string text);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var portNames = SerialPort.GetPortNames();
foreach (var port in portNames) {
SerialPort sp;
sp = new SerialPort(port, 19200, Parity.None, 8, StopBits.One);
sp.Handshake = Handshake.None;
//sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.ReadTimeout = 500;
sp.WriteTimeout = 500;
serialPort.Add(sp);
listPorts.Items.Add(port);
}
}
private void listPorts_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
foreach (var sp in serialPort) {
// Open port
try
{
if (!sp.IsOpen)
sp.Open();
MessageBox.Show(sp.PortName + " aberto!");
sp.Write("at\r\n");
}
catch (Exception ex)
{
MessageBox.Show("Error opening/writing to serial port :: " + ex.Message, "Error!");
}
}
}
/* HELP START
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
string data = sp.ReadLine();
this.BeginInvoke(new SetTextDeleg(si_DataReceived), new object[] { data });
}
private void si_DataReceived(string data)
{
String retorno = data.Trim();
MessageBox.Show(retorno);
// Fecha a porta após pegar o retorno
sp.Close();
}
HELP END */
}
What to put in place 'sp.ReadLine ();' and 'sp.Close ();'?
I don't know do this because of the List <>
The simplest approach would be to use a lambda expression which would capture the port you're using. A lambda expression is a way of building a delegate "inline" - and one which is able to use the local variables from the method you declare it in.
For example:
foreach (var port in portNames)
{
// Object initializer to simplify setting properties
SerialPort sp = new SerialPort(port, 19200, Parity.None, 8, StopBits.One)
{
Handshake = Hanshake.None,
ReadTimeout = 500,
WriteTimeout = 500
};
sp.DataReceived += (sender, args) =>
{
Thread.Sleep(500); // Not sure you need this...
string data = sp.ReadLine();
Action action = () => {
MessageBox.Show(data.Trim());
sp.Close();
};
BeginInvoke(action);
};
serialPort.Add(sp);
listPorts.Items.Add(port);
}
A few notes about this:
Just because some data has been received doesn't mean that a whole line has, so ReadLine may still block
If you only need to show a message box, you may not need Control.BeginInvoke. (If you need to do more here, you might want to extract most of that code into a separate method which just takes a string, then create an action which would call that method.)
Are you sure you want to close the serial port as soon as the first line has been received?
You can chage your sp_DataReceived method as,
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
SerialPort sp = (SerialPort)sender;
string data = sp.ReadLine();
this.BeginInvoke(new SetTextDeleg(si_DataReceived), new object[] { data });
sp.Close();
}
and remove the sp.Close(); from si_DataReceived method.
If you want to have a Serial port value in your si_DataReceived method,
you should pass it there:
// First, add port into your delegate
private delegate void SetTextDeleg(SerialPort port, string text);
...
/* HELP START */
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
SerialPort sp = (SerialPort) sender; // <- Obtain the serial port
string data = sp.ReadLine();
// Pass the serial port into si_DataReceived: SetTextDeleg(sp, ...
this.BeginInvoke(new SetTextDeleg(sp, si_DataReceived), new object[] { data });
}
// "SerialPort sp" is added
private void si_DataReceived(SerialPort sp, string data) {
String retorno = data.Trim();
MessageBox.Show(retorno);
// Fecha a porta após pegar o retorno
sp.Close();
}
/* HELP END */
See also:
http://msdn.microsoft.com/library/system.io.ports.serialport.datareceived.aspx