The flash is the bigger memory and every time we load a complied sketch it is stored there. If we use havily a lot of constants in our program would be better if we could store them into the flash memory instead the RAM.
Notice that real variables cannot be stored into the flash memory at runtime. This means that the buttonPushCounter value cannot be stored at the flash memory programmatically. Let's see a tipical usage of PREGMEM
#include <avr/pgmspace.h> // this constant won't change: const int buttonPin = 12; // the pin that the pushbutton is attached to // Variables will change: unsigned int buttonState = 0; // current state of the button unsigned int lastButtonState = 0; // previous state of the button //The PROGMEM is unable to store non-const data //SAVE SOME STUFF INTO FLASH MEMORY ... //A) Single unsigned integer (0 to 65535) unsigned int OneInteger_RAM; PROGMEM prog_uint16_t OneInteger_FLASH = 100; //prog_uint16_t -> an unsigned int (2 bytes) 0 to 65,535 //B) Array of bytes (0,255) byte ArrayOfBytes_RAM[] = {0, 0}; PROGMEM prog_uchar ArrayOfBytes_FLASH[] = {5, 44}; //prog_uchar -> an unsigned char (1 byte) 0 to 255 //C) String (Char array) unsigned char LongMessage_RAM[] = {""}; PROGMEM prog_uchar LongMessage_FLASH[] = {"This is a long message string"}; //prog_uchar -> an unsigned char (1 byte) 0 to 255 //D) Array of integers (0 to 65535) unsigned int ArrayOfIntegers_RAM[] = {0, 0, 0, 0, 0}; PROGMEM prog_uint16_t ArrayOfIntegers_FLASH[] = {61153, 32, 16843, 10, 11234}; //prog_uint16_t -> an unsigned int (2 bytes) 0 to 65,535 void ReadFromFLASH(){ // read back a 2-byte int OneInteger_RAM = pgm_read_word(&OneInteger_FLASH); // read back a byte int ArrayOfBytes_RAM[0] = pgm_read_byte(&ArrayOfBytes_FLASH[0]); // read back a byte int (only the first letter of the long string) LongMessage_RAM[0] = pgm_read_byte(&LongMessage_FLASH[0]); // read back a 2-byte int ArrayOfIntegers_RAM[0] = pgm_read_word(&ArrayOfIntegers_FLASH[0]); } void PrintProgString(const prog_uchar str[]) { char c; if(!str) return; while((c = pgm_read_byte(str++))) Serial.print(c,BYTE); } void setup() { // initialize the button pin as a input: pinMode(buttonPin, INPUT); // initialize serial communication: Serial.begin(9600); } void loop() { // read the pushbutton input pin: buttonState = digitalRead(buttonPin); // compare the buttonState to its previous state if (buttonState != lastButtonState) { // if the state has changed, increment the counter if (buttonState == HIGH) { Serial.println("on"); Serial.print("Initial OneInteger_RAM "); Serial.println(OneInteger_RAM, DEC); Serial.print("Initial ArrayOfBytes_RAM[0] "); Serial.println(ArrayOfBytes_RAM[0], DEC); Serial.print("Initial LongMessage_RAM[0] "); Serial.println(LongMessage_RAM[0], DEC); Serial.print("Initial ArrayOfIntegers_RAM[0] "); Serial.println(ArrayOfIntegers_RAM[0], DEC); ReadFromFLASH(); Serial.print("Restored value from flash OneInteger_RAM "); Serial.println(OneInteger_RAM, DEC); Serial.print("Restored value from flash ArrayOfBytes_RAM[0] "); Serial.println(ArrayOfBytes_RAM[0], DEC); Serial.print("Restored value from flash LongMessage_RAM[0] "); Serial.println(LongMessage_RAM[0], BYTE); Serial.print("Restored value from flash ArrayOfIntegers_RAM[0] "); Serial.println(ArrayOfIntegers_RAM[0], DEC); PrintProgString(LongMessage_FLASH); } else { // if the current state is LOW then the button // went from on to off: Serial.println("off"); } } // save the current state as the last state, //for next time through the loop lastButtonState = buttonState; }
As you can see we have used pgmspace.h library this time.
In order to store into flash a costant variable just do
PROGMEM dataType variableName[] = {};
As datatypes you can use
prog_char - a signed char (1 byte) -127 to 128
prog_uchar - an unsigned char (1 byte) 0 to 255
prog_int16_t - a signed int (2 bytes) -32,767 to 32,768
prog_uint16_t - an unsigned int (2 bytes) 0 to 65,535
prog_int32_t - a signed long (4 bytes) -2,147,483,648 to * 2,147,483,647.
prog_uint32_t - an unsigned long (4 bytes) 0 to 4,294,967,295
Once you have stored the data to Flash you can read it by using
pgm_read_byte if you need to read one byte variables
pgm_read_word if you need to read two byte variables
Here are some valid examples :
OneInteger_RAM = pgm_read_word(&OneInteger_FLASH); // read back a 2-byte int
ArrayOfBytes_RAM[0] = pgm_read_byte(&ArrayOfBytes_FLASH[0]); // read back a byte int
LongMessage_RAM[0] = pgm_read_byte(&LongMessage_FLASH[0]); // read back a byte int (only the first letter of the long string)
ArrayOfIntegers_RAM[0] = pgm_read_word(&ArrayOfIntegers_FLASH[0]);// read back a 2-byte int
As you can see we read from the flash memory and restore the one byte or two bytes into RAM.
Since a string is an array of chars you can read one byte at a time and make a loop in order to read the hole string.
This is done by the PrintProgString function. So... the program sets some constant values at the beginning into the flash memory. After the button is pressed read these values and store them into the RAM associated variables. Then using the PrintProgString function prints the flash stored string into the screen.
Flash memory test video :
In this long article we have seen all three types of memories and how to use them .
You can download all three memory tests from here : MemoryTests