NVIC和外部中断(HAL库)

 如有错误,请在评论区指出,万分感谢,我也是学习者,再更系统学习一次。

c6131a7b72d44f5599210903372e9a54.png

NVIC

中断向量表

STM32F407有82个可屏蔽中断,13个系统中断。可屏蔽中断和部分系统中断可以配置优先级,共16个.

fd1fa60a051f4475815183c69a440075.png

5c988acc5d924caaac3de13648f57212.png

4cead8f4a55749c8a55a83ff10e7030a.png

 0ae242db14984df79ab1bb94dffcb510.png

5ef1eb7412ff4ac3b1cbce799696553e.png

中断优先级

4位二进制数,配置抢占优先级(preemption priority),次优先级(subpriority)

bee94c5518c74c94bfa0beec40cdc236.png

NVIC常用配置函数

1b65093023f04b7984c881077d3c5ff2.png

HAL_NVIC_SetPriorityGrouping()

设置4位二进制数的优先级分组策略

063ad59da1b24da6adfeeac994b72d2d.png

HAL_NVIC_SetPriority()

设置某个中断的抢占优先级和次优先级

IRQn: 要设置优先级的中断号(如:TIM1_UP_IRQn)。

Priority: 抢占优先级值,数值范围通常为 0 到 15(具体取决于微控制器的实现)。

SubPriority: 次优先级值,数值范围同样是 0 到 15。

HAL_NVIC_EnableIRQ()

b3f8ed041ef747bb8a6e158396d044e2.png

启用某个中断

HAL_NVIC_DisableIRQ()

禁用某个中断

HAL_NVIC_GetPriorityGrouping()

返回当前的优先级分组策略

HAL_NVIC_GetPriority()

返回某个中断的抢占优先级、次优先级数值

HAL_NVIC_GetPendingIRQ()

检查某个中断是否被挂起

HAL_NVIC_SetPendingIRQ()

设置某个中断的挂起标志,表示发生了中断

HAL_NVIC_ClearPendingIRQ()

 

外部中断EXTI

外部中断功能,外部中断线

dd57a31253dc4bc6b4bbf0f70ba9f7fb.png

903ea565746341bba96809946309df4e.png

1a5214eb27a348f19ba7a227f4613871.png

外部中断函数

_HAL_GPIO_EXTI_GET_IT(uint16_t GPIO_Pin)

a0fafc28cee1446697051c52ed1bd49e.png

if (HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) 
{ 
    // 中断处理代码

    // 清除中断标志 
    HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
 }

_HAL_GPIO_EXTI_CLEAR_IT(uint16_t GPIO_Pin)

e6dfd21ef3e34888a40eab19bf9d4374.png

void EXTI0_IRQHandler(void)
{
    // 检查是否是 GPIO_PIN_0 的中断
    if (HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {
        // 清除中断标志
        HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);

        // 在此处执行中断处理逻辑,例如切换 LED 状态
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    }
}

_HAL_GPIO_EXTI_GET_FLAG()

_HAL_GPIO_EXTI_GET_IT_()

729da8630c634e379fbae3b334195726.png

_HAL_GPIO_EXTI_GENERATE_SWIT(uint16_t GPIO_Pin)

786b130b1ef04d7184783515af0ff26b.png

// 在某个条件下调用该函数以生成软件中断 
if (some_condition)
 {
    HAL_GPIO_EXTI_GENERATE_SWIT(GPIO_PIN_0); 
}

HAL_GPIO_EXTIx_IRQHandler()

5ca4d7aca1334d0dbd763ef602f162b9.png

void EXTI0_IRQHandler(void)
{
    // 检查是否是 GPIO_PIN_0 的中断
    if (HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {
        // 清除中断标志
        HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
        
        // 执行中断处理逻辑,例如切换 LED 状态
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    }
}

// 对于其他外部中断线,如 EXTI1
void EXTI1_IRQHandler(void)
{
    if (HAL_GPIO_EXTI_GET_IT(GPIO_PIN_1) != RESET) {
        HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);
        // 处理 GPIO_PIN_1 的中断
    }
}

确保在向 NVIC 注册中断时,正确指定了中断优先级和使能相关中断。在 ISR 中,尽量避免耗时操作,以保持响应速度。

HAL_GPIO_EXTIx_Callback()

3ea626a7faa048fb8bb1b598e3f56c39.png

对于0到15线的外部中断,EXTIO至EXTI4有独立的ISR,EXTIT[9:5]共用一个ISR,EXTI[15:10]共用一个ISR。在启用某个中断后,在CubeMX自动生成的中断处理程序文件stm32f4xx itc中会生成ISR的代码框架。这些外部中断ISR 的代码都是一样的,下面是几个外部中断的ISR 代码框架,只保留了其中一个ISR 的完整代码,其他的删除了代码沙箱注释。

8f0ba34dc69c42e79e3d70842e908c3e.png

5d154aa81c3b4a969fc7ee821d9b6233.png

// 中断服务例程 (ISR)
void EXTI0_IRQHandler(void)
{
    // 检查 GPIO_PIN_0 是否产生中断
    if (HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {
        HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);  // 清除中断标志
        HAL_GPIO_EXTI_Callback(GPIO_PIN_0);   // 调用用户自定义的回调函数
    }
}

// 用户定义的回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_0) {
        // 在这里处理 GPIO_PIN_0 的中断,例如切换 LED 状态
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    }
}

87217d34ca1a4510890ea289b8a2444b.png

按键中断

38511928a6f74bc2b6c66d983612e779.png

一般来说,此方式触发外部中断,但是对于按键触发是有问题的,软件查询时,有20ms的延时设计,但这样的代码,虽然清除了挂起标志,有回调函数的延时,但是下一次抖动仍可能会触发中断再执行一次回调函数。

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
/* EXTIline interrupt detected */
//检测中断挂起标志
    if( HAL_GPIO_EXTI_GET_IT(GPIO_Pin) !=RESET)
    {
        HAL_GPIO_EXTI_Callback(GPIOPin);
        HAL_GPIO_EXTI_CLEAR_IT(GPIO Pin);
    }
}

代码实例

#define KEY_UP               GPIO_Pin_2
#define KEY_UP_Port           GPIOE
#define KEY_UP_EXTI_IQR       EXTI2_IQRn
//上升沿

#define KEY_DOWN              GPIO_Pin_3
#define KEY_DOWN_Port         GPIOE
#define KEY_DOWN_EXTI_IQR     EXTI3_IQRn
//下降沿

#define KEY_Toggle              GPIO_Pin_0
#define KEY_Toggle _Port         GPIOA
#define KEY_Toggle _EXTI_IQR     EXTI0_IQRn

#define LED_ON        HAL_GPIO_WritePin(GPIOB,GPIO_Pin_1,ENABLE)
#define LED_OFF       HAL_GPIO_WritePin(GPIOB,GPIO_Pin_1,ENABLE)
#define LED_Toggle    HAL_GPIO_Togggle(HAL_GPIO_Togggle(GPIOB,GPIO_Pin_1)


void MX_GPIO_Init()
{    
    _HAL_RCC_GPIOE_CLK_ENABLE();
    _HAL_RCC_GPIOE_CLK_ENABLE();
    ……    
    /*配置GPIO引脚:KEY_UP,下拉输入,上跳沿触发*/
    GPIO_InitStruct.Pin=KEY_UP|KEY_Toggle;
    GPIO_InitStruct.Mode=GPIO_MODE_IT_RISING;
    GPIOInitStruct.Pull =GPIO_PULLDOWN;
    HAL_GPIO_Init(KEY_UP_Port|KEY_Toggle_Port,&GPIO_InitStruct);
    //上跳沿触发:
上跳沿触发意味着当引脚从低电平(0V)跳变到高电平,
    //外部中断将被触发。这用于检测按键的按下事件。
    
    //为什么使用下拉输入?
    //防止浮动状态
    /*如果不使用下拉电阻,按键未按下时 GPIO 引脚可能处于一个未定义的浮动状态(Floating State)。在这种状态下,由于噪声或其他干扰信号,GPIO 引脚可能会随机改变状态,这会导致误触发中断。使用下拉电阻可以确保在按键未按下时,引脚始终保持在稳定的低电平。*/
    
     /*配置GPIO引脚:KEY_DOWN,上拉输入,下降沿触发*/
    GPIO_InitStruct.Pin=KEY_DOWN;
    GPIO_InitStruct.Mode=GPIO_MODE_IT_FALLING;
    GPIOInitStruct.Pull =GPIO_PULLUP;
    HAL_GPIO_Init(KEY_DOWN_Port,&GPIO_InitStruct);
    
     ……     
    HAL_NVIC_SetPriority(KEY_UP_EXTI_IQR, 3, 0);      // 设置中断优先级
    HAL_NVIC_EnableIRQ(KEY_UP_EXTI_IQR);               // 启用中断    
}

void EXTI0_IRQHandler(void){
    HAL_GPIO_EXTI_IQRHandler(GPIO_PIN_0);
}

void EXTI0_GPIO_IRQHandler(uint16_t GPIO_Pin)
{
    if(_HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
    {
        HAL_GPIO_EXTI_Callback(GPIO_Pin);
        _HAL_GPIO_CLEAR_IT(GPIO_Pin);    
    }
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == KEY_UP)
    {
        HAL_Delay(10);
        /*将外部中断优先级降低,低于嘀嗒系统中断优先级,这时候可以在外部中断回调函数内使用hal delay*/
        LED_UP;
    }
    else if(GPIO_Pin == KEY_DOWN)
    {
        HAL_Delay(10);
        LED_DOWN;    
    }
    else if(GPIO_Pin == KEY_TOGGLE)
    {
        HAL_Delay(10);
        LED_TOGGLE; 
    }
}

注意事件

外部中断优先级如果优于系统记数延时中断,那么不可以使用HAL_Delay()进行延时,否则会由于低优先级的嘀嗒中断发生在高优先级的外部中断而死机。

 

STM32外部中断 HAL 通常用于处理微控制器外部中断事件,如GPIO端口的上升沿或下降沿触发。点灯功能常常作为示例来演示中断的应用,比如当某个外部信号(如按钮)被按下时,点亮 LED 表示接收到中断。 以下是使用 STM32HAL 实现外部中断并控制 LED 点亮的基本步骤: 1. **初始化硬件**: - 首先,需要配置GPIO端口作为输入,并启用中断功能。 ```c GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; // 初始化GPIO用于LED中断输入 GPIO_InitStructure.GPIO_Pin = LED_PIN; // LED所在的GPIO引脚 GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP; // 设置为推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_FREQ_LOW; // 设定速度 HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化EXTI用于外部中断 EXTI_InitStructure.EXTI_Line = EXTI_LINE_BUTTON; // 按钮对应的EXTI线 EXTI_InitStructure.EXTI_Mode = EXTI_MODE_IT_FALLING; // 异常下降沿触发 EXTI_InitStructure.EXTI_Trigger = EXTI_TRIGGER_RISING; // 触发方式 EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 开启中断 HAL_EXTI_Init(&EXTI_InitStructure); ``` 2. **设置中断服务函数**: - 创建一个回调函数,当中断发生时,这个函数会被HAL自动调用。 ```c void EXTI_Handler(void) { HAL_GPIO_WritePin(GPIOA, LED_PIN, GPIO_PIN_SET); // LED点亮 } ``` 3. **注册中断处理程序**: - 在HAL初始化之后,需要将中断处理程序注册到系统的中断管理器中。 ```c HAL_NVIC_Register ISR_IRQn, EXTI_IRQn, 0); // 替换成实际中断编号 HAL_NVIC_EnableIRQ(ISR_IRQn); // 启动中断 ``` 4. **配置中断**: ```c HAL_NVIC_SetPriority(ISR_IRQn, 0, 0); // 设置中断优先级 ``` 5. **处理用户交互**: - 用户可以按按钮,中断触发后,LED会亮起。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值