주기적 타이머

컴퓨터나 임베디드시스템에서 주기적 타이머는 주기적으로 반복되는 동작을 하기 위해 디지털 하드웨어 회로에 의해 신호를 만든다. 이 신호에 따라 컴퓨터의 인터럽트 처리 방식을 사용하여 주기적인 작업을 수행하는 것이 일반적 처리 방법이다. 소프트웨어 기계어 실행없이 일정 시간을 만들 수 있기 때문에 중앙 처리 장치(CPU)의 부담을 줄일 수 있다. 클럭과 디지털회로를 사용하므로 정확한 시간을 얻을 수 있다. 컴퓨터 시스템의 필수 요소이며, 현실적으로 소프트웨어로 일정 시간을 얻는 것이 아주 간단한 시스템 아니면 기계어 코드의 복잡성 때문에 힘들어 타이머에 의존한다. 실시간 시계와 다르게 CPU의 클럭 신호를 주로 이용하여 디지털회로에 필요한 클럭을 만든다. 보통 CPU 클럭이 주파수가 높아 빠르기 때문에 프리 스켈일러(prescaler) 회로에 의해 주파수를 낮추어 타이머 모듈에 공급한다. 카운터 회로에 의해 일정 시간이 되면 인터럽트 디지털 신호를 발생하고, CPU가 접수하면 현재 실행하는 기계어 코드를 종료한 후 해당 인터럽트 처리 루틴(ISR)을 자동 호출한다. 인터럽트 발생 여부는 레지스터 설정에 의해 선택적으로 처리할 수 있다. 인터럽트를 발생하는 부분과 인터럽트를 수용하는 CPU가 처리할 것인가는 레지스터 설정에 의해 별도로 동작 시킬 수 있다. 일정 주기의 듀티를 변경하여 만드는 PWM 신호도 타이머의 카운터와 비교 회로에 의해 쉽게 만들 수 있다. 인터럽트와의 결합여부는 응용에 따라 반복적으로 같은 듀티를 사용할 수도 있고, 실행 중간에 듀티값을 변경할 수도 있다. 컴퓨터 시스템에서 마이크로컨트롤러는 하나의 칩에 여러 가지 기능을 하는 모듈이 결합되어 있고, 이중에 가장 대표적인 모듈이 주기적 타이머이다. 대부분의 마이크로컨트롤러는 타이머를 내장하고 있다. 타이머의 구성은 각 칩에 따라 성능과 기능이 다르다. 칩의 성능에 따라 제조사에서 몇개의 타이머 모듈을 넣을 지를 결정하여 다양한 모델의 마이크로컨트롤러를 만든다. AVR의 대표적 모델인 ATmega 시리즈는 8비트와 16비트 타이머를 사용한다. AVR8의 여러 가지 모델 중, 타이머 번호는 일반적으로 다음과 같이 배치되어 있다 : 타이머 0, 2: 8비트 카운터 타이머 타이머 1, 3: 16비트 카운터 타이머 카운터 비트수가 늘어나면 긴 주기의 시간을 만들 수 있으므로 시스템 사양에 따라 적절히 선택하여 사용하면 된다. AVR8 시리즈에서 사용하는 프리스케일러의 예에서, 시스템 클럭으로 최대 1024분주까지 얻을 수 있다. CS 레지스터의 값에 따라서 분주 값을 설정하여 빠르기를 조절할 수 있다. T0, T1외부 핀에서 입력되는 클럭으로 선택적으로 사용할 수 있다. ATmega328P등의 AVR8 시리즈의 타이머0는 8비트 카운터를 사용한다. 프리스케일러로부터 입력되어 선택된 클럭을 사용하여 일정한 주기를 얻을 수 있다. 동작모드를 다양하게 설정할 수 있고, 만약 인터럽트를 사용한다면 타이머의 설정한 최댓값까지 도달하면 TOV0가 설정되고, 인터럽트 가능 레지스터 설정에 따라 인터럽트 신호가 작동한다. AVR8의 인터럽트를 활용한 타이머0 프로그래밍 예 (avr-gcc 컴파일러를 사용할 경우) : #include <avr/io.h> #include <avr/interrupt.h> int main(void) { TIMSK |= (1 << TOIE0); // 인터럽트 가능하게 설정 TCCR0 |= (1 << CS01) | (1 << CS00); // 프리스케일러 64분주로 설정 sei(); // CPU가 인터럽트 받아 들여 처리 시작하게 설정 while (1) { // 시스템 전체를 제어 } } // 타이머0 오버플로워 인터럽트 핸들러 ISR (TIMER0_OVF_vect) { // 주기적인 일이 필요할 때, 해당 기능을 프로그래밍 } 처음 모델의 8051 타이머는 2개가 장착되었다. 8051이 다양한 회사에서 출시되면서, 성능도 향상과 함께 다양한 모델이 나오면서 타이머 역시 기능과 개수가 다양하다. 타이머의 동작은 다음 두가지를 선택할 수 있다. CPU의 동작 클럭을 이용하여 일정한 주기의 신호를 얻기 타이머의 클럭은 보통 CPU의 메인 클럭 신호로부터 만들어진다. 이 클럭을 기반으로 우선 프리스케일러를 통해 주파수를 낮춘다. 8051은 간단히 1/12을 사용한다. 즉, 12분주 회로를 사용하여 클럭의 속도를 낮추어 타이머 모듈의 디지털 카운터 회로에 클럭을 공급한다. 외부의 어떤 클럭 신호가 몇개의 펄스로 동작했는지를 카운터 외부의 클럭 신호를 타이머의 카운터 회로에 클럭으로 넣어 카운터 횟수를 파악할 수 있다. 즉, 어떤 클럭의 신호가 몇번 펄스가 발생했는지를 카운터하여 그 값을 프로그램으로 읽을 수 있다. 모드 설정에서 일정한 주기를 얻을 것인지 외부의 클럭신호의 카운터를 할 것인지는 레지스터 설정을 통해 일어어 진다. 모드 0: TH0[7:0]와 TL[4:0] 연결로 13비트 카운터로 0~8191까지 카운터 한다. 모드 1: TH0[7:0]와 TL[7:0] 연결로 16비트 카운터로 0~65535까지 카운터 한다. 모드 2: TL0[7:0] 8비트 카운터가 완료되면 TH[7:0] 레지스터 값이 TL0에 재 설정되어 카운터가 계속된다. 모드 3: TH0[7:0]와 TH[7:0]가 분리되어 8비트 카운터로 동작한다. 타이머 0을 사용한 프로그래밍 (Keil 통합 개발 환경) : #include <reg52.h> #include <stdio.h> /*------------------------------------------------ Timer 0 인터럽트 핸들러 - 65536 클럭 주기 ------------------------------------------------*/ static unsigned long overflow_count = 0; // 디버깅 용으로 사용 void timer0_ISR (void) interrupt 1 { overflow_count++; // 카운터 값 증가 } void main (void) { // 타이머 0 설정 : // 16비트 카운터 타이머 모드 설정 // 65535 카운터 후, 오버플로워가 발생하여 인터럽트 신호가 발생한다. TMOD = (TMOD & 0xF0) | 0x01; // T/C0 모드 설정 ET0 = 1; // 타이머 0 인터럽트 가능 설정 TR0 = 1; // 타이머 0 동작 시작 EA = 1; // 8051 코어의 인터럽트 수용하여 동작 설정 - Global Interrupt Enable while (1) { // 메인 루프 } } 인터럽트 핸들러의 표현은 표준 C/C++가 아니므로 개발환경에 따라 다르다. : /// IAR E.W. 통합 개발 환경에서 인터럽트 핸들러의 표현 /// #pragma vector=0x0b __interrupt void timer0_interrupt_handler(void) { // ... } /// SDCC 컴파일러에서 인터럽트 핸들러의 표현 /// #include <mcs51reg.h> void Timer0_ISR(void) __interrupt (1) { // ... } 인터럽트 마이크로프로세서 마이크로컨트롤러 아두이노 “ATmega Timer0,1,2,3” (PDF). 2015년 7월 24일에 원본 문서 (PDF)에서 보존된 문서. 2015년 6월 18일에 확인함.  “8051 Timer” (PDF). 2015년 6월 18일에 원본 문서 (PDF)에서 보존된 문서. 2015년 6월 18일에 확인함.  “Software Timing Loops”. 2015년 6월 18일에 원본 문서에서 보존된 문서. 2015년6월18일에 확인함.  다음 날짜 값 확인 필요: |access-date= (도움말) “Introduction to Embedded Programming Timer”. 2015년 5월 8일에 원본 문서에서 보존된 문서. 2015년6월18일에 확인함.  다음 날짜 값 확인 필요: |access-date= (도움말) “Architecture and programming of 8051 MCU's, 2.6 Counters and Timers”. 2015년 8월 14일에 원본 문서에서 보존된 문서. 2015년 8월 12일에 확인함.  “8051 타이머 0, 모드 1 예”.  지원되지 않는 변수 무시됨: |날짜확인= (도움말)