C# read Arduino - c#

I'm trying to make a app that read the outgoing signals from Arduino, but I can't make it work in C# Windows Forms, only in the console. Is my C# Windows Forms code wrong? I don't get any errors when I debug, but it doesn't mean that I haven't forgot something.
Here is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace CommunicateWithArduino
{
public partial class Form1 : Form
{
public static System.IO.Ports.SerialPort port;
delegate void SetTextCallback(string text);
private BackgroundWorker hardWorker;
private Thread readThread = null;
public Form1()
{
InitializeComponent();
hardWorker = new BackgroundWorker();
sendBtn.Enabled = false;
}
private void btnConnect_Click(object sender, EventArgs e)
{
System.ComponentModel.IContainer components =
new System.ComponentModel.Container();
port = new System.IO.Ports.SerialPort(components);
port.PortName = comPort.SelectedItem.ToString();
port.BaudRate = Int32.Parse(baudRate.SelectedItem.ToString());
port.DtrEnable = true;
port.ReadTimeout = 5000;
port.WriteTimeout = 500;
port.Open();
readThread = new Thread(new ThreadStart(this.Read));
readThread.Start();
this.hardWorker.RunWorkerAsync();
btnConnect.Text = "<Connected>";
btnConnect.Enabled = false;
comPort.Enabled = false;
sendBtn.Enabled = true;
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (string s in SerialPort.GetPortNames())
{
comPort.Items.Add(s);
}
if (comPort.Items.Count > 0)
comPort.SelectedIndex = comPort.Items.Count-1;
else
comPort.SelectedIndex = 0;
baudRate.Items.Add("2400");
baudRate.Items.Add("4800");
baudRate.Items.Add("9600");
baudRate.Items.Add("14400");
baudRate.Items.Add("19200");
baudRate.Items.Add("28800");
baudRate.Items.Add("38400");
baudRate.Items.Add("57600");
baudRate.Items.Add("115200");
baudRate.SelectedIndex = 2;
}
private void sendBtn_Click(object sender, EventArgs e)
{
if (port.IsOpen)
{
port.Write(sendText.Text);
}
}
private void SetText(string text)
{
if (this.receiveText.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.receiveText.Text += "Text: ";
this.receiveText.Text += text;
this.receiveText.Text += Environment.NewLine;
}
}
public void Read()
{
while (port.IsOpen)
{
try
{
if (port.BytesToRead > 0)
{
string message = port.ReadLine();
this.SetText(message);
}
}
catch (TimeoutException) { }
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
try
{
if(!(readThread == null))
readThread.Abort();
}
catch (NullReferenceException)
{
}
try
{
port.Close();
}
catch (NullReferenceException)
{
}
}
}
}

By default, the ReadLine method will block until a line is received. Is your Arduino program sending a line? Did you close the Arduino serial monitor program while running your program?
I would change to port.ReadChar until you verify that you are receiving characters.

Related

How to make two forms receive information from the serial port that receives information from Arduino?

I am developing a graphical interface that reads variables from different sensors that arrive through the serial port, so far I have managed to read all the variables with a single form but now I want to have two forms.
The first form asks the user to choose the COM and confirms whether the connection was successful or not. Once the connection is successful, the second form is opened where the variables from the sensors will be shown in "labels", the readings sent from Arduino are read by the serial port and stored in an array:
data[0], data[1], data[2] etc...
This is the first form where Serialport1 is found and the data arrives through the serialPort1_DataReceived event:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Media;
namespace AUTOCLAVES_GUI
{
public partial class GUI_AUTOCLAVES_GENERADOR_DE_VAPOR : Form
{
/*VARIABLES GLOBALES*/
string puerto_seleccionado;
public GUI_AUTOCLAVES_GENERADOR_DE_VAPOR()
{
InitializeComponent();
string[] puertos = SerialPort.GetPortNames();
foreach (string mostrar in puertos)
{
comboBox1.Items.Add(mostrar);
}
}
private void Salir_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void Minimizar_Click(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
}
private void Maximizar_Click(object sender, EventArgs e)
{
WindowState = FormWindowState.Maximized;
Maximizar.Visible = false;
Restaurar.Visible = true;
}
private void Restaurar_Click(object sender, EventArgs e)
{
WindowState = FormWindowState.Normal;
Restaurar.Visible = false;
Maximizar.Visible = true;
}
private void MenuSideBar_Click(object sender, EventArgs e)
{
if (Sidebar.Width == 270)
{
Sidebar.Visible = false;
Sidebar.Width = 68;
SidebarWrapper.Width = 90;
LineaSidebar.Width = 68;
AnimacionSidebar.Show(Sidebar);
}
else
{
Sidebar.Visible = false;
Sidebar.Width = 270;
SidebarWrapper.Width = 300;
LineaSidebar.Width = 268;
AnimacionSidebarBack.Show(Sidebar);
}
}
private void bunifuFlatButton8_Click(object sender, EventArgs e)
{
try
{
serialPort1.Close();
serialPort1.Dispose();
serialPort1.Open();
CheckForIllegalCrossThreadCalls = false;
label2.Text = "CONEXIÓN EXITOSA";
label2.ForeColor = Color.Green;
label2.Font = new Font(label2.Font, FontStyle.Bold);
openChildForm(new MUESTREO_EN_TIEMPO_REAL());
}
catch
{
label2.Text = "CONEXIÓN FALLIDA";
label2.ForeColor = Color.Red;
label2.Font = new Font(label2.Font, FontStyle.Bold);
MessageBox.Show("REVISE CONEXIÓN DE ARDUINO", "ADVERTENCIA", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
puerto_seleccionado = comboBox1.Text;
serialPort1.PortName = puerto_seleccionado;
}
private void bunifuFlatButton7_Click(object sender, EventArgs e)
{
comboBox1.Items.Clear();
label2.Text = "SIN CONEXIÓN";
label2.ForeColor = Color.White;
string[] puertos = SerialPort.GetPortNames();
foreach (string mostrar in puertos)
{
comboBox1.Items.Add(mostrar);
}
}
private Form activeForm = null;
private void openChildForm(Form childForm)
{
if (activeForm != null)
activeForm.Close();
activeForm = childForm;
childForm.TopLevel = false;
childForm.FormBorderStyle = FormBorderStyle.None;
childForm.Dock = DockStyle.Fill;
panel1.Controls.Add(childForm);
panel1.Tag = childForm;
childForm.BringToFront();
childForm.Show();
}
private void bunifuFlatButton2_Click(object sender, EventArgs e)
{
openChildForm(new MUESTREO_EN_TIEMPO_REAL());
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string[] data = serialPort1.ReadLine().Split(',');
if (data.Length > 10)
{
}
else
{
MessageBox.Show("Intente nuevamente", "ADVERTENCIA", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
}
}
}
Here is my second form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AUTOCLAVES_GUI
{
public partial class MUESTREO_EN_TIEMPO_REAL : Form
{
public MUESTREO_EN_TIEMPO_REAL()
{
InitializeComponent();
}
private void MUESTREO_EN_TIEMPO_REAL_Load(object sender, EventArgs e)
{
}
private void Salir_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
I hope someone can help me overcome this problem.

Arduino, Visual C# best Serial comunication

I'm new to Arduino and serial ports and I want to make the best communication between Arduino and my C# program. In my code I want to control one or more servo motors fast as possible. This is my Arduino code:
#include <Servo.h>
Servo serv;
void setup() {
Serial.begin(115200);
Serial.setTimeout(5);
pinMode(9,OUTPUT);
serv.attach(9);
}
String msg;
void loop() {
String val = Serial.readString();
if(val!=0) {
if(val.startsWith("U")) {
val.replace("U","");
serv.write(val.toInt());
delay(10);
}
}
if(Serial.available()>0) {
msg = "U";
msg = msg+serv.read();
Serial.println(msg);
}
}
And my C# program:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace arduino_servo {
public partial class Form1 : Form {
SerialPort port;
public Form1() {
InitializeComponent();
init();
}
private void Form1_Load(object sender, EventArgs e) {
}
private void init() {
port = new SerialPort();
port.PortName = "COM5";
port.BaudRate = 115200;
port.DataReceived += new SerialDataReceivedEventHandler(Primire_date);
try {
port.Open();
}
catch(Exception ex) {
MessageBox.Show("Eroare",ex.Message,MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void trackBar1_Scroll(object sender, EventArgs e) {
if (port.IsOpen) {
port.WriteLine("U"+trackBar1.Value.ToString());
}
}
private void Primire_date(object emitator, SerialDataReceivedEventArgs e) {
string msg = port.ReadLine();
if (msg.IndexOf("U") > -1) {
msg = msg.Replace("U", "");
label1.Text = msg;
}
}
}
}
If you guys could give me some advice or some modifications, I would be very thankful. My communication is a bit laggy.

c# serial port cannot read data from arduino

For a school project I am creating a pong game connected to the arduino, where if you hold a button pressed the racket moves in one direction and if you don't it moves in the other. The game works fine if I don't use arduino data as an input. I tried using different functions but it doesnt work.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace pong
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace pong
{
public partial class Form1 : Form
{
SerialPort port1 = new SerialPort();
public int points = 0;
public int speed_left = 0;
public int speed_top = 0;
public Form1()
{
InitializeComponent();
timer1.Enabled = true;
Cursor.Hide(); //skrije kurzor
this.TopMost = true;
this.Bounds = Screen.PrimaryScreen.Bounds;
this.FormBorderStyle = FormBorderStyle.None;
racket.Top = panel1.Bottom - (panel1.Bottom / 10);
SerialPort port1 = new SerialPort("COM3");
port1.BaudRate = 9600;
port1.Parity = Parity.None;
port1.StopBits = StopBits.One;
port1.DataBits = 8;
port1.Handshake = Handshake.None;
port1.RtsEnable = true;
port1.Open();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
if(!port1.IsOpen)
{
port1.Open();
port1.ReadTimeout = 1000;
}
if (port1.IsOpen)
{
if (port1.ReadExisting()=="")
{
racket.Left = racket.Left - 0;
}
else
{
racket.Left = racket.Left + 10;
}
}
ball.Left += speed_left;
ball.Top += speed_top;
if(ball.Bottom >=racket.Top && ball.Bottom <= racket.Bottom && ball.Left >= racket.Left && ball.Right <= racket.Right)
{
speed_left += 2;
speed_top += 2;
speed_top = -speed_top;
points += 1;
label2.Text = points.ToString();
}
if(ball.Left<=panel1.Left)
{
speed_left = -speed_left;
}
if (ball.Right >= panel1.Right)
{
speed_left = -speed_left;
}
if(ball.Top <= panel1.Top)
{
speed_top = -speed_top;
}
if(ball.Bottom>=panel1.Bottom)
{
timer1.Enabled=false;
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode==Keys.Escape)
{
this.Close();
}
}
private void label1_Click(object sender, EventArgs e)
{
}
}
}
arduino:
void setup() {
// put your setup code here, to run once:
pinMode(8,INPUT);
digitalWrite(8,LOW);
}
void loop() {
Serial.begin(9600);
while(1){
if(digitalRead(8)==HIGH)
{
Serial.write('1');
}
}
}
I would suggest putting a breakpoint in timer1_Tick, I suspect it is not going to be called at all because you haven't called
timer1.Start();
to start the timer.

My textbox clear is getting Cannot implicitly convert type

All I want to do is just clear the text box on a button click. I get this error
"Error 2 Cannot implicitly convert type 'string' to 'System.Windows.Forms.TextBox' C:\Users\Ed\Downloads\BT1_B\BT1_B\Form1.cs 108 36 BT1_B
"
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using InTheHand;
using InTheHand.Net;
using InTheHand.Net.Sockets;
using InTheHand.Net.Bluetooth;
namespace BT1_B
{
public partial class Form1 : Form
{
Guid service = new Guid("{00001101-0000-1000-8000-00805F9B34FB}");
BluetoothListener bl;
BluetoothClient bc;
bool radioAvailable = false;
bool listening = false;
delegate void SettbMessageReceivedCallback(string text);
public Form1()
{
InitializeComponent();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
listening = false;
bl.Stop();
}
catch
{
}
}
private void btn_listen_Click(object sender, EventArgs e)
{
try
{
BluetoothRadio.PrimaryRadio.Mode = RadioMode.Discoverable;
radioAvailable = true;
}
catch
{
MessageBox.Show("Please make sure Bluetooth is available");
}
if (radioAvailable)
{
bl = new BluetoothListener(BluetoothService.SerialPort);
bl.Start();
listening = true;
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(ListenLoop));
t.Start();
}
}
private void ListenLoop()
{
try
{
while (listening)
{
bc = bl.AcceptBluetoothClient();
StreamReader sr = new StreamReader(bc.GetStream());
String message = sr.ReadLine();
sr.Close();
SettbMessageReceived(message);
}
}
catch
{
}
}
private void SettbMessageReceived(string text)
{
try
{
if (this.txt_incoming_message.InvokeRequired)
{
SettbMessageReceivedCallback d = new SettbMessageReceivedCallback(SettbMessageReceived);
this.Invoke(d, new object[] { text });
}
else
{
this.txt_incoming_message.Text += text + "\r\n";
}
}
catch (ThreadAbortException ex)
{
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btn_clear_Click(object sender, EventArgs e)
{
txt_incoming_message.Clear();
}
}
}
private void btn_clear_Click(object sender, EventArgs e)
{
txt_incoming_message.Text = "";
}
but please keep the question specific, and do some research before asking for help.

C# multi-threading

I have a problem with C# multi-threading.
Form contents are two buttons and two lables.
If I press on the first button, going looping from 1..to 60000, to update label1. ( It works)
If I press on the second button, going looping from 1..to 6000 to update label2,(and my form is lagged). (is not responding)
Please help!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(countNumbers));
thread.IsBackground = true;
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Thread thread2 = new Thread(new ThreadStart(countNumbers2));
thread2.Start();
}
public void countNumbers()
{
try
{
for (int i = 0; i < 60000; i++)
{
this.Invoke((MethodInvoker)delegate()
{
label2.Text = "" + i.ToString();
}
);
}
}
catch (Exception e)
{
}
}
public void countNumbers2()
{
try
{
for (int i = 0; i < 60000; i++)
{
this.Invoke((MethodInvoker)delegate()
{
label4.Text = "" + i.ToString();
}
);
}
}
catch (Exception e)
{
}
}
private void label3_Click(object sender, EventArgs e)
{
}
}
}
Try using a Forms.Timer in the form and poll a value at regular intervals to update the label in a controlled way. Updating the UI the way you do puts way to much load on the system.
A System.Windows.Forms.Timer runs on the GUI thread.
Just make sure to guard the shared resource in some way, this example uses a volatile member to handle thread synchronization.
You do not need the extra Thread.Sleep(10), it is just there to simulate some load.
private volatile int _counter;
private readonly Timer _timer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
_timer.Tick += TimerTick;
_timer.Interval = 20; // ~50 Hz/fps
_timer.Start();
}
void TimerTick(object sender, EventArgs e)
{
_label.Text = _counter.ToString();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CountNumbers) {IsBackground = true};
thread.Start();
}
public void CountNumbers()
{
for (int i = 0; i < 60000; i++)
{
_counter++;
Thread.Sleep(10); // <-- Simulated work load
}
}
Of course, you can easily expand this example to fit your example with two different counters, calculated on separate threads but still using only one Timer to update the entire UI.
You end up with lagging because Invoke (switching to another thread) is very expensive operation and you are calling it too frequently
Try giving this.Refresh() or Application.DoEvents() in your loop
Try to use lock statement
lock (this)
{
label2.Text = "" + i.ToString();
}
you shoud change your code to
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication23
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(countNumbers));
thread.IsBackground = true;
thread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Thread thread2 = new Thread(new ThreadStart(countNumbers2));
thread2.Start();
}
public void countNumbers()
{
try
{
for (int i = 0; i < 60000; i++)
{
this.Invoke((MethodInvoker)delegate()
{
lock (this)
{
label2.Text = "" + i.ToString();
}
}
);
}
}
catch (Exception e)
{
}
}
public void countNumbers2()
{
try
{
for (int i = 0; i < 60000; i++)
{
this.Invoke((MethodInvoker)delegate()
{
lock (this)
{
label4.Text = "" + i.ToString();
}
}
);
}
}
catch (Exception e)
{
}
}
private void label3_Click(object sender, EventArgs e)
{
}
}
}
Put some synchronization mechanism there
You can use
1.lock(this);
2.monitor.enter(obj); and monitor.exit(obj);
lock (this){
label2.Text = "" + i.ToString();
}
monitor.enter(obj);
label2.Text = "" + i.ToString();
monitor.exit(obj);

Categories

Resources