реклама на сайте
подробности

 
 
> STM32F051 Таймер и прерывания
Влад Р.
сообщение Jan 22 2014, 20:50
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 87
Регистрация: 9-12-10
Пользователь №: 61 511



Всем привет!

Пишу под STM32F051.
На контакте PC1 при помощи таймера общего назначения TIM16 формирую сигнал, где положительный полупериод имеет фиксированную длительность 1 мс, а а длительность отрицательного возрастает в арифметической прогрессии от 3 мс и до... большого числа, не столь важно. Отрицательный полупериод формируется первым, переключение уровня осуществляется в обработчике прерывания таймера, которое должно вызываться !ТОЛЬКО! по переполнению таймера (с установкой флага UIF в регистре SR). Обратное переключение осуществляется уже в основной функции программы без вызова прерывания.

Однако, прерывание вызывается еще в ряде случаев. В обработчике видно. что флаг UIF в регистре SR сброшен. Иногда в обработчике отладчик показывает установленный флаг CC1IF в регистре SR. Если вход в обработчик произошел не из-за переполнения таймера, то необходимо обнулять весь регистр SR, иначе происходит следующее: корректно формируется отрицательный полупериод только первый раз, в последующих периодах длительность отрицательного полупериода составляет порядка 2 мкс.
Это может происходить по причине неустановки правильного конечного значения счета или же еще по какой-то неизвестной мне причине.

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

Код
void TIM16_IRQHandler(void)
{
  // Что вызывает прерывние, если в регистре DIER установлен только бит TIM_DIER_UIE?
  if (!(TIM16->SR & TIM_SR_UIF)) {                              // То самое "магическое" условие
    TIM16->SR = 0;
    return;
  }
  NVIC_DisableIRQ(TIM16_IRQn);                                  // Запретить обработку прерываний от таймера TIM16
  GPIOC->ODR ^= GPIO_ODR_1;                                     // Инвертировать значение на порту PC1 - установить высокий уровень
  TIM16->SR &= ~TIM_SR_UIF;                                     // Сбросить флаг прерывания
}


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

CODE
#include "stm32f0xx.h"

void main(void)
{
uint16_t delay = 2999;

RCC->AHBENR |= RCC_AHBENR_GPIOCEN; // Тактируем порт в/в C
RCC->APB2ENR |= RCC_APB2ENR_TIM16EN; // Тактируем таймер TIM16

// Настраиваем пин выхода
GPIOC->MODER &= ~GPIO_MODER_MODER1; // Срасываем настройки режима работы пина
GPIOC->MODER |= GPIO_MODER_MODER1_0; // Режим выхода
GPIOC->OTYPER &= ~GPIO_OTYPER_OT_1; // Режим двухтактного выхода
GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR1_0; // Выходная частота - 10 МГц
GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR1; // Отключаем подтягивающие резисторы пинов
GPIOC->ODR &= ~GPIO_ODR_1; // Установить низкий уровень

TIM16->PSC = 47; // Настраиваем таймер TIM16 на период 1 мкс
TIM16->EGR = TIM_EGR_UG; // Сгенерировать событие для загрузки нового значения предделителя
TIM16->SR &= ~TIM_SR_UIF; // Сбросить флаг прерывания
TIM16->CR1 = TIM_CR1_OPM; // Установить режим "одного импульса"
TIM16->DIER = TIM_DIER_UIE; // Включить прерывание по переполнению счетчика таймера TIM16
NVIC_SetPriority(TIM16_IRQn, 1);

while (1) {
TIM16->ARR = delay; // Установить начальную длительность отрицательного полупериода - 3 мкс
delay += 100; // Увеличивать каждый отрицательный полупериод импульса на 0,1 мкс
TIM16->CR1 |= TIM_CR1_CEN; // Включить таймер TIM16
NVIC_EnableIRQ(TIM16_IRQn); // Разрешить обработку прерываний от таймера TIM16
while (NVIC->ISER[0] & (1 << TIM16_IRQn)); // Ожидаем отключения прерываний от таймера TIM16 (после выхода из обработчика)
TIM16->ARR = 999; // Установить постоянную длительность положительного полупериода - 1 мкс
TIM16->CR1 |= TIM_CR1_CEN; // Включить таймер TIM16
while (!(TIM16->SR & TIM_SR_UIF)); // Дождаться конца задержки
TIM16->SR &= ~TIM_SR_UIF; // Сбросить флаг прерывания
GPIOC->ODR ^= GPIO_ODR_1; // Инвертировать значение на порту PC1 - установить низкий уровень
}
}

void TIM16_IRQHandler(void)
{
// Что вызывает прерывние, если в регистре DIER установлен только бит TIM_DIER_UIE?
if (!(TIM16->SR & TIM_SR_UIF)) { // То самое "магическое" условие
TIM16->SR = 0;
return;
}
NVIC_DisableIRQ(TIM16_IRQn); // Запретить обработку прерываний от таймера TIM16
GPIOC->ODR ^= GPIO_ODR_1; // Инвертировать значение на порту PC1 - установить высокий уровень
TIM16->SR &= ~TIM_SR_UIF; // Сбросить флаг прерывания
}


Сообщение отредактировал Влад Р. - Jan 23 2014, 06:47
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 13:10
Рейтинг@Mail.ru


Страница сгенерированна за 0.01367 секунд с 7
ELECTRONIX ©2004-2016