شناخت انواع حافظه آردوينو و بهینه سازی آن
مقدمه
سلام دوستان در این جلسه می خواهیم در مورد حافظه ها و رفع مشکل اون ها در بردهای آردوینو بحث کنیم. ابتدا انواع معماری های مربوط به حافظه ها رو توضیح میدیم و سپس انواع حافظه ها رو در آردوینو با هم دیگه میشناسیم و در انتها روش هایی برای حل مشکل کمبود حافظه در آردوینو ارایه میدیم. پیشنهاد من این هست که اگه هیچ آشنایی با آردوینو ندارید ، ابتدا از لینک زیر نگاهی به دوره مقدماتی آردوینو وبسایت داشته باشید:
انواع معماری حافظه ها
معماری Von-Neumann
معماری ون نیومن که برای ENIAC (اولین کامپیوتری که ساخته شد) توسعه داده شده بود مسیر داده و برنامه یکی بود. در شکل زیر بوضوح مشاهده می شود که مسیر ذخیره داده و برنامه یکسان است یعنی کلا یک مموری برای هر دوتا بود:
معماری Harvard
معماری هاروارد که نوع دوم بود مسیر داده و برنامه کاملا جدا بود یعنی داده ها یه جایی ذخیره میشد و برنامه هم یه جای دیگه ذخیره میشد. در شکل زیر می بینید که دوتا حافظه جداگانه برای هر کدوم داریم:
کدام بهتر است؟
هر معماری مزایای خاص خودش را دارد. معماری هاروارد یک لبه اجرایی دارد و معماری ون نیومن انعطاف پذیری بالایی دارد.
مدل های دوگانه:
امروزه مدلهای حافظه از هر دونوع معماری استفاده می کنند تا بهترین نتیجه را بگیرند
حافظه آردوینو و میکروکنترلرها
میکروکنترلرهایی که در آردوینو استفاده می شود تقریبا از مدل هاروارد استفاده می کنند.برای مثال Atmega 328 که در آردوینو UNO استفاده شده است را در نظر بگیرید که برنامه ها در حافظه FLASH ریخته می شود و داده های تولید شده در حافظه SRAM ذخیره می شود. حافظه آردوینوUNO دارای 32کیلو بایت حافظه FLASH و 2کیلوبایت حافظه SRAM است. یعنی 100000 برابر کمتر از حافظه یک کامپیوتر شخصی مدل پایین است. بنابرین کارکردن در این محیط ریز باید با خردمندی صورت پذیرد.
سه نوع حافظه آردوینو داریم:
- حافظه Flash
- حافظه SRAM
- حافظه EEPROM
حافظه Flash
حافظه فلش برای ذخیره عکس برنامه و داده های اولیه ای که در برنامه استفاده می شود. شما می توانید برنامه را در حافظه فلش اجرا کنید ولی برنامه اجرا شده را در حافظه فلش نمی توانید اصلاح کنید. برای اصلاح برنامه ابتدا باید در حافظه SRAM کپی شود و سپس اصلاح کنید.
حافظه فلش دارای عمر محدود 100000 بار نوشتن است. یعنی اگر شما هر روز یک برنامه را روی حافظه فلش لود کنید تا 27 سال طول می کشد تا این حافظه از بین برود.
حافظه SRAM
مخفف Static Random Access Memory است. این حافظه هم خواندنی است و هم نوشتنی است. از این حافظه برای موارد زیر استفاده می شود:
- static data: این قسمت از حافظه برای داده های کلی و متغیرهایی که دارای مقادیر ثابت هستند رزرو شده است. متغیرهایی که دارای مقادیر اولیه هستند ابتدا از حافظه فلش به این قسمت از حافظه کپی می شوند و سپس برنامه اجرا میشود.
- Heap: این قسمت برای داده های دینامیکی است(منظور همون داده هایی است که تغییر میکنند و میان و میرن و… داده هایی که خیلی ورجه وورجه میکنن). محل قرارگیریش هم اگه به شکل نگاه کنید از بالای Static Ram هست تا جایی که کل آیتم های داده هاست.
- Stack: این قسمت برای داده های محلی است و برای نگهداری داده های مربوط به وقفه و فراخوانی توابع. محل قرارگیریش هم باتوجه به شکل از بالای حافظه شروع میشه و میاد به سمت Heap.
مشکل اکثر حافظه ها زمانی است که قسمت Static و Heap با هم برخورد میکنن. هنگامی که این دوتا قسمت حافظه به هم میخورن خیلی از نتایج هم غیرقابل پیش بینی میشه.
حافظه EEPROM
این نوع حافظه هم خواندنی است و هم نوشتنی. فقط بیت به بیت می توان آن را خواند بنابراین برای استفاده مشکلاتی به همراه می آورد.سرعت آن از SRAM کمتر است و می تونید 100000بار داخل اون برنامه بریزید.
درسته که به پای ارزش های SRAM نمیرسه ولی یه جاهایی واقعا سودمنده.
مقایسه حافظه های آردوینو
در جدول زیر میتوانید حافظه آردوینو مدل هاي مختلف رو با هم مقایسه کنید
اندازه گیری میزان استفاده شده در حافظه آردوینو
حافظه Flash
یک روش برای تشخیص مشکلات مربوط به حافظه اینه که میزان حافظه ای که استفاده کردیم رو اندازه گیری کنیم.
اندازه گیری حافظه فلش راحته و خود کامپایلر آردوینو این کار رو براتون انجام میده. بعنی هر بار که برنامه رو کامپایل کنید تو کادر پایینش می تونید ببینید که چقد حجم برنامتونه. در شکل زیر میبینید که برنامه چشمک زن رو اجرا کردیم و چون من آردوینو MEGA2560 رو انتخاب کردم عدد253982 ظاهر شد که با جدول بالا میتوانید مقایسه کنید.
نکته: 1 کیلوبایت= 1024 بایت
حافظه EEPROM
کنترل حافظه EEPROM بطور کامل در اختیار شماست چون شما مجبورید برای هر بیت که در این حافظه استفاده می کنید آدرس دهی می کنید یعنی اگر نوشتید BOOK باید برای دونه به دونه هر بیت یک آدرس تعیین کنید و بگید که جای هر چیز کجاست. بنابراین جای هیچ عذر و بهانه ای برای ندانستن میزان استفاده شده وجود ندارد.
مصرف کننده های بزرگ حافظه
کارت های SD
برای ارتباط با SD کارت نیاز به 512بایت حافظه بافر SRAM دارد.
پیکسل ها
هر پیکسل به 3بایت حافظه SRAM جهت ذخیره رنگ نیاز دارد و هنگامی که یک نوار رنگارنگ دارید به حافظه بسیار زیادی نیاز دارد. در یک حافظه آردوینو شما می توانید حداکثر 500پیکسل را استفاده کنید.
نمایشگرهای مونوکروم OLED
اینها برای هر 8 پیکسل نیازمند 1بایت هستند ولی به دلیل رزولوشن زیاد باعث بالا رفتن بایت مصرفی می شوند.
حل مشکلات مربوط به حافظه
حافظه جزو منابع محدود در یک میکروکنترلر است و در بعضی مواقع یک کاربرد ساده ممکن است تمام یک حافظه آردوینو را بگیرد. خوشبختانه اکثر برنامه ها را می توان بهینه سازی کرد. بنابراین اگر برنامه شما مقداری زیاد شد می توان با کمی نرمش و تمرین حجمش رو کم کرد.
نحوه بهینه سازی یک برنامه
هنگامی که برنامه را اجرا می کنید در پایین محیط برنامه نویسی آردوینو پیغامی مبنی بر حجم برنامه را مشاهده می کنید در صورتی که به محدوده مجاز رسیده باشید با استفاده از روشهایی می توانید حجم برنامه را بهینه کنید.
گام 1 : حذف کدهای بی استفاده
چنانچه کدهای شما از چندین منبع آمده است احتمالا مواردی اضافی و غیر قابل کاربرد در آن وجود دارد که می توانید آن را حذف کنید:
- کتابخانه های بی استفاده : همه توابع کتابخانه ای که لازم نیستند را حذف کنید. include#
- توابع بی استفاده: همه توابعی که از آنها استفاده نمی کنید.
- متغیرهای بی استفاده: همه متغیرهایی که بلااستفاده است را حذف کنید.
- عبارات شرطی بی استفاده: آن عبارات شرطی که هرگز به جواب true نمی رسند را حذف کنید.
نکته: برای اینکه بدونید یک تابع کتابخانه ای یا یک متغیر یا یک تابع در برنامه تان استفاده می شود یا نه با // آن را تبدیل به کامنت کنید و برنامه را اجرا کنید چنانچه باز برنامه اجرا شد یعنی اینکه اضافی است.
نوشتن تابع برای کدهای تکراری
چنانچه عباراتی وجود دارد که چندین بار در برنامه تکرار می شود بهتر است برای آن یک تابع بنویسید تا از نوشتن چندباره آن جلوگیری شود.
استفاده از حافظه Bootloader
چنانچه نیاز مبرم به حافظه اضافی داشتید می توانید حافظه مربوط به بوت لودر را حذف کنید که حدود 2تا4 کیلوبایت به دست می آورید. برای اینکار باید از یک ISP programmer برای برنامه ریزی استفاده کنید نه کابل USB آردوینو.
نکته کلیدی: سعی کنید در برنامه خود تاجایی که می توانید متغیرها را محلی تعریف کنید نه global. بخاطر اینکه اگر محلی تعریف کنید بعد از اینکه متغیر استفاده شده خودبخود حذف میشود و فضای حافظه خالی می شود در صورتی که متغیر گلوبال یا عمومی همیشه یک فضای اختصاصی را اشغال می کند.
برای دریافت آخرین مطالب سایت و همچنین مطالب منحصر به فرد دیگر که در سایت منتشر نمی شوند میتوانید در کانال تلگرام ما عضو شوید و یا در اینستاگرام ما را فالوو کنید:
17 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
خدا شما را ساخته برای آموزش _ مثل همیشه عالی
سپاس از لطف شما.
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; استفاده کنید که در این صورت هر دفعه برای ذخیره سازی به خانه بعد مربوط به حافظه مراجعه میشود و داده مربوطه در آنجا ذخیره میشود.
تذکر: لطفا کامنت های خود را به زبان فارسی بنویسید.
با تشکر
باسلام.لطفا راهنمایی کنید چطور حافظه فلش وحافظه 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
بسیار قشنگ توضیح دادی خسته نباشی.تشکر