حافظه آردوينو-آموزش جامع آردوینو

این جلسه مربوط به دوره قدیمی آردوینو وبسایت می باشد. برای دیدن دوره جدید به این لینک مراجعه فرمایید.

سلام دوستان

در این جلسه می خواهیم در مورد رفع مشکل حافظه آردوینو بحث کنیم.

حافظه آردوينو

شاید واضح ترین علامت برای اینکه بفهمیم حافظه آردوینو پر شده این باشه که کامپایلر به ما بگه که طول برنامه ای که نوشتید زیاده و من اصلا جاندارم که ذخیره کنم چه برسه به اجرای اون. شاید هم لود بشه ولی اجرا نمیشه و آسیب میبینه.

اول یه توضیح مختصری در مورد حافظه ها داریم:

اوایل که بحث حافظه بوجود اومد دو نوع معماری برای حافظه پدیدار شد

انواع معماری

1-Von Neumann (a.k.a. Princeton) architecture :

معماری ون نیومن که برای ENIAC (اولین کامپیوتری که ساخته شد) توسعه داده شده بود مسیر داده و برنامه یکی بود. در شکل زیر بوضوح مشاهده می شود که مسیر ذخیره داده و برنامه یکسان است یعنی کلا یک مموری برای هر دوتا بود:

 

 

2- Harvard architecture: معماری هاروارد که نوع دوم بود مسیر داده و برنامه کاملا جدا بود یعنی داده ها یه جایی ذخیره میشد و برنامه هم یه جای دیگه ذخیره میشد. در شکل زیر می بینید که دوتا حافظه جداگانه برای هر کدوم داریم:

 

 

کدام بهتر است؟

هر معماری مزایای خاص خودش را دارد. معماری هاروارد یک لبه اجرایی دارد و معماری ون نیومن انعطاف پذیری بالایی دارد.

مدل های دوگانه:

امروزه مدلهای حافظه از هر دونوع معماری استفاده می کنند تا بهترین نتیجه را بگیرند

حافظه آردوینو  و ميكروكنترلرها:

میکروکنترلرهایی که در آردوینو استفاده می شود تقریبا از مدل هاروارد استفاده می کنند.برای مثال Atmega 328 که در آردوینو UNO استفاده شده است را در نظر بگیرید که برنامه ها در حافظه FLASH ریخته می شود و داده های تولید شده در حافظه SRAM ذخیره می شود. حافظه آردوینوUNO دارای 32کیلو بایت حافظه FLASH  و 2کیلوبایت حافظه SRAM است. یعنی 100000 برابر کمتر از حافظه یک کامپیوتر شخصی مدل پایین است. بنابرین کارکردن در این محیط ریز باید با خردمندی صورت پذیرد.

سه نوع حافظه آردوینو داریم:

1-Flash or Program Memory

2-SRAM

3-EEPROM

Flash Memory

حافظه فلش برای ذخیره  عکس برنامه و داده های اولیه ای که در برنامه استفاده می شود. شما می توانید برنامه را در حافظه فلش اجرا کنید ولی برنامه اجرا شده را در حافظه فلش نمی توانید اصلاح کنید. برای اصلاح برنامه ابتدا باید در حافظه SRAM کپی شود و سپس اصلاح کنید.

حافظه فلش دارای عمر محدود 100000 بار نوشتن است. یعنی اگر شما هر روز یک برنامه را روی حافظه فلش لود کنید تا 27 سال طول می کشد تا این حافظه از بین برود.

SRAM

مخفف Static Random Access Memory است. این حافظه هم خواندنی است و هم نوشتنی است. از این حافظه برای موارد زیر استفاده می شود:

1-static data: این قسمت از حافظه برای داده های کلی و متغیرهایی که دارای مقادیر ثابت هستند رزرو شده است. متغیرهایی که دارای مقادیر اولیه هستند ابتدا از حافظه فلش به این قسمت از حافظه کپی می شوند و سپس برنامه اجرا میشود.

2-Heap: این قسمت برای داده های دینامیکی است(منظور همون داده هایی است که تغییر میکنند و میان و میرن و… داده هایی که خیلی ورجه وورجه میکنن). محل قرارگیریش هم اگه به شکل نگاه کنید از بالای Static Ram هست تا جایی که کل آیتم های داده هاست.

3-Stack: این قسمت برای داده های محلی است و برای نگهداری داده های مربوط به وقفه و فراخوانی توابع. محل قرارگیریش هم باتوجه به شکل از بالای حافظه شروع میشه و میاد به سمت Heap.

مشکل اکثر حافظه ها زمانی است که قسمت Static و Heap با هم برخورد میکنن. هنگامی که این دوتا قسمت حافظه به هم میخورن خیلی از نتایج هم غیرقابل پیش بینی میشه.

EEPROM

این نوع حافظه هم خواندنی است و هم نوشتنی. فقط بیت به بیت می توان آن را خواند بنابراین برای استفاده مشکلاتی به همراه می آورد.سرعت آن از SRAM کمتر است و  می تونید 100000بار داخل اون برنامه بریزید.

درسته که به پای ارزش های SRAM نمیرسه ولی یه جاهایی واقعا سودمنده!!!

 

مقایسه حافظه آردوینو

در جدول زیر میتوانید حافظه آردوینو مدل هاي مختلف رو با هم مقایسه کنید

 

 

اندازه گیری میزان استفاده شده در حافظه  آردوینو:

Flash

یک روش برای تشخیص مشکلات مربوط به حافظه اینه که میزان حافظه ای که استفاده کردیم رو اندازه گیری کنیم.

اندازه گیری حافظه فلش راحته و خود کامپایلر آردوینو این کار رو براتون انجام میده. بعنی هر بار که برنامه رو کامپایل کنید تو کادر پایینش می تونید ببینید که چقد حجم برنامتونه. در شکل زیر میبینید که برنامه چشمک زن رو اجرا کردیم و چون من آردوینو MEGA2560 رو انتخاب کردم عدد253982 ظاهر شد که با جدول بالا میتوانید مقایسه کنید.

نکته: 1 کیلوبایت= 1024 بایت

EEPROM

کنترل حافظه EEPROM بطور کامل در اختیار شماست چون شما مجبورید برای هر بیت که در این حافظه استفاده می کنید آدرس دهی می کنید یعنی اگر نوشتیدGHASEM باید برای دونه به دونه هر بیت یک آدرس تعیین کنید و بگید که جای هر چیز کجاست. بنابراین جای هیچ عذر و بهانه ای برای ندانستن میزان استفاده شده وجود ندارد.

مصرف کننده های بزرگ حافظه:

SD Cards

برای ارتباط با SD کارت نیاز به 512بایت حافظه بافر SRAM دارد.

 

Pixels

هر پیکسل به 3بایت حافظه SRAM جهت ذخیره رنگ نیاز دارد و هنگامی که یک نوار رنگارنگ دارید به حافظه بسیار زیادی نیاز دارد. در یک حافظه آردوینو شما می توانید حداکثر 500پیکسل را استفاده کنید.

 

Monochrome OLED Displays

اینها برای هر 8 پیکسل نیازمند 1بایت هستند ولی به دلیل رزولوشن زیاد باعث بالا رفتن بایت مصرفی می شوند.

 

 

حل مشکلات مربوط به حافظه

حافظه جزو منابع محدود در یک میکروکنترلر است و در بعضی مواقع یک کاربرد ساده ممکن است تمام یک حافظه آردوینو را بگیرد. خوشبختانه اکثر برنامه ها را می توان بهینه سازی کرد. بنابراین اگر برنامه شما مقداری زیاد شد می توان با کمی نرمش و تمرین حجمش رو کم کرد.

 

 

نحوه بهینه سازی یک برنامه

هنگامی که برنامه را اجرا می کنید در پایین محیط برنامه نویسی آردوینو پیغامی مبنی بر حجم برنامه را مشاهده می کنید در صورتی که به محدوده مجاز رسیده باشید با استفاده از روشهایی می توانید حجم برنامه را بهینه کنید.

 

 

Remove Dead Code

چنانچه کدهای شما از چندین منبع آمده است احتمالا مواردی اضافی و غیر قابل کاربرد در آن وجود دارد که می توانید آن را حذف کنید:

1-Unused Libraries : همه توابع کتابخانه ای که لازم نیستند را حذف کنید. include#

2-Unused Functions: همه توابعی که از آنها استفاده نمی کنید.

3-Unused Variables: همه متغیرهایی که بلااستفاده است را حذف کنید.

4-Unreachable Code: آن عبارات شرطی که هرگز به جواب true نمی رسند را حذف کنید.

نکته: برای اینکه بدونید یک تابع کتابخانه ای یا یک متغیر یا یک تابع در برنامه تان استفاده می شود یا نه با // آن را تبدیل به کامنت کنید و برنامه را اجرا کنید چنانچه باز برنامه اجرا شد یعنی اینکه اضافی است.

Consolidate Repeated Code

چنانچه عباراتی وجود دارد که چندین بار در برنامه تکرار می شود بهتر است برای آن یک تابع بنویسید تا از نوشتن چندباره آن جلوگیری شود.

Eliminate the Bootloader

چنانچه نیاز مبرم به حافظه اضافی داشتید می توانید حافظه مربوط به بوت لودر را حذف کنید که حدود 2تا4 کیلوبایت به دست می آورید. برای اینکار باید از یک ISP programmer برای برنامه ریزی استفاده کنید نه کابل USB آردوینو.

نکته کلیدی: سعی کنید در برنامه خود تاجایی که می توانید متغیرها را محلی تعریف کنید نه global. بخاطر اینکه اگر محلی تعریف کنید بعد از اینکه متغیر استفاده شده خودبخود حذف میشود و فضای حافظه خالی می شود در صورتی که متغیر گلوبال یا عمومی همیشه یک فضای اختصاصی را اشغال می کند.

برای دریافت آخرین مطالب سایت  و همچنین مطالب منحصر به فرد دیگر که در سایت منتشر نمی شوند میتوانید در کانال تلگرام ما عضو شوید و یا در اینستاگرام ما را فالوو کنید:

در پناه حق باشید

قاسم قاسمی

 

5 نظر

  • mahmoud eghbali

    ba salam
    lotfan komakam konid ta barname ra takmil konam. dar in barname 2 counter hast ke counter 1 ba har dafe start o mishe va counter 2 bayad zakhire beshe va be shomaresh edame bede hata agar bargh ghat beshe. man har chi talash kardam moteasefane movafagh nashodam raghame dword ro dar eeprom berizam

    #include

    int powerPin = 3;
    int keyPin = 4;
    int power = 0;
    int powerState = 0;
    int key = 0;
    int keyState = 0;
    int tStart = 0;
    unsigned long count1 = 0;
    unsigned long count2 = 0;

    void setup()
    {
    Serial.begin(9600);
    pinMode(keyPin,INPUT);
    pinMode(powerPin,INPUT);
    }

    void loop()
    {
    powerState = digitalRead(powerPin);
    keyState = digitalRead(keyPin);

    if ( powerState != power )
    {
    delay(200);
    if ( powerState == HIGH ) // positive flank
    {
    count1 = 0;
    }
    else
    {
    if( tStart != 0 )
    tStart = 0;
    }
    power = powerState;
    }
    if( power == HIGH )
    {
    if (keyState != key)
    {
    delay(200);
    if (keyState == HIGH) //positive flank
    {
    ++count1;
    ++count2; // how can i save this counter in EEPROM?

    if( tStart == 0 )
    tStart = millis();

    }
    key = keyState;
    }
    else
    {
    Serial.print(“count1: “);
    Serial.println(count1);
    Serial.print(“count2: “);
    Serial.println(count2);
    Serial.println();
    delay(200);
    }
    }
    }

    • حامد قاسمی

      با سلام خدمت شما.
      برای نوشتن بر روی eeprom میکروکنترلر باید از دستور EEPROM.write(addr, val); استفاده کنید. این دستور دارای دو آرگومان هست. آرگومان اول که با نام addr مشخص شده مربوط به آدرس eeprom هست که شما تعیین میکنید داده مورد نظرتون در کدوم آدرس ذخیره بشه. آرگومان دوم هم مربوط به خود داده ای هست که شما میخواید داخلش ذخیره کنید.
      برای این که هر دفعه آدرس خانه مربوط به eeprom شما آپدیت شود میتونید بعد از دستور مربوط به نوشتن در حلقه loop از دستور addr = addr + 1; استفاده کنید که در این صورت هر دفعه برای ذخیره سازی به خانه بعد مربوط به حافظه مراجعه میشود و داده مربوطه در آنجا ذخیره میشود.

      تذکر: لطفا کامنت های خود را به زبان فارسی بنویسید.
      با تشکر

  • kamali

    باسلام.لطفا راهنمایی کنید چطور حافظه فلش وحافظه eepromبرد اردوینو رو پاک کنم؟

    • حامد قاسمی

      با سلام.
      برای پاک کردن حافظه فلش که کار خاصی نیاز نیست و هر دفعه که کد جدیدی رو میریزید کد قبلی پاک میشه. طبیعی هست که اگه یه کد با دو تابع voidloop و void setup با محتوای خالی رو روی برد بریزید حافظه ی فلش عملا پاک شده و میکروکنترلر کار خاصی رو برای شما انجام نمیده.
      برای پاک کردن حافظه eeprom هم از اونجایی که این حافظه در برد آردوینو 12 بایت هست باید به جای هر 12 بایت مقدار صفر رو قرار بدیم که این کار با استفاده از دستور EEPROM.write(i, 0) و قرار دادن این دستور در یک حلقه for قابل انجام هست و به جای i باید شماره بایت مورد نظر رو بنویسید. این نمونه کد در زیر آورده شده:

      void setup() {

      pinMode(13, OUTPUT);

      for (int i = 0 ; i < EEPROM.length() ; i++) { EEPROM.write(i, 0); } digitalWrite(13, HIGH); } void loop() { /** Empty loop. **/ } برای دریافت اطلاعات بیشتر نیز میتونید به لینک زیر مراجعه کنید: EEPROMClear

  • ali

    بسیار قشنگ توضیح دادی خسته نباشی.تشکر

  • نوشتن نظر

    نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

    Optionally add an image (JPEG only)