I´d like to stream a text file containing G-Code to an Arduino UNO via the serialPort.
The Arduino receives all bytes with the SerialEvent and adds it to a char array named buffer. If the buffer is full it is supposed to send an "!;" over the serial port to C#.
This works fine as I have tested it with the Serial Montior application of the Arduino IDE. But I can´t type text as fast as C# can send it :)
The C# program reads the G-Code file linewise and then sends each char in a line to the arduino. After each char I want to check if the Arduino tells me if the buffer is full. Otherwise keep streaming.
Somehow c# never notices the "!;" or even gets any Bytes to read from the Arduino while streaming. I have the feeling that the serialPort.Write() function blocks the port.
This is the Arduino Code:
void serialEvent()
{
// wenn im Puffer noch platz ist
if (buffercount < MAX_BUF)
{
char c = (char)Serial.read();
buffer[buffercount++] = c;
}
else
{
Serial.print("!;");
}
}
The serialEvent is fired every time the Arduino receives bytes on the port.
Max_BUF has a value of 64.
This is the C# Code:
private void startStreaming(string Text)
{
string[] stringSeparators;
string Text2Stream;
if (Text == "")
{
Text2Stream = File.ReadAllText(textBoxSelectFile.Text);
stringSeparators = new string[] { "\n" };
}
else
{
stringSeparators = new string[] { "\r\n" };
Text2Stream = Text;
}
string[] t2s = Text2Stream.Split(stringSeparators, StringSplitOptions.None);
foreach (string zeile in t2s)
{
if (zeile.Contains(")") || zeile.Contains("("))
{
continue;
}
// Code schicken
foreach (char c in zeile)
{
if (c == ' ') continue;
serialPort.Write(c.ToString());
if (serialPort.BytesToRead > 0)
{
if(serialPort.ReadExisting() == "!;")
{
**wait and do smth.**
}
}
}
serialPort.Write(";");
addTextToLog(zeile);
}
}
serialPort.ReadExisiting() never happens because there are never BytesToRead.
The ";" is for both the sign for the end of a line.
startStreaming is started in an asynchronous thread as BackGroundWorker.
Somehow c# never notices the "!;" or even gets any Bytes to read from the Arduino while streaming. I have the feeling that the serialPort.Write() function blocks the port.
The Write command is not blocking the port. The arduino is just much slower then your computer. So between these two lines:
serialPort.Write(c.ToString());
if (serialPort.BytesToRead > 0)
the arduino is occupied and no data is received yet. Therefore BytesToRead is 0. Two possibilities to solve that come right away to my mind.
1) Use the serialPort.DataReceived event for asynchronous processing. This will be triggered every time you receive data. Then you can react upon the received data in that event or
2) Just give the arduino some time with System.Threading.Thread.Sleep(1000);
serialPort.Write(c.ToString());
System.Threading.Thread.Sleep(1000);
if (serialPort.BytesToRead > 0)
You need to find out which is the minimum timespan to wait.
Related
I'm making a C# Win forms app that reads data from an arduino over serial port, parses it and displays it in a textbox.
My problem is that the value in the textbox is always a few seconds older than the value being sent by arduino even if I slow down the arduino to send the data once per second.
I know the problem must be in my C# code because when I read the serial port using a serial monitor everything's fine.
my code:
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
string msgType;
string serialMsg;
serialMsg = port.ReadLine();
if(serialMsg.Substring(0, 1) != "#")
{
return;
}
msgType = serialMsg.Substring(1, 4);
if(msgType == "VOLT") // recieve supply voltage reading
{
textBox1.Invoke((MethodInvoker)delegate { textBox1.Text = serialMsg.Substring(5, serialMsg.Length - 5); });
}
if (msgType == "AMPS") // recieve supply current reading
{
textBox2.Invoke((MethodInvoker)delegate { textBox2.Text = serialMsg.Substring(5, serialMsg.Length - 5); });
}
if (msgType == "LOAD") // recieve load current reading
{
textBox3.Invoke((MethodInvoker)delegate { textBox3.Text = serialMsg.Substring(5, serialMsg.Length - 5); });
}
}
The messages coming from the arduino are in this format: # + TYPE + DATA
Can you tell me what's slowing it down?
I was sending the messages from the arduino too quickly so I put a 50ms delay between them
I also used ReadExisting instead of ReadLine
This solved all the lagging
I have a program that reads serial data from an arduino through a com port.
It works successfully when i program it to print the serial data onto a console, and it does so.
For example, the arduino says outputs "21", and the console writes "21".
But if I make an if statement saying If(data == "21"){/*dosomething*/}
it doesnt work even if the data is printed as "21".
Here are the parts of my code related to this issue.
Arduino
if(digitalRead(i) == HIGH && stat[i-2] == false){
Serial.print(i); Serial.println(1);
stat[i-2] = true;
}
The arduino code is kind of difficult to understand without the rest of the code, but all it does is scans all the ports to see if one of them is high. If it is, it prints the port number and a 1 next to it. For example if port 2 is high, it outputs "21". The same happens when port 2 is low, it outputs "20".
C# (an event handler)
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort serialPort1 = sender as SerialPort;
string dataString = (serialPort1).ReadLine();
screen.clearline();
Console.Write(dataString);
if (dataString == "connectAlready")
{
connect.con();
}
if (dataString == "20")
{
Console.WriteLine("pdown");
}
if (dataString == "21")
{
Console.WriteLine("pup");
}
}
This is the event handler called when data is received.
It prints data to the screen such as "21","20", but it does not perform the functions in the If statements.
Any help would be appreciated, thank you very much.
My guess is that the strings you are comparing aren't completely equal. Arduino's documentation for its println() function states that the serial print ends in a carriage return character ('\r'), followed by the newline character ('\n'). The SerialPort.ReadLine() function reads and returns the string "up to the NewLine value in the input buffer" (found here), so the '\r' character is probably still in dataString.
If this is your problem, you can solve it by removing the last character with something like:
dataString = dataString.TrimEnd('\r');
I'm making my first steps in Arduino programming and noticed that serial output working only with the default serial console that came with the Arduino software
This is my Arduino Code:
void setup()
{
pinMode(13 , OUTPUT);
Serial.begin(9600);
}
void loop ()
{
if (Serial.available()> 0)
{
Serial.println("Hello World");
char Letter = Serial.read();
if (Letter == '1')
{
digitalWrite(13,HIGH);
}
else if (Letter = '0')
{
digitalWrite(13, LOW);
}
}
}
And for the PC side I'm using the MSDN console application which is working for for any other device I've used before.
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport(VS.90).aspx
All I want for now is for it to print the "Hello World" when property has changed.
Now when I using the Arduino's own serial console every thing works well.
I've checked that the Baud-rate and port are correct, and other settings I've left on default.
What can be the problem ??
Okay so I am stuck for almost 20 days now in the same problem of a serial communication device. I have a hardware sensor which read tags and returns the tag code number on every read through serial com port 1 or 3.Any of these I use doesn't matter. I am using a program I wrote in c# to play with the incoming data.
Now problem is that if forexample:
my sensor reads tag with code "e2 0 10 1 83 10 1 23 7 0 d0 c0 1 be"
It will not read this tag again unless I switch of the sensor and turn it on again (Power reset) . So I can't figure out how to make my sensor forget all the data it read till I closed the port. ANY ONE CAN HELP PLEASE I AM DESPERATE NOW
Some one told me that we need to write to device with some commands but he didn't know more than that.
Here is the current code:
void IntializeSensor()
{
try
{
if (mySerialPort==null)
{
mySerialPort = new SerialPort("COM3");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.ReadTimeout = 2000;
mySerialPort.Handshake = Handshake.None;
LoglistBox.Items.Add("--Port Intilalized at COM1--");
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void OpenPort()
{
try
{
str = "";
if (mySerialPort.IsOpen)
{
ClosePort();
Thread.Sleep(6000);
}
mySerialPort.Open();
LoglistBox.Items.Add("--Port Opened at COM1 Success--");
}
catch (Exception ex)
{
LoglistBox.Items.Add("--Port Opened Failed--Error: "+ex.Message);
}
}
void ClosePort()
{
try
{
mySerialPort.Write("ABCABCABCABCABC");
mySerialPort.DiscardInBuffer();
mySerialPort.DiscardOutBuffer();
mySerialPort.Dispose();
mySerialPort.Close();
LoglistBox.Items.Add("--Port Closed at COM1 Success--");
}
catch (Exception ex)
{
LoglistBox.Items.Add("--Port Closed Failed--Error: " + ex.Message);
MessageBox.Show(ex.Message);
}
}
private void DataReceivedHandler(object sender,SerialDataReceivedEventArgs e)
{
try
{
if (e.EventType != SerialData.Chars) return;
SerialPort COMPort = (SerialPort)sender;
int bytes = COMPort.BytesToRead;
//create a byte array to hold the awaiting data
byte[] comBuffer = new byte[bytes];
//read the data and store it
COMPort.Read(comBuffer, 0, bytes);
// System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
str = ByteArrayToHexString(comBuffer);
holdfirstvalue += str;
//str = str +" "+ str;
//MessageBox.Show("after concat "+str);
if (str.Contains("FF") || str.Contains("F F") || str.Contains("F"))
{
SetText(holdfirstvalue.ToString());// ONE TAG CODE SENT TO BE SET IN LIST
str = "";
holdfirstvalue = "";
}
}
catch (Exception ex)
{
// LoglistBox.Items.Add("--Port Opened Failed--Error: " + ex.InnerException);
MessageBox.Show(ex.Message+" "+ex.InnerException);
}
}
As I understood from your comments, even the program that is shipped with it does not read the same bar-code twice in a row. Am I right?
To me it seems that "the tag reader manufacturer" may have put that mechanism intentionally to prevent user mistakenly scan an item twice at check-out. because it happens a lot that a same stays on the scanner or be crossed against the scanner couple of times when moving things around.
Unless you have access to the scanner Firmware and are able to make changes yourself, I'd say contact the manufacturer. I would contact the manufacturer and ask about this directly. There should be a command that tells the scanner to "Get out of lock mode and restart scanning again" for the special case of scanning a same item several times (e.g. buying multiple similar things.)
They should provide you with a manual with the list of all the commands you can send to your device and you use this commands to build up your system.
One more thing to try! can you scope out your serial port using "Real Term" or any other terminal monitoring application to see if the scanner sends the code to the PC after you scan the same item again or not? This helps you to isolate the problem to make sure if it is the Scanner Firmware or the desktop software. (it seems to me that it is the scanner Firmware ignoring the item because you say it works fine when you reset it)
edit: also I see you are reading your serial port based on DataREadyEvent, again, if it was me, I would add another thread with a very short delay say 20ms or 50ms to keep reading the serial port constantly. there are plenty of examples on how to implement this on the net, one simple and quick way of this is described here:
Read com ports using threading in c#
Hope it helps.
Ok so I finally found the code in hex which actually resets the sensor.
So to help anyone out there who bought Middle Range UHF RFID Reader or any type of this model.
What we did is we hacked into the wires of serial port by soldering copper wire on data pins. Then we attached the other end of those copper wires to my laptop and used the terminal reader "Putty" to see what is actually being sent by the PC to the Reader on RESET HEAD button click.
This way we found the hex code , converted it to byte array and here is the C# code to write it to reader device by serial port and resets the device:
{
mySerialPort.Open();
byte[] bytesToSend = StringToByteArray("A00265F9");// correct command to reset READER
mySerialPort.Write(bytesToSend, 0, 4);
}
public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
I am trying to send a word over to an Arduino running as a server, from a WPF C# application. Every now and again the complete work is not sent.
C# Code
public void send(String message)
{
TcpClient tcpclnt = new TcpClient();
ConState.Content = "Connecting.....";
try
{
tcpclnt.Connect("192.168.0.177", 23);
ConState.Content = "Connected";
String str = message;
Stream stm = tcpclnt.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(str);
stm.Write(ba, 0, ba.Length);
tcpclnt.Close();
}
catch (Exception)
{
ConState.Content = "Not Connected";
return;
}
}
How it is sent to the method:
String mes = "back;";
send(mes);
Arduino code:
if (client.available() > 0) {
// Read the bytes incoming from the client:
char thisChar = client.read();
if (thisChar == ';')
{
//Add a space
Serial.println("");
}
else {
//Print because it's not a space
Serial.write(thisChar);
}
}
The Arduino is using the chat server example. I am sending "back;" and "forward;" across. The results on the serial monitor:
back
forwaback
forward
back
forwaforwar
The problem seems to be with this code:
if (client.available() > 0) {
// read the bytes incoming from the client:
char thisChar = client.read();
...
}
What it does is:
Check if we have received data from the client
Read a single byte from the client buffer
Exit, and go on to do other things
As the OP pointed out, this comes direct from Arduino chat server example. In that example, this working correctly in loop() depends on the alreadyConnected flag being set right after a new connection is made: if it isn't, then the buffer is flushed before any data is read. That's one possible landmine.
Nonetheless, there is no reason to change the if block to be a while loop in the OP's case so, in other words instead of
if (client.available() > 0) {
have
while (client.available() > 0) {
The only reason to have an if statement there is to make sure that you frequently do other processing in loop() if you have clients that send a lot of data: If the reading of client data is done from inside a while this loop will not exit until the there is no more data from the client. Since this doesn't seem to be an issue in the asked-about case, the if to while change makes sense.