so im new in C# Programming. I have programmed a C# Forms Application in Visual Studio to communicate to/initialze a device over the Serial Port. The communication between the device is COBS coded, so there are no 0x00 bytes except on the end of each message. The messages sent and received have different length.
My problem is at the moment, that the Messages I receive are not complete or start at the middle of a message, so i cannot trigger sent messages on a specific value in the received messages. You can determine end of a message with received 0x00 (0x00 means end of message in COBS coded data)
So what i need is something to handle the complete message and put it in a byte array to analyze i.e. byte[11] for a specific value.
Here is what ive done so far:
private bool b_portopen = false;
private byte[] b_rcv_buffer = new byte[256];
private void button1_Click(object sender, EventArgs e) {
//InitTimer();
if (b_portopen == false)
{
serialPort1.PortName = comboBox1.SelectedItem.ToString();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
serialPort1.Open();
b_portopen = true;
button1.Text = "Close";
button2.Enabled = true;
Console.WriteLine("Serial Port Opened");
}
else if (b_portopen == true)
{
serialPort1.Close();
b_portopen = false;
button1.Text = "Open";
button2.Enabled = false;
Console.WriteLine("Serial Port Closed");
}
}
private async void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
serialPort1.Read(b_rcv_buffer, 0, 256);
//serialPort1.Read(b_rcv_buffer1, 11, 2);
richTextBox1_receive.Invoke(new Action(() =>
{
richTextBox1_receive.AppendText(BitConverter.ToString(b_rcv_buffer) + "\n");
richTextBox1_receive.ScrollToCaret();
}));
switch (b_rcv_buffer[10])
{
case b_state_startup:
do something
case b_state_be_start_conf:
do something
case b_state_keepalive_conf:
do something
case b_state_unprepare_conf:
do something
case b_state_prepare_conf:
do something
}
}
So, i found a solution with using ConcurrentQueue:
ConcurrentQueue<byte> b_rcv_buffer = new ConcurrentQueue<byte>();
private Timer timer2;
public void InitTimer()
{
timer2 = new System.Windows.Forms.Timer();
timer2.Tick += new EventHandler(timer2_Tick);
timer2.Interval = 1; // in miliseconds
timer2.Start();
}
private async void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
int bytes = serialPort1.BytesToRead;
byte[] buf = new byte[bytes];
serialPort1.Read(buf, 0, serialPort1.BytesToRead);
for(int i = 0; i < buf.Length; i++)
{
b_rcv_buffer.Enqueue(buf[i]); //Enqueue every received Byte in Concurrentqueue
}
}
private async void timer2_Tick(object sender, EventArgs e)
{
if (b_rcv_buffer.Contains<byte>(0x00))
{
byte[] array = b_rcv_buffer.ToArray();
richTextBox1_receive.Invoke(new Action(() =>
{
richTextBox1_receive.AppendText(BitConverter.ToString(array) + "\n");
//richTextBox1_receive.ScrollToCaret();
}));
byte ignored;
while (b_rcv_buffer.TryDequeue(out ignored));
}
I have got myself a little lost with this Windows forms application:(
I have a stream of data arriving at a serial port in the format of \W0987654321\L555666444\W3456789900\L9842429009 and so it repeats with different values for \L and \W
I need to split out the \W and \L values and add them to an array which is to expand as needed. and then plot them on a graph in real time.
Where i'm lost is how to read the port to get each complete value once it has arrived and not truncate it. I just can't get my brain around this so any help would be great...
I open the port thus:
port.PortName = "COM9";
port.BaudRate = 38400;
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.DtrEnable = false;
port.Handshake = Handshake.None;
port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived_1);
port.Open();
textBox1.Clear();
port.DiscardInBuffer();
port.DtrEnable = true;
Currently i have it all writing to a text box:
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
InputData = port.ReadExisting();
if (InputData != String.Empty)
{
this.BeginInvoke(new SetTextCallback(SetText), new object[] { InputData });
}
}
private void SetText(string text)
{
this.textBox1.AppendText(text);
}
which shows all the data OK
var readQueue = string.Empty;
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
readQueue += port.ReadExisting();
while (readQueue.Substring(1).Contains(#"\"))
{
var slashPos = readQueue.IndexOf(#"\",1);
var completeEntry = readQueue.Substring(0, slashPos);
Console.WriteLine(completeEntry);
readQueue = readQueue.Substring(slashPos);
}
}
I am trying to send ASCII caracters to a VideoJet Excel 170i printer, via a RS-232 cable (Serial)
When I am using the test program, i have no problem getting a response from the printer, i can change the status of the printer.
This is the code i've made
public partial class Form1 : Form
{
private SerialPort port = new SerialPort("COM1");
private delegate void SetTextDeleg(string data);
public Form1()
{
InitializeComponent();
}
private void addtoText(string text)
{
this.richTextBox1.Text = this.richTextBox1.Text + "\n" + text;
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
port.BaudRate = 9600;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.DataBits = 8;
port.Handshake = Handshake.None;
port.ReadTimeout = 2000;
port.WriteTimeout = 500;
port.DtrEnable = true;
port.RtsEnable = true;
port.Open();
port.DataReceived += DataReceivedHandler;
addtoText("Port is ready");
}
catch (Exception ex)
{
//Console.WriteLine("Error opening my port: {0}", ex.Message);
addtoText("Error opening my port: {0}" + ex.Message);
}
}
public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
System.Threading.Thread.Sleep(500);
string indata = sp.ReadExisting();
this.BeginInvoke(new SetTextDeleg(DisplayToUI), new object[] { indata });
}
private void DisplayToUI(string displayData)
{
addtoText(displayData);
}
private void button1_Click(object sender, EventArgs e)
{
port.Write(tbxAscii.Text);
}
private void Form1_Leave(object sender, EventArgs e)
{
port.Close();
}
}
I need to sent ASCII caracters to the printer, like
[1B][01][09]
To turn the printer to Print Mode.
The printer is supposed to respond, i get no response, and the printer doesn't change its status.
I have a program made to test the serial connection made by the printer, and i can see that all the settings are OK (Baud rate, Parity... port), and indeed on port COM1.
So i think that my port.write is not sending any info to the printer... or maybe i'm sending corrup info and i'm not reading the response of the printer.
are you sure that you want to send [1B][01][09] or do you want to send that byte sequence 0x1b,0x01,0x09
just to see if this works, send the following in you click handler
private void button1_Click(object sender, EventArgs e)
{
var bytes = new byte[] { 0x1b, 0x01, 0x09 };
port.Write(bytes, 0, bytes.Length);
port.Flush(); // make sure everything is written
}
reading has to be changed, to handle bytes
SerialPort sp = (SerialPort)sender;
System.Threading.Thread.Sleep(500);
var available = sp.BytesToRead; // check how many bytes are ready to be read
if (available < 1)
return;
var buffer = new byte[available];
sp.Read(buffer, 0, available);
var indata = BitConverter.ToString(buffer); // convert bytes to a hex representation
this.BeginInvoke(new SetTextDeleg(DisplayToUI), new object[] { indata });
I've been assigned to display weight from weighing scale (CAS CI-201A) into a textbox using C#. The weight will be sent via serial port RS-232 or USB converter. The scale is with me but I don't know where to start. How can I achieve my goal?
Have you tried anything yet?
If you want to use the serial port it makes sense to first give the user a way to select which port to use. This can be done easily, by filling a combobox with all available ports.
private void Form1_Load(object sender, EventArgs e)
{
string[] portNames = SerialPort.GetPortNames();
foreach (var portName in portNames)
{
comboBox1.Items.Add(portName);
}
comboBox1.SelectedIndex = 0;
}
This code uses a form with a comboBox on it, called "comboBox1" (Default).
You will need to add:
using System.IO.Ports;
to the using directives.
Then add a button (button1) and a multiline textbox (textbox1) to the form and add this code:
private void button1_Click(object sender, EventArgs e)
{
_serialPort = new SerialPort(comboBox1.Text, BaudRate, Parity.None, 8, StopBits.One);
_serialPort.DataReceived += SerialPortOnDataReceived;
_serialPort.Open();
textBox1.Text = "Listening on " + comboBox1.Text + "...";
}
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
while(_serialPort.BytesToRead >0)
{
textBox1.Text += string.Format("{0:X2} ", _serialPort.ReadByte());
}
}
This also requires you to add:
private SerialPort _serialPort;
private const int BaudRate = 9600;
right below the opening brackets of
public partial class Form1 : Form
After clicking the button, all received data from the selected comPort will be displayed as hex values in the TextBox.
DISCLAIMER: The above code contains NO error-handling and will produce errors if button1 is clicked multiple times, due to the fact that the previous instance of "SerialPort" is not closed properly. Please remember this when using this example.
Regards Nico
Complete Code:
using System;
using System.IO.Ports; //<-- necessary to use "SerialPort"
using System.Windows.Forms;
namespace ComPortTests
{
public partial class Form1 : Form
{
private SerialPort _serialPort; //<-- declares a SerialPort Variable to be used throughout the form
private const int BaudRate = 9600; //<-- BaudRate Constant. 9600 seems to be the scale-units default value
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] portNames = SerialPort.GetPortNames(); //<-- Reads all available comPorts
foreach (var portName in portNames)
{
comboBox1.Items.Add(portName); //<-- Adds Ports to combobox
}
comboBox1.SelectedIndex = 0; //<-- Selects first entry (convenience purposes)
}
private void button1_Click(object sender, EventArgs e)
{
//<-- This block ensures that no exceptions happen
if(_serialPort != null && _serialPort.IsOpen)
_serialPort.Close();
if (_serialPort != null)
_serialPort.Dispose();
//<-- End of Block
_serialPort = new SerialPort(comboBox1.Text, BaudRate, Parity.None, 8, StopBits.One); //<-- Creates new SerialPort using the name selected in the combobox
_serialPort.DataReceived += SerialPortOnDataReceived; //<-- this event happens everytime when new data is received by the ComPort
_serialPort.Open(); //<-- make the comport listen
textBox1.Text = "Listening on " + _serialPort.PortName + "...\r\n";
}
private delegate void Closure();
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired) //<-- Makes sure the function is invoked to work properly in the UI-Thread
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); })); //<-- Function invokes itself
else
{
while (_serialPort.BytesToRead > 0) //<-- repeats until the In-Buffer is empty
{
textBox1.Text += string.Format("{0:X2} ", _serialPort.ReadByte());
//<-- bytewise adds inbuffer to textbox
}
}
}
}
}
Based on this:
Listening on COM1... 30 30 33 33 20 49 44 5F 30 30 3A 20 20 20 31 30
2E 36 20 6B 67 20 0D 0A 0D 0A
Being the ASCII for this:
0033 ID_00: 10.6 kg
You can get the result by trimming the received string. Assuming your listener puts the bytes into an array byte[] serialReceived :
string reading = System.Text.Encoding.UTF8.GetString(serialReceived);
textBox1.Text = reading.Substring(13);
Firstly, before you start to code anything, I would check whether you're using the right cable. Try open a serial terminal of your choice (HyperTerm, putty) and check whether there is any data at all.
Be sure to configure the same baudrate, stopbits and parity on both the weight scale and your terminal program.
If you receive data (the terminal program should at least display some garbage), then you can move on to coding. If not, check if you're using the right cable (nullmodem aka crossed-over).
When you're this far, then you may use the SerialPort class of C#
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.aspx
based on adam suggestion i converted the output to human readable format ( from ASCII to UTF8 )
i puts the bytes into an array byte[]
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired) //<-- Makes sure the function is invoked to work properly in the UI-Thread
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); })); //<-- Function invokes itself
else
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
string str = System.Text.Encoding.UTF8.GetString(data);
textBox1.Text = str.ToString();
}
}
here is the full working code
using System;
using System.IO.Ports; //<-- necessary to use "SerialPort"
using System.Windows.Forms;
namespace ComPortTests
{
public partial class Form1 : Form
{
private SerialPort _serialPort; //<-- declares a SerialPort Variable to be used throughout the form
private const int BaudRate = 9600; //<-- BaudRate Constant. 9600 seems to be the scale-units default value
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] portNames = SerialPort.GetPortNames(); //<-- Reads all available comPorts
foreach (var portName in portNames)
{
comboBox1.Items.Add(portName); //<-- Adds Ports to combobox
}
comboBox1.SelectedIndex = 0; //<-- Selects first entry (convenience purposes)
}
private void button1_Click(object sender, EventArgs e)
{
//<-- This block ensures that no exceptions happen
if(_serialPort != null && _serialPort.IsOpen)
_serialPort.Close();
if (_serialPort != null)
_serialPort.Dispose();
//<-- End of Block
_serialPort = new SerialPort(comboBox1.Text, BaudRate, Parity.None, 8, StopBits.One); //<-- Creates new SerialPort using the name selected in the combobox
_serialPort.DataReceived += SerialPortOnDataReceived; //<-- this event happens everytime when new data is received by the ComPort
_serialPort.Open(); //<-- make the comport listen
textBox1.Text = "Listening on " + _serialPort.PortName + "...\r\n";
}
private delegate void Closure();
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired) //<-- Makes sure the function is invoked to work properly in the UI-Thread
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); })); //<-- Function invokes itself
else
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
string str = System.Text.Encoding.UTF8.GetString(data);
textBox1.Text = str.ToString();
}
}
}
if your are using A&D EK V Calibration Model : AND EK-610V. you have use BaudRate = 2400; and DataBits = 7
Note : if you get output like this
you have to check the BaudRate,DataBits (refer your weighing machine manual ) or check your cable
I was using Anto sujesh's Code, but I had the problem that some of the values I got from the scale were corrupted. I solved it by buffering the values in a cache file.
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired) //<-- Makes sure the function is invoked to work properly in the UI-Thread
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); })); //<-- Function invokes itself
else
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
string str = Encoding.UTF8.GetString(data);
//Buffers values in a file
File.AppendAllText("buffer1", str);
//Read from buffer and write into "strnew" String
string strnew = File.ReadLines("buffer1").Last();
//Shows actual true value coming from scale
textBox5.Text = strnew;
using System;
using System.IO.Ports;
using System.Windows.Forms;
namespace ComPortTests
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private SerialPort _serialPort = null;
private void Form1_Load(object sender, EventArgs e)
{
_serialPort = new SerialPort("COM1", 9600, Parity.None, 8);
_serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
_serialPort.Open();
}
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = _serialPort.ReadExisting();
textBox2.Text = data;
}
}
}
using System;
using System.IO;
using System.IO.Ports;
namespace comport
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private SerialPort _serialPort = null;
private void Form1_Load(object sender, EventArgs e)
{
AppConfiguration.sConfigType = "default";
_serialPort = new SerialPort("COM1", 9600, Parity.None, 8);
_serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
_serialPort.Open();
}
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = _serialPort.ReadExisting();
textBox2.Text = data;
}
}
}
I am using
yaohua xk3190-a9
Weighing Scale indicator connected to my serial port. And after trying lots of codes, follwing code finally worked for me. I am pasting the code here so that if anybody is using the same device can get help.
private SerialPort _serialPort;
private const int BaudRate = 2400;
private void Form1_Load(object sender, EventArgs e)
{
string[] portNames = SerialPort.GetPortNames();
foreach (var portName in portNames)
{
comboBox1.Items.Add(portName);
}
comboBox1.SelectedIndex = 0;
//<-- This block ensures that no exceptions happen
if (_serialPort != null && _serialPort.IsOpen)
_serialPort.Close();
if (_serialPort != null)
_serialPort.Dispose();
//<-- End of Block
_serialPort = new SerialPort(comboBox1.Text, BaudRate, Parity.None, 7, StopBits.One); //<-- Creates new SerialPort using the name selected in the combobox
_serialPort.DataReceived += SerialPortOnDataReceived; //<-- this event happens everytime when new data is received by the ComPort
_serialPort.Open(); //<-- make the comport listen
}
private delegate void Closure();
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
{
if (InvokeRequired) //<-- Makes sure the function is invoked to work properly in the UI-Thread
BeginInvoke(new Closure(() => { SerialPortOnDataReceived(sender, serialDataReceivedEventArgs); })); //<-- Function invokes itself
else
{
string data = _serialPort.ReadExisting();
if (data != null)
{
if (data.ToString() != "")
{
if (data.Length > 6)
{
var result = data.Substring(data.Length - 5);
textBox1.Text = result.ToString().TrimStart(new Char[] { '0' });
}
}
}
}
}
I'm having some issues trying to figure out Async communication on a serialport object and was hoping to get some help. I'm still learning Async stuff so be gentle:)
I basically need to make sure that the buffer isn't full prior to writing to the serial port and also all data has been read before any more data gets written to avoid packet collision. Unfortunately the microcontroller that I am writing to does not have any handshaking or CTSEnabled so I have to mimic it in code.
public partial class Form2 : Form
{
System.IO.Ports.SerialPort port = new System.IO.Ports.SerialPort();
System.Timers.Timer tmrPolling = new System.Timers.Timer(200);
static byte [] inputPacket = new byte[2] { (byte)255, (byte)0 }; // Byte to send to SerialPort when input polling timer is activated.
AsyncCallback callback;
IAsyncResult result;
Form2()
{
InitializeComponent();
port.PortName = "COM9";
port.BaudRate = 38400;
port.DataBits = 8;
port.StopBits = System.IO.Ports.StopBits.One;
port.Parity = System.IO.Ports.Parity.None;
port.ReadTimeout = 1;
port.ReceivedBytesThreshold = 5;
port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived);
callback = new AsyncCallback(ReadComplete);
port.ReadBufferSize = (byte)60;
port.WriteBufferSize = (byte)60;
port.Open();
tmrPolling.Elapsed += new System.Timers.ElapsedEventHandler(tmrPolling_Elapsed);
}
void WritePacket(byte[] packet)
{
result = port.BaseStream.BeginWrite(packet, 0, packet.Count(), callback, port); // writes the input packet to the SerialPort - needed to read the IO values
}
void ReadComplete(IAsyncResult result)
{
}
void tmrPolling_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
WritePacket(inputPacket); // writes the input packet to the SerialPort - needed to read the IO values
}
void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
port.BaseStream.EndWrite(result);
// Reads the data coming in from the serial port and calls the thread safe delegate to update the values on the form.
byte [] received = new byte[port.BytesToRead];
result = port.BaseStream.BeginRead(received, 0, received.Count(), callback, port);
port.BaseStream.EndRead(result);
}
private void UpdateValues()
{
byte[] b = new byte[] { (byte)255, (byte)6, (byte)hsbPan.Value, (byte)vsbTilt.Value, (byte)0,
(byte)0, (byte)0, (byte)0, (byte)13, (byte)10 };
WritePacket(b);
}
private void chkEnablePolling_CheckedChanged(object sender, EventArgs e)
{
tmrPolling.Enabled = chkEnablePolling.Checked;
test.Enabled = chkEnablePolling.Checked;
vsbInputInterval.Enabled = chkEnablePolling.Checked;
vsbInputInterval.Value = Convert.ToInt32(tmrPolling.Interval);
txtInputInterval.Enabled = chkEnablePolling.Checked;
txtInputInterval.Text = ((float)tmrPolling.Interval / ( float)1000).ToString() + " sec";
}
private void vsbInputInterval_Scroll(object sender, ScrollEventArgs e)
{
// adjusts the tick frequency of the Timer for input polling.
txtInputInterval.Text = ((float)tmrPolling.Interval / (float)1000).ToString() + " sec";
tmrPolling.Interval = vsbInputInterval.Value;
}
private void vsbTilt_Scroll(object sender, ScrollEventArgs e)
{
UpdateValues();
}
private void hsbPan_Scroll(object sender, ScrollEventArgs e)
{
UpdateValues();
}
}