STM32L1 上的外部中断设置没有 运行 ISR
External Interrupt Setup on STM32L1 doesn't run ISR
现在已经 4 天了,我一直在努力在我的 STM32 上设置外部中断,我已经阅读了大量的资料和其他人的代码来获得它。但没有运气。
我有两个按钮,当按下其中任何一个按钮时,我希望点亮一个 LED,这个例子只是让它工作,我想在继续和构建其余代码之前有一些功能。
如果代码有点乱,我很抱歉,但我正在努力整理我的编码技巧。
我浏览了手册和数据表,但似乎无济于事。
这是我的 main.c
#include "stm32l1xx_hal.h"
#include "buttons.h"
static void MX_GPIO_Init(void);
bool RightButtonFlag = 0;
bool LeftButtonFlag = 0;
int main(void)
{
HAL_Init();
SystemClock_Config();
controls_Interrupt_Init();
MX_GPIO_Init();
while (1)
{
if(RightButtonFlag){
Blue_ON();
}
if(LeftButtonFlag){
Green_ON();
}
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
{
后跟部分stm32l1xx_it.c
#include "stm32l1xx_hal.h"
#include "stm32l1xx.h"
#include "stm32l1xx_it.h"
#include "buttons.h"
extern volatile uint8_t RightButtonFlag;
extern volatile uint8_t RightButtonFlag;
void EXTI15_10_IRQHandler(void)
{
if(GPIOC->IDR & GPIO_IDR_IDR_10){
RightButtonFlag = 1;
EXTI->PR |= EXTI_PR_PR10;
}
if(GPIOC->IDR & GPIO_IDR_IDR_11){
LeftButtonFlag = 1;
EXTI->PR |= EXTI_PR_PR11;
}
}
buttons.c
void controls_Interrupt_Init(void){
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* Enable System Configuration Register */
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR3_EXTI11_PC; /* Set up External Interrupt for Pin 11 Port C */
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR3_EXTI10_PC; /* Set up External Interrupt for Pin 10 Port C */
EXTI->IMR |= EXTI_IMR_MR11;
EXTI->IMR |= EXTI_IMR_MR10;
EXTI->FTSR |= EXTI_FTSR_TR11; /* Falling trigger Selection Reg. Trigger 11 */
EXTI->FTSR |= EXTI_FTSR_TR10; /* Falling trigger Selection Reg. Trigger 10 */
NVIC_SetPriority(EXTI15_10_IRQn,1); /* Set Interrupt priority for pins 10-15 */
NVIC_EnableIRQ(EXTI15_10_IRQn); /* Enable NVIC for Pins Between 10-15 */
}
和buttons.h
void controls_Interrupt_Init(void);
#define Blue_ON() (HAL_GPIO_WritePin(BLUE_LED_PORT, BLUE_LED_PIN, 1))
#define Green_ON() (HAL_GPIO_WritePin(GREEN_LED_PORT, GREEN_LED_PIN, 1))
我对编码还很陌生,而且我的经验很差,我希望搞砸一些非常简单的事情。
您必须将标志声明为 volatile
。这是对编译器的提示,变量可以随时更改,独立于正常的程序流程。
volatile bool RightButtonFlag = 0;
volatile bool LeftButtonFlag = 0;
当那里没有 volatile
时,编译器可以假设标志在主循环中永远不会改变,并以这种方式优化它,变量只会在循环之前加载一次。
仅在中断处理程序范围内声明它们 volatile
没有任何好处,因为优化仍将在 main()
中进行,其中 volatile
声明不可见。
将声明移至头文件并在引用变量的所有位置包含该头文件是一种很好的做法。然后编译器可以检查类型是否确实兼容。
更新
中断处理程序毫无意义。您将 EXTI 设置为检测 falling 边缘,然后检查输入是否为 high。由于机械按钮的弹跳效应,检查 GPIO 数据寄存器无论如何都不可靠。
您应该在处理程序中检查 EXTI->PR
,并使用简单的赋值而不是 |=
重置挂起位,否则您可能会不小心清除另一个挂起位。
void EXTI15_10_IRQHandler(void)
{
if(EXTI->PR & EXTI_PR_PR10){
RightButtonFlag = 1;
EXTI->PR = EXTI_PR_PR10;
}
if(EXTI->PR & EXTI_PR_11){
LeftButtonFlag = 1;
EXTI->PR = EXTI_PR_PR11;
}
}
您仍然可以在某处检查 GPIOC->IDR
是否确实反映了按钮状态,以消除可能的硬件问题。
您也可以尝试通过调试器或在代码中设置 EXTI->SWIER
来模拟按下按钮。
现在已经 4 天了,我一直在努力在我的 STM32 上设置外部中断,我已经阅读了大量的资料和其他人的代码来获得它。但没有运气。 我有两个按钮,当按下其中任何一个按钮时,我希望点亮一个 LED,这个例子只是让它工作,我想在继续和构建其余代码之前有一些功能。 如果代码有点乱,我很抱歉,但我正在努力整理我的编码技巧。 我浏览了手册和数据表,但似乎无济于事。
这是我的 main.c
#include "stm32l1xx_hal.h"
#include "buttons.h"
static void MX_GPIO_Init(void);
bool RightButtonFlag = 0;
bool LeftButtonFlag = 0;
int main(void)
{
HAL_Init();
SystemClock_Config();
controls_Interrupt_Init();
MX_GPIO_Init();
while (1)
{
if(RightButtonFlag){
Blue_ON();
}
if(LeftButtonFlag){
Green_ON();
}
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
{
后跟部分stm32l1xx_it.c
#include "stm32l1xx_hal.h"
#include "stm32l1xx.h"
#include "stm32l1xx_it.h"
#include "buttons.h"
extern volatile uint8_t RightButtonFlag;
extern volatile uint8_t RightButtonFlag;
void EXTI15_10_IRQHandler(void)
{
if(GPIOC->IDR & GPIO_IDR_IDR_10){
RightButtonFlag = 1;
EXTI->PR |= EXTI_PR_PR10;
}
if(GPIOC->IDR & GPIO_IDR_IDR_11){
LeftButtonFlag = 1;
EXTI->PR |= EXTI_PR_PR11;
}
}
buttons.c
void controls_Interrupt_Init(void){
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* Enable System Configuration Register */
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR3_EXTI11_PC; /* Set up External Interrupt for Pin 11 Port C */
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR3_EXTI10_PC; /* Set up External Interrupt for Pin 10 Port C */
EXTI->IMR |= EXTI_IMR_MR11;
EXTI->IMR |= EXTI_IMR_MR10;
EXTI->FTSR |= EXTI_FTSR_TR11; /* Falling trigger Selection Reg. Trigger 11 */
EXTI->FTSR |= EXTI_FTSR_TR10; /* Falling trigger Selection Reg. Trigger 10 */
NVIC_SetPriority(EXTI15_10_IRQn,1); /* Set Interrupt priority for pins 10-15 */
NVIC_EnableIRQ(EXTI15_10_IRQn); /* Enable NVIC for Pins Between 10-15 */
}
和buttons.h
void controls_Interrupt_Init(void);
#define Blue_ON() (HAL_GPIO_WritePin(BLUE_LED_PORT, BLUE_LED_PIN, 1))
#define Green_ON() (HAL_GPIO_WritePin(GREEN_LED_PORT, GREEN_LED_PIN, 1))
我对编码还很陌生,而且我的经验很差,我希望搞砸一些非常简单的事情。
您必须将标志声明为 volatile
。这是对编译器的提示,变量可以随时更改,独立于正常的程序流程。
volatile bool RightButtonFlag = 0;
volatile bool LeftButtonFlag = 0;
当那里没有 volatile
时,编译器可以假设标志在主循环中永远不会改变,并以这种方式优化它,变量只会在循环之前加载一次。
仅在中断处理程序范围内声明它们 volatile
没有任何好处,因为优化仍将在 main()
中进行,其中 volatile
声明不可见。
将声明移至头文件并在引用变量的所有位置包含该头文件是一种很好的做法。然后编译器可以检查类型是否确实兼容。
更新
中断处理程序毫无意义。您将 EXTI 设置为检测 falling 边缘,然后检查输入是否为 high。由于机械按钮的弹跳效应,检查 GPIO 数据寄存器无论如何都不可靠。
您应该在处理程序中检查 EXTI->PR
,并使用简单的赋值而不是 |=
重置挂起位,否则您可能会不小心清除另一个挂起位。
void EXTI15_10_IRQHandler(void)
{
if(EXTI->PR & EXTI_PR_PR10){
RightButtonFlag = 1;
EXTI->PR = EXTI_PR_PR10;
}
if(EXTI->PR & EXTI_PR_11){
LeftButtonFlag = 1;
EXTI->PR = EXTI_PR_PR11;
}
}
您仍然可以在某处检查 GPIOC->IDR
是否确实反映了按钮状态,以消除可能的硬件问题。
您也可以尝试通过调试器或在代码中设置 EXTI->SWIER
来模拟按下按钮。