rs232 communication C# data read issue - c#

I have a problem regarding the rs232 communication with a Melfa rv-2aj robot. I am sending to commands in ASCII and when the robot replies via rs232 I get something like this: ??QY?e0?L???0???0???. My first thought was that I am not doing a proper conversion from ASCII when I read from RS232, but if I convert this set of charaters to a unicode output I get some chinesse characters and this should not be right. As the robot sends a reply via rs232, makes me think that my implementation is not wrong , but maybe my approch has some faults in it. I think "?" represent ASCII characters that are not properly displayed.
Below I have attached the source code to my application.
Can somebody give some pointers on what I doing wrong when I am reading from the serial that i get his kind of ouput?
I would really appreciate any kind of help, suggestion or reference.
Thank you very much.
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;
namespace RS232_Communication
{
public partial class Form1 : Form
{
private SerialPort COM_port = new SerialPort();
private byte[] _array = new byte[] {0};
public Form1()
{
InitializeComponent();
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.SelectedIndex = 2;
DATAUnit.Items.Add("5");
DATAUnit.Items.Add("6");
DATAUnit.Items.Add("7");
DATAUnit.Items.Add("8");
DATAUnit.Items.Add("9");
DATAUnit.SelectedIndex = 3;
ParityUnit.Items.Add("None");
ParityUnit.Items.Add("Odd");
ParityUnit.Items.Add("Even");
ParityUnit.Items.Add("Mark");
ParityUnit.Items.Add("Space");
ParityUnit.SelectedIndex = 2;
STOPUnit.Items.Add("One");
STOPUnit.Items.Add("Two");
STOPUnit.SelectedIndex = 1;
this.Load += new EventHandler(Form1_Load);
SendText.KeyPress +=new KeyPressEventHandler(SendText_KeyPress);
COM_port.DataReceived +=new SerialDataReceivedEventHandler(COM_port_DataReceived);
}
private string GetString(byte[] bBuffer, int iIndex, int iLen, bool bUni)
{
string sBuffer;
if (bUni) sBuffer = Encoding.Unicode.GetString(bBuffer, iIndex, iLen);
else sBuffer = Encoding.ASCII.GetString(bBuffer, iIndex, iLen);
//return the string
return sBuffer;
}
void COM_port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
ReceiveText.Invoke(new EventHandler(delegate
{
byte[] data = new Byte[COM_port.BytesToRead];
COM_port.Read(data, 0, data.Length);
//string read = GetString(data, 0, data.Length, true);
string read = System.Text.Encoding.ASCII.GetString(data);
ReceiveText.AppendText(read);
//ReceiveText.AppendText(COM_port.ReadExisting());
}
)
)
;
}
void Form1_Load(Object sender, EventArgs e)
{
foreach (string COMstr in SerialPort.GetPortNames())
COMPort.Items.Add(COMstr);
if (COMPort.Items.Count > 0)
COMPort.SelectedIndex = 0;
else MessageBox.Show("No COM Ports available");
}
private void ConnectBTN_Click(object sender, EventArgs e)
{
try
{
if (COM_port.IsOpen)
{
COMPort.Enabled = true;
BAUDRate.Enabled = true;
ParityUnit.Enabled = true;
STOPUnit.Enabled = true;
DATAUnit.Enabled = true;
COM_port.DtrEnable = false;
COM_port.RtsEnable = false;
ConnectBTN.Text = "Connect";
COM_port.Close();
}
else
{
COM_port.BaudRate = int.Parse(BAUDRate.Text);
COM_port.Parity = (Parity)Enum.Parse(typeof(Parity), ParityUnit.Text);
COM_port.StopBits = (StopBits)Enum.Parse(typeof(StopBits), STOPUnit.Text);
COM_port.DataBits = int.Parse(DATAUnit.Text);
COM_port.PortName = COMPort.Text;
//COM_port.DtrEnable = true;
//COM_port.RtsEnable = true;
COM_port.Open();
COM_port.ReadTimeout = 2000;
COM_port.WriteTimeout = 2000;
COMPort.Enabled = false;
BAUDRate.Enabled = false;
ParityUnit.Enabled = false;
STOPUnit.Enabled = false;
DATAUnit.Enabled = false;
ConnectBTN.Text = "Disconnect";
}
}
catch
{
MessageBox.Show("Connection Error");
}
}
public void WriteBytes(byte[] array)
{
COM_port.Write(array, 0, array.Length);
}
public void WriteBytes(byte[] array, int index, int length)
{
COM_port.Write(array, index, length);
}
public void WriteLine(String line)
{
//string s="";
//foreach (byte b in StringToBytes(line + "\r\n"))
// s = s + b.ToString();
//COM_port.WriteLine(s);
WriteBytes(StringToBytes(line + "\r\n"));//CR + LF
}
public static byte[] StringToBytes(string input)
{
return Encoding.ASCII.GetBytes(input);
}
private void SendBTN_Click(object sender, EventArgs e)
{
if (SendText.Text != "")
{
WriteLine(SendText.Text);
//COM_port.WriteLine(SendText.Text);
SendText.Text = "";
}
}
void SendText_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13)
{
WriteLine(SendText.Text);
//COM_port.WriteLine(SendText.Text);
SendText.Text = "";
}
}
}
}

I managed to figure out what was the problem. In the manual for the rv-2aj it is specified that in order to use the rs232 communication the following parameters have to be set: baud rate 9600, parity even, stop bits 2, data bits 8. So I configured my communication this way, and when I sent data to the controller I would receive strange messages as I showed in my previous post. It seems that the configuration for communication on the robot side was different then mine, so I changed the value for parity to none and the stop bits to one and now everything works as expected. I get proper feedback from the robot and the commands work. The code I wrote in c# works fine, no necessary modifications required.

Related

Waiting for a serial message before proceeding in C#

I'm currently working on an interface between C# and an arduino project. I'm using the serial port to send and receive messages from the arduino and so far everything looks fine.
However I came to a point, where I want to send a string to the arduino and wait for a response until I'm going to send over the next string.
I figured that I cannot simply timeout here since my RichTextField is also going to freeze and the "OK*" message cannot be read from there.
I've read about some other solutions online but since I'm very new to C# I hope that somebody can point me in the right direction.
Best regards
//Edited the post with a full code example:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
namespace interface_test
{
public partial class Form1 : Form
{
string serialDataIn;
public Form1()
{
InitializeComponent();
Enable_Console();
comboBox_baudRate.Text = "115200";
comboBox_comPort.Text = "COM3";
string[] portLists = SerialPort.GetPortNames();
comboBox_comPort.Items.AddRange(portLists);
}
private void Form1_Load(object sender, EventArgs e)
{
}
/* erase textbox contents */
private void button_clearLog_Click(object sender, EventArgs e)
{
richTextBox_receiveMsg.Text = "";
}
/* listening to the serial port */
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
serialDataIn = serialPort1.ReadExisting();
this.Invoke(new EventHandler(ShowData));
}
/* process the serial data */
public void ShowData(object sender, EventArgs e)
{
string trimmedMsg = serialDataIn;
richTextBox_receiveMsg.Text += trimmedMsg;
if (trimmedMsg.Contains("Initialization done."))
{
button_detectCEM.Enabled = false;
}
}
/* open COM-port to arduino */
private void button_openCom_Click(object sender, EventArgs e)
{
try
{
serialPort1.PortName = comboBox_comPort.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox_baudRate.Text);
serialPort1.Open();
Enable_Console();
button_detectCEM.Enabled = true;
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
/* close COM-port to arduino */
private void button_closeCom_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
try
{
serialPort1.Close();
Enable_Console();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
private void button_fileBrowser_Click(object sender, EventArgs e)
{
openAndWrite();
}
public void openAndWrite()
{
/* load a .txt file */
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = "c:\\";
openFileDialog1.Filter = "TXT files (*.txt)|*.txt";
openFileDialog1.FilterIndex = 0;
openFileDialog1.RestoreDirectory = true;
string selectedFile = "";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
selectedFile = openFileDialog1.FileName;
}
/* parse file and store it in data[] */
byte[] data;
using (FileStream fsSource = new FileStream(selectedFile, FileMode.Open, FileAccess.Read))
{
data = new byte[fsSource.Length];
int numBytesToRead = (int)fsSource.Length;
int numBytesRead = 0;
while (numBytesToRead > 0)
{
// Read may return anything from 0 to numBytesToRead.
int n = fsSource.Read(data, numBytesRead, numBytesToRead);
// Break when the end of the file is reached.
if (n == 0)
break;
numBytesRead += n;
numBytesToRead -= n;
}
numBytesToRead = data.Length;
}
for (int i = 0; i < BitConverter.ToInt32(blockLength, 0); i++)
{
data[i] = data[offset + i];
}
/* write data block */
offset = 0;
while (offset < data.Length)
{
byte[] dataString = new byte[6];
string blockMsg = "FFFFFF";
int start = offset;
offset += 6;
if (offset > data.Length) offset = data.Length;
for (int i = 0; i < 6; i++)
{
if ((start + i) < data.Length) dataString[i] = data[start + i];
}
blockMsg += BitConverter.ToString(dataString).Replace("-", string.Empty);
blockMsg += "*";
serialPort1.Write(blockMsg);
//Wait for "OK*" before next Message...
}
}
}
}
}
There's a few ways that you could solve this. My approach would be to make use of the TaskCompletionSource class and a lambda function. Here's a rough example, you'll need to make the method containing this code async, and potentially have it return a Task to await it all the way up the chain.
var tcs = new TaskCompletionSource<string>();
serialPort1.DataReceived += (s, e) =>
{
SerialPort sp = (SerialPort)s;
string newData = sp.ReadExisting();
tcs.SetResult(newData);
}
serialPort1.Write(Msg);
var dataFromPort = await tcs.Task;
I'm away from an IDE, nor do I have access to all your code, so without the wider context it's hard to know exactly what else you might need. But I've done some Arduino work in the past, and this is how I solved the problem.
EDIT :: Thinking about it, you might (test it first) run into a problem because that event isn't being unsubscribed from and the code is running in a loop. IF that turns out to be a problem, you could make use of C#'s Local Functions to handle the event subscription, like this:
var tcs = new TaskCompletionSource<string>();
void localHandler(object s, SerialDataReceivedEventArgs e)
{
serialPort1.DataReceived -= localHandler;
SerialPort sp = (SerialPort)s;
string newData = sp.ReadExisting();
tcs.SetResult(newData);
};
serialPort1.DataReceived += localHandler
serialPort1.Write(Msg);
var dataFromPort = await tcs.Task;
It might look a little strange, but it's certainly cleaner (IMO) then needing to keep track of instance variables and manually manage threads.
EDIT2 :: Tested when I was sat at a computer, if I understand your requirement correctly, this should do everything you need.
This may take you in the right direction.
It might be useful in this case to separate the data received from the display update thread. Since the data received is an event, it will be coming in on its own thread, likely from some component - in this case the serial port.
The form, and all the display objects on it, run on a single thread, owned by the form.
You can use a timer as a background thread to make the leap between what was received and what you want to do/display.
For example, one way is to use a concurrent queue and a timer to poll the status of the queue.
using System.Collections.Concurrent;
private ConcurrentQueue<string> dataIn = new ConcurrentQueue<string>();
private System.Threading.Timer timer = new System.Threading.Timer(CheckQue,null,TimeSpan.FromSeconds(1),TimeSpan.FromSeconds(1));
private void CheckQue(object state)
{
while(dataIn.TryDequeue(out var data))
{
ShowData(data);
if (data.Contains("OK*"))
{
//Do Something
//Better yet raise an event that does something
Msg += BitConverter.ToString(dataString).Replace("-", string.Empty);
Msg += "*";
serialPort1.Write(Msg);
}
}
}
Then modify your above code to add to the queue when data is received
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
dataIn.Enqueue(SerialPort1.ReadExisting());
}
And since your using a windows form, you need to make sure you don't get a cross-threaded operation when updating it, by marshaling the update onto the form's thread like so.
public static void ShowData(string data)
{
if (this.InvokeRequired)
{
var del = new MethodInvoker(() => ShowData(data));
try
{
this.Invoke(del);
return;
}
catch
{ }
}
richTextBox_receiveMsg.Text += data;
}
EDIT based on your revised question:
To modify for sending blocks of a file you could added another Que
private ConcurrentQueue<string> dataOut = new ConcurrentQueue<string>();
Then when you read the file, do whatever processing you need and put the final output in the queue and finish by sending the first block.
public void openAndWrite()
{
/* load a .txt file */
.
.
.
while (offset < data.Length)
{
.
.
blockMsg += BitConverter.ToString(dataString).Replace("-", string.Empty);
blockMsg += "*";
dataOut.Enqueue(blockMsg);
}
SendBlock();
}
Where SendBlock looks like this
private void SendBlock()
{
if(dataOut.TryDequeue(out var data))
{
serialPort1.Write(data);
}
}
Then just modify the timer handler to send blocks as needed
private void CheckQue(object state)
{
while (dataIn.TryDequeue(out var data))
{
ShowData(data);
if (data.Contains("OK*"))
{
SendBlock();
}
}
}

Collection not modified,Enumeration operation may not execute- in mschart

I am using Fiddler API. In this API I am using AfterSessionComplete event. This event fires whenever I am accessing any page on the browser. This event also calls the method i.e. (drawGraph_2(List<Fiddler.Session>)). The method has the functionality of drawing the graph. I am sharing the code with you. For few requests I am able to draw the graph but once I access too many pages I get this error i.e collection is modified.
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using Fiddler;
using System.Threading;
namespace MSRealTime
{
public partial class Form1 : Form
{
static int i = 0;
List<Fiddler.Session> fs = new List<Session>();
int iSecureEndpointPort = 8877, get = 0, post = 0, threshold_value = 0;
string sSecureEndpointHostname = "localhost";
Proxy oSecureEndpoint;
static int k = 0;
TimeSpan cbr, sbr, cdr;
double rt, request_response_time;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
List<Fiddler.Session> numb = new List<Session>();
//List<Fiddler.Session> removeprev = new List<Fiddler.Session>();
#region AttachEventListeners
Fiddler.FiddlerApplication.BeforeRequest += delegate (Fiddler.Session oS)
{
oS.bBufferResponse = false;
Monitor.Enter(numb);
numb.Add(oS);
Monitor.Exit(numb);
oS["X-AutoAuth"] = "(default)";
};
//this event fires when server response received by fiddler
Fiddler.FiddlerApplication.BeforeResponse += delegate (Fiddler.Session oS)
{
string s = oS.PathAndQuery;
int i = oS.port;
};
//this event fires when a session has been completed
Fiddler.FiddlerApplication.AfterSessionComplete += delegate (Fiddler.Session oS)
{
//URLMonInterop.SetProxyInProcess("127.0.0.1:8888", "<-loopback>");
CheckForIllegalCrossThreadCalls = false;
if (oS.HTTPMethodIs("CONNECT")) { return; }
else
{
label1.Text = numb.Count.ToString();
}
//Monitor.Enter(numb);
numb.Add(oS);
//removeprev.Add(oS);
numb = numb.OrderBy(x => x.id).ToList();
// Monitor.Exit(numb);
//numb.Add(TimeSpan.Parse(oS.Timers.ClientBeginRequest.ToString()).TotalMilliseconds-TimeSpan.Parse(oS.Timers.ClientBeginRequest.ToString()).TotalMilliseconds);
drawGraph_2(numb);
//numb.Clear();
};
#endregion AttachEventListeners
//Fiddler.CONFIG.IgnoreServerCertErrors = true;
FiddlerCoreStartupFlags oFCSF = FiddlerCoreStartupFlags.Default;
try
{
Fiddler.FiddlerApplication.Startup(iSecureEndpointPort, oFCSF);
}
catch (Exception exe) { MessageBox.Show(exe.Message); }
FiddlerApplication.Log.LogFormat("Created endpoint listening on port {0}", iSecureEndpointPort);
FiddlerApplication.Log.LogFormat("Starting with settings: [{0}]", oFCSF);
FiddlerApplication.Log.LogFormat("Gateway: {0}", CONFIG.UpstreamGateway.ToString());
oSecureEndpoint = FiddlerApplication.CreateProxyEndpoint(iSecureEndpointPort, true, sSecureEndpointHostname);
}
private void drawGraph_2(List<Fiddler.Session> numb)
{
//for (; i < numb.Count; i++)
//{
// fs[i] = numb[i];
//}
fs = numb;
//foreach (Session fs in numb)
for(;i<fs.Count;i++)
{
cbr = fs[i].Timers.ClientBeginRequest.TimeOfDay;
sbr = fs[i].Timers.ServerBeginResponse.TimeOfDay;
cdr = fs[i].Timers.ClientDoneResponse.TimeOfDay;
double cbr_millisecond = TimeSpan.Parse(cbr.ToString()).TotalMilliseconds;
double sbr_millisecond = TimeSpan.Parse(sbr.ToString()).TotalMilliseconds;
double cdr_millisecond = TimeSpan.Parse(cdr.ToString()).TotalMilliseconds;
rt = (cdr_millisecond - cbr_millisecond); // page response time
request_response_time = (sbr_millisecond - cbr_millisecond); // request response time
// Add point.
chart1.Series["Series1"].Points.AddXY(fs[i].id, rt);
}
}
}
Your event AfterSessionCompletefires faster than your handler code can process it. So your collection gets modified while you are still iterating it.
You will need to make a copy to have a collection that does not get modified.
You could do this by calling ToList on it as suggested:
fs = numb.ToList();
As you seem to handle it like an array afterwards anyway, you could also create an array straight away:
fs = numb.ToArray();

GUI with Serial Communication C#

I am new to C# and Visual Studio. I have built a GUI to choose the COM port from a MenuStrip in Visual Studio 2013. What I want to know is how can I connect this with serial port communication.
Should I use a another class for serial communication? Or can I do it in the same class? How can it be programmed?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace exo_new
{
public partial class rehab : Form
{
public rehab()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void conndToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void cOM1ToolStripMenuItem_Click(object sender, EventArgs e)
{
cOM1ToolStripMenuItem.Checked = true;
cOM2ToolStripMenuItem.Checked = false;
cOM3ToolStripMenuItem.Checked = false;
cOM4ToolStripMenuItem.Checked = false;
cOM5ToolStripMenuItem.Checked = false;
cOM6ToolStripMenuItem.Checked = false;
cOM7ToolStripMenuItem.Checked = false;
cOM8ToolStripMenuItem.Checked = false;
cOM9ToolStripMenuItem.Checked = false;
cOM10ToolStripMenuItem.Checked = false;
}
private void cOM2ToolStripMenuItem_Click(object sender, EventArgs e)
{
cOM2ToolStripMenuItem.Checked = true;
cOM1ToolStripMenuItem.Checked = false;
cOM3ToolStripMenuItem.Checked = false;
cOM4ToolStripMenuItem.Checked = false;
cOM5ToolStripMenuItem.Checked = false;
cOM6ToolStripMenuItem.Checked = false;
cOM7ToolStripMenuItem.Checked = false;
cOM8ToolStripMenuItem.Checked = false;
cOM9ToolStripMenuItem.Checked = false;
cOM10ToolStripMenuItem.Checked = false;
}
You can use the System.IO.SerialPort class to program the serial port from a .NET application. (The link is to the MSDN documentation for the class, which includes an example program.) If you want more help than that you'll need to provide some of your code and more of an explanation of what you want to do, and when. (For example, user clicks button X and you want to send message Y...)
UPDATE: Thanks for sharing your code so far. Here is how I would implement a simple solution based on what you've started with:
public partial class rehab : Form
{
private string portName = "COM1";
private const int baudRate = 9600;
public Form1()
{
InitializeComponent();
//TODO: Simplify your UI by dynamically creating the COM port names.
// Get the list of available ports on the computer via the following:
//var portNames = SerialPort.GetPortNames();
// Call this to initially mark 'COM1' as checked.
UpdatePortCheckmarks();
}
private void conndToolStripMenuItem_Click(object sender, EventArgs e)
{
var textToSend = this.textBox1.Text;
// Use a try-catch block to log any exceptions that occur.
try
{
// Use a using block to close and dispose of the serial port
// resource automatically. Also, note that the SerialPort
// constructor takes the port name and baud rate here.
// There are also overloads that let you pass the number of
// data bits, parity, and stop bits, if needed.
using (var serialPort = new SerialPort(portName, baudRate))
{
// Open the port before writing to it.
serialPort.Open();
// Send the content of the textbox (with a newline afterwards).
serialPort.WriteLine(textToSend);
}
}
catch (Exception ex)
{
// You could also use MessageBox.Show. Console.WriteLine will
// display errors in your debugger's output window.
Console.WriteLine("ERROR: " + ex.ToString());
}
}
private void cOM1ToolStripMenuItem_Click(object sender, EventArgs e)
{
portName = "COM1";
UpdatePortCheckmarks();
}
private void cOM2ToolStripMenuItem_Click(object sender, EventArgs e)
{
portName = "COM2";
UpdatePortCheckmarks();
}
// .. and so on for each additional port menu item (COM3 through COM10)
// This method lets you share the code for updating the checkmarks on
// the menu items, so your form code will be cleaner.
private void UpdatePortCheckmarks()
{
cOM1ToolStripMenuItem.Checked = portName == "COM1";
cOM2ToolStripMenuItem.Checked = portName == "COM2";
cOM3ToolStripMenuItem.Checked = portName == "COM3";
cOM4ToolStripMenuItem.Checked = portName == "COM4";
cOM5ToolStripMenuItem.Checked = portName == "COM5";
cOM6ToolStripMenuItem.Checked = portName == "COM6";
cOM7ToolStripMenuItem.Checked = portName == "COM7";
cOM8ToolStripMenuItem.Checked = portName == "COM8";
cOM9ToolStripMenuItem.Checked = portName == "COM9";
cOM10ToolStripMenuItem.Checked = portName == "COM10";
}
}
I've included a 'TODO' comment as a suggestion on how you can further improve your code, but that's optional (and should be a new question if you do have any questions about it).

Get Weight From Weigh Bridge Machine Using Serial Port in C#

i am develop application for getting weight from weigh Bridge machine using C#.Net.i am trying lot of ways but,doesn't read correct data format weight from weigh bridge machine.i am getting ouput like ?x???????x?x?x??x???x??x???x???x? continuously get from serial port.i want to get weight from weigh bridge machine my code is listed below:
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.IO;
namespace SerialPortTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
String a = "";
private void button1_Click(object sender, EventArgs e)
{
serialPort1 = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
if (serialPort1.IsOpen == false)
{
serialPort1.Open();
}
timer1.Start();
button1.Enabled = false;
button2.Enabled = true;
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
a = a + serialPort1.ReadExisting();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (a.Length != 0)
{
textBox1.AppendText(a);
a = "";
}
}
private void button2_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen == true)
{
serialPort1.Close();
button2.Enabled = false;
button1.Enabled = true;
}
}
private void Form1_Load(object sender, EventArgs e)
{
if (serialPort1.IsOpen == true)
{
button1.Enabled = false;
button2.Enabled = true;
}
else
{
button1.Enabled = true;
button2.Enabled = false;
}
}
}
}
my code is append text from serial port data to textbox but,it's shows only like ?xxx?xxxx?xxxx?
can any one help me how to get weight from serial port using c#
Thanks For Reading My Post!
You are using ReadExisting(), that method tries to convert the bytes received by the port into a string. You'll get a question mark if that conversion fails. The default Encoding is ASCII, a byte value between 128 and 255 is not an ASCII character and thus produces a ?
Several possible reasons, roughly in order of likelihood:
Using the wrong baud rate, in particular guessing too high.
The device might be sending binary data, not strings. Which requires using Read() instead of ReadExisting and decoding the binary data.
Electrical noise picked up by a long cable that isn't shielded well enough. Easy to eliminate as a possible reason by disconnecting the cable at the bridge end. If that stops the data then it isn't likely to be noise.
Be sure to thoroughly read the manual. Contact the vendor of the device if you don't have one or can't make sense of it.
This code will be reading weightbridge continuously in background. Be sure to connect the pc with serial port. Also in design page Form1.cs[Design] you need to add Serial port from the toolbox. This code works for me, I hope it works for you too...
public partial class Form1 : Form
{
//Initialize the port and background Worker
private SerialPort port;
private BackgroundWorker backgroundWorker_Indicator;
public Form1()
{
backgroundWorker_Indicator = new BackgroundWorker();
backgroundWorker_Indicator.WorkerSupportsCancellation = true;
backgroundWorker_Indicator.DoWork += new DoWorkEventHandler(Indicator_DoWork);
//set the port according to your requirement.
port = new SerialPort("COMM2", 2400, Parity.None, 8, StopBits.One);
port.DataReceived += new SerialDataReceivedEventHandler(this.Indicator_DataReceived);
}
//button which starts the method. You can also put the method in Form1_Load()
private void SerialPortButton(object sender, EventArgs e)
{
StartStopIndicator();
}
private void StartStopIndicator()
{
try
{
port.Open();
backgroundWorker_Indicator.RunWorkerAsync();
}catch (Exception ea)
{
MessageBox.Show("13 "+ea.Message);
}
}
// Not a button. Just a methood.
private void Indicator_DoWork(object sender, DoWorkEventArgs e)
{
}
private void Indicator_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
string str = StripNonNumeric(port.ReadLine());
UpdateWeightOnUI(str);
}
catch (Exception eb)
{
MessageBox.Show("12"+eb.Message);
}
}
private void UpdateWeightOnUI(string Weight)
{
try
{
// A label named weightLabel from the toolbox. This will keep updating on weight change automatically
if (weightLabel.InvokeRequired)
{
this.Invoke((Delegate)new Form1.SetTextCallBack(this.UpdateWeightOnUI), (object)Weight);
}
else
{
weightLabel.Text = Weight;
}
}
catch (Exception ec)
{
MessageBox.Show("11"+ec.Message);
}
}
// This method will remove all other things except the integers
private string StripNonNumeric(string original)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (char c in original)
{
if (char.IsDigit(c))
stringBuilder.Append(c);
}
return stringBuilder.ToString();
}
private delegate void SetTextCallBack(string text);

C# Reading Serial data from sensor

I want to make a GUI for my device to show the value of each sensor. My device send data with this format
:1*895*123;
:1*987*145;
* is use to separate data from sensors
; is for the end of data
: is for start of data in next loop
I have variables dot, Rx1 and Ry2 to storing the data and show it on label, but looks like my program didn't works.. here's 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;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
string TestText, Rx1, Ry1, dot;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM7";
serialPort1.BaudRate = 2400;
serialPort1.Open();
if (serialPort1.IsOpen)
{
button1.Enabled = false;
button2.Enabled = true;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
button1.Enabled = true;
button2.Enabled = false;
}
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
TestText = serialPort1.ReadExisting();
string[] nameArray = TestText.Split ('*');
foreach (string name in nameArray)
{
dot = nameArray[0];
Rx1 = nameArray[1];
Ry1 = nameArray[2];
}
}
private void label3_Click(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
label3.Text = dot;
posY.Text = Ry1;
posX.Text = Rx1;
}
//this.Invoke(new EventHandler(DisplayText));
}
}
I'm still new in c# and not so good with it.. so i need help. thanks before.
Are you sure that you're getting complete packets in the data received method? if not you'll need to buffer them up to be sure it's working properly.
You could try something like this.
// A buffer for the incoming data strings.
string buffer = string.Empty;
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// buffer up the latest data.
buffer += serialPort1.ReadExisting();;
// there could be more than one packet in the data so we have to keep looping.
bool done = false;
while (!done)
{
// check for a complete message.
int start = buffer.IndexOf(":");
int end = buffer.IndexOf(";");
if (start > -1 && end > -1 && start < end)
{
// A complete packet is in the buffer.
string packet = buffer.Substring(start + 1, (end - start) - 1);
// remove the packet from the buffer.
buffer = buffer.Remove(start, (end - start) + 1);
// split the packet up in to it's parameters.
string[] parameters = packet.Split('*');
rx1 = parameters[0];
ry1 = parameters[1];
dot = parameters[2];
}
else
done = true;
}
If you getting just one chunk of data after reading. For example :1*895*123;
TestText = serialPort1.ReadExisting();//:1*895*123;
string[] nameArray = TestText.Split(new []{":", "*", ";"}, StringSplitOptions.RemoveEmptyEntries);
label3.Text = nameArray[0];//1
posY.Text = nameArray[1]; //895
posX.Text = nameArray[2]; //123
and if you receive :1*895*123; :1*987*145;
var chunks = s.Split(new [] { ":", ";", " "}, StringSplitOptions.RemoveEmptyEntries);
foreach (var chunk in chunks)
{
string[] data = chunk.Split(new [] { "*" }, StringSplitOptions.RemoveEmptyEntries);
label3.Text = data[0];
posY.Text = data[1];
posX.Text = data[2];
}
But then in labels you just see latest chunk data, so you need store a list of your data. For example you can create class:
class chunkData
{
public string dot;
public string posX;
public string posY;
}
and use it like this:
private List<chunkData> dataList = new List<chunkData>();
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
TestText = serialPort1.ReadExisting();
var chunks = TestText.Split(new [] { ":", ";", " "}, StringSplitOptions.RemoveEmptyEntries);
foreach (var chunk in chunks)
{
string[] data = chunk.Split(new [] { "*" }, StringSplitOptions.RemoveEmptyEntries);
dataList.Add(new chunkData(){dot=data[0], posX=data[1], posY=data[2]})
}
//display dataList to DataGridView or other control
}
EDIT: here is what you can do if you receiving data symbol by symbol:
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string temp = serialPort1.ReadExisting();
if(temp == ";") //OK we have end of data lets process it
splitAndDisplay();
else
TestText += temp;
}
private void splitAndDisplay()
{
string[] nameArray = TestText.Split(new []{":", "*"}, StringSplitOptions.RemoveEmptyEntries);
this.Invoke(new Action(() =>
{
label3.Text = nameArray[0];
posY.Text = nameArray[1];
posX.Text = nameArray[2];
}));
TestText = "";
}

Categories