이번에는 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. 를 통해 출력합니다.