وقت آن رسیده اولین برنامهٔ واقعی خود را بنویسیم: چشمکزدن یک LED، معروف به «Blink». این سادهترین و درعینحال مهمترین برنامهٔ آغازین در دنیای الکترونیک است، چون ثابت میکند ارتباط بین کد و سختافزار بهدرستی برقرار است. اگر تازهکار هستید نگران نباشید — هر خط از این کد را با جزئیات کامل توضیح میدهیم.
قبل از شروع: چند مفهوم پایه
پیش از دیدن کد، سه مفهوم را در یک جمله توضیح میدهیم تا بقیهٔ درس برایتان روشنتر باشد:
- ماژول (Module): یک فایل آماده پر از کد کاربردی است که دیگران (یا خودِ میکروپایتون) نوشتهاند؛ بهجای بازنویسی آن، با
importآن را «وارد» برنامهٔ خودمان میکنیم. - کلاس (Class) و آبجکت (Object): کلاس مثل یک «نقشهٔ ساخت» است (مثلاً نقشهٔ ساخت یک ماشین). وقتی از روی آن کلاس یک نمونهٔ واقعی میسازیم (مثلاً
Pin(2, Pin.OUT))، به آن «آبجکت» میگوییم — دقیقاً مثل ساختن یک ماشین واقعی از روی نقشه. - GPIO: مخفف General Purpose Input/Output؛ یعنی «پایهٔ ورودی/خروجی همهمنظوره». هر پایهٔ فلزی کنار برد ESP32 یک GPIO است که میتوانید به آن بگویید ورودی باشد (چیزی را بخواند) یا خروجی (چیزی را روشن/خاموش کند).
ماژول machine و کلاس Pin
در میکروپایتون، برای کار مستقیم با پایههای سختافزاری از ماژول machine استفاده میکنیم. کلاس Pin به شما اجازه میدهد هر پایهٔ GPIO را بهصورت ورودی یا خروجی پیکربندی کنید.
from machine import Pin
from time import sleep
led = Pin(2, Pin.OUT) # پایه ۲؛ روی اغلب بردها LED آبی داخلی است
while True:
led.on()
sleep(0.5)
led.off()
sleep(0.5)خط به خط، با جزئیات کامل
این بار عمیقتر از قبل، دلیل وجود هر خط را هم توضیح میدهیم، نه فقط کاری که انجام میدهد:
from machine import Pin— از ماژولmachine(که ماژول اصلی سختافزاری میکروپایتون است) فقط کلاسPinرا وارد میکنیم. چرا کل ماژول را وارد نمیکنیم؟ چون معمولاً فقط به بخش کوچکی از یک ماژول نیاز داریم و وارد کردن فقط همان بخش، هم کد را خواناتر میکند و هم کمی حافظه صرفهجویی میکند.from time import sleep— به همین ترتیب، فقط تابعsleep(به معنای «بخواب») را از ماژولtimeوارد میکنیم؛ این تابع اجرای برنامه را برای مدت مشخصی متوقف میکند.led = Pin(2, Pin.OUT)— اینجا یک متغیر بهنامledمیسازیم و آن را برابر یک آبجکت جدید از کلاسPinقرار میدهیم. عدد2شمارهٔ فیزیکی پایهای است که میخواهیم کنترل کنیم (روی اغلب بردهای ESP32 DevKit، یک LED آبی کوچک از قبل به همین پایه وصل است).Pin.OUTبه میکروپایتون میگوید «این پایه قرار است خروجی باشد»، یعنی ما به آن ولتاژ میفرستیم، نه اینکه از آن چیزی بخوانیم.while True:— یک «حلقهٔ بینهایت». عبارتTrueدر پایتون همیشه درست است، پس شرط حلقه هرگز نادرست نمیشود و کد داخل آن تا قطع برق یا ریستشدن برد، بیوقفه تکرار میشود. تقریباً همهٔ برنامههای میکروکنترلری (چه در آردوینو چه در میکروپایتون) درون چنین حلقهای اجرا میشوند، چون برخلاف یک برنامهٔ کامپیوتری معمولی که یکبار اجرا و تمام میشود، یک میکروکنترلر باید تا ابد کار خودش را تکرار کند.led.on()— پایهٔ متصل بهledرا HIGH (سطح ولتاژ ۳٫۳ ولت) میکند؛ LED روشن میشود. توجه کنید این خط با فاصله (Indentation) نوشته شده — در پایتون، فاصلهگذاری اجباری است و مشخص میکند این خط «داخل» حلقهٔ while قرار دارد، نه بعد از آن.sleep(0.5)— اجرای برنامه را دقیقاً نیمثانیه (۵۰۰ میلیثانیه) متوقف میکند تا چشم انسان بتواند روشنبودن LED را ببیند؛ بدون این تأخیر، تغییرات آنقدر سریع اتفاق میافتند که LED فقط کمنور بهنظر میرسد.led.off()وsleep(0.5)— دقیقاً برعکسِ دو خط قبل: پایه را LOW (صفر ولت) میکند و نیمثانیه صبر میکند. سپس حلقه به خط اول (led.on()) برمیگردد و همین چرخه تا ابد تکرار میشود — نتیجه: چشمکزدن پیوسته.
بهجای led.on() و led.off() میتوانید از led.value(1) و led.value(0) یا حتی led.toggle() (در نسخههای جدید) استفاده کنید.
چند اشتباه رایج مبتدیان (و راهحل آنها)
- خطای IndentationError: اگر فاصلهگذاری خطوط داخل
while True:رعایت نشود (مثلاً یک خط چهار فاصله و خط بعدی سه فاصله داشته باشد)، پایتون خطا میدهد. همیشه از یک اندازهٔ ثابت (معمولاً ۴ فاصله، نه Tab) استفاده کنید. - فراموشکردن دو نقطه «:» بعد از while True: بدون این دو نقطه، پایتون نمیفهمد کجا بدنهٔ حلقه شروع میشود.
- روشن نشدن LED: اگر روی برد واقعی LED روشن نشد، شمارهٔ پایه را با سیلکاسکرین (نوشتههای روی خودِ برد) مقایسه کنید؛ بعضی بردها بهجای GPIO2 از پایهٔ دیگری برای LED داخلی استفاده میکنند.
همین حالا امتحان کنید
شبیهسازی زیر همین کد را روی یک ESP32 مجازی اجرا میکند. روی دکمهٔ پخش کلیک کنید تا LED شروع به چشمک زدن کند.
کارگاه عملی: مقدار sleep را به 0.1 تغییر دهید و دوباره اجرا کنید. چه اتفاقی میافتد؟ سپس با یک if ساده، پس از هر ۱۰ بار چشمک زدن پیامی چاپ کنید.
جمعبندی این درس
در این درس یاد گرفتید: چطور یک ماژول را وارد کنید (import)، چطور یک آبجکت از کلاس Pin بسازید، تفاوت ورودی/خروجی در GPIO، و چرا برنامههای میکروکنترلری درون یک while True بینهایت اجرا میشوند. این چهار مفهوم پایهٔ تقریباً تمام درسهای بعدی این دوره هستند.