学习记录:使用STM32外部输入中断

系列文章目录

学习笔记:外部输入中断的概念,以及配置方法;


文章目录

  • 系列文章目录
  • 前言
  • 一、EXTI 简介
  • 二、EXTI 功能框图
    • 2.1、红色参考线
    • 2.2、绿色参考线
  • 三、中断/事件线
  • 四、外部中断的一般配置步骤
  • 五、按照外部中断配置步骤,进行代码编写
  • 实验现象


前言

STM32F1 的每个 IO 都可以作为外部中断的中断输入口.STM32F103 的中断控制器支持20个外部中断/事件请求。
每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F103 的 20 个外部中断为:
EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。


一、EXTI 简介

EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了控制器的 20 个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。

二、EXTI 功能框图

(借鉴野火参考手册)
学习记录:使用STM32外部输入中断_第1张图片
EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所不同。

2.1、红色参考线

编号 1是输入线,EXTI 控制器有 19 个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个 GPIO,也可以是一些外设的事件,输入线一般是存在电平变化的信号。
编号2 是一个边沿检测电路,它会根据上升沿触发选择寄存器 (EXTI_RTSR) 和下降沿触发选择寄存器 (EXTI_FTSR) 对应位的设置来控制信号触发。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号 1 给编号 3 电路,否则输出无效信号 0。而 EXTI_RTSR 和EXTI_FTSR 两个寄存器可以控制器需要检测哪些类型的电平跳变过程,可以是只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发。
编号 3 电路实际就是一个或门电路,它一个输入来自编号 2 电路,另外一个输入来自软件中断事件寄存器 (EXTI_SWIER)。EXTI_SWIER 允许我们通过程序控制就可以启动中断/事件线,所以这两个输入随便一个有有效信号 1就可以输出 1 给编号 4 和编号 6 电路。
编号 4 电路是一个与门电路,它一个输入是编号 3 电路,另外一个输入来自中断屏蔽寄存器(EXTI_IMR)。与门电路要求输入都为1才输出1,导致的结果是如果EXTI_IMR设置为0 时,那不管编号 3 电路的输出信号是1 还是 0,最终编号 4 电路输出的信号都为 0;如果EXTI_IMR设置为 1 时,最终编号 4 电路输出的信号才由编号 3 电路的输出信号决定,这样可以简单的控制 EXTI_IMR 来实现是否产生中断的目的。编号 4 电路输出的信号会被保存到挂起寄存器(EXTI_PR) 内,如果确定编号 4 电路输出为 1 就会把 EXTI_PR 对应位置 1。
编号 5 是将 EXTI_PR 寄存器内容输出到 NVIC 内,从而实现系统中断事件控制。

2.2、绿色参考线

产生事件线路是在编号 3 电路之后与中断线路有所不同,之前电路都是共用的。
编号 6 电路是一个与门,它一个输入来自编号 3 电路,另外一个输入来自事件屏蔽寄存器 (EXTI_EMR)。如果EXTI_EMR 设置为 0 时,那不管编号 3 电路的输出信号是 1 还是 0,最终编号 6 电路输出的信号都为 0;如果 EXTI_EMR 设置为 1 时,最终编号 6 电路输出的信号才由编号 3 电路的输出信号决定,这样我们可以简单的控制 EXTI_EMR 来实现是否产生事件的目的。
编号 7 是一个脉冲发生器电路,当它的输入端,即编号 6 电路的输出端,是一个有效信号 1 时就会产生一个脉冲;如果输入端是无效信号就不会输出脉冲。
编号 8 是一个脉冲信号,就是产生事件的线路最终的产物,这个脉冲信号可以给其他外设电路使用,比如定时器 TIM、模拟数字转换器 ADC 等等,这样的脉冲信号一般用来触发 TIM 或者 ADC开始转换。
产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
EXTI 是在 APB2 总线上的

三、中断/事件线

EXTI0EXTI15 用于 GPIO,通过编程控制可以实现任意一个 GPIO 作为 EXTI 的输入源。EXTI0 可以通过 AFIO 的外部中断配置寄存器 1(AFIO_EXTICR1) 的EXTI0[3:0] 位选择配置为 PA0、PB0、PC0、PD0、PE0、PF0、PG0、PH0 或者 PI0。
学习记录:使用STM32外部输入中断_第2张图片

GPIO 的引脚 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线 0~15。
这样每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。
学习记录:使用STM32外部输入中断_第3张图片

四、外部中断的一般配置步骤

① 初始化IO口为输入。

GPIO_Init();

② 开启IO口复用时钟。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

③ 设置IO口与中断线的映射关系。

 void GPIO_EXTILineConfig();

④ 初始化线上中断,设置触发条件等。

EXTI_Init();

⑤ 配置中断分组(NVIC),并使能中断。

NVIC_Init();

⑥ 编写中断服务函数。

EXTIx_IRQHandler();

⑦ 清除中断标志位

EXTI_ClearITPendingBit();

五、按照外部中断配置步骤,进行代码编写

exti.h代码如下所示

#ifndef __EXTI_H
#define __EXIT_H	 
#include "sys.h"

void EXTIX_Init(void);//外部中断初始化	

#endif


exti.c代码如下所示

#include "exti.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
#include "beep.h"
 
/*外部中断0服务程序*/
void EXTIX_Init(void)
{
 
			EXTI_InitTypeDef EXTI_InitStructure;
			NVIC_InitTypeDef NVIC_InitStructure;

			KEY_Init();	 //	按键端口初始化

			RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟

			//GPIOE.3	 中断线以及中断初始化配置 下降沿触发 //KEY1
			GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
			EXTI_InitStructure.EXTI_Line=EXTI_Line3;//指定要配置的中断线3
			EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	//模式:中断
			EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//触发方式下降沿
			EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

			//GPIOE.4	 中断线以及中断初始化配置  下降沿触发	//KEY0
			GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);
			EXTI_InitStructure.EXTI_Line=EXTI_Line4;
			EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器


			//GPIOA.0	  中断线以及中断初始化配置 上升沿触发 PA0  WK_UP
			GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); 

			EXTI_InitStructure.EXTI_Line=EXTI_Line0;
			EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
			EXTI_Init(&EXTI_InitStructure);		//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器


			NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//使能按键WK_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 = EXTI3_IRQn;			//使能按键KEY1所在的外部中断通道
			NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
			NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;					//子优先级1 
			NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
			NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

			NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;			//使能按键KEY0所在的外部中断通道
			NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
			NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;					//子优先级0 
			NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
			NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 
}
//外部中断0服务程序 
void EXTI0_IRQHandler(void)
{
		delay_ms(10);//消抖
		if(WK_UP==1)	 	 //WK_UP按键
		{				 
				BEEP=!BEEP;	
		}
		EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位  
}
 

//外部中断3服务程序
void EXTI3_IRQHandler(void)
{
		delay_ms(10);//消抖
		if(KEY1==0)	 //按键KEY1
		{				 
			LED1=!LED1;
		}		 
		EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志位  
}

void EXTI4_IRQHandler(void)
{
		delay_ms(10);//消抖
		if(KEY0==0)	 //按键KEY0
		{
			LED0=!LED0;
			LED1=!LED1; 
		}		 
		EXTI_ClearITPendingBit(EXTI_Line4);  //清除LINE4上的中断标志位  
}
 

main.c代码如下所示

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


实验现象

外设中断按键控制串口通讯

你可能感兴趣的:(STM32学习笔记,stm32,单片机,学习)