Перейти к содержанию
    

Вопрос по таймеру в STM32 Cortex

Всем привет!

Настраиваю таймер 3.

Работает так: постоянно считает до T=1000 мсек (с шагом t=1мс) и сбрасывается. Авторелоад включен.

В какой-то момент времени нужно отмерить интервал времени t1=400мс.

Текущее состояние таймера = t0

Если t1+t0 <= T то компаратор можно назначить через время = t1+t0 и всё будет хорошо,

а вот если t1+t0 >= T то получается немного сложнее т.к. захват нужен после релоада счетчика. А раз так, то получается t1<t0 и компаратор сразу сработает после назначения нового порога.

 

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

 

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

 

Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Отказаться от авторелода и отпустить таймер в свободный забег :)

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AHTOXA

Что значит свободный забег? не понял. и как это может помочь в настоящей задаче?

 

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

 

На счет System Timer не знаю - пока не думал и про него даже не читал. Но тут еще одно дело - замеров может быть 4 и все на разные интервалы и могут перекрывать друг друга (поэтому удобно использовать CC1...CC4). Т.е. в то время когда идет замер 400мс по СС1 может произойти замер на 200мс по СС2 и/или 650мс по СС3.

Изменено пользователем Halfback

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Используйте под каждый замер разный таймер. Ведь у микроконтроллере не один таймер.

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

:biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что значит свободный забег? не понял. и как это может помочь в настоящей задаче?

Ну, без автозагрузки. Чтоб считал до 0xFFFF, потом снова 0.

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

Именно так всё и работает:) . Compare match = совпадение (равенство).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Предлагаю ближе к делу:

Таймер конфигурируется так (конкретные значения периода, прескалеров привести не могу т.к. проект не под рукой):

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-

остальные таймера заняты другими задачами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На данный момент проблему решил так: когда надо делать замер то делал TIM_SetCompare2(400-(1000-800)) на событие не активировал а активировал событие по Update. В событии Update по наличию спец. программного флага активировал событие TIM_ITConfig(TIM3,TIM_IT_CC2,ENABLE); Ес-но сбрасывал соответствующие битики событий чтобы не вываливаться в обработчик сразу после активации события. Не самое красивое решение но главное что работает и других идей лично у меня нет.

Изменено пользователем Halfback

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Далее в момент времени таймера = 800 (таймер считает до 1000 и перезагружается, начинает считать с 0) надо отмерить 400мс и делаю

TIM_SetCompare1(TIM3,400-(1000-800));
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE)

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

Что за чушь? Ещё раз повторю: компаратор сравнивает не на "больше", а на "равно".

В обработчик вы вылетаете по другой причине.

Посмотрите пример к библиотеке в папке TIM\OCToggle - это то, что вам надо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не вижу смысла на такие большие времена использовать аппаратный таймер. Сделайте "системный тик" с периодом 1мсек, и считайте хоть 100 разных задержек любой разрядности и длительности с дискретностью этого системного тика

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подскажите, на брекпоинте таймер перестает работать? Интересует, что будет с ШИМ в режиме отладки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подскажите, на брекпоинте таймер перестает работать? Интересует, что будет с ШИМ в режиме отладки.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день. Проблема похожа чем то: прерывания работают но не все, в частности использую TIM1, TIM2, TIM3, прерывания от TIM1 c фиксированной частотой по переполнению, TIM2 - захват 1 и переполнение, TIM3 - сравнение 1 и переполнение. не работают переполнения во всех. Вот так настраиваю:

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);

 

Вот так обработчик прерываний:

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;
}

Изменено пользователем IgorKossak
[codebox]

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Прерывания по CCx не использовал, но DMA в режиме TIM_OCMode_Timing тоже не работало. Заработало только в режиме TIM_OCMode_PWM1. Правда если соотв пин. находится в режиме в режиме AF_Out тогда...

 

Как особо извращенный вариант при наличии "лишних" таймеров могу предложить такое:

1. Настраиваете один из неиспользуемых таймеров в режим slave TIM_SlaveMode_Reset(функ. TIM_SelectSlaveMode), в качестве мастера выбираете ваш таймер.

2. В качестве выхода тригера в мастере выбираем необходимое СС(функ. TIM_SelectOutputTrigger).

3. Используем update прерывания от slave.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...