I am reading data from an Arduino board using C#.
In C#, I have the following:
// Write a string
port.Write("x");
Thread.Sleep(50);
SerialPortRead();
... and in SerialPortRead() I have:
private static void SerialPortRead()
{
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
}
private static void port_DataReceived(object sender,SerialDataReceivedEventArgs e)
{
Console.WriteLine(port.ReadExisting());
}
and, the output would look something like:
329327
32
7
327
3
26
327
3
26
32
7
What did I do wrong? The output should be a around 326-329, where this value is coming from a compass which is hooked up to one of the pins that I am reading from Arduino.
Note that:
In Arduino, I have a Serial read method that watch for the input character x and return the value of the compass.
I'd guess that you are reading faster that the compass is writing. So that way your program believes that it is receiving two direction, while if it has delayed reading a little bit it would have received only one.
This hypothesis is supported by that if you group the read data into numbers of three, we get directions in the range you expect.
Try adding a delay before reading after sending the trigger character, or even better - add a control character to signal that the compass has written the entire direction and then read until you receive that char.
Edit: I now noticed that you already have a sleep - so the option remaining would be a separation/termination char.
Related
I am writing a simple app where an Ardunio sends read data to the C# program using simple serial.write()'s. I send the data from Ardunio with special syntax and the c# program reads and interprets it and eventually graphs the data.
For example, the Ardunio program sends data
Serial.write("DATA 1 3 90;");
which means: X value and Y value in chart 1 is 3 and 90 respectively.
And the c# program reads it using
private async void Serialport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
await serialport.BaseStream.ReadAsync(buffer, 0, 1024);
await Task.Run(() => Graph()); // Graph function graphs the data
}
In the graph() function, I convert the buffer to a string with Encode.ASCII.GetString(buffer); and interpret the data with the syntax and stuff. But for some reason either the c# program doesn't read it fast enough or the Arduino doesn't send it fast enough and the messages are sometimes interrupted For example the packet I received is:
DATA 2 5 90;DATA 5 90 10;DATA 1 1 <|-------- I cannot get the last Y Value
And the next data module starts with
75;DATA 5 4 60;DATA 14 5 6;DATA
/\
|
+==================== It is here
BTW, all the packets are 32 bytes.
So I either need to get the data line by line but I cannot do that because ardunio sends it too fast
Serial.write("DATA 1 3 90;");
Serial.write("DATA 2 4 40;");
Comes to C# as DATA 1 3 90;DATA 2 4 40; as a whole block.
Or I need to get it all at once?
(I prefer getting it line by line)
UPDATE:
When delay(1000); is added between sends. The data is processed correctly. Without the delays, Arduino sends the data too fast, and data clumps and interrupted. How can I make sure that there is no delay in the data yet the data is reliable and without interruption?
UPDATE 2:
When buffer size is increased to 100 * 1024 * 1024 as well as the readCount in ReadAsync method, the read message is much larger still with interruptions tho.
I can give you any extra information.
PS. I didn't give the whole code because it is a large block. But I can give it piece by piece if you tell me where you want it.
Any help is appreciated.
I am very new to interacting with hardware. I am currently building a GUI in C# using the Windows Forms. I am using a serial port/usb to interact with a hardware device. What I am trying to achieve is to have multiple threads poll the device at different times. Some data such as temperature, current, power, etc. should be retrieved regularly (at least every second) and be updated on the GUI for the user to see. While other data will only be retrieved when the user presses a button on the form. Would multi-threading be the right approach to tackle this problem? If not, what would be a better solution? Examples would be greatly appreciated. Thank you for your time guys!
Update: I am trying to use the SerialPort.DataReceived Event as many of you have suggested and a terminator character '\r' to parse out individual replies from the serial port. Then I am invoking a method called DisplayText to handle that string. My problem now is I have no idea how to figure out what the string represents. Does it represent a temperature, a current, etc.
private char terminator = '\r';
private void SerialPorts_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
output += serialPort1.ReadExisting();
if (output.IndexOf((char)this.terminator) > -1)
{
string workingString = output.Substring(0, output.IndexOf(terminator));
output = output.Substring(output.IndexOf(terminator) + 1);
this.Invoke(new EventHandler((s, a)=>DisplayText(s, a, workingString)));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void DisplayText(object sender, EventArgs e, string s)
{
Console.WriteLine(s); // for testing only
richTextBox1.AppendText(s); // for testing only
}
I think it is not a good idea to have multiple threads to poll single port and try to synchronize.
Better have one thread which does the polling and which stores all the values in some "middle" object (singleton, static fields, what you like) and than synchronize access to this storage.
So one threads polls the port, collects the values and stores them somewhere, than the other threads gets the values from there.
You can guard all serial port access functionality using a mutex and design your application in such a way that the serial port is closed after each discrete operation (e.g. reading the temperature). One possible way to do this would be to write a wrapper API of-sorts which would:
Check if the mutex is unlocked (and return with an error code if it is locked),
Open the serial port
Read the required value
Close the serial port and clear the mutex
Return the read value
However, you are opening yourself up to all sorts of deadlocks with this solution and you will have to implement additional application level checks to prevent this.
As suggested above, a better solution would be to have a single thread periodically poll the serial port and continuously update all values in a data structure of your choice.
For the values which only need to be read after user input, you will have to implement a MessageQueue to request this data.
Update in response to the OPs edit
I would recommend either of the following 2 ways to approach the communication in your device:
Implement a request/response mechanism where you send request for a
specific data value (e.g. current) via serial port to your device,
the device parses this request and returns the corresponding value
Have your device return all values in a "frame" e.g.
[SOF][D0...Dn][EOF], where "D0...Dn" is all your data in a
pre-determined sequence; SOF and EOF can be any values of your
choosing (you can also choose to skip these entirely and rely on the
number of bytes to delimit frames).
In case you don't have the option of changing the code in the device, there must be some sort of order in which the values are reported by the device so maintaining a sequence number of the received data would be the way to go. But without knowing more details about what your device is doing, it would be difficult to suggest a solution.
My problem now is I have no idea how to figure out what the string
represents. Does it represent a temperature, a current, etc.
Use simple protocol to send temperature, a current, ect.
SOH + DATA + ETX + BCC
SOH = 0x02;
ETX = 0x03;
BCC = 0x00-0xFF, XOR value of of all DATA + ETX.
DATA = use ';' as delimiter between Temperature(Temp) and Current(Curr)
Example:
TempCmd = 0x01
TempValue = 32 celcius = 0x20
CurrCmd = 0x02
CurrValue = 1,4 ampere = 0x0E -> result must be divide with 10 on receiver.
SOH + DATA + ETX + BCC
SOH + TempCmd:TempValue; CurrCmd:CurrValue + ETX + BCC
02 + 01:20;02:0E + 03 + BCC
BCC = 01 xor ':' xor 20 xor ';' xor 02 xor ':' xor 0E xor 03
Send data from microcontroller "0201:20;02:0E03;XX" (send as string)
Receive data in computer:
Detect SOH and ETX in package
Validate BCC is true (completed package) or false (broken package)
Parsing DATA with ; as delimiter // data1= 01:20 data2= 02:0E03
Parsing data1 and data2 with : as delimiter // data1= 20 data2= 0E03
Convert hex to decimal and divide data2 with 10 for get current with float format.
I'm testing out a program right now that is supposed to receive data from a serial port and parse it, and continually update certain variables tied to that parsed data. I'm having trouble with the actual parsing itself.
The data string output of the port I'm using is: 8 data bits, 1 start bit, 1 stop bit, and no parity. A message starts with the colon symbol : and ends with . An example - : 3.00 20.45 2355 1000 554
First question: Is there any method for setting the start bit? I know there's a .StopBits which I have equal to StopBits.One, but I haven't found anything for a start bit.
In regards to the parsing-
In the code method below:
serial.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Receive);
private void Receive(object sender, SerialDataReceivedEventArgs e)
{
// Collecting the characters received to our 'buffer' (string).
received_Data = serial.ReadExisting();
}
Would the best way be to set up a string array = received_Data.Split, then use a for loop to go through each "split" and assign it to the correct variable? I've never worked with ports before so this is all new to me. After looking around there seems to be several ways to do this, not sure what the best way would be though.
Apologies if my 'lingo' doesn't make sense... I'm fairly new to this and coding!
I am working on a project which involves a RFID reader and a Bluetooth module communicating with a C# windows form.
The com port event handler sends the RFID tag's unique ID continuously. Is there a way for it to be sent just once?
Is there a way for the program to just receive the ID once, so it can be processed; as opposed to receiving the ID numerous times.
Thanks in advance! :)
My code so far is as follows.
I have the serial port open from somewhere else
private void port_DataRecieved(object sender, System.IO.Ports.SerialDataRecievedEventArgs e)
{
string data = serialPort.ReadExisting(); // read what came from the RFID reader
if (data.Length > 9) // check if the string if bigger than 9 characters
{
CODE = data.Substring(0, 9); // if string is bigger than 9 characters trim the ending characters until it is only 9 long
}
else
{
CODE = data; // if less that 9 characters use however many it gets
}
}
Don't use ReadExisting. Instead check whether there are 9 bytes yet.
If not, return immediately.
If yes, read only 9 and leave the others for the next event.
You probably should have some resynchronization logic also.
Also, received data needs to be in a byte[], not a string. The Microsoft-provided serial port class always leads people to use the wrong approach.
I've got a little application written in C# that listens on a SerialPort for information to come in. The information comes in as: STX + data + ETX + BCC. We then calculate the BCC of the transmission packet and compare. The function is:
private bool ConsistencyCheck(byte[] buffer)
{
byte expected = buffer[buffer.Length - 1];
byte actual = 0x00;
for (int i = 1; i < buffer.Length - 1; i++)
{
actual ^= buffer[i];
}
if ((expected & 0xFF) != (actual & 0xFF))
{
if (AppTools.Logger.IsDebugEnabled)
{
AppTools.Logger.Warn(String.Format("ConsistencyCheck failed: Expected: #{0} Got: #{1}", expected, actual));
}
}
return (expected & 0xFF) == (actual & 0xFF);
}
And it seems to work more or less. It is accurately not including the STX or the BCC and accurately including the ETX in it's calculations. It seems to work a very large percentage of the time, however we have at least two machines we are running this on, both of which are Windows 2008 64-bit in which the BCC calculation NEVER adds up. Pulling from a recent log I had in one byte 20 was sent and I calculated 16 and one where 11 was sent and I calculated 27.
I'm absolutely stumped as to what is going on here. Is there perhaps a 64 bit or Windows 2008 "gotcha" I'm missing here? Any help or even wild ideas would be appreciated.
EDIT:
Here's the code that reads the data in:
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// Retrieve number of bytes in the buffer
int bytes = serialPort.BytesToRead;
// Create a byte array to hold the awaiting data
byte[] received = new byte[bytes];
//read the data and store it
serialPort.Read(received, 0, bytes);
DataReceived(received);
}
And the DataReceived() function takes that string and appends it to global StringBuilder object. It then stays as a string builder until it's passed to these various functions at which point the .ToString() is called on it.
EDIT2: Changed the code to reflect my altered routines that operate on bytes/byte arrays rather than strings.
EDIT3: I still haven't figured this out yet, and I've gotten more test data that has completely inconsistent results (the amount I'm off of the send checksum varies each time with no pattern). It feels like I'm just calculating the checksum wrong, but I don't know how.
The buffer is defined as a String. While I suspect the data you are transmitting are bytes. I would recommend using byte arrays (even if you are sending ascii/utf/whatever encoding). Then after the checksum is valid, convert the data to a string
computing BCC is not standard, but "customer defined". we program interfaces for our customers and many times found different algorithms, including sum, xor, masking, letting apart stx, etx, or both, or letting apart all known bytes. for example, package structure is "stx, machine code, command code, data, ..., data, etx, bcc", and the calculus of bcc is (customer specified!) as "binary sum of all bytes from command code to last data, inclusive, and all masked with 0xCD". That is, we have first to add all the unknown bytes (it make no sense to add stx, etx, or machine code, if these bytes do not match, the frame is discarded anyhow! their value is tested when they are got, to be sure the frame starts, ends correctly, and it is addressed to the receiving machine, and in this case, we have to bcc only the bytes that can change in the frame, this will decrease the time, as in many cases we work with 4 or 8 bit slow microcontrollers, and caution, this is summing the bytes, and not xoring them, this was just an example, other customer wants something else), and second, after we have the sum (which can be 16 bits if is not truncated during the addition), we mask it (bitwise AND) with the key (in this example 0xCD). This kind of stuff is frequently used for all kind of close systems, like ATM's for example (connecting a serial keyboard to an ATM) for protection reasons, etc., in top of encryption and other things. So, you really have to check (read "crack") how your two machines are computing their (non standard) BCC's.
Make sure you have the port set to accept null bytes somewhere in your port setup code. (This maybe the default value, I'm not sure.)
port.DiscardNull = false;
Also, check for the type of byte arriving at he serial port, and accept only data:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (e.EventType == SerialData.Chars)
{
// Your existing code
}
}