необходимые документы - RM, AN4013- STM32 cross-series timer overview, AN4776 -General-purpose timer cookbook
Time base generator является основой любого таймера STM, как STM8 так и STM32 и по сути это сердце таймера
Time base generator определяет временные характеристики таймера.
Состав Time base generator :
CNT- Counter Счетчик таймера
PSC - Prescaler Прескалер - предделитель
ARR - Auto reload Регистр автоперезагрузки
Опционально:
RCR - Repetition counter счетчик повторов
Рассмотрим частный случай работы таймера - режим счетчика, счет вверх.
Счетчик инкриминируется (увеличивается) с частотой определяемой в PSC .
Счетчик считает с 0 до значения в ARR.
Если в Time base generator нет Repetition counter(RCR) либо его значение равно 0,
то при достижении счетчиком значения равного тому что занесено в ARR,
счетчик сбрасывается ,
генерируется событие Update и выставляется флаг прерывания UIF: Update interrupt flag
Если значение RCR отлично от 0, то генерация события Update и установка флага прерывания UIF: Update interrupt flag
произойдут только после переполнения счетчиком количество раз равному значению в RCR.
Диаграммы поясняющие работу таймера.
ARR=36
Действие RCR - Repetition counter
Таким образом частота Update_event = TIM_CLK/((PSC + 1)*(ARR + 1)*(RCR + 1))
Где:
TIM_CLK - тактовая TIMx
PSC -значение предделителя
ARR - значение регистра ARR(по сути период)
RCR - значение RCR
Подставляем значения:
TIM_CLK - 48 000 000 Hz
PSC - 48 000-1
ARR - 500-1
RCR -0
48 000 000/((47999 + 1)*(499+ 1)*(0 + 1)) =2
Применим на практике.
чип F0, таймер TIM2, частота тактирования таймера 48MHz, выхлоп на PA1 -2Hz.
Определяем необходимые тайминги.
define TIMx_CLK 48000000UL // Hz #define TIMx_Internal_Frequency 1000UL // Hz #define TIMx_Out_Frequency 2UL // Hz #define Prescaler (TIMx_CLK /TIMx_Internal_Frequency)-1UL #define Period (TIMx_Internal_Frequency/TIMx_Out_Frequency)-1UL
Включаем тактирование таймера и PORTA для наблюдения за процессом.
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
Конфигурируем пин .
GPIOA->MODER &=~GPIO_MODER_MODER1; GPIOA->MODER |= GPIO_MODER_MODER1_0 ;
Загружаем регистры таймера.
TIM2->PSC = Prescaler; TIM2->ARR = Period;
Разрешаем прерывания от Update и запускаем счетчик.
TIM2->DIER |= TIM_DIER_UIE; TIM2->CR1|=TIM_CR1_CEN;
Включаем прерывание TIM2.
NVIC_SetPriority(TIM2_IRQn,0); NVIC_EnableIRQ(TIM2_IRQn);
Само прерывание. Инвертируем состояние пина и сбрасываем флаг прерывания.
void TIM2_IRQHandler (void) { GPIOA->ODR ^= GPIO_ODR_1; TIM2->SR = ~TIM_SR_UIF; }
Код целиком.
#define TIMx_CLK 48000000UL // Hz #define TIMx_Internal_Frequency 1000UL // Hz #define TIMx_Out_Frequency 2UL // Hz #define Prescaler (TIMx_CLK /TIMx_Internal_Frequency)-1UL #define Period (TIMx_Internal_Frequency/TIMx_Out_Frequency)-1UL void TIM2_IRQHandler (void) { GPIOA->ODR ^= GPIO_ODR_1; TIM2->SR = ~TIM_SR_UIF; } void tim2_led_init(void) { RCC->AHBENR |= RCC_AHBENR_GPIOAEN; RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; GPIOA->MODER &=~GPIO_MODER_MODER1; GPIOA->MODER |= GPIO_MODER_MODER1_0 ; TIM2->PSC = Prescaler; TIM2->ARR = Period; TIM2->DIER |= TIM_DIER_UIE; TIM2->CR1|=TIM_CR1_CEN; NVIC_SetPriority(TIM2_IRQn,0); NVIC_EnableIRQ(TIM2_IRQn); }