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

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

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

记得在keil5里面添加
image.png

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

  3. }

开启时钟
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);       

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

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

  5. GPIO_Init(GPIOA,&GPIO_InitStruct);

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

创建变量, 存储EXTI的配置参数
  1. EXTI_InitTypeDef EXTI_InitStruct;

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

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


设置NVIC优先级为2
  1. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

创建变量,存储NVIC的配置参数
  1. NVIC_InitTypeDef NVIC_InitStruct;

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

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


(三)主函数
先引用我们所需的库
  1. #include "stm32f10x.h"                  // Device header
  2. #include "Delay.h"
  3. #include "zhong.h"

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

  7.         zhong_star();

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

  3.         }

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

  15.             EXTI_ClearITPendingBit(EXTI_Line0);// 清除中断标志位
  16.       }


  17. }


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