(一)简介
之前学过用按键点灯,但是会有一种缺点,就是单片机在执行别的任务时,不能及时响应按键
为了解决这个问题,我们可以学习到新的功能----中断
可以用外部中断,在按下按钮的时候,立刻处理按钮的事件,完成按钮事件后,再跳回正常程序
按键引脚PA0,LED引脚PC13

(二)讲解
引脚的外部中断配置流程
  • 开启时钟
  • 配置GPIO的模式
  • 使能NVIC中断并配置优先级
  • 配置GPIO中断
  • 使能中断和清除中断标志位
  • 编写中断服务函数

我们可以复制工程模板,同时在System文件夹内,创建一个库,"zhong.c","zhong.h"里面用来写我们的中断函数
image.png

记得在keil5里面添加
image.png

我们创建一个zhong_star函数,用来初始化中断
void zhong_star()
  • {

  • }
  • 复制代码

    开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  • RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);       
  • 复制代码

    配置GPIO,因为按键另一端是GND,所以引脚模式选择上拉输入
    // 配置GPIO口
  • GPIO_InitTypeDef GPIO_InitStruct;

  • GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
  • GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//上拉输入

  • GPIO_Init(GPIOA,&GPIO_InitStruct);
  • 复制代码

    配置中断
    配置外部中断线(EXTI Line)与GPIO端口和引脚的连接。
    • GPIO_PortSourceGPIOA:指定EXTI线与GPIOA端口相连。
    • GPIO_PinSource0:指定EXTI线与GPIOA端口的第0号引脚(PA0)相连。
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
    复制代码

    创建变量, 存储EXTI的配置参数
    EXTI_InitTypeDef EXTI_InitStruct;
  • 复制代码

    配置
    EXTI_Line0:选择中断线为EXTI Line 0。
    ENABLE:使能该EXTI线。
    EXTI_Mode_Interrupt:设置EXTI的模式为中断响应。
    EXTI_Trigger_Rising:设置EXTI触发方式为上升沿触发。
    函数:EXTI_Init,用于初始化EXTI配置。
    EXTI_InitStruct.EXTI_Line = EXTI_Line0;
  • EXTI_InitStruct.EXTI_LineCmd = ENABLE;
  • EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
  • EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
  • EXTI_Init(&EXTI_InitStruct);
  • 复制代码

    配置NVIC
    NVIC负责管理微控制器的中断和异常,确保它们能够按照既定的优先级和顺序得到处理


    设置NVIC优先级为2
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  • 复制代码

    创建变量,存储NVIC的配置参数
    NVIC_InitTypeDef NVIC_InitStruct;
  • 复制代码

    配置NVIC
    EXTI0_IRQn:指定要启用的IRQ通道为EXTI0中断。
    ENABLE:使能该IRQ通道。
    NVIC_IRQChannelPreemptionPriority:设置抢占优先级为1。
    NVIC_IRQChannelSubPriority:设置响应优先级为1(在指定的优先级分组下)。
    NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
  • NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  • NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
  • NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  • NVIC_Init(&NVIC_InitStruct);
  • 复制代码

    完成以上操作,我们可以实现
    • 将GPIOA的第0号引脚(PA0)配置为EXTI Line 0的外部中断输入。
    • 设置EXTI Line 0为中断模式,上升沿触发。
    • 配置NVIC,使能EXTI0中断,并设置其抢占优先级和响应优先级。


    (三)主函数
    先引用我们所需的库
    #include "stm32f10x.h"                  // Device header
  • #include "Delay.h"
  • #include "zhong.h"
  • 复制代码

    这里我初始化了板载LED,PC13引脚,当然可以把这一大段封装成库,这样看起来好看一点
    同时调用了中断初始化的函数zhong_star();
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  •         GPIO_InitTypeDef GPIO_InitStructure;
  •         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  •         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  •         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  •         GPIO_Init(GPIOC, &GPIO_InitStructure);

  •         zhong_star();
  • 复制代码

    while循环内可以不写程序,模拟一种运行while循环的程序
    while (1)
  •         {

  •         }
  • 复制代码

    EXTI0_IRQHandler用于处理外部中断 0(EXTI0)的中断服务函数
    意味着,当检测到中断时,会立刻跳转到这个函数内
    EXTI_GetITStatus(EXTI_Line0)这个是中断标志位,当有中断时,标志位为SET否则就是RESET
    当完成我们的函数后,需要将标志位清除EXTI_ClearITPendingBit(EXTI_Line0);
    void EXTI0_IRQHandler(void)
  •        
  • {    if(EXTI_GetITStatus(EXTI_Line0) == SET)//判断是否为EXTI0中断
  •       {
  •                     if (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13) == 0)                //获取输出寄存器的状态,如果当前引脚输出低电平
  •         {
  •                 GPIO_SetBits(GPIOC, GPIO_Pin_13);                                        //则设置PA1引脚为高电平
  •                           Delay_ms(100);
  •         }
  •         else                                                                                                        //否则,即当前引脚输出高电平
  •         {
  •                 GPIO_ResetBits(GPIOC, GPIO_Pin_13);                                        //则设置PA1引脚为低电平
  •                                           Delay_ms(100);
  •         }

  •             EXTI_ClearITPendingBit(EXTI_Line0);// 清除中断标志位
  •       }


  • }
  • 复制代码


    (四)程序现象
    2edc12eb74a9857185d1 -small-original.gif