Timer1 en stm32f4

1

Estoy probando stm32 después de un largo tiempo de programación en avr, y parece que estoy luchando con el temporizador. Quiero usar el temporizador para manejar las congelaciones:

 HAL_TIM_Base_Start_IT(&htim1);
while ((GPIOA->IDR  & GPIO_PIN_3) == 0x08) 
{
        Clk_h
    DWT_Delay(200);
    Clk_l
    DWT_Delay(200);
}
 HAL_TIM_Base_Stop_IT(&htim1);

En el código anterior, estoy esperando cuando GPIO_PIN_3 se encuentre en un estado bajo. Lo que pasa es que es posible que permanezca en estado alto para siempre, por lo que quiero iniciar el temporizador1 y después de 500 ms, debe disparar la interrupción. El problema es que mientras el bucle atrapa 0, tomó alrededor de 100 us, y mi temporizador se configuró con:

static void MX_TIM1_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 16799;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 4999;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

así que es mucho más que 100us, pero lo que sea que se dispare una vez, no sé por qué. Como entiendo temporizador, después de iniciarlo, debería comenzar a contar y cuando se alcance el valor, se activará la interrupción. Pero aquí incluso si inmediatamente inicio y detengo el temporizador:

  HAL_TIM_Base_Start_IT(&htim1);
 HAL_TIM_Base_Stop_IT(&htim1);

se activará una vez de todos modos. Lo que necesito es activar la función de interrupción solo cuando ocurre un desbordamiento en el registro de conteo. Aquí está mi función de desbordamiento, que se encuentra en stm32f4xx_it.c:

void TIM1_UP_TIM10_IRQHandler(void)
{
  /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 0 */

  /* USER CODE END TIM1_UP_TIM10_IRQn 0 */
  HAL_TIM_IRQHandler(&htim1);
  /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */
    sprintf(str123,"<<FAIL>>");
    CDC_Transmit_FS((uint8_t*)str123,strlen(str123));
  /* USER CODE END TIM1_UP_TIM10_IRQn 1 */
}
    
pregunta James_BK

2 respuestas

3

Realmente no me gusta el HAL, por lo que aquí se explica cómo hacer lo que quiere simplemente accediendo directamente al periférico del temporizador:

// SETUP STUFF:

// Enable the timer clock. I use the HAL for this
// as it adds the required startup delay. The code
// is pretty simple though.
__HAL_RCC_TIM1_CLK_ENABLE();

// Reset the control register. This gives us the 
// default operation which is counting up with no
// divider.
TIM1->CR1 = 0;

// Set prescaler
TIM1->PSC = 16799;

// Will generate interrupt when this value is reached
TIM1->ARR = 4999;

// The PSC and ARR values are currently in the preload
// registers. To load them into the active registers we
// need an update event. We can do this manually as
// follows (or we could wait for the timer to expire).
TIM1->EGR |= TIM_EGR_UG;

// Timer is now ready to use.

// POLLING OPERATION:

// Next we setup the interrupts. We should first clear
// the update interrupt flag in case it has already been
// set.
TIM1->SR = ~TIM_SR_UIF;

// Then we can enable the update interrupt source
TIM1->DIER |= TIM_DIER_UIE;

// Note: we also need to setup the interrupt channel on
// the NVIC. Once that is done the isr will fire
// when the timer reaches 5000.

// We can now start the timer running...
TIM1->CR1 |= TIM_CR_CEN;

while ((GPIOA->IDR  & GPIO_PIN_3) == 0x08) 
{
    Clk_h
    DWT_Delay(200);
    Clk_l
    DWT_Delay(200);
}

// ...and stop the timer when we're done
TIM1->CR1 &= ~TIM_CR_CEN;

// Note if we want to repeat the polling loop again we should
// issue another TIM1->EGR |= TIM_EGR_UG event as this
// resets the timer to zero.
    
respondido por el Jon
3

Mi solución sería casi idéntica a la de @Jon's, pero iniciaría el temporizador en modo de un disparo, para evitar una segunda interrupción cuando el procesamiento de la primera toma demasiado tiempo. De esta manera, no se necesita la función de parada del temporizador.

void TIM1_Init() {
    // edit: added clock and interrupt enable
    __HAL_RCC_TIM1_CLK_ENABLE();
    NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0);
    NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);

    TIM1->PSC = 16799;         // prescaler
    TIM1->EGR = TIM_EGR_UG;    // generate an update event to load the prescaler
    TIM1->ARR = 4999;          // counter limit
    TIM1->SR = 0;              // clear interrupt status after the update event
    TIM1->DIER = TIM_DIER_UIE; // enable interrupt on update (overflow) event
}

void TIM1_Stop() {
    TIM1->CR1 = 0;             // stop timer by clearing CEN (and everything else) in CR1
    TIM1->CNT = 0;             // reset counter, so it will start from 0 at restart
}

void TIM1_Start() {
    TIM1->CR1 = TIM_CR1_CEN    // start the timer
        | TIM_CR1_OPM;         // in one-pulse-mode
}

void TIM1_UP_TIM10_IRQHandler(void) {
    TIM1->SR = 0;
    strcpy(str123,"<<FAIL>>"); // sprintf should not be used in an interrupt handler
    CDC_Transmit_FS((uint8_t*)str123,strlen(str123));
}
    
respondido por el berendi

Lea otras preguntas en las etiquetas