I've got the logic of the program right, as when I remove the PROGMEM stuff and do it all in flash it works fine. Can anyone suggest where it's going wrong, please.
Also:
I've seen in a PROGMEM tutorial the PSTR macro, to print a string directly from program memory. It was demonstrated by:
LCD_puts ( PSTR (" Program Memory String ") );
This looks useful, but doesn't work with:
Serial.println( PSTR (" Program Memory String ") );
I seem to be totally missing something regarding PROGMEM, and can't get the most simple operation to work.
Whilst the following code compiles without a snivel, it just doesn't work - all I get printed from the following is rubbish:
#include <avr/pgmspace.h>
void setup(){
Serial.begin(9600);
const char greet[] PROGMEM = "Hi There!";
char character = char(pgm_read_byte(greet[0]));
Serial.println(character); // I'm expecting an 'H' here, but all I get is a square!
}
void loop(){}
I'd be grateful to anyone who can indicate where I'm going wrong, please!
In my opinion the string greet should be static (or define it globally). I have no idea how the compiler will treat your version. And maybe you could use strcpy_P() to get your strings.
In pgmspace.h it is defined as
extern char *strcpy_P(char *, PGM_P);
but it might be your Arduino version doesn't know this function, I am using a newer toolchain at the moment, just give it a try.
You are dereferencing too soon. So you read the "H" and then try to get something from PROGMEM at address H, not the address where H is. Also don't put the PROGMEM inside a function. This prints H:
My main problem was that I had the PROGMEM string inside setup().
I quoted the array subscript because I wanted to access individual characters, so it really should have had:
char character = pgm_read_byte(&(greet[j])); where j is the subscript for the character I'm interested in. I'd omitted the reference operator!
All this is to get a handle on what I really want to do - that is to access individual characters in an array of strings - this sort of thing:
#include <avr/pgmspace.h>
/* Program to extract just the file name and version number from RCS strings
and display in the form of:
menu.pde:1.2
meter.pde:1.1
current.pde:1.3
temp.pde:1.3
*/
char buffer[100];
const char menu_rcs[] PROGMEM = \
"$Id: menu.pde,v 1.2 2012/03/22 17:40:06 jim Exp $";
const char meter_rcs[] PROGMEM = \
"$Id: meter.pde,v 1.1 2012/03/22 17:40:06 jim Exp $";
const char current_rcs[] PROGMEM = \
"$Id: current.pde,v 1.3 2012/03/22 17:40:06 jim Exp $";
const char temp_rcs[] PROGMEM = \
"$Id: temp.pde,v 1.3 2012/03/22 17:40:06 jim Exp $";
/* Array of pointers to above, also in progmem.
NULL to stop from falling off the end of the array.
*/
const char* rcs_strings[] PROGMEM = {menu_rcs, meter_rcs, current_rcs, temp_rcs, NULL};
void setup() {
Serial.begin(9600);
int array_index = 0; // Counter for rcs_strings array.
int buffer_index = 0;
int i = 0;
while (pgm_read_word(&rcs_strings[i++])) { // Do for each rcs string.
int string_index = 5; // Index of first file name char.
char c;
while((c = pgm_read_byte(pgm_read_word(&rcs_strings[array_index][string_index++]))) \
!= ',') buffer[buffer_index++] = c; // Copy string up until ','.
string_index += 3; // Skip ",v " and point to 1st char of version number.
buffer[buffer_index++] = ':'; // Write a separating colon.
// String_index now pointing to first digit in version number
while((c = pgm_read_byte(pgm_read_word(&rcs_strings[array_index][string_index++]))) \
!= ' ') buffer[buffer_index++] = c; // Copy string until next space.
buffer[buffer_index++] = '\n'; // write newline and increment to next location
array_index++; // Select next version string.
}
buffer[buffer_index] = '\0'; // All done - write terminating null.
// Show what we've done.
Serial.println(buffer);
}
void loop() {}
It's the inner 'while' loops that have got me stumped:
I'm hoping to get the address of the string character with "pgm_read_word(&rcs_strings[array_index][string_index++]" and use that to read the character at that location with the outer "pgm_read_byte" - but its not working. It's pretty ugly and the referencing and de-referencing has got my head swimming!
while((c = pgm_read_word(&rcs_strings[array_index][string_index++]))" Does work - 'c' returns the characters in the strings OK, but I've got some extreme weirdness going on in the outer loop!
Embedding it into a loop breaks it. Basically I can hard wire any numbers I like into the array subscript and get sensible results, but as soon as I set up an outer loop to step through the array of strings it falls over.
I'll try to set up an example stripped own to the bare bones to illustrate it!
I've stripped my problem down to the bare bones and it appears to be related to a simple loop as shown in this example:
The following program just prints out character by character parts of the strings. I want to be able to do this rather than do a string copy, because I need to select just the elements that I need.
With the outer loop commented out, the following works and I can 'hard-wire' various indexes (within range) for the string_table, and it works fine. If I uncomment the outer loop I just get rubbish printed - not even sensible values for the index 'i'.
I can't understand it - it's as if the outer loop somehow corrupts the inner one.
#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "String 0";
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char *string_table[] PROGMEM = \
{
string_0,
string_1,
string_2,
string_3
};
char buffer[40];
void setup()
{
Serial.begin(9600);
int i = 0; // Counter for string_table.
// while(i < 4) {
Serial.println(i); // Show position in string_table.
int j = 2; // Counter for characters in strings (starting at 'r').
char c;
while((c = pgm_read_word(&string_table[i][j++])))
Serial.print(c); // Show string character by character, starting at 'r'.
//i++;
//}
}
void loop() {}
I'm not sure where to go to next. I might just have to copy each string into a buffer in flash memory in turn, and do the substring stuff there, if it's a restriction in using PROGMEM.