아두이노 타이머 (Hardware timer)

주기적으로 반복되는 동작을 요하는 경우에는 정확한 시간 뒤 특정한 코드가 실행될 수 있도록 타이머를 사용하게 됩니다. 타이머는 알람처럼 시간 관련된 이벤트를 위해 설계된 함수입니다.

아래 내용이 어려우시다면 1, 2, 6, 7, 8 번 항목만 참고하세요.

.

1. 아두이노에서의 타이머

비록 아두이노 프로그래밍을 할 때 타이머를 사용하는 경우는 흔치 않지만, 역설적이게도 타이머는 흔히 사용되는 함수 중 하나입니다. 왜냐면 아두이노의 시간관련 함수들 – delay(), millis(), micros(), delayMicroseconds(), PWM 함수인 analogWrite() 및 tone(), noTone() 함수들 및 서보모터 라이브러리 등이 내부적으로는 타이머를 사용하기 때문입니다.

타이머는 (혹은 카운터라 불리우는 것들은) 아두이노 컨트롤러에 내장된 하드웨어의 한 구성요소입니다. 그리고 사용자는 특별한 레지스터들을 이용해서 타이머의 동작방식, 주기 등등을 프로그래밍 할 수 있습니다.

아두이노의 Atmel AVR ATmega168, ATmega328 컨트롤러는 3개의 타이머 – timer0, timer1, timer2 를 가지고 있습니다. timer0, timer2 는 8비트 타이머고 timer1은 16비트 타이머입니다. 8비트와 16비트 타이머의 차이점은 해상도입니다. 8비트는 256단계의 값을 가지고 16비트는 65536 단계의 값을 가지고 있습니다. (ATmega1280, ATmega2560 칩은 6개의 타이머를 제공합니다. timer0, timer1, timer2 는 ATmega128/328 과 동일한데 timer3, timer4, timer5는 16비트 타이머로 동작합니다.)

모든 타이머는 아두이노의 시스템 클럭에 종속적입니다. 일반적으로 시스템 클럭이 16MHz 이므로 여기에 맞춰 아래 내용을 보셔야 합니다. Pro mini 보드와 같이 8MHz 로 동작하는 경우는 다르게 적용됩니다.

타이머 하드웨어는 특별한 타이머 레지스터에 의해 설정됩니다. 아두이노 펌웨어에서는 모든 타이머가 1kHz frequency 로 맞춰져 있고, 인터럽트가 활성화되어 있습니다.

.

2. Timer0, Timer1, Timer2

Timer0 는 8비트 타이머로 시간관련 함수에 사용되고 있습니다. 따라서 Timer0 레지스터를 변경하면 delay(), millis(), micros() 와 같은 시간관련 함수들도 영향을 받게 됩니다.

Timer1 은 16비트 타이머입니다. 아두이노 UNO 보드의 경우 서보모터 라이브러리(Servo)가 Timer1을 사용합니다. (아두이노 Mega 보드에서는 Timer5 를 사용)

Timer2 는 8비트 타이머로 tone() 함수 등에 사용됩니다.

.

3. 타이머 레지스터 (Timer Register)

타이머 레지스터를 통해 타이머 동작을 바꿀 수 있습니다. 레지스터는 아두이노 시스템 영역에서 사용하는 설정 값 정도로 보시면 되겠습니다. 가장 중요한 타이머 레지스터는 TCCRx (Timer/Counter Control Register) 입니다.

tccr1a

tccr1b

  1. TCNTx – Timer/Counter Register. 실질적인 타이머 동작 값이 여기에 저장됩니다.
  2. OCRx – Output Compare Register
  3. ICRx – Input Capture Register (16비트 타이머용)
  4. TIMSKx – Timer/Counter Interrupt Mask Register. 타이머 인터럽트 활성화/비활성화 용도
  5. TIFRx – Timer/Counter Interrupt Flag Register. pending timer interrupt 용도인지 표시

.

4. 동작 클럭과 타이머 주기 (Clock select and timer frequency)

CPU 동작 클럭에 따라 타이머 주기(timer frequency)는 아래와 같이 결정됩니다.

  1. CPU 동작 주기 = 16MHz
  2. 최대 타이머 카운트 (8비트는 256, 16비트는 65536)
  3. CPU 주기를 선택한 prescaler 로 나눔 (16000000 / 256 = 62500)
  4. 결과값을 다시 원하는 주기로 나눔 (62500 / 2Hz = 31250)
  5. 결과값을 최대 카이머 카운트와 비교 (31250 < 65536 : 적합). 적합하지 않은 경우 더 큰 prescaler 를 선택함

.

5. 레지스터와 타이머 동작

타이머 모드 (Timer modes)

타이머는 여러가지 타이머 모드로 설정할 수 있습니다. 예를 들어, PWM 모드에서는 OCxy output 값이 PWM 신호를 생성하기 위해 사용됩니다. CTC(Clear timer On Compare match) 모드에서는 타이머 카운터가 compare match register 값에 도달할 때 타이머가 삭제됩니다.

레지스터에 따라 변화되는 모드는 아래 표를 참고하세요.

waveform-gen

타이머 인터럽트 (Timer interrupts)

인터럽트에 대한 기본내용은 아래 링크를 참고하세요.

https://www.hardcopyworld.com/?p=594

Pending interrupt 가 ISR(Interrupt Service Routine)을 실행하기 위해서는 아래 조건이 활성화 되어야 합니다.

  • 인터럽트가 활성화 되어야 함
  • 관련된 인터럽트 마스크가 활성화 되어야 함.

인터럽트는 interrupts(), noInterrupts() 함수로 활성화/비활성화 할 수 있습니다. 아두이노의 기본설정은 인터럽트 활성화 상태입니다. 인터럽트 마스크는 interrupt mask register(TIMSKx) 에서 setting/clearing bit 를 설정함으로써 활성화/비활성화 할 수 있습니다.

인터럽트가 발생할 때 interrupt flag register(TIFRx) 값이 설정됩니다. 이 값에 따라 ISR(Interrupt Service Routine)이 실행되고, 실행 후 자동으로 해제됩니다. 혹은 수동으로 값을 변경할 수 있습니다.

일반적으로 코드에서 attachInterrupt(), detachInterrupt()  함수에 의해 설정되는 인터럽트는 외부 인터럽트 핀에의해 활성화 됩니다. 이것들은 다른 인터럽트 소스이므로 여기서는 논외로 합니다.

타이머는 여러종류의 타이머 인터럽트를 발생시킬 수 있습니다. 레지스터와 비트 설정 값은 아두이노의 프로세서 데이터 시트를 참고하세요. (Atmega328 or Atmega2560). suffix x 는 타이머 숫자 (0~5)를 의미하고 suffix y 는 출력 값 (A, B, C)을 의미합니다.  예를들어 TIMSK1 = timer1 interrupt mask register, OCR2A = timer2 output compare register A 입니다. 아래에서 연관된 설명이 이어집니다.

Timer overflow

타이머 오버플로우는 타이머 카운트가 최대값에 도달함을 의미합니다. 타이머가 오버플로우되면 인터럽트가 발생하고 timer overflow bit (TOVx) 값이 interrupt flag register(TIFRx) 에 설정됩니다. 만약 interrupt mask register(TIMSKx)에 timer overflow interrupt enable bit(TOIEx) 값이 설정되어 있다면 interrupt service routine – ISR(TIMERx_OVF_vect) 함수가 호출될 것입니다.

Output Compare Match

OCFxy 플래그가 interrupt flag register(TIFRx) 에 설정되면 Output compare match interrupt 가 발생합니다. Output compare interrupt 가 발생하면 interrupt mask register(TIMSKx) 에 output compare interrupt enable bit(OCIExy) 값이 설정됩니다. 그리고 output compare match interrupt service – ISR(TIMERx_CAPT_vect) 함수가 호출될 것입니다.

Timer input capture

Interrupt flag register(TIFRx)에 input capture flat bit (OCFxy) 가 설정되어 있으면 Timer input capture interrupt 가 발생합니다. Interrupt mask register(TIMSKx) 에 input capture interrupt enable bit (ICIEx) 가 설정되면 timer input capture interrupt service routine – ISR(TIMERx_CAPT_vect) 함수가 실행됩니다.

PWM 과 timer

타이머와 PWM 핀은 밀접하게 연관되어 있습니다. 프로세서의 핀아웃 문서나 데이터 시트를 보면 OCRxA, OCRxB, OCRxC 로 표기된 PWM 핀이 있습니다. (x는 타이머 숫자 0~5) Mega를 제외한 일반적인 아두이노는 3개의 타이머와 6개의 PWM 핀이 있으며 아래와 같이 연관되도록 설정되어 있습니다.

  • Pin 5, 6 : timer0 에 의해 컨트롤
  • Pin 9, 10 : timer1 에 의해 컨트롤
  • Pin 11, 3 : timer2 에 의해 컨트롤

6. 주의사항

서보 라이브러리(Servo library)는 Timer1 을 사용합니다. 서보 라이브러리를 사용할 경우 9, 10번 PWM 은 사용할 수 없습니다. 아두이노 Mega 보드의 경우는 좀 더 복잡해서 사용하는 서보의 갯수에 따라 제한이 바뀝니다. 아래 링크를 참고하세요.

http://letsmakerobots.com/content/arduino-101-timers-and-interrupts

tone() 함수는 적어도 timer2 를 사용합니다. 이 경우 3, 11번 핀의 PWM을 사용할 수 없습니다. Mega 보드의 경우는 9, 10번 핀을 사용할 수 없습니다.

7. 라이브러리

타이머 레지스터를 수정해가며 타이머를 사용한다는 것은 굉장히 소모적이고 복잡한 방법입니다. 따라서 보다 간편하게 사용할 수 있는 아래 라이브러리를 추천합니다. 물론 세부적으로 원하는 컨트롤을 요하는 경우 위와 같은 방법을 사용할 수도 있겠지만요.

Timer1,  Timer3 라이브러리 : ATmega128/328 의 16비트 타이머(Timer1)를 설정해주는 라이브러리입니다. 일반적인 라이브러리 설정경로와는 다르게 (Arduino/hardware/libraries/) 에 설치하셔야 합니다. Mega 보드에서는 Timer3 라이브러리를 사용하시길 추천합니다.

타이머를 이용한 IR 리모트 컨트롤 예제 및 라이브러리

SW Timer 라이브러리, SimpleTimer, Metro :  아두이노에 built-in 된 hardware 타이머를 직접 사용하는 방식이 아니라 단순히 millis() 함수를 이용해서 타이머를 구현한 라이브러리. 단순하고 하드웨어적인 정밀도와 제어가 필요치 않은 경우 유용.

8. 예제

아래 링크 하단부에 타이머를 직접 설정해서 사용하는 예제가 있습니다.

http://letsmakerobots.com/content/arduino-101-timers-and-interrupts

참고자료 :

아두이노 공식 페이지 : http://letsmakerobots.com/content/arduino-101-timers-and-interrupts,  http://playground.arduino.cc/Code/Timer1

타이머 설정 방법(instructables.com) : http://www.instructables.com/id/Arduino-Timer-Interrupts/

Timer and Interrupts : http://letsmakerobots.com/content/arduino-101-timers-and-interrupts

You may also like...