بررسی حافظه EEPROM در آردوینو و نحوه کار با آن

در این مقاله قصد داریم حافظه EEPROM در آردوینو و کاربرد آن را بررسی کنیم. سپس به نحوه خواندن و نوشتن از EEPROM می‌پردازیم و در پایان همراه با انجام یک پروژه، مفاهیم آموخته شده را به صورت عملی اجرا می‌کنیم.

مقدمه

زمانی که شما متغیری را در یک برنامه تعریف و از آن استفاده می‌کنید، داده‌های حاصل تنها تا زمانی که آردوینو روشن است، ذخیره می‌شوند و با ریست یا خاموش شدن آردوینو، داده‌های ذخیره شده نیز پاک خواهند شد. یا ممکن است نیاز باشد در ابتدای شروع به کار یک دستگاه، از کاربر مقداری دریافت شود و دستگاه همیشه بر اساس آن عدد کار کند.

چنانچه بخواهید داده‌ها را ذخیره و در آینده مجدداً از آن‌ها استفاده کنید، به حافظه EEPROM در آردوینو نیاز خواهید داشت. به طوری که این حافظه مقادیر متغیرها را حتی زمانی که آردوینو را ریست یا خاموش می‌کنید، برای شما ذخیره می‌کند.

حافظه EEPROM چیست؟

EEPROM یا E2PROM مخفف عبارت Electronically-Erasable Programmable Read-Only Memory به معنای حافظه فقط-خواندنی با قابلیت پاک کردن و نوشتن به صورت الکتریکی است و در واقع یک فضای کوچک با امکان ذخیره متغیرهای از نوع بایت می‌باشد.

همان‌طورکه اشاره شد مقادیر متغیرهای ذخیره شده در EEPROM با ریست یا خاموش شدن آردوینو پاک نمی‌شوند. به زبان ساده‌تر،  EEPROM یک حافظه دائمی مشابه هارد دیسک کامپیوترها می‌باشد و فرایندهای خواندن، نوشتن و پاک کردن حافظه به صورت الکترونیکی صورت می‌گیرد. با استفاده از کتابخانه EEPROM در آردوینو، می‌توانید عملیات خواندن و نوشتن در این حافظه را به راحتی انجام دهید.

میکروکنترلر ATMEGA از پکیج DIP که دارای حافظه EEPROM می‌باشد

میکروکنترلری که بر روی برد آردوینو تعبیه شده (ATMEGA328 در آردوینو UNO که در شکل بالا نشان داده شده‌است) دارای یک حافظه EEPROM است.

تاریخچه حافظه

نسل قدیمی تر EEPROM، حافظه های EPROM است. آی سی‌های EPROM قابل پاک شدن هستند اما نه به صورت الکتریکی، برای پاک کردن حافظه‌های EPROM لازم است آن‌ها را در معرض نور فرابنفش قرار بدهیم. برای نمونه تصویر یک آی سی EPROM از STmicroelectronics در زیر آورده شده که محفظه شیشه‌ای برای تابش فرابنفش، در مرکز آی سی مشخص شده است.

آی سی EPROM که از نسل قدیمی حافظه‌های EEPROM می‌باشد

اگر باز هم به عقب برگردیم، به PROMها می‌رسیم. این حافظه‌ها به شکل خام عرضه می‌شوند و قابل برنامه‌ریزی توسط کاربر هستند اما به این علت که قابلیت پاک شدن ندارند، فقط یک بار می‌توان داخل آن‌ها اطلاعات نوشت. با قدمت‌ترین نسل حافظه‌های فقط-خواندنی نیز ROMها هستند که به سفارش کاربر، در کارخانه سازنده برنامه‌ریزی می‌شوند و قابلیت نوشتن مجدد یا پاک کردن ندارند.

تفاوت حافظه FLASH با EEPROM

اما شاید برای شما سوال باشد که برای حافظه غیر فرار، چرا از حافظه FLASH (حافظه‌ای که برنامه روی آن قرار می‌گیرد) استفاده نمی‌کنیم؟ در پاسخ به این سوال بهتر است تفاوت حافظه فلش با EEPROM را بررسی کنیم:

حافظه فلش، در اصل نوعی EEPROM است و مهم‌ترین تفاوت آن‌ها این است که حافظه EEPROM به صورت بایت به بایت قابل نوشتن و پاک کردن است، اما FLASH، فقط به شکل بلوک به بلوک قابل پاک کردن می‌باشد. همین تفاوت باعث می‌شود حافظه‌های فلش سرعت بیشتری داشته باشند، یعنی برای ذخیره اطلاعات با حجم بیشتر (مثل برنامه‌ای که برای آردوینو می‌نویسید) مناسب‌تر و به نسبت حجم، قیمت پایین‌تری هم داشته باشند.

در مقابل حافظه EEPROM به علت قابلیت پاک کردن کلمه به کلمه، برای ذخیره داده‌های کم حجم چند بایتی، مانند وضعیت یک کلید یا عددی که نیاز است از کاربر بگیریم، مناسب‌تر است. به دلیل وجود همین تفاوت، حجم این حافظه در آردوینو UNO برابر 1 کیلو بایت می‌باشد که به نسبت فلش 32 کیلوبایتی، بسیار کمتر است.

در حافظه EEPROM چند بایت می توان ذخیره کرد؟

هر مکان از EEPROM  قابلیت ذخیره یک بایت را دارد، به این معنا که شما تنها می‌توانید اعداد 8 بیتی که اعداد صحیح بین 0 تا 255 را شامل می‌شود، ذخیره کنید و تعداد بایت‌هایی که می‌توانید در این حافظه ذخیره کنید به میکروکنترلر شما بستگی دارد. با این حال، در صورت نیاز به ذخیره داده‌های بیشتر می‌توانید از یک تراشه EEPROM خارجی کمک بگیرید.

در جدول زیر تعداد بایت قابل ذخیره با میکروکنترلرهای به‌کاررفته در بردهای مختلف آردوینو ذکر شده‌است:

میکروکنترلرتعداد بایت قابل ذخیره در EEPROM
ATmega328 (Arduino Uno, Nano, Mini)1024 بایت
ATmega168 (Arduino Nano)512 بایت
ATmega2560 (Arduino Mega)4096 بایت

عمر حافظه EEPROM چقدر است؟

عمر حافظه EEPROM محدود است. برای مثال در آردوینو، حداکثر صدهزار مرتبه نوشتن یا پاک کردن هر مکان از این حافظه امکان‌پذیر می‌باشد، اما میزان خواندن از آن نامحدود است، بدین معنا که می‌توان به تعداد نامحدود از EEPROM خواند، بدون اینکه عمر مفید آن کاهش یابد. بنابراین بهتر است برای افزایش طول عمر، از نوشتن اطلاعات تکراری روی آن خودداری کنید و همین‌طور قبل از نوشتن، یکبار خانه موردنظر خود را بخوانید و در صورتی که حاوی اطلاعات متفاوتی بود، روی آن بنویسید.

همچنین بهتر است پس از نوشتن هر خانه، یک بار آن را بخوانید تا مطمئن شوید داده به درستی نوشته شده‌است و در صورتی که داده درستی نوشته نشده بود، نوشتن را دوباره انجام دهید. درنهایت، اگر پس از چند تلاش داده به درستی نوشته نشد، یک پیغام خطا نمایش دهید.

کاربرد حافظه EEPROM در پروژه‌های آردوینو

در پروژه‌های آردوینو زمانی که به ذخیره و حفظ داده‌ها حتی بعد از قطع تغذیه آردوینو یا راه اندازی مجدد آن نیاز دارید، این حافظه بسیار کمک‌کننده و مفید خواهد بود. برای مثال برای به‌ خاطر سپردن آخرین وضعیت یک متغیر یا تعداد فعال شدن یک دستگاه بسیار مناسب است.

برای توضیح بیشتر این کاربرد، سناریو فرضی زیر را درنظر بگیرید:

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

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

روند قطع و وصل شدن برق آردوینو که توسط حافظه‌ی EEPROM آخرین وضعیت ال ای دی ذخیره و مشخص شده

بدین منظور می‌توان وضعیت لامپ را در EEPROM ذخیره کرده و یک شرط در برنامه اضافه نمود تا در ابتدا بررسی کند که آیا وضعیت لامپ با وضعیت ذخیره شده قبلی در EEPROM مطابقت دارد یا خیر؟

در ادامه با دستورات نوشتن و خواندن از آردوینو آشنا خواهیم شد:

نحوه‌ی کار با کتابخانه EEPROM و دستورات موردنیاز

با استفاده از کتابخانه EEPROM می‌توان به راحتی عملیات خواندن و نوشتن در EEPROM را انجام داد.

#include <EEPROM.h>

عملیات نوشتن در حافظه EEPROM

برای نوشتن داده‌ها در EEPROM، از تابع ()EEPROM.write استفاده می‌شود که شامل دو آرگومان است. اولین آرگومان بیانگر مکان یا آدرس حافظه است که می‌خواهید داده‌ها در آنجا ذخیره ‌شود و دومی مقداری است که قصد ذخیره آن را دارید:

EEPROM.write(address, value);

برای مثال برای نوشتن مقدار 10 در آدرس 0 خواهیم داشت:

EEPROM.write(0, 10);

عملیات خواندن حافظه EEPROM

برای خواندن یک بایت ذخیره شده در EEPROM، از تابع ()EEPROM.read استفاده می‌شود. این تابع با بررسی آدرس بایتی که به عنوان ورودی دریافت می‌کند، مقدار ذخیره شده را بر می‌گرداند.

EEPROM.read(address);

به عنوان مثال، دستور زیر مقدار 10 که در آدرس 0 ذخیره شده را بر می‌گرداند:

EEPROM.read(0);

به‌روز‌رسانی یک مقدار در EEPROM

عملیات به‌روزرسانی در حافظه EEPROM، توسط تابع پرکاربرد ()EEPROM.update استفاده می‌شود و تنها در صورتی در این حافظه می‌نویسد که مقدار نوشته شده با مقدار ذخیره شده قبلی متفاوت باشد.

با توجه به این‌که عمر مفید این حافظه به سیکل محدود نوشتن یا پاک کردن آن وابسته است، استفاده از تابع ()EEPROM.update به جای ()EEPROM.write مانع از به‌کارگیری سیکل‌های اضافی می‎‌شود و در افزایش عمر حافظه موثر خواهد بود.

با دستور زیر می‌توانید به روزرسانی مقادیر موردنظر خود را انجام دهید:

EEPROM.update(address, value);

در حال حاضر، مقدار 10 در آدرس 0 ذخیره شده است، چنانچه از دستور زیر استفاده کنید، با توجه به مطابقت مقدار متغیر ذخیره شده قبلی با مقدار جدید، عمل نوشتن در حافظه EEPROM دوباره انجام نمی شود:

EEPROM.update(0, 10);

مثال: ذخیره وضعیت LED توسط EEPROM در آردوینو

اکنون که با عملکرد و نحوه انجام عملیات خواندن، نوشتن و بروزرسانی داده ها در حافظه EEPROM آشنا شدید، می‌توانیم در ادامه با اجرای یک پروژه ساده با آردوینو این آموزش را کامل کنیم:

با این مثال یاد می‌گیریم چگونه وضعیت یک ال‌ای‌ای را در این حافظه ذخیره کنیم. به گونه‌ای که حتی با قطع تغذیه ماژول و یا ریست شدن آن، آخرین وضعیت LED از دست نرود!

قطعات مورد نیاز

برای انجام این پروژه به قطعات زیر نیاز خواهید داشت:

شماتیک مدار

همان‌طورکه در شکل زیر نمایش داده شده‌است، می‌توانید به آسانی مدار خود را ببندید. در اینجا یک کلید فشاری قرار دارد که با کمک آن یک LED را روشن و خاموش می‌کنیم:

شماتیک اتصالات مدار آردوینو و کلید فشاری و ال ای دی روی برد بورد

کد آردوینو

کد زیر را بر روی آردوینو خود آپلود نمایید. در انتخاب برد و پورت COM صحیح دقت داشته باشید.

/*
 * Rui Santos 
 * Complete Project Details https://randomnerdtutorials.com
 */

#include <EEPROM.h>

const int buttonPin = 8;    // pushbutton pin
const int ledPin = 4;       // LED pin

int ledState;                // variable to hold the led state
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin


// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  // set input and output
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  // set initial LED state
  digitalWrite(ledPin, ledState);

  // initialize serial monitor
  Serial.begin (9600);

  //check stored LED state on EEPROM using function defined at the end of the code
  checkLedState(); 
}

void loop() {
  // read the state of the switch into a local variable
  int reading = digitalRead(buttonPin);

  if(reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if(reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if(buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // set the LED state
  digitalWrite(ledPin, ledState);
  // save the current LED state in the EEPROM
  EEPROM.update(0, ledState);
  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState
  lastButtonState = reading;
}

// Prints and upates the LED state
// when the Arduino board restarts or powers up
void checkLedState() {
   Serial.println("LED status after restart: ");
   ledState = EEPROM.read(0);
   if(ledState == 1) {
    Serial.println ("ON");
    digitalWrite(ledPin, HIGH);
   } 
   if(ledState == 0) {
    Serial.println ("OFF");
    digitalWrite(ledPin, LOW);
   }
}
  • توضیحات کد

این یک کد Debounce است، به این معنا که برای اطمینان از فشرده شدن کلید، ورودی در یک بازه زمانی کوتاه دو بار بررسی می‌شود. بدین منظور تابع ()Millis مورد استفاده قرار می‌گیرد. با هر بار فشردن کلید، وضعیت ال‌ای‌دی تغییر داده می‌شود و دراینجا آخرین وضعیت ال‌ای‌دی در حافظه EEPROM میکروکنترلر ذخیره می‌شود.

درابتدای برنامه متغیر ledState برای ذخیره وضعیت LED تعریف شده و سپس با دستور زیر ذخیره مقدار این متغیر در آدرس “0” از حافظه انجام می‌شود.

EEPROM.update(0,ledState);

در تابع ()setup، وضعیت ذخیره شده ال ای دی (ledState) در حافظه EEPROM بررسی می‌شود و زمانی که برنامه مجدداً اجرا می‌شود، LED  مطابق با آخرین حالتی که داشته، روشن یا خاموش خواهد شد. این امر توسط تابع ()checkLedState که در انتهای برنامه قرار دارد، انجام می‌شود.

void checkLedState() {
    Serial.println("LED status after restart: ");
    ledState = EEPROM.read(0);
     if (ledState == 1) {
       Serial.println ("ON");
       digitalWrite(ledPin, HIGH);
     } 
     if (ledState == 0) {
       Serial.println ("OFF");
       digitalWrite(ledPin, LOW);
     }
}

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

انواع آی سی حافظه‌ EEPROM را از فروشگاه روبوایکیو خریداری کنید

مقالات مشابه

دیدگاهتان را بنویسید

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

Fill out this field
Fill out this field
لطفاً یک نشانی ایمیل معتبر بنویسید.
You need to agree with the terms to proceed

پر بازدید ترین مقالات