I got some trouble with my console application. I'm trying to retrieve data from a serial connection with a barcode scanner.
The problem is that:
- first read is perfect;
- second read results incorrect unless I wait approximately one minute.
Here is the code:
using System;
using System.IO.Ports;
class PortDataReceived
{
public static void Main()
{
SerialPort mySerialPort = new SerialPort("COM10");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.RequestToSend;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.WriteLine(indata);
}
}
and here is the result of 2 reads of the same barcode without waiting enough time from the first to the second read:
Press any key to continue...
Data Received:
229000400718
Data Received:
2
Data Received:
2
Data Received:
9
Data Received:
0
Data Received:
0
Data Received:
0
Data Received:
4
Data Received:
0
Data Received:
0
Data Received:
7
Data Received:
1
Data Received:
8
Any suggestions?
Thanks in advance!
It appears that the data of the second read comes in char by char, so I would use a StringBuilder b and append incoming data until a valid barcode was received and is contained in b (ie check validity against a database)
I suggest something like this:
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
StringBuilder b = new StringBuilder();
while(!IsValidBarcode(b.ToString()))
{
b.Append(sp.ReadExisting());
}
Console.WriteLine("Data Received:");
Console.WriteLine(b.ToString());
}
private static Boolean IsValidBarcode(String s)
{
if (String.IsNullOrEmpty(s)) return false;
// (1) Query a database for expected barcodes ...
// (2) Check s for Start-Stop-Characters ...
// (3) Query the device for completed barcode ...
throw new NotImplementedException();
}
or this
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
StringBuilder b = new StringBuilder();
Thread.Sleep(1000); // 1 second delay for testing purposes
b.Append(sp.ReadExisting());
Console.WriteLine("Data Received:");
Console.WriteLine(b.ToString());
}
You need some sort of timer to check if the multiple characters being read are part of a single read or if they are 2 different scans. The time between the event firing for your second scan is probably very short, simply set a timer to start after an event firing, if this expires before the next event then it is the end of the barcode, if not append the read to the previous (use a buffer of some sort).
You need to have an ending character to know when your message is completed. Most people are using a \r\n (13,10) and read from the serial port to the end of the line (i.e. \r\n).
You are getting an event for each character and reading it too quickly.
Luca Pillin, I have just included thread.sleep for 3 seconds and it solves the issue
using System;
using System.Threading;
using System.IO.Ports;
class PortDataReceived
{
public static void Main()
{
SerialPort mySerialPort = new SerialPort("COM2");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.RequestToSend;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
//
string indata = string.Empty;
SerialPort sp = (SerialPort)sender;
**Thread.Sleep(3000);**
indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.WriteLine(indata);
}
}
Related
I'm working with Dallas Key which is wired on the COM2 port.
The dallas Key has a value when it's ON (for example 00 AA BB) and a value when it's removed (for example 00 00 00).
How can I ready continuously the value of the COM2 port in order to detect it's change and take actions based on it ( winforms application ).
I've tried to get the value by port name and read it but it says access denied in some cases.
private SerialPort port = new SerialPort("COM2",9600, Parity.None, 8, StopBits.One);
static void Main(string[] args)
{
SerialPortProgram();
}
private static void SerialPortProgram()
{
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();
Console.ReadLine();
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine(port.ReadExisting());
}
I want to listen to the COM2 port value all the time without having a big impact on the application speed, get the value of the COM2 port (my dallas key) when it is ON and detect when it is off and take specific action.
Even though you didn't describe what line actually throws, by reading the documentation i found this nuget
SerialPort.Open Method
Exceptions UnauthorizedAccessException Access is denied to the port.
-or-
The current process, or another process on the system, already has the
specified COM port open either by a SerialPort instance or in
unmanaged code.
You either don't have permission to open the port, or you already have it open, you need to figure out which one it is and deal with it appropriately
Note : com ports can be a bit fickle if you are using usb to com
The below code works when I write in console (Project is Console Application) but when I changed back to Windows Application and try to write in a label or change a variable value: this doesn't work:
public Form1()
{
InitializeComponent();
SerialPortProgram();
}
private void SerialPortProgram()
{
SerialPort mySerialPort = new SerialPort("COM2");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
mySerialPort.Close();
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
switch (ASCIItoHex(indata))
{
case "00000113":
LB_Display.Text = "User 1";
break;
case "0000017a":
LB_Display.Text = "User 2";
break;
default:
LB_Display.Text = "Disconnect";
break;
}
}
public static string ASCIItoHex(string Value)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in Value)
sb.Append(string.Format("{0:x2}", b));
return sb.ToString();
}
I have a question , i build a form application in C# but i am not so good in it.
I want to add a new feature to the form that listen to the serial port in the background and that then show the received data in a textbox and this has to be done so long that the appication is running.
I found some code from how to do this for a console application but now i want to change the code so that i can use it in a form , could anyone help me?
using System;
using System.IO.Ports;
class PortDataReceived
{
public static void Main()
{
SerialPort mySerialPort = new SerialPort("COM8");
mySerialPort.BaudRate = 57600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
}
}
Put the serial port initialization code into the form's Shown event handler, copy the DataReceived event handler code into the form class an instead of writing to the console, put the data into a text box or so.
Please note that the DataReceived handler will be called on a separate thread, so you need to call this.Invoke to execute the code that updates your UI on the UI thread. Otherwise you'll get an exception.
You can use the method invoker delegate and set the text in your DataRecieved event.
Example:
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
this.Invoke((MethodInvoker)delegate
{
textBox.Text += indata;
});
}
I tried to connect the scale and retrieve the weight from visual studio 2013, but it's wire that sometimes I can get the exacted weight and sometimes I couldn't. I was not sure what's wrong with the code. Can someone help? My code is listed below
using System;
using System.IO.Ports;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows;
using System.Data.SqlClient;
using System.Collections;
using System.Threading;
namespace PortDataReceived
{
class PortData
{
public static void Main(string[] args)
{
try
{
string lineOne = "One";
string lineTwo = "Two";
char CarriageReturn = (char)0x0D;
string final = lineOne + CarriageReturn.ToString() + lineTwo + CarriageReturn.ToString();// define the hexvalues to the printer
SerialPort mySerialPort = new SerialPort("COM3");//initiate the new object and tell that we r using COM1
mySerialPort.BaudRate = 9600;
//mySerialPort.Parity = Parity.Odd;
//mySerialPort.StopBits = StopBits.Two;
//mySerialPort.DataBits = 7;
mySerialPort.Parity = Parity.Odd;
mySerialPort.StopBits = StopBits.Two;
mySerialPort.DataBits = 7;
mySerialPort.Handshake = Handshake.None;
mySerialPort.ReadTimeout = 20;
mySerialPort.WriteTimeout = 50;
mySerialPort.DtrEnable = true;
mySerialPort.RtsEnable = true;
//those r all the setting based on the scale requirement
/*foreach (string port in System.IO.Ports.SerialPort.GetPortNames())
{
Console.WriteLine(port);
}*/
while (true)
{
mySerialPort.Open();
mySerialPort.Write(final);
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
}
//mySerialPort.Close();
}
catch (System.IO.IOException e)
{
if (e.Source != null)
Console.WriteLine("IOException source: {0}", e.Source);
throw;
}
}
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
Console.ReadKey();
}
}
}
Often with serial communication, you have to read multiple times, and concatenate each read, until you finally detect you've read the part that shows you've received it all. Detecting the end may be based on a specific count of bytes received, or it might be looking for a particular byte or sequence of bytes. But it's up to you to make that determination, and to continue reading until that condition is fulfilled. When you first read, there may be characters waiting, but the device has not sent them all yet, so you will have to read again almost immediately after your first read. You're dealing with a stream. The handler event fires when the stream starts, but it doesn't know how long the stream will flow.
This blog post discusses this and some other common serial port issues:
http://blogs.msdn.com/b/bclteam/archive/2006/10/10/top-5-serialport-tips-_5b00_kim-hamilton_5d00_.aspx
im writing a program which reads the input from the serial port. It does recieve something but its breaking the line without reason.
The right input
This right inout should be
Sending...Sending...Sending...Sending...Sending...
Without changing line.
The actual input
Sending...
Se
ndin
g...
S
endi
ng..
.
Send
ing.
..
Se
ndin
g...
The code
public void Serial ()
{
try
{
SerialPort serial = new SerialPort(this.comboBox1.Text);
serial.BaudRate = 9600;
serial.Parity = Parity.None;
serial.StopBits = StopBits.One;
serial.DataBits = 8;
serial.Handshake = Handshake.None;
serial.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceivedHandler);
serial.Open();
}
catch
{
}
}
public void SerialDataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string dataIn = sp.ReadExisting();
if (log_time == true)
{
this.richTextBox1.AppendText(time + dataIn);
}
else
{
this.richTextBox1.AppendText(dataIn + "\n");
}
}
The this.combobox1.Text is working fine, im using try because if not the program would crash if the serial port wasnt on!
Im initializing the serial on an other void with Serial();
How can i get the right input?
In your else clause, you should not append "\n" to this.richTextBox1. That is the special character for a new line. If you want the right input, need something like this.richTextBox1.AppendText(dataIn + "...");
Data received output http://postimg.org/image/5hvqgosc7/
This is the string display of RFID tag number.
Is it really this one shows up for all rfid or can I change it to display numbers only without spaces and symbols?
or is there a problem in my code.
This is my code:
private void Form1_Load(object sender, EventArgs e)
{
cn.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Thesis\Desktop\Projects\Employees.accdb;Persist Security Info=True";
cmd.Connection = cn;
this.myDelegate = new AddDataDelegate(AddDataMethod);
rfidbox.Enabled = true;
string[] ports = SerialPort.GetPortNames();
foreach (string port in ports)
{
SerialPort mySerialPort = new SerialPort(port);
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.ReadTimeout = 3000;
mySerialPort.Handshake = Handshake.None;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
}
}
private void DataReceivedHandler( object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string s = sp.ReadExisting();
rfidbox.Invoke(this.myDelegate, new Object[]{s});
}
public void AddDataMethod(String myString)
{
rfidbox.AppendText(myString);
}
Thanks for help in advance.
I would assume that your data has a binary part after the few bytes whith ASCII values. You probably need to consult the documentation of your hardware for the structure of the data. If parts are binary you need to use binary read routines like SerialPort.ReadByte() n times and assemble a string manually from bytes. The bytes after the string need to be interpreted according to the meaning; watch for potential endianness issues with binary integers, if any are contained in the data.