facebook pixel מדריך: פירוט שפת תכנות - כלי עזר - PROGMEM - www.4project.co.il
Main logo www.4project.co.il
כל הרכיבים לפרוייקט שלכם
עגלת קניות

העגלה ריקה

פירוט שפת תכנות - כלי עזר - PROGMEM


2023-06-26 10:19:48
PROGMEM מאפשר לשמור את הנתונים בזכרון FLASH (מיקום של קוד התוכנית) במקום זכרון SRAM (מיקום של המשתנים).

מילת המפתח PROGMEM היא מאפיין של הגדרת משתנה ואפשר להשתמש במאפיין זה רק עם סוגי נתונים המוגדרים בקובץ pgmspace.h. המאפיין בעצם אומר לקומפיילר "שים את הנתונים האלה ב-FLASH" במקום ה-SRAM שזהו המקום הרגיל לשמירת המשתנים.

PROGMEM הוא חלק מספריית pgmspace.h הזמינה רק לארכיטקטורת רכיבי AVR.
קודם כל תצטרכו לכלול את קובץ הגדרות של הספרייה בתחילת התוכנית שלכם בצורה זו:
קוד: בחר הכל
#include <avr/pgmspace.h>


תחביר

קוד: בחר הכל
const dataType variableName[] PROGMEM = {data0, data1, data3...};

פרמטרים בתחביר:
dataType - הגדרת סוג המשתנה
variableName - שם של מערך הנתונים

שימו לב כי מכוון ש-PROGMEM הוא מאפיין של משתנה, אין חוק קשיח למיקום של המאפיין בשורת ההגדרה, כך שהקומפיילר של Arduino יקבל את כל צורות ההגדרה שבהמשך. עם זאת, ניסויים הראו שבגרסאות מסוימות (משהו שקשור לגרסת ה-GCC) ה-PROGMEM יכול לעבוד במיקום אחד ולא יעבוד במיקום אחר.
קוד: בחר הכל
const dataType variableName[] PROGMEM = {};   // use this form
const PROGMEM  dataType  variableName[] = {}; // or this form
const dataType PROGMEM variableName[] = {};   // not this one


תוכלו להשתמש ב-PROGMEM על משתנה בודד, אבל לרוב משתמשים במאפיין זה כשיש לכם גוש גדול של נתונים שצריך לשמור, בדרך כלל כמערך (או מבנה נתונים אחר של שפת C שמעבר לדיון הנוכחי).

השימוש ב-PROGMEM מורכב משני שלבים. אחרי ששמרנו את הנתונים ב-FLASH, צריך להשתמש בפונקציות מיוחדות, שגם הן מוגדרות בספריית pgmspace.h, כדי לקרוא את הנתונים בחזרה ל-SRAM כדי שאפשר יהיה להשתמש בהם.

דוגמה

הקוד הבא מדגים איך לשמור ולקרוא תווים (בגודל של byte) ומספרי int (בגודל 2bytes) מ-FLASH בעזרת PROGMEM.
קוד: בחר הכל
#include <avr/pgmspace.h>


// save some unsigned ints
const PROGMEM  uint16_t charSet[]  = { 65000, 32796, 16843, 10, 11234};

// save some chars
const char signMessage[] PROGMEM  = {"I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};

unsigned int displayInt;
int k;    // counter variable
char myChar;


void setup() {
  Serial.begin(9600);
  while (!Serial);

  // put your setup code here, to run once:
  // read back a 2-byte int
  for (k = 0; k < 5; k++)
  {
    displayInt = pgm_read_word_near(charSet + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // read back a char
  int len = strlen_P(signMessage);
  for (k = 0; k < len; k++)
  {
    myChar =  pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }

  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:

}


מערכים של מחרוזות טקסט

כשעובדים עם כמויות גדולות של מחרוזות טקסט כמו בפרוייקטים עם מסכי LCD, לרוב נוח להגדיר מערך של מחרוזות. בגלל שמחרוזת טקסט היא בעצמה מערך, זוהי למעשה דוגמה של מערכים דו-מימדיים.

מערכים כאלה נוטים להיות במני נתוני די גדולים, כך שבדרך כלל רצוי לשמור אותם ב-FLASH יחד עם קוד התוכנית. הקוד הבא מדגים את הרעיון:
קוד: בחר הכל
/*
PROGMEM string demo
How to store a table of strings in program memory (flash),
and retrieve them.

Information summarized from:
https://www.nongnu.org/avr-libc/user-manual/pgmspace.html

Setting up a table (array) of strings in program memory is slightly complicated, but
here is a good template to follow.

Setting up the strings is a two-step process. First define the strings.
*/

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "String 0";   // "String 0" etc are strings to store - change to suit.
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";


// Then set up a table to refer to your strings.

const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};

char buffer[30];    // make sure this is large enough for the largest string it must hold

void setup()
{
  Serial.begin(9600);
  while(!Serial);
  Serial.println("OK");
}


void loop()
{
  /* Using the string table in program memory requires the use of special functions to retrieve the data.
     The strcpy_P function copies a string from program space to a string in RAM ("buffer").
     Make sure your receiving string in RAM  is large enough to hold whatever
     you are retrieving from program space. */


  for (int i = 0; i < 6; i++)
  {
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table))); // Necessary casts and dereferencing, just copy.
    Serial.println(buffer);
    delay( 500 );
  }
}


שימו לב שכדאי שאפשר יהיה לעבוד עם PROGMEM, המשתנים צריכים להיות גלובליים (globals) או מוגדרים כ-static.
הקוד הבא לא יעבוד אם ההגדרה מתבצעת בתוך פונקציה:
קוד: בחר הכל
const char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n";


הקוד הבא כן יעבוד, גם אם ההגדרה מתבצעת בתוך פונקציה:
קוד: בחר הכל
const static char long_str[] PROGMEM = "Hi, I would like to tell you a bit about myself.\n"


מאקרו ה-()F

כשאתם משתמשים בקוד שנכתב בצורה זו:
קוד: בחר הכל
Serial.print("Write something on  the Serial Monitor");

המחרוזת המודפסת בדרך כלל נשמרת ב-SRAM. אם התוכנית שלכם מבצעת הרבה הדפסות בצורה דומה, זכרון ה-SRAM של הבקר יכול להתמלא מהר מאוד. אם יש לכם מקום פנוי בזיכרון FLASH, תוכלו בקלות לציין שהמחרוזת צריכה להישמר ב-FLASH ע"י שימוש בתחביר הבא:
קוד: בחר הכל
Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));



ראו גם:

סוגי זכרונות הזמינים על כרטיסי Arduino (אנגלית).
arrays (מערכים)
string (מערך של תווים chars)

פירוט שפת תכנות לסביבת Arduino


עמוד זה הוא תרגום של PROGMEM לפי רישיון Creative Commons Attribution-ShareAlike 3.0.