آموزش تایمر/کانتر ATMega32 - قسمت اول

در کل سه تایمر/کانتر به نام‌های "تایمرصفر ، تایمر‌یک و تیامردو " داریم که صفر و یک هشت بیتی هستند و تایمر‌یک ۱۶ بیتی.

رجیستر‌هایی که باید بشناسید

TCNTn: Timer / Counter Register

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

TOVn: Timer Overflow Flag

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

TCCRn : Timer Counter Control Register

این رجیستر برای تنظیم حالت های تایمر/کانتر استفاده میشه.

OCRn : Output Compare Register

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



تایمر صفر

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

TCNT0: Timer / Counter Register 0

یک رجیستر هشت بیتی که با هرپالس یکی بهش اضافه می‌شه.که بهش شمارنده می‌گیم.

TCCR0: Timer / Counter Control register 0

یک رجیستر هشت بیتی برای تنظیم حالت و منبع کلاک

Bit 7- FOC0: Force compare match

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

Bit 6, 3 - WGM00, WGM01: Waveform Generation Mode
Bit 6, 3 - WGM00, WGM01: Waveform Generation Mode

Bit 6, 3 - WGM00, WGM01: Waveform Generation Mode

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

  • حالت نرمال : با رسیدن شمارنده به ۲۵۵ فلگ سرریز ست می‌شود.
  • حالت ctc : با رسیدن شمارنده به مقدار مقایسه شونده وقعه فعال می‌شود و شمارنده نیز صفر می‌شود.
  • حالت PWM : توضیح قسمت های بعدی ...
  • حالت fast PWM

Bit 5:4 - COM01:00: Compare Output Mode

این دو بیت تعیین کننده حالت تولید‌کننده شکل‌موج هستند.

Bit 2:0 - CS02:CS00: Clock Source Select

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

ولی بعد از ست کردن مقدار بین ۲ تا ۵ باینری با pre-scaler شروع به تولید کلاک می‌کنه و شمارنده عددش رو اضافه می‌کنه در هر سیکل.

تعیین کلاک
تعیین کلاک

خب تصویر بالا نیاز به توضیح نداره از مقدار ۲ باینری تا ۵ باینری کلاک رو تقسیم بر عدد سمت راستش میکنه.


TIFR: Timer Counter Interrupt Flag register

رجیستر فلگ وقفه تایمر/کانتر

Bit 0 - TOV0: Timer0 Overflow flag

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

Bit 1 - OCF0: Timer0 Output Compare flag

فلگ خروجی مقایسه : وقتی مقدار شمارنده و مقایسه شونده برابر شوند این بیت یک در غیر اینصورت صفر می‌شود.

بقیه بیت ها هم به صورت زیر هستند.

Bit 2 - TOV1: Timer1 Overflow flag

Bit 3 - OCF1B: Timer1 Output Compare B match flag

Bit 4 - OCF1A: Timer1 Output Compare A match flag

Bit 5 - ICF1: Input Capture flag

Bit 6 - TOV2: Timer2 Overflow flag

Bit 7 - OCF2: Timer2 Output Compare match flag



سرریز در تایمر صفر

درحالت نرمال : وقتی شمارنده سرریز می‌شود، یعنی مثلا از صفر به ۲۵۵ می‌رود، فلگ TOV0 ست می‌شود.توجه کنید که مقدار شمارنده بصورت خودکار صفر نمی‌شود و باید بصورت دستی این کار را انجام دهیم.

مقدار شمارنده بر اثر زمان
مقدار شمارنده بر اثر زمان

ساخت تاخیر با اسفاده از تایمر صفر

مراحل برنامه نویسی :

  1. مقدار اولیه TCNT0 را مشخص کنیم. مثلا 0x25
  2. برای حالت نرمال و حالت pre-scalar کلاک ، به رجیستر TCCR0 مقدار می‌دهیم. به محض مقدار دهی به این رجیستر ، تایمر/کانتر شروع به شمارش می‌کند.
  3. تایمر به شمارش ادامه می‌دهد ، پس برای کنترل سرریز مقدار TOVO رو نظارت میکنیم که وقتی مقدار یک بگیره یعنی سرریز رخ داده.
  4. توقف تایمر با مقدار دهی صفر به TCCR0.
  5. پاک کردن فلگ TOV0. برای پاک کردن فلگ ما باید مقدار یک در این بیت بریزیم .
  6. برگشت به تابع main.

برنامه‌ی وقته با تایمر

#include <avr/io.h>
void T0delay();
int main(void){
	DDRB = 0xFF;		/* PORTB as output*/
    	while(1){  		/* Repeat forever*/
		PORTB=0x55;
		T0delay();  	/* Give some delay */
		PORTB=0xAA;
		T0delay();
    	}
}
void T0delay() {
	TCNT0 = 0x25;  		/* Load TCNT0*/
	TCCR0 = 0x01;  		/* Timer0, normal mode, no pre-scalar */
	
	while((TIFR&0x01)==0);  /* Wait for TOV0 to roll over */
	TCCR0 = 0;
	TIFR = 0x1;  		/* Clear TOV0 flag*/
}



مثال

یک شکل موج مربعی با طول ۱۰ میلی ثانیه بالا و ۱۰ میلی ثانیه پایین تولید کنیم.

اول باید یک وقفه ۱۰ میلی ثانیه‌ای با تایمر صفر تولید کنیم.

فرض که میکرو رو روی فرکانس ۸ مگاهرتز تنظیم کردیم.

با استفاده از pre-scaler اه ۱۰۲۴ ، فرکانس منبع کلاک می‌شود :

8 MHz / 1024 = 7812.5 Hz

زمان هر سیکل :

1 / 7812.5 = 128 μs

بنابراین برای وقفه ۱۰ میلی‌ثانیه‌ای تعداد سیکل‌های مورد نیاز تقریبا 78 میشه

10 ms / 128 μs = 78

پس ما به ۷۸ سیکل نیاز داریم تا وقفه ۱۰ میلی‌ثانیه‌ای بسازیم. پس مقداری که باید توی TCNT0 بزاریم میشه 178 :

TCNT0 = 256 – 78

یعنی شمارنده از ۱۷۸ شروع می‌کنه به شمردن و ۷۸ تا سیکل می‌شماره تا سرریز کنه.

پس ما اگه مقدار 0xB2 رو داخل رجیستر TCNT0 بزاریم ، تایمر بعد از ۱۰ میلی ثانیه سرریز می‌کنه.


برنامه وقفه ۱۰ میلی‌ثانیه‌ای با تایمر صفر

#include <avr/io.h>
void T0delay();
int main(void)
{
	DDRB = 0xFF;		/* PORTB as output */
	PORTB=0;
    	while(1)  		/* Repeat forever */
    	{
		PORTB= ~ PORTB;
		T0delay();
    	}
}
void T0delay()
{
	TCCR0 = (1<<CS02) | (1<<CS00); /* Timer0, normal mode, /1024 prescalar */
	TCNT0 = 0xB2;  		/* Load TCNT0, count for 10ms */
	while((TIFR&0x01)==0);  /* Wait for TOV0 to roll over */
	TCCR0 = 0;
	TIFR = 0x1;  		/* Clear TOV0 flag */
}



وقفه تایمر

TIMSK: Timer / Counter Interrupt Mask Register

ما باید بیت TOIE0 (Timer0 Overflow Interrupt Enable) رو در رجیستر TIMSK ست کنیم تا وققه‌ی تایمر صفر فعال بشه. بعد از فعال شدن ، به محض سرریز تایمرصفر ، کنترلر به روتین وقفه تایمر صفر پرش می‌کنه.

برنامه وقفه یک میلی‌ثانیه‌ای با تایمر صفر

#include <avr/io.h>
#include <avr/interrupt.h>

/* timer0 overflow interrupt */
ISR(TIMER0_OVF_vect)
{
	PORTB=~PORTB;		/* Toggle PORTB */
	TCNT0 = 0xB2;
}
int main( void )
{
	DDRB=0xFF;  		/* Make port B as output */
	sei();
	TIMSK=(1<<TOIE0);  	/* Enable Timer0 overflow interrupts */
	TCNT0 = 0xB2;  		/* Load TCNT0, count for 10ms*/
	TCCR0 = (1<<CS02) | (1<<CS00); /* Start timer0 with /1024 prescaler*/
	while(1);
}



منبع :

https://www.electronicwings.com/avr-atmega/atmega1632-timer