STM32学习心得十五:外部中断实验

记录一下,方便以后翻阅~
主要内容:
1) 外部中断概述;
2) 外部中断库函数一般设置。
官方资料:《STM32中文参考手册V10》第9章——中断和事件
1. 外部中断基础知识
1.1 STM32的每个I/O都可以作为外部中断输入;
1.2 STM32的中断控制器支持19个外部中断/事件请求:
线0~15:对应外部IO口的输入中断;
线16:连接到PVD输出;
线17:连接到RTC闹钟事件;
线18:连接到USB唤醒事件。
1.3 每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位;
1.4 从上面可以看出,STM32供I/O使用的中断线只有16个,但是STM32F10x系列的I/O口多达上百个,如STM32F103ZET6(112个),STM32F103RCT6(51个);
1.5 外部中断通用I/O映像:
GPIOx.0映射到EXTI0;
GPIOx.1映射到EXTI1;

GPIOx.15映射到EXTI15。
STM32学习心得十五:外部中断实验_第1张图片
备注:同一时间,只能有一个I/O口映射到中断线EXTIx上。
1.6 对于每个中断线,可以设置相应的触发方式(上升沿触发,下降沿触发,边沿触发)以及使能;
1.7 I/O口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数(下表缺EXTI0);
STM32学习心得十五:外部中断实验_第2张图片
从上表中可以看出,外部中断线5~ 9分配一个中断向量,共用一个服务函数,外部中断线10~15分配一个中断向量,共用一个中断服务函数。
2. 外部中断服务函数列表

void EXTI0_IRQHandler (void);
void EXTI1_IRQHandler (void);
void EXTI2_IRQHandler (void);
void EXTI3_IRQHandler (void);
void EXTI4_IRQHandler (void);
void EXTI9_5_IRQHandler (void);
void EXTI15_10_IRQHandler (void);

3. 外部中断常用库函数
3.1 库函数一

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
//设置IO口与中断线的映射关系,例如GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);//

2.2 库函数二

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//初始化中断线:触发方式等//

2.3 库函数三

ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//判断中断线中断状态,是否发生,用在写中断服务函数时开头//

2.4 库函数四

 void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//清除中断线上的中断标志位,用在写中断服务函数时末尾//

3. EXTI_Init函数解读

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
typedef struct
{
uint32_t EXTI_Line;                 //指定要配置的中断线//
EXTIMode_TypeDef EXTI_Mode;         //模式:事件OR中断,对于外部就选择中断//
EXTITrigger_TypeDef EXTI_Trigger;   //触发方式:上升沿/下降沿/双沿触发//
FunctionalState EXTI_LineCmd;       //使能 OR失能//
}
EXTI_InitTypeDef;

案例:

//*申明一个结构体,名字为EXTI_InitStructure,结构体原型由EXTI_InitTypeDef确定*//
EXTI_InitTypeDef EXTI_InitStructure;
//使能复用功能时钟//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); 
//设置I/O口与中断线的映射关系//
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);       //GPIOE.2//
//GPIOE.2 中断线以及中断初始化配置,下降沿触发//
EXTI_InitStructure.EXTI_Line=EXTI_Line2;      
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
//*根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器*//  
EXTI_Init(&EXTI_InitStructure);

4. 外部中断的一般配置步骤
4.1 初始化IO口为输入;

GPIO_Init();

4.2 开启IO口复用时钟;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

4.3 设置IO口与中断线的映射关系;

void GPIO_EXTILineConfig();

4.4 初始化线上中断,设置触发条件等;

EXTI_Init();

4.5 配置中断分组(NVIC),并使能中断;

 NVIC_Init();

4.6 编写中断服务函数;

EXTIx_IRQHandler();

4.7 清除中断标志位。

EXTI_ClearITPendingBit();

5. 外部中断实验
实现功能:启动后,LED0亮,WK_UP按键控制蜂鸣器叫与不叫,KEY2按键控制LED0亮与灭,KEY1按键控制LED1亮与灭,KEY0按键同时控制LED0和LED1亮灭,这些按键操作的同时,串口会将按键的相关信息传输至PC端。跑马灯,蜂鸣器,按键输入,串口初始化相关代码可参考之前的文章。
5.1exti.h外部中断头文件

#ifndef __EXTI_H
#define __EXTI_H
//申明一个EXTIx_Init初始化函数//
void EXTIx_Init(void);
#endif

5.2exti.c外部中断.c文件

#include "led.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "usart.h"
#include "sys.h"
//编写EXTIx_Init初始化函数,包括中断线配置和每个中断线的优先级配置//
void EXTIx_Init(void)
{
    //*申明一个结构体,名字为EXTI_InitStructure,结构体原型由EXTI_InitTypeDef确定*//
    EXTI_InitTypeDef EXTI_InitStructure;
    //*申明一个结构体,名字为NVIC_InitStructure,结构体原型由NVIC_InitTypeDef确定*//
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   //使能复用功能时钟AFIO//
    //设置I/O口与中断线的映射关系//
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);         //PE2对应KEY2//
    //PE2中断线初始化配置,中断模式,下降沿触发,使能//
    EXTI_InitStructure.EXTI_Line=EXTI_Line2;                           //GPIOx,Pin2对应EXTI2中断线//
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;                //中断模式//
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;            //下降沿触发//
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;                          //使能//
    //中断线初始化,GPIOE,Pin2映射到EXTI2中断线,中断模式,下降沿触发,使能// 
    EXTI_Init(&EXTI_InitStructure); 
    //设置I/O口与中断线的映射关系//
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);         //PE3对应KEY1//
    //PE3中断线初始化配置,中断模式,下降沿触发,使能//
    EXTI_InitStructure.EXTI_Line=EXTI_Line3;                           //GPIOx,Pin3对应EXTI3中断线//                      
    //中断线初始化,GPIOE,Pin3映射到EXTI3中断线,中断模式,下降沿触发,使能// 
    EXTI_Init(&EXTI_InitStructure);                                    //EXTI_InitStructure结构体参数只改中断线//
    //设置I/O口与中断线的映射关系//
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);         //PE4对应KEY0//
    //PE4中断线初始化配置,中断模式,下降沿触发,使能// 
    EXTI_InitStructure.EXTI_Line=EXTI_Line4;                           //GPIOx,Pin4对应EXTI4中断线// 
    //中断线初始化,GPIOE,Pin4映射到EXTI4中断线,中断模式,下降沿触发,使能// 
    EXTI_Init(&EXTI_InitStructure);                                    //EXTI_InitStructure结构体参数只改中断线//
    //设置I/O口与中断线的映射关系// 
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);         //PA0对应WK_UP//
    //PA0中断线初始化配置,中断模式,上升沿触发,使能//
    EXTI_InitStructure.EXTI_Line=EXTI_Line0;                           //GPIOx,Pin0对应EXTI0中断线// 
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;             //上升沿触发//
    //中断线初始化,GPIOA,Pin0映射到EXTI0中断线,中断模式,上降沿触发,使能// 
    EXTI_Init(&EXTI_InitStructure);                                    //EXTI_InitStructure结构体参数改中断线和触发//
    //对上述配置好的每个中断进行优先级初始化//
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;                   //选择EXTI0外部中断通道,即PA0,即K_UP
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;       //抢占优先级2, 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;              //响应优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                    //使能//
    NVIC_Init(&NVIC_InitStructure); 
    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;                   //选择EXTI2外部中断通道,即PE2,即KEY2
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;       //抢占优先级2, 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;              //响应优先级2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                    //使能//
    NVIC_Init(&NVIC_InitStructure); 
    NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;                   //选择EXTI3外部中断通道,即PE3,即KEY1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;       //抢占优先级2 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;              //响应优先级1 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                    //使能//
    NVIC_Init(&NVIC_InitStructure);  
    NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;                   //选择EXTI4外部中断通道,即PE4,即KEY0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;       //抢占优先级2 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;              //响应优先级0 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                    //使能//
    NVIC_Init(&NVIC_InitStructure);   
 }
//编写EXTI0中断服务函数//
void EXTI0_IRQHandler(void)
{
 delay_ms(10);                           //消抖
 if(WK_UP==1)                            //判断WK_UP按键是否按下,按下则WK_UP==1,if(1)
   {     
    BEEP=!BEEP; 
    printf("蜂鸣器值转换\r\n");  
   }
    EXTI_ClearITPendingBit(EXTI_Line0);  //清除LINE0上的中断标志位  
}
//编写EXTI2中断服务函数//
void EXTI2_IRQHandler(void)
{
 delay_ms(10);                        //消抖
 if(KEY2==0)                          判断KEY2按键是否按下,按下则KEY2==0,if(1)
   {
    LED0=!LED0;
    printf("LED0值转换\r\n");
   }   
    EXTI_ClearITPendingBit(EXTI_Line2);  //清除LINE2上的中断标志位  
}
//编写EXTI3中断服务函数//
void EXTI3_IRQHandler(void)
{
 delay_ms(10);                        //消抖
 if(KEY1==0)                          判断KEY1按键是否按下,按下则KEY1==0,if(1)
   {     
    LED1=!LED1;
    printf("LED1值转换\r\n");
   }   
    EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志位  
}
//编写EXTI4中断服务函数//
void EXTI4_IRQHandler(void)
{
 delay_ms(10);                        //消抖
 if(KEY0==0)                          判断WK_UP按键是否按下,按下则KEY0==0,if(1)
   {
    LED0=!LED0;
    LED1=!LED1;
    printf("LED0和LED1值转换\r\n");  
   }   
    EXTI_ClearITPendingBit(EXTI_Line4);  //清除LINE4上的中断标志位  
}

5.3 main.c主函数

#include "led.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "usart.h"
#include "sys.h"
 int main(void)
 {  
  delay_init();                                    //延时函数初始化   
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  uart_init(115200);                               //串口波特率设置为115200
  LED_Init();                                      //初始化与LED连接的硬件接口
  BEEP_Init();                                     //初始化蜂鸣器端口
  KEY_Init();                                      //初始化与按键连接的硬件接口
  EXTIx_Init();                                    //外部中断初始化
  LED0=0;                                          //点亮LED0
  while(1)
  {     
   printf("OK\r\n"); 
   delay_ms(1000);   
  }
 }

旧知识点
1)复习如何新建工程模板,可参考STM32学习心得二:新建工程模板;
2)复习基于库函数的初始化函数的一般格式,可参考STM32学习心得三:GPIO实验-基于库函数;
3)复习寄存器地址,可参考STM32学习心得四:GPIO实验-基于寄存器;
4)复习位操作,可参考STM32学习心得五:GPIO实验-基于位操作;
5)复习时钟使能相关函数,可参考STM32学习心得七:STM32时钟系统框图解读及相关函数;
6)复习延迟函数,可参考STM32学习心得九:Systick滴答定时器和延时函数解读;
7)复习ST-LINK调试方法,可参考STM32学习心得十一:ST-LINK调试原理+软硬件仿真调试方法;
8)复习如何对GPIO进行复用,可参考STM32学习心得十二:端口复用和重映射;
9)复习中断相关知识,可参考STM32学习心得十三:NVIC中断优先级管理;
10)复习串口通信相关知识,可参考STM32学习心得十四:串口通信相关知识及配置方法。

你可能感兴趣的:(STM32基于标准库的学习,stm32,嵌入式,单片机,keil,mdk,c语言)