STM32F103C8 — прерывания таймера по сравнению (Arduino IDE)

В микроконтроллере STM32F103C8 имеются 4 таймера, таймер TIM1 работает на  шине APB2, частота которой равна частоте системной шины SYSCLK и является более продвинутым таймером,  TIM2, TIM2 и TIM4 простые таймеры общего назначения,  работают от шины APB1 частота которой равна половине частоте системной шины SYSCLK (для периферийных уст-в).

В этой статье будет рассмотрен пример работы таймера в режиме прерывания по сравнению.

Работа таймера в режиме сравнения, это когда в регистрах сравнения CCR1...CCR4 устанавливается значение которое ограничено регистром переполнения ARR. Как только отсчет таймера совпадет со значениями регистров сравнения, то тут же вызывается прерывание. Таким образом один таймер может вызывать несколько прерываний (например для исполнения какого либо кода) в рамках одного цикла переполнения.

Ниже показан пример кода, который позволяет мигать светодиодом в такт работы таймера:

void setup() {
  pinMode(PA1, OUTPUT);
  
  timer_attach_interrupt(TIMER2, TIMER_UPDATE_INTERRUPT, led1); // прерывание по переполнению
  timer_attach_interrupt(TIMER2, TIMER_CC1_INTERRUPT, led);     // прерывание по сравнению 1

  RCC_BASE->APB1ENR |= RCC_APB1ENR_TIM2EN;     // TIM2EN > включить тактирование tim_2 
  TIMER2_BASE->CR1 &= ~TIMER_CR1_CEN;          // TIMx_CR1_CEN > стоп таймер
  TIMER2_BASE->PSC = 7200-1;                   // TIMx_PSC > значение пред делителя -1 === F = 72 000 000 / 7200 = 10000 Hz
  TIMER2_BASE->ARR = 10000-1;                  // TIMx_ARR > считать до установленного числа и обнулить === F = 10000 / 10000 = 1 Hz | T = 1 s
  TIMER2_BASE->CCR1 = 5000-1;                  // TIMx_CCR1 > регистр сравнения 1 === F = 10000 / 5000 = 2 Hz | T = 0.5 s
  TIMER2_BASE->DIER |= TIMER_DIER_UIE;         // TIMx_DIER_UIE > разрешить прерывание по переполнению
  TIMER2_BASE->DIER |= TIMER_DIER_CC1IE;       // TIMx_DIER_CC1IE > разрешить прерывание по сравнению 1
  TIMER2_BASE->CR1 |= TIMER_CR1_CEN;           // TIMx_CR1_CEN > старт таймер
}

void loop() {}

void led1(){
  digitalWrite(PA1, HIGH); 
  TIMER2_BASE->SR &=~ TIMER_SR_UIF;            // TIMx_SR_UIF > сбрасываем флаг прерывания
}
void led(){  //обработчик прерывания 
  digitalWrite(PA1, LOW); 
  TIMER2_BASE->SR &=~ TIMER_SR_UIF;            // TIMx_SR_UIF > сбрасываем флаг прерывания
}

Для работы таймера на него нужно подать тактирование, делается это в регистре RCC->APB1ENR установкой бита TIM2EN.

RCC_BASE—>APB1ENR|= (1<<0);

Регистр RCC_APB1ENR

Перед настройкой таймера рекомендуется его отключить (остановить):

TIMER2_BASE—>CR1=0;  

Регистр TIMx_CR1

Все таймеры микроконтроллера STM32F103C8 16 бит (0…65535), каждый таймер имеет предделитель за который отвечает регистр TIMx_PSC. Значение этого регистра определяет коэффициент деления частоты поступающего на счетчик CK_CNT.

f(CK_CNT) = f(CK_PSC) / (PSC+1)

Так как нам необходимо чтобы таймер переполнялся через определенный интервал времени, то установим для начала предделитель на 7200.

TIMER2_BASE—>PSC = 7200—1;

Регистр TIMx_PSC

Так как предделитель равен 7200, а частота ядра микроконтроллера 72 МГц, то с выхода предделителя мы получаем частоту 10000 Гц.

Что бы еще уменьшить частоту прерываний таймера используем регистр TIMx_ARR.

TIMx_ARR — это 16-и битный регистр переполнения, который начинает считать с 0 до значения переполнения, после чего обнулится и начнет считать заново.

 TIMER2_BASE—>ARR = 10000—1;

Регистр TIMx_ARR

Так как после предделителя частота работы таймера 10 кГц, а значения прерывания по переполнению в регистре ARR равно 10000, то прерывания таймера TIM2 будут происходить с интервалом 1 секунда.

В интервал (в нашем примере) можно поместить от 1 до 4 прерываний которые будут происходить благодаря регистрам сравнения CCR1…CCR4. В примере я использую только один регистр сравнения CCR1.

Регистр TIMx_CCR1 

TIMER2_BASE>CCR1 = 50001;

Так как регистр переполнения имеет значение 10000 (72 000 000 / 7 200 / 10 000 = 1 секунда), то регистр сравнения в который установлено значение 5000 сработает ровно от половины времени установленного в регистре переполнения (0,5 сек).

Далее необходимо разрешить прерывания по переполнению и совпадению, делается это при помощи регистра TIMx_DIER.

TIMx_DIER — регистр разрешения прерываний. При при записи в биты UIE и CC1IE единиц, прерывания разрешены.

TIMER2_BASE->DIER |= TIMER_DIER_UIE; 
TIMER2_BASE->DIER |= TIMER_DIER_CC1IE;

После настройки таймера его можно запустить:

TIMER2_BASE—>CR1=1;  

Чтобы исполнять различный код по времени прерывания необходимо использовать обработчики прерывания:

timer_attach_interrupt(TIMER2, TIMER_UPDATE_INTERRUPT, led1);

timer_attach_interrupt(TIMER2, TIMER_CC1_INTERRUPT, led);

где:

  • TIMER2 — номер таймера
  • TIMER_UPDATE_INTERRUPT — вызов прерывания по переполнению
  • TIMER_CC1_INTERRUPT — вызов прерывания по совпадению
  • led и led1 — имена функций с исполняемым кодом

Функция led1 содержит код управления светодиодом, при каждом прерывании таймера светодиод  загорается.

Функция led содержит код управления светодиодом, при каждом прерывании таймера светодиод  гаснет.

После каждого прерывания необходимо сбросить флаг прерывания:

TIMER2_BASE->SR &=~(1<<0);

Регистр TIMx_SR

TIMx_SR — регистр состояния, содержит флаги прерываний. UIF – флаг прерывания по переполнению.

Добавить комментарий

Войти с помощью: