STM32 и таймеры. STM32CubeMx. Настройка и использование.

Таймер в микроконтроллерах

Всем доброго времени суток! Сегодня мы снова будем исследовать возможности STM32CubeMx и рассмотрим таймеры в STM32. Вот предыдущие статьи мини-цикла:

Без лишних слов, перейдем сразу к делу!

В предыдущей статье мы разобрались как настраивать и использовать порты ввода-вывода в STM32CubeMx, а сегодня рассмотрим конфигурацию таймера и прерываний. Пусть будет такая задача – задействуем таймер таким образом, чтобы он генерировал прерывания, допустим, каждые 500 мс, и в прерывании помигаем диодиком для наглядной демонстрации работы. В принципе, ничего сложного, так что приступаем!

Выполняем привычную нам последовательность действий – создаем и настраиваем новый проект в STM32CubeMx. И для начала нам нужно активировать таймер. Пусть в нашем примере будет использоваться TIM3:

Настройка таймера STM32.

Для активации таймера в разделе TIM3 нам нужно в поле Clock Source выбрать источник тактирования. Кроме того, я тут настроил вывод PD12 на работу в режиме выхода, чтобы управлять светодиодом на плате для демонстрации работы программы. Вроде бы все понятно, но с таймером не все так просто. Его нужно как минимум еще и настроить 🙂 Для этого переходим на вкладку Configuration:

Дополнительные настройки.

Дважды нажимаем на TIM3 и открывается новое окно, в котором мы уже можем более гибко настроить параметры таймера:

Таймеры STM32, настройка периода.

Таймер сидит на шине APB1, частота которой составляет 16 МГц (это настройка по умолчанию – как изменить тактовые частоты при помощи Cube я расскажу  в следующей статье). Выбираем делитель частоты равным 16000 (в Cube необходимо установить значение, меньшее на 1). В итоге получаем (16 МГц / 16000) = 1000 Гц. То есть один тик таймера будет соответствовать 1 мс. Установив период 500, получим прерывания по переполнению таймера каждые 500 мс – то, что нам и надо. В этом же окне во вкладке NVIC Settings нужно, собственно, включить нужное нам прерывание, и на этом настройки заканчиваются. Генерируем код и получаем готовый проект для IAR.

Теперь осталось совсем немного – запустить наш таймер (STM32CubeMx занимается только инициализацией, все активные действия мы должны совершать сами). Кроме того, в прерывании по переполнению таймера мы будем менять состояние светодиода. Кстати, сам обработчик прерывания Cube создал за нас и найти его совсем несложно – для всех прерываний генерируется отдельный файл stm32f4xx_it.c.

Давайте все это поэтапно осуществим. Для начала идем в main() и запускаем таймер:

int main(void)
{
	/* USER CODE BEGIN 1 */

	/* USER CODE END 1 */

	/* MCU Configuration----------------------------------------------------------*/

	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();

	/* Configure the system clock */
	SystemClock_Config();

	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_TIM3_Init();

	/* USER CODE BEGIN 2 */

	HAL_TIM_Base_Start_IT(&htim3);

	/* USER CODE END 2 */

	/* USER CODE BEGIN 3 */
	/* Infinite loop */
	while (1)
	{
	}
	/* USER CODE END 3 */
}

Поскольку мы будем использовать прерывания, то нам нужна функция HAL_TIM_Base_Start_IT(). Переходим к следующему этапу – а именно к изменению состояния светодиода в прерывании. Для этого даже есть специальная функция HAL_GPIO_TogglePin():

void TIM3_IRQHandler(void)
{
	/* USER CODE BEGIN TIM3_IRQn 0 */

	/* USER CODE END TIM3_IRQn 0 */
	HAL_TIM_IRQHandler(&htim3);
	/* USER CODE BEGIN TIM3_IRQn 1 */

	HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);

	/* USER CODE END TIM3_IRQn 1 */
}

Теперь мы можем скомпилировать код, собрать проект и прошить микроконтроллер. Сразу же увидим мигающий диод, причем мигает он каждые 500 мс – задача успешно реализована!

Как видите, STM32CubeMx оказывается довольно-таки удобным инструментом для создания своих проектов и это заметно даже в небольших проектах, поэтому в следующих статьях мы продолжим его изучение, оставайтесь на связи!

Поделиться!

Подписаться
Уведомление о
guest
70 комментариев
старее
новее большинство голосов
Inline Feedbacks
View all comments
Alexey
Alexey
5 лет назад

Спасибо за материал! Ответьте, пожалуйста, на вопрос! Можно ли при работе с АЦП устанавливать частоту дискретизации, т.е. количество выборок в секунду? Или нужно использовать прерывание по таймеру и делать однократное преобразование?

Alexey
Alexey
Reply to  Aveal
5 лет назад

Спасибо за ответ! А в каком регистре задается значение, указанное вами 1 мвыборка/с? Наверное, слишком бегло я просмотрел даташит и не увидел. Могли вы привести просто пару строчек кода с примером! Спасибо!

Sergey
Sergey
5 лет назад

STM32Cube вещь интересная.
Но! Сделав простой пример, поразился размером прошивки даже с оптимизацией. На SPL в 3 раза меньше получается, уж не говоря про проект на чисто регистрах.
И мало хелпа, я так и не смог запустить ADC.

Алексей
Алексей
5 лет назад

В Версии иара 7.3 строка HAL_TIM_Base_Start_IT(&htim3); работает в таком виде только: HAL_TIM_Base_Start_IT(htim3); , на описанный вид ругается. И еще, чтобы сделать, например 10 мс период, необходимо например при 1 кГц предделителя ставить 9 (а не 10) в число периода.

Алексей
Алексей
5 лет назад

а также строка HAL_TIM_IRQHandler(&htim3); меняется на HAL_TIM_IRQHandler(&htim3);

Алексей
Алексей
5 лет назад

*извиняюсь: В Версии иара 7.3 строка HAL_TIM_Base_Start_IT(&htim3); работает в таком виде только: HAL_TIM_Base_Start_IT(&htim3);

Алексей
Алексей
5 лет назад

также извиняюсь HAL_TIM_IRQHandler(&htim3); на HAL_TIM_IRQHandler(&htim3);

Алексей
Алексей
5 лет назад

хмхм чето не ладное с ответами((( HAL_TIM_Base_Start_IT(&htim3) строка

Алексей
Алексей
5 лет назад

пишется без &amp

Алексей
Алексей
5 лет назад

И насчет точности времени: приходит на APB1 Timer Clocks 2 МГц, выставляю такие параметры (используя таймер 12)
htim12.Instance = TIM12;
htim12.Init.Prescaler = 2000;
htim12.Init.CounterMode = TIM_COUNTERMODE_UP;
htim12.Init.Period = 3;
htim12.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim12);

получаю на осцилле период в 8 мс (частотой 125 Гц), то есть таймер меняется через каждые 4 мс. То есть получается, что для получения нужного периода необходимо убавлять единицу, возможно это происходит, что счет начинается с 0, и по факту при занесении константы 3, у нас будет период 4 мс., верно ли я полагаю???

Алексей
Алексей
5 лет назад

И еще, прескаллер 16000-1 для повышения точности.

Андрей
Андрей
5 лет назад

Подскажите, break interrupt – это прерывания чем вызываются.

Никита
Никита
5 лет назад

Здравствуйте. Подскажите пожалуйста. Вот строка HAL_TIM_Base_Start_IT(&htim3); запускает таймер? То есть таймер начинает считать только после этой строки. Правильно ли я понял?
И в связи с этим вопрос: а при настройке таймера в режим аппаратного ШИМ эта строка так же необходима?

Андрей
Андрей
5 лет назад

Друзья, недавно в stm. Сразу начал осваивать hal. Требуется помощь.
Подскажите, пожалуйста, как правильно обрабатывать прерывания DMA? Я настроил прерывания от DMA. Настроил таймеры. Обработчик находится в _it.c. я так понимаю.
У меня алгоритм следующий. 1) Таймер по захвату передает данные посредством DMA. DMA по окончанию приема должно выработать прерывание. Но так как перывания от DMA объединены, нам надо убедиться, что это “прерывание по завершению” прочитав соответствующий флаг.
Верная ли последовательность?
Как это сделать (прочитать флаг)?
Нужно ли потом очищать флаги?
2) Нужно определить по спаду или нарастанию на таймере-счетчике произошел запрос от DMA.
Как прочитать регистр флагов прерывания?
3) подскажите как пользоваться библиотекой, иногда получается (с выводами, с USART, а иногда нет).
Вот например очистка флагов DMA. В dma.h есть такой define:

#define __HAL_DMA_CLEAR_FLAG(__HANDLE__, __FLAG__) \
(((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA2_Stream3)? (DMA2->HIFCR = (__FLAG__)) :\
((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA1_Stream7)? (DMA2->LIFCR = (__FLAG__)) :\
((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA1_Stream3)? (DMA1->HIFCR = (__FLAG__)) : (DMA1->LIFCR = (__FLAG__)))

#define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__)\
(((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA2_Stream3)? (DMA2->HISR & (__FLAG__)) :\
((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA1_Stream7)? (DMA2->LISR & (__FLAG__)) :\
((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA1_Stream3)? (DMA1->HISR & (__FLAG__)) : (DMA1->LISR & (__FLAG__)))

Как им воспользоваться, как с помощью него считывать?

Андрей
Андрей
5 лет назад

И еще один вопрос. После создания проекта в Cube в keil у меня на некоторых строках в файлах .h следующая надпись unknow type name uint32_t , в частности напротив этой строки #include “stm32f4xx_hal_def.h” . Это ненормально же? Как это исправить можно?

Андрей
Андрей
5 лет назад

Keil5. Сразу после генерации проекта в Cube, еще ничего не пишу, просто проект собираю и в .h файлах такая штука появляется

Александр
Александр
5 лет назад

TIM1 расширенный режим. Генерация комплементарных сигналов PWM с deadtime.
Запуск HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
Вопрос: сигнал генерится только на одном выходе TIM1_CH1N (PA7), на другом выходе TIM1_CH1 (PA8) фиксированный уровень. В чем может быть проблема?

Викор
Викор
5 лет назад

Если ВЫ уж используете HAL, то советую не в прерывании писать а использовать Callback, например HAL_TIM_PeriodElapsedCallback(прерывание по периоду).

Lexa
Lexa
4 лет назад

Здравствуйте.
Подскажите пожалуйста как пользоваться Callback-ми для обработки данных? Вот допустим получил данные по SPI, мне необходимо обработать их. Если не писать обработку в обработчике прерываний, то как это сделать с помощью callback?

Алексей
Алексей
4 лет назад

Здравствуйте.
Столкнулся с проблемой разного времени выхода на вектор прерывания. В cube установил высокий приоритет HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0); у всех остальных HAL_NVIC_SetPriority(x, 0, 1);
Вот код void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
counter_time ++;
switch (counter_time)
{
case 1:
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
break;

case 2: HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_SET); flag_1 = 1; break;

case 3: HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); break;

case 4: HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); counter_time =0;break;

}
}
Смотрел осциллографом pin stm32f429. Все болтается такое ощущение что что-то выполняет какие то операции и не дает сразу перейти на вектор но что не понятно. Подскажите что делать

Ефим
Ефим
4 лет назад

Здравствуйте!
Я начинающий, поэтому не судите строго, но данное занятие я проделать не смог.
Не объясняется что , как и почему, почему именно эти значения в инфекциях и откуда взяли. Также куда вставили последний кусок
В общем приходится додумывать самому

Ефим
Ефим
4 лет назад

в общем разобрался откуда ноги растут
https://www.youtube.com/watch?v=GrF0Kto5c48
вот не плохое видео. которое хорошо дополняет этот урок
сам все делаю в воркбенхе код после куба автоматом разбит на файлы
править нужно майн и stm32f1xx_it.c
единственное пока не понял у меня 103 контроллер от кварца на 72 мегагерца. таймер 2 на 1APB частота 36М делил на 36к и потом умножал на 499 получалось 2 секунды. пока с определением времени вопрос открытый

Voha
Reply to  Aveal
4 лет назад

Добрый день Aveal. Спасибо за такие классные материалы по HAL, всё очень просто и понятно.

Есть у меня небольшой вопрос. Подразумевает ли Cube возможность изменение периода таймера во время работы контроллера? Я хочу изменять период таймера на работающем контроллере, без перепрошивки.

Я предполагаю нужно в этой строке “htim3.Init.Period = 499” вместо числового значения поставить переменную “htim3.Init.Period = a”, а потом перезапускать таймер после изменения значения этой переменной. Но боюсь Cube сотрёт эту переменную, т.к. она будет находится вне блока User Code.

Может есть ещё способы?
А может ткнёте носом в мануал\ссылку, где это всё расписано 🙂

Владислав
Владислав
Reply to  Aveal
3 лет назад

Нет, при такой схеме мы просто альтернативно инициализируем таймер, в зависимости от некоего условия на входе.
Могу кусок простого кода добавить для ясности.
Проблема в том, что пишу с Мака, а реальный код – на работе.
Но суть-то в другом: в Кубе мы МОЖЕМ указывать некие ПЕРЕМЕННЫЕ, а вот где и в каком блоке кода их можно использовать – я про это говорил.
На вкус и цвет.

Владислав
Владислав
Reply to  Voha
3 лет назад

В самом Cube надо в настройках писать не числа, а имена переменных или даже формулы с переменными (надо только там галку тыкнуть, чтоб не проверял на корректность) – тогда в коде, который он генерит, будет ровно то, что вы напишете в строке параметра.

Владислав
Владислав
Reply to  Владислав
3 лет назад

Поясню на примере. Допустим, мы пишем код для приемника и передатчика и хотим, чтобы это была одна и та же программа, которая, в зависимости от 0 или 1 на некоем пине работала бы либо как приемник, либо как передатчик, но при этом, моргала бы разной частотой светодиода – штоб отличать одну от другой.
Пусть за отличие приемника от передатчика морганием светодиода будет отвечать шестой таймер, как самый простой.
Пусть у нас на ARB частота равна 36МГц.
Пусть мы хотим на приемнике мигать лениво, а на передатчике – в 2 раза чаще.
1. До функции main() в пользовательском блоке объявляем свою переменную – MyTIM6_Cnt (название – произвольное).
2. В CubeMX указываем в прескалере “36000 – 1”
3. В CubeMX указываем значение счетчика “MyTIM6_Cnt -1” (справа указывая, что данное поле проверять не надо, а надо вставлять в код так, как написано).
4. В main(), после инициализаций, добавляем в юзерской части проверку порта, который по-умолчанию Pull-Up.
(А если хотим сделать девайс обратным – просто замыкаем вывод на землю)
5. А дальше – просто: после всех инициализаций в юзерском блоке проверяем значение порта, присваиваем MyTIM6_Cnt нужное значение и еще раз переинициализируем и запускаем таймер:
MX_TIM6_Init();
HAL_Base_Start_IT(&htim6);

Вот и всё – получаем кубом код, который не зависит от того, что написано там в полях настройки не будет испорчен при изменении настроек куба.

Владислав
Владислав
Reply to  Владислав
3 лет назад

Одна особенность.
По умолчанию, все инициализации всего в Keil делаются в файле main.c
Когда девайсов становится много – удобнее тыкнуть галочку в настройках проекта, штоб инициализации для каждого устройства и их “.h”-файлы были различными (чтоб не мешали в main.c)
Так вот – тогда у вас эта ваша переменная типа MyTIIM6_Cnt – не опознается в отдельных файлах инициализаций.

Просто добавьте там строчку, типа
extern MyTIM6_Cnt.
Но не

Владислав
Владислав
Reply to  Владислав
3 лет назад

но не оставляйте так – указывайте между словом extern и именем переменной – тот самый тип, который нужен.

если у вас было в main.c указано
unsigned short MyTIM6_Cnt
то и в файле инициализации нужно будет сказать полно:
extern unsigned short MyTIM6_Cnt;

Впрочем, это уже знания Си, а не МК.

Владислав
Владислав
Reply to  Владислав
3 лет назад

Нет, при такой схеме мы просто альтернативно инициализируем таймер, в зависимости от некоего условия на входе.
Могу кусок простого кода добавить для ясности.
Проблема в том, что пишу с Мака, а реальный код — на работе.
Но суть-то в другом: в Кубе мы МОЖЕМ указывать некие ПЕРЕМЕННЫЕ, а вот где и в каком блоке кода их можно использовать — я про это говорил.
На вкус и цвет.

P.S. У вас не туда и не так привязываются ответы.
Что-то с базой не так.

Владислав
Владислав
Reply to  Владислав
3 лет назад

А, понял.
Нет, после повторной инициализации таймера и его запуска (а это все происходит по коду после системных инициализаций) – получаем результат.

Тут ведь как – изначальная настройка таймера – была в системном блоке.

А вот в юзерском – опрашиваем пин и еще раз таймер перенастраиваем на запуск.

Владислав
Владислав
Reply to  Владислав
3 лет назад

Ну, короче, если вы поймете, как в настройках CubeMX указывать не числа, а переменные (и где и как в коде эти переменные располагать и где их использовать) – вы малаццы.

Мне, так-то, добавить уже нечего.

Владислав
Владислав
Reply to  Владислав
3 лет назад

Давайте я завтра просто пример кода сюда скопирую?

Владислав
Владислав
Reply to  Voha
3 лет назад

Вот кусок кода из main.c
(на ibyt ARB1 для таймера задана частота 36МГц)

/* USER CODE BEGIN PV */
/* Private variables ———————————————————*/

unsigned short MyTIM6_Cnt=0; /* Здесь будет храниться значение счетчика таймера */

#define MODE_RECEIVER 0
#define MODE_TRANSMITTER 1

/* Т.к. пин режима “подтянут” к единице, то по умолчанию – мы передатчик */
unsigned short RxTxMode = MODE_TRANSMITTER;

/* USER CODE END PV */

/* Private function prototypes ———————————————–*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_NVIC_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes ———————————————–*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void)
{

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration———————————————————-*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* Configure the system clock */
SystemClock_Config();

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM6_Init();

/* Initialize interrupts */
MX_NVIC_Init();

/* USER CODE BEGIN 2 */

/* TEST HAL_GPIO_WritePin(Light_1_GPIO_Port, Light_1_Pin, GPIO_PIN_SET);*/

/* Опрашиваем пин режима и принимаем решение кто мы сейчас */
RxTxMode = (HAL_GPIO_ReadPin(RxTxMode_GPIO_Port, RxTxMode_Pin) == GPIO_PIN_RESET)
? MODE_RECEIVER
: MODE_TRANSMITTER;

/* Пусть приемник будет мигать раз в секунду, передатчик – 2 раза в секунду */
MyTIM6_Cnt = (RxTxMode == MODE_RECEIVER) ? (500-1) : (250-1);

/* А теперь еще раз инициализируем таймер и запускаем его */
MX_TIM6_Init();
HAL_TIM_Base_Start_IT(&htim6);

if (RxTxMode == MODE_RECEIVER)
{
while (1)
{
/* Здесь код приемника */
}
}
else /* MODE_TRANSMITTER */
{
while (1)
{
/* Здесь код передатчика */
}
}

/* USER CODE END 2 */

А вот то, что генерит Куб в инициализации таймера:

/* TIM6 init function */
void MX_TIM6_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig;

htim6.Instance = TIM6;
htim6.Init.Prescaler = 36000 – 1;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = MyTIM6_Cnt;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}

sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}

}

В строчках

htim6.Init.Prescaler = 36000 – 1;
htim6.Init.Period = MyTIM6_Cnt;

Куб подставил именно то, что было указано в настройках Куба.

Итак, это пример того, что вовсе необязательно в настройках Куба указывать абсолютные числа – можно (и нужно иногда) указывать свои переменные.

Владислав
Владислав
Reply to  Ефим
3 лет назад

завтра ответить попробую, не сегодня.

а завтра – предъявлю владение CubeMX в тех вопросах, где малость разобрался.

Оки?

Ефим
Ефим
4 лет назад

Ув. Aveal насчет частот все понятно.
вы не указали что надо поставить галочку NVIC Setting ну отсюда и естественно куда вкладывать код моргания диода (без галочки он не генерируется), так же нет объяснения откуда взялся параметр (&htim3) – по логике вещей понятно, но на видео по ссылке, что вкладывал автор все показывает и становится понятно, т.к. хотелось, что бы инструкция была относительно универсальна. (т.е. к разным МК и таймерам)
для своего Мк выставил все верно – таймер2 частота 36МГЦ (по кубу и это максимальная по даташиту) при делении на 36к и умножении на 499 почему то получилось 2сек, в итоге сделал умножение на 249 и вроде стала 1сек., но почему не понял

Василий Теркин
Василий Теркин
4 лет назад

(c)”вы не указали что надо поставить галочку NVIC Setting”
А я два часа голову себе ломал – что я не так делаю. Досадная неточность автора. Спасибо Ефим.

Адлан
Адлан
Reply to  Aveal
2 лет назад

Здравствуйте!
Настраиваю в Кубе таймер на энкодер. Куб позволяет подтягивать входы вниз, вверх или оставить болтаться. Однако в созданном коде (IAR EWARM) нигде не нашел, чтобы эти входы инициализировались. Между тем, таймер и не считает данные с энкодера. Может, надо было вручную?

Василий Теркин
Василий Теркин
3 лет назад

Спасибо. Разобрался, в общем. Есть вопрос – как посчитать количество импульсов за единицу времени. Как я понял – нужно считать “тики” между спадом импульса и фронтом следующего. Нет ли у Вас подобного примера? Может, будет желание статью написать?

Василий Теркин
Василий Теркин
Reply to  Aveal
3 лет назад

Метод надежен, но есть слабое место. При низкой частоте импульсов – очень большая погрешность. Я собираюсь считывать сигнал с импульсного водомера. Частота (средняя), пусть, 10 имп./сек. При опросе счетчика, по прерыванию таймера, например, каждую секунду – может быть полная лажа. 8-11…а это более 10%
Я думал, что ловить нужно спад импульса, начинать считать “тики” и по фронту следующего – считывать счетчик. Частота “тиков” известна, все остальное – уже детали. Но вот именно этот кусок – мне непонятно, как реализовать. Спад – подсчет – остановка по фронту… Если подскажете примером – буду очень признателен 🙂

Василий Теркин
Василий Теркин
Reply to  Aveal
3 лет назад

Спасибо. Метод с обработкой значения счетчика в прерывании по входу – похоже, то, что надо. Но там, видимо, есть нюанс – с учетом переполнения таймера, оно может попасть в период между импульсами на входе. Возможно, таймер нужно сбрасывать в 0, в обработчике прерывания?
Нет ли у Вас интереса на эту тему сделать урок? Например, урок в DISCOVERY – как считать количество нажатий на кнопку за 1…10 сек?

Адлан
Адлан
Reply to  Aveal
3 лет назад

Здравствуйте!
Вот, как раз ищу, как сбросить таймер, когда он еще не “досчитал” до сброса?
Спасибо

Сергей
Сергей
3 лет назад

при вхождении в процедуру обработки прерывания надо сбрасывать флаг прерывания или он автоматически сбрасывается?

LEV
LEV
3 лет назад

Здравствуйте! Есть необходимость менять htim3.Init.Period прямо в прерывании. Я пытаюсь сделать так:

В прерывании
htim3.Init.Period = 10000; // или др. значение

ошибку не выдает но и период прерываний не меняется… подскажите пожалуйста как это исправить

Адлан
Адлан
Reply to  Aveal
2 лет назад

Здравствуйте!
Я так и делаю: TIM4->ARR = “расчетное значение” – для генерации импульсов управления частотником – от 20 до 5000 Гц. Почему-то при росте частоты генерация срывается и возобновляется через (примерно) 4 секунды, а при уменьшении все работает непрерывно. Если бы контроллер сбивали импульсы от энкодера или собственного выхода, это было бы и при падении частоты (кажется). Если бы МК зависал от внешних помех, то перестал бы работать весь, а не только таймер TIM4. Если бы не хватало быстродействия (чтобы переключать выход с частотой в сотню – другую герц?), его не хватало бы и после паузы в несколько секунд… В общем, не знаю, что и предполагать. Ваши опыт и знания что-нибудь подсказывают?
Спасибо

Адлан
Адлан
2 лет назад

Править комментарий здесь, похоже, нельзя, но Вы можете – если слишком длинно – сократить его до разумных пределов, или удалить совсем

Адлан
Адлан
Reply to  Aveal
2 лет назад

Спасибо, я об этом не подумал. Завтра проверю и отпишусь

Адлан
Адлан
Reply to  Адлан
2 лет назад

Здравствуйте! Сегодня попробовал записывать в прерывании в регистр ARR значение, вычисленное в цикле. Но переменная в обработчике получает нулевое значение независимо от результатов расчета. Может, что то опять не так делаю? Сообщение с проектом на Ваш адрес почему-то не ушло, сейчас попробую сообщение без вложения. Спасибо

Адлан
Адлан
Reply to  Aveal
2 лет назад

Письмо без вложения ушло. Значит, дело было не в адресе, а во вложении (проект IAR, завернутый в RAR) – в списке запрещенных такого файла нет, не знаю, почему

Присоединяйтесь!

Profile Profile Profile Profile Profile
Vkontakte
Twitter

Язык сайта

Ноябрь 2020
Пн Вт Ср Чт Пт Сб Вс
 1
2345678
9101112131415
16171819202122
23242526272829
30  

© 2013-2020 MicroTechnics.ru