I would like to read information from a device connected to a SerialPort. I did this previously using a form (code below) but I am trying to do it without one, just storing the information into an array of string.
Code used with a form:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string line = port.ReadExisting();
this.BeginInvoke(new LineReceivedEvent(LineReceived), line);
}
private delegate void LineReceivedEvent(string line);
private void LineReceived(string line)
{
textBox3.AppendText(line);
}
How far i got without a form (the DA method is allows to store variables within the program). I get the following error on the last line Cannot implicitly convert type 'string' to 'System.IO.Ports.SerialDataReceivedEventHandler'.
protected override void SolveInstance(IGH_DataAccess DA)
{
string selectedportname;
DA.GetData(1, ref selectedportname);
int selectedbaudrate;
DA.GetData(2, ref selectedbaudrate);
bool connecttodevice;
DA.GetData(3, ref connecttodevice);
bool sendtoprint;
DA.GetData(3, ref sendtoprint);
port = new SerialPort(selectedportname, selectedbaudrate, Parity.None, 8, StopBits.One); //Create the serial port
port.DtrEnable = true; //enables the Data Terminal Ready (DTR) signal during serial communication (Handshaking)
port.Open(); //Open the port
port.DataReceived += port.ReadExisting();
}
Assuming ReadExisting is a method with the right parameters:
//port.DataReceived += port.ReadExisting();
port.DataReceived += port.ReadExisting;
But the error indicates it is returning a 'string' so there is more to solve here.
Edit:
Looks like it should be:
port.DataReceived += this.serialPort1_DataReceived;
Related
So, I am trying to read data from the serial port to communicate with an Arduino. Here is the code I am using:
public partial class Form1 : Form
{
SerialPort port = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
public Form1()
{
InitializeComponent();
port.Open();
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
this.Invoke(new EventHandler(DoUpDate));
}
private void DoUpDate(object s, EventArgs e)
{
textBox1.AppendText(port.ReadLine() + "\r\n");
}
}
But the result I get in the textBox is (check the picture):
The value read should be 975 but I got separated values as well as many empty lines.
Any help is apperciated.
EDIT#1:
Here is the Arduino code:
int sensorPin=A0;
int sensorValue=0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
sensorValue=analogRead(sensorPin);
Serial.print(sensorValue);
Serial.print("\n");
}
And here is the result when I click on the serial reader within arduino IDE (which what C# code should show)
EDIT#2
After thinking more about the problem, I think that the C# code is very fast that it is reading uncomplete data but I don't have a solution for it, do you know anything I can try to solve it?
I'm not fluent in C#, but maybe you should wait for data to be in the Serial buffer before trying to read them. A method for that is to use port.ReadExisting() as it can be seen here!
Hope it helps!
Insert a 20ms delay in your loop()
After a long time i need to program again.
I need to constantly send a command through serial port from a car ecu(? data).
Then i need to receive that data which i will process to be shown on a display(thinking racing display with car parameters like temperature etc).
I need to do this constantly
I wonder before i start whats best way to do this?
1 thread for constantly asking and receiving data
main thread for showing data in screen.
(store data in buffer and save once a minute or so)
anyone has any tips a guide or so how to start on this.
i tested receiving data with terminal and i got data back so config is working.
sent ? data => i got data back.
You could just use the SerialPort class and configure the BaudRate, DataBits etc.. and then just wait for the DataReceived event to fire:
public class SerialPortReader
{
public SerialPortReader(string yourPortName)
{
var serialPort = new SerialPort() {
PortName = yourPortName,
BaudRate = 57600; //This will control the rate at what you receive the data
}
serialPort.DataReceived += new SerialDataReceivedEventHandler(OnDataReceived);
serialPort.Open();
}
}
public void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = (SerialPort)sender;
// Process your data reading the stream with Read, ReadLine etc...
}
The approach we are using in our SerialPort Handler is, to have an AutoResetEvent to get notified as soon as there is an answer from the port.
SerialPort class of the FrameWork has a few issues with the integrated DataReceived event. It is sometimes fired when there is no complete package available (in case you defined the answer length). So you should check for the answer length you expect.
Our very stripped down implementation:
public class Serialport
{
private SerialPort _serialPort;
private List<byte> _buffer;
private AutoResetEvent _autoResetEvent;
private const int WriteTimeOut = 5;
private event EventHandler ReceivedDataChanged;
public Serialport()
{
_serialPort = new SerialPort();
// set PortName, BaudRate etc
_serialPort.Open();
_serialPort.DiscardInBuffer();
_serialPort.DiscardOutBuffer();
_serialPort.DataReceived += ReceiveData;
}
private void ReceiveData(object sender, SerialDataReceivedEventArgs e)
{
var bytes = _serialPort.BytesToRead;
byte[] buffer = new byte[bytes];
if (_serialPort.IsOpen)
{
_serialPort.BaseStream.Read(buffer, 0, bytes);
_buffer.AddRange(buffer);
}
ReceivedDataChanged?.Invoke(this, new ReceivedBytesEventArgs(_buffer.ToArray()));
_buffer.Clear();
}
private void SendData(byte[] message, int answerLength)
{
_serialPort.ReceivedBytesThreshold = answerLength;
_serialPort.WriteTimeout = WriteTimeOut;
_serialPort.Write(message, 0, message.Length);
}
public string SendDataCommand()
{
if (_serialPort.IsOpen)
{
ReceivedDataChanged += InterpretAnswer;
SendData(message, length);
if (_autoResetEvent.WaitOne(100))
{
ReceivedDataChanged -= InterpretAnswer;
//Data Received and interpreted and send to the caller
return _requestAnswer;
}
ReceivedDataChanged -= InterpretAnswer;
}
return "Connection not open";
}
private void InterpretAnswer(object sender, EventArgs e)
{
// handle all interpretation
// Set the event
_autoResetEvent.Set();
}
}
The serialPort is initialised and opened. After that, we wire up all needed events and call the SendDataCommand() Method. This method is the public visible method which is called from some task. This calls the method SendData. As soon as there is an answer, the event is triggered and the interpretation is started. If the interpretation is done in the specified amount of time (_autoResetEvent.WaitOne(msToWait)) the result is given back to the calling method.
This should be done in a separate task, so the ui will not Block while you wait for the answer
As mentioned, this is a very stripped down example. You should do more checking in the received handler of SerialPort, because there are some issues with the event. With this approach you will have a bit more of abstraction to your business logic.
Hope this helps.
I am develop a Console Application which is able to read and write data from an Arduino through serial port. When I read from the Arduino I have to wait to get a response from it so creating a timer is the better option.
So I've created this Timer and will run every 2000 milliseconds.
static void Main(string[] args)
{
SerialPort port = new SerialPort("COM1", 9600, Parity.Odd, 7, StopBits.One);
Timer t = new Timer(TimerCallback, null, 0, 2000);
port.DataReceived += Port_DataReceived;
port.Open();
}
private static void TimerCallback(Object o)
{
//Call the method
}
What I want to do is call this method into the TimerCallback
private static void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = sender as SerialPort;
// Leitura de dados
string incoming = port.ReadExisting();
string questionmark = "?";
string carriageReturn = "\r";
string text = string.Empty;
switch (incoming)
{
case "#r\r":
// send the message back
port.Write(questionmark + "*" + carriageReturn);
break;
case "#{/r":
port.Write("#" + text);
break;
default:
Console.WriteLine("Unknown command sent by the Arduino!\n Command: " + incoming);
break;
}
}
How should I call the Port_DataReceived method?
It seems strange that you would want to call the event handler directly from your code?
Suggest having a new function that is called from your timer and also from the event handler.
But why you want to do this still seems smelly to me.
You don't need the timer. Remove it.
The event will be called whenever data is received on the serial port. You don't need to call it yourself.
I have methos that recieve data from opening COM port:
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
try
{
if (sp.IsOpen)
{
if (sp.BytesToRead > 0)
{
// Get data
}
}
}
}
Also I have method that does connection to COM port:
private void connectPort()
{
SerialPort mySerialPort = new SerialPort(port);
...
}
When I call method that closes port:
mySerialPort.DiscardInBuffer();
mySerialPort.DiscardOutBuffer();
mySerialPort.Close();
After I get data from device still. What is wrong?
I don't know for sure, but from the docs it sounds like the fact that the data is being raised from another thread may be buffering and/or lagging a bit behind the actual data (plus it's possible for you to receive data between when you've discarded the buffer and when you close it).
I'd probably unhooking the DataReceivedHandler first, then close the connection, finally discard the data, ex.
mySerialPort.DataReceived -= new SerialDataReceivedEventHandler(DataReceivedHandler);
Hi i've got here a simple program, but it's not working properly.
When i receive 'A' on the serial port i set checkbox1, and when 'a' i unset checkbox1.
public partial class MainWindow : Window
{
public static SerialPort sp = new SerialPort();
public MainWindow()
{
InitializeComponent();
sp.BaudRate = 2400;
sp.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Prijem);
if (!sp.IsOpen)
sp.Open();
}
private delegate void UpdateUiTextDelegate(char text);
private void Prijem(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
char c = (char)sp.ReadChar();
Dispatcher.Invoke(DispatcherPriority.Send,
new UpdateUiTextDelegate(WriteData), c);
}
private void WriteData(char c)
{
if (c == 'A')
{
checkBox1.IsChecked = true;
}
else if (c == 'a')
{
checkBox1.IsChecked = false;
}
}
}
When the DataReceived event is thrown it is not guaranteed how many characters are within the buffer. So if you simply call ReadChar() you don't read the full content of the buffer. So if the characters are send quite fast it would be possible that you miss something, cause your event handler is called when two or more characters are within the buffer.
Also you should set ALL serial port properties and not just the baud rate. This is needed cause the serial port has no default state and will remain the last set option for each parameter. So if you use some terminal program to change some lesser used settings (like Xon/off, HW Handshake, StartBits, etc.) your program will simply use the same settings if you don't reset them to your desired values.
The SerialPort properties are not all set. Asign a port number.