I've been working on a large project to build an automated system in my lab. I'm using the library from this post and going off their examples for making an Arduino talk to the PC through the serial port:
The Arduino code reads characters from the serial port until it reaches a carriage return and then parses the string into a command, which tells it to move various actuators in the system. This part of the code seems to be working fine, but the .ino file is attached for reference. The important part of the code is in the serialEvent() function.
The C++ code uses the library from the link above. I created a small test loop before the rest of the code for debugging which looks like this:
To clarify, the variable pcr is defined before this and is a pointer to the carriage return character. When I attempt to run this code I get the output in the .jpg attached to the post. First I sent the command "getp" which causes the the arduino to send back a string with with the x and y position of two actuators in the system. I also put in some other print statements while I was debugging earlier, which is why it also prints back the input each iteration as it reads it off the serial and a string "Valid Command." when it confirms that there was a carriage return at the end. Finally it sends the string that it should followed by "ok" which it prints after every command. All of this is fine, but then it starts sending back a bunch of gibberish as if the serials had mismatched baudrates. I then sent another command "setpx0y0"; however it only repeated this gibberish and didn't print back any of the debug statements. This doesn't happen when I use the serial monitor. Does anyone know what the problem could be?
if I run code using the serial monitor or teraterm it appears towork OK, e.g. teraterm
g
ge
get
getp
getp
Valid Command.
X: -1.38, Y: -1.00
ok
s
se
set
setp
setpx
setpx0
setpx0y
setpx0y0
setpx0y0
Valid Command.
ok
g
ge
get
getp
getp
Valid Command.
X: 0.00, Y: 0.00
ok
it looks as though the C++ code is the problem
which C++ compiler are you using?
what happens in
readResult = SP->ReadData(incomingData, dataLength);
//printf("Bytes read: (0 means no data available) %i\n", readResult);
incomingData[readResult] = 0;
if there is no data available and ReadData() returns -1 ?
you will access array index -1 which is before the start of the array hence corrupting memory
//Read data in a buffer, if nbChar is greater than the
//maximum number of bytes available, it will return only the
//bytes available. The function return -1 when nothing could
//be read, the number of bytes actually read.
int ReadData(char *buffer, unsigned int nbChar);
could you do something along the lines of
while((readResult = SP->ReadData(incomingData, dataLength)) <= 0) ;
//printf("Bytes read: (0 means no data available) %i\n", readResult);
incomingData[readResult] = 0;
i.e. loop until data is available
using Visual Studio I tend to use the SerialPort component from the toolbox
I'm thinking this error might have something to do with the RX buffer on the Arduino becoming corrupted. My reasoning for this is because I set the Arduino's code to print out "Event" whenever SerialEvent was called and print out each character as it read it. When I ran it again I got the attached result. The program seems to run SerialEvent until it gets to the carriage return, prints what it's supposed to, but the SerialEvent is trigger several more times as it seems to parse data that was not meant to be reached. Subsequent commands don't have as much effect. I made some slight changes to the C++ code so here it is again for reference:
Yes, I noticed that and changed it after I posted, but it didn't seem to change anything. I don't know why I had it set to that in the first place, but it doesn't seem to be the root of the problem.
hello
length = 9
Ï■mlo
Process returned 0 (0x0) execution time : 2.900 s
I enter "hello" and append a carriage retrun which should be six characters but it displays the outputData string length as 9 characters and the display of outputData shows none printable characters
the problem is you have defined cr as a single character '\r' not as a C string with a terminating '\0' so when it is appended to outputData you append '\r' and whatever is in memory until a 0 is found
const byte Led = 13; // Declaramos la variable pin del Led.
char caracter;
String comando;
void setup()
{
pinMode(Led, OUTPUT); // Inicializa el pin del LED como salida:
Serial.begin(115200); // Puerto serie 115200 baudios.
}
void loop()
{
/*
Voy leyendo carácter a carácter lo que se recibe por el canal serie
(mientras llegue algún dato allí), y los voy concatenando uno tras otro
en una cadena. En la práctica, si usamos el "Serial monitor" el bucle while
acabará cuando pulsamos Enter. El delay es conveniente para no saturar el
canal serie y que la concatenación se haga de forma ordenada.
*/
while (Serial.available() > 0)
{
caracter = Serial.read();
comando.concat(caracter);
delay(10);
}
/*
Una vez ya tengo la cadena "acabada", compruebo su valor y hago que
la placa Arduino reacciones según sea este. Aquí podríamos hacer lo
que quisiéramos: si el comando es "tal", enciende un Led, si es cual,
mueve un motor... y así.
*/
// Si le llega el mensaje Luz_ON.
if (comando.equals("Luz_ON") == true)
{
digitalWrite(Led, HIGH); // Enciende el Led 13.
Serial.write("ON - Led encendido."); // Envía este mensaje a C++.
}
// Si le llega el mensaje Luz_ON.
if (comando.equals("Luz_OFF") == true)
{
digitalWrite(Led, LOW); // Apaga el Led 13.
Serial.write("OFF - Led apagado. "); // Envía este mensaje a C++.
}
// Limpiamos la cadena para volver a recibir el siguiente comando.
comando = "";
}
C++:
#include
#include
#include
#include "SerialClass.h"
using namespace std;
void main()
{
// Título de la ventana
SetConsoleTitle("Control Led Arduino - Visual Studio C++ 2017");
// Puerto serie.
Serial* Puerto = new Serial("COM4");
// Comandos para Arduino.
char Luz_ON[] = "Luz_ON"; // Envía "Luz_ON" al puerto serie.
char Luz_OFF[] = "Luz_OFF";
char lectura[50] = "\0"; // Guardan datos de entrada del puerto.
int opc; // Guarda un 1 o 2 tipo entero queintroduces desde la consola.
while (Puerto->IsConnected())
{
cout << endl; // Retorno.
cout << "Introduzca la opcion deseada: " << endl;
cout << "Pulse 1 para encender el Led, pulse 2 para apagar." << endl << endl; // Muestra texto en pantalla.
cin >> opc; // Aquí introduces un número, el 1 o el 2.
switch (opc) // Espera recibir un 1 o un 2.
{
case 1:
// Encener luz.
cout << "Enviando: " << Luz_ON << endl; // Muestra en pantalla textos.
Puerto->WriteData(Luz_ON, sizeof(Luz_ON) - 1); // Envía al puerto el texto "Luz_ON".
break;
case 2:
// Apagar luz.
cout << "Enviando: " << Luz_OFF << endl;
Puerto->WriteData(Luz_OFF, sizeof(Luz_OFF) - 1);
break;
default: // Si haz pulsado otro número distinto del 1 y 2, muestra
cout << "Puse del 1 al 2."; // este mensaje.
}
Sleep(500);
int n = Puerto->ReadData(lectura, 49); // Recibe datos del puerto serie.
if (n > 0)
{
lectura[n + 1] = '\0'; // Limpia de basura la variable.
cout << "Recibido: " << lectura << endl; // Muestra en pantalla dato recibido.
cout << "-------------------" << endl;
}
cin.ignore(256, '\n'); // Limpiar buffer del teclado.
}
}