I am working with arduino serial monitor. My goal is to connect through serial port, send some data and close the application after it's done.
This is a C# application. Everything works well besides the fact that the application does not close. To solve the issue, I added Application.Exit() call at the end of Form1_Load method. After this change, the application starts and closes without reading the uppercase letter that I'm sending.
Source code:
namespace ForTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
foreach (string port in ports)
{
SerialPort sp = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
try
{
sp.Open();
try
{
sp.WriteLine("Z"); // Send 1 to Arduino
sp.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
catch (Exception ek)
{
System.Diagnostics.Debug.WriteLine(ek.Message);
}
}
Application.Exit();
}
private void label2_Click(object sender, EventArgs e)
{
}
private void label1_Click(object sender, EventArgs e)
{
}
}
}
if I understood properly, you want to send data FROM C# to ARDUINO and then you exit the C# app
you can't just call Application.exit() after the InitializeComponent(), instead to achieve that you need to exit after sending the data
sp.WriteLine("Z"); // Send 1 to Arduino
sp.Close();
Application.Exit(); ///here!!
Related
I'm following this tutorial. The goal is to receive periodic data from the arduino via serial port. I've been struggling with this for a while now. The com port connection is fine as i'm unable to connect with another terminal program to the arduino when my c# app is running ( port is already connected). At this point the SerialListen thread should start but this doesn't happen.
namespace TestReceiveArduino
{
public partial class Form1 : Form
{
//object serialport to listen usb
System.IO.Ports.SerialPort Port;
//variable to check if arduino is connect
bool IsClosed = false;
public Form1()
{
InitializeComponent();
//configuration of arduino, you check if com3 is the port correct,
//in arduino ide you can make it
Port = new System.IO.Ports.SerialPort();
Port.PortName = "COM11";
Port.BaudRate = 9600;
Port.ReadTimeout = 500;
try
{
Port.Open();
Console.WriteLine("open port ");
}
catch { }
}
private void Form1_Load(object sender, EventArgs e)
{
//A Thread to listen forever the serial port
Console.WriteLine("start thread ");
Thread Hilo = new Thread(ListenSerial);
Hilo.Start();
}
private void ListenSerial()
{
Console.WriteLine("start listener");
while (!IsClosed)
{
Console.WriteLine("in while");
try
{
//read to data from arduino
string AString = Port.ReadLine();
//write the data in something textbox
txtSomething.Invoke(new MethodInvoker(
delegate
{
txtSomething.Text = AString;
}
));
}
catch { }
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
//when the form will be closed this line close the serial port
IsClosed = true;
if (Port.IsOpen)
Port.Close();
}
}
}
My arduino is sending data, i've checked this with terminal software. I'm also using the correct COM port
I have some experience with c# but i'm new to threads. What could be the reason for this?
OK:
See if these changes help:
namespace TestReceiveArduino
{
public partial class Form1 : Form
{
//object serialport to listen usb
System.IO.Ports.SerialPort Port;
//variable to check if arduino is connect
bool IsClosed = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
// Connect to Arduino
Port = new System.IO.Ports.SerialPort();
Port.PortName = "COM11";
Port.BaudRate = 9600;
Port.ReadTimeout = 500;
Port.Open();
Console.WriteLine("Port successfully opened: Name: {0}, Baud: {1}, ReadTimeout: {2}", Port.PortName, Port.BaudRate, Port.ReadTimeout);
//A Thread to listen forever the serial port
Console.WriteLine("start thread ");
Thread Hilo = new Thread(ListenSerial);
Hilo.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
...
I moved "Open Serial Connection" and "Start Listener Thread" to the same place (Form1_Load), and wrapped both in the same try/catch block. You might even want to move the "try/catch" to a higher level (e.g. so you can display any exceptions in your Windows GUI).
I assume you're using Microsoft VisualStudio (e.g. MSVS Express 2019) as your GUI, correct? Definitely familiarize yourself with your IDE's debugger; definitely get in the habit of stepping through the code as you're developing it.
Your next steps:
Verify the code gets to "Open Serial Connection", and verify that it opens correctly (e.g.prints "Port successfully opened...").
Verify the code then gets to "ListenSerial()", and prints "start listener" and "in while" at least once.
'Hope that helps...
The code i have works, but i want to make sure it's robust, as i remember writing similar code in the past (with python) and noticing that i was receiving datas that would be 3 or 4 minutes old and would get even older with time.
I guess this has to do with the serial buffer, and that i should "clear it" from time to time, what is the best practice for this ?
C# form code:
using System;
using System.Windows.Forms;
using System.IO.Ports;
namespace SerialTest1
{
public partial class Form1 : Form
{
public SerialPort ArduinoSerial;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Timer MyTimer = new Timer();
MyTimer.Interval = (1000); // 1 sec
MyTimer.Tick += new EventHandler(SerialTimer_Tick);
MyTimer.Start();
Console.WriteLine("Form1_Loading....");
OpenSerialPort();
}
private void OpenSerialPort() // creating serial communication object
{
try
{
Console.WriteLine("OpenSerialPort: opening port.....");
ArduinoSerial = new SerialPort("COM7", 115200);//Set board COM
ArduinoSerial.Open();
ArduinoSerial.DataReceived += new SerialDataReceivedEventHandler(dataReceived);
}
catch (Exception ex)
{
Console.WriteLine("OpenSerialPort: Can not find port");
}
}
// write to arduino and restart Serial com if error like cable disconnected and reconnected
private void writeToArduino()
{
try
{
Console.WriteLine($"writeToArduino: writing msg to arduino");
ArduinoSerial.WriteLine("hello from pc");
}
catch (Exception ex)
{
Console.WriteLine("writeToArduino: Serial Error");
//MessageBox.Show("Serial Error: " + ex.ToString(), "ERROR");
if (!ArduinoSerial.IsOpen)
{
Console.WriteLine("writeToArduino: ArduinoSerial is close, opening it...");
OpenSerialPort();
}
}
}
private void SerialTimer_Tick(object sender, EventArgs e) // will write to arduino at each timer tick
{
writeToArduino();
}
private void dataReceived(object sender, SerialDataReceivedEventArgs e) // receiving datas from arduino
{
string SerialLine = ArduinoSerial.ReadLine();
Console.WriteLine($"dataReceived: Got serial line for arduino: {SerialLine}");
}
}
}
Arduino code:
#include <TimeLib.h>
#include <Time.h>
//WINDOWS COMMUNICATION
String receivedString;
void setup(void) {
Serial.begin(115200);
}
void loop(void) {
static time_t lastMsg = 0;
static int counter = 1;
if (now() - lastMsg > 1) {
lastMsg = now();
Serial.print("msg ");
Serial.print(counter);
Serial.println("Hello from arduino");
counter++;
}
while (Serial.available() > 0) {
receivedString = Serial.readString();
Serial.println(receivedString);
}
delay(5);
}
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.
I'm trying to program the UBW in C# to take a command and give me the input back. For example, when I establish the USB connection in TeraTerm, a input v would give me a output of the current firmware version of the UBW I'm using.
I have the connection established in C#. I think I'm sending the command right, but my datareceived handler is never called in the debugger.
Here is the code to try to write to the port:
private void button1_Click(object sender, EventArgs e)
{
if (port.IsOpen)
{
//write command to port
port.WriteLine(textBox1.Text);
}
else
{
MessageBox.Show("Serial port is closed! Try again!");
}
textBox1.Clear();
}
Here is the code to try to read from it (which is never called from the debugger)
private void port_dataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
port.ReadLine();
}
catch { }
}
Here is the UBW home page to show how it works. http://schmalzhaus.com/UBW/
My comboBox code to set up my port:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string portName = comboBox1.SelectedItem.ToString();
port = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
port.DataReceived += new SerialDataReceivedEventHandler(port_dataReceived);
try
{
port.Open();
//port.DataReceived += new SerialDataReceivedEventHandler(port_dataReceived);
}
catch
{
MessageBox.Show("The selected serial port cannot be opened!");
Application.Exit();
}
}
Go into TeraTerm's COM port properties, and make sure you're using the same properties in your code.
Try using this class (it wraps up a lot of serial stuff to make it easier):
http://code.google.com/p/flux3gui/source/browse/Flux3GUI/SerialCommunication.cs?r=b4a4f8546b936eeabe60b7de32e3027493498dc6
I have a magnetic card reader with serial port interface.
I used following C#.net code to send command to the card reader.
System.IO.Ports.SerialPort myport = new System.IO.Ports.Serialport("COM1", 9600, Parity.Nonek, 8, StopBits.One);
myport.Open();
// initiates the card reader to read.
myport.write("command to initiate card reader");
// Once the card is swiped it shows the read data.
MessageBox.Show(myport.ReadExisting());
myport.Close();
The above code will work well when i have some pause before Messagebox. But I don't want pause.Rather I want to initiate messagebox whenever the card is swiped.
How can we do so?
I am implementing this in user login system.
I assume you have some kind of GUI that you want to update on card swipe. I will assume you have a form with a single text box called "textBox1" and a button labelled "Start" (button1).
using System;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
namespace SerialPortExample {
public partial class Form1 : Form {
SerialPort myport;
public Form1() {
InitializeComponent();
myport = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
myport.DataReceived += new SerialDataReceivedEventHandler(myport_DataReceived);
myport.ErrorReceived += new SerialErrorReceivedEventHandler(myport_ErrorReceived);
}
delegate void SerialDataReceivedDelegate(object sender, SerialDataReceivedEventArgs e);
delegate void SerialErrorReceivedDelegate(object sender, SerialErrorReceivedEventArgs e);
void myport_ErrorReceived(object sender, SerialErrorReceivedEventArgs e) {
if (this.InvokeRequired) {
this.Invoke(new SerialErrorReceivedDelegate(myport_ErrorReceived_Client), sender, e);
} else {
myport_ErrorReceived_Client(sender, e);
}
}
void myport_ErrorReceived_Client(object sender, SerialErrorReceivedEventArgs e) {
MessageBox.Show("Error recieved: " + e.EventType);
}
void myport_DataReceived(object sender, SerialDataReceivedEventArgs e) {
if (this.InvokeRequired) {
this.Invoke(new SerialDataReceivedDelegate(myport_DataRecieved_Client), sender, e);
} else {
myport_DataRecieved_Client(sender, e);
}
}
void myport_DataRecieved_Client(object sender, SerialDataReceivedEventArgs e) {
textBox1.Text = myport.ReadExisting();
}
private void button1_Click(object sender, EventArgs e) {
try {
if (myport.IsOpen) {
myport.Close();
button1.Text = "Start";
} else {
myport.Open();
button1.Text = "Stop";
}
} catch (IOException ex) {
MessageBox.Show(ex.Message);
}
}
}
}
I don't have a serial device to test this code on, but it should be correct.
Breaking it down, the important part is the method myport_DataRecieved. This method is called whenever data arrives on the serial port, i.e. when a card is swiped.
Other areas of interests are the Form1 constructor, where we initialize the SerialPort (but, not open it yet), and the method button1_Click where we open/close the port (and change the button's text to reflect that. We also handle exceptions, in case we can't open the port for some reason.
Edit: I've updated the answer, thanks to Hans's comment. You cannot directly access the UI controls from the data events, as they run on a different thread. I split the event methods in half, so that I could call Invoke on them, and run them in the proper context.