تایمرهای آردوینو
ماژول های تایمر در آردوینو عملکرد زمان بندی دقیقی را ارائه می دهند. آنها به ما اجازه می دهند وظایف مختلفی را انجام دهیم، مثلاً ایجاد تأخیرهای دقیق، ایجاد رویدادهای دوره ای، اندازه گیری فواصل زمانی و برآورده کردن نیازهای زمانی برنامه مورد نظر.
هر ماژول آردوینو با میکروکنترلر خاصش مجموعه ای از تایمرهای سخت افزاری خاص خود را دارد. بنابراین، برای استفاده از قابلیت های تایمرهای انواع ماژول آردوینو همیشه باید به دیتاشیت میکروکنترلر مربوطه ماژول مورد نظر مراجعه کنیم تا بیشتر با قابلیت های سخت افزاری آن و نحوه استفاده بهینه از آن آشنا شویم.
1. تایمرهای سخت افزاری آردوینو
Arduino UNO (Atemga328p) دارای 3 تایمر سخت افزاری است که عبارتند از:
تایمر 0: تایمر 8 بیتی
تایمر 1: تایمر 16 بیتی
تایمر 2: تایمر 8 بیتی
این ماژولهای تایمر برای تولید سیگنالهای خروجی PWM و ارائه قابلیتهای زمانبندی و تاخیر در آردوینو استفاده میشوند، و همچنین میتوانیم از آنها برای دستیابی به عملکرد زمانی مورد نظر استفاده کنیم.
هر تایمر سخت افزاری، یک رجیستر شمارنده دیجیتال در هسته خود دارد که بر اساس کلاک پالس ورودی شمارش می شود. اگر کلاک پالس از یک منبع داخلی با فرکانس ثابت تغذیه می شود، گفته می شود که در حالت تایمر کار می کند. اما اگر کلاک پالس به صورت خارجی از یک IO یا هر منبع ناهمگام تغذیه شود، گفته می شود که به عنوان شمارنده کار می کند که پالس های دریافتی را می شمارد.
2. مقایسه تایمرهای آردوینو
جدول زیر خلاصه ای از تایمرهای Arduino UNO (Atmega328p)، تفاوت بین آنها، قابلیت ها، حالت های عملکرد، وقفه ها و موارد استفاده آن را بیان می کند.
Timer0 | Timer1 | Timer2 | |
دقت | 8 Bits | 16 Bits | 8 Bits |
پایه های PWM | 5, 6 | 9, 10 | 11, 3 |
توابع | ()delay ()millis ()micros | Servo Functions | ()tone |
مد تایمر | ✓ | ✓ | ✓ |
مد شمارنده | ✓ | ✓ | ✓ |
ساخت PWM به کمک OCM (Output Compare Mode) | ✓ | ✓ | ✓ |
مد واحد تسخیر ورودی ICU (Input Capture Unit) | – | ✓ | – |
بردارهای اینتراپت | TIMER0_OVF_vect TIMER0_COMPA_vect TIMER0_COMPB_vect | TIMER1_OVF_vect TIMER2_COMPA_vect TIMER1_COMPB_vect TIMER1_CAPT_vect | TIMER2_OVF_vect TIMER2_COMPA_vect TIMER2_COMPB_vect |
ضرایب تقسیم فرکانس | 1:1, 1:8, 1:64, 1:256, 1:1024 | 1:1, 1:8, 1:64, 1:256, 1:1024 | 1:1, 1:8, 1:32, 1:64, 1:128, 1:256, 1:1024 |
نکته مهم:
دستکاری در پیکربندی تایمر می تواند باعث اختلال در کانال های خروجی PWM مرتبط با آن ماژول شود. به خصوص، تغییر تنظیمات تایمر 0 باعث اختلال در عملکردهای زمان بندی داخلی آردوینو (delay()، Microseconds() و millis()) می شود. بنابراین این را در نظر داشته باشید تا در صورتی که از ماژول تایمر سخت افزاری برای پروژه خود استفاده می کنید، تصمیمات طراحی بهتری بگیرید. تایمر 1 می تواند بهترین انتخاب باشد.
3. کنترل تایمر آردوینو
شما می توانید ماژول های تایمر آردوینو را به دو روش مختلف پیکربندی و برنامه ریزی کنید. اولین مورد، برنامه نویسی با استفاده از رجیسترهای کنترلی تایمر و اطلاعات ارائه شده در دیتاشیت است. در این قسمت راجع به این روش توضیحاتی را ارائه خواهیم کرد:
مقسم فرکانس تایمر آردوینو
مقسم فرکانس در ماژول تایمر سختافزاری یک مدار دیجیتالی است که برای تقسیم فرکانس کلاک پالس بر یک عدد قابل تنظیم برای کاهش نرخ ساعت تایمر استفاده میشود تا رسیدن به سرریز (حداکثر تعداد شمارش) بیشتر طول بکشد.
این واقعاً برای کنترل حداکثر بازه زمانی قابل تولید با استفاده از ماژول تایمر، فرکانس خروجی PWM یا محدوده زمانی قابل اندازه گیری با استفاده از ماژول تایمر مفید است.
اجرای ماژول تایمر با فرکانس سیستم برای وضوح خوب است، اما وقفه های سرریز تایمر زیادی ایجاد می کند که نیاز به دقت بیشتری در کد شما دارد. از این رو، استفاده از مقسم فرکانس می تواند برای جلوگیری از این وضعیت در وهله اول در صورت نیاز مفید باشد.
در حالت تایمر، ماژول تایمر کلاک داخلی سیستم را به عنوان منبع کلاک در نظر خواهد داشت و مانند شکل زیر از مقسم فرکانسی عبور می کند. شما می توانید به صورت برنامه ریزی شده نسبت تقسیم مقسم فرکانسی را کنترل کنید تا فرکانس کلاک ورودی تایمر را در صورت نیاز کنترل کنید.
مقادیر تقسیم کننده فرکانس تایمر از یک ماژول تایمر به ماژول دیگر متفاوت است و به وضوح در برگه داده برای هر ماژول تایمر (Timer0، 1 و 2) بیان شده است.
وقفه های تایمر آردوینو
تایمرهای آردوینو سیگنال های وقفه متفاوتی را برای رویدادهای مختلف ارائه می دهند. مانند سرریز تایمر، زمانی که یک تایمر به حداکثر مقدار شمارش خود می رسد (255 برای تایمرهای 8 بیتی و 65535 برای تایمرهای 16 بیتی). یک وقفه سرریز ایجاد می کند، به صفر می رسد و دوباره شروع به شمارش می کند.
همچنین دو رجیستر مقایسه خروجی در هر تایمر وجود دارد (COMPA و COMPB). هنگامی که مقدار شمارنده رجیستر تایمر به مقدار COMPA میرسد، پین OCnA را بسته به تنظیمات شما HIGH یا LOW میکند و همچنین یک وقفه COMPA (در صورت فعال بودن) ایجاد میکند. و همین امر در مورد COMPB نیز صدق می کند.
هر سیگنال وقفه تایمر را می توان به صورت جداگانه فعال یا غیرفعال کرد و آدرس برداری وقفه خاص خود را دارد.
مد زمان سنجی تایمر:
ماژول تایمر در حالت تایمر به گونه ای پیکربندی شده است که کلاک داخلی سیستم را به عنوان منبع کلاک با چندین گزینه مقسم فرکانس داشته باشد. معمولاً برای ایجاد وقفههای بازه زمانی ثابت برای درج تأخیرهای زمانی بین رویدادها یا اجرای رویدادهای دورهای در فواصل زمانی ثابت استفاده میشود.
در مد زمان سنجی تایمر، ماژول تایمر به شمارش ادامه می دهد (0 تا 255 یا 65535 بسته به وضوح). هنگام سرریز، یک وقفه سرریز تایمر فعال می شود و تایمر به صفر برمی گردد و دوباره شروع به شمارش می کند.
معادلات تایمر آردوینو
ماژول های تایمر در میکروکنترلرها یک معادله کلی دارند که به شرح زیر است:
فاصله زمانی خروجی مورد نظر (TOUT) برابر است با تعداد شمارش های تایمر ضرب در زمان دوره تناوب هر پالس. زمان دوره تناوب تایمر با فرکانس کلاک ورودی و نسبت ضریب مقسم فرکانس که انتخاب کرده اید تعیین می شود. بنابراین، معادله کلی تایمر را می توان به صورت زیر بیان کرد:
و این معادله ای است که ما برای طراحی برنامه های کاربردی مبتنی بر تایمر (مانند تأخیرهای بازه زمانی، اجرای دوره ای وظایف و موارد دیگر) استفاده خواهیم کرد. باید توجه داشته باشید که حداکثر TOUT با پیکربندی ضریب مقسم فرکانس تعریف می شود. تغییر این ضریب به ما این امکان را می دهد که حداکثر تولید بازه زمانی TOUT مجاز را با ماژول تایمر قبل از سرریز شدن آن افزایش دهیم.
به عنوان مثال، Timer1 در آردوینو UNO با فرکانس 16 مگاهرتز است. با ضریب 1:1، حداکثر TOUT را می توان با تنظیم TicksCount روی حداکثر مقدار آن 65536 به دست آورد.
اگر نیاز به ایجاد بازه زمانی TOUT بزرگتر با آن ماژول تایمر @ ساعت 16 مگاهرتز دارید، باید گزینه دیگری را برای ضریب مقسم انتخاب کنید. فرض کنید میخواهید یک وقفه تایمر 500 میلیثانیه ای را به عنوان یک پایه زمانی برای سیستم خود ایجاد کنید. این بدان معناست که TOUT(MAX) باید بیش از 500 میلی ثانیه باشد.
بنابراین، تنظیم نسبت prescaler روی 1:256 بهترین گزینه خواهد بود. زیرا حداکثر TOUT(MAX) = (256×65536)/16M = 1.049 ثانیه را مجاز میکند. که بیش از نیاز 500 میلیثانیه است، بنابراین با انتخاب این نسبت ضریب مقسم بزرگتر میتوان به آن دست یافت. حالا بیایید در مورد نحوه استفاده از معادله تایمر کلی صحبت کنیم و محاسبات لازم را انجام دهیم تا بتوانیم ماژول تایمر را به درستی پیکربندی کنیم.
محاسبات تایمر آردوینو
بهترین راه برای نشان دادن محاسبات ماژول تایمر این است که یک مثال کاربردی را در نظر بگیرید و مراحل محاسبه را مرحله به مرحله طی کنید. و این کاری است که ما در این بخش انجام خواهیم داد.
فرض کنید می خواهید هر 100 میلی ثانیه یک وقفه تایمر دوره ای ایجاد کنید و از آن به عنوان پایه زمانی برای سیستم خود استفاده کنید. ما از ماژول Timer1 استفاده خواهیم کرد که با فرکانس 16 مگاهرتز (در بردهای آردوینو UNO) کار می کند.
مرحله 1) یک ضریب تقسیم کننده مناسب انتخاب کنید. TOUT مورد نیاز 100 میلی ثانیه است. TOUT (MAX) باید > 100 میلیثانیه باشد. بنابراین، انتخاب پیش مقیاس 1:64 کافی خواهد بود. زیرا در پیش مقیاس 1:64، TOUT(MAX) = (64×65536)/16M = 262 میلیثانیه. که قطعاً بالاتر از فاصله زمانی 100 میلیثانیه است.
مرحله 2) با استفاده از معادله کلی تایمر، (مقدار TOUT، تقسیم کننده Prescaler و فرکانس CLK) را وصل کنید. سپس معادله مقدار TicksCount را حل کنید.
مرحله 3) تعداد تیک = 25000 تیک. و این خروجی محاسباتی است که پس از آن برای برنامهریزی ماژول تایمر برای ایجاد رویداد وقفه تایمر 100 میلیثانیه مورد نظر استفاده میکنیم.
برنامه نویسی تایمر آردوینو
پس از محاسبه تایمر مورد نیاز TicksCount برای رسیدن به بازه زمانی TOUT مورد نظر برای رویدادهای وقفه تایمر، میتوانیم به دو روش مختلف به برنامهنویسی ماژول تایمر آردوینو بپردازیم.
1- پیش بارگذاری تایمر
روش اول این است که رجیستر تایمر (TCNTx) را با مقداری از قبل بارگذاری کنید به گونه ای که تنها پس از تیک های TicksCount به سرریز (65535) برسد. برای مثال 100 میلیثانیه قبلی، TicksCount 25000 تیک بود. بنابراین، مقدار پیش بارگذاری تایمر = 65535-25000 = 40535 است.
با نوشتن 40535 در رجیستر TCNTx، تضمین می کنیم که 25000 تیک را برای رسیدن به حالت سرریز تیک می زنیم. در کنترل کننده ISR وقفه سرریز تایمر، ما همچنین باید رجیستر TCNTx را با همان مقدار بارگذاری کنیم و بارها و بارها تکرار کنیم.
در اینجا یک نمونه کد آردوینو برای پیش بارگذاری تایمر آورده شده است.
ISR(TIMER1_OVF_vect)
}
TCNT1 = 40535; // Timer Preloading
// Handle The 100ms Timer Interrupt
//...
{
()void setup
}
TCCR1A = 0; // Init Timer1
TCCR1B = 0; // Init Timer1
TCCR1B |= B00000011; // Prescalar = 64
TCNT1 = 40535; // Timer Preloading
TIMSK1 |= B00000001; // Enable Timer Overflow Interrupt
{
()void loop
}
// Do Nothing
{
روش رجیسترهای مقایسه ای تایمر
یک راه ساده تر برای دستیابی به همان هدف بدون ایجاد اختلال در مقدار رجیستر TCNTx تایمر، استفاده از رویدادهای وقفه تطبیق خروجی است. این احتمالاً بهترین راه برای اجرای رویدادهای وقفه مبتنی بر تایمر است. زیرا دو رجیستر (COMPA و COMPB) برای تولید دو رویداد وقفه زمانی مستقل با استفاده از یک ماژول تایمر به شما می دهد.
با توجه به مثال قبلی وقفه با فاصله زمانی 100 میلیثانیه، برای دریافت وقفه دورهای 100 میلیثانیه به تایمر نیاز داریم که 25000 تیک بزند. بنابراین، از COMPA compare register استفاده میکنیم، وقفه آن را فعال میکنیم و مقدار آن را 25000 میکنیم. هنگامی که یک تطابق مقایسه رخ میدهد (زمانی که TCNT1 = OCR1A)، یک وقفه ایجاد میشود. و این وقفه دوره ای 100 میلی ثانیه ای است که ما می خواهیم.
برای اینکه آن را با همان سرعت 100 میلیثانیه در حال اجرا نگه داریم، باید مقدار COMPA را بهروزرسانی کنیم زیرا تعداد تایمر اکنون به 25000 رسیده است. بنابراین، باید 25000 تیک به مقدار COMPA اضافه کنیم. نگران سرریز نباشید، در 65535، رجیستر دقیقاً مانند رجیستر TCNTx تایمر به صفر برمیگردد. بنابراین همیشه بی عیب و نقص کار می کند.
در اینجا یک نمونه کد آردوینو برای وقفه تطبیق مقایسه تایمر آورده شده است.
define led 3
ISR(TIMER1_COMPA_vect)
}
OCR1A += 25000; // Advance The COMPA Register
digitalWrite(led,!digitalRead(led));
// Handle The 100ms Timer Interrupt
//...
{
()void setup
}
;()cli
TCCR1A = 0; // Init Timer1
TCCR1B = 0; // Init Timer1
TCCR1B |= B00000011; // Prescalar = 64
OCR1A = 25000; // Timer CompareA Register
TIMSK1 |= B00000010; // Enable Timer COMPA Interrupt
;()sei
{
()void loop
}
// Do Nothing
{
#define led 3
تایمر در مد شمارش:
مثال زیر را در نظر بگیرید:
()void setup
}
TCCR1A = 0; // Init Timer1A
TCCR1B = 0; // Init Timer1B
TCCR1B |= B00000111; // External Clock on T1 Pin (RISING)
; TCNT1 = 0
Serial.begin(9600)
{
()void loop
}
; Serial.print("Counter Ticks = ")
;Serial.println(TCNT1)
;delay(250)
{
توجه داشته باشید که مد شمارش از جدول زیر تعیین می شود:
روش دیگر برای کنترل ماژول های تایمر استفاده از کتابخانه های تایمر مانند کتابخانه Arduino-timer است. در مقاله بعدی به این موضوع خواهیم پرداخت، و در مورد نحوه نصب و استفاده از کتابخانه arduino-timer بحث خواهیم کرد. استفاده از آن می تواند بسیار ساده تر از آنچه قبلاً در آموزش وقفه های تایمر آردوینو انجام دادیم باشد.
دیدگاه خود را بنویسید