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

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

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

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

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

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

 

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

 

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

 

به نام خدا

 

سلام

 

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

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

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

 

بگذریم ...

 

اول از همه پیشنهاد میشه یه بار دیگه مبحث CTC رو که توضیح دادم بخونید و پنجره ی مربوطه رو در کنار این مبحث باز نگه دارید:

 

 

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

 

تعریف مسئله :

 

میخوایم یه فلاشر 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 براتون توضیح بدم که خیلی مورد احتیاجمونه.

 

پس فعلا ...

سلام

آقا احسان ممنون که وقت میذارین و دوباره نوشتن رو ادامه دادین

منتظرمطالب بعدیتون هستم

موفق باشین

پاسخ:
سپاس ...
hooraaaa,agha damet garm,inshala ba angize bishtar edame bedi
faghat ye moshkel darim,inke yekam yademoon rafte bayad moroor konim
bazam mamnoon
پاسخ:
تشکر دانیال جان ! :))))
دادش کجایی ؟
ما منتظر ادامه ی مباحث هستیم
پاسخ:
باشه داداش .
یکم بهم فرصت بدین. :)
عالی بود مرسی از این همه مطلب کامل با زبان ساده
پاسخ:
ممنون
خوب شد که دوباره شروع کردی :*
ممنون به خاطر مطالب مفید و روانی که میزاری
پاسخ:
:)
سلام
لطفا ادامه بدید مطالبو
بی صبرانه منتظر بخش مربوط به lcdهستیم دوست عزیز

پاسخ:
انشاالله در اولین فرصت !
واقعا دمت گرم
پاسخ:
خواهش ...
سلام
با توجه به اینکه موافق استفاده از کد ویزارد  کدویژن نیستید بهتر نیست از نرم افزار Atmel studioاستفاده کنید(البته با عرض پوزش)  که مخصوص avr است . و از کد ویژن بهتره هم از لحاظ کاربری و هم  کد نویسی.
پاسخ:
من به شخصه از Atmel Studio هم استفاده میکنم.
اما بنا به دلایلی فعلا کدویژن بحث میشه اینجا.

ضمنا اتمل استادیو هم به زبان سی هست.
سلام
ممنون بابت آموزشها، واقعاً خوبن
لطفاً اگه امکانش هست طریقه تولید موج pwm سینوسی و همچنین سینوسی سه فاز رو آموزش بدین ممنون میشم
من می خوام یه اینورتر سه فاز با avr بسازم ولی توی زمینه avr هنوز کاربلد نشدم
ممنون میشم راهنماییم کنی
ضمناً میخوام سه فاز رو با میکروهای ارزون تولید کنم که جنبه اقتصادی داشته باشه

سپاس فراوان و آرزوی موفقیت
پاسخ:
PWM آموزش داده خواهد شد.
اما پروژه ای در وبلاگ قرار داده نخواهد شد !

موفق باشید...
 سلام
 خوشحالم کردی چون منم دارم atmel استفاده میکنم البته به سختی ، ولی جالبه . می تونم سوالاتم را از atmel مطرح کنم ؟
پاسخ:
سوالتون اگه در حوزه مباحث آموزش داده شده باشه،پرسیدنش ایرادی نداره !
خدا خیرتون بده،من این ترم درس میکرو دارم،از بس استادمون افتضاحه هیچی سر کلاس یاد نمیگیرم...
با سلام
اگه زحمتی نیست در مورد کد زیر توضیح دهید:
if(PINA & (1<<PA0) == 1) //If switch is pressed
البته از این کد برای ست پین ورودی استفاده کرد ،تست کردم  تا پین خروجی مثلا PD4 روشن (ست) بشه جواب میده، حالا اگه بخوام از PA1استفاده کنم  تاPD4را ست کنم جواب نمیده منظور از ==1 چیه؟
اینم کد کامل:
#include <avr/io.h>
#include <util/delay.h>
int main()
{
while(1){

DDRA &= ~(1<<PA0);//Makes firs pin of PORTA as Input

if(PINA & (1<<PA0) == 1) //If switch is pressed
DDRD=0xff;
PORTD=(1<<PD4);
}
با تشکر

پاسخ:
سوالات خارج از بحث پاسخ داده نمیشود.
ضمن اینکه برنامه تون با AVR Studio نوشته شده.

توجه داشته باشید که معنای PINA & (1<<PA0) == 1 آن است که اگر پایه صفرم از پورت A یک شد ...

موفق باشید.
سلام. اگه ممکنه راجب به کپچر تایمر یک توضیح بدین.اگه ممکنه یه مثال هم بزنین. مرسی
پاسخ:
:|
اگه ممکنه راجب به کپچر تایمر 1 توضیح بدین. یه مثال هم بزنین ممنون میشم
پاسخ:
باید موقعیتش پیش بیاد
چون کاربرد خاص خودشو داره کپچر !
سلام .من این برنامه رو تو پروتئوس اجرا کردم (برنامه اولی)اما هر 30میلی ثانیه TOGGLE میشه.مگه برا 100میلی محاسبه نکردید؟ممنون از زحمات گران قدرتان
سلام.من برنامه رو با ای سی tiny45 نوشتم این ارور میده! Error: C:\1.c(27): undefined symbol 'TCCR1A'
Error: C:\1.c(28): undefined symbol 'TCCR1B'چون کار با این ای سی خیلی برام مهمه از تاینی استفاده کردم.
میخواستم یه سیگنال حامل قابل تنظیم 36 و 38 و 40 کیلوهرتزی درست کنم که با آموزشتون موفق شدم.
خیلی ممنون
سلام
خب یه سوال

اگه قراره پایه oc1a تاقل بشه پس چرا اومدین و بیت صفرم رجیستر DDRCرو یک کردین ما که دگ کاری باهاش نداریم
۳۱ خرداد ۹۵ ، ۱۵:۲۳ پوریا حسینی
ُسلام خسته نباشی
دوست عزیز من عین پروژه شما رو راه اندازی کردم فقط تو اون مثالی که با استفاده از رجیستر TIFR فلشر انجام شد، زمان دقیقا دو برابر می شه، باید 100 میلی ثانیه باشه ولی 200 میلی هست.
این زمان رو به 1 ثانیه افزایش دادم اما شد 2 ثانیه علت چیه؟ چون دو دو حالت دیگه که زحمت کشیدی گفتی همه چی درسته فقط تووو این قسمته که زمان دو برابر میشه !!!!!

سلام
در مورد تنظیمات نرم افزار هم مطالب بزارید  من الان خودم در تنظیمات تایمر برای سر ریز شدن و تنظیمات وقفه تایمرها  تنظیمات پورت سریال به عنوان رسیور با باود ریت9600مشکل دارم  نمیدونم چه طوری باید تنظیم کنم اگه امکان ره با عکس راهنمایی کنید با سپاس
من میخوام برنامه یه  شمارنده  رو با avr بنویسممه شمارشش  رو روی lcd نمایش بده و وقتی کلید منصل به INT0 رو زدیم شمارش متوقف بشه و آخرین عدد شمارش شده روی lcd نمایش داده بشه.کمکم کند ممنون.اگه امکانش هس برنامه رو برام ایمیل کنید

ارسال نظر

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