About STM32

Реализация пауз

     Реализация пауз – пожалуй, одна из фундаментальных прикладных задач. Если вспомнить прошлый пример на stm32, в котором мы мигали светодиодом, то там тоже были паузы. Только та реализация задержек и эта, что я предложу сейчас – это две большие разницы.
     Если в старом примере длительность задержки измерялась ведрами, метрами, зайцами, в общем всем, чем угодно, кроме времени, то в новом примере реализация пауз на stm32 будет в секундах, а если быть более точным, то в милисекундах (0,001 с = 1 мс) и микросекундах (0,000001 с = 1 мкс).
     Для реализации этих функций, назовем их delay_ms и delay_us, я буду использовать базовый таймер 7. Описание его режимов и принципов работы можно прочитать тут.
     Итак, собственно код функций:

void delay_ms(unsigned int delay)
{
     TIM7->PSC = F_APB1/1000+1; //устанавливаем предделитель
     TIM7->ARR = delay; //устанавливаем значение переполнения таймера, а значит и значение при котором генерируется Событие обновления
     TIM7->EGR |= TIM_EGR_UG; //Генерируем Событие обновления для записи данных в регистры PSC и ARR
     TIM7->CR1 |= TIM_CR1_CEN|TIM_CR1_OPM; //Запускаем таймер записью бита CEN и устанавливаем режим Одного прохода установкой бита OPM
     while (TIM7->CR1&TIM_CR1_CEN!=0);
}

void delay_us(unsigned int delay)
{
     TIM7->PSC = F_APB1/1000000+1; //устанавливаем предделитель
     TIM7->ARR = delay; //устанавливаем значение переполнения таймера, а значит и значение при котором генерируется Событие обновления
     TIM7->EGR |= TIM_EGR_UG; //Генерируем Событие обновления для записи данных в регистры PSC и ARR
     TIM7->CR1 |= TIM_CR1_CEN|TIM_CR1_OPM; //Запускаем таймер записью бита CEN и устанавливаем режим Одного прохода установкой бита OPM
     while (TIM7->CR1&TIM_CR1_CEN!=0);
}

     Режим Одного прохода, который был включен установкой бита OPM ( one pulse mode ) в регистре CR1 ( control register 1 ), задает следующий алгоритм работы таймера:
1. Счетчик ( регистр CNT ) считает до значения переполнения ( регистр ARR).
2. Когда значения уравниваются - таймер 7 выключается.

     Момент выключения и ожидает цикл while, который останавливает выполнение программы

     while (TIM7->CR1&TIM_CR1_CEN!=0);

     Реализация функий delay_ms и delay_us полностью идентична, за иключением первой строки, где устанавливается предделитель таймера. Тут, кстати, у Вас должен был бы возникнуть вопрос: «Что такое “F_APB1” ? » ведь о нем не упоминалось при описании работы базового таймера. Для пояснения этого вопроса стоит немного углубиться в систему тактирования stm32, а именно –в тактирование базового таймера 7. В даташите stm32f100rb, который установлен на отладочной плате STM32F1-Discovery, указано, что таймер тактируется от шины APB1, вот как раз ее частоту мы и указываем в директиве F_APB1 следующим образом:

     #define F_APB1 24000000

     Эту строку кода нужно объявить вне функции и до использования ее далее в коде, например, так:

#define F_APB1 24000000

void delay_ms(unsigned int delay)
{
     TIM7->PSC = F_APB1/1000+1;
     …
}

void delay_us(unsigned int delay)
{
     TIM7->PSC = F_APB1/1000000+1;
     …
}

     О предделите тактовой частоты я вскользь упоминал в теоретической статье о базовых таймерах. Рассказывать подробно я не вижу смысла ибо, как мне кажется, назначение этой штуки уже понятно, приведу лишь формулу для ее рассчета из руководства по программированию (стр. 450):

F = F_ABP1/(PSC+1), где

F – итоговая частота работы таймера.
F_ABP1 – частота шины ABP1,к которой подключен таймер 7. Это же – начальная частота работы таймера.
PSC – значение в регистре настроек таймера.

Таким образом:

Итоговая частота таймера = Начальная частота таймера / Предделитель.

     Вернемся к #define F_APB1 24000000. Зачем это делается? Для того, чтобы не переписывать функции, зависящие от тактовой частоты, всякий раз, когда эта частота изменяется. Теперь достаточно будет просто изменить значение в директиве.

     Фуф, вроде настроили! Теперь применим полученные функции на практике, например, помигаем светодиодом:

while (1) //бесконечный цикл
{ //blink
     GPIOC->BSRR |= GPIO_BSRR_BS8; //установкой соответствующего бита зажигаем светодиод
     delay_ms(1000); //Пауза длительностью 1 секунда
     GPIOC->BRR |= GPIO_BRR_BR8; //установкой соответствующего бита тушим светодиод
     delay_ms(2500); //Пауза длительнотью 2,5 секунды
}

     А теперь у меня вопрос: что я не сделал для того, чтобы все это заработало?
     Ответ: не подал тактирование на базовый таймер 7. Я напомню, что по умолчанию вся периферия микроконтроллера stm32 отключена от тактирования.

     Включить тактирование базового таймера нужно следующим образом:

     RCC->APB1ENR |= RCC_APB1ENR_TIM7EN;

     Вот и все. Проект в кэил по традиции:
     delay.rar

 
Хостинг от uCoz