I've just started a new project. I have a game pad that communicates with my arduino using a VB.net interface.
The data that is send to the arduino looks something like this (depending on what button is pressed): ~ButtonLeft#
Where ~is the Header, # is the footer and ButtonLeft is the button being pushed on the game pad.
I use the following code to read the serial data, but something goes wrong and at the moment I am completely lost....... :-?
const char HEADER = '~';
const char FOOTER = '#';
// Serial read constants
const byte INPUT_MAX_LENGTH = 10;
//Serial read variables
char StringIn[INPUT_MAX_LENGTH] = {
'\0'};
void ReceivedSerialData(){
if(Serial.available() > 0) {
char IncomingByte = 0;
char CharIn = 0;
IncomingByte = Serial.read();
if (IncomingByte == HEADER) {
int i = 0;//index of char array
StringIn[i++] = HEADER; //add the header to the char array
do {
CharIn = Serial.read();
StringIn[i++] = CharIn;
}
while ( CharIn != FOOTER && i<INPUT_MAX_LENGTH-1); //we can not exceed the MAX_LENGTH
for (int j=i; j<INPUT_MAX_LENGTH; j++) {
StringIn[j] = '\0'; // null out string
}
Serial.flush();
}
}
}
void setup()
{
Serial.begin(9600);
Serial.print("~SetupOK#");
Serial.flush();
}
void loop(){
ReceivedSerialData();
}
The problem is if I send ~test# in the arduino serial monitor it is displayed the right way, but right after the display of ~test# a lot of rubbish is printed?
What's wrong with the code? It is a modified version from a previous project and a far as I can see, it looks OK ( but I've been staring to it for a long time......). So a fresh look will help
You checked that there was at least one byte to read.
How many characters do you then read?
do {
CharIn = Serial.read();
StringIn[i++] = CharIn;
}
while ( CharIn != FOOTER && i<INPUT_MAX_LENGTH-1);
All this code comes after you made sure that there was some data. There may have been only one byte available, which was the header.
This is unnecessary:
for (int j=i; j<INPUT_MAX_LENGTH; j++) {
StringIn[j] = '\0'; // null out string
}
One NULL is sufficient. Printing will stop when the first NULL is encountered.
Why are you doing this?
Serial.flush();
Any pending serial that has not yet been read just got dumped. Unless you know what you are doing, and there is a real reason to do this, don't.
The problem is if I send ~test# in the arduino serial monitor it is displayed the right way, but right after the display of ~test# a lot of rubbish is printed?
I don't see where you are printing the received data.
I want to read characters until the FOOTER ("#" ). That what I am doing using this code I assume:
do {
CharIn = Serial.read();
StringIn[i++] = CharIn;
}
while ( CharIn != FOOTER && i<INPUT_MAX_LENGTH-1);
Ok, so only one NULL ('/0') is necessary in an array of chars. Should this be after the last char in the array or at the last position of the array?
Serial.flush();
The Serial.flush(); was just a desperate attempt to stop the Arduino from printing rubbish.
Another thing: The serial.available() can hold 128 bytes. What will happen when more characters are send to the Arduino (200)? Will it overflow and cause a reset for example? Or will byte 129 until 200 be lost?
Well the printing code code lost when i made this post... It looks like this:
Serial.print("~")
for (int j=0; j=INPUT_MAX_LENGTH; j++) {
Serial.print(StringIn[j])
}
Serial.print("#")
do {
CharIn = Serial.read();
StringIn[i++] = CharIn;
}
while ( CharIn != FOOTER && i<INPUT_MAX_LENGTH-1);
For reading serial data, a do/while loop is really a bad idea. The reason is that the body of the do/while loop is executed at least once. In the case of reading serial data, it might be that the body should not be executed at all, in the case of there being no data to read.
Instead, use a plain while loop.
CharIn = '\0';
while(Serial.available() > 0 && CharIn != FOOTER && i<INPUT_MAX_LENGTH-1)
{
CharIn = Serial.read();
StringIn[i++] = CharIn;
StringIn[i] = '\0'; // Append a NULL so the string is NULL terminated
}
based on you suggestions I've modified the code. Please note that I am not an professional coder!! The code may contain some non efficient structure. But I just want to show it and share it.
If you have got any suggestions (more efficient routine) please let me know.
Thanks a lot!!
Cheers.
/*This example reads serial data.
The serial data should contain a one character header and a one character footer.
*/
// Header and Footer
const char HEADER = '~';
const char FOOTER = '#';
// Maximum number of elements allowed in StringIn
const int INPUT_MAX_LENGTH = 30;
//Serial read variables
char StringIn[INPUT_MAX_LENGTH] = {
'\0'};
void setup()
{
Serial.begin(9600);
Serial.println("~SetupOK#");
Serial.flush();
}
void loop(){
if(Serial.available() > 0) {
// Read the first byte in the buffer
char IncomingByte = Serial.read();
Serial.println(IncomingByte);
// Check if first char is footer
if (IncomingByte == HEADER) {
Serial.println("Header found!!"); //Debugging code
int i = 0;//index of char array
StringIn[i++] = HEADER; //add the header to the char array
// This loop reads the remaining bytes based on certain criteria.
while(Serial.available() > 0)
{
//Check if String in still has elements available. If not array will be termindated
if (i != (INPUT_MAX_LENGTH - 1)){
//If serial data is in buffer read the next char
IncomingByte = Serial.read();
Serial.println(IncomingByte);
// Check if read char is footer, if yes add to array and add NULL
if (IncomingByte == FOOTER) {
Serial.println("Footer found!!");
StringIn[i++] = FOOTER; //add footer to the char array
StringIn[i++] = '/0'; // add NULL
Serial.println(i); // print the amount of elemnts in array. Debugging code.
// Print the array. Debugging code
for(int j=0; j < i ; j++){
Serial.println(StringIn[j]);
}
break; // stop the while loop
}
// No footer found yet but character in between. It will be added to the array.
else
{
Serial.println("Other char added to array!!"); //Debugging code
StringIn[i++] = IncomingByte;
}
}
// Array full. Probably no footer found.
else
{
StringIn[i++] = '/0'; // add NULL
Serial.println("~Warning: Array overflow, no footer found!! Serial buffer flushed!!#");
Serial.flush();
break; // Break the loop.
}
}
}
}
}
I only had a quick scan of your sketch, but I'd say it's too complex.
Look at the level of nesting of "if"s and "while"s - it's difficult to follow.
I don't think the "flush" is necessary.
Maybe think about how you'd implement this, if all you had was a single function "getChar" that returned a single, received character.