.:: نویز | آموزش AVR | میکروکنترلر | الکترونیک ::.

وبلاگ آموزشی احسان نوری ::: Ehsan Nouri's Weblog

.:: نویز | آموزش AVR | میکروکنترلر | الکترونیک ::.

وبلاگ آموزشی احسان نوری ::: Ehsan Nouri's Weblog

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

دریافت مستندات
آخرین نظرات
  • ۱۵ آبان ۹۵، ۱۸:۵۸ - الهام
    ممنون

کارگاه عملی - شماره 4 : کار با تایمر/کانتر یک [21]

چهارشنبه, ۶ فروردين ۱۳۹۳، ۱۱:۳۰ ق.ظ

 

چهارمین قسمت کارگاه عملی با تشریح برنامه نویسی تایمر/کانتر یک آماده شده است.

 

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

 

 

 

 به نام خدا

سلام

روزهای بهاریتون خوب و خوش...

 

در پست قبلی (بررسی تایمر/کانتر یک (1) در میکروکنترلرهای AVR ؟ [20]) تایمر/کانتر شماره یک که 16 بیتی هست رو بررسی کردیم و حرفایی که باید میزدیم رو هم زدیم.

 

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

ایندفعه میخوایم از وقفه هم که تا حالا تو کدنویسی هامون ازش استفاده نکردیم،استفاده کنیم.

پس به گوش و به هوش باشید ... wink

 

کد نویسی به زبان سی در محیط کامپایلر کدویژن :

 

فرکانس کاری میکروکنترلر 16 مگاهرتز خارجی تعریف شده.

 

 #include <mega32.h>

در ابتدای کار،طبق معمول فایل سرآیند مربوط به میکروکنترلر مورد نظرمون که اینجا ATmega32 هست رو اضافه میکنیم.

 

#include <mega32.h>

void timer1_configuration (){}

تابعی تعریف کردیم با نام : timer1_configuration ، که تنظیمات اولیه و پیکربندی تایمر/کانتر یک رو در اون انجام میدیم.

 

#include <mega32.h>

void timer1_configuration (){

TCCR1B |=(1<<CS11); // Prescaler=8
TIMSK |=(1<<TOIE1); // Enable Timer1 Overflow

TCNT1=0; // Initialize Timer/Counter1

#asm ("sei"); // Enable Global Interrupts

}

تموم اون حرفایی که قبلا زدیم رو داریم میاریم رو کامپایلر !

توضیحات رو بصورت کامنت روبروی هر عبارت براتون نوشتم.فکر نکنم مسئله خاصی باشه.

 

بریم سراغ تابع main :

void main(){

DDRB.0 = 1; // Config B.0 As Output Pin
timer1_configuration (); // Load Timer1 Configuration
while(1){} // Loop Forever

}

پین B.0 همون پایه ای هست که میخوایم بهش LED رو وصل کنیم.پس خروجی تعریف میشه !

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

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

 

خب ...

توصیه میکنم که خوندن آموزش رو از همینجا متوقف کنید و برگردید یه نگاه بکنید ببینید اصلا چیکار کردیم و چیکار میخوایم بکنیم ! Cool

 

اگه آماده اید،ادامه میدیم ...

 

یه متغیری تعریف میکنیم از جنس int ، با نام مثلا : overflow

وظیفه این متغیر،شمارش تعداد سرریز های رخ داده است !

یادتونه گفتم طبق فرضیات باید 61 بار سرریز رخ بده تا 2 ثانیه طی بشه ؟!

پس این متغیر میخواد ببینه که، کِی تعداد سرریز ها 61 عدد میشه ؟

 

 #include <mega32.h>

int overflow=0;

این هم از تعریف متغیر از نوع integer با نام overflow و همچنین مقدار اولیه 0.

 

بریم سراغ اصل کار؛

تعریف زیرروال مربوط به وقفه :

 

 در مورد وقفه قبلا جداگانه بحث کردیم :

معرفی وقفه در میکروکنترلرهای AVR ؟ [15]

 

اما درباره برنامه نویسیش نه !

فکر کنم که دیگه الان وقتش باشه.

 

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

interrupt [Vector Number] void int_expression (void) {

برنامه سرویس وقفه

}

به جای عبارت int_expression ، یه نام دلخواه برای تابع وقفه انتخاب میکنیم.

به جای [Vector Number]،عدد وکتور مورد نظر رو از روی دیتاشیت انتخاب میکنیم.

در مورد Vector Number هم از روی دیتاشیت نگاه میکنیم و عدد مورد نظر رو انتخاب میکنیم و از اون استفاده میکنیم !

 

نکته : در داخل براکت،به جای عدد،میتوان از عبارت متناظر در ستون Source جدول بالا نیز استفاده کرد.

 

interrupt [10] void timer1_int (){}

 اینجا هم اومدیم و برای Vector Number عدد 10 رو انتخاب کردیم که مربوط به وقفه Timer/Counter1 Overflow میشه.

اسمش رو هم گذاشتیم : timer1_int

 

interrupt [10] void timer1_int (){

overflow++; // Increase The Number Of Overflow 

// Check If 2 Sec Passed

if(overflow>=61){ 

PORTB^=(1<<0); // Toggle B.0
overflow=0; // Reset The number Of Overflow

}
}

با هر بار سر ریز شدن،یک واحد به متغیر overflow اضافه میشه.

هنگامیکه تعداد سرریزها 61 (یا احیانا بیشتر از 61) بشه،پین B.0 شروع به Toggle شدن میکنه !

یعنی اگه خاموشه،روشن میشه و اگه روشنه خاموش.

در انتها مقدار متغیر overflow رو مجددا صفر میکنیم تا تایمر/کانتر یک،مجددا اقدام به محاسبه زمان مورد نظر ما کنه.

 

و در انتها کل کد :

 

#include <mega32.h>

int overflow=0;

void timer1_configuration (){

TCCR1B |=(1<<CS11); // Prescaler=8
TIMSK |=(1<<TOIE1); // Enable Timer1 Overflow

TCNT1=0; // Initialize Timer/Counter1

#asm ("sei"); // Enable Global Interrupts

}

interrupt [10] void timer1_int (){

overflow++; // Increase The Number Of Overflow 

// Check If 2 Sec Passed

if(overflow>=61){ 

PORTB^=(1<<0); // Toggle B.0
overflow=0; // Reset The number Of Overflow

}
}

void main(){
DDRB.0 = 1; // Config B.0 As Output Pin 
timer1_configuration (); // Load Timer1 Configuration 
while(1){} // Loop Forever
}

 

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

 

هدف این بود که تاخیری به میزان 2 ثانیه بسازیم.

با محاسباتی که انجام دادیم به این نتیجه رسیدیم که باید حدودا 61 بار سرریز در تایمر/کانتر یک رخ بده تا مدت زمان 2 ثانیه بدست بیاد.

با ایجاد یک تابع با نام timer1_configuration ، پیکربندی تایمر/کانتر یک رو انجام دادیم.

در تابع اصلی main هم،پین B.0 رو خروجی تعریف کردیم و تابع timer1_configuration رو فراخوانی کردیم.

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

منتظر میمونیم تا 2 ثانیه طی بشه !

حالا کِی 2 ثانیه طی میشه ؟! هر وقت تعداد سرریزها 61 تا شد !

پس تایمر/کانتر تا سرریز کرد،چون براش وقفه سرریز رو فعال کردیم،سریع میپره به برنامه زیرروال خودش (timer1_int).

برنامه زیرروال رو انجام میده و پس از اینکه انجام داد،مجددا برمیگرده به محل قبلی(حلقه بینهایت).

دائما طی سیکلهای زمانی مشخص،سرریز انجام میپذیره و برنامه زیرروال مربوطه انجام میشه.

حالا ببینیم زیرروال چی میگه ؟! Undecided

به تایمر/کانتر میگه آقا هروقت سرریز کردی،یه دونه به مقدار متغیر overflow که خودمون تعریفش کردیم و مقدار اولیش رو صفر تعیین کردیم،اضافه کن.

همونطور که گفتم؛دائما سرریز تایمر/کانتر یک انجام میشه و یکی یکی به مقدار متغیر overflow اضافه میشه.

میایم یه شرط هم تعریف میکنیم داخل زیر روال؛هر وقت تعداد این سرریزها 61 یا بیشتر شد(2 ثانیه گذشت !!!)؛پین B.0 رو Toggle کن.

 

 

بعععععله ...

این هم تا اینجای آموزش !

منتظر قسمت های بعدی آموزش باشید...

نظر هم فراموش نشه !

 

بای بای LaughingKiss

سلام

ممنون اقا احسان زحمت میکشی بی ادعا.

منتظر قسمت های بعد هستم

پاسخ:
خواهش میکنم.

سلام

این اعداد وکتور همین بیست و یکیه ؟

یا نه هست اعداد دیگه ای؟

من خیلی خوشم اومد از این تعریف ساده و استفاده ی وقفه ها

اگه نکات دیگه ای هم توی استفاده  از وقفه ها هست بی زحمت مارو بی نصیب نذار

تشکر

پاسخ:
برای Atmega32 همین هاست.
وقفه که نکته زیاد داره،اما اگه علاقمند هستید میتونید از روی دیتاشیت مطالب رو دنبال کنید.
موفق باشید.
سلام
نمیشه این آموزش ها رو فعلا اینتراپت کنین! و شبیه سازی همینا با پروتئوس رو یاد بدید؟ آخه اینجوری نمیشه مدار رو عملی ساخت خیلی وقتا و همینطوری آموزش ها برای من خشک و تئوری شدن! اگه صلاح میدونید یه کاری بکنید که حدقل مجازی نتیجه کارمون رو ببینیم و اگه کسی خواست ایده های برنامه نویسی دیگه رو امتحان کنه به مشکل نخوره
ممنون
پاسخ:
سلام
ما هنوز چیز خاصی نگفتیم که بخوایم شبیه سازی انجام بدیم !
تنها مداری که ما ازش صحبت کردیم مدار چشمک زن بوده + مدار LM35 که شماتیک هر دو در وبلاگ هست !
مدار چشمک زن سخت افزار خاصی نداره ! (مگا32+LED+مقاومت) !!!

نکته بعدی و مهمتر اینکه وبلاگ ما پروژه محور نیست ! (حداقل فعلا ...)

موفق باشید.
سلام دست شما درد نکنه امیدوارم موفق باشید
یه پیشنهاد: در هر موضوعی اگه یه پروژه هم بذارین و روی اون توضیحات بدین بد نیست حالا فقط یه پیشنهاد بود
با سلام
منظورم از تابع وقفه مثلا تو همین مثالی که زدین هستش
interrupt [10] void timer1_int
این وقفه بعد از تابع اصلی  void main چجوری فرا خوند میشه(بعد از چه دستوری) چون دستور زبان c که نگاه کردم دیدم اسم خود تابع باید بعد از تابع اصلی بیاد.ممنون میشم راهنماییم کنید
باتشکر.

پاسخ:
سلام

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

وقفه یه اتفاقی هست که میوفته و معمولا هم از زمان رخدادش خبر نداریم ...
این تابع،با اون تابعی که مد نظر شماست فرق داره.

وقفه ها یا منبع داخلی دارند و یا خارجی !!!

پیشنهاد میکنم که یکبار دیگه مطالب رو بخونید...

موفق باشید.
سلام
اگه درست جوابتون رو متوجه شده باشم منظورتون اینکه مثلا با فعال کردن رجیستر وقفه سرریز و وقفه کلی شرایط رو برای تابع وقفه فراهم میکنیم که هر وقت سریز رخ داد تابع وقفه هم اجرا بشه اگه این درست باشه میتونیم بگیم که زمان رخدادش رومیدونیم واون موقعیه که شمارش انجام بشه تا سرریز رخ داد تابع وقفه اجرا بشه؟ ازاینکه سریع و باحوصله به سوالات جواب میدید ممنونم
پاسخ:
ببینید؛
اینکه برداشت شما از وقفه چی بوده رو من دقیقا نمیدونم.
اما هر وقت متوجه شدید که چرا نیاز داریم از وقفه استفاده کنیم و اگه از وقفه استفاده نکنیم چی میشه،اون موقع اینجور سوالاتتون به پاسخ میرسه !
استفاده از وقفه تنها در تایمر/کانتر ها محدود نمیشه و بحث مفصلی داره که بنده به ناچار مجبور شدم خلاصشو پست بزنم.
مسائلی مثل : اولویت وقفه ها،وقفه های تو در تو و ... نیاز به جوی مناسبتر نسبت به الان داره !
گرچه که نمیشه از میزان اهمیتشون صرفنظر کرد !!!
با کمال تشکر
ممنون از پاسختون

پاسخ:
موفق باشید.

با سلام

با تشکر از سایت عالیتون 

مطالب  شما در مورد تایمر  واقعاً عالیه ، البته من فعلاً  فقط این مطلب رو خوندم  و مطمئاً هستم وقتی تایمر که

مبحث سختی  هست رو به این خوبی توضیح دادید ، حتماً مطالب دیگر با توضیحات شما فراگیری راحتری داره.

اگر ممکن هستش در  مورد  تفاوت بیت TICE1 در رجیستر TIMSK با بیت ICF1 در رچیستر TIFR در تایمر و کانتر

یک  در مٌد  capture توضیح مختصری بدهید ممنون می شوم  چون در کتاب آقای الوندی من هر چه مطالعه می کنم به طور واضح تفاوت این دو بیت رو متوجه نمیشم.

با تشکر

 

 

پاسخ:
سلام
ممنون از نظرتون

به ساده ترین شکل اگه بخوام براتون توضیح بدم :

رجیستر TIFR :
هر فلگش مشخص میکنه که آیا سرریز تایمر مربوطه اتفاق افتاده یا نه ؟!

رجیستر TIMSK :
هر فلگش مشخص میکنه که آیا اجازه هست وقفه مربوطه اجرا بشه یا نه ؟!
با این رجیستر وقفه های موردنظرمون رو فعال میکنیم !

اما مود Capture :
مشخصا در ATmega32 پایه ای داریم تحت عنوان : ICP
اگر این پایه به عنوان ورودی معرفی بشه،هنگامی که سیگنالی در لبه بالارونده یا پایین رونده به این پایه وارد بشه،محتوای رجیستر TCNTx در رجیستر کپچر ICRx ذخیره میشه.
به قول یکی از اساتید،همانند اینه که یه عکاس یه واقعه ای رو در یه لحظه با فشار دادن دکمه شاتر دوربین ثبت کنه.
در واقع هنگامی که پالس وارد پایه مورد نظر میشه،زمان سنجیده شده توسط تایمر/کانتر ازش یه کپی گرفته میشه و داخل رجیستر ICRx ذخیره میشه !
که این مود هم استفاده های خاص خودشو داره !

حالا با این اوضاع،بیت ICF1 وقتی یک بشه،اینو میرسونه که یه پالس به پایه تسخیر (Capture) وارد شده.
و بیت TICIE1 هم اگه یک تعریف شده باشه و وقفه سراسری (SREG) هم فعال باشه و بیت ICF1 از رجیستر TIFR هم فعال باشه،وقفه رو فعال میکنه و زیرروال وقفه رو اجرا میکنه !

این ساز و کار برای سایر تایمر/کانتر ها هم صادقه !

موفق باشید.
با سلام وغرض خسته نباشید
سوالی داشتم در مورد برنامه بالا. میخواستم بدونم در این برنامه دستور while دقیقا چکار میکند و این که وقفه چه موقع فراخوانده میشود
با تشکر از مطالب مفیدتان
پاسخ:
سلام

به نظر میرسه که شما پست های وبلاگ رو کامل نخوندید.
پیشنهاد میکنم که بخشهای مربوط به معرفی وقفه رو با تامل مطالعه کنید.
اگر باز هم مشکلی بود،در خدمتتون هستم !

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

تلاش خودتونو بکنید...
خیلی ممنون از راهنمایی های شما واقعا شما این مباحث را خیلی خوب و قابل درک بیان میکنید
باز هم از شما متشکرم
سلام من مقدار دهی رجستر OCR رونمیدونم که مثلا میشه OCR0=0XC7 چرا شده C ,7 چرا این عدد شده چرا نشده مثلا =0X08 میدونم هشت بیتی مقدار میدونم ولی نمیدنم چر این عدد شده.لطفا توضیح دهید.
پاسخ:
سلام
عبارت 0x به معنای هگزادسیمال بودن عدد هست و دو رقم بعدی معادل هگزا دسیمال مقدار رجیستر مورد نظر.
اگر میخواستیم بصورت باینری به این رجیستر مقدار بدیم از عبارت 0b استفاده میکردیم.

در مطالب ابتدایی وبلاگ اینها توضیح داده شده.
لطفا مطالب را به ترتیب شماره بخونید و بیاین جلو !!!

موفق باشید.
سلام
ببخشید میشه در مورد فعال کردن واحد capture با a/d توضیح بدین
چرا هیچ مثالی از این بخش تو کتابا نیست :(
پاسخ:
چشم
انشاالله در آینده.
یک هفتست دنبال چنین مطلبیم هرجا خوندم چیزی نفهمیدم الان فهمیدم خیلی مرسی خدا هرچی می خوای بهت بده :)
با سلام
نمیشه با دستور c  وقفه رو فعال یا غیر فعال کرد تا در گیر زبان اسمبلی نشیم.
پاسخ:
نوچ ! :)))
با سلام و احترام
اگه زحمتی نیست در موردvector numberتوضیح بدین 
پاسخ:
سلام
به مبحث وقفه ها مراجعه شود !
سلام و خدا قوت. من دانشجوی برق دانشگاه تهرانم. بخاطر غیبت اجباری جلسات مربوط به تایمر کانتر درس میکروکنترلرمو از دست دادم. استاد عزیزم برای این قسمت جزوه دست نویس نداده بود و غافلگیر شدم. خلاصه اینکه در قعر ناامیدی این بلاگ و پیدا کردم و وقتی نظرات بقیه رو خوندم ترغیب شدم از روی این بخونم برای امتحان.
ما که نمیتونیم واست جبران کنیم. ایشالا مصداق نیکی در دجله انداختن باشه. :) زکات علمتو دادی.
پاسخ:
ممنون

موفق باشید.
void  main چکارمیکنه
پاسخ:
Wooooooooow !!!
واقعا  عالی
پاسخ:
ممنون
خوب و مفید
 بسکامش رو هم بذارید.
ممنون مثل پست های قبلی  عالی بود
خیلی عالی بود. ممنون
یه سوالی راجع ب void timer1_configuration () پرسیدم الان با خوندن پست های بعدی جوابمو گرفتم با سپاس!
دست مریزاد دارید شما.زکات علم آموزش اون به بقیس.واقعا از زحمتتون ممنون.
با سلام وتشکر از وبلگ خوبتون
بنده قسمت while(1) متوجه نشدم مگر این طور نیست که دستورات داخل while دایما تکرار میشه الان داخل دستورات while چیزی نوشته نشده چطوری تابع وقفه دایما تکرار پیدا میکنه مگر میرو در خود حلقه while گیر نمیوفته.وتابع وقفه فقط یک بار باید انجام شه و ایا نباید این طوری نوشته شه:                                                           

while(1){timer1_configuration (); }
سلام
 بهترین توضیحی بود که درمورد تایمر/کانتر AVR خوانده بودم.
خدا خیرت بده.

ارسال نظر

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