Таймеры на STM32. Настройка базового таймера

В данном примере попробуем настроить самый простой таймер STM32Под простым таймером будем понимать таймер с минимально возможными настройками. Для платы stm32f3discovery это таймер TIM2. Будем генерировать или выходить в прерывания с определенным интервалом, в методе прерывания будем изменять состояние вывода порта. У в нашем примере для нашей платы это вывод 8 на порте E.

Перед тем как начать работу с таймером, нам необходимо с начала подключить следующие файлы:

#include "stm32f30x.h"                  
#include "stm32f30x_rcc.h" 
#include "stm32f30x_tim.h" 
#include "stm32f30x_gpio.h"  

Первый файл импортируется по умолчанию и необходим для базовых настроек контроллера.

Файл с суффиксом RCC необходим для включения тактирования переферии микроконтроллера. Перед тем как использовать какую либо перефирию сначала на нее необходимо включить, подавая на нее тактовые импульсы, именно для этого и предназначен данный файл.

Файл с суффиксом TIM содержит все необходимы методы константы и переменные для настройки таймера.

Файл с суффиксом GPIO необходим для настройки порта. Подробнее о том что такое порты микроконтроллера stm32 было сказано в предыдущей статье.

Объевляем структуру таймера и порта

GPIO_InitTypeDef GPIO_InitStructure;       //Структура для настройки порта
TIM_TimeBaseInitTypeDef TIM_InitStructure; //Структура настройки таймера   

Структура представляет собой некий объект который содержит в себе ряд переменных которым нужно присвоить определенные значения. Названия всех структур и возможные значения переменных можно посмотреть в файле stm32f30x_tim.h - для таймера и stm32f30x_gpio.h - для порта.

Включаем тактирование переффирии

void rccinit(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
} 

Данные методы включают тактирование порта и таймера TIM2. Подробнее в фале stm32f30x_rcc.h

Инициализируем таймера TIM2

void init_timer(void)
{ 
TIM_InitStructure.TIM_Prescaler = 48000-1;   			
TIM_InitStructure.TIM_Period = 1000;   
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);	
TIM_Cmd(TIM2, ENABLE); 													
NVIC_EnableIRQ(TIM2_IRQn);  
} 

Очень важно соблюдать последовательность кода. Не правильно написанный код работать не будет, даже при условии хорошей компиляции иотсутсвии ошибок и предупреждений.  Настраивая данный таймер я убил около получаса на то чтобы найти ошибку. Она была в прямом смысле перед носом. Оказывается что перед тем как произвести инициализацию таймера при помощи кода

TIM_TimeBaseInit(TIM6, &TIM_InitStructure); 

Нужно сначала настроить структуру таймера TIM_InitStructure.

Код компилировался без ошибок и без проблем заливался в плату. Но так таймер был настроен "пустой" - непроинициализированной структурой, плата не подавала признаков жизни и лампочка не мигала должным образом, а точнее вообще не мигала.

Следующие строчкой мы настраиваем предделитель. Наш таймер затактирован от шины с частотой в 48Мгц. Выставляя предделительв 48000-1 мы тем самым делим тактовую частоту. В итоге наш таймар начинает "тикать" с частотой 48000000/48000=1000Гц. Т.е. за 1 секунду таймер сосчитает до 1000. Для того чтобы таймер каждую тысячу тиков сбрасывал свое значение нам нужно установить период. При помощи следующей конструкции:

TIM_InitStructure.TIM_Period = 1000;

В процессе счета таймер сравнивает свое текущее значение с установленным в структуре, если эти значения совпадают то происходит прерывание по переполнению. И наша программа уход в прерывание. Для того чтобы объяснить таймеру что нужно срабатывать при переполнении пользуемся методом

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

Следующие два метода включают таймер и разрешают прерывание.

TIM_Cmd(TIM2, ENABLE); 													
NVIC_EnableIRQ(TIM2_IRQn);

Настраиваем порт микроконтроллера

void init_led(void)
{
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
} 

Как настаивать порты было сказано ранее. Не будем на этом заморачиваться)

Метод прерывания таймера TIM2

void TIM2_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		if(state)
		{GPIO_SetBits(GPIOE,GPIO_Pin_8);state=0;}
		else {GPIO_ResetBits(GPIOE,GPIO_Pin_8);state=1;}
  }
}
Метод прерывания таймера, в данном методе происходит изменения состояния вывода 8 порта E.
Исходный код настройки таймера

#include "stm32f30x.h"                 
#include "stm32f30x_rcc.h" 
#include "stm32f30x_tim.h" 
#include "stm32f30x_gpio.h" 
uint16_t state=1;
void TIM2_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		if(state)
		{GPIO_SetBits(GPIOE,GPIO_Pin_8);state=0;}
		else {GPIO_ResetBits(GPIOE,GPIO_Pin_8);state=1;}
  }
}

GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_InitStructure; 
void rccinit(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
}
void init_led(void)
{
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
}
void init_timer(void)
{ 
TIM_InitStructure.TIM_Prescaler = 48000-1;   			
TIM_InitStructure.TIM_Period = 1000;   
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);	
TIM_Cmd(TIM2, ENABLE); 													
NVIC_EnableIRQ(TIM2_IRQn);  
}
int main(void)
{
	rccinit();
	init_led();
	init_timer();	
	
while(1) 
{
__NOP();
}
}

 

Комментарии  

 
#1 Miha 23.01.2015 12:39
Во норм пример, сразу заработал. Спс автору, долго не мог разобраться)
Цитировать
 
 
#2 Андрей 22.10.2015 13:27
А если я хочу получать прерывания при каждом изменении значения таймера (или при каждом четвертом), но чтобы он при этом не обнулялся?
Цитировать
 

Добавить комментарий


Защитный код
Обновить

Последние комментарии

Последнии темы форума

  • Нет сообщений для показа