본문 바로가기
DSP, MCU/STM32 (ARM Cortex-M)

STM32 , Timer Interrupt 타이머 인터럽트 사용하기 (TIM2)

by eteo 2022. 5. 25.

 

 

이전의 동기식 / 비동기식 카운터 프로그래밍으로 구현하기 글에서 이어진다.

 

2022.05.23 - [MCU/STM32 (ARM Cortex-M)] - STM32 , 동기식 / 비동기식 카운터 프로그래밍으로 구현하기 ( + Timer 사용 방법 )

 

STM32 , 동기식 / 비동기식 카운터 프로그래밍으로 구현하기 ( + Timer 사용 방법 )

4비트 상향 카운터 4비트 하향 카운터 main.h 먼저 main.h 에 플립플롭에 필요한 변수들을 묶어 구조체로 정의해주었다. 함수에 매개변수를 여러개 둘 필요없이 보다 간략하게 짤 수 있다. /* USER CODE

eteo.tistory.com

 

 

프로젝트 파일은 위 글 똑같고 while문 내에서 지역변수를 토글시키며 HAL_Delay(500) 한 이전버전과 달리 Timer 인터럽트 기능을 사용해 카운터함수에 클락펄스를 준 버전이다.

 

 

 

 

이번에 사용한건 General Purpose Timer 인 TIM2이고,

 

레퍼런스 매뉴얼 67페이지 참고. TIM2는 APB1을 사용한다.

 

 

 

 

 

Clock Configuration 가서 확인하면 APB1 Timer Clocks 는 90MHz이다.

 

 

 

 

 

TIM2 - Clock Source를 Internal Clock 으로 선택 하고 아래와 같이 설정

 

 

Parameter Settings 에서

 

Counter mode는 Up이고

Prescaler를 8999, ARR (AutoReload Resister = Counter Period)를 1249로 설정해 주었다.

너무 느리게 깜빡이면 답답하기 적당히 넣어준 값이다.

 

만약 시계를 구현하기 위해 1Hz를 뽑아낸다면,

90,000,000 / (Prescaler * ARR) = 1이 되도록 8999, 9999 로 설정하면 될 것 같다.

 

 

그리고 -1 한 이유는 카운터가 0부터 세기 때문이다. 8999 대신 9000-1 이런식으로 적어두면 더 직관적이다.

 

 

 

 

참고사진.

 

Prescaler 역할은 버스를 통해 공급되는 클락을 1~65,536 범위 내의 원하는 값으로 분주하는 것이고,

up 카운터의 경우 Counter(CNT)의 값이 계속 증가하다가 ARR(Auto-Reload Regiter)의 값과 동일해지면 Overflow 가 나서 인터럽트가 트리거되며 CNT의 값은 다시 0으로 돌아간다.

 

http://embeddedsystemengineering.blogspot.com/2015/08/stm32f4-discovery-tutorial-9-timer.html

 

 

 

 

인터럽트를 쓸거기 때문에 TIM2의 파라미터 세팅 위의 NVIC 세팅에서 interrupt를 Enabled 해준다.

 

 

 

 

 

 

Generate Code 후 소스코드 작성하러 간다.

 

 

 

 

 

보드 실행시 바로 시작되는 Systick timer와 달리 다른 타이머는 Start 함수를 써주어야 한다. main 함수내의 MX_TIM2_Init(); 아래 위치한 USER CODE BEGIN 2 부분에 썼다.

 

타이머 인터럽트를 사용하기 때문에 HAL_TIM_Base_Start_IT( ) 함수를 사용했으며 인수로 들어간 &htim2는 MX툴에서의 Generate Code에 의해 상단에 구조체로 선언된 것을 확인할 수 있다.

 

  /* Private variables ---------------------------------------------------------*/
  
  TIM_HandleTypeDef htim2;
  
  //중략..

  /* Initialize all configured peripherals */
  MX_TIM2_Init();
  
  //중략..
  
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim2);

 

 

 

 

 

 

전역변수로 ClockFlag를 선언하고, main 함수 바깥(USER CODE BEGIN 0)에 HAL_TIM_PeriodElapsedCallback 함수를 썼다. 이 함수의 정의는 stm32f4xx_hal_tim.c 에 있으며 복붙으로 가져와 사용하면 된다.

 

MX에서 파라미터 세팅 해준 값에 따르면 90MHz/((8999+1)*( 1249+1)) = 8Hz 가 TIM2 의 동작 주파수가 되고, 이때마다 인터럽트가 발생해 이 콜백 함수가 호출된다.

 

/* USER CODE BEGIN PV */

uint8_t ClockFlag = 0;

/* USER CODE END PV */

// 중략

/* USER CODE BEGIN 0 */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	ClockFlag ^= 0x01;
}

/* USER CODE END 0 */

 

호출될 때 마다 ClockFlag를 0이면 1, 1이면 0으로 토글해준다.

 

 

 

 

 

 

그리고 while문에서는 이전글에서 main함수의 지역변수로 선언한 clock 토글시키는 부분이랑 HAL_Delay(500); 을 주석처리 해주고 대신 타이머 인터럽트에 의해 토글되는 전역변수 ClockFlag 를 카운터 함수의 인수로 전달하면 끝이다. 아주 잘 동작한다.

 

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  //clock ^= 1;

	  ttl7490(jkff, ClockFlag); // can use ClockFlag also and delete HAL_Delay.


	  for(int i=0; i<4 ; i++){
		  if(jkff[i].Q)
			  GPIOD->ODR |= (0x80 >>i);
		  else
			  GPIOD->ODR &= ~(0x80 >>i);
	  }

	  //HAL_Delay(500);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }