در این درس یاد میگیرید چگونه از یک دکمهٔ فشاری بهعنوان ورودی دیجیتال استفاده کنید و مفهوم مهم Pull-up و Pull-down را درک کنید — مفهومی که تقریباً هر مبتدی در ابتدا با آن گیج میشود، پس با دقت و آرام جلو میرویم.
چرا به مقاومت Pull-up نیاز داریم؟
یک آزمایش ذهنی کنید: یک سیم را فقط به یک پایهٔ ورودی وصل کنید و سر دیگرش را به هیچجا وصل نکنید (نه به ۳٫۳ ولت، نه به زمین). این پایه در حالت «شناور» (Floating) قرار دارد — نه واقعاً HIGH است و نه LOW، و نویز الکتریکی محیط (حتی دستتان که نزدیک سیم میآید) میتواند مقدار خواندهشده را بهطور تصادفی بین ۰ و ۱ بپراند. برای دکمه هم دقیقاً همین مشکل پیش میآید: وقتی دکمه فشرده نیست، پایهٔ ورودی به هیچ ولتاژ مشخصی وصل نیست.
راهحل: یک مقاومت «کمکی» بین پایه و ۳٫۳ ولت قرار میدهیم (Pull-up) تا وقتی دکمه فشرده نشده، پایه همیشه HIGH بماند. طرف دیگر دکمه به زمین (GND) وصل است؛ پس وقتی دکمه را فشار میدهید، مسیر مستقیمی به زمین باز میشود و پایه ناگهان LOW میشود. ESP32 این مقاومت را بهصورت داخلی دارد، پس نیازی به یک مقاومت فیزیکی جداگانه نیست — کافی است در کد فعالش کنیم.
from machine import Pin
from time import sleep
button = Pin(4, Pin.IN, Pin.PULL_UP)
led = Pin(2, Pin.OUT)
while True:
if button.value() == 0: # دکمه فشرده شده (چون Pull-up است)
led.on()
else:
led.off()
sleep(0.05)خط به خط
Pin(4, Pin.IN, Pin.PULL_UP)— سه آرگومان به Pin میدهیم: شمارهٔ پایه (۴)، حالت (Pin.IN یعنی «ورودی»، برخلاف Pin.OUT در درس قبل)، و سومی Pin.PULL_UP که مقاومت داخلی توضیحدادهشده در بالا را فعال میکند.button.value()— مقدار فعلی پایه را میخواند: عدد ۱ (HIGH) اگر دکمه رها شده، یا ۰ (LOW) اگر فشرده شده باشد.if button.value() == 0:— دقت کنید که شرط برابر با ۰ است، نه ۱! این همان نکتهٔ گیجکنندهای است که در جعبهٔ زیر توضیح دادهایم.sleep(0.05)— کمی مکث (۵۰ میلیثانیه) بین هر خواندن؛ بدون این تأخیر، پردازنده بیوقفه و با سرعت بسیار بالا پایه را میخواند که هم غیرضروری است و هم کمی مصرف انرژی را بالا میبرد.
در حالت Pull-up: دکمهٔ رهاشده = 1 (HIGH)، دکمهٔ فشرده = 0 (LOW). این برعکس چیزی است که خیلیها ابتدا انتظار دارند — منطقیتر بهنظر میرسد که «فشردن دکمه» باید HIGH تولید کند، اما چون از Pull-up استفاده میکنیم، دقیقاً برعکس است.
حذف لرزش کلید (Debounce)
اگر با یک میکروسکوپ زمانی به سیگنال یک دکمهٔ فیزیکی نگاه کنید، میبینید که هنگام فشردن، تماس فلزی داخل دکمه چند بار خیلی سریع (در حد چند میلیثانیه) به هم میخورَد و از هم جدا میشود قبل از اینکه کاملاً «وصل» بماند — این پدیده «لرزش» یا Bounce نام دارد. نتیجه: میکروکنترلر ممکن است یک فشردن واقعی را بهاشتباه بهعنوان ۳ یا ۴ فشردن جداگانه بشمارد. راهحل ساده: بعد از تشخیص اولین تغییر، چند میلیثانیه صبر میکنیم (که لرزشها تمام شوند) و بعد دوباره بررسی میکنیم.
from machine import Pin
from time import sleep
button = Pin(4, Pin.IN, Pin.PULL_UP)
led = Pin(2, Pin.OUT)
counter = 0
last_state = 1
while True:
state = button.value()
if state == 0 and last_state == 1:
sleep(0.03) # debounce
counter += 1
led.value(counter % 2)
print("تعداد فشردن:", counter)
last_state = state
sleep(0.01)نکتهٔ کلیدی این نسخه، متغیر last_state است: با مقایسهٔ حالت فعلی و حالت قبلی، فقط لحظهٔ «تغییر» از رهاشده به فشرده را تشخیص میدهیم (نه هر بار که دکمه فشرده مانده)، و همان لحظه یک تأخیر کوتاه (debounce) اعمال میکنیم تا لرزش تمام شود.
کارگاه عملی: برنامه را طوری تغییر دهید که با هر بار فشردن دکمه، یک پیام متفاوت در سریال چاپ شود (مثلاً با یک لیست از پیامها و شمارنده).
جمعبندی این درس
یاد گرفتید: چرا یک پایهٔ ورودی بدون مقاومت Pull-up/Pull-down «شناور» و غیرقابلاعتماد است، چطور مقاومت داخلی ESP32 را فعال کنید، چرا در حالت Pull-up منطق برعکس میشود، و چطور با مقایسهٔ حالت فعلی/قبلی، لرزش فیزیکی دکمه را کنترل کنید.