معماری میکروکنترلر
داخل ATmega328P؛ تفکیک حافظههای Flash و SRAM و EEPROM، معماری هاروارد، مفهوم کلاک ۱۶ مگاهرتز، ساختار GPIO و ADC و PWM، بودجهبندی حافظه و مقایسهٔ حافظهٔ Uno با ESP32.
آنچه در این درس میآموزید
- نقش سه حافظهٔ Flash و SRAM و EEPROM را در ATmega328P توضیح دهید
- مفهوم کلاک و چرخهٔ ساعت را با عدد واقعی ATmega328P بیان کنید
- اتصال GPIO و ADC و PWM و وقفه به سختافزار داخلی را ردیابی کنید
- بودجهٔ ۲ کیلوبایت SRAM را حساب کنید و دلیل کرش برنامههای سنگین را بدانید
فهرست مطالب
هر اسکچی که تا حالا نوشتهاید، در نهایت روی یک تراشهٔ کوچک اجرا شده: ATmega328P، همان چیپ دیپای ۲۸ پینی که وسط Uno نشسته. تا اینجا با توابع آردوینو با آن حرف زدهاید؛ حالا وقت آن است که داخل این چیپ را ببینید: برنامه کجا نگه داشته میشود؟ متغیرها کجا هستند؟ چرا حافظه اینقدر کم است و چرا برنامههای سنگین «بهظاهر درست» ناگهان کرش میکنند؟ این درس نقشهٔ داخلی میکروکنترلر را سطحی اما درست — بدون رجیسترنویسی — ترسیم میکند.
سه حافظه، سه نقش
داخل ATmega328P سه نوع حافظه با نقشهای کاملاً متفاوت وجود دارد:
| حافظه | ظرفیت | چه چیزی نگه میدارد | با قطع برق |
|---|---|---|---|
| Flash | ۳۲ کیلوبایت | برنامهٔ شما (اسکچ کامپایلشده) | میماند |
| SRAM | ۲ کیلوبایت | متغیرها، پشته و دادهٔ زمان اجرا | پاک میشود |
| EEPROM | ۱ کیلوبایت | دادهٔ ماندگارِ دلخواه | میماند |
این تفکیک عمدی است و یک نام دارد: «معماری هاروارد» (Harvard Architecture) — مسیر برنامه و مسیر داده از هم جدا هستند و CPU هر دو را بهطور موازی میخواند. نتیجهٔ عملی برای شما: کامپایلر گزارش میدهد اسکچ چند درصد Flash را گرفته، اما متن برنامه هرگز در SRAM جا نمیشود و برعکس؛ و اگر دادهٔ مهمی بخواهید پس از خاموشی بماند، باید خودتان آن را در EEPROM بنویسید (کتابخانهٔ EEPROM از همان کتابخانههای همراه هسته است که در درس کتابخانهها دیدید).
کلاک: ضربان چیپ
هر میکروکنترلر با یک ساعت بیرونی/داخلی تپ میکند. روی Uno یک «کریستال کوارتز» ۱۶ مگاهرتز کنار چیپ هست؛ یعنی چیپ در هر ثانیه ۱۶ میلیون «چرخهٔ ساعت» (Clock Cycle) میزند و هر چرخه ۶۲٫۵ نانوثانیه است. بسیاری از دستورهای سادهٔ AVR در یک چرخه انجام میشوند؛ پس عدد ۱۶ مگاهرتز را میتوانید تقریباً «۱۶ میلیون دستور ساده در ثانیه» بفهمید. همین تپش است که سرعت حلقهٔ millis، نرخ نمونهبرداری ADC و فرکانس PWM را تعیین میکند؛ وقتی میگوییم Due با ۸۴ مگاهرتز سریعتر است، یعنی همین ضربان پنجبرابر است.
از CPU تا پینها
نقشهٔ سادهٔ ارتباطات داخلی چنین است: CPU در مرکز، دورش حافظهها، و از CPU به سمت پینهای لبهٔ چیپ چند واحد پیرامونی:
- GPIO — هر گروه از پینهای دیجیتال به یک «پورت» متصل است (مثلاً پورت B برای پینهای ۸ تا ۱۳ در Uno). وقتی digitalWrite مینویسید، کتابخانه در نهایت یک بیت از رجیستر همان پورت را یک یا صفر میکند. به همین دلیل pinMode و digitalWrite روی پینهای «یک پورت» بهصورت گروهی هم قابلانجاماند — بحث پیشرفته، اما ریشهاش همین است.
- ADC — پینهای A0 تا A5 به یک مبدل آنالوگ به دیجیتال ۱۰ بیتی مشترک میروند. ده بیت یعنی ۱۰۲۴ پله: ولتاژ ۰ تا ۵ ولت به عدد ۰ تا ۱۰۲۳ نگاشت میشود؛ هر پله حدود ۴٫۹ میلیولت. analogRead همین مبدل را به پین دلخواه وصل میکند.
- PWM و تایمرها — ATmega328P سه تایمر سختافزاری دارد که هم پشت millis هستند و هم خروجی PWM را روی پینهای ۳، ۵، ۶، ۹، ۱۰ و ۱۱ میسازند؛ همان پینهای ~ که در درس PWM استفاده کردید.
- واحد وقفه — همان که در درس وقفهها دیدید: سختافزاری که رویداد پینهای ۲ و ۳ و تایمرها را به CPU اعلام میکند.
بودجهبندی حافظه: چرا ۲ کیلوبایت کم است؟
همهٔ متغیرها، رشتهها، پشتهٔ توابع و بافرهای کتابخانهها باید در ۲ کیلوبایت SRAM جا شوند. مشهورترین قربانی این محدودیت کلاس String است: هر بار که رشتهای را ترکیب میکنید، حافظهٔ جدید گرفته و حافظهٔ قدیمی رها میشود؛ بعد از هزاران تکرار، حافظه «تکهتکه» (Fragmentation) میشود — جمع فضای خالی کافی است اما هیچ قطعهٔ پیوستهای برای رشتهٔ جدید نمیماند — و برنامه بیپیام ریست میشود یا قفل میکند. قاعدهٔ عملی: روی Uno رشتههای در حال چرخه را تا حد امکان با آرایهٔ کاراکتری ثابت (char) نگه دارید و String را برای مقادیر موقت بهکار ببرید.
نکتهٔ دوم EEPROM است: نگهداشتن داده در آن رایگان نیست؛ هر خانه حدود ۱۰۰ هزار بار نوشتن را تحمل میکند. اگر حلقهای هر ثانیه یک عدد در EEPROM بنویسد، پس از حدود ۱۱۵ روز آن خانه میپالاید. برای همین دادهای که مرتب عوض میشود را در SRAM نگه دارید و فقط هنگام تغییر واقعی و کمتکرار در EEPROM بنویسید.
مقایسهٔ کوچک با ESP32
| ویژگی | Uno (ATmega328P) | برد توسعهٔ ESP32 |
|---|---|---|
| SRAM | ۲ کیلوبایت | حدود ۵۲۰ کیلوبایت |
| Flash | ۳۲ کیلوبایت | معمولاً ۴ مگابایت روی برد |
| کلاک | ۱۶ مگاهرتز تکهسته | ۲۴۰ مگاهرتز دوهستهای |
همان اسکچی که روی Uno با تکهتکهشدن حافظه دستوپا میزند، روی ESP32 جا و اسباب فراوان دارد؛ اما اصول یادشده یکی است: SRAM زمان اجراست، Flash برنامه است و EEPROM/حافظهٔ ماندگار ظرفیت نوشتن محدود دارد.
اشتباهات رایج و عیبیابی
| نشانه | علت رایج | راهحل |
|---|---|---|
| برنامه بعد از ساعتها بیدلیل ریست میکند | تکهتکهشدن SRAM با ساختن String در حلقه | رشتههای چرخهای را با char ثابت یا بافر پیشتعریفشده جایگزین کنید |
| گزارش کمبود حافظه هنگام کامپایل | متن رشتهها و دادههای بزرگ در SRAM بارگذاری شدهاند | رشتههای ثابت را با ماکروی F() به Flash منتقل کنید |
| دادهٔ ذخیرهشده در EEPROM بعد از مدتی خراب میشود | نوشتن بیش از حد در یک خانه (فرسایش حدود ۱۰۰ هزار نوشتن) | فقط هنگام تغییر واقعی بنویسید و آدرسها را بین چند خانه بچرخانید |
| متغیرها بعد از قطع برق از دست رفتهاند | نگهداری در SRAM که پاکشونده است | مقادیر ماندگار را در EEPROM ذخیره کنید |
| analogRead عدد پرت میدهد | پین آنالوگ شناور بدون اتصال قطعی | پین را به منبع ولتاژ مشخص و GND مشترک وصل کنید |
تمرینها
تمرین
تمرین ۱ — بودجهٔ SRAM
چند متغیر از نوع int در ۲ کیلوبایت SRAM جا میشود؟ محاسبه را نشان دهید. سپس بگویید اگر یک آرایهٔ ۵۰۰ عضوی از int بسازید، چند بایت از بودجه مصرف شده و چند بایت برای بقیهٔ برنامه (متغیرهای دیگر، پشته و کتابخانهها) میماند.
نمایش راهحل
هر int در آردوینو Uno ۲ بایت است و ۲ کیلوبایت برابر ۲۰۴۸ بایت:
۲۰۴۸ ÷ ۲ = ۱۰۲۴ متغیر int — حداکثر نظری.
آرایهٔ ۵۰۰ عضوی: ۵۰۰ × ۲ = ۱۰۰۰ بایت، یعنی نیمی از کل SRAM. باقی میماند:
۲۰۴۸ − ۱۰۰۰ = ۱۰۴۸ بایت برای همهٔ متغیرهای دیگر، بافر کتابخانهها (مثلاً سریال) و پشتهٔ توابع.
نتیجهٔ عملی: عدد ۱۰۲۴ سقف نظری است؛ در واقعیت چون پشته و کتابخانهها همیشه سهم دارند، آرایهای در حد یک سوم تا نیم SRAM سقف معقول برنامههای واقعی است. حسابی که اینجا کردید همان بودجهبندی ذهنیای است که پیش از ساختن آرایههای بزرگ روی Uno باید انجام دهید.
:::
خلاصه
- ATmega328P سه حافظه دارد: Flash ۳۲ کیلوبایتی برای برنامه، SRAM ۲ کیلوبایتی برای متغیرها و EEPROM ۱ کیلوبایتی برای دادهٔ ماندگار؛ تفکیک برنامه و داده، معماری هاروارد است.
- کریستال ۱۶ مگاهرتز یعنی ۱۶ میلیون چرخه در ثانیه و هر چرخه ۶۲٫۵ نانوثانیه؛ بسیاری از دستورها یک چرخه طول میکشند.
- GPIOها به پورتها و ADC دهبیتی (۰ تا ۱۰۲۳) و سه تایمر پشت PWM و millis و واحد وقفه، پیرامونهای داخلی CPU هستند.
- String در حلقه SRAM را تکهتکه میکند و ریست بیدلیل میآورد؛ EEPROM حدود ۱۰۰ هزار نوشتن در هر خانه دوام دارد.
- همین اسکچ روی ESP32 با حدود ۵۲۰ کیلوبایت SRAM و ۴ مگابایت Flash نفس راحت میکشد.
حالا میدانید زیر هر درس این دوره چه سختافزاری ایستاده: از پین دیجیتال تا گذرگاهها و حافظهها. با این نقشه، مسیر پیشرفت — تایمرهای رجیستری، بردهای ARM و پروژههای چندماژولی — بهدست خودتان باز است.