STM32 STM32VL Discovery STM32F100RBT6 (урок 4) Basic timers, таймеры
Восстановленные материалы удаленного сайта www.doneathome.ru
По многочисленным просьбам пользователей попробую восстановить
STM32VL Discovery STM32F100RBT6 (урок 4) Basic timers, таймеры
Таймер – одна из самых полезных вещей в микроконтроллере и основная его задача – отсчитывание точных интервалов времени. На отладочной плате STM32VL Discovery установлен микроконтроллер STM32F100RBT6, который имеет следующие таймеры:
Basic timers (TIM6, TIM7) – самый простой таймер, который умеет только генерировать прерывания в заданный промежуток времени, но при этом очень легко настраивается и управляется.
General-purpose timers (TIM2-TIM4, TIM15-TIM17) – более продвинутый таймер, позволяющий генерировать ШИМ, считывать состояние ног, обрабатывать данные от энкодера и т.д.
The advanced-control timers (TIM1) – самый продвинутый таймер, может использоваться как трехфазный ШИМ генератор, например для управления трехфазными электродвигателями.
Устройство Базовых таймеров/счётчиков. Basic Timers
Набор разных сведений про базовые таймеры/счётчики. Basic Timers
1) Как называется обработчик для определенного прерывания
В этом файле смотрим прототипы обработчиков startup_stm32f10x_md_vl.c
2) Изменение пред делителя в любой момент
Менять можно когда угодно но оно поменяется после прерывания
3) Принудительный вызов прерывания
Можно программно вызвать принудительно вызвать (UDE) или (UIF)
Регистры (TIM6 & TIM7)
TIMx_CR1 [0x0000]
Описание: Регистр управления 1.
Биты:
Bit 7 ARPE: Auto-reload preload enable
Описание: Бит управления буферизацией регистра TIMx_ARR (смена происходит моментально или после события прерывания)
Bit 3 OPM: One-pulse mode
Описание: Ставится для включения режима одиночного счета счетчика.
Bit 2 URS: Update request source
Описание: Бит выбирает возможные источники для прерывания и DMA (1 – только переполнение счетчика)
Bit 1 UDIS: Update disable
Описание: Бит разрешает/запрещает возможность генерирования прерывания или DMA.
Интересно что разрешение это ’0′, а запрет ’1′(для уверенности уточните в документации)
Bit 0 CEN: Counter enable
Описание: Бит вкл/выкл работы таймера. (1 – счет запущен)
TIMx_CR2 [0x0000]
Описание: Регистр управления 2. Эти биты устанавливают значение выходного сигнала в режиме “Master – Slave”, когда один таймер управляет другими устройствами в составе микроконтроллера.
Биты:
Bits 6:4 MMS[2:0]: Master mode selection
000 – формируется сигнал RESET (бит UG)
001 – формируется сигнал ENABLE (бит CEN)
010 – формируется сигнал UPDATE (таймер досчитал)
TIMx_DIER [0x0000]
Описание: Здесь всего два значащих бита, которые разрешают запрос DMA и генерацию прерывания – UDE (DMA) и UIE (прерывание). “1” – можно, “0” – нельзя. (разрешается единицей).
Биты:
Bits 8 UDE: Reserved, must be kept at reset value.
Описание: Этот бит ставится программно, разрешить UDE (DMA).
Bits 0 UIE: Update interrupt enable
Описание: Этот бит ставится программно, разрешить UIE (прерывание).
TIMx_SR [0x0000]
Описание: Это регистр статуса. Всего один значащий бит UIF – флаг прерывания. умолчанию. Устанавливается в единицу.
Биты:
Bits 8 UIF: Update interrupt flag.
Описание: Этот бит ставится аппаратно, (UIF) – флаг прерывания.
TIMx_EGR [0x0000]
Описание: Это регистр статуса. Всего один значащий бит UG. Его установка (программно) принудительно вызовет формирование события – прерывание или запрос DMA.(зависит от того что разрешено)
Биты:
Bits 8 UG: Update generation.
Описание: Этот бит ставится программно, чтобы принудительно вызвать (UDE) или (UIF) .
TIMx_CNT [0x0000]
Описание: Этот регистр содержит значение счета, так как это счетный регистр. Каждый такт частоты увеличивает значение этого счетчика на единицу. Необходимо предварительно включить таймер.
TIMx_PSC [0x0000]
Описание: Этот регистр содержит биты для определения результирующей частоты работы счетчика. Вот формула расчета результирующей частоты работы (частота называется CK_CNT) расчет fck/(PSC[15:0] + 1)
TIMx_ARR [0x0000]
Описание: Этот регистр содержит биты, которые определяют до какого значения надо досчитывать счетчику. Это регистр автоперезагрузки (сравнения).
Практика
Порядок запуска таймера таков:
1. Подать тактирование на выбранный таймер. Через RCC. Все таймеры сидят на шине APB1, и, соответственно, включаются с помощью регистра RCC_APB1EN.
2. Назначить предделитель, записав необходимое число в регистр TIMx_PSC (это необходима для формирования частоты счета, которая считается исходя из частоты шины APB1). Частота счёта будет определяться как Ftclk / (TIMx_PSC + 1). Например, если частота шины APB1 24 МГц, а TIMx_PSC равен 2399, то частота счёта (с какой скоростью будет увеличиваться значение счётчика) будет равна 24 / (2399 + 1) = 1 МГц.
3. Назначить максимальное значение счётчика, при коем он будет перезагружаться, записав его в TIMx_ARR. При наличии там нуля, таймер работать не будет.
4. Установить флаг разрешения счёта (CEN в TIMx_CR1).
Пример
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
void Init_Pin (void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); // это функция разрешения тактирования порта С
GPIO_InitTypeDef Pinyshka; // создаём переменную (структуру) для ножки
// заполняем поля структуры для определения режима ножки(ЗАМЕТИМ определение 2-ух ножек)
Pinyshka.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_8; // определяем ножки!!! порта
Pinyshka.GPIO_Mode = GPIO_Mode_Out_PP; // определяем режим работы ножки
Pinyshka.GPIO_Speed = GPIO_Speed_50MHz; // так как режим на выход то определяем скорость работы ножки
// этой функцией мы определяем работу ножек (ссылка на заполненную структуру ножки) + (указываем порт необходимых нам ножек)
GPIO_Init( GPIOC , &Pinyshka);
}
void Init_timer(void){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); // включаем тактирование таймера
// Другие параметры структуры TIM_TimeBaseInitTypeDef не имеют смысла для базовых таймеров.
TIM_TimeBaseInitTypeDef base_timer;
// TIM_TimeBaseStructInit(&base_timer);
/* Делитель учитывается как TIM_Prescaler + 1, поэтому отнимаем 1 */
base_timer.TIM_Prescaler = 24000 - 1; // делитель 24000
base_timer.TIM_Period = 1000; //период 1000 импульсов
TIM_TimeBaseInit(TIM6, &base_timer);
// Разрешаем прерывание по обновлению счётчика таймера TIM6.
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM6, ENABLE); // Включаем таймер
// Разрешаем обработку прерывания по переполнению счётчика таймера TIM6.
NVIC_EnableIRQ(TIM6_DAC_IRQn);// это же прерывание отвечает и за опустошение ЦАП.
}
void TIM6_DAC_IRQHandler(){
static uint8_t Flag = 0; // Определяем чет/нечетн вход в обработчик
// Проверяем от таймера ли прерывание
if (TIM_GetITStatus(TIM6, TIM_IT_Update) == SET) {
Flag = ~Flag; // инвертируем значение флага
if(Flag) { //по флагу определяем ЛОГ уровни на светодиодах
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET);
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_SET);
}
else {
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET);
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_RESET);
}
/* Очищаем бит обрабатываемого прерывания */
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
}
}
int main(void) {
Init_Pin(); // инициализация ножек (светодиодных)
Init_timer(); // инициализация таймера 6
while (1); // безконечный цикл
return 0;
}