HONG按键中断

按键中断

从主函数开始
#include "main.h"
#include "driver_key.h"
#include "driver_led.h"

int main(void)
{    
    // 初始化HAL库函数必须要调用此函数
    HAL_Init();

    /*
     * 系统时钟即AHB/APB时钟配置    
	 * 使用外部高速时钟HSE(8MHz)配置系统时钟,经过PLL放大9倍,得到72MHz
    */
    SystemClock_Config();
    
    // 初始化按键
    KeyInit();
    
    //初始化LED
    LedGpioInit();
    
    while(1)
    {
    }
}

/*
 *  函数名:void Error_Handler(void)
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*  函数作用:程序错误处理函数,此处暂时设为死循环,不做任何动作
*/
void Error_Handler(void)
{
    while(1)
    {
    }
}

Step1:初始化库函数及HAL_Init():

Step2:系统时钟配置SystemClock_Config();

Step3:初始化按键KeyInit(); 这是和上一个使用按键轮询方式区别最大的函数

  • 进入KeyInit();
/*
 *  函数名:void KeyInit(void)
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
 *  函数作用:初始化按键的引脚,配置为下降沿触发外部中断
*/
void KeyInit(void)
{
    // 定义GPIO的结构体变量
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    // 使能按键的GPIO对应的时钟
    KEY_UP_GPIO_CLK_EN();
    KEY_DOWN_GPIO_CLK_EN();
    KEY_LEFT_GPIO_CLK_EN();
    KEY_RIGHT_GPIO_CLK_EN();

    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;        // 设置为下降沿触发外部中断
    GPIO_InitStruct.Pull = GPIO_PULLUP;                 // 默认上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;       // 引脚反转速度设置为快
    
    // 初始化'Up'键引脚配置 
    GPIO_InitStruct.Pin = KEY_UP_GPIO_PIN;              // 选择按键的引脚
    HAL_GPIO_Init(KEY_UP_GPIO_PORT, &GPIO_InitStruct);
    // 初始化'Down'键引脚配置
    GPIO_InitStruct.Pin = KEY_DOWN_GPIO_PIN;            // 选择按键的引脚
    HAL_GPIO_Init(KEY_DOWN_GPIO_PORT, &GPIO_InitStruct);
    // 初始化Left'键引脚配置
    GPIO_InitStruct.Pin = KEY_LEFT_GPIO_PIN;            // 选择按键的引脚
    HAL_GPIO_Init(KEY_LEFT_GPIO_PORT, &GPIO_InitStruct);
    // 初始化'Right'键引脚配置
    GPIO_InitStruct.Pin = KEY_RIGHT_GPIO_PIN;           // 选择按键的引脚
    HAL_GPIO_Init(KEY_RIGHT_GPIO_PORT, &GPIO_InitStruct);
    
    /* EXTI interrupt init*/
    HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);

    HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI3_IRQn);

    HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}

第一步使能时钟:__HAL_RCC_GPIOx_CLK_ENABLE()
为了方便使用,使用宏定义:

#define KEY_UP_GPIO_CLK_EN()            __HAL_RCC_GPIOA_CLK_ENABLE()
#define KEY_DOWN_GPIO_CLK_EN()          __HAL_RCC_GPIOG_CLK_ENABLE()
#define KEY_LEFT_GPIO_CLK_EN()          __HAL_RCC_GPIOC_CLK_ENABLE()
#define KEY_RIGHT_GPIO_CLK_EN()         __HAL_RCC_GPIOE_CLK_ENABLE()

第二步配置结构体:Pin引脚、Mode模式、Pull上拉或者推挽

GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;        // 设置为下降沿触发外部中断
    GPIO_InitStruct.Pull = GPIO_PULLUP;                 // 默认上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

第三步初始化GPIOHAL_GPIO_Init(GPIO_TypeDef *GPIOx,GPIO_InitTypeDef *GPIO_Init)初始化每个按键对应的GPIO,“HAL_GPIO_Init()”里会判断该引脚是否为EXTI模式,如果是则调用“__HAL_RCC_AFIO_CLK_ENABLE()”使能AFIO时钟;

// 初始化'Up'键引脚配置 
    GPIO_InitStruct.Pin = KEY_UP_GPIO_PIN;              // 选择按键的引脚
    HAL_GPIO_Init(KEY_UP_GPIO_PORT, &GPIO_InitStruct);
    // 初始化'Down'键引脚配置
    GPIO_InitStruct.Pin = KEY_DOWN_GPIO_PIN;            // 选择按键的引脚
    HAL_GPIO_Init(KEY_DOWN_GPIO_PORT, &GPIO_InitStruct);
    // 初始化Left'键引脚配置
    GPIO_InitStruct.Pin = KEY_LEFT_GPIO_PIN;            // 选择按键的引脚
    HAL_GPIO_Init(KEY_LEFT_GPIO_PORT, &GPIO_InitStruct);
    // 初始化'Right'键引脚配置
    GPIO_InitStruct.Pin = KEY_RIGHT_GPIO_PIN;           // 选择按键的引脚
    HAL_GPIO_Init(KEY_RIGHT_GPIO_PORT, &GPIO_InitStruct);

第四步设置EXTI中断线的优先级和使能

/* EXTI interrupt init*/
    HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);

    HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI3_IRQn);

    HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}

Step4:中断处理函数
当中断发生后,则自动跳到中断向量表(startup.stm32f103xe.s)中所对应的中断函数所在位置,执行中断函数的内容

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                DCD     EXTI4_IRQHandler           ; EXTI Line 4
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
                DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler            ; TIM2
                DCD     TIM3_IRQHandler            ; TIM3
                DCD     TIM4_IRQHandler            ; TIM4
                DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                DCD     I2C2_ER_IRQHandler         ; I2C2 Error
                DCD     SPI1_IRQHandler            ; SPI1
                DCD     SPI2_IRQHandler            ; SPI2
                DCD     USART1_IRQHandler          ; USART1
                DCD     USART2_IRQHandler          ; USART2
                DCD     USART3_IRQHandler          ; USART3
                DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                DCD     RTC_Alarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
                DCD     TIM8_BRK_IRQHandler        ; TIM8 Break
                DCD     TIM8_UP_IRQHandler         ; TIM8 Update
                DCD     TIM8_TRG_COM_IRQHandler    ; TIM8 Trigger and Commutation
                DCD     TIM8_CC_IRQHandler         ; TIM8 Capture Compare
                DCD     ADC3_IRQHandler            ; ADC3
                DCD     FSMC_IRQHandler            ; FSMC
                DCD     SDIO_IRQHandler            ; SDIO
                DCD     TIM5_IRQHandler            ; TIM5
                DCD     SPI3_IRQHandler            ; SPI3
                DCD     UART4_IRQHandler           ; UART4
                DCD     UART5_IRQHandler           ; UART5
                DCD     TIM6_IRQHandler            ; TIM6
                DCD     TIM7_IRQHandler            ; TIM7
                DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1
                DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
                DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End

因此我们需要编写中断函数的内容。

/*
 *  函数名:void EXTI0_IRQHandler(void)
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
 *  函数作用:外部中断0的中断处理函数
*/
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(KEY_UP_GPIO_PIN);
}

/*
 *  函数名:void EXTI3_IRQHandler(void)
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
 *  函数作用:外部中断3的中断处理函数
*/
void EXTI3_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(KEY_RIGHT_GPIO_PIN);
}

/*
 *  函数名:void EXTI15_10_IRQHandler(void)
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
 *  函数作用:外部中断10-15的中断处理函数
*/
void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(KEY_DOWN_GPIO_PIN);
    HAL_GPIO_EXTI_IRQHandler(KEY_LEFT_GPIO_PIN);
}

每个中断处理函数里,都调用的“HAL_GPIO_EXTI_IRQHandler()”准备后续处理,传入参数为外部中断的引脚号
进入到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_Callback()”回调函数

static volatile bool up_flag = false;           // 定义一个全局静态标志,用以判断按键按下的次数,上下左右键类似
static volatile bool down_flag = false;
static volatile bool left_flag = false;
static volatile bool right_flag = false;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    switch(GPIO_Pin)                    // 判断是哪个按键
    {           
        case KEY_UP_GPIO_PIN:           // 如果是上键
        {           
            up_flag = !up_flag;         // 按下一次标志翻转一次
            RLED(OFF);                  
            GLED(up_flag?OFF:ON);       // 根据标志控制绿灯的亮灭
            BLED(OFF);
            break;  
        }   
        case KEY_DOWN_GPIO_PIN:         // 如果是下键
        {                               
            down_flag = !down_flag;     // 按下一次标志翻转一次
            RLED(down_flag?OFF:ON);     // 三色灯全灭或全亮
            GLED(down_flag?OFF:ON);
            BLED(down_flag?OFF:ON);
            break;  
        }   
        case KEY_LEFT_GPIO_PIN:         // 如果是左键
        {                               
            left_flag = !left_flag;     // 按下一次标志翻转一次
            RLED(left_flag?OFF:ON);     // 根据标志控制红灯的亮灭
            GLED(OFF);
            BLED(OFF);               
            break;
        }
        case KEY_RIGHT_GPIO_PIN:        // 如果是右键
        {                               
            right_flag = !right_flag;   // 按下一次标志翻转一次
            RLED(OFF);                  // 根据标志控制蓝灯的亮灭
            GLED(OFF);
            BLED(right_flag?OFF:ON);
            break;
        }
        default:break;
    }
}

主函数只需初始化LED和按键,无需任何操作。一旦按键按下产生中断,将自动跳转到对应中断向量位置,调用该位置的中断处理函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值