Всем привет!
Пишу под 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