Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.91/55: Рейтинг темы: голосов - 55, средняя оценка - 4.91
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739

STM32F303 задержка базовым таймером

20.07.2017, 13:31. Показов 10731. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет! Решил тут внести пару исправлений в один свой проект в отношении временных задержек и решил, что начинающим разработчикам может пригодиться опыт реализации задержки на основе базовых таймеров.
В чем собственно суть? Первые эксперименты у начинающих разработчиков, начинаются с моргания диодом с заданной частотой. Это некий "Hello world!" в этой сфере. Поэтому встает логичный вопрос, как реализовать задержку? Вариантов существует несколько, возможно назову не все но основные.
Простая:
- Программная задержка (существует много вариаций):
C++
1
2
3
4
5
void Delay(long i)
{
    while(i)
        i--;
}
Вариант рабочий, но не очень удобный и стабильный, необходимо самому рассчитывать, как будет задержка исходя из длительности выполнения команды в тактах. Поменяли частоту процессора - пересчитываем задержки. Для "поморгать" сойдет, но не более. В моем старом проекте, было что-то подобное.
Посложнее:
- Функция задержки в ОСРВ:
C++
1
vTaskDelay(50);
Уже лучше, тут есть привязка к системному таймеру - изменил частоту процессора, изменил дефайн и не надо перебирать все задержки по проекту. Минусы естественно присутствуют: 1) Освоение ОСРВ нетривиальная задача на первых порах; 2) Не получится сделать задержку меньше, чем один тик планировщика ОС. Можно конечно уменьшить, период тика ОС, но это черевато проблемами. Стандартный тик выбирают 1 мс, соответственно задержку меньше 1 мс не сделать. (Если можно сделать, подскажите как). 3) Задержку ОСРВ можно использовать только внутри потоков, а что если нам надо запустить дисплей или прочитать из внешней EEPROM еще до запуска планировщика?
Средний вариант:
-Используем базовые таймеры. В STM32 есть куча таймеров с разным функционалом, почему бы не выделить один базовый таймер? Почему базовый: в основном внутри МК установлены таймеры с функциями генерации ШИМ, захвата и т.д. оставим их на другие нужды. Базовый таймер умеет немногое, просто считать вверх/вниз генерировать прерывания по переполнению, то что нам и надо.
В своем проекте мне нужна была задержка около 100 и 200 мкс, хоть я и использую FreeRTOS, стандартная задержка ОСРВ здесь не подойдет. И так в моем распоряжении 2 базовых таймера TIM6/TIM7. Возьму TIM7 так как 6 уже занят. Подрыгать ножкой с задержкой, ножка у меня на порту E 12 пин.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "stm32f30x_conf.h"
 
/*Переменная задержки*/
/*volitile, так как переменная изменяется в прерывании, на всякий случай, чтобы компилятор не накосячил*/
volatile int Delay_us = 0;
/*Функция задержки*/
void Delay(int us);
/*Функция инициализация таймера задержки*/
void Init_DelayTIM();
 
int main(void)
{
  /*Сбрасываем настройки тактового генератора*/
  RCC_DeInit();
  /*отключаем внешний кварц, у меня его нет*/
  RCC_HSEConfig(RCC_HSE_OFF);
  /*включаем внутренний генератор 8 МГц*/
  RCC_HSICmd(ENABLE);
  /*Настраиваем внутренний ФАПЧ на частоту  64 МГц*/
  RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);
  /*Включаем ФАПЧ*/
  RCC_PLLCmd(ENABLE);
  /*Источник тактирования системной шины - ФАПЧ*/
  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  /*Остальные шины без предделителя*/
  RCC_HCLKConfig(RCC_SYSCLK_Div1);
  RCC_PCLK1Config(RCC_HCLK_Div1);
  RCC_PCLK2Config(RCC_HCLK_Div1);
  /*Инициализация таймера задержки*/
  Init_DelayTIM();
  /*Включаем тайтирование порта E*/
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
  GPIO_InitTypeDef leds;
  /* без подтяжки, на выход*/
  leds.GPIO_Pin     =    GPIO_Pin_12;
  leds.GPIO_Speed   =   GPIO_Speed_2MHz;
  leds.GPIO_OType   =   GPIO_OType_PP;
  leds.GPIO_Mode    =   GPIO_Mode_OUT;
  leds.GPIO_PuPd    =   GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOE, &leds);
  /*Основной цикл*/
  while(1)
  {
      Delay(200);
      GPIOE->ODR ^= GPIO_Pin_12;
  }
}
Итак, тут все просто Настроили систему тактирования, настроили пин который будем дергать, проинициализировали таймер, ну и в while(1) дергаем ножку с частотой 200 мкс.
Теперь подробнее про инициализацию таймера Init_DelayTIM();
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void Init_DelayTIM()
{
        /*Структура вектора прерывания*/
    NVIC_InitTypeDef NVIC_InitStructure;
        /*Структура таймера задержки*/
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
 
    //Включение тактирования таймера
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
    TIM_DeInit(TIM7);
 
    TIM_TimeBaseStructure.TIM_Prescaler = 64-1 ; //делитель частоты шины тактирования (период тика таймера 1 мкс)
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //частота без деления 64 Мгц
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //считаем вверх
    TIM_TimeBaseStructure.TIM_Period = 10-1; //до этого значения будет считать таймер ( и того 10 мкс)
    TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
 
    TIM_ClearFlag(TIM7, TIM_FLAG_Update); //очистка флага переполнения
    TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE); //разрешение прерываний по переполнению
    TIM_Cmd(TIM7, ENABLE); // запускаем таймер
 
    NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; // устанавливаем вектор прерывания
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // устанавливаем приоритет
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // включаем прерывания
    NVIC_Init(&NVIC_InitStructure);
}
И так, что мы имеем таймер переполняется с периодом 10 мкс, так как предделитель дает частоту тика таймера 64 МГц/64 = 1 МГц и считает он до 10. Простая математика.
По переполнению вызывается прерывание:
C++
1
2
3
4
5
6
7
void TIM7_IRQHandler(void)
{
    /*Очищаем флаг прерывания*/
    TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
    /*декрементируем переменную*/
    if(Delay_us > 0) --Delay_us;
}
Прерывание простенькое, в нем декрементируется переменная дающая нашу задержку. Установка значения переменной задержки производится в функции:
C++
1
2
3
4
5
6
7
void Delay(int us)
{
    /*Устанавливаем значение задержки*/
    Delay_us = us/10;
    /*Ждем конца задержки*/
    while(Delay_us);
}
У меня разрешение таймера 10 мкс, в моем случае меньше не нужно. Поэтому если мы хотим задержку в 200 мкс, то в Delay_us нужно записать 20. Если хотите поправить под себя, сделайте другое разрешение таймера и уберите деление на 10.
Что по итогу получилось, замеряем осциллографом. Собственно интервал выдержан, период немного плавает в пределах 1 мкс. С внешним кварцем будет лучше. Примеров в сети огромное количество, где то понятные, где то не очень. Ну и я свой оставлю тут, может кому пригодится.
Миниатюры
STM32F303 задержка базовым таймером  
2
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
20.07.2017, 13:31
Ответы с готовыми решениями:

Задержка с таймером TMR0 MPASM
Ребят, всем привет. Я сейчас осваиваю программирование на ассемблере MPASM для МК PIC. Я понимаю, что в интернете куча информации, но...

Прерывание EXTI на stm32f303
Всем добрый вечер!:) Начал изучать новый микроконтроллер и хочу зажигать светодиоды от нажатия кнопки на плате stm32f3discovery. Для этого...

Проблема с USART STM32f303
Доброго времени суток. Настроил USART, отсылает сообщения. Но, когда разрешаю прерывания по окончанию отправки сообщения, USART перестает...

8
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
25.07.2017, 09:49  [ТС]
Решил немного оптимизировать задачу. В примере приведенном выше в прерываниях каждые 10 мкс декрементируется переменная, скажем если мы возьмем задержку в 500 мкс, то за это время нам надо обработать 50 прерываний, а оно нам надо? Сделаем проще:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Init_DelayTIM()
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
 
    //Включение тактирования таймера
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
    TIM_DeInit(TIM7);
 
    TIM_TimeBaseStructure.TIM_Prescaler = 64-1 ; //делитель частоты шины тактирования
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //частота без деления 64 Мгц
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //считаем вверх
    TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //до этого значения будет считать таймер
    TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
 
    TIM_Cmd(TIM7, ENABLE);
}
Настроим таймер с частотой тика 1 мкс, а период счета установим по максимуму 0xFFFF, прерывания уберем совсем ни к чему они, пускай себе гоняет по кругу.

А вот и сама функция задержки:

C++
1
2
3
4
5
void Delay(unsigned short us)
{
    TIM7->CNT = 0;
    while(TIM7->CNT < us);
}
Как только нам надо использовать задержку, мы программно скидываем таймер на 0, и ждем пока он не досчитает до нужного значения.
Таким образом, мы избавились от прерываний, избавились от лишней переменной ( мелочь, а приятно) и увеличили разрешение счетчика до 1 мкс. Небольшой профит.
1
Тутошний я
 Аватар для Grey
2147 / 1202 / 225
Регистрация: 03.11.2009
Сообщений: 4,424
Записей в блоге: 2
28.07.2017, 02:08
Цитата Сообщение от _SayHello Посмотреть сообщение
А вот и сама функция задержки:
Задержка опять стала программной? На её точность ничего не влияет(прерывания, другие процессы)?
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
29.07.2017, 06:44  [ТС]
Grey, вы правы, не спорю, при классической программе другие прерывания будут влиять на время задержки ( если таковые будут происходить в таковой промежуток времени). В ОСРВ все немного хуже, если нам требуется задержка в одном процессе на 5 мкс и шедулер в некий момент задержки переключит на другую задачу, то задержка увеличится минимум на 1 мс ( если брать стандартный тик в 1 мс). Есть варианты отключать планировщик на время действия задержки. Если есть другие варианты предложите, я бы с удовольствием перенял опыт. Ибо сам не так давно в разработке
0
Тутошний я
 Аватар для Grey
2147 / 1202 / 225
Регистрация: 03.11.2009
Сообщений: 4,424
Записей в блоге: 2
01.08.2017, 00:20
Я тоже недавно начал изучать STM. Потому и интересуюсь.
Цитата Сообщение от _SayHello Посмотреть сообщение
увеличили разрешение счетчика до 1 мкс
Я не могу придумать задачу под такую длительность.
Но думаю, что если такая функция нужна, то нужно не отключать планировщик, а встроить функцию в ОСРВ. Но использовать только для небольших длительностей.

Например в винде есть таймер работающий от системного таймера( тот же планировщик).
И есть пара функций работающих от тактов процессора. Но они вроде тормозят винду. Но винда же не ОСРВ.
0
 Аватар для Voland_
1983 / 1276 / 131
Регистрация: 04.01.2010
Сообщений: 4,607
01.08.2017, 09:03
Цитата Сообщение от Grey Посмотреть сообщение
Я не могу придумать задачу под такую длительность.
во множестве производств, связанных с механической (количественной) обработкой потока изделий это можно себе представить. Скажем, при разливке напитков, в различного рода сортировке, а также металлургии (прокатке). Опять же - при испытаниях реактивных моторов, всяческого рода высокооборотистых двигателей.

Цитата Сообщение от _SayHello Посмотреть сообщение
В ОСРВ все немного хуже, если нам требуется задержка в одном процессе на 5 мкс и шедулер в некий момент задержки переключит на другую задачу, то задержка увеличится минимум на 1 мс ( если брать стандартный тик в 1 мс).
В более-менее современных МК всегда имеется приоретизация прерываний. Ее нет разве что в ранних AVR и PIC. Насчет последних - может и появилось, не знаю. Так что даже обработчик в 1мкс имеет место быть, в особенности есть частота МК и прямота рук программиста позволяют "с этим жить". В ThreadX, FreeRTOS, RTOS конечно имеются скедьюлеры, но их роль, учитывая богатейшую периферию довольно низко пала. Главное в вашем коде - разработать правильную схему прерываний от периферии, и разрешить их возможные коллизии по части общих ресурсов. В случае, чтобы не париться - всем этим должен заниматься скедьюлер в ОСРВ. Но... если честно, как бы я ни писал задачи на базе ОСРВ - в трушном имбеддед они все равно получались лучше ).
PS: имхо.
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
01.08.2017, 13:23  [ТС]
Grey,
Цитата Сообщение от Grey Посмотреть сообщение
Я не могу придумать задачу под такую длительность.
Я дергаю дисплей импульсом в 10 мкс.
Voland_, мне ОСРВ удобна, так как много периодических задач, которые не зависят друг от друга. А сам проект достаточно большой. Удобно с потоками по отдельности работать. Не спорю, что все тоже самое можно сделать с помощью таймеров, в первом примере, что-то подобное представлено, скажем делаем прерывания по таймеру в которых инкрементируем переменные, а в основном цикле проверяем. Интересно было попробовать ОСРВ, теперь втыкаю по случаю...
0
 Аватар для Voland_
1983 / 1276 / 131
Регистрация: 04.01.2010
Сообщений: 4,607
01.08.2017, 14:08
Цитата Сообщение от _SayHello Посмотреть сообщение
мне ОСРВ удобна
Я вас очень хорошо понимаю. Просто ОСРВ удобна на уровне, когда вы не работаете напрямую с периферией, но имеете функции на логическом уровне, то есть "измерить напряжение", "событие щелчка кнопки", "сигнал получен". Вот на этом уровне ОСРВ будет полезна. А на уровне "отсчитать 10мкс" ОСРВ не применима - это пишется на самом низком уровне, уровне прерываний и их приоритетов. Это не уровень ОСРВ.
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
01.08.2017, 14:11  [ТС]
Voland_, ну, да все что требует отклика менее > 1 мс приходится на периферии делать, благо в stm32 её навалом
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
01.08.2017, 14:11
Помогаю со студенческими работами здесь

STM32f303+EEPROM I2C
Всем добрый день! С полгода назад, начинал проект на камушке stm32f103, но проект сильно разросся и его заморозили, сейчас пришло время...

Stm32f303+freertos+interrupts
Без прерываний все работает неплохо, хочу прикрутить прерывания, пока без семафоров, просто в прерывании отправить чтонибудь в USORT. По...

STM32F303 comp --> timer
помогите пжлста вот с такой проблемой: выходы с компараторов 3,5,6 хочу направить на капчи tim4 -- соответственно 1,3,4....

STM32F303 внешнее прерывание
привет всем, хочется опробовать внешнее прерывание на плате stm32f3discovery - не получается... кнопка USER-button на PA0, зелёный...

USART в STM32F303 [закрыто]
USORT. Вроде все нормально, как положено инициализируется и т.д., но не работает ;) Код#include &quot;stm32f30x_gpio.h&quot; #include...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
10 пpимет, которые всегда сбываются
Maks 31.03.2026
1. Чтобы, наконец, пришла маршрутка, надо закурить. Если сигарета последняя, маршрутка придет еще до второй затяжки даже вопреки расписанию. 2. Нaдоели зима и снег? Не надо переезжать. Достаточно. . .
Перемещение выделенных строк ТЧ из одного документа в другой
Maks 31.03.2026
Реализация из решения ниже выполнена на примере нетипового документа "ВыдачаОборудованияНаСпецтехнику" с единственной табличной частью "ОборудованиеИКомплектующие" разработанного в конфигурации КА2. . . .
Functional First Web Framework Suave
DevAlt 30.03.2026
Sauve. IO Апнулись до NET10. Из зависимостей один пакет, работает одинаково хорошо как в режиме проекта так и в интерактивном режиме. из сложностей - чисто функциональный подход. Решил. . .
Автоматическое создание документа при проведении другого документа
Maks 29.03.2026
Реализация из решения ниже выполнена на нетиповых документах, разработанных в конфигурации КА2. Есть нетиповой документ "ЗаявкаНаРемонтСпецтехники" и нетиповой документ "ПланированиеСпецтехники". В. . .
Настройка движения справочника по регистру сведений
Maks 29.03.2026
Решение ниже реализовано на примере нетипового справочника "ТарифыМобильнойСвязи" разработанного в конфигурации КА2, с целью учета корпоративной мобильной связи в коммерческом предприятии. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru