STM32F101-107 HAL TIM2-TIM5 основа таймера и его настройка.
Схема для таймеров TIM2-TIM5.
Для настройки таймера в режиме счётчика(тактов контроллера или времени) нам понадобятся его регистры которые выделены в схеме выше.
Это следующие регистры:
PSC prescaler-делитель входящих импульсов для счётчика CNT counter;
Auto-reload register-регистр отвечает за сброс регистра счетчика CNT counter;
CNT counter-основной регистр таймера или его счётчик.
Регистры настройки таймера.
__HAL_RCC_TIMx_CLK_ENABLE()- включение тактирования соответствующего таймера.
__HAL_RCC_TIMx_CLK_DISABLE()- выключение тактирования нужного таймера.
TIM_HandleTypeDef- структура для настройки таймера.
HAL_TIM_Base_Init( TIM_HandleTypeDef *htim)- функция настраивает нужный таймер.
HAL_TIM_Base_DeInit( TIM_HandleTypeDef *htim)- сброс настроек таймера.
HAL_TIM_Base_Start( TIM_HandleTypeDef *htim)-функция запускает таймер.
HAL_TIM_Base_Stop( TIM_HandleTypeDef *htim)-функция останавливает таймер.
__HAL_TIM_GET_FLAG( TIM_HandleTypeDef *htim, TIM_FLAG)-функция проверяет флаг прерывания.
__HAL_TIM_CLEAR_FLAG( TIM_HandleTypeDef *htim, TIM_FLAG)- функция сбрасывает флаг нужного прерывания.
__HAL_TIM_SET_AUTORELOAD( TIM_HandleTypeDef *htim, data)- функция изменяет значение регистра Auto-reload register.
__HAL_TIM_GET_AUTORELOAD( TIM_HandleTypeDef *htim)- функция читает значение из Auto-reload register.
__HAL_TIM_SET_PRESCALER( TIM_HandleTypeDef *htim, data)- функция изменяет предделитель таймера PSC prescaler.
Для активации нужного таймера необходимо включить его тактирование следующей функцией.
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_TIM4_CLK_ENABLE();
__HAL_RCC_TIM5_CLK_ENABLE();
Для деактивации тактирования таймера необходимо выполнить следующие функции.
__HAL_RCC_TIM2_CLK_DISABLE()
__HAL_RCC_TIM3_CLK_DISABLE()
__HAL_RCC_TIM4_CLK_DISABLE()
__HAL_RCC_TIM5_CLK_DISABLE()
Структура для настройки таймера
TIM_HandleTypeDef;
Настраиваемые параметры структуры:
/*Выбор нужного таймера для настройки*/
.Instance =
TIM2
TIM3
TIM4
TIM5
/*Настройка перезаписи Auto-reload register*/
.Init.AutoReloadPreload =
TIM_AUTORELOAD_PRELOAD_DISABLE изменение значения Auto-reload register напрямую
TIM_AUTORELOAD_PRELOAD_ENABLE перезапись значения Auto-reload register происходит через его теневой регистр, будет изменён только после сброса CNT counter(сброс происходит когда CNT counter равен Auto-reload register)
/*Делитель для входных фильтров ETR и TIx входов, в ШИМ режиме не используется*/
.Init.ClockDivision =
TIM_CLOCKDIVISION_DIV1
TIM_CLOCKDIVISION_DIV2
TIM_CLOCKDIVISION_DIV4
/*Режимы работы CNT counter*/
.Init.CounterMode =
TIM_COUNTERMODE_UP счёт ведется от 0 до 65535 или до значения в Auto-reload register потом сброс в 0
TIM_COUNTERMODE_DOWN счёт ведётся от 65535 до 0 или до значения в Auto-reload register потом сброс в 65535
TIM_COUNTERMODE_CENTERALIGNED1 счёт ведётся от 0 до значения в Auto-reload register потом от значения в Auto-reload register до 0 и так по кругу, прерывание срабатывает при отсчёте в низ
TIM_COUNTERMODE_CENTERALIGNED2 тоже, что предыдущий только прерывание срабатывает при отсчёте вверх
TIM_COUNTERMODE_CENTERALIGNED3 тоже, что предыдущий только прерывание срабатывает при отсчёте вниз и вверх
/*Период или значение в Auto-reload register, CNT counter сбрасывается доходя до этого значения*/
.Init.Period =
значение от 0 до 65535
/*Предделитель таймера, делит входные импульсы*/
.Init.Prescaler =
значение от 0 до 65535
/*Делитель для прерывания от сброса CNT counter(сброс происходит когда CNT counter равен Auto-reload register)*/
.Init.RepetitionCounter =
значение от 0 до 255 возможно 65535 в зависимости от таймера
/*Пример настройки*/
TIM_HandleTypeDef TIM2_InitStruct;
TIM2_InitStruct.Instance = TIM2;
TIM2_InitStruct.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
TIM2_InitStruct.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TIM2_InitStruct.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM2_InitStruct.Init.Period = 65535;
TIM2_InitStruct.Init.Prescaler = 20;
TIM2_InitStruct.Init.RepetitionCounter = 0;
Функция настраивает нужный таймер.
HAL_TIM_Base_Init(TIM_HandleTypeDef *htim);
/*Функция принимает структуру для настройки таймера*/
/*Пример настройки*/
HAL_TIM_Base_Init( &TIM2_InitStruct);
Функция сбрасывает настройки таймера.
HAL_TIM_Base_DeInit(TIM_HandleTypeDef *htim);
/*Функция принимает структуру для настройки таймера*/
/*Пример использования*/
HAL_TIM_Base_DeInit( &TIM2_InitStruct);
Функция включает нужный таймер.
HAL_TIM_Base_Start(TIM_HandleTypeDef *htim);
/*Функция принимает структуру для настройки таймера*/
/*Пример*/
HAL_TIM_Base_Start( &TIM2_InitStruct);
Функция отключает нужный таймер.
HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim);
/*Функция принимает структуру для настройки таймера*/
/*Пример*/
HAL_TIM_Base_Stop( &TIM2_InitStruct);
Функция проверяет состояние флага нужного прерывания, если прерывание было то функция вернёт SET или в противном случае RESET.
__HAL_TIM_GET_FLAG( TIM_HandleTypeDef *htim, TIM_FLAG);
/*Функция принимает структуру для настройки таймера*/
TIM_HandleTypeDef *htim
/*И название проверяемого флага*/
TIM_FLAG_UPDATE Update
TIM_FLAG_CC1 Capture/Compare 1
TIM_FLAG_CC2 Capture/Compare 2
TIM_FLAG_CC3 Capture/Compare 3
TIM_FLAG_CC4 Capture/Compare 4
TIM_FLAG_COM Commutation
TIM_FLAG_TRIGGER Trigger
TIM_FLAG_BREAK Break
TIM_FLAG_CC1OF Capture/Compare 1
TIM_FLAG_CC2OF Capture/Compare 2
TIM_FLAG_CC3OF Capture/Compare 3
TIM_FLAG_CC4OF Capture/Compare 4
/*Пример*/
if(__HAL_TIM_GET_FLAG( &TIM2_InitStruct, TIM_IT_UPDATE) != RESET){}
Функция сбрасывает состояние флага если он был установлен нужного прерывания.
__HAL_TIM_CLEAR_FLAG( TIM_HandleTypeDef *htim, TIM_FLAG);
/*Функция принимает структуру для настройки таймера*/
TIM_HandleTypeDef *htim
/*И название проверяемого флага*/
TIM_FLAG_UPDATE Update
TIM_FLAG_CC1 Capture/Compare 1
TIM_FLAG_CC2 Capture/Compare 2
TIM_FLAG_CC3 Capture/Compare 3
TIM_FLAG_CC4 Capture/Compare 4
TIM_FLAG_COM Commutation
TIM_FLAG_TRIGGER Trigger
TIM_FLAG_BREAK Break
TIM_FLAG_CC1OF Capture/Compare 1
TIM_FLAG_CC2OF Capture/Compare 2
TIM_FLAG_CC3OF Capture/Compare 3
TIM_FLAG_CC4OF Capture/Compare 4
/*Пимер*/
__HAL_TIM_CLEAR_FLAG( &TIM2_InitStruct, TIM_IT_UPDATE);
Функция переписывает значения регистра Auto-reload register который отвечает за период и заставляет сбрасываться CNT counter.
__HAL_TIM_SET_AUTORELOAD(TIM_HandleTypeDef *htim, data);
/*Функция принимает структуру настройки таймера*/
TIM_HandleTypeDef *htim
/*И значение*/
от 0 до 65535
/*Пример*/
__HAL_TIM_SET_AUTORELOAD( &TIM2_InitStruct, 1000);
Функция читает значение из регистра Auto-reload register и возвращает его.
__HAL_TIM_GET_AUTORELOAD( TIM_HandleTypeDef *htim);
/*Функция принимает структуру настройки таймера*/
TIM_HandleTypeDef *htim
/*Пример*/
uint16_t DataARR = __HAL_TIM_GET_AUTORELOAD( &TIM2_InitStruct);
Функция изменяет значение предделителя таймера PSC prescaler.
__HAL_TIM_SET_PRESCALER( TIM_HandleTypeDef *htim, data);
/*Функция принимает структуру настройки таймера*/
TIM_HandleTypeDef *htim
/*И значение*/
от 0 до 65535
/*Пример*/
__HAL_TIM_SET_PRESCALER( &TIM2_InitStruct, 20);
Пример программы.
Настраиваем таймер(TIM2) и в коде проверяем переполнение его счётчика через флаг прерывания TIM_FLAG_UPDATE, если было переполнение то сбрасываем флаг и изменяем состояние вывода порта GPIOC вывод 13 на противоположное.
/*ProgCont.ru*/
#include "main.h"
int main(void)
{
HAL_Init();
/*Настраиваем вывод для контроля, подключен светодиод*/
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init( GPIOC, &GPIO_InitStruct);
/*Настраиваем таймер*/
__HAL_RCC_TIM2_CLK_ENABLE();
TIM_HandleTypeDef TIM2_InitStruct;
TIM2_InitStruct.Instance = TIM2;
TIM2_InitStruct.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
TIM2_InitStruct.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TIM2_InitStruct.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM2_InitStruct.Init.Period = 65535;
TIM2_InitStruct.Init.Prescaler = 20;
TIM2_InitStruct.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init( &TIM2_InitStruct);
HAL_TIM_Base_Start( &TIM2_InitStruct);
/*Проверяем флаг и меняем состояние вывода*/
while (1){
if(__HAL_TIM_GET_FLAG( &TIM2_InitStruct, TIM_IT_UPDATE) != RESET){
__HAL_TIM_CLEAR_FLAG( &TIM2_InitStruct, TIM_IT_UPDATE);
HAL_GPIO_TogglePin( GPIOC, GPIO_PIN_13);
}
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line){}
#endif /* USE_FULL_ASSERT */
Тут показана работа основы таймера или его счетчика(CNT counter) и регистра сравнения(Auto-reload register) который ограничивает счётчик и заставляет его сбрасываться.
Можете по экспериментировать с регистрами с помощью функций __HAL_TIM_SET_AUTORELOAD(TIM_HandleTypeDef *htim, data) и __HAL_TIM_SET_PRESCALER( TIM_HandleTypeDef *htim, data) которые буду изменять время периода таймера и соответственно время изменения состояния вывода.