Atmega128 기초 - 8비트 타이머/카운터 일반모드
용어 정의
BOTTOM - 카운터가 0이 되었을 때를 의미.
MAX – 카운터가 0xFF(=255)에 도달했을 때를 의미
TOP
TOP값은 0xFF(MAX) 또는 OCR0 레지스터에 저장된 값으로 지정할 수 있다.
카운터가 TOP값과 똑같거나 더 커진 경우를 의미한다.
일반 모드
TCCR0 레지스터의 WGM00 비트와 WGM01 비트가 0으로 설정된 경우이다.
TCNT0 레지스터는 카운터에서 값을 직접 읽거나 쓸 수 있게 해주는 레지스터이다.
일반 모드에서 카운팅은 항상 증가하는 방향으로 이루어 진다.
8비트로 표현할 수 있는 최대값인 0xFF(=255)를 초과하면 다시 bottom(=0)부터 카운팅을 시작한다. TCNT0가 0이 되는 순간 TIFR 레지스터의 TOV0 비트가 1로 설정된다.
타이머/카운터 오버플로우 인터럽트와 같이 사용되면, TIFR 레지스터의 TOV0 플래그 비트는 자동으로 0으로 클리어된다.
TIMSK 레지스터의 TOIE0 비트가 1로 설정되고 Status 레지스터의 I비트가 1로 설정되었을 때 타이머/카운터0 오버플로우 인터럽트가 활성화된다.
프리스케일러 선택은 TCCR0레지스터의 CS02, CS01, CS00 비트에 의해서 결정된다.
아래처럼 회로를 구성하고 프로그램 코드를 테스트한다.
사용중인 크리스탈의 값 F_CPU = 16Mhz이고 8비트 타이머(최대값 255)를 사용한다면 만들 수 있는 최소 딜레이값은 0.016ms이다. 계산과정은 다음과 같다.
주기 = 1/주파수 = 1/16000000 Hz = 0.0000000625 s = 0.0000625 ms
타이머 카운터 = 필요한 딜레이 시간 / 클록 시간 주기 – 1
255 = X / 0.0000625 ms – 1
X = 256 * 0.0000625 ms = 0.016 ms
1 ms를 만들고 싶다면... 위에서 계산한 순서대로 계산해보면 된다.
F_CPU 그대로 사용한다면
16MHz => 0.0000625 ms
1ms/0.0000625ms –1 = 15999=> 8비트 표현 범위를 넘어섬..
프리스케일러로 8을 사용한다면
16MHz / 8 = 16000000/8 = 2000000Hz => 0.0000005 s = 0.0005ms
1ms/0.0005ms –1 = 1999 => 8비트 표현 범위를 넘어섬..
프리스케일러 64를 사용한다면
16Mhz / 64 = 16000000/64 = 250000Hz => 0.000004 s = 0.004ms
1ms/0.004ms –1 = 249 => 8비트 카운터로 사용가능
프리스케일러 256을 사용한다면
16Mhz / 256 = 16000000/256 = 62500Hz => 0.000016 s = 0.016ms
1ms/0.016ms-1=61.5 => 소수점이 있음
프리스케일러 1024를 사용한다면...
16Mhz / 1024 = 16000000/1024 = 15625Hz => 0.000064 s = 0.064ms
1ms/0.064ms-1=14.625 => 소수점이 있음..
위에서 계산한 결과를 이용하여 1ms마다 오버플로우 인터럽트가 발생하도록 설정해놓았다.
프르스케일러로 64를 사용하게 되며 TCNT0의 시작값은 256-249인 7이 된다.
249는 위에서 계산한 결과 값이다.
따라서 total_overflow_count값이 1000이 될때마다 1초가 되므로
LED는 1초가 될 때마다 켜지게 된다..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /* * 8bit_timer_example.c * * Created: 2016-06-17 * Author : webnautes */ #define F_CPU 16000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> volatile uint16_t total_overflow_count; ISR(TIMER0_OVF_vect) { total_overflow_count++; TCNT0 = 7; } int main(void) { DDRB |= (1<<DDB3); //LED용 //프리스케일러로 64를 선택 TCCR0 |= (1<<CS02); //카운터 초기화 256-249 TCNT0 = 7; //타이머/카운터 오버플로우 인터럽트 활성화 TIMSK |= (1<<TOIE0); //전역 인터럽트 활성화 sei(); total_overflow_count = 0; /* Replace with your application code */ while (1) { if ( total_overflow_count == 1000 ) //1초마다 LED 켜짐 { total_overflow_count = 0; PORTB |= (1<<PB3); _delay_ms(10); } else PORTB &= (~(1<<PB3)); } } | cs |