الکترونیک، رباتیک و مکانیک

آموزش به زبان بسیار ساده و روان (از صفر تا بینهایت)

الکترونیک، رباتیک و مکانیک

آموزش به زبان بسیار ساده و روان (از صفر تا بینهایت)

الکترونیک، رباتیک و مکانیک

با سلام و عرض ادب خدمت هموطنان عزیز
در این سایت قصد داریم موضوعاتی که در حیطه الکترونیک ،مکانیک و برنامه نویسی ربات ها دارای جذابیت خاصی می باشد رو آموزش بدیم. امیدواریم که با نظرات شما عزیزان شاهد آموزشهای جامعی در این زمینه باشیم.
با تشکر

نویسندگان
پیوندهای روزانه
طبقه بندی موضوعی
آخرین نظرات

دوشنبه, ۱۴ دی ۱۳۹۴، ۱۰:۵۱ ق.ظ

۰

 

در ششمین قسمت از کارگاه عملی « مد CTC تایمر/کانتر یک میکروکنترلرهای AVR » را بررسی میکنیم.

 

پس با ما در ادامه مطلب همراه باشید...

 

به نام خدا

سلام

بالاخره تصمیم گرفتم که برگردم و دوباره بنویسم.

اما با انگیزه ای کمتر از گذشته ...

خلاصه قول نمیدم که با توجه به مشغله های تحصیلی بتونم مثل گذشته زیاد پست بذارم ولی حواسم به وبلاگ هست و وقت کنم پست میزارم.

بگذریم ...

طبق معمول ابتدا یه مسئله تعریف میکنیم :

تعریف مسئله :

میخوایم یه فلاشر LED بسازیم که هر 100 میلی ثانیه چشمک بزنه.

از تایمر/کانتر یک و CTC استفاده کنید.

 

با ذکر این نکته که از کریستال 16 مگاهرتزی خارجی استفاده میکنیم.

 

حل مسئله :

اول از همه اینکه میدونیم تایمر یک نهایتا تا 65535 میتونه بشماره.

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

 

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

پس دیگه اون فلگایی که قبلا توضیح دادمو توضیح نمیدم !

بسم الله ...

 

#include <mega32.h>

 

فایل سرآِیند (هدر فایل) مربوط به ATmega32 رو لود میکنیم.

 

 

#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); //Mode = CTC , Prescaler = 64

TCNT1 = 0; //initialize timer/counter 1

OCR1A = 24999; //initialize compare value
} 

 

کلیه تنظیمات تایمر/کانتر یک به همراه توضیحات مربوطه داخل تابع نوشته شده.

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

 

 

تا اینجای کار تایمر/کانتر در مود 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 یک شد،با Toggle شدن پین 0 از پورت C میکرو ، LED چشمک بزنه.

رجیستر TIFR هم که اینجوری بود :

 

 

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

و از یک شدن این فلگ متوجه میشیم که سرریز رخ داده و عمل تطبیق یا مچ شدن روی داده !

 

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

اگه یادتون باشه هم گفتیم که با نوشتن یه یک دیگه روی اون صفر میشه که ما هم دستور مربوطه رو نوشتیم براش !

 

خب این از روش اول !

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

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

 

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

یه بار دیگه تابع 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 بوده و هست ! cheeky

یه اسم هم گذاشتیم برای تابع وقفه ؛ compare_interrupt که ورودی هم نداره (void) .

داخل زیرروال وقفه هم دستور Toggle شدن PORTC.0 میکرو رو نوشتیم.

 

 

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

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

timer1_configuration ();

while(1){}
}  

 

ابتدا پایه 0 از پورت C رو بعنوان خروجی تعریف میکنیم.

در خط بعدی تابع timer1_configuration رو فراخوانی میکنیم تا تایمر/کانتر یک تنظیم بشه.

و در انتها یه حلقه بینهایت تعریف کردیم که داخلش هم هیچی ننوشتیم چون اصلا نیازی نبوووود ! (حال میکنم توش هیچی ننویسم،مشکلیه ؟! laugh)

حالا میدونم خیلی ها متوجه نشدند که چرا داخلش هیچی ننوشتیم اما مشکل خودشونه !

باشه میگم ... (نزنیدمون !  خخخخ...)

آقا جون برای چی آخه باید داخل حلقه بینهایت چیزی بنویسم ؟! چــــــــــــــــــــــــرا ؟؟؟؟؟؟؟؟

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

میکرو گیر میوفته داخل حلقه و تنها هنگام وقوع وقفه است که یه سر میره توی زیرروال وقفه و بعد دوباره برمیگرده به همون حلقه !

 

میرسیم به قسمت قشنگ بحث امروز :


آشنایی با سخت افزار CTC :

 

به شکل زیر نگاه کنید :

 

ایندفعه حواستون بیشتر به پرانتزهای موجود باشه ! cool

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

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

 

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

 

بررسی رجیستر TCCR1A :

 

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

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

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

جدول زیر را که برای مد CTC است،ببینید :

 

 

در اینجا چون خاموش/روشن کردن 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) {

}

}

 

والسلام ...

همه ی کدهامون همین شد !

خداییش کدوم سبک نوشتن جالب تر بود ؟! surprise indecision frown

 

اومدیم و مقدار COM1A0 رو برابر یک گذاشتیم و در نتیجه اون حالت Toggle رو برای پایه‌ی OC1A فعال کردیم و بقیه برنامه هم که مثل قبله !!!

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

 

خب برای تایمر/کانتر های هشت بیتی صفر و دو وضعیت به همین ترتیبه،ولی رجیسترهاشون با تایمر/کانتر یک فرق دارند که برای مشاهده تفاوت ها پیشنهاد میشه که به دیتاشیت میکرو مراجعت کنید.

 

این هم از این قسمت از آموزش.

انشاالله در قسمت بعدی سعی میکنم یه کم راجع به LCD براتون توضیح بدم که خیلی مورد احتیاجمونه.

 

پس فعلا ...


منبع : www.noise.blog.ir

نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی