이번에는 Timer을 사용해서 stopwatch 구현해보겠습니다.
Stopwarch에는 Start 함수와 Stop 함수가 있고 각 조건은 아래와 같습니다.
Start 함수: TIM 주파수 -> 50kHz(20us tick), CNT -> 최대 값(0xFFFF)로 설정
Stop 함수: TIM2를 정지하고 경과된 펄스수를 이용, 경과 시간 리턴(usec 단위)
// timer.c
#include "device_driver.h"
#define TIM2_TICK 20 // usec
#define TIM2_FREQ (1000000./TIM2_TICK) // Hz
#define TIM2_CNT_MAX 0xFFFF
void TIM2_Stopwatch_Start(void)
{
Macro_Set_Bit(RCC->APB1ENR, 0);
// TIM2 CR1 설정: down count, one pulse
TIM2->CR1 = (0x3<<3);
// PSC 초기값 설정 => 20usec tick이 되도록 설계 (50KHz)
TIM2->PSC = (int)((TIMXCLK / TIM2_FREQ) + 0.5) - 1;
// ARR 초기값 설정 => 최대값 0xFFFF 설정
TIM2->ARR = TIM2_CNT_MAX;
// UG 이벤트 발생
Macro_Set_Bit(TIM2->EGR, 0);
// TIM2 start
Macro_Set_Bit(TIM2->CR1, 0);
}
TIM2_Stopwatch_Start() 함수부터 자세하게 알아보겠습니다.
**Macro_Set_Bit(RCC->APB1ENR, 0)**에서 APB1 버스 클럭을 TIM2에 공급합니다. **TIM2->CR1 = (0x3<<3)**에 3번부터 2개의 bit를 1로 만듭니다. 이는 one pulse mode, down count로 동작하도록 설정하는 것입니다.
TIM2->PSC = (int)((TIMXCLK / TIM2_FREQ) + 0.5) - 1는 **프리스케일러 설정으로 20usec tick(50kHz)**가 되도록 설정하였습니다. 즉 1 tick이 정확하게 20us가 되도록 프리스케일러를 설정한 코드입니다.
설계한 Stopwatch는 one pulse/down count 모드이기 때문에 TIM2->ARR = TIM2_CNT_MAX에서 ARR의 초기값을 최대값인 0xFFFF로 설정하였습니다. **Macro_Set_Bit(TIM2->EGR, 0)**으로 위에서 정의한 PSC, ARR 레지스터들의 설정값을 CNT에 즉시 반영하도록 트리거 하였습니다.
이후에 **Macro_Set_Bit(TIM2->CR1, 0)**으로 타이머를 시작하였습니다.
// timer.c
unsigned int TIM2_Stopwatch_Stop(void)
{
unsigned int time;
// TIM2 stop
Macro_Clear_Bit(TIM2->CR1, 0);
// CNT 초기 설정값 (0xffff)와 현재 CNT의 펄스수 차이를 구하고
// 그 펄스수 하나가 20usec이므로 20을 곱한값을 time에 저장
time = (TIM2->ARR - TIM2->CNT) * TIM2_TICK;
// 계산된 time 값을 리턴(단위는 usec)
return time;
}
다음은 TIM2_Stopwatch_Stop() 함수에 대해 알아보겠습니다.
**Macro_Clear_Bit(TIM2->CR1, 0)**은 타이머를 중지하는 코드입니다.
우리가 결과적으로 반환해아 하는 값은 Stopwatch가 동작한 시간입니다. 따라서 타이머의 초기값인 TIM2->ARR에서 현재 카운팅 된 TIM2->CNT의 pulse 수 차이를 구하고 1tick 당 20us이므로 구하려고 하는 시간은 다음과 같습니다.
time = (TIM2->ARR - TIM2->CNT) * TIM2_TICK 으로 구할 수 있고 time을 return 함으로써 시간을 구할 수 있습니다.
// main.c
void Main(void)
{
int i;
Sys_Init();
Uart1_Printf("TIM2 stopwatch test\\n");
for(i=1; i<=10; i++)
{
LED_Display(i%4);
TIM2_Stopwatch_Start();
SysTick_Run(100*i);
while(!SysTick_Check_Timeout());
SysTick_Stop();
Uart1_Printf("[%d] Elapsed Time = %f msec\\n", i, TIM2_Stopwatch_Stop()/1000.);
}
}
main.c 파일에서는 for 문을 통해 총 10번 동안 TIM2으로 측정한 경과 시간을 msec로 변환하여 TIM2_Stopwatch_Stop()/1000. 를 통해 출력합니다.