I'm working on a program that controls a stepper board. The board issues an '' character each time it finished a command. So, I have some code that waits for the * and then issues a stepper location. The board also issues feedback on location and such. Right now I use a String object to load in the response form the board and print it out to the serial monitor. After feedback on this forum, I'm trying to replace this String object with a character array so that I don't run into memory problems. However, I'm running into compiling problems and I get a lot of "invalid conversion from 'char' to 'const char'" errors doing what I'm doing. I think there is some char* vs char stuff going on that I don't quite understand.
Here is the code that compiles with my String object. The comparison between the readString object and the "L,16392" isn't working, but that's kinda why I'm trying to change these Objects to C strings...in hopes that I can make that comparison work out. Right now my output looks like it is the same, but the IF statement always says that the strings are not equal.
/*
CNC Bed Sketch
This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
*/
//******************Constants***********
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
char homePosition[5] = "0XYG";
//******************Variables***********
String readString;
int commandNumber = 0;
int numCommands = 0;
//****************Function Prototypes******
long convertToSteps(int inches);
//***************Setup******************************
void setup() {
delay(1000);
Serial.begin(9600); //Begin serial communication at 9600
mySerial.begin(9600); //Set software serial baud rate
randomSeed(analogRead(0));
// Initialize Stepperboard Values
mySerial.write("!"); //reset Stepper Board
delay(50);
mySerial.write("1500R"); //Set Run Rate
delay(50);
mySerial.write("800P"); //Set Ramp Rate
delay(1000);
}
//*************Main Program Loop************************
void loop() {
char* stepCommand[] = { //Load up CNC Patterns into string array
"30000XG",
"-30000XG"
};
int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size
while(mySerial.available()){
char c = mySerial.read(); //get one byte from buffer
readString += c;
if(c== '*'){
mySerial.write(stepCommand[commandNumber]);
Serial.print(stepCommand[commandNumber]);
Serial.println(" --> IF LOOP");
commandNumber++;
if(commandNumber == numCommands){ //if the max number of commands is reached...
commandNumber = 0; //reset command number back to zero
}
break;
}
}
mySerial.write("L");
if(readString.length() > 0){
Serial.println(readString + " --> ReadString");
String response = "L,16392";
if(readString == response){
Serial.println("Write Q Here");
}
else{
Serial.println("Strings not Egual");
}
readString = ""; //clears variable for new input
}
}
//*********************FUNCTIONS***************************
long convertToSteps(int inches){
long steps = 130435 * inches; //there are 130435 steps in 1-inch
return(steps);
}
//**************************************************************************
And here is my attempt at converting the readString into a C character array. I made an array 20 characters long to hold the myserial.read() data. I'm trying to use the strcat() concatenate function to load charachters into the array, but I get the "invalid conversion from 'char' to 'const char*'" errors. I can get around the errors by pointing to the address of c like:
strcat(readString, &c); but the output is all garbled up.
/*
CNC Bed Sketch
This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
*/
//******************Constants***********
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
char homePosition[5] = "0XYG";
//******************Variables***********
char readString[20];
int commandNumber = 0;
int numCommands = 0;
int i = 0;
//****************Function Prototypes******
long convertToSteps(int inches);
//***************Setup******************************
void setup() {
delay(1000);
Serial.begin(9600); //Begin serial communication at 9600
mySerial.begin(9600); //Set software serial baud rate
randomSeed(analogRead(0));
// Initialize Stepperboard Values
mySerial.write("!"); //reset Stepper Board
delay(50);
mySerial.write("1500R"); //Set Run Rate
delay(50);
mySerial.write("800P"); //Set Ramp Rate
delay(1000);
}
//*************Main Program Loop************************
void loop() {
char* stepCommand[] = { //Load up CNC Patterns into string array
"30000XG",
"-30000XG"
};
int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size
while(mySerial.available()){
char c = mySerial.read(); //get one byte from buffer
strcat(readString, c);
if(c== '*'){
mySerial.write(stepCommand[commandNumber]);
Serial.print(stepCommand[commandNumber]);
Serial.println(" --> IF LOOP");
commandNumber++;
if(commandNumber == numCommands){ //if the max number of commands is reached...
commandNumber = 0; //reset command number back to zero
}
break;
}
}
mySerial.write("L");
if(strlen(readString) > 0){
Serial.print(readString);
Serial.println(" --> Read String");
char response[10] = "L,16392";
if(strncmp(readString, response, 7) == 0){
Serial.println("Write Q Here");
}
else{
Serial.println("Strings not Equal");
}
for(int j = 0; j <= 20; j++){
readString[j] = ' '; //clears variable for new input
}
}
}
//*********************FUNCTIONS***************************
long convertToSteps(int inches){
long steps = 130435 * inches; //there are 130435 steps in 1-inch
return(steps);
}
//**************************************************************************
In the char array version, the readString array is NOT NULL terminated. Life will be a lot more pleasant when you NULL terminate it.
for(int j = 0; j <= 20; j++){
readString[j] = ' '; //clears variable for new input
}
Wrong.
readString[0] = '\0';
is all that is needed.
When you concatenate a character onto the end of your array, the strcat() function looks for the NULL, and replaces it with the new character(s), and then puts the NULL in the next empty spot. No NULL means that strcat() is going to write outside the bounds of your array.
I'm getting closer. I'm a bit confused on how to make sure readString is null terminated..I just chose the last place in the array and put a '\0' there. I made c a character array and null terminated the second spot. So, now the strcmp() function is working. Looking at the serial monitor output, it makes sense that readString is loading up. I've noticed that if I increase the size of the serialRead array, I get more of my code going through. If I don't make it big enough to accept the initialization/firmware strings from the stepper board, it never gets to the " * " and my motors won't start. If I make the readString array around [40] my code will go load for a while and stop. If I make it [100], the code runs for a long time, and doesn't seem to stop. Any clue as to what going on here?
The string compare function that compares my limit code "L,16392" to readString still doesn't work, even if I put an * on the end. So, there is still something fishy there, too.
/*
CNC Bed Sketch
This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
*/
//******************Constants***********
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
char homePosition[5] = "0XYG";
//******************Variables***********
char readString[100];
int commandNumber = 0;
int numCommands = 0;
//****************Function Prototypes******
long convertToSteps(int inches);
//***************Setup******************************
void setup() {
delay(1000);
readString[99] = '\0'; //Add a null termination to readString
Serial.begin(9600); //Begin serial communication at 9600
mySerial.begin(9600); //Set software serial baud rate
randomSeed(analogRead(0));
// Initialize Stepperboard Values
mySerial.write("!"); //reset Stepper Board
delay(50);
mySerial.write("1500R"); //Set Run Rate
delay(50);
mySerial.write("800P"); //Set Ramp Rate
delay(1000);
}
//*************Main Program Loop************************
void loop() {
char* stepCommand[] = { //Load up CNC Patterns into string array
"30000XG",
"-30000XG"
};
int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size
while(mySerial.available()){
char c[2] = {mySerial.read(), '\0'} ; //get one byte from buffer
strcat(readString, c);
//Serial.print(c);
//Serial.println(" --> c charachter byte");
if(strcmp(c, "*") == 0){
mySerial.write(stepCommand[commandNumber]);
Serial.print(stepCommand[commandNumber]);
Serial.println(" --> IF LOOP");
commandNumber++;
if(commandNumber == numCommands){ //if the max number of commands is reached...
commandNumber = 0; //reset command number back to zero
}
break;
}
}
mySerial.write("L");
if(strlen(readString) > 0){
Serial.print(readString);
Serial.println(" --> Read String");
char response[10] = "L,16392";
response[9] = '\0';
if(strncmp(readString, response, 7) == 0){
Serial.println("Write Q Here");
}
else{
Serial.println("Strings not Equal");
}
readString[0] = '\0'; //clear the array
}
}
//*********************FUNCTIONS***************************
long convertToSteps(int inches){
long steps = 130435 * inches; //there are 130435 steps in 1-inch
return(steps);
}
//**************************************************************************
SERIAL MONITOR OUTPUT BELOW:
M1,-12
SD4DNCRouter 4.3 Oct 3, 2011
o?
--> Read String
Strings not Equal
-30000XG --> IF LOOP
?
--> Read String
Strings not Equal
30000XG --> IF LOOP
?
--> Read String
Strings not Equal
-30000XG --> IF LOOP
?
G3* --> Read String
Strings not Equal
30000XG --> IF LOOP
?
L,256
--> Read String
Strings not Equal
-30000XG --> IF LOOP
?
--> Read String
Strings not Equal
30000XG --> IF LOOP
?
G2* --> Read String
Strings not Equal
-30000XG --> IF LOOP
?
L,0
--> Read String
Strings not Equal
30000XG --> IF LOOP
I'm a bit confused on how to make sure readString is null terminated..I just chose the last place in the array and put a '\0' there.
You should quit trying to use strcat() to append the character to the string. The problem with that is that it expects the string being appended to to be NULL terminated. And, yours isn't.
NULL terminated means that the NULL goes at the end of the valid data NOT at the end of the array.
Start with the NULL in the 0th position.
Ditch using strcat(). Create an index, and increment that every time a character is added (after adding the character), and put the NULL at the location defined by index.
Of course, use your own names, and the code does not go together like this snippet shows. index and array are global (in your case) and the other code goes inside the while statement, where you are currently using strcat().
Let's see how much better this makes things for you, as the next step. Then, if there are still issues, we'll work on them.
Thanks, Paul. I've indexed the array and its working better. I've tried to get an idea of what is in the readSting array by using a FOR loop to print each character and where it is in the array. Just the initialization strings sent from the control board after power up eats up 43 array spots. I copied a portion of the Serial Monitor output showing where I hit the limit switch. The "L,16392" in the readString array seems to be chopped into spaces and some other garbage characters. So, I either need to filter the characters coming into the array so I don't get the garbage. Or, I have to somehow modify my strcmp() function to start looking at the "L" character and then read the array from there. Maybe strbrk() would do this? Any recommendations?
SERIAL MONITOR OUTPUT:
? ---> Character 0
---> Character 1
? ---> Character 2
---> Character 3
? ---> Character 4
---> Character 5
L ---> Character 6
, ---> Character 7
0 ---> Character 8
---> Character 9
---> Character 10
---> Character 11
?
?
?
L,0
--> Read String
Strings not Equal
-30000XG --> IF LOOP
30000XG --> IF LOOP
-30000XG --> IF LOOP
30000XG --> IF LOOP
-30000XG --> IF LOOP
---> Character 0
? ---> Character 1
---> Character 2
L ---> Character 3
, ---> Character 4
1 ---> Character 5
6 ---> Character 6
3 ---> Character 7
9 ---> Character 8
2 ---> Character 9
---> Character 10
---> Character 11
---> Character 12
?
L,16392
--> Read String
Strings not Equal
30000XG --> IF LOOP
-30000XG --> IF LOOP
30000XG --> IF LOOP
-30000XG --> IF LOOP
/*
CNC Bed Sketch
This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
*/
//******************Constants***********
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
char homePosition[5] = "0XYG";
//******************Variables***********
char readString[70];
char c;
int i = 0;
int commandNumber = 0;
int numCommands = 0;
//****************Function Prototypes******
long convertToSteps(int inches);
//***************Setup******************************
void setup() {
delay(1000);
//readString[0] = '\0'; //Add a null termination to readString
Serial.begin(9600); //Begin serial communication at 9600
mySerial.begin(9600); //Set software serial baud rate
randomSeed(analogRead(0));
// Initialize Stepperboard Values
mySerial.write("!"); //reset Stepper Board
delay(50);
mySerial.write("1500R"); //Set Run Rate
delay(50);
mySerial.write("800P"); //Set Ramp Rate
delay(1000);
}
//*************Main Program Loop************************
void loop() {
char* stepCommand[] = { //Load up CNC Patterns into string array
"30000XG",
"-30000XG"
};
int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size
while(mySerial.available()){
c = mySerial.read(); //get one byte from buffer
readString[i++] = c; //increment array (original array index is returned)
readString[i] = '\0'; //Add NULL to next index
//i=i+1;
//Serial.print(c);
//Serial.println(" --> c charachter byte");
if(readString[i-1]== '*'){
mySerial.write(stepCommand[commandNumber]);
Serial.print(stepCommand[commandNumber]);
Serial.println(" --> IF LOOP");
commandNumber++;
if(commandNumber == numCommands){ //if the max number of commands is reached...
commandNumber = 0; //reset command number back to zero
}
break;
}
}
mySerial.write("L");
if(strlen(readString) > 0){
for(int j=0; j < strlen(readString); j++){
Serial.print(readString[j]);
Serial.print(" ---> Character ");
Serial.println(j);
}
Serial.print(readString);
Serial.println(" --> Read String");
char response[] = {'L', ',','1', '6', '3', '9', '2',' ','\0'};
if(strcmp(readString, response) == 0){
Serial.println("Write Q Here");
}
else{
Serial.println("Strings not Equal");
}
readString[0] = '\0'; //clear the array
}
}
//*********************FUNCTIONS***************************
long convertToSteps(int inches){
long steps = 130435 * inches; //there are 130435 steps in 1-inch
return(steps);
}
//**************************************************************************
Good and bad. The problem here is that you are not also resetting i to 0. The name i is terrible. One letter global variables generally are. The name index is a much better choice.
All right. So I changed the println command in include HEX and the spaces disappear. I also set index back to zero right after I clear the array. The Hex shows all the crap in there. Thats a good trick! Now, I think I can use the strstr() function (or something) to pluck out useful string. Or, is there an easier way to do that?
LIMIT SWITCH PORTION OF SERIAL MONITOR OUTPUT:
30000XG --> IF LOOP
Character Read:
FFFFFF86 ---> Character 0
A ---> Character 1
FFFFFF86 ---> Character 2
A ---> Character 3
FFFFFF86 ---> Character 4
A ---> Character 5
4C ---> Character 6
2C ---> Character 7
31 ---> Character 8
36 ---> Character 9
33 ---> Character 10
39 ---> Character 11
32 ---> Character 12
D ---> Character 13
A ---> Character 14
2A ---> Character 15
?
?
?
L,16392
--> Read String
Strings not Equal
/*
CNC Bed Sketch
This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
*/
//******************Constants***********
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
char homePosition[5] = "0XYG";
//******************Variables***********
char readString[70];
char c;
int index = 0;
int commandNumber = 0;
int numCommands = 0;
//****************Function Prototypes******
long convertToSteps(int inches);
//***************Setup******************************
void setup() {
delay(1000);
//readString[0] = '\0'; //Add a null termination to readString
Serial.begin(9600); //Begin serial communication at 9600
mySerial.begin(9600); //Set software serial baud rate
randomSeed(analogRead(0));
// Initialize Stepperboard Values
mySerial.write("!"); //reset Stepper Board
delay(50);
mySerial.write("1500R"); //Set Run Rate
delay(50);
mySerial.write("800P"); //Set Ramp Rate
delay(1000);
}
//*************Main Program Loop************************
void loop() {
char* stepCommand[] = { //Load up CNC Patterns into string array
"30000XG",
"-30000XG"
};
int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size
while(mySerial.available()){
c = mySerial.read(); //get one byte from buffer
readString[index++] = c; //increment array (original array index is returned)
readString[index] = '\0'; //Add NULL to next index
//i=i+1;
//Serial.print(c);
//Serial.println(" --> c charachter byte");
if(readString[index-1]== '*'){
mySerial.write(stepCommand[commandNumber]);
Serial.print(stepCommand[commandNumber]);
Serial.println(" --> IF LOOP");
commandNumber++;
if(commandNumber == numCommands){ //if the max number of commands is reached...
commandNumber = 0; //reset command number back to zero
}
break;
}
}
mySerial.write("L");
if(strlen(readString) > 0){
Serial.println("Character Read: ");
for(int j=0; j < strlen(readString); j++){
Serial.print(readString[j], HEX);
Serial.print(" ---> Character ");
Serial.println(j);
}
Serial.println("======================");
Serial.print(readString);
Serial.println(" --> Read String");
char response[] = {'L', ',','1', '6', '3', '9', '2','\0'};
if(strcmp(readString, response) == 0){
Serial.println("Write Q Here");
Serial.println("");
}
else{
Serial.println("Strings not Equal");
Serial.println("");
}
readString[0] = '\0'; //clear the array
index = 0;
}
}
//*********************FUNCTIONS***************************
long convertToSteps(int inches){
long steps = 130435 * inches; //there are 130435 steps in 1-inch
return(steps);
}
//**************************************************************************
Maybe. The values starting with FF are clearly negative values. So, it appears that the device you are talking to is sending a mix of binary and ASCII data. You could store only those characters that are meaningful to humans ('0' to '9', 'A' to 'Z', and 'a' to 'z'). Stop storing when the '*' arrives. This will exclude the ',', but that might be OK. You could elect to use a different range (or ranges) for the characters to store (maybe ' ' to 'z'), which would then include the ','.
I used the strstr() function and it seems to be working. I finally got the code to recognize the output. So, a minor victory! Thanks a ton.
Now, I use this information to set the home position for my CNC, or to let me know if my bed over-traveled in the +X, -X, +Y or -Y directions. Each limit has it's own L,XXXX code. In the grand scheme of things, I'd like to be able to call a function like "triangle" or "square" that would fill my stepCommand array with the desired string commands. This involves loading my char *stepCommand array with passed from functions, which I'm guessing is going to be a pain. But, I'll research that and see what I can do.
Serial Monitor output at limit switch activation:
-30000XG --> IF LOOP
Character Read:
FFFFFF86 ---> Character 0
A ---> Character 1
4C ---> Character 2
2C ---> Character 3
31 ---> Character 4
36 ---> Character 5
33 ---> Character 6
39 ---> Character 7
32 ---> Character 8
D ---> Character 9
A ---> Character 10
2A ---> Character 11
?
L,16392
--> Read String
Write Q Here
/*
CNC Bed Sketch
This program drives a Peter Norburg SD4DEU Stepper Driver board running SD4DNCRouter firmware connecting at 9600 Baud.
*/
//******************Constants***********
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
char homePosition[5] = "0XYG";
//******************Variables***********
char readString[70];
char c;
int index = 0;
int commandNumber = 0;
int numCommands = 0;
//****************Function Prototypes******
long convertToSteps(int inches);
//***************Setup******************************
void setup() {
delay(1000);
//readString[0] = '\0'; //Add a null termination to readString
Serial.begin(9600); //Begin serial communication at 9600
mySerial.begin(9600); //Set software serial baud rate
randomSeed(analogRead(0));
// Initialize Stepperboard Values
mySerial.write("!"); //reset Stepper Board
delay(50);
mySerial.write("1500R"); //Set Run Rate
delay(50);
mySerial.write("800P"); //Set Ramp Rate
delay(1000);
}
//*************Main Program Loop************************
void loop() {
char* stepCommand[] = { //Load up CNC Patterns into string array
"30000XG",
"-30000XG"
};
int numCommands = (sizeof(stepCommand)/sizeof(char*)); //Calculate array size
while(mySerial.available()){
c = mySerial.read(); //get one byte from buffer
readString[index++] = c; //increment array (original array index is returned)
readString[index] = '\0'; //Add NULL to next index
//i=i+1;
//Serial.print(c);
//Serial.println(" --> c charachter byte");
if(readString[index-1]== '*'){
mySerial.write(stepCommand[commandNumber]);
Serial.print(stepCommand[commandNumber]);
Serial.println(" --> IF LOOP");
commandNumber++;
if(commandNumber == numCommands){ //if the max number of commands is reached...
commandNumber = 0; //reset command number back to zero
}
break;
}
}
mySerial.write("L");
if(strlen(readString) > 0){
Serial.println("Character Read: ");
for(int j=0; j < strlen(readString); j++){
Serial.print(readString[j], HEX);
Serial.print(" ---> Character ");
Serial.println(j);
}
Serial.println("======================");
Serial.print(readString);
Serial.println(" --> Read String");
char response[10];
response[0] = '\0';
if((strstr(readString, "L,16392")) != 0){
Serial.println("Write Q Here");
Serial.println("");
}
else{
Serial.println("Strings not Equal");
Serial.println("");
}
readString[0] = '\0'; //clear the array
index = 0;
}
}
//*********************FUNCTIONS***************************
long convertToSteps(int inches){
long steps = 130435 * inches; //there are 130435 steps in 1-inch
return(steps);
}
//**************************************************************************