STM32/STM8技术论坛
直播中

王燕

7年用户 1731经验值
私信 关注
[问答]

关于stm32f4上的Timer1的问题

我在avr上进行了长时间的编程后尝试了STM32,我想使用计时器来处理冻结:
  1. HAL_tiM_Base_Start_IT(&htim1);
  2. while ((GPIOA->IDR  & GPIO_PIN_3) == 0x08)
  3. {
  4.         Clk_h
  5.     DWT_Delay(200);
  6.     Clk_l
  7.     DWT_Delay(200);
  8. }
  9. HAL_TIM_Base_Stop_IT(&htim1);

在上面的代码我等待GPIO_PIN_3将变为低状态。事情是它可能会永远保持高状态,所以我想启动timer1并在500ms之后启动触发中断。问题是while循环捕获0需要大约100us,而我的计时器配置为:


  1. static void MX_TIM1_Init(void)
  2. {

  3.   TIM_ClockConfigTypeDef sClockSourceConfig;
  4.   TIM_MasterConfigTypeDef sMasterConfig;

  5.   htim1.Instance = TIM1;
  6.   htim1.Init.Prescaler = 16799;
  7.   htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  8.   htim1.Init.Period = 4999;
  9.   htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  10.   htim1.Init.RepetitionCounter = 0;
  11.   if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  12.   {
  13.     _Error_Handler(__FILE__, __LINE__);
  14.   }

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

  20.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  21.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  22.   if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  23.   {
  24.     _Error_Handler(__FILE__, __LINE__);
  25.   }

  26. }

所以它远远超过100us,不知道为什么。正如我理解计时器,启动它后,它应该开始计数,当达到该值时,它将触发中断。但即使我立即开始和停止计时器,这里:
  1. HAL_TIM_Base_Start_IT(&htim1);
  2. HAL_TIM_Base_Stop_IT(&htim1);

无论如何它会触发一次。我只需要在计数寄存器溢出时触发中断功能。这是我的溢出函数,它位于stm32f4xx_it.c:
  1. void TIM1_UP_TIM10_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 0 */

  4.   /* USER CODE END TIM1_UP_TIM10_IRQn 0 */
  5.   HAL_TIM_IRQHandler(&htim1);
  6.   /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */
  7.     sprintf(str123,"<>");
  8.     CDC_Transmit_FS((uint8_t*)str123,strlen(str123));
  9.   /* USER CODE END TIM1_UP_TIM10_IRQn 1 */
  10. }





回帖(9)

王斌

2018-9-5 14:57:14
“Clk_h”和“Clk_l”是什么意思?
举报

王燕

2018-9-5 14:57:35
只是一些宏:#define Clk_h HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); #define Clk_l HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET)
举报

李萍

2018-9-5 14:58:09
我没有使用HAL,但预加载了定时器1寄存器,因此你需要发出更新事件以将新值加载到它们中。在HAL中的某个地方(可能是Base_Init?),它将执行此操作,这将导致设置更新中断标志。这就是启用中断时计时器正在激活的原因。在启动定时器/允许中断之前,只需要清除SR寄存器中的UIF(向其写入1 - 在某处执行HAL功能)。
举报

李萍

2018-9-5 14:58:42
此外,如果您来自AVR,我建议不要使用HAL。
举报

王平

2018-9-5 14:59:51
我不太习惯用HAL,所以这里是如何通过直接访问定时器外设来做你想做的事情:
// 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.
举报

张华

2018-9-5 15:00:56
楼上厉害,但是请注意,如果你不在TIM1->SR中断处理程序中再次清除,则会得到无休止的中断。
举报

陈静

2018-9-5 15:02:33
我的解决方案几乎与6楼的相同,但我会以单次模式启动计时器,以避免在处理第一次中断时花费太长时间获得第二次中断。这样,不需要定时器停止功能。
  1. void TIM1_Init() {
  2.     // edit: added clock and interrupt enable
  3.     __HAL_RCC_TIM1_CLK_ENABLE();
  4.     NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0);
  5.     NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);

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

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

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

  20. void TIM1_UP_TIM10_IRQHandler(void) {
  21.     TIM1->SR = 0;
  22.     strcpy(str123,"<>"); // sprintf should not be used in an interrupt handler
  23.     CDC_Transmit_FS((uint8_t*)str123,strlen(str123));
  24. }
举报

王燕

2018-9-5 15:04:11
如果我理解中断将被激活到TIM1_UP_TIM10_IRQHandler,我不需要触发中断功能,当应用程序没有冻结在一个looop
举报

陈静

2018-9-5 15:06:17
添加了启用时钟和中断的代码,以及定时器停止。如果它仍然不起作用,请尝试降低定时器周期(ARR)值,以防时钟按预期运行较慢。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分