تایمر چیست؟
قبل از پرداختن به آموزش PWM در کدویژن، با تایمر آشنا میشویم. ما هر روز از تایمر استفاده میکنیم. سادهترین آن را میتوانید روی مچ دست خود مشاهده کنید. یک ساعت ساده ثانیهها، دقیقهها و ساعتهای سپری شده در یک روز معین (در مورد ساعتهای دوازدهساعته، از نیمروز گذشته) را زمانبندی میکند. تایمرهای میکروکنترلرهایی مانند AVR نیز کار مشابهی را انجام میدهند و فاصله زمانی معینی را اندازهگیری میکنند.
تایمر AVR در سادهترین حالت یک ثَبات (رجیستر) است. تایمرها به طور کلی دارای وضوح ۸ یا ۱۶ بیت هستند. بنابراین یک تایمر ۸ بیتی ۸ بیت عرض یا پهنا دارد و میتواند مقداری بین ۰ تا ۲۵۵ را در خود نگه دارد. اما این رجیستر دارای یک ویژگی جادویی است: مقدار آن به طور خودکار با نرخ از پیش تعیین شده (توسط کاربر) افزایش/کاهش مییابد. این همان کلاکِ (ساعت) تایمر است و این عملیات نیازی به مداخله CPU ندارد.
تایمرهای AVR بسیار کاربردی و کارآمد هستند، زیرا به صورت ناهمزمان با هسته اصلی AVR اجرا میشوند. به بیان سادهتر، تایمرها مدارهای جداگانهای روی تراشه میکروکنترلر هستند که میتوانند از طریق رجیسترهای کنترل و شمارش، مستقل از برنامه اصلی اجرا شوند و چیزی به نام تایمر وقفه ایجاد کنند. تولید PWM در کدویژن را به سادگی میتوان برای میکروکنترلر AVR انجام داد.
وقفه چیست؟
قبل از یادگیری تایمرها باید مفهوم وقفه را بدانید، زیرا تایمرها عمدتاً از طریق وقفه با CPU تعامل دارند. مفهوم وقفه در ارتباط با میکروکنترلرها شبیه به مفهوم وقفه در زندگی روزمره ما است: فرض کنید شما این آموزش را میخوانید و ناگهان تلفن همراه شما زنگ می زند. کاری که شما انجام میدهید این است که مدتی مطالعه را متوقف کرده و در تماس تلفنی شرکت میکنید و سپس کارتان از سر میگیرید. از جایی که خواندنتان قطع شد، ادامه میدهید و این دقیقاً همان کاری است که وقفه در MCU انجام میدهد. وقتی MCU برنامهای را اجرا میکند، اگر چیزی نیاز به توجه فوری داشته باشد، وقفهای در آن کار ایجاد میشود و اجرای برنامه فعلی در آن زمان متوقف میماند و وقفه مدیریت میشود. پس از آن، اجرای برنامه به طور معمول از نقطهای که متوقف شده است ادامه مییابد. تایمرها موازی و مستقل از CPU با فرکانس خاصی کار میکنند و با صدور وقفه با CPU تعامل دارند.
دو نوع وقفه وجود دارد:
- وقفه سرریز (Overflow Interrupt)
- وقفه تطبیق مقایسه (Compare Match Interrupt)
وقفه سرریز
وقفه سرریز هر زمان که رجیستر تایمر سرریز میشود، یعنی به حداکثر مقدار خود میرسد (در این مورد، ۲۵۵ یا در حالت هگزادسیمال، FFh) ایجاد میشود.
برای استفاده از وقفه سرریز، ابتدا باید فرکانس ساعت خود را تعیین کنید. سپس کادر تأیید “overflow interrupt” را که در برگه Timers در CodeWizard AVR ظاهر میشود، علامت بزنید (توجه: از قسمت “Timer value” میتوان مقدار اولیه تایمر را تنظیم کرد. به طور پیشفرض روی ۰ تنظیم شده است). اکنون وقتی فایل تولید میشود، متوجه میشوید که یک تابع در کد ظاهر می شود:
اکنون می توانید کدی را در اینجا قرار دهید که هر بار که وقفه سرریز ایجاد میشود، اجرا شود.
از این وقفه میتوان برای اندازه گیری فواصل زمانی بزرگتر از یک چرخه استفاده کرد. به عنوان مثال، فرض کنید یک LED متصل به پین ۰ پورت A است و میخواهید با فرکانس ۰٫۵ هرتز با استفاده از وقفههای سرریز چشمک بزند. از آنجا که فرکانس سیستم ۸ مگاهرتز است، میتوانید سرعت ساعت مناسبی را مثلاً FCPU/۱۰۲۴ تنظیم کنید (به Prescalar نگاه کنید) و سپس این کار را به صورت زیر انجام دهید:
این تابع هر بار که وقفه سرریز فراخوانی میشود، متغیر “count” را افزایش میدهد و هنگامی که زمان مناسب سپری میشود، مقدار PORTA.۰ را تغییر میدهد.
وقفه تطبیق مقایسه
هرگاه مقدار تایمر برابر با یک مقدار معین از پیش تعیین شده باشد، یک وقفه مقایسهای توسط تایمر صادر میشود. این مقدار از پیش تعریف شده در رجیستری ذخیره میشود که به عنوان رجیستر مقایسه خروجی (Output Compare Register) شناخته میشود.
وقفه تطبیق مقایسه توسط CTC ، Fast-PWM و Phase correct PWM modes of a timer (شکل زیر را ببینید).
برای استفاده از وقفه تطبیق مقایسه، کادر تأیید “compare match interrupt” را که در برگه Timers در CodeVision Wizard ظاهر شده است، علامت بزنید. مقدار OCR را در مقدار Compare value در اعداد هگزادسیمال تنظیم کنید. اکنون وقتی فایل خود را تولید میکنید، متوجه میشوید که یک تابع در کد ظاهر میشود:
اکنون میتوانید کدی را که هر بار وقفه تطبیق مقایسه ایجاد میکند، اجرا کنید:
چگونه از تایمرها استفاده کنیم؟
از آنجا که تایمر مستقل از CPU کار میکند، میتوان از آن برای اندازهگیری دقیق زمان استفاده کرد. تایمر تحت شرایط خاص به صورت خودکار اقداماتی را انجام میدهد یا CPU را مطلع میکند. همانطور که میدانیم، تایمر یک رجیستر ۸ بیتی است که مقدار خود را افزایش میدهد، بنابراین یکی از شرایط اساسی این است که تایمر سرریزها را ثبت کند، یعنی حداکثر مقدار خود را (۲۵۵ برای تایمر ۸ بیتی) شمارش کند.
بازگشت به ۰ در این شرایط تایمر میتواند وقفهای ایجاد کند و باید یک روال سرویس وقفه (ISR) را برای مدیریت رویداد بنویسید. سه تایمر مختلف در Atmega۱۶ موجود است و همه تایمرها تقریباً به یک شکل کار میکنند. این تایمرها TIMER۰ و TIMER۱ و TIMER۲ هستند.
مقسم
«مقسم» (Prescaler) مکانیزمی برای تولید ساعت برای تایمر توسط ساعت CPU است. هر CPU دارای یک منبع ساعت است و فرکانس این منبع نرخ اجرای دستورات توسط پردازنده را تعیین میکند. ساعت Atmega دارای چندین فرکانس مانند ۱ مگاهرتز، ۸ مگاهرتز، ۱۲ مگاهرتز، ۱۶ مگاهرتز (حداکثر) است. مقسم برای تقسیم این فرکانس ساعت و تولید ساعت برای تایمر استفاده میشود. مقسم را میتوان طوری تنظیم کرد که انواع زیر را تولید کند:
- بدون ساعت (No Clock) یا توقف ساعت
- بدون تقسیم (فرکانس ساعت = فرکانس CPU)
- FCPU/۸
- FCPU/۶۴
- FCPU/۲۵۶
- FCPU/۱۰۲۴
- ساعت خارجی، اگرچه به ندرت استفاده میشود.
حالتهای تایمر
تایمرها معمولاً در یکی از حالتهای زیر استفاده میشوند:
- نرمال (Normal)
- CTC
- PWM سریع (Fast PWM)
- PWM تصحیح فاز (Phase correct PWM)
در ادامه، این حالتها را توضیح میدهیم.
حالت نرمال
تایمری که در حالت نرمال کار میکند، حداکثر مقدار خود را محاسبه میکند. وقتی به این حداکثر مقدار میرسد، یک وقفه سرریز صادر میکند و مقدار تایمر را به مقدار اولیه خود باز میگرداند.
در مورد بالا، میتوانید ببینید که دوره ۲۵۶ برابر دوره ساعت است. ۲۵۵ چرخه یا دوره ساعت برای دستیابی به حداکثر مقدار و یک چرخه ساعت برای پاک کردن مقدار تایمر مورد نیاز است. بنابراین، ftimer = fclock/۲۵۶.
حالت CTC
در اینجا نحوه استفاده از تایمر در حالت مقایسه را خواهیم دید. در حالت نرمال، ساعت تایمر را با استفاده از مقسم تنظیم میکنیم و اجازه میدهیم تایمر کار کند. وقتی سرریز شد، یک وقفه برای مدیریت سرریز ایجاد میکنیم. این حالت، با وجود سادگی، محدودیتهای خود را دارد، زیرا در یک مجموعه بسیار کوچک از مقادیر فرکانس تایمر محدود شدهایم. این محدودیت با حالت مقایسه برطرف میشود.
در حالت مقایسه از رجیستری استفاده میشود که به عنوان خروجی مقایسه میشود و مقدار انتخابی ما را ذخیره میکند. تایمر به طور مداوم مقدار فعلی خود را با مقدار موجود در ثبات مقایسه میکند و هنگامی که دو مقدار با هم مطابقت داشته باشند، میتوان وقایع زیر را تنظیم کرد:
- یک پین مربوط به مقایسه خروجی میتواند تنظیم شود (روی high قرار گیرد)، پاک شود (low قرار داده شود) یا به طور خودکار تغییر حالت دهد. این حالت برای تولید امواج مربعی با فرکانسهای مختلف ایدهآل است.
- میتوان از آن برای تولید سیگنال PWM مورد استفاده برای پیادهسازی مبدل دیجیتال به آنالوگ (DAC) استفاده کرد که می تواند برای کنترل سرعت موتورهای DC استفاده شود.
- به سادگی تولید، وقفه و فراخوانی یک ناظر (Handler) را انجام دهید.
در یک تطبیق مقایسه، تایمر خود را به ۰ بازنشانی میکند که CTC (مخففِ Clear Timer on Compare Match به معنی پاک کردن زمان در تطبیق مقایسه) نامیده میشود.
در این حالت، فرض کنید ما پیشامد خود را طوری تنظیم کردهایم که پین خروجی را تغییر دهد. در این حالت، پین خروجی برای یک دوره زمانی تایمر high باقی میماند و برای یک دوره زمانی دیگر low خواهد ماند. بنابراین، tout = ۲ × ttimer.
از حالت نرمال میتوانیم برای پیدا کردن ttimer بنویسیم: ttimer = tclock × (OCR + ۱)
حالت مدولاسیون پهنای پالس (PWM)
یک قطعه دیجیتالی مانند میکروکنترلر میتواند به راحتی با ورودی و خروجیهایی که فقط دو حالت (روشن یا خاموش) دارند، کار کند. بنابراین، میتوانید به راحتی از آن برای کنترل وضعیت LED، یعنی روشن یا خاموش کردن آن استفاده کنید. به همین ترتیب، میتوانید از آن برای روشن یا خاموش کردن هر وسیله برقی با استفاده از درایورهای مناسب (ترانزیستور، ترایاک ، رله و غیره) استفاده کنید. اما گاهی نیازی به کنترل «روشن» و «خاموش» دستگاه ندارید. به عنوان مثال، اگر می خواهید روشنایی یک LED (یا هر لامپ دیگری) یا سرعت موتور DC را کنترل کنید، سیگنال های روشن/خاموش دیجیتال کافی نخواهد بود. این وضعیت بسیار هوشمندانه با تکنیکی به نام PWM یا «مدولاسیون پهنای پالس» (Pulse Width Modulation) اداره میشود.
PWM تکنیکی است که برای تولید سیگنالهای آنالوگ از قطعات دیجیتال، مانند MCU، به کار میرود. در ادامه، با PWM و روش تولید PWM در کدویژن آشنا میشویم.
مدولاسیون پهنای پالس
یک میکروکنترلر فقط میتواند دو سطح در خروجی خود ایجاد کند: HIGH = ۵V و LOW = ۰V. اما اگر بخواهیم ۲٫۵ ولت یا ۳٫۱ ولت یا هر ولتاژی بین ۰ تا ۵ ولت را به عنوان خروجی تولید کنیم، باید چه کاری را انجام دهیم؟ برای این کار، به جای تولید خروجی ولتاژ DC ثابت، یک موج مربعی تولید میکنیم که ویژگی آن HIGH = ۵V و LOW = ۰V است.
یک اصطلاح به نام «چرخه وظیفه» ( Duty Cycle) تعریف میشود:
d = ton/ttotal×۱۰۰%
مشاده میکنید که چرخه وظیفه در مورد شکل بالا ۵۰ درصد است. اگر فرکانس چنین موجی به اندازه کافی زیاد باشد (مثلاً ۵۰۰ هرتز)، خروجی نصف ۵ ولت یعنی ۲٫۵ ولت است. بنابراین، اگر این خروجی به موتور وصل شود (با استفاده از درایورهای مناسب)، در ۵۰٪ سرعت کامل ۵V کار میکند. تکنیک PWM در کدویژن و میکروکنترلر از این حقیقت برای ایجاد هرگونه ولتاژ بین دو مقدار (به عنوان مثال بین ۰ ولت و ۱۲ ولت) استفاده میکند. کافی است که چرخه وظیفه را بین ۰ تا ۱۰۰ درصد تغییر دهید و درصد مشابهی از ولتاژ ورودی را به خروجی به دست آورید.
به مثالهای زیر توجه کنید.
در شکل بالا، چرخه وظیفه ۷۵ درصد است. بنابراین معادل ولتاژ خروجی آنالوگ ۳٫۷۵ ولت خواهد بود.
در شکل اخیر، چرخه وظیفه ۱۲٫۵ درصد است. بنابراین ولتاژ خروجی آنالوگ ۰٫۶۲۵ ولت خواهد بود. میبینیم که به راحتی میتوان به ولتاژهای دلخواه دست یافت. در ادامه این مطلب، نحوه تنظیم تایمر و تولید PWM در کدویژن را بیان میکنیم.
تولید سیگنال PWM با استفاده از تایمرهای AVR
در میکروکنترلرهای AVR، سیگنالهای PWM توسط تایمرها تولید میشوند. دو روش برای تولید PWM از تایمرها وجود دارد:
- PWM سریع
- PWM تصحیح فاز
در ادامه این موارد را شرح میدهیم.
تولید PWM سریع
ما از سادهترین تایمر، یعنی TIMER۰ برای تولید PWM استفاده میکنیم. بنابراین یک شمارنده ۸ بیتی داریم که از ۰ تا ۲۵۵ شمارش میکند و سپس روی ۰ و غیره تنظیم میشود. این را میتوان به صورت شکل زیر نشان داد.
دوره به تنظیمات مقسم بستگی دارد. در حال حاضر برای تولید PWM در کدویزن از این توالی شمارش از OCR۰ (مقایسه خروجی رجیستر صفر) استفاده میشود (صفر به دلیل اینکه برای TIMER۰ است و تعداد بیشتری از آنها برای TIMER۱ و TIMER۲ وجود دارد). می توانیم هر مقداری بین ۰ تا ۲۵۵ را در OCR۰ ذخیره کنیم. به عنوان مثال، ۶۴ را در OCR۰ ذخیره میکنیم که به صورت شکل زیر نشان داده میشود (خط قرمز).
وقتی TIMER۰ برای حالت PWM سریع پیکربندی میشود، در حالی که تایمر در حال شمارش است، هر زمان که مقدار شمارنده TIMER۰ با مقدار موجود در رجیستر OCR۰ مطابقت داشته باشد، پین خروجی Low یا ۰ میشود و هنگام شمارش مجدد دوباره از ۰ شروع میشود و پس از آن، پین دوباره SET خواهد شد (VCC). این موضوع در شکل زیر نشان داده شده است. این پین OC۰ نام دارد و میتوانید آن را در نقشه پین ATmega۳۲ پیدا کنید.
در شکل بالا میبینید که موجی از چرخه وظیفه ۲۵٪ = ۶۴/۲۵۶ با تنظیم OCR۰ روی ۶۴ تولید میشود. میتوانید OCR۰ را روی هر مقداری تنظیم کرده و یک PWM چرخه وظیفه OCR۰/۲۵۶ را به دست آورید. هنگامی که آن را روی ۰ تنظیم کنید، ۰٪ چرخه وظیفه را دریافت میکنید، در حالی که اگر آن را روی ۲۵۵ قرار دهید، ۱۰۰٪ خروجی چرخه وظیفه را خواهید داشت. بنابراین با تغییر چرخه کاری میتوانید خروجی ولتاژ آنالوگ را از پین OC۰ دریافت کنید.
در حالت معکوس، مقدار پین OC۰ معکوس مقدار فوق است. بنابراین هرگاه مقدار شمارنده TIMER۰ کمتر از مقدار OCR۰ باشد، پین OC۰ روی LOW است، در غیر این صورت HIGH خواهد بود. میتوانید حالت معکوس یا غیرمعکوس را در قسمت “Output” در CodeWizard AVR انتخاب کنید. حالتهای معکوس و غیرمعکوس دارای چرخههای کاری متفاوتی به صورت زیر است:
dinv + dnon-inv = ۱۰۰%
و خواهیم داشت:
tout = ttimer = ۲۵۶ × tclock
تولید PWM تصحیح فاز
این حالت بسیار شبیه حالت سریع PWM است، با این تفاوت که هر زمان که مقدار تایمر به حداکثر مقدار خود رسید، به جای پاک کردن مقدار تایمر، به سادگی شروع به شمارش معکوس میکند.
مقدار پین فقط زمانی تغییر میکند که مقدار OCR۰ با شمارنده TIMER۰ مطابقت داشته باشد.
در اینجا، داریم:
tout = ttimer = ۲ × tclock × OCR
و
fout = fclock / (۲ × OCR)
در ادامه، روش تنظیم تایمر و PWM در کدویژن را شرح میدهیم.
تنظیم تایمر و PWM در کدویژن
هنگام تنظیم یک پروژه جدید، میتوان تایمرها را در پنجره CodeWizard AVR پیکربندی کرد. PWM در کدویژن را بدین صورت میتوان تولید کرد. برای تنظیم تایمر، این دستورالعملها را دنبال کنید:
- CodeVision AVR را باز کرده و روی File -> New کلیک کنید.
- پنجره نشان داده شده در شکل بالا ظاهر میشود. روی “Yes” کلیک کنید.
- در پنجره CodeWizard AVR، تراشه و فرکانس خود را انتخاب کنید.
- روی برگه “Timers” در بالا کلیک کنید.
پنجره به شما امکان میدهد TIMER۰ و TIMER۱ و TIMER۲ را پیکربندی کنید. در حال حاضرو، میتوانید تایمر Watchdog را نادیده بگیرید.
- منوی “Clock Source” به شما امکان میدهد منبع ساعت را برای تایمر فعلی انتخاب کنید. میتوانید ساعت سیستم یا یک ساعت خارجی را انتخاب کنید. اغلب میتوانید “System Clock” را انتخاب کنید.
- منوی “Clock Value” به شما این امکان را میدهد که فرکانس ساعت تایمر را تنظیم کنید.
- حالت یا مد تایمر را در منوی “Mode” انتخاب کنید.
- در منوی “Output”، گزینه مناسب را برای تایمر خود انتخاب کنید. این منو بسته به حالت تایمر شما گزینههای متفاوتی خواهد داشت. مثلاً Toggle یا Set یا Reset یا Inverting یا Non-Inverting و… .
- با انتخاب کادرهای مناسب میتوانید وقفه سرریز و وقفه تطبیق مقایسه را فعال کنید.
- گزینه “Timer Value” به شما این امکان را میدهد که مقدار اولیه تایمر را انتخاب کنید. مقدار پیشفرض ۰ است.
- گزینه “Compare Value” به شما این امکان را میدهد که مقدار OCR را انتخاب کنید. این مقدار برای حالتهای CTC و PWM و همچنین وقفه تطبیق مقایسه لازم است. مقدار را برحسب اعداد هگزادسیمال وارد کنید.
اکنون، تنظیمات تایمر را به پایان رساندهاید و میتوانید تنظیمات باقیمانده تایمر را پیکربندی کرده و روی File -> Generate، Save and Exit کلیک کنید. پس از ذخیره فایلها، میتوانید در صورت فعال کردن موارد، تنظیمکنندههای وقفه خود را در پنجره کد پیکربندی کنید. به سادگی میتوانید این کارها را برای تولید PWM در کدویژن انجام دهید.