Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос по таймеру в STM32 Cortex
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Halfback
Всем привет!
Настраиваю таймер 3.
Работает так: постоянно считает до T=1000 мсек (с шагом t=1мс) и сбрасывается. Авторелоад включен.
В какой-то момент времени нужно отмерить интервал времени t1=400мс.
Текущее состояние таймера = t0
Если t1+t0 <= T то компаратор можно назначить через время = t1+t0 и всё будет хорошо,
а вот если t1+t0 >= T то получается немного сложнее т.к. захват нужен после релоада счетчика. А раз так, то получается t1<t0 и компаратор сразу сработает после назначения нового порога.

Есть идея использовать событие по переполнению таймера и там делать переинициализацию на новый порог захвата - в этом случае компаратор словит всё как надо но это как то не красиво.

Есть у кого идеи по решению задачи?

Спасибо!
AHTOXA
Цитата(Halfback @ Jun 14 2010, 02:59) *
Есть у кого идеи по решению задачи?

Отказаться от авторелода и отпустить таймер в свободный забег smile.gif
А ежели надо, чтоб что-то случалось через каждые 1000 тиков - использовать один модуль compare этого таймера. (Или специально предназначенный для этого System Timer).
Halfback
AHTOXA
Что значит свободный забег? не понял. и как это может помочь в настоящей задаче?

Может не совсем доходчиво объяснил но хочется, чтобы событие возникало не при t0>=t1 а только при t0==t1. Может штатные таймеры такое позволяют?

На счет System Timer не знаю - пока не думал и про него даже не читал. Но тут еще одно дело - замеров может быть 4 и все на разные интервалы и могут перекрывать друг друга (поэтому удобно использовать CC1...CC4). Т.е. в то время когда идет замер 400мс по СС1 может произойти замер на 200мс по СС2 и/или 650мс по СС3.
-SANYCH-
Используйте под каждый замер разный таймер. Ведь у микроконтроллере не один таймер.
Можно в прерывании от таймера увеличивать переменные (переменных выделяется столько, сколько нужно делать замеров). По событию вы берете значения переменных это и будут ваши замеры.
biggrin.gif
AHTOXA
Цитата(Halfback @ Jun 14 2010, 12:06) *
Что значит свободный забег? не понял. и как это может помочь в настоящей задаче?

Ну, без автозагрузки. Чтоб считал до 0xFFFF, потом снова 0.
Цитата
Может не совсем доходчиво объяснил но хочется, чтобы событие возникало не при t0>=t1 а только при t0==t1. Может штатные таймеры такое позволяют?

Именно так всё и работаетsmile.gif . Compare match = совпадение (равенство).
Halfback
Предлагаю ближе к делу:
Таймер конфигурируется так (конкретные значения периода, прескалеров привести не могу т.к. проект не под рукой):
Код
TIM_TimeBaseStructure.TIM_Period = 65535;
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

TIM_Cmd(TIM3, ENABLE);


Захват вот так:
Код
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM3, &TIM_OCInitStructure);


Далее в момент времени таймера = 800 (таймер считает до 1000 и перезагружается, начинает считать с 0) надо отмерить 400мс и делаю
Код
TIM_SetCompare1(TIM3,400-(1000-800));
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE)

и сразу вылетаю в обработчик прерывания. Почему это происходит понятно, т.к. 800>(400-(1000-800))

Так вот надо чтобы таймер обнулился, начал считать заново и сделал событие в момент времени (400-(1000-800)).

Потом попробую отработать событие TIM_EventSource_COM
Может это то что надо.
Halfback
TIM_EventSource_COM не то, да и работает на 1 и 8 таймерах.

-SANYCH-
остальные таймера заняты другими задачами.
Halfback
На данный момент проблему решил так: когда надо делать замер то делал TIM_SetCompare2(400-(1000-800)) на событие не активировал а активировал событие по Update. В событии Update по наличию спец. программного флага активировал событие TIM_ITConfig(TIM3,TIM_IT_CC2,ENABLE); Ес-но сбрасывал соответствующие битики событий чтобы не вываливаться в обработчик сразу после активации события. Не самое красивое решение но главное что работает и других идей лично у меня нет.
AHTOXA
Цитата(Halfback @ Jun 14 2010, 20:59) *
Далее в момент времени таймера = 800 (таймер считает до 1000 и перезагружается, начинает считать с 0) надо отмерить 400мс и делаю
Код
TIM_SetCompare1(TIM3,400-(1000-800));
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE)

и сразу вылетаю в обработчик прерывания. Почему это происходит понятно, т.к. 800>(400-(1000-800))

Что за чушь? Ещё раз повторю: компаратор сравнивает не на "больше", а на "равно".
В обработчик вы вылетаете по другой причине.
Посмотрите пример к библиотеке в папке TIM\OCToggle - это то, что вам надо.
koyodza
Не вижу смысла на такие большие времена использовать аппаратный таймер. Сделайте "системный тик" с периодом 1мсек, и считайте хоть 100 разных задержек любой разрядности и длительности с дискретностью этого системного тика
_Макс
Подскажите, на брекпоинте таймер перестает работать? Интересует, что будет с ШИМ в режиме отладки.
klen
Цитата(_Макс @ Jul 8 2010, 14:59) *
Подскажите, на брекпоинте таймер перестает работать? Интересует, что будет с ШИМ в режиме отладки.

как настроиш, можно сказать микосхеме чтоб вставал таймер, по умолчанию молотит дальше - это сделали для того чтоб можно былобы ШИМ отлаживать
ELEKTROS
Добрый день. Проблема похожа чем то: прерывания работают но не все, в частности использую TIM1, TIM2, TIM3, прерывания от TIM1 c фиксированной частотой по переполнению, TIM2 - захват 1 и переполнение, TIM3 - сравнение 1 и переполнение. не работают переполнения во всех. Вот так настраиваю:
CODE
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

TIM_TimeBaseInitStruct.TIM_Prescaler=3664; //
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up; //
TIM_TimeBaseInitStruct.TIM_Period=0xFFFF;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //

TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);

//TIM_PrescalerConfig(TIM2, 900, TIM_PSCReloadMode_Update); //
//TIM_SetAutoreload(TIM3,0xFFFF);//
//TIM_SetCompare1(TIM3, 0x0045); //

TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICFilter=0;


TIM_ICInit(TIM2, &TIM_ICInitStruct);


TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_Timing;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OCInitStruct.TIM_Pulse=0x00FF; //
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

TIM_OC1Init(TIM3, &TIM_OCInitStruct);
//TIM_SelectOCxM(TIM3);
TIM_UpdateDisableConfig(TIM1,ENABLE);
TIM_UpdateDisableConfig(TIM2,ENABLE);
TIM_UpdateDisableConfig(TIM3,ENABLE);

TIM_Cmd(TIM1,ENABLE);
TIM_Cmd(TIM2,ENABLE);
TIM_Cmd(TIM3,ENABLE);


TIM_ITConfig(TIM1,TIM_IT_Update, ENABLE); //
TIM_ITConfig(TIM2, TIM_IT_Update | TIM_IT_CC1, ENABLE);//
TIM_ITConfig(TIM3, TIM_IT_Update | TIM_IT_CC1,ENABLE); //

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //


NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM16_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);


Вот так обработчик прерываний:
CODE
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_CC1)!=RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
/*какой то код*/
}
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
/*какой то код*/
}
TIM3->SR=0;
}
void TIM1_UP_TIM16_IRQHandler(void)
{
if(TIM_GetITStatus(TIM1,TIM_IT_Update)!=RESET)
{
TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
/*какой то код*/
}
TIM1->SR=0;
}
void TIM2_IRQHandler(void)
{
/*** Ôóíêöèÿ ïðåðûâàíèÿ ïî çàõâàòó ñ ÄÏÐ ***/
if(TIM_GetITStatus(TIM2,TIM_IT_CC1)!=RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
/*какойто код*/
}

if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
freq=0;
}
TIM2->SR=0;
}
=F8=
Прерывания по CCx не использовал, но DMA в режиме TIM_OCMode_Timing тоже не работало. Заработало только в режиме TIM_OCMode_PWM1. Правда если соотв пин. находится в режиме в режиме AF_Out тогда...

Как особо извращенный вариант при наличии "лишних" таймеров могу предложить такое:
1. Настраиваете один из неиспользуемых таймеров в режим slave TIM_SlaveMode_Reset(функ. TIM_SelectSlaveMode), в качестве мастера выбираете ваш таймер.
2. В качестве выхода тригера в мастере выбираем необходимое СС(функ. TIM_SelectOutputTrigger).
3. Используем update прерывания от slave.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.