STM32F429外部中断边缘

时间:2016-01-26 09:53:51

标签: c arm embedded stm32 stm32f4discovery

我正在使用STM32F429I-Discovery板,该板有一个连接到PA0的按钮,PA0又连接到外部中断线0(EXTI0)。

使用HAL库,我可以使用外部中断在下降沿或上升沿切换LED。例如,一旦我按下按钮,LED就会改变状态,或者只有在我松开按钮后才会改变状态。

我想要做的是在上升沿中断,启动定时器,然后再次在下降沿中断,以停止定时器。我不知道如何实现这个目标?

还有一个选项可以在上升沿和下降沿触发。我不知道是否只应该有一个中断,然后我会弄清楚它是上升沿还是下降沿(可能直接访问寄存器),或者是否应该有两个配置的中断 - 一个作为上升沿,一个作为下降力?

以下是外部中断代码;首先将GPIO设置为外部中断,然后检测中断然后处理中断(回调)。

    static void EXTILine0_Config(void)
{
  GPIO_InitTypeDef   GPIO_InitStructure;

  /* Enable GPIOA clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /* Configure PA0 pin as input floating */
  GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  GPIO_InitStructure.Pin = GPIO_PIN_0;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Enable and set EXTI Line0 Interrupt to the lowest priority */
  HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}


/* Clears the interrupt after calling this I think */
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(KEY_BUTTON_PIN);
}


/**
  * @brief EXTI line detection callbacks
  * @param GPIO_Pin: Specifies the pins connected EXTI line
  * @retval None
  */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == KEY_BUTTON_PIN)
  {
    /* Toggle LED3 */
    BSP_LED_Toggle(LED3);
  }
}

有人可以指出我是如何实现这一目标的吗?

3 个答案:

答案 0 :(得分:2)

您正在寻找的是“输入捕获”,可以直接使用定时器实现,无需外部中断。在STM32F429上,PA0内部映射到定时器2通道1。

sConfigIC结构负责处理与输入捕获相关的配置。

初始化看起来像这样:

/* TIM2 init function */
void MX_TIM2_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_IC_InitTypeDef sConfigIC;

  /* Peripheral clock enable */
  __TIM2_CLK_ENABLE();

  /* Peripheral interrupt init*/
  HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(TIM2_IRQn);

  /**TIM2 GPIO Configuration    
  PA0/WKUP     ------> TIM2_CH1 
  */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 0;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 0xFFFFFFFF;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_Base_Init(&htim2);

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);

  HAL_TIM_IC_Init(&htim2);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);

  /* Input capture stuff HERE
     Change polarity as needed */
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);

}

还有中断功能:

/* IRQ */
void TIM2_IRQHandler(void)
{
   // Check for interrupt flags here
}

在中断中你必须检查CC1IF标志。定时器值存储在名为CCR1的捕获和比较寄存器中。

/编辑

不要忘记启动计时器并输入捕获通道:

HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);

这使能定时器,输入捕获的相应通道和中断。

答案 1 :(得分:1)

首先,你必须设置一个计时器,例如

TIM_HandleTypeDef htim1;

void TIM1_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 71;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 65535;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  HAL_TIM_Base_Init(&htim1);

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);

}

代码来自STM32F1,所以也许你需要适应一点,只需查看HAL手册。

上升沿和下降沿的中断是相同的,因此您必须检查中断处理程序中引脚的状态。

启动计时器

  HAL_TIM_Base_Start(&htim1);

并停止

  HAL_TIM_Base_Stop(&htim1);

计数器值存储在

TIM1->CNT

答案 2 :(得分:0)

一些背景知识:使用STM32F429I,下面的代码是显示按下蓝色用户按钮的时间,计数以毫秒为单位。 PCB具有硬件去抖电路,因此我能够获得的最快响应是大约50ms。

如前所述,PA0连接到EXTILine0。 我将PA0线设置为在上升沿和下降沿上中断。

static void EXTILine0_Config(void)
{
  GPIO_InitTypeDef   GPIO_InitStructure;

  /* Enable GPIOA clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /* Configure PA0 pin as input floating */
  GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING_FALLING;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  GPIO_InitStructure.Pin = GPIO_PIN_0;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Enable and set EXTI Line0 Interrupt to the lowest priority */
  HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

当发生中断时,我读取当前存储在HAL_GetTick()中的计数量,此函数每1毫秒计时一次。我还读取引脚是高还是低,以确定中断是在下降还是在上升沿。

uint16_t beginCount;
uint16_t stopCount;

void EXTI0_IRQHandler(void)
{

uint16_t var;
var = HAL_GetTick();
uint16_t calcCount = 0;
unsigned char buffer[10];
BSP_LCD_Clear(LCD_COLOR_WHITE);
        // The Pin Goes high when the pushbutton is pressed. 
        if (HAL_GPIO_ReadPin(GPIOA, KEY_BUTTON_PIN) == 0x01)
            {
                  beginCount = 0;
                  beginCount = var;
                  BSP_LCD_SetTextColor(LCD_COLOR_GREEN);
                  BSP_LCD_DisplayStringAtLine(6, "Rising Edge" );
            }
        else 
            {
                    stopCount = 0;
                    stopCount = var;
                    BSP_LCD_SetTextColor(LCD_COLOR_RED);
                    BSP_LCD_DisplayStringAtLine(7, (uint8_t*)"Falling Edge");

                    // Calculate Counts and covert to seconds - What if the counter overflows?
                    calcCount = stopCount - beginCount;
                    sprintf(buffer, "%d", calcCount); // Convert the integer to string and put it in variable buffer

                    BSP_LCD_DisplayStringAtLine(8, (&buffer) ); // Display the value stored at buffer's location

            }



    HAL_GPIO_EXTI_IRQHandler(KEY_BUTTON_PIN);

}

最后,中断回调会触发并切换板上的LED。 计数器只能达到65秒之后,之后它会溢出并且我的“计算”时间不正确。这种方法适用于我打算用它做的事情。我想测量20-300毫秒,精确度为几毫秒。如果计时器在两次测量之间溢出,我仍然需要进行捕获。

这种方法有什么根本错误吗?我对C不太熟悉,而STM32则没有。