STM32通过外部中断控制灯的亮灭

中断是指把正常正在运行的程序打断,运行中断服务函数,运行完之后再回到主程序。之后笔者会附上详细的介绍。这个是相当重要的知识点,相当于插入任务,可以类似的理解为cpp中线程的join()方法。

首先我们需要再次回顾一下KEY的结构来判断我们的触发条件。

 可以看到,我们的普通按键KEY在未按下时候是高电平的高阻态,于是我们接入上拉电阻维持高电平并且使用下降沿触发中断EXTI;我们的触发按键WAKE_UP_KEY在未按下时候是低电平的高阻态,于是我们接入下拉电阻维持低电平并且使用上升沿触发中断EXTI。

 这里对上升沿触发中断和下降沿触发中断进行一些简单的解释。上升沿触发就是指在默认初始状态下原来点电位为低电位,在输入高电位信号之后转为高电平,此时便会被判断为中断触发;而下降沿则正好相反,原来的电位为高电平,在输入低电平信号之后转为低电位,此时会被判断为中断触发。

由此容易得知,我们的WAKE_UP_KEY(PA0)设置为下拉输入、上升沿触发中断,KEY0/1/2(PE4/3/2)设置为上拉输入、下降沿触发中断。

然后我们编译一些相关的C语言文件

首先是头文件exti.h:

#ifndef __EXTI_H
#define __EXTI_H

#include "./SYSTEM/sys/sys.h"

void exti_init(void);
void EXTI4_IRQHandler(void);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

#endif

再接下来是含有函数的C文件exti.c:

#include "./BSP/EXTI/exti.h"
#include "./BSP/DELAY/delay.h"

void exti_init(void){
    GPIO_InitTypeDef gpio_init_struct;
    __HAL_RCC_GPIOE_CLK_ENABLE();
    
    gpio_init_struct.Pin = GPIO_PIN_4;
    gpio_init_struct.Mode = GPIO_MODE_IT_FALLING;
    gpio_init_struct.Pull = GPIO_PULLUP;
    
    HAL_GPIO_Init(GPIOE, &gpio_init_struct);

    HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}

void EXTI4_IRQHandler(void){
    HAL_GPIO_EXTI_IRQHandler(EXTI4_IRQn);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
    delay_ms(20);
    
    if(GPIO_Pin == GPIO_PIN_4){
        if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) == 0){
            HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);
        }
    }
}

1. gpio_init_struct.Mode = GPIO_MODE_IT_FALLING

因为是在输入模式中选择的下降沿触发中断,故如此选择。

2. HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(EXTI4_IRQn);

HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)有三个参数,第一个是中断口的序号,这里因为KEY0是PE4,所以这里选择EXTI4_IRQn。

第二个是PreemptPriority抢断优先级(先占优先级), 第三个是SubPriority相应优先级(从优先级), 优先级数字越小,优先级越高。高中断优先级可在低中断优先级的处理过程中被响应,即高中断优先级可嵌套在低中断优先级的程序中。当两个中断优先级相同时候,那就要按顺序处理,如果同时中断达到,则按相应优先级区分响应。都相同时,则按中断表中的排位顺序进行处理。

如果不设置中断优先级分组,则中断优先级分组默认为0,即0位抢占优先级,4位响应优先级。

3. HAL_GPIO_EXTI_IRQHandler()

首先展示他的源码:

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

其中 __HAL_GPIO_EXTI_GET_IT(GPIO_Pin)是负责获取中断标志位的,它的原理如下源码所示,从PR(Program Register)程序寄存器获取它的串口值,如果不是0,则有中断产生。然后便会清除相应的标志位,往其中写1,并且调用相关串口的回调函数。

#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))

对于回调函数,我们发现它有weak前缀,类似于cpp里的virtual,是可以overwrite的,可以自己覆写改写,一般都是需要自定义的。

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

4.HAL_GPIO_ReadPin()

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

第一个参数为对应的GPIO口,另一个是对应的串口。如果是KEY0这样的,对应之前的图解,可以看到,key0按下之后对应的pin值就变成了0。同理,如果是WAKE_UP_KEY按下,则输出1。这个在判断串口值的时候很重要。

5.HAL_GPIO_EXTI_Callback

这是中断的回调函数,已经被我们复写了。判断如果是PE4且已经按下之后,将启动pin值反转程序。

最后我们来写主函数main.c:

#include "./BSP/EXTI/exti.h"
#include "./BSP/LED/led.h"

int main(){
    HAL_Init();
    sys_stm32_clock_init(RCC_PLL_MUL9);
    delay_init(72);
    led_init();
    exti_init();

    while(1){
        LED1(1);
        delay_ms(500);
        LED1(0);
        delay_ms(500);
    }
}

于是我们的代码就编写成功了。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值