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

 
 
> STM32F429I-DISCO PWM Input Capture Mode
retterberg
сообщение Feb 29 2016, 09:33
Сообщение #1





Группа: Новичок
Сообщений: 3
Регистрация: 29-02-16
Пользователь №: 90 657



STM32F429I-DISCO (STM32F429ZIT6U) + датчик угла наклона. Осциллографом вижу, что при 0 градусов идут импульсы с периодом 1кгц, и шириной около 0,5кгц. При изменении угла наклона, ширина имульса меняется. Используя даташит накидал код, представленный ниже. Занимаюсь с этим микроконтроллером две недели, да и вообще занимаюсь с микроконтроллерами две недели, да и радиоэлектроникой... Ну вы поняли. biggrin.gif
Мне не удается получить ширину импульса в CCR2, лишь его период в CCR1. В CCR2 чаще всего период, иногда проскакивают 0 или 1.
И ещё, почему то не могу обнулить ни один бит регистра SR, соответственно вот эти условия if (TIM2_SR & 2) и if (TIM2_SR & 4) не имеют никакого смысла.
Как же получить в CCR2 ширину импульса?
Очень нужна помощь. Уже хочется выть и биться головой об стену.
Код
#include "define.h" //адреса и значения регистров (не пользуюсь cmsis, hal)

volatile int up;
volatile int down;

void main(void){
  RCC_AHB1ENR |= RCC_AHB1ENR_GPIOA; //GPIOA clocking
  RCC_APB1ENR |= RCC_APB1ENR_TIM2; //TIM2 clocking

  GPIOA_MODER |= GPIOA_MODER_AF_P0; //GPIOA0 alternate function
  GPIOA_AFRL |= GPIOA_AFRL_AF1_P0 //GPIOA0 TIM2_CH1

  TIM2_PSC = 16-1; //Prescaler 16
  
  TIM2_CCMR1 |= TIM2_CCMR1_CC1S_0_1; //Select TI1 active input for TIM2_CCR1
  TIM2_CCER &= ~TIM2_CCER_CC1P &
               ~TIM2_CCER_CC1NP; //TI1FP1 rising edge

  TIM2_CCMR1 |= TIM2_CCMR1_CC2S_1_0; //Select TI1 active input for TIM2_CCR2
  TIM2_CCER |= TIM2_CCER_CC2P &
              ~TIM2_CCER_CC2NP; //TI1FP2 falling edge
  
  TIM2_SMCR |= TIM2_SMCR_TS_1_0_1; //Select TI1FP1 valid trigger input
  TIM2_SMCR |= TIM2_SMCR_SMS_1_0_0; //Reset mode
  
  TIM2_CCER |= TIM2_CCER_CC1E; //Enable the capture CC1            
  TIM2_CCER |= TIM2_CCER_CC2E; //Enable the capture CC2
  
  TIM2_DIER |= TIM2_DIER_CC1IE; //Enable the interrupt CC1
  TIM2_DIER |= TIM2_DIER_CC2IE; //Enable the interrupt CC2

  TIM2_CR1 |= TIM2_CR1_CEN; //Counter enabled
  
  NVIC_ISER0 |= NVIC_ISER0_TIM2; //TIM2 Interrupt
  
  while(1);
}

//обработчик прерывания (startup.c)
void interrupt(void){
        if(TIM2_SR & 2) up=TIM2_CCR1;
        if(TIM2_SR & 4) down=TIM2_CCR2;
        TIM2_SR = 0;
}
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Сергей Борщ
сообщение Feb 29 2016, 09:41
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



С этим режимом таймера не работал, поэтому несколько общих замечаний:
Цитата(retterberg @ Feb 29 2016, 11:33) *
И ещё, почему то не могу обнулить ни один бит регистра SR, соответственно вот эти условия if (TIM2_SR & 2) и if (TIM2_SR & 4) не имеют никакого смысла.
Возможно вы просто не успеваете заметить как бит обнулился. Пока вы делаете шаг в отладчике датчик присылает новый сигнал и бит устанавливается снова. И еще - не используйте "магические числа", пишите if (TIM2_SR & TIM_SR_CC1IF), if (TIM2_SR & TIM_SR_CC2IF) - вам самому потом будет понятнее. Кроме этого - после обнуления флагов надо поставить инструкцию DSB, иначе есть риск войти в этот же обработчик снова сразу после выхода, из-за конвейера. Далее, можно на входе в прерывание считать TIM2_SR во временную переменную, тут же сбросить SR записью в него инвертированного значения считанных флагов и дальше анализировать флаги в переменной. Это позволит обойтись без DSB (конвейер успеет продвинуться за время проверки флагов) и позволит вам не потерять флаги, возникшие между чтением SR и его сбросом (так как вы сбросите только те флаги, которые уже считаны) и код ваш будет короче и быстрее, ибо чтение TIM2_SR произойдет только один раз, а не при проверке каждого флага:

Код
void interrupt(void)
{
     uint32_t Flags = TIM2_SR;
     TIM2_SR = ~Flags;

     if(Flags & TIM_SR_CC1IF)
        up=TIM2_CCR1;
     if(Flags & TIM_SR_CC2IF)
        down=TIM2_CCR2;
}


Цитата
Код
TIM2_DIER |= TIM2_DIER_CC1IE; //Enable the interrupt CC1
TIM2_DIER |= TIM2_DIER_CC2IE; //Enable the interrupt CC2
Эти две записи можно объединить:

Код
TIM2_DIER |= 0
    | TIM2_DIER_CC1IE    //Enable the interrupt CC1
    | TIM2_DIER_CC2IE    //Enable the interrupt CC2
  ;
Тогда у вас будет всего одно чтение и одна запись в регистр. И если вам не нужно сохранять состояние остальных битов (а чаще всего это именно так), такой вариант позволяет писать "=" вместо "|=" и заодно обнулить ненужные биты.

Код
NVIC_ISER0 |= NVIC_ISER0_TIM2; //TIM2 Interrupt
Здесь "|=" избыточно. Запись нуля в этот регистр не меняет его состояния, поэтому достаточно писать NVIC_ISER0 = NVIC_ISER0_TIM2


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post



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

 


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


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