mortomyx
1

помогите с TIM2

23.02.2013, 23:47. Показов 12909. Ответов 12
Метки нет (Все метки)

привет,
Начал изучать STM32 на примере STM32VLDyscover
И вот добрался до таймеров. Решил сделать себе delay_ms и использовал пример найденный в интрернетах.
Иничу таймер :
Код
 RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;   //подать тактирование на TIM2
TIM2->PSC     = 24000-1;                //настроить делитель для формирования миллисекунд
TIM2->CR1     = TIM_CR1_OPM;          //режим одного импульса
Функция :
Код
void delay_ms(uint16_t value)
{
TIM2->ARR = value;                  //загрузить значение задержки
TIM2->CNT = 0;
TIM2->CR1 = TIM_CR1_CEN;         //запустить таймер
while((TIM2->SR & TIM_SR_UIF)==0){} //дождаться конца задержки
TIM2->SR &= ~TIM_SR_UIF;         //сбросить флаг
}
И все бы ничего, но первый раз TIM2->CNT досчитывал до 14мс и вываливался из цикла ожидания. В последующие вызовы delay_ms() отрабатывала корректно.
Я исправил методом почти научного тыка код на такой :

Код
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;   //подать тактирование на TIM2
TIM2->PSC     = 24000-1;   //настроить делитель для формирования миллисекунд
TIM2->CR1 = TIM_CR1_CEN; //Включаю таймер
Код
void delay_ms(uint32_t value) // на всякий пожарный функция задержки
{
TIM2->ARR = value;                  //загрузить значение задержк
TIM2->CNT = 0;                  //обнуляем счетчик
TIM2->SR &= ~TIM_SR_UIF;
TIM2->CR1 = TIM_CR1_CEN;         //запустить таймер
while((TIM2->SR & TIM_SR_UIF)==0){} //дождаться конца задержки
TIM2->SR &= ~TIM_SR_UIF;         //сбросить флаг
}
В таком виде все работает ок. Пожалуйста, разъясните :
- почему первый код не работал при первом вызове delay_ms()
- зачем в рабочем коде мне нужно при ините включать таймер TIM2->CR1 = TIM_CR1_CEN, я же включаю его в коде функции?
- Зачем перед включением таймера в коде функции мне нужно сбрасывать флаг переполнения TIM2->SR &= ~TIM_SR_UIF;?

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.02.2013, 23:47
Ответы с готовыми решениями:

Прерывание от TIM2
Добрый день. Всплыла такая проблемка, что при инициализации NVIC void InteruptTIM2(void) { /*...

Прерывание таймера TIM2
Начал потихоньку разбираться в STM32. Сконфигурировал прерывание таймера 2 с частотой 1Гц (1...

TIM2 задержка в 1 сек
Пытаюсь реализовать задержк черз TIM2 - но в итоге ее будто нет. В чем ошибка? int main() {...

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

12
bzoukotmov
24.02.2013, 12:54 2
Цитата Сообщение от nortomyx
В таком виде все работает ок. Пожалуйста, разъясните :
- почему первый код не работал при первом вызове delay_ms()
- зачем в рабочем коде мне нужно при ините включать таймер TIM2->CR1 = TIM_CR1_CEN, я же включаю его в коде функции?
- Зачем перед включением таймера в коде функции мне нужно сбрасывать флаг переполнения TIM2->SR &= ~TIM_SR_UIF;?
1. Скорее всего нужно сгенерить update event, иначе значения ARR и PSC из промежуточного регистра не загружаются в основной.
2. Если One putsi mode, то таймер нужно включать каждый раз, т.к. при переполнении он останавливается. Если обычный режим, то можно включать один раз, при инициализации, или наоборот при начале задержки включать, а по окончании выключать.
3. Если используете обычный режим, то такая последовательность: сбросить флаг, включить таймер, дождаться переполнения, выключить таймер. Если таймер не выключить, он продолжит счет и снова выставит флаг переполнения, когда основной цикл покинет процедуру задержки. При one putsi mode: сбросили флаг переполнения, включили таймер, дождались переполнения, при этом таймер выключится сам.
0 / 0 / 0
Регистрация: 24.07.2010
Сообщений: 286
24.02.2013, 13:30 3
https://github.com/sasha85ru/stm32f0
http://mycontroller.ru/stm32-t... zaderzhki/
0
mortomyx
24.02.2013, 14:14 4
Цитата Сообщение от bzoukotmov
1. Скорее всего нужно сгенерить update event, иначе значения ARR и PSC из промежуточного регистра не загружаются в основной.
А что это за апдейт ивент?

Цитата Сообщение от Sosho85ru
Именно отсюда я брал код, при использовании которого первый вызов delay_ms() давал задержку ~14мс независимо от аргумента.
bzoukotmov
24.02.2013, 15:25 5
Цитата Сообщение от nortomyx
что это за апдейт ивент?
При окончании счета (ARR, RCR) генерируется "update event". В этот момент обновляется содержимое регистров (например PSC). Т.е. просто сама запись значения в PSC ни на что не влияет, нужно еще вызвать/дождаться "update event", тогда значение из предварительного регистра будет записано в скрытый регистр (есть некоторые варианты). Но это событие можно вызвать и программно, установив бит UG в TIMx_EGR. А можно наоборот запретить генерацию этого события при переполнении, тогда из предварительных регистров ничего загружаться не будет.
bzoukotmov
24.02.2013, 16:44 6
Цитата Сообщение от nortomyx
Именно отсюда я брал код, при использовании которого первый вызов delay_ms() давал задержку ~14мс независимо от аргумента.
При инициализации, после установки PSC, все-таки один раз вызвать update event, тогда задержка будет работать с первого раза.
При изменении ARR каждый раз вызывать событие не обязательно, достаточно чтобы ARPE бит в TIMx_CR1 = 0, тогда ARR будет сразу загружаться из предварительного регистра. В этом примере как раз так сделано (TIM2->CR1 = TIM_CR1_OPM; - обнуляет все, кроме One putsi mode)
mortomyx
24.02.2013, 17:16 7
С апдейт ивентом я понял.

Цитата Сообщение от bzoukotmov
Цитата Сообщение от nortomyx
Именно отсюда я брал код, при использовании которого первый вызов delay_ms() давал задержку ~14мс независимо от аргумента.
При инициализации, после установки PSC, все-таки один раз вызвать update event, тогда задержка будет работать с первого раза.
При изменении ARR каждый раз вызывать событие не обязательно, достаточно чтобы ARPE бит в TIMx_CR1 = 0, тогда ARR будет сразу загружаться из предварительного регистра. В этом примере как раз так сделано (TIM2->CR1 = TIM_CR1_OPM; - обнуляет все, кроме One putsi mode)

Не совсем понял, то есть, в этом примере из-за отсутствия в начала апдейт ивента, действительно первый делей будет проходить с неясным значением из-за того, что TIM2->PSC не применен к скрытому регистру? так?
bzoukotmov
24.02.2013, 21:17 8
Цитата Сообщение от nortomyx
Не совсем понял, то есть, в этом примере из-за отсутствия в начала апдейт ивента, действительно первый делей будет проходить с неясным значением из-за того, что TIM2->PSC не применен к скрытому регистру? так?
Да.
И еще один момент: TIM2->CR1 = TIM_CR1_CEN; //запустить таймер
лучше заменить на TIM2->CR1 |= TIM_CR1_CEN; Иначе one putsi mode будет сбрасываться. И соответственно, очистку флага TIM2->SR &= ~TIM_SR_UIF; можно будет оставить только одну.
0 / 0 / 0
Регистрация: 24.07.2010
Сообщений: 286
24.02.2013, 22:33 9
Цитата Сообщение от Sosho85ru
https://github.com/sasha85ru/stm32f0
Работает ли нормально этот код задержки? Я тоже его слямзил с майконтроллер.ру
0
btosk27512
05.01.2016, 22:35 10
Странность с этими таймерами, почему-то перезагрузка при принудительном вызове события update (TIM4->EGR = TIM_EGR_UG) не срабатывает второй раз, хотя если позволить таймеру вызвать прерывание, то всё же загружаются (PSC и ARR)
В начале делаю так:
Код
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //включаем таймер TIM4
TIM4->CR1 |= (TIM_CR1_OPM);
TIM4->CNT = 0;
TIM4->PSC = 0;
TIM4->ARR = 1000;
TIM4->EGR = TIM_EGR_UG; //Это нужно, что бы теневые ARR и PSC записались в рабочие, иначе будет сразу прерывание после запуска
__NOP();
__NOP();
TIM4->SR &= ~TIM_SR_UIF; //Сбрасываем флаг UIF
TIM4->DIER |= TIM_DIER_UIE; //включаем прерывние от таймера
NVIC_EnableIRQ(TIM4_IRQn); //разрешаем прерывание от таймера
TIM4->CR1 |= TIM_CR1_CEN; //запуск
В этом случае задержка отрабатывает верно, обработчик прерываний вызывается через заданное время.
В обработчике перезапускаю таймер с другими параметрами, вот так:
Код
TIM4->SR &= ~TIM_SR_UIF; //Сбрасываем флаг UIF
.... прочий код....
TIM4->CNT = 0;
TIM4->PSC = 4999; //задержка на 500мс
TIM4->ARR = 3600;
TIM4->EGR = TIM_EGR_UG;
__NOP();
__NOP();
TIM4->SR &= ~TIM_SR_UIF; //Сбрасываем флаг UIF

TIM4->CR1 |= TIM_CR1_CEN;
И вот в этом случае следующий вызов обработчика происходит через время установленное при инициализации в начале, а вот уже второй вызов происходит через 500мс как задумано. Что я делаю не так ? И почему оно сразу второй раз не перезагружается ?
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 3,113
05.01.2016, 23:28 11
У таймеров есть одна документированная "фича", надо лишь читать внимательно документацию (по своим граблЯм) - параметры устанавливаются по сигналу UPDATE, который возникает при переполнении счетчика. Теперь внимательно - эта "фича" распространяется и на делитель тоже.
Обычное положение дел - установить настройки (частоту/делитель/макс.), запустить таймер и надеяться на результат. Но(!), делитель применится только по переполнению, а значит он будет максимальный. Если на 16х таймере это не слишком заметно (ну, кроме subj), а вот на M0 с его 32х счетчиком выходит просто жуткий результат.
Корректная инициализация (IMHO) должна быть выполнена так:
- настроить все параметры, только в длительность поставить "1". Запустить счетчик. Подождать UPDATE. Поставить нужную длительность и пользоваться.

Не стоит использовать аппаратный таймер для системного delayP.S.
Для М3/4: Вообще-то, использовать стандартный таймер для delay - жуткое разбазаривание аппаратуры. Для этого лучше подходит системный таймер, входящий в состав ядра. К тому-же, он еще и весьма точный.

Код
void Delay_ms(uint32_t dtime)
{
int32_t tp = DWT->CYCCNT;
tp += dtime * (MySYSCLK_FREQ_MHz*1000);
while (((int32_t)DWT->CYCCNT - tp) < 0);
}
0
btosk27512
05.01.2016, 23:51 12
Бывают же ошибки в ДШ, однако...
Разобрался, что бы это нормально работало нужно установить еще и URS в CR1 (в ДШ написано, что его включение наоборот ограничивает источники апдейта)
Надо вот так в общем:
Код
TIM4->CR1 |= (TIM_CR1_OPM | TIM_CR1_URS);
Может кому пригодится...
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
06.01.2016, 00:04 13
А если посмотреть что внутри функции инициализации таймера из SPL, то станет ясно, что там последняя строчка - принудительное обновление регистров, как раз таки выставлением бита URS. Выше уже все объяснили - значение ARR и предделители буферизированы, они не обновляются мгновенно. В ДШ подробно описаны варианты обновлений этих регистров.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
06.01.2016, 00:04

Захват и переполнение TIM2
STM8S003F3P6. IAR Stomdalone license 8K. ST-LINK V2. Измеряю длительность периода с помощью...

STM8S + TIM2 +PWM
День добрый, господа. Возник вопрос. Сначала что сделал и в чем проблема: Настроил TIM2_CH1 вывод...

TIM2 по сравнению -> в прерывание
Нужно по сравнению таймера выпасть в прерывание и дернуть ногой //описываю прерывание void...

STM8S + TIM2 = 100kHz на канале №2
Друзья! Есть задачка организовать на ножке порта генератор 100кГц (время нуля = время единицы)...


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.