Good day,
I have tried everything to read a few strings from my xbee module on csharp.
but my code keeps telling me the serial port is not open when it reaches the event handler. any help would be appreciated greatly. thanks string display = myserial.ReadLine();
using System;
using System.Management;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
namespace ConsoleApplication2
{
class Program
{
public static SerialPort myserial = new SerialPort();
public string display;
static void Main(string[] args)
{
string[] ports = SerialPort.GetPortNames();
foreach (string p in ports)
{
Console.WriteLine(p);
}
SerialPort myserial = new SerialPort();
myserial.BaudRate = 9600;
myserial.Parity = Parity.None;
myserial.StopBits = StopBits.One;
myserial.DataBits = 8;
myserial.Handshake = Handshake.None;
myserial.RtsEnable = true;
myserial.DtrEnable = true;
myserial.ReadTimeout = 100000;
myserial.PortName = "COM3";
myserial.ReadTimeout = 10000;
myserial.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler);
myserial.Open();
if (myserial != null)
{
if (myserial.IsOpen)
{
Console.WriteLine("connected");
}
}
Console.ReadLine();
}
static void DataRecievedHandler(object sender, SerialDataReceivedEventArgs e)
{
string display = myserial.ReadLine();
}
}
}
Your problem is that you have an ambiguity in your code. 2 Variables with the same name.
The class variable that you declare outside the main:
class Program
{
public static SerialPort myserial = new SerialPort();
and the variable inside the main method:
static void Main(string[] args)
{
SerialPort myserial = new SerialPort();
Inside the method the compiler will take the local variable myserial. You open it and register the event:
myserial.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler);
So far everything is fine. But outside the Main method this SerialPort myserial does not exist. That means when you try to access myserial inside the DataRecievedHandler method the compiler "thinks" that you mean the first variable on class level! But this SerialPort has never been opened! Therefore it gives you the error.
You can solve it by using the sender object inside the event. Since the open SerialPort fires this event:
static void DataRecievedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = sender as SerialPort;
if(port != null)
{
string display = port.ReadLine();
}
}
Note: This variable display exist only inside the DataRecievedHandler method. You cannot use it in the main. Because you declare it again. This is a local variable which is not the same as you have declared on class level! remove the string and the class level variable will be used:
make it:
display = port.ReadLine();
2.
You can also solve it by simply removing the declaration of the SerialPort myserial variable inside the Main method. Probably would be simpler ;)
Just remove this line inside the Main method:
SerialPort myserial = new SerialPort();
Related
I am trying to make a program for controlling axis servos but have a small problem with sending values to the Arduino through serial (USB). It seems data don't arrive in the correct format. For purpose of testing, I made a special Arduino code to see what's wrong.
Arduino code:
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
String received;
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available()>0)
{
received=Serial.readString();
}
Serial.println("received: "+received);
}
C# code:
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.Threading;
namespace ServoControl
{
public partial class Form1: Form
{
public Form1()
{
InitializeComponent();
}
SerialPort Sp = new SerialPort();
String AngleX = "0";
String AngleY = "0";
String AngleZ = "0";
String rec = "";
private void Form1_Load(object sender, EventArgs e)
{
Sp.PortName = "COM8";
Sp.BaudRate = 9600;
Sp.DataReceived += Sp_DataReceived;
}
private void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
rec=Sp.ReadLine();
}
//when value changed on slider
private void xAxisServo_Scroll(object sender, EventArgs e)
{
if (AngleX!= xAxisServo.Value.ToString())
{
AngleX = xAxisServo.Value.ToString(); valueXaxis.Text = AngleX;
}
if (Sp.IsOpen == true & int.Parse(AngleX) <= 180)
{
Sp.WriteLine(AngleX.ToString());
}
else
{
Sp.Open();
}
}
//when value changed in value box
private void valueXaxis_TextChanged(object sender, EventArgs e)
{
if (int.TryParse(valueXaxis.Text, out int res)==true && int.Parse(valueXaxis.Text)<=180)
{
AngleX = valueXaxis.Text;
xAxisServo.Value = int.Parse(AngleX);
}
if (int.TryParse(valueXaxis.Text, out int res2) == true && int.Parse(valueXaxis.Text) > 180)
{
AngleX = "180";
}
if (Sp.IsOpen == false)
{
Sp.Open();
}
if (Sp.IsOpen == true)
{
Sp.WriteLine(AngleX.ToString());
}
}
private void timer1_Tick(object sender, EventArgs e)
{
textBox1.Text = rec;
}
}
}
I was able to send one value for axis X by function Serial.parseInt(); I was able to read a value from a string in Arduino, but I need to send more than one and I have problem with sending and receiving string.
I have tested a lot with Arduino serial monitor and it seems when sending through builtin monitor in Arduino IDE it works as expected got correct string back, but when using C# checking through textbox1 it shows only received and when not interrupted shows an only bunch of nonsense changing every second.
In reaction to that, I've tried to replace WriteLine with Write because I don't know the background of Arduino very well so I don't how Arduino proceeds data using Serial.readString();.
I've tried to find how builtin serial monitor in Arduino IDE works if in C# or if not in C# at least how are data send.
Any idea why I am getting different results with IDE serial monitor and C#.
Concatenate the Serial.read then add a terminating character to cut the concatenation:
char received;
while(Serial.available()>0)
{
if(received=='#') // put the # in the end of your data
{
Serial.println("received: "+String(received));
break;
}
received+=Serial.read();
}
This question already has answers here:
SerialPort not receiving any data
(3 answers)
Closed 8 years ago.
I wanna read from my sensors' data from serial ports, and i can read the name of the ports but i can't receive data from them... i'm new in #c and serial port coding, thanks before~
And here's my try:
using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
//----------------------------------------------------- GLOBAL PARAMETER ------------------------------------------------------
//---serial port objects
static private List <SerialPort> _serialPort = new List<SerialPort>();
//---serial port read buffer
static private List <byte[]> _buffer = new List<byte[]>();
//---length of the port list
static private int _length;
//--------------------------------------------------- INIT FUNCTIONS ----------------------------------------------------------
//---init main function
static private void initFunction(){
//create the serial port objs
createPortObj();
//create the buffers
createBuffer();
//init a clock
//init the ports' name
return;
}
//---Set the port objs
static private void setPortOption(int i) {
SerialPort tPort = _serialPort[i];
//set options
tPort.BaudRate = 9600;
tPort.Parity = Parity.None;
tPort.StopBits = StopBits.One;
tPort.DataBits = 8;
tPort.Handshake = Handshake.None;
//set the datareceived function
//tPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
tPort.DataReceived += DataReceivedHandler;
tPort.Open();
return;
}
//---Create the port objs
static private void createPortObj(){
// Get a list of serial port names.
string[] _names = SerialPort.GetPortNames();
_length = _names.Length;
//create the objs
for(int i=0; i < _length; i++)
{
Console.WriteLine(_names[i]);
//create the port objects
_serialPort.Add(new SerialPort(_names[i]));
//init the port object
setPortOption(i);
}
return;
}
//---Create the buffer
static private void createBuffer() {
//create buffer for each port obj
for (int i = 0; i < _length; i++){
byte[] bufferOne = new Byte[_serialPort[i].BytesToRead];
_buffer.Add(bufferOne);
}
return;
}
//-------------------------------------------------- FEATURED FUNCTION ----------------------------------------------------
//---Transmit the code
//---Data received handler
static public void DataReceivedHandler(Object sender, SerialDataReceivedEventArgs e){
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
//Receive the data from serial ports
for (int i=0; i<_length; i++){
int temp;
temp = _serialPort[i].Read(_buffer[i], 100, _buffer[i].Length);
Console.WriteLine(temp);
}
return;
}
//-------------------------------------------------- RETRIVE FUNCTION ----------------------------------------------------
//---Retrive the source
static private void retriveFunction(){
//close the serial ports
foreach (SerialPort port in _serialPort){
port.Close();
}
return;
}
//-------------------------------------------------- MAIN -----------------------------------------------------------------
//---main function
static void Main(string[] args){
//init function, and open the
initFunction();
int[] num = new int[_length];
for (int i = 0; i < _length; i++){
num[i] = _serialPort[i].Read(_buffer[i], 0, _buffer[i].Length);
}
//check the result of the read function
Console.Write(num[0]);
//on serial port receiving
//retrive the source
retriveFunction();
Console.ReadLine();
}
}
}
thanks again~
I think your code is not wait for data receive.Before your sensors sends back data,your code is finish,program is end,you should handle data in a new thread or in DataReceived event.
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));
}
I saw that similar topics were posted on this forum, but I simply don't understand how to send AT commands and receive a response. (I started to program in C# several months ago. I'm still an n00b, but I'm working hard to learn it...).
I need to create application which would only receive SMS message through GSM USB dongle. So far I managed to create app that will recognize and connect modem through COM ports that is available. Now I need to push AT commands for receiving messages and displaying them into a textBox. I was wondering if anyone can spare few minutes to explain the process to me, and modify my code with comments so I can finally learn and understand how to use serialPort for communication. What I need to know, when SMS is sent, does this message is received and stored by GSM modem (and it is stored until I send some requests to read them or do I need to send some event that would trigger GSM modem to collect message from ISP)? how to push AT commands and receive their response (I only know that is done by using serialPort object, but doesn't have clue how to do it...)
This is my method for receiving (which I'm stuck BTW... :))
private void receiveMessage()
{
//commclass is only a class for getting COM port, baud rate and timeout
CommClass cc = new CommClass();
cc.setParameters();
serialPort1.PortName = cc.getPort();
serialPort1.BaudRate = cc.getBaud();
serialPort1.ReadTimeout = cc.getTimeout();
serialPort1.Open();
if (!serialPort1.IsOpen)
{
//MessageBox is written in Croatian language, it is only an alert to check the configuration because port is not opened...
MessageBox.Show("Modem nije spojen, molimo provjerite konfiguraciju...!");
//timer1.Stop();
}
else
{
//this.label2.Text = serialPort1.PortName;
//this.label2.Visible = true;
//this.label3.Visible = true;
//this is where I need to place a code for receiving all SMS messages
this.serialPort1.Write("AT+CMGL=\"REC UNREAD\"");
}
serialPort1.Close();
}
If anyone willing to help, I would appreciate that, if not I would have to deal with it by my self (probably spent few hours/days until I figure it out...)
In both cases, thank you anyway... Cheers.
Sorry for waiting for my reply, been busy lately.
In short this is my code for getting message from GSM USB dongle. I hope that it will be useful to someone...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
namespace SMSget
{
public partial class SMSLogPanel : UserControl
{
SerialPort sp;
int datab = 0;
bool dtr = false;
bool encod;
Handshake h;
Parity p;
int wtimeout = 0;
StopBits s;
#region default constructor
public SMSLogPanel()
{
InitializeComponent();
this.sp = serialPort1 = new SerialPort();
this.datab = serialPort1.DataBits = 8;
this.dtr = serialPort1.DtrEnable = true;
this.encod = serialPort1.Encoding.Equals("iso-8859-1");
this.h = serialPort1.Handshake = Handshake.RequestToSend;
this.p = serialPort1.Parity = Parity.None;
this.wtimeout = serialPort1.WriteTimeout = 300;
this.s = serialPort1.StopBits = StopBits.One;
checkLink();
}
#endregion
#region checking communication and setting user controls...
private void checkLink()
{
GetValues value = new GetValues();
string com = value.getPort();
int baud = value.getBaud();
int timeot = value.getTimeout();
serialPort1.PortName = com;
serialPort1.BaudRate = baud;
serialPort1.ReadTimeout = timeot;
serialPort1.Open();
if (serialPort1.IsOpen)
{
label1.Visible = true;
}
else
{
MessageBox.Show("Komunikacija sa modemom se ne može uspostaviti, molimo postavite novu konfiguraciju...!");
this.Controls.Clear();
SMSConfigPanel cfg = new SMSConfigPanel();
cfg.Show();
this.Controls.Add(cfg);
}
serialPort1.Close();
}
#endregion
#region panel load method
private void SMSLogPanel_Load(object sender, EventArgs e)
{
setGSM();
}
#endregion
#region execute serialport handler
public void getMessage()
{
if (serialPort1.IsOpen)
{
serialPort1.DataReceived += new SerialDataReceivedEventHandler(getResponse);
}
else
{
MessageBox.Show("Nije moguće zaprimiti poruku, komunikacijski port nije otvoren...1");
return;
}
}
#endregion
#region get response from modem
public void getResponse(object sender, SerialDataReceivedEventArgs e)
{
SerialPort serPort = (SerialPort)sender;
string input = serPort.ReadExisting();
if (input.Contains("+CMT:"))
{
if (input.Contains("AT+CMGF=1"))
{
string[] message = input.Split(Environment.NewLine.ToCharArray()).Skip(7).ToArray();
textBox1.Text = string.Join(Environment.NewLine, message);
}
this.Invoke((MethodInvoker)delegate
{
textBox1.Text = input;
});
}
else
{
return;
}
}
#endregion
#region initialize GSM
private void setGSM()
{
serialPort1.Open();
if (!serialPort1.IsOpen)
{
MessageBox.Show("Problem u komunikaciji sa modemom, port nije otvoren...!");
}
serialPort1.Write("AT+CMGF=1" + (char)(13));
serialPort1.Write("AT+CNMI=1,2,0,0,0" + (char)(13));
}
#endregion
#region setiranje timer-a...
private void timer1_Tick_1(object sender, EventArgs e)
{
timer1.Stop();
getMessage();
timer1.Start();
}
#endregion
}
}
This was only code for testing so it works but there is lot to fix and improve. Basically it will be a nice start for all that are searching something like this...
cheers.
I try to subscribe a event handler to the data received event. Seems like I cant specify the event handler function name. I dont understand why
myComPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived); is giving me error message.
Here is the problem, hope anyone can answer it.
a busy cat http://img827.imageshack.us/img827/5904/20120125102247.png
a busy cat http://img444.imageshack.us/img444/3855/20120125102202.png
namespace serialport
{
public class Program
{
internal List<Byte> portBuffer = new List<Byte>(1024);
static void Main()
{
//1. find available COM port
string[] nameArray = null;
string myComPortName = null;
nameArray = SerialPort.GetPortNames();
if (nameArray.GetUpperBound(0) >= 0)
{
myComPortName = nameArray[0];
}
else
{
Console.WriteLine("Error");
return;
}
//2. create a serialport object
// the port object is closed automatically by use using()
SerialPort myComPort = new SerialPort();
myComPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
myComPort.PortName = myComPortName;
//the default paramit are 9600,no parity,one stop bit, and no flow control
//3.open the port
try
{
myComPort.Open();
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message);
}
//Add timeout, p161
//reading Bytes
byte[] byteBuffer = new byte[10];
Int32 count;
Int32 numberOfReceivedBytes;
myComPort.Read(byteBuffer, 0, 9);
for (count = 0; count <= 3; count++)
{
Console.WriteLine(byteBuffer[count].ToString());
}
}
//The event handler should be static??
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int numberOfBytesToRead;
numberOfBytesToRead = myComPort.BytesToRead;
byte[] newReceivedData = new byte[numberOfBytesToRead];
myComPort.Read(newReceivedData, 0, numberOfBytesToRead);
portBuffer.AddRange(newReceivedData);
ProcessData();
}
private void ProcessData()
{
//when 8 bytes have arrived, display then and remove them from the buffer
int count;
int numberOfBytesToRead = 8;
if (portBuffer.Count >= numberOfBytesToRead)
{
for (count = 0; count < numberOfBytesToRead; count++)
{
Console.WriteLine((char)(portBuffer[count]));
}
portBuffer.RemoveRange(0, numberOfBytesToRead);
}
}
}
}
First, since method Main is static, you can only call other static methods in the same class. As it is, comPort_DataReceived is declared as an instance method, the following code should fix the assignment of the event handler:
static void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// ...
}
Second, since myComPort is defined in Main, it will not be visible in comPort_DataReceived. You have two choices: either declare myComPort as a static member of your class, or use the sender argument of the event handler:
static void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = (SerialPort)sender;
// ...
}
In your event handler, myComPort isn't in scope - it's declared locally in your main() method. I would suggest that you extract the com port handling into a class and make myComPort a member variable of that class.
Also, your comments note that the SerialPort class has a managed resource that it needs to dispose of using the IDisposable / Using pattern, but you don't have a using block wrapping the access to the comm port.
Last, the method you are adding as the event handler exists as an instance member rather than as a static member; to access it from the main() method's static scope, you need to either grab it from an instance of the class or make the method static.
Tetsujin no Oni's answer is the ideal way to handle your issue with scope. Another approach that also works is to declare myComPort as a static member of your Program, e.g.:
internal List<Byte> portBuffer = new List<Byte>(1024);
private SerialPort myComPort = new SerialPort();
Then simply remove the myComPort declaration from your main method.