Ouput on Serial:
I ª±±½�World!
I ª±±½�World!
I ª±±½�World!
InHello World!
I ª±±½�World!
I ª±±½�World!
I ª±±½�World!
I ª±±½�World!
I ª±±½�World!
The Ardiuno (UNO R3) unit seems to be rebooting when calling the foo() function.
I would like to use the foo() function to be able to get the data that I need and pass it to different exit points later down the line. eg. Ethernet, wireless or in this case serial.
I have been trying to follow a few tutorials on memory optimization such as these:
The buffer[] in the function "foo" is created on the stack. When the function ends, the buffer[] is out of scope and no longer valid. You can make it a global variable or make it 'static', then it has a fixed location in ram.
Could you make changes. It should be used like this:
I have managed to get something working now.
Once I changed the table to const char * const it stopped crashing.
I have expanded the code a bit to give more of a view to what I wanted.
I do still need to work on rejecting strings that are longer than the buffer. This causes another crash if it is too bit
Comments on the current code are welcome.
char buffer[10];
enum {string1,string2,string3,string4,string5};
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";
//const char string_5[] PROGMEM = "This is a extra long string to break stuff and see what happens";
const char * const string_table[] PROGMEM =
{
string_1,
string_2,
string_3,
string_4,
string_5
};
void setup(){
Serial.begin(115200);
Serial.println(F("Hello World!"));
if (foo(string1)) Serial.print(F("In Setup: ")); Serial.println(buffer);
if (foo(string2)) Serial.print(F("In Setup: ")); Serial.println(buffer);
}
void loop(){
Serial.println("tick");
delay(3000);
for (int i = 0; i < 5; i++)
{
if (foo(i)) Serial.print(F("In loop. | ")); Serial.println(buffer);
}
}
bool foo(int i)
{
// Display buffer on LCD.
Serial.print(F("In Function. | "));
char * ptr = (char *)pgm_read_word(&string_table [i]);
strcpy_P(buffer, ptr );
Serial.print("buffer = ");
Serial.println(buffer);
return true;
}
You use the PROGMEM with a string table as it should be.
The 'enum' is almost the same as using an index. It might also be confusing that "string1" is an index and "string_1" is a string in flash memory.
Do you want the 'enum' to have more explaining names for the strings ? Because at the moment is the only an extra name for an index.
Please use indents, spaces, brackets and everything in the same way. Don't try to put everything on the same line.
This is not okay: if (foo(string1)) Serial.print(F("In Setup: ")); Serial.println(buffer);The first Serial.print is within the if-statement, but the second Serial.println is outside the if-statement.
Everyone has his/her own style to write code. I would do it like this:
enum {stringIndex0, stringIndex1, stringIndex2, stringIndex3, stringIndexApples};
const char string_0[] PROGMEM = "String 1";
const char string_1[] PROGMEM = "String 2";
const char string_2[] PROGMEM = "String 3";
const char string_3[] PROGMEM = "String 4";
const char string_4[] PROGMEM = "Apples ";
const char * const string_table[] PROGMEM =
{
string_0, // stringIndex0
string_1, // stringIndex1
string_2, // stringIndex2
string_3, // stringIndex3
string_4, // stringIndexApples
};
char buffer[20];
void setup()
{
Serial.begin(115200);
while (!Serial); // Added for Leonardo
Serial.println(F("Hello World!"));
if (foo(stringIndex0))
{
Serial.print(F("In Setup: "));
Serial.println(buffer);
}
if (foo(stringIndex1))
{
Serial.print(F("In Setup: "));
Serial.println(buffer);
}
}
void loop()
{
Serial.println("tick");
delay(3000);
for (int i = 0; i < 5; i++)
{
if (foo(i))
{
Serial.print(F("In loop. | "));
Serial.println(buffer);
}
}
}
bool foo(int i)
{
// Display buffer on LCD.
Serial.print(F("In Function. | "));
// The next line retrieves the pointer to the string in flash.
// This is also allowed: const char * ptr = (const char *)pgm_read_word(&string_table[i]);
char * ptr = (char *)pgm_read_word(&string_table[i]);
strcpy_P(buffer, ptr);
Serial.print("buffer = ");
Serial.println(buffer);
return true;
}
An array starts at zero, so it is easier to name the first string with a zero. Both links in my Reply #1 use names that start with a zero.
@Koepel, Thanks for the input.
I was not aware that the if statement was only until the first ;. I assumed that it was till the end of the line aka \n.
My cheeky lazy coding has failed me on that one.
The idea here was to refactor the code from the original youtube video which no longer works with the newer versions of the libraries. Here is the github to the original code.
The enum idea was taken from the above and allows for the use of a case statement when looking at incoming commands.
What I want out of it is basically a API that I can interrogate for states/readings and also to control things like pumps, lights and fans.
This hopefully will then evolve into the controllers for an automated poly tunnel.
If all goes well hopefully also a decent instructables post
Don't copy that bad code into your sketch. The (temporary) buffer is created on the stack, and after the function returns the buffer is out of scope and may be overwritten. But the pointer to the (temporary) buffer is still used outside the function. That is bad programming.
A semicolon after a function is not needed.