首页 文章

STM32F429外部中断边沿

提问于
浏览
0

我使用的是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

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

    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
    
  • 1

    您正在寻找的是“输入捕获”,可以直接使用定时器实现,无需外部中断 . 在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);
    

    这使得定时器,输入捕获的相应通道和中断成为可能 .

  • 2

    一点背景:使用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则没有 .

相关问题