I'm developing a small program that receives analog data from the serial port and displays it into multiple Textboxes.
The data is 10 bit A2D from a micro in the form of two Hex bytes and a letter to identify which A2D port it came from.
eg: 0x1A, 0x02, A
My program is receiving the data ok, and if I only display receive analog value at a time it works fine.
The problem I have is that I'm unsure how to process the incoming data when I try to receive multple A2D values.
The code below is suppose to display 3 analog values in separate text boxes, but only the first text box displays any data. What would be the best way to go able this?
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
//Initialize a buffer to hold the received data
byte[] buffer = new byte[serialPort1.ReadBufferSize];
int bytes = serialPort1.BytesToRead;
//There is no accurate method for checking how many bytes are read
//unless you check the return from the Read method
bytesRead = serialPort1.Read(buffer, 0, bytes);
nValue = buffer[0] + (buffer[1] << 8);
switch1 = Convert.ToChar(buffer[2]);
switch (switch1)
{
case 'A':
DispString1 = nValue.ToString();
this.Invoke(new EventHandler(textBox0_TextChanged));
break;
case 'B':
DispString2 = nValue.ToString();
this.Invoke(new EventHandler(textBox1_TextChanged));
break;
case 'C':
DispString3 = nValue.ToString();
this.Invoke(new EventHandler(textBox2_TextChanged));
break;
}
}
private void textBox0_TextChanged(object sender, EventArgs e)
{
textBox0.Text = DispString1;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox1.Text = DispString2;
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
textBox2.Text = DispString3;
}
bytesRead = serialPort1.Read(buffer, 0, bytes);
You blindly assume that you'll get 3 bytes, required to make the rest of the code work. That is not how serial ports work. You in fact usually get only 1 or 2 bytes, serial ports are very slow. So of course your switch() statement cannot get a match.
Get ahead with:
byte[] buffer = new byte[3];
int len = 0;
while (len < 3) {
len += serialPort1.Read(buffer, 0, 3-len);
}
// etc..
Do note that you have a tricky synchronization problem. If you call the Open() method while the device is sending then the first byte you receive is not necessarily the first byte of the 3 byte response. You'll never get a proper response. A device usually sends extra bytes to indicate the start and the end of a frame of data to help solve that problem, that however doesn't seem to be the case here. Fixing this at the device end ought to be a strong goal.
Related
I'm trying to communicate back and forth with an Arduino via serial through a C# program. I've got a basic working example, but it's not pretty and not fault-less. I've included it at the end. I have done some research online, but it's difficult to look for something when you don't know all the details and intricacies of what you're looking for.
I'm under the impression that good serial communication protocol should include a handshake, send data and wait for response, receive data and send response, data clocking, etc. My question is how best to implement this. My existing code is one-way, from C# to the arduino's serial port, and it just sends the data and assumes that it was received. It's also very simple, sending just two bytes (a 1 or 0 to turn on or off an LED, and a 0-255 to control the LED's brightness via PWM). I'd like to be able to send sensor data or confirmation that the data was received and acted on, back from the arduino to the program.
I'm also curious about syncing. Does that go hand in hand with the handshake (no pun intended)? How can I reliably send data either way and be assured that nothing will be lost due to being out of sync?
Anywho, I've rambled, sorry. Hopefully someone can shed a little learning light on this subject. Here's my current messy code:
Arduino:
#define LEDPin 9
byte SerialCmd = 0;
byte SerialVal = 0;
void setup() {
Serial.begin(9600);
pinMode(LEDPin, OUTPUT);
digitalWrite(LEDPin, LOW);
}
void loop() {
while(Serial.available() > 1) {
SerialCmd = Serial.read();
SerialVal = Serial.read();
switch(SerialCmd) {
case 0:
digitalWrite(LEDPin, LOW);
break;
case 1:
analogWrite(LEDPin, SerialVal);
break;
}
}
}
C#:
using System;
using System.Windows.Forms;
namespace ArduinoTest2
{
public partial class Form1 : Form
{
byte[] SerialData = new byte[] { 0, 0 };
public Form1()
{
InitializeComponent();
serialPort1.PortName = "COM3";
serialPort1.BaudRate = 9600;
serialPort1.Open();
}
public void SerialWrite()
{
serialPort1.Write(SerialData, 0, 2);
}
private void button1_Click(object sender, EventArgs e)
{
SerialData[0] = 1;
SerialWrite();
}
private void button2_Click(object sender, EventArgs e)
{
SerialData[0] = 0;
SerialWrite();
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
SerialData[1] = Convert.ToByte(trackBar1.Value);
label1.Text = trackBar1.Value.ToString();
SerialWrite();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
serialPort1.Close();
}
}
}
I am simply trying to send "0" to my MCU, when the MCU receive this byte, it will send back another byte ("0" or 1" or "2" or "3"). The MCU receive the byte normally, since the code written for the MCU is waiting till I receive the byte. The problem is with the C#, it seems that it's missing the data from the MCU, because sometimes I got the data correctly but most of the time I got it wrong.
Here is the code for the C#:
private void CheckConnPuf_Click(object sender, EventArgs e) //When Check Connected PUF button is clicked
{
comboBox2.Items.Clear();
int serialinput;
serialPort1.WriteLine("0"); //send "0" to the MCU to receive back a byte
while (serialPort1.BytesToRead < 0) ;//if there is no data in the buffer do nothing
serialinput = serialPort1.ReadChar(); // receive the byte
richTextBox1.Text = serialinput.ToString(); //print the received byte
if (serialinput==48) { //if the byte is "0"
comboBox2.Items.Add("R0_SPREAD");
}
else if (serialinput == 49) {//if the byte is "1"
comboBox2.Items.Add("R0_COMP");
}
else if (serialinput == 50) {//if the byte is "2"
comboBox2.Items.Add("ARBITER");
}
else if (serialinput == 51) {//if the byte is "3"
comboBox2.Items.Add("SRAM_150X125");
}
}
Here is the C# form to make things clear :
I am not sure about The part in the code where I wait for the data to be available in the buffer and then I can read it. If it's not correct, what is the way to do it ?
I'm trying to read data from serial port. It reads data when I set breakpoint.
I have tried with parent delegate invoke, some delay also. It doesn't work for me.
Here is my code
Read code from class file:
public void comport_DataReceived2(object sender, SerialDataReceivedEventArgs e)
{
var bytes = comport.BytesToRead;
var buffer = new byte[bytes];
string test2 = comport.ReadExisting();
if (IsReadPDSS)
{
if(test2 != string.Empty && test2 != " " && test2.Length > 30)
{
test2 = test2.Substring(30);
test2.Replace("000000000000P0000W", "");
strReceived += test2;
}
}
else
{
strReceived = test2;
}
}
windows form retriving read data :
string ss=FormObj.strReceived.ToString();
When you do application debugging, your system is not entirely frozen. Only the application you debug. Thus, while your app is in a breakpoint, incoming data on the serial port still is being accumulated.
The control flow is a bit fuzzy (probably because you changed it over a few times while looking for the problem). As it is written now, you read the data from the serial port whenever the event is raised. It is not likely that 30 bytes have arrived at the time you read the data. If you break into the debugger and do single stepping, it is rather more likely that you will find more than 30 bytes in the receive buffer (depending on what your device which transmits does).
Hence, a better way to write the control flow would look like this:
public void comport_DataReceived2(object sender, SerialDataReceivedEventArgs e)
{
var bytes = comport.BytesToRead;
if( bytes > 30 )
{
var test2 = comport.ReadExisting();
// additional testing code as required...
}
}
Depending on how the event raising behavior works, you might need to accumulate the data yourself in an extra buffer if the event is not getting re-raised after being fired for the first time... But that should be easy enough to test and adapt.
I have device that can connect to my laptop via blue-tooth as COM5. The device has a Pulse sensor. I want to draw data coming from sensor to graph. However when i connected to COM5 the serialport_Datarecieved event is not triggered. I tried device using matlab. It takes and draws data but i cant get data in c#. I checked the connection status of device and it is ok. I tried to change DtrEnabled and RtsEnapled properties but not worked.
private void Form1_Load(object sender, EventArgs e)
{
cmbPortList.Items.AddRange(SerialPort.GetPortNames());
cmbPortList.Sorted = true;
cmbPortList.SelectedIndex = 0;
this.serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(serialPort1_DataReceived);
}
private void btnOpenPort_Click(object sender, EventArgs e)
{
try
{
serialPort1.PortName = cmbPortList.Text;
serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8;
serialPort1.ReadTimeout = 500;
serialPort1.WriteTimeout = 500;
serialPort1.Handshake = Handshake.None;
if (!serialPort1.IsOpen)
{
btnRun.Enabled = true;
serialPort1.Open();
}
}
catch (Exception ex)
{
serialPort1.Close();
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (serialPort1.BytesToRead > 0)
{
Thread.Sleep(50);
byte[] buffer = new byte[serialPort1.BytesToRead];
serialPort1.Read(buffer, 0, buffer.Length);
}
}
I cant read any data in buffer. There is led is flashing while device is not connected with via blue-tooth. So i am absolutely sure i connected to device.
Is problem about Bluetooth or code? Should i use another library to communicate blue tooth device?
I have read links below.
SerialPort fires DataReceived event after close
SerialPort not receiving any data
This may have less to do with the SerialPort and more to do with the way that Winforms threads are interacting with the serial port's background worker threads. See the solution to this for more info.
I think the designer of the circuit requests data from device with 's'. It must be about its protocol or hex code. I have found that code in matlab sample of circuit % Request Data fprintf(s,'s'); That's why i can read data when i use serialport.Write("Blast"); Also i tried all letters. Only 's' char triggers the event.
I am sending a character from visual studio C# to the serial port and I want arduino to read the character and do some work. But, its not reading it correctly. I have tested the arduino program using the serial monitor and it is working perfectly.Here's my C# code.
private void startBit_Click(object sender, EventArgs e)
{
char start = '!';
byte[] buffer = new byte[] { Convert.ToByte(start) };
timerRealTimeData.Enabled = true;
serialPort1.PortName = "COM29";
serialPort1.BaudRate = 9600;
serialPort1.DtrEnable = true;
serialPort1.Open();
serialPort1.Write(buffer, 0, 1);
if (serialPort1.IsOpen)
{
Start.Enabled = false;
Stop.Enabled = true;
}
}
Here's the arduino code for reading the serial port
char incomingByte;
void setup()
{
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop()
{
if(Serial.available() > 0) {
incomingByte = Serial.read();
if(incomingByte=='!')
{
digitalWrite(13,HIGH);
delay(2000);
digitalWrite(13,LOW);
}
}
}
I am stuck on this for a long time.Any help is appreciated
Try to read the equivalent Ascii (33) using an int instead of a char. Also change the line
if(Serial.available() > 0)
To
if(Serial.available())
Some reference for you. Here
First of all, create a function where you open the serial port, and a function where you close the serial port. Your click handler startBit_Click opens the serial port, which means that if the handler is called again, the port is already open and an exception will be generated. (unless you have other code not shown that closes the serial port?)
Second, I am guessing you are connected to the arduino through the USB port?
If so, DtrEnable should be false (default), as you have no XON/XOFF software handshaking.
You should also examine the buffer in the debug window, set a breakpoint after the buffer is assigned the character and check that the character you send is indeed what you think it is.