🌗 PWM با میکروپایتون روی رزبری پای پیکو: LED نفسکش با duty_u16 و freq
پایههای دیجیتال فقط دو حالت دارند: روشن یا خاموش. پس چطور میشود نور یک LED را آرام کم و زیاد کرد یا سرعت موتور را تنظیم کرد؟ جواب PWM است. در این آموزش PWM با میکروپایتون روی رزبری پای پیکو را یاد میگیری: فرکانس را با freq و شدت را با duty_u16 تنظیم میکنیم، یک LED «نفسکش» با حرکت نرم و طبیعی میسازیم و در آخر با سه کانال PWM روی یک LED رنگی، رنگ درست میکنیم.
PWM به زبان ساده
فرض کن یک چراغ را خیلی سریع روشن و خاموش کنی؛ هزار بار در ثانیه. چشم تو این چشمکها را نمیبیند و فقط «میانگین» نور را حس میکند. اگر در هر چرخه چراغ نصف زمان روشن باشد، نور نصف به نظر میرسد؛ اگر یکدهم زمان، کمنور. به این روش مدولاسیون پهنای پالس (Pulse Width Modulation) میگویند. دو عدد آن را تعریف میکنند:
- فرکانس (freq): چند بار در ثانیه چرخه تکرار شود. برای LED حدود ۱۰۰۰ هرتز.
- دیوتی سایکل (duty): چند درصد هر چرخه روشن باشد. در میکروپایتون با
duty_u16از ۰ (خاموش) تا ۶۵۵۳۵ (کاملاً روشن) داده میشود.
برای فهم دقیقتر عددها، ماشینحساب PWM و تعریف کوتاه PWM در واژهنامه را ببین.
قطعهها و سیمکشی
- رزبری پای پیکو
- یک LED و یک مقاومت ۲۲۰ اهم
- برای بخش دوم: یک LED رنگی RGB کاتد مشترک و سه مقاومت ۲۲۰ اهم
| قطعه | پایهی پیکو |
|---|---|
| آند LED (پایهی بلند) | از راه مقاومت ۲۲۰ اهم به GP15 (پایهی فیزیکی ۲۰) |
| کاتد LED (پایهی کوتاه) | GND (مثلاً پایهی فیزیکی ۱۸) |
کد کامل: LED نفسکش
from machine import Pin, PWM
import time
led = PWM(Pin(15))
led.freq(1000) # 1000 pulses per second
def set_brightness(percent):
# Eyes are not linear: squaring gives a smoother fade (simple gamma)
level = (percent / 100) ** 2
led.duty_u16(int(level * 65535))
try:
while True:
for p in range(0, 101, 2): # fade in
set_brightness(p)
time.sleep_ms(15)
for p in range(100, -1, -2): # fade out
set_brightness(p)
time.sleep_ms(15)
except KeyboardInterrupt:
led.duty_u16(0)
led.deinit() # release the pin
توضیح خط به خط
PWM(Pin(15)): پایهی GP15 را به سختافزار PWM میسپارد. از این به بعد خود تراشه پالسها را میسازد و پردازنده آزاد است.led.freq(1000): هر ثانیه هزار چرخه. در نسخههای جدید میکروپایتون میتوانی همه را یکجا بنویسی:PWM(Pin(15), freq=1000, duty_u16=0).duty_u16: عدد ۱۶ بیتی بین ۰ و ۶۵۵۳۵. نیمهروشن یعنی32768. اگر از آردوینو میآیی، این همانanalogWrite(pin, 0..255)است با بازهی خیلی بزرگتر.- اصلاح گاما: چشم انسان به تغییرهای نور در نورهای کم خیلی حساستر است تا نورهای زیاد. اگر دیوتی را خطی زیاد کنی، LED در نیمهی اول سریع پرنور میشود و نیمهی دوم تقریباً فرقی نمیکند. با به توان دو رساندن درصد، حرکت نور برای چشم یکنواخت میشود. خط
level = percent / 100را جایگزین کن و فرقش را ببین. range(100, -1, -2): از ۱۰۰ تا ۰ با گام منفی؛ عدد ۱- آخر لازم است تا خود صفر هم جزو حلقه باشد.deinit(): PWM را خاموش میکند و پایه را آزاد. روی برد واقعی اگر برنامه را با Stop متوقف کنی و این خط اجرا نشود، PWM سختافزاری به کارش ادامه میدهد و LED روشن میماند.
sleep هم روشن میماند؟ چون PWM یک «کار سختافزاری» است. وقتی دیوتی را تنظیم کردی، تراشه تا ابد همان پالس را تولید میکند و برنامهات میتواند هر کار دیگری بکند. این بزرگترین فرقش با روشن و خاموش کردن دستی پایه در حلقه است.فرکانس را چطور انتخاب کنیم؟
| کاربرد | فرکانس رایج | توضیح |
|---|---|---|
| LED | ۵۰۰ تا ۲۰۰۰ هرتز | زیر ۱۰۰ هرتز ممکن است لرزش ببینی، مخصوصاً در فیلم گوشی. |
| موتور DC با درایور | ۱ تا ۲۰ کیلوهرتز | فرکانس پایین وزوز شنیدنی ایجاد میکند. |
| سروو موتور | دقیقاً ۵۰ هرتز | اینجا پهنای پالس زاویه را تعیین میکند؛ سروو با میکروپایتون را ببین. |
| بازر پسیو | فرکانس همان نت | مثلاً ۴۴۰ هرتز برای نت لا، با دیوتی ۵۰ درصد. |
کمترین فرکانسی که پیکو با میکروپایتون میسازد حدود ۸ هرتز است. در فرکانسهای خیلی بالا (صدها کیلوهرتز) دقت دیوتی کم میشود، چون شمارندهی سختافزاری قدمهای کمتری در هر چرخه دارد؛ برای LED و موتور اصلاً نگرانش نباش.
بخش دوم: ساختن رنگ با سه PWM
یک LED RGB در واقع سه LED قرمز، سبز و آبی در یک بدنه است. با سه کانال PWM میتوانی هر رنگی بسازی. پایهی بلند (کاتد مشترک) به GND و سه پایهی رنگ هر کدام از راه یک مقاومت ۲۲۰ اهم به GP13، GP14 و GP15:
from machine import Pin, PWM
import time
red = PWM(Pin(13))
green = PWM(Pin(14))
blue = PWM(Pin(15))
for ch in (red, green, blue):
ch.freq(1000)
def color(r, g, b):
# r, g, b from 0 to 255, like on a web page
red.duty_u16(r * 257)
green.duty_u16(g * 257)
blue.duty_u16(b * 257)
palette = [(255, 0, 0), (255, 120, 0), (255, 255, 0),
(0, 255, 0), (0, 200, 255), (0, 0, 255), (160, 0, 255)]
while True:
for r, g, b in palette:
color(r, g, b)
print("color:", r, g, b)
time.sleep(0.7)
چرا ضرب در ۲۵۷؟ چون ۲۵۵ ضرب در ۲۵۷ دقیقاً ۶۵۵۳۵ میشود؛ پس عددهای آشنای ۰ تا ۲۵۵ رنگها را به بازهی duty_u16 میبریم. GP14 و GP15 یک برش PWM را شریکاند، ولی چون هر دو ۱۰۰۰ هرتزند، مشکلی پیش نمیآید.
اجرا در شبیهساز
در تینکرکد فارسی مثال آمادهی دیمر LED با MicroPython روی پیکو همین PWM را با یک پتانسیومتر ترکیب میکند. کد آن را با برنامهی LED نفسکش بالا عوض کن و نور را تماشا کن. پیکو و میکروپایتون جزو اشتراک پلاس هستند؛ مثال برای خواندن رایگان باز میشود و برای اجرا پلاس لازم است. اگر میخواهی اصل مفهوم را اول رایگان روی آردوینو ببینی، درس PWM و فید LED و پروژهی نفس کشیدن LED را باز کن.
اشکالهای رایج
- LED فقط روشن و خاموش میشود و نرم نیست: به جای
PWM(Pin(15))نوشتهایPin(15, Pin.OUT)و باvalueکار میکنی. - ValueError یا خطای محدوده: عدد
duty_u16بیشتر از ۶۵۵۳۵ یا منفی است. باmax(0, min(65535, x))محدودش کن. - TypeError: can't convert float to int:
duty_u16عدد صحیح میخواهد؛ حاصل محاسبه را باint()گرد کن. - LED بعد از Stop روشن میماند: روی برد واقعی
deinit()صدا نشده؛ همانtry/except KeyboardInterruptرا به کار ببر. - دو LED با هم عوض میشوند: GP0 و GP16 (یا هر دو پایهای با ۱۶ عدد فاصله) یک کانال PWM هستند. یکی را جابهجا کن.
- فید پلهپله است: گام حلقه را کوچکتر کن (۱ به جای ۲) یا اصلاح گاما را اضافه کن.
قدم بعدی: نور را با یک ولوم کنترل کن در ADC پیکو با میکروپایتون. اگر با ESP32 کار میکنی، همین مفهوم آنجا اسم ledc دارد: فید LED با ledc روی ESP32. نقشهی پایهها و برشهای PWM در پین اوت رزبری پای پیکو آمده و اگر پایههای پایتون را هنوز محکم نکردهای، آموزش میکروپایتون از صفر را ببین.
دیمر PWM پیکو را باز کن 🌗سؤالهای رایج
duty_u16 چه عددی میگیرد؟
عددی از ۰ تا ۶۵۵۳۵. صفر یعنی همیشه خاموش، ۶۵۵۳۵ یعنی همیشه روشن و ۳۲۷۶۸ یعنی نصف زمان روشن. این همان analogWrite آردوینو است، فقط با بازهی بزرگتر به جای ۰ تا ۲۵۵.
برای LED چه فرکانسی مناسب است؟
هر عددی بین ۵۰۰ تا ۲۰۰۰ هرتز خوب است و ۱۰۰۰ هرتز انتخاب رایج است. زیر حدود ۱۰۰ هرتز ممکن است لرزش نور را حس کنی. موتور معمولاً با چند کیلوهرتز و سروو با ۵۰ هرتز کار میکند.
چرا دو پایهی PWM من با هم عوض میشوند؟
پایههایی که یک برش (slice) PWM را شریکاند، مثل GP14 و GP15، فرکانس یکسان دارند؛ با تغییر فرکانس یکی، دیگری هم عوض میشود. GP0 و GP16 حتی یک کانالاند و خروجی یکسان میدهند. پایهها را از برشهای مختلف انتخاب کن.
مقالههای مرتبط
ADC رزبری پای پیکو با میکروپایتون: خواندن پتانسیومتر با read_u16 و تبدیل به ولتاژ
سروو موتور با میکروپایتون روی رزبری پای پیکو: PWM پنجاه هرتز و کنترل زاویه
سنسور اولتراسونیک HC-SR04 با میکروپایتون روی رزبری پای پیکو (time_pulse_us)
قفل در با کارت RFID (MFRC522) و سروو موتور در آردوینو
همهی آموزشهای رزبری پای پیکو و میکروپایتون ← · همهی مقالهها