خانه | سیستم های نهفته | میکروکنترلر | دوره آموزشی AVR | تایمر یک (TIMER1) و تایمر دو (TIMER2) در AVR – (جلسه ی ۵)

تایمر یک (TIMER1) و تایمر دو (TIMER2) در AVR – (جلسه ی ۵)

با سلام و وقت بخیر خدمت علاقه مندان به دنیای میکروکنترلر در جلسه ی ۱۲ با مفاهیم پایه ای تایمرها در AVR آشنا شدید و در جلسه ی ۱۳ با تایمر صفر در مد نرمال کار کردید. حالا نوبت به تایمرهای ۱ و ۲ می رسه. اگه مفاهیم دو جلسه ی قبل رو به خوبی یاد گرفته باشید پست امروز رو هم خیلی راحت یاد می گیرید. این بار هم فقط در مورد مد نرمال تایمر یک و تایمر دو صحبت می کنیم و بقیه ی مدها رو میذاریم برای جلسات بعد.

  • توضیحات
  • کدنویسی
  • شبیه سازی

در این جلسه قرار است همان کارهایی را انجام دهیم که در جلسه ی قبل انجام دادیم. در جلسه قبل با تایمر ۰ آشنا شدیم. تایمر صفر را در فرکانس CPU راه اندازی نمودیم. سپس کد نوشته شده را طوری اصلاح کردیم تا از تقسیم کننده ی فرکانس استفاده کنیم. همچنین باز هم کد نوشته شده را جهت استفاده از وقفه ی تایمر اصلاح نمودیم. حال که مفاهیم مربوط به تایمر را در دو پست قبلی آموخته ایم، این بار به طور مختصر در مورد تایمر یک و تایمر دو صحبت خواهیم کرد. تمام کارهایی که در مورد تایمر صفر انجام دادیم در مورد تایمرهای ۱ , ۲ نیز انجام می دهیم.

timer

تایمر یک

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

رجیستر TCCR1B

رجیستر کنترل تایمر/کانتر یک (Timer/Counter Control Register B) به صورت زیر است:

TCCRB1

در حال حاضر فقط بیت هایی که هایلایت شده اند مورد استفاده ی ما خواهند بود. بیت های ۰ تا ۲ این رجیستر که با نام های CS11، CS10 و CS12 شناخته می شوند، بیت های انتخاب ساعت تایمر ۱ هستند. جدول زیر نشان می دهد که به ازای حالت های مختلف این سه بیت، وضعیت ساعت تایمر به چه صورت خواهد بود:

CS12-10

رجیستر TCNT1

رجیستر تایمر/کانتر یک در شکل زیر نشان داده شده است:

TCNT1

همان طور که در شکل نیز مشاهده می کنید، این رجیستر ۱۶ بیتی است، که متشکل از دو رجیستر هشت بیتی TCNT1H و TCNT1L است. TCNT1H بایت بالایی و TCNT1L بایت پایینی این رجیستر را نشان می دهند. مقدار تایمر/کانتر یک در این رجیستر ذخیره می شود.

رجیستر TIMSK

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

TIMSK1

این رجیستر در جلسه ی قبل نیز معرفی گردید چرا که بین هر سه تایمر صفر، یک و دو مشترک است. در شکل بالا بیت هایی که مربوط به تایمر ۱ نیستند، خاکستری شده اند. بیت های ۲ تا ۵ این رجیستر با تایمر یک مرتبط هستند. در این جا از بیت TOIE1 یا بیت فعال کردن وقفه ی سرریز تایمر ۱ (Timer/Counter Overflow Interrupt Enable) استفاده می کنیم. در مورد دیگر بیت های این تایمر که مربوط به مد CTC هستند، در پست های آتی صحبت خواهیم کرد.

رجیستر TIFR

رجیستر پرچم وقفه ی تایمر/کانتر در شکل زیر نشان داده شده است:

TIMSK1

این رجیستر نیز در بین هر سه تایمر AVR مشترک است. در شکل بالا بیت هایی که به رنگ خاکستری هستند مربوط به تایمرهای دیگر هستند. فقط بیت های ۲ تا ۵ مربوط به تایمر ۱ می باشند. در این جلسه از بین این بیت ها با بیت TOV1 کار داریم که بیت پرچم سرریز تایمر/کانتر ۱ (Timer/Counter Overflow Flag) می باشد. وقتی که تایمر سرریز می کند این بیت یک می شود و به محض این که روال وقفه اجرا شود به طور خودکار دوباره صفر می گردد. ولی هنگامی که روالی برای وقفه وجود نداشته باشد، با نوشتن یک بر روی TOV1 آن را صفر می کنیم.

مثال ۱ :

در این مثال می خواهیم یک LED را در هر ۲ ثانیه (در فرکانس ۰/۵ هرتز) خاموش و روشن کنیم. همچنین از کریستال ۱۶ مگاهرتز خارجی به عنوان مولد پالس ساعت در میکروکنترلر استفاده می کنیم.

با استفاده از فرمول هایی که در جلسه ی ۱۲ یاد گرفتیم و با توجه به این که می دانیم فرکانس CPU برابر با ۱۶ مگاهرتز است، و همچنین با توجه به این که تایمر ۱۶ بیتی می تواند حداکثر تا مقدار ۶۵۵۳۵ بشمارد، حداکثر تأخیر قابل ایجاد برابر با ۴/۰۹۶ میلی ثانیه است. و این مقدار بسیار کوچک است. با استفاده از مقسم فرکانس ۸، فرکانس تایمر تا ۲ مگاهرتز کاهش می یابد. با استفاده از این مقسم فرکانس می توانیم حداکثر ۳۲/۷۶۸ میلی ثانیه تاخیر تولید کنیم. حال ما می خواهیم به مدت ۲ ثانیه تاخیر داشته باشیم. داریم:

 ۶۱≈ ۶۱٫۰۳۵  = ۲s ÷  ۳۲٫۷۶۸ ms

این بدان معناست که تایمر باید ۶۱ بار سرریز شود تا یک تاخیر حدودا ۲ ثانیه ای تولید شود. اکنون با توجه به دانسته هایمان از این جلسه و جلسات قبل (آشنایی با تایمرها – جلسه ی ۱۲ و کار با تایمر صفر – جلسه ی ۱۳) قادر به نوشتن کد این مثال هستیم. در صورتی که نیاز به یادآوری در مورد کار با پورت های AVR دارید به جلسه ی ۱۰ مراجعه نمایید. جهت یادآوری وقفه ها در AVR روی جلسه ی ۱۱ کلیک کنید.

کد این مثال را در محیط کد ویژن می نویسیم. برای استفاده از تقسیم کننده ی ۸ نیز ترکیب بیت های CS10-CS12 ردیف سوم جدول بالا را به کار می بریم. کد نوشته شده همراه با توضیحات در قسمت کدنویسی قابل دسترسی است. پس از نوشتن کد، شبیه سازی این مثال را در محیط پروتئوس انجام می دهیم. انیمیشن شبیه سازی نیز در تب شبیه سازی آمده است. فایل های هگز، c و شبیه سازی نیز در پایین صفحه قابل دانلود کردن می باشد.

**************************************************

تایمر دو

سومین تایمر AVR که TIMER2 نام دارد، مانند تایمر صفر یک تایمر هشت بیتی است. اغلب رجیسترهای مربوط به این تایمر همانند تایمر صفر هستند. به علاوه تایمر دو دارای یک ویژگی خاص است که تایمرهای دیگر آن را دارا نیستند. این ویژگی عمل‌کرد غیرهمزمان (Asynchronous Operation) است که در پست های آتی در مورد آن صحبت خواهد شد. به این دلیل که قبلاً در جلسه ی تایمر صفر با مفاهیم تایمر ۸ بیتی و کار با آن آشنا شده ایم، همان رویه را برای تایمر دو نیز در پیش می‌گیریم و در یک مثال هم از تقسیم کننده ی فرکانس و هم از وقفه ی تایمر استفاده خواهیم نمود. اما نیاز است که در ابتدا با رجیسترهای مربوط به TIMER2 آشنا شویم:

رجیستر TCCR2

این رجیستر به شکل زیر است:

TIMSK1

با توجه به اینکه بعداً در مورد مد CTC صحبت خواهیم کرد، اینجا فقط بیت‌های ۰ تا ۲ را مورد توجه قرار می دهیم. این بیت‌ها برای انتخاب ساعت (Clock Select) بوده و عبارتند از: CS20 و CS21 و CS22. بر خلاف دو تایمر دیگر، تایمر۲ تعداد بیشتری از تقسیم کننده های فرکانس را در اختیار ما می گذارد. مقسم های ارائه شده در تایمر صفر و تایمر یک عبارت بودند از: مقسم های ۸ ، ۶۴، ۲۵۶ و ۱۰۲۴ در حالی که در تایمر دو تقسیم کننده های ۸ ، ۳۲، ۶۴، ۱۲۸، ۲۵۶ و ۱۰۲۴ را داریم. در جدول زیر نحوه ی انتخاب این مقسم ها را مشاهده می کنید:

CS2

رجیستر TCNT2

رجیستر تایمر/کانتر (Timer/Counter Register 2) مربوط به تایمر ۲ ، مقدار این تایمر را در خود ذخیره می کند. با توجه به اینکه تایمر ۲ هشت بیتی است، این رجیستر نیز هشت بیتی می باشد. شکل زیر این رجیستر را نشان می دهد:

TCNT2

رجیستر TIMSK

رجیستر وقفه ی تایمر/کانتر که بین هر سه تایمر نیز مشترک است به صورت زیر می باشد. در حال حاضر ششمین بیت این رجیستر یا TOIE2 مورد توجه ماست. برای فعال کردن وقفه ی سرریز تایمر ۲ این بیت را یک می کنیم.

TIMSK2

رجیستر TIFR

رجیستر پرچم تایمر/کانتر در شکل زیر نشان داده شده است. این رجیستر نیز در بین هر سه تایمر مشترک است. در اینجا با بیت ششم یا TOV2 کار داریم. این بیت هنگامی که تایمر سرریز کند یک می‌شود و به طور اتوماتیک هنگامی که زیرروال وقفه اجرا گردد دوباره صفر می‌شود. البته هنگامی که روال وقفه‌ای موجود نباشد می‌توانیم با نوشتن یک بر روی این بیت آن را صفر کنیم.

TIFR2

مثال ۲ :

همان مساله ای که در پست تایمر صفر طرح کردیم را در اینجا نیز مطرح می کنیم. فرض کنیم می‌خواهیم یک LED را هر ۲۵۰ میلی ثانیه خاموش و روشن کنیم. یک کریستال خارجی۱۶ مگاهرتز نیز پالس ساعت CPU را فراهم می کند.

در اینجا نیز از مقسم فرکانس ۲۵۶ استفاده می‌کنیم. طبق محاسباتی که در پست قبل انجام دادیم (برای مشاهد محاسبات به مثال ۳ از جلسه ی ۱۳ مراجعه کنید.) در چنین شرایطی برای ایجاد هر تأخیر۲۵۰ میلی ثانیه ای تایمر باید ۶۱ بار سرریز کرده و سپس ۹ بار بشمارد.

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

کد مثال ۱ :

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

*****************************************

کد مثال ۲ :

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

شبیه سازی مثال ۱ به صورتی که در انیمیشن زیر قابل مشاهده است انجام می گیرد:

 

timer1-smltn

 

همان طور که در انیمیشن بالا نیز مشاهده می شود زمان تولید شده توسط تایمر دقیقا برابر با دو ثانیه است.

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

پسورد فایل: www.microlearn.ir

دانلود فایل های تایمر ۱ و ۲

خب حسابی خسته نباشید، چون که الان دیگه هر سه تایمر AVR رو شناختید و با هر سه در مود نرمال کار کردید. جلسه ی بعد در مورد مد CTC صحبت خواهیم کرد.  ما رو از نظرات خودتون بی نصیب نذارید.

درباره‌ی مجتبی

کارشناس الکترونیک و کارشناس ارشد مخابرات سیستم | زمینه ی تحقیقاتی : پردازش تصویر و تعقیب اشیاء متحرک |‌فعال در حوزه ی الکترونیک مبتنی بر میکروکنترلر | برنامه نویس و طراح بردهای الکترونیکی مبتنی بر میکروکنترلر

۲۸ ديدگاه

  1. امیر مسعودیان

    با عرض سلام و خسته نباشید و تشکر از سایت واقعا عالیتون یه سوالی داشتم
    سوالم اینه که اگر مثلا در تایمر یک برای اندازه گیری یه تاخیر مشخص تا قبل از سر ریز شدن بخوایم وارد اینتراپت بشیم نمیشه به صورت دستی رجیستر مربوط به پرچم سر ریز تایمر یکو یک کنیم؟چون من توی کدی که نوشتم این کارو کردم اما جواب نمیده؟لطفا اگر کدش شکل خاصی داره راهنمایی کنید
    پیشاپیش از زحمات شما کمال تشکر را دارم

    • با سلام و ممنون از لطف شما دوست عزیز
      وقتی تایمر به مقدار مشخص نرسیده که دلیلی نداره شما اینتراپت بدین. اما اگه میخواید قبل از سرریز وقفه بده باید از مد CTC استفاده کنید تا وقتی به حد مشخصی رسید وقفه فعال بشه.

  2. امیر مسعودیان

    با عرض سلام و خسته نباشید یه سوالی داشتم و سوالم اینه که اگر فرض کنیم دوره تناوب تایمرمون مثلا ۰٫۱ ثانیه باشه برای اندازه گیری ۰٫۳ ثانیه باید تا چن بشماره دو تا یا سه تا؟در واقع وقتی همون اول رجیستر صفر مربوط به تایمر صفر میشه اون خودش ۰٫۱ ثانیه زمان میبره یا نه ؟و همچنین بعد از وقوع سرریز چطوره و آیا واسه صفر شدن ۰٫۱ ثانیه زمان لازم داره؟
    ممنون میشم پاسخ بدید

    • درود و عرض ادب
      سوال بسیار خوبی را مطرح فرمودید. من یه توضیح میدم که شما بر اساس همین توضیح میتونید برنامتون را بنویسید. شما مقدار شمارنده تایمر را صفر کنید و تایمر را فعال کنید. در مثال شما بعد از ۳ شمارش اگه وقفه در مد مقایسه فعال باشه به زمان دلخواهتون درست پیدا کردید و این روال به صورت خودکار میتونه برای ساختن پالس شما ادامه داشته باشه. اما در حال سرریز وقتی مثل ۲۵۵ شمارش کامل شد پرچم وقفه فعال نمیشه و زمانی که از ۲۵۵ به صفر بر میگردیم دقیقا یه دوره طول کشیده و بعد پرچم فعال میشه.

  3. اقا دمت گرم خیلی خیلی باحال توضیح دلادی

  4. حمیده سعدآبادی

    سلام وقتتون به خیر! راستش من یه مشکل تو تایمر ۱ دارم. من یه برنامه نوشتم برای ATMEGA16 که توش با تایمر ۱ موج PWM متغییر ساخته بودم. درواقع یک سنسور دمایی هست. حالا می خوام همون برنامه رو با تایمر ۱ بنویسم که دقت کارم بره بالا ولی مشکلی که هست اینه که وقتی در تایمر ۱ تعریف می کنم که تا ۱۰۲۴ بشمره مثل برنامه قبل فقط تا ۲۵۶ می شماره و دوباره از اول شروع می کنه به شمردن تا ۲۵۶ و بیشتر از اون نمیتونه بالا بره. البته من برنامه رو هیچ تغییری ندادم همون برنامه قبل هست فقط توش تایمر ۲ رو غیر فعال کردم و تایمر ۱ رو فعال کردم. ممنون می شم اگر راهنمایی کنید من رو.
    با تشکر

    • سلام به شما دوست عزیز
      مشکلی که گفتید قطعا به دلیل برنامه نویسی اشتباه هست که انجام دادید. وگرنه در صورت اصولی نوشتن برنامه شمارش تا مقدار دلخواه شما اتفاق می افته. لطف کنید و برنامتون را به ایمیل یا آی دی تلگرام بنده بفرستید تا براتون اشکال یابی کنم:
      ایمیل:eaca89@gmail.com
      تلگرام:https://telegram.me/EhsanAo

  5. سلام
    طبق جدول های مربوط به بیت های انتخاب ساعت تایمر های صفر و یک در دو حالت آخر امکان استفاده از منبع ساعت خارجی به عنوان سیگنال مورد شمارش وجود دارد در صورتی که برای تایمر ۲ این امکان نیست و به جای آن تقسیمات فرکانسی بیشتری در اختیار داریم. این یعنی از تایمر دو به عنوان شمارنده نمیشه استفاده کرد؟
    و سوال دوم این که در کد مثال یک میشه شرط if یعنی خطوط ۱۵ تا ۱۹ را به داخل حلقه ی وایل انتقال داد( مثل مثال ۲ و مثال های تایمر صفر ). این دو مدل نوشتن به لحاظ عملکرد بهتر برنامه با هم تفاوت دارن؟ میشه گفت حالت اول که شرط در روال وقفه انجام میشه دقیق تره چون بیشتر از سخت افزار استفاده کردیم؟

    • سلام
      در رابطه با سوال اولتون: در میکروکنترلر مگا۳۲ تایمر دو امکان شمارش رویدادهای خارجی رو نداره. در حالت کلی، تایمرها در ویژگی ها و امکاناتی با هم تفاوت دارن تا شما بتونین بهترین تایمر رو برای کارتون انتخاب کنید.
      اما سوال دومتون:
      در این مثالها و این کاربردها تفاوت چندانی ندارن. فقط وقتی شرط رو داخل اینتراپت تایمر می نویسیم، شرط فقط وقتی چک میشه که وارد روال وقفه بشیم. ولی وقتی شرط رو داخل حلقه ی وایل می نویسیم، همینطور هرلحظه در حال چک کردن شرط هستیم. بردن شرط داخل روال وقفه بهتره، تا سی پی یو برای کارهای دیگه آزاد تر باشه.

  6. سلام مهندس. ایمیل دارید تا من سوالم رو بپرسم؟ چون تصویری هست.

  7. سلام.
    متشکرم از این که با صبر و حوصله سوالات ما رو همیشه پیگیری می کنین.
    بله همانطور که گفتین نیازی به استفاده از تایمر برای این عملکرد ساده نیست.
    منتها هدفم بررسی بیشتر عملکرد تایمر کانتر با یکسری برنامه های ساده بود….
    از توضیح شما بهتر متوجه عملکرد برنامه شدم
    مرسی

  8. با سلام
    در برنامه زیر T/C0 را به کار انداخته ایم و برای ایجاد گام زمانی بزرگ تر از متغیر x استفاده کردیم. در یک زمان معین(x=5) تابع f فراخوانی می شود.(نتیجه : led ها پس از مدتی روشن و بعد از مدتی دیگر خاموش می شوند)
    سوال : اگر تاخیر داخل تابع f را حذف کنیم اجرای تابع و دستور خاموشی(PORTB=0x00) برای چند بار پشت سر هم اجرا شده و سپس نهایتا خاموشی را خواهیم داشت. چرا این اتفاق می افتد؟!
    (ظاهرا در این مدت x افزایشی ندارد! درصد استفاده از cpuهم شدیدا زیاد می شود!)
    با تشکر

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

    • سلام دوست من، برنامه ت رو خوندم. بیایم اول ببینیم توی برنامه ت چه اتفاقی میفته. تایمر راه اندازی میشه. اگه tcnt0 از ۲۴۳ بیشتر باشه X اضافه میشه. وقتی x به ۵ رسید f اجرا میشه. درون f مقدار پورت کلا یک میشه. بعد از ۵۰ میلی ثانیه هم از f خارج میشیم و پورت کلا صفر میشه.
      یه سوال؟ بعد از این که از f خارج شدیم آیا بازم F فراخوانی خواهد شد؟ جواب: هم بله و هم نه!!! چرا؟ چون، تا مدتی که X یکی بهش اضافه نشه همچنان شرط ارضا میشه و f فراخوانی میشه و پورت یک میشه و دوباره بعد از خروج از F صفر میشه. و چون تاخیری هم وجود نداره باز هم همین اتفاق تا چندین بار پشت سر هم میفته. و بعد از اون وقتی x برابر با ۶ شد، شرط دیگه ارضا نمیشه و پورت صفر باقی می مونه و دستورهای داخل if اجرا نمیشن. فراموش کردی x رو دوباره صفر کنی. (البته اگه بخوای این خاموش و روشن شدن ادامه پیدا کنه وگرنه باید بعد از اجرای f سریعا مقدارش رو مثلا ۶ کنی.)
      اما من یه سوال اساسی تر دارم: شما اگه از همون اول میخواستی از delay استفاده کنی، چرا پس اصلا داری از تایمر استفاده میکنی؟ از تایمر هم استفاده نمیکردی و خیلی راحت با دستورات Delay توی حلقه ی while پورتت رو صفر و یک میکردی. و اگه از تایمر داری استفاده میکنی، چرا پس دوباره میایی از delay استفاده میکنی؟
      برنامه ت که نقص داره، ولی من بازم جواب سوالت رو میدم. شما وقتی delay رو بر میداری چی میشه؟ به محض این که پورتت درون تابع f یک میشه، از تابع خارج میشی و سریعا صفرش میکنی. ولی هنوز x برابر ۵ هست و دوباره این اتفاق تکرار میشه و اینقدر این اتفاق میفته تا از روی شانس x برابر ۵ نباشه. برای همین مشکل ایجاد میشه.

      برنامه ت رو اصلاح کن و دوباره تست کن. در صورتی که مشکلی بود در خدمتم. 🙂

  9. سلام مهندس. وقت بخیر. تشکر بابت راهنمایی شما. بنده یک برنامه ساده میخوام بنویسم. یک LED دارم و میخوام یک ثانیه روشن و یک ثانیه خاموش باشه و به طور مداوم تکرار بشه. برنامه اش که نوشتنش ساده اس. ولی مسئله مهم برای من بحث زمان دقیق است. من اومدم کریستال خارجی بین پایه های XTAL1 و XTAL2 با فرکانس ۸MHZ وصل کردم. برای این کار باید فیوز بیت های CKSEL3 و CKSEL2 و CKSEL1 و CKSEL0 را نباید پروگرام کنیم. یعنی پیش فرض همه این چهار فیوز بیت را “۱” قرار می دهیم. در محیط پروتئوس هم گزینه “۱۱۱۱” را انتخاب می کنیم. و فیوز بیت CKOPT را فعال می کنیم تا بتوان کریستال خارجی بالای ۱MHZ به آن وصل کرد که هدف ما کریستال خارجی ۸MHZ است. تا اینجا مشکل ایجاد زمان دقیق رفع شد. حالا تو حلقه while(1) باید بنویسم مثلا PORTA.0=1;delay_ms(1000);PORTA.0=0;delay_ms(1000); تنظیمات فیوز بیت هم تو پروتئوس انجام دادم. ولی بازم می بینم که در یک دقیقه ۳۰ مرتبه روشن و خاموش انجام نمیشه و حدود ۸۰ ثانیه طول میکشه. به نظر شما من اگر عملی ببندم (با کریستال خارجی البته!) باز این مشکل وجود داره یا نه حل میشه؟؟؟

    • سلام دوست من٬ قبلا هم بهتون گفتم که وقتی حرف از زمان دقیق می زنید از شبیه ساز استفاده نکنید. نکات دیگه این که وقتی مسئله ی مهم برای شما زمان دقیق هست از منبع ساعت داخلی هم استفاده نکنید٬ در ضمن برای ایجاد زمان دقیق از تابع delay_ms هم استفاده نکنید. لابد الان میپرسی که پس مگه چیز دیگه ای هم برای استفاده موند؟ 🙂
      باید بگم که بله٬ به جای شبیه ساز به طور عملی تست کن. به جای منبع ساعت داخلی از کریستال خارجی استفاده کن. و به جای تابع delay از تاخیر تایمر یک استفاده کن. البته بازم بگم شبیه ساز نباید در این حد اختلاف فاحش داشته باشه٬ ببین کجای کار رو اشتباه میری؟

  10. پس اگر بخواهیم بیت TOV1 رو چک کنیم چجوری نوشته میشه ؟ به این صورت؟

    ( if(TIFR.2==1

    • نخیر به این صورت ایراد داره و اصلا کامپایل هم نمیشه. برای هیچ کدوم از رجیسترها (به جز PORTx ، DDRx و PINx) نمیتونیم بیت رو با شماره ش انتخاب کنیم. برای انتخاب یک بیت از یک رجیستر باید به صورت زیر عمل کنید، مثلا در اینجا قصد داریم بیت شماره ی ۲ رو انتخاب کنیم:

      (۰x04&TIFR)

      با این کار بیت شماره ی دو که مقدارش یک هست، هرچی باشه باقی می مونه و بقیه ی بیت ها مطمئناً صفر می شن. بعد باید بیت ۲ رو به تعداد دو بار به راست شیفت بدیم:

      (۰x04&TIFR)>>2

      حالا اگه بیت ۲ صفر باشه مقدار عبارت بالا صفره و اگه مقدارش یک باشه مقدار عبارت بالا هم یک خواهد بود.
      برای نوشتن شرط:

      if((0x04&TIFR)>>2)

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

  11. واقعا توضیحاتتون کامل بود ممنون
    ببخشید در شرط if که من TOV1==1 گذاشتم در اینجور مواقع نیازی نیست اسم رجیستر هم آورده شود (TIFR) یعنی خودش مستقیم میدونه این بخش از کدوم رجیستره ؟

    • خواهش می کنم، لطف دارین.
      شاید شما توی برنامه تون نوشتین TOV1 و هیچ ایرادی هم نگرفت. البته نباید هم ایرادی بگیره. ولی این جای برنامه تون اشتباهه. چرا؟ بذارین اینطوری بگم:
      شما وقتی مثلا توی کدویژن هدر mega16.h رو اد می کنی از اون به بعد یه سری متغیرها برای کدویژن شناخته شده هستن. مثلا همین TOV1. اما TOV1 اینجا برابر با چنده؟ اشتباهی که خیلی ها میکنن اینه که فکر میکنن منظور از TOV1 بیت TOV1 هست. ولی این طور نیست. مقدار TOV1 همیشه ثابت و برابر ۲ هست. اما چرا؟ به تصویری که از رجیستر TIFR درون پست گذاشتم مراجعه کنید. TOV1 بیت شماره ی ۲ در رجیستر TIFR هست. در کدویژن TOV1 نشان دهنده ی شماره ی بیت TOV1 هست (که مقدارش همیشه برابر ۲ خواهد بود). باز هم بگم که TOV1 نشون دهنده ی شماره ی بیت TOV1 هست نه بیت TOV1.
      حالا یه سوال؟ من اگه جایی نوشتم CS22 یعنی چی؟
      جواب: CS22 شماره ی بیت CS22 در رجیستر TCCR2 و همیشه برابر با مقدار ۲ هست.
      شاید بپرسین چرا اینجوریه؟ چون ما همیشه نمیتونیم حفظ کنیم که بیت TOV1 بیت چندم از رجیستر TIFR هست ولی اسمش یادمون می مونه.
      حالا میخوایم مقدار TOV1 رو صفر کنیم. برای این کار باید مقدار یک رو روی اون بریزیم. به این صورت مینویسیم:

      TIFR |= (1 << TOV1);

      این یعنی ۱ رو به تعداد ۲ بار شیفت به چپ بده و بریز داخل رجیستر TIFR.
      حالا به برنامه ای که شما نوشتین یه نگاه بندازیم. نوشتین if (TOV1==1). کامپایلر اون رو اینجوری میخونه: if(2==1) و چه اتفاقی میفته؟ چون هیچوقت ۲ برابر با یک نیست هیچوقت دستورهای داخل if اجرا نمیشن. 😐

  12. سلام مهندس. وقت بخیر. بنده کارشناسی برق قدرت دارم. یکم تو میکرو میلنگم. سوالم ساده است. من میخوام یک زمان سنج دقیق بسازم. ولی مشکل اینجاست که وقتی از تایمر ۲ استفاده کردم و کریستال ۳۲۷۶۸ هرتز روی خروجی پورت تایمر گذاشتم. مشاهده کردم که ساعت شبیه سازی شده تو پروتئوس کند تر از ساعت مچی خودم کار می کنه. حتی یکبار یک برنامه اینکه ال ای دی یک ثانیه روشن و یک ثانیه خاموش باشد را نوشتم. بعد قاعدتا باید در یک دقیقه ۳۰ بار ال ای دی روشن می بود و ۳۰ بار خاموش.البته یکی در میان روشن و خاموش. ولی مشاهده کردم که در ۹۰ ثانیه این اتفاق میفته و نه در ۶۰ ثانیه. آیا باید کریستال جداگانه ای هم به پایه xtal1&2 وصل کند. کلا نحوه اتصال کریستال به پایه xtal چطوریه و تو پروتئوس چه جوری شبیه سازیش کنم؟

    • سلام
      ایشالا به زودی در میکروکنترلر استاد هم میشی 🙂
      اول از همه یه چیزی بگم: وقتی حرف از دقت میزنی اصلا روی شبیه سازها و علی الخصوص پروتئوس هیچ حسابی باز نکن. همیشه از تست عملی برای صحت برنامه و … استفاده کن. چون پروتئوس به دلالیل متعددی ممکنه به صورت real time عمل نکنه.
      البته خطای زمانی پروتئوس نباید زیاد باشه. شما کریستال خارجی واحد تایمر رو که باید به پایه های TOSC وصل کنی. البته نیاز به تنظیم دقیق فرکانس میکروکنترلر هم داری. مثلا اگه از کریستال خارجی استفاده می کنی و در کدویژن برنامه می نویسی. فرکانس کلاک رو روی مقداری که دوست داری (فرض کنیم ۸ مگ) تنظیم کن. بعد از کامپایل کردن برنامه، در محیط پروتئوس هم روی میکروکنترلر دابل کلیک کن و طبق تصویر زیر عمل کن:


      با این کار حتی اگه در پروتئوس کریستالی رو هم به پایه های Xtal وصل نکنی اتفاقی نمیفته و شبیه سازیت درسته.

  13. فکر کنم منظورتون اینه ” هنگامی که روالی برای وقفه وجود نداشته باشد، با نوشتن یک بر روی TOV1 آن را صفر می کنیم ”

    while(1)
    {
    ……
    if VOT1==1
    {
    tot_overflow++;
    VOT1=0;
    }
    …..
    }

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

  14. ” ولی هنگامی که روالی برای وقفه وجود نداشته باشد، با نوشتن یک بر روی TOV1 آن را صفر می کنیم ”

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

    • خواهش میکنم، چرا که نه؟
      TOV1 بیت شماره ی ۲ از رجیستر TIFR هست و پرچم سرریز برای تایمر یکه. یعنی وقتی سرریز اتفاق بیفته این بیت مقدارش یک میشه. حالا اگه بیت وقفه ی عمومی I و همچنین بیت TIOE1 یک باشن (یعنی وقفه ها از قبل فعال شده باشن) و سرریز اتفاق بیفته و TOV1 هم یک بشه، زیرروال وقفه فراخوانی میشه و اجرا میشه. بعد از این که زیرروال وقفه به اتمام رسید میکروکنترلر به طور اتوماتیک بیت TOV1 رو دوباره صفر میکنه.
      حالا فرض کنیم شخصی میخواد وقتی تایمر ۱ سرریز کرد، متوجه این سرریز بشه و نیازی هم به اجرای وقفه نداره. برای این منظور بعد از این که تایمر رو راه اندازی کرد، مرتب بیت TOV1 رو چک میکنه و وقتی که سرریز اتفاق افتاد و TOV1 برابر یک شد، متوجه این سرریز میشه و کاری که میخواد رو میکنه. اما این بار دیگه بیت TOV1 به طور اتوماتیک صفر نمیشه و برای کارهای بعدی باید اون رو به طور دستی صفر کرد، برای صفر کردنش باید نوشت:


      TIFR |= (1 << TOV1);

پاسخ دهید

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

Time limit is exhausted. Please reload CAPTCHA.