آموزش AVRآموزش ها

برنامه نویسی تایمر / کانتر یک در مود CTC (آموزش AVR #18)

سلام. آموزش کامل برنامه نویسی تایمر / کانتر یک در مود CTC (آموزش AVR #18) را آماده کردیم.

آموزش کار با مود CTC در تایمر کانتر 1

در این قسمت از سری آموزش های AVR ، به طور کامل با نحوه کار با مود CTC و برنامه نویسی آن در Timer / Counter 1 آشنا میشویم. در قسمت قبلی ، ما با مد های مختلف تایمر / کانتر در میکروکنترلر های AVR آشنا شدیم. حتما قبل از خواندن این قسمت از آموزش ، قسمت قبل را بخوانید.

قسمت قبل : آموزش مود های مختلف تایمر / کانتر در میکروکنترلر های AVR (آموزش AVR #17)

این آموزش را نیز با تعریف یک مسئله شروع میکنیم.

مثال اول برای فهمیدن مد CTC در تایمر کانتر یک

به طور مثال ما میخواهیم یک فلاشر ال ای دی بسازیم که هر 100 میلی ثانیه چشمک بزند. ما از Timer / Counter 1 و مد CTC استفاده میکنیم. میدانیم که تایمر کانتر یک نهایتا میتواند تا 65535 میتونه بشمارد. با انتخاب ضریب تقسیم 64 ، فرکانس تایمر/کانتر به 250 کیلوهرتز کاهش پیدا میکند و برای ایجاد تاخیر 100 میلی ثانیه ای ، مقدار TimerCount برابر 24999 میشود.

چند تا رجیستر هم داریم که قبلا با اکثرشان آشنا شدید و اینجا با فلگ های جدیدتری از آن ها آشنا میشویم.

ابتدا مثل همیشه کتابخانه میکروکنترلر Atmega 32 را فراخوانی میکنیم.

#include <mega32.h>
void timer1_configuration (void){}

تابعی با نام timer1_configuration تعریف میکنیم و تنظیمات مربوط به پیکربندی تایمر/کانتر یک را در آن انجام میدهیم.

#include <mega32.h>
void timer1_configuration (void){
TCCR1A = 0x00; //WGM10 = 0 , WGM11 = 0
TCCR1B = (1 << WGM12)|(1 << CS11)|(1 << CS10); 
TCNT1 = 0; 
OCR1A = 24999; 
} 

مقدار ضریب تقسیم 64 در نظر گرفته شده و مقادیر فلگ های CS10 و CS11 از رجیستر TCCR1B جهت استفاده در مد CTC و با توجه به جدول زیر یک شده اند.

برنامه نویسی تایمر / کانتر یک در مود CTC (آموزش AVR #18)

اگر میخواهید آردوینو را به صورت اصولی و پروژه محور (برنامه نویسی حرفه ای، ارتباط آردوینو با اندروید، ساخت ربات با آردوینو) یاد بگیرید، روی دوره آموزش آردوینو کلیک کنید.

تا اینجای کار تایمر/کانتر در مود CTC برنامه ریزی شد. مقدار رجیستر OCR1A هم با توجه به محاسبات انجام شده در ابتدای پست 24999 تعیین شد.

تابع اصلی یعنی تابع main :

void main(){

DDRC |=(1 << 0);

timer1_configuration();

while(1){

  if (TIFR & (1 << OCF1A)){
    PORTC ^=(1 << 0);
  }

TIFR |=(1 << OCF1A);

}
} 

پین 0 از پورت C بعنوان خروجی در نظر گرفته میشود و به LED مربوطه وصل میشود. در خط بعدی تابع timer1_configuration فراخوانی میشود که حاوی تنظیمات تایمر/کانتر شماره یک است. پس از آن یه حلقه بی نهایت داریم که در آن یک شرط مینویسیم.

یک شرط گذاشتیم که هر وقت فلگ OCF1A از رجیستر TIFR یک شود، پین 0 از پورت C فعال / غیرفعال شود.

فلگ OCF1A وظیفه اش این بود که هروقت مقدار تایمر/کانتر یک، با مقدار مشخص شده در رجیستر OCR1A برابر شد یک شود. و از یک شدن این فلگ متوجه میشیم که سرریز رخ داده و عمل برابر شدن اتفاق افتاده است.

همچنین اگر در مورد این مطلب سوالی داشتید در انتهای صفحه در قسمت نظرات بپرسید

پس از اینکه فلگ OCF1A یک شد،باید بصورت دستی آن را 0 کنیم.

مثال برای فهمیدن مود CTC در تایمر کانتر 1

مثال دوم برای فهمیدن مود CTC در تایمر کانتر 1

میتوانیم همین برنامه را حرفه ای بنویسیم در آن از اینتراپت (وقفه) استفاده کنیم.

اول از همه شروع میکنیم به پیکربندی تایمر/کانتر یک با استفاده از ویژگی وقفه !

بار دیگر تابع timer1_configuration را بازنویسی میکنیم و تغییرات مورد نیاز را اعمال میکنیم.

void timer1_configuration (void){

TCCR1A = 0x00; //WGM10 = 0 , WGM11 = 0
TCCR1B = (1 << WGM12)|(1 << CS11)|(1 << CS10); //Mode = CTC , Prescaler = 64

TCNT1 = 0; //initialize timer/counter 1

OCR1A = 24999; //initialize compare value

TIMSK |=(1<<OCIE1A); //Enable Compare Interrupt

#asm("sei") //Enable Global Interrupt
} 

فلگ OCIE1A از رجیستر TIMSK را یک میکنیم تا وقفه مقایسه ای تایمر/کانتر یک فعال بشود. در انتها هم فلگ I از رجیستر SREG را فعال میکنیم.

حالا نوبت به نوشتن زیرروال وقفه میرسد :

interrupt [8] void compare_interrupt (void){
PORTC ^=(1 << 0);
}  

تابع اینتراپت را نوشتیم با Vector Number معادل 8 که همان بردار Timer/Counter1 Compare Match A است. یک اسم هم گذاشتیم برای تابع وقفه ؛ compare_interrupt که ورودی هم نداره (void). در زیرروال وقفه هم دستور Toggle شدن PORTC.0 میکروکنترلر را نوشتیم.

نوبت میرسه به تابع main :

void main (void){
DDRC |= (1<<0);

timer1_configuration ();

while(1){}
}

ابتدا پایه 0 از پورت C را بعنوان خروجی تعریف میکنیم. در خط بعدی تابع timer1_configuration را فراخوانی میکنیم تا تایمر/کانتر یک تنظیم بشود. و در انتها یه حلقه بینهایت تعریف کردیم که داخلش هم هیچی ننوشتیم چون نیازی نیست.

تمام کاری که میخوایم انجام بدیم داخل زیرروال وقفه انجام میشود. بنابراین تنها دلیل ما برای نوشتن این حلقه بینهایت اینه که برنامه تمام نشود و از داخل تابع main بیرون نیاید و برنامه به کار خودش ادامه بدهد.

آموزش کامل سخت افزار CTC

به تصویر زیر که دیتاشیت میکروکنترلر ات مگا 32 است دقت کنید.

آموزش کامل سخت افزار CTC

4 تا از پایه ها یعنی PB3 , PD4 , PD5 , PD7 داخل پرانتزهاشون به ترتیب نوشته شده است : OC0 , OC1B , OC1A , OC2

این پایه ها به پایه های مقایسه گر خروجی یا Output Compare Pins معروف هستند که به تایمر/کانتر 0 ، 1 و 2 مربوط میشوند.

رجیستری داشتیم به نام TCCR1A که قبلا معرفیش کردیم :

رجیستر TCCR1A : Timer/Counter1 Control Register A – TCCR1A

رجیستر TCCR1A : Timer/Counter1 Control Register A - TCCR1A

بیت های 6 و 7 ؛ COM1A1 و COM1A0 :

این بیت ها وظیفه کنترل پایه های OC را بر عهده دارند.

بطور کلی این بیتها برای مود های کاری مختلف، بصورت جداگانه بحث میشوند که در اینجا مد CTC مدنظر ماست. جدول زیر را ببینید :

آموزش کار با مود CTC در تایمر کانتر 1

در اینجا چون خاموش/روشن کردن LED مدنظر ماست از ردیف دوم جدول بالا یعنی حالت 01 استفاده میکنیم. البته دقت داشته باشید که ما اینجا از تایمر/کانتر یک داریم استفاده میکنیم و به همین دلیل هم رفتیم سراغ رجیستر TCCR1A. و اگر میخواستیم از تایمر/کانتر صفر یا دو استفاده کنیم قطعا باید به رجیستر های مربوط به خودشون مراجعه میکردیم.

کد کامل : 

#include <mega32.h>

void timer1_configuration (void){

TCCR1A = (1<<COM1A0); //WGM10 = 0 , WGM11 = 0 , Set OC1A In CTC Toggle Mode
TCCR1B = (1 << WGM12)|(1 << CS11)|(1 << CS10); //Mode = CTC , Prescaler = 64

TCNT1 = 0; //initialize timer/counter 1

OCR1A = 24999; //initialize compare value
}

void main (void) {

DDRC |=(1<<0);
timer1_configuration ();

while(1) {

}

}

مقدار COM1A0 را 1 کردیم و در نتیجه حالت روشن / خاموش شدن را برای پایه‌ی OC1A فعال کردیم.

یعنی هربار که تایمر/کانتر 1 سرریز شود، با توجه به تنظیماتی که ما برایش انجام دادیم، مقدار پایه‌ی PD5 شروع به روشن و خاموش شدن میکند.

این قسمت آموزش AVR هم تمام شد. در قسمت بعدی به طور کامل با برنامه نویسی ال سی دی کاراکتری در میروکنترلر AVR در محیط کدویژن آشنا میشویم.

قسمت بعد : توابع برنامه نویسی ال سی دی کاراکتری در کدویژن (آموزش AVR #19)

نظرتان را در مورد این مطلب با ستاره دادن اعلام کنید
امیدوارم این مطلب برای شما مفید بوده باشد. نظرات ، مشکلات و پیشنهادات خود را در پایین صفحه اعلام کنید
محمد رحیمی

محمد رحیمی

محمد رحیمی هستم. سعی میکنم در آیرنکس مطالب مفید را قرار دهم. مالکیتی بر مطالب ارائه شده ندارم. اکثر فعالیت بنده در زمینه ترجمه است. (در خصوص سوال در مورد این مطلب از قسمت نظرات همین مطلب اقدام کنید)

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *