STM32F103 外部中断EXIT

外部中断基本知识介绍

EXTI–外部中断/事件控制器

STM32的每个IO都可以作为外部中断的中断输入口。

STM32的中断控制器支持19个外部中断/事件请求:

**线0~15:**对应外部IO口的输入中断。
**线16:**连接到PVD(可编程电压监测器:它的作用是监视供电电压,在供电电压下降到给定的阈值以下时,产生一个中断,通知软件做紧急处理)输出。
**线17:**连接到RTC闹钟事件。
**线18:**连接到USB唤醒事件。

注:互联网型STM32有20个中断/事件请求,多了一个线19:连接到以太网事件,星光嵌入式的枭龙,猛龙开发板的STM32为非互联网型。

每个外部中断线可以独立的配置出发方式(上升沿,下降沿或者双边沿触发)

外部中断通用I/O映像
在这里插入图片描述
在这里插入图片描述

外部中断服务函数

IO口外部中断在中断向量表中只分配了7个中断向量,只能使用7个中断服务函数

中断服务函数如下,名称要与启动代码中的保持一致

EXTI0_IRQHandler ------>GPIOx.0
EXTI1_IRQHandler ------>GPIOx.1
EXTI2_IRQHandler ------>GPIOx.2
EXTI3_IRQHandler ------>GPIOx.3
EXTI4_IRQHandler ------>GPIOx.4
EXTI9_5_IRQHandler ------>GPIOx.5~GPIOx.9
EXTI10_15_IRQHandler ------>GPIOx.10~GPIOx.15

注:中断服务函数没有入口参数,没有返回值。

寄存器 :有关中断函数

初始化函数

void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)	
//中断初始化(抢占优先级,响应优先级,中断编号,中断分组) 
{ 
	u32 temp;	
	MY_NVIC_PriorityGroupConfig(NVIC_Group);
	//设置分组
	temp=NVIC_PreemptionPriority<<(4-NVIC_Group);	  
	temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
	temp&=0xf;
	//取低四位  
	NVIC->ISER[NVIC_Channel/32]|=(1<<NVIC_Channel%32);
	//使能中断
	NVIC->IP[NVIC_Channel]|=temp<<4;
	//设置响应优先级和中断优先级				   
} 

设置NVIC分组

void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)	 
{ 
	u32 temp,temp1;	  
	temp1=(~NVIC_Group)&0x07;
	//取后三位
	temp1<<=8;
	temp=SCB->AIRCR;  
	//读取先前的设置
	temp&=0X0000F8FF; 
	//清空先前的分组
	temp|=0X05FA0000; 
	//写入钥匙
	temp|=temp1;	   
	SCB->AIRCR=temp;  
	//设置分组	  				   
}

外部中断配置函数

void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM) 
//外部中断配置(GPIOx,需要使能的位,触发模式)
{
	u8 EXTADDR;
	u8 EXTOFFSET;
	EXTADDR=BITx/4;
	//得到中断寄存器组的编号
	EXTOFFSET=(BITx%4)*4; 
	RCC->APB2ENR|=0x01;
	//使能IO复用时钟	 
	AFIO->EXTICR[EXTADDR]&=~(0x000F<<EXTOFFSET);
	//清除原来的设置
	AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET;
	//EXTI.BITx映射到GPIOx.BITx
	//自动设置
	EXTI->IMR|=1<<BITx;
	//开启line BITx上的中断
	
 	if(TRIM&0x01)EXTI->FTSR|=1<<BITx;
 	//line BITx上事件下降沿触发
	if(TRIM&0x02)EXTI->RTSR|=1<<BITx;
	//line BITx上事件上升降沿触发
}

寄存器代码

test.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
#include "exti.h"


int main(void)
{
	Stm32_Clock_Init(9);
	//系统时钟设置
	uart_init(72,115200);
	//串口初始化为115200
	delay_init(72);
	//延时初始化
	LED_Init();
	//初始化与LED连接的硬件接口
	BEEP_Init();
	//初始化蜂鸣器
	EXTIX_Init();
	//初始化外部中断输入

	
	while(1)
	{
		printf("OK\r\n");
		delay_ms(500);
	}
}

exti.h

#ifndef __EXTI_H
#define __EXTI_H

void EXTIX_Init(void);

#endif

exti.c

#include "exti.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "beep.h"

void EXTI0_IRQHandler(void)
//外部中断0服务函数
//我记得函数我写成了 
//void EXTI0_IRQnHandler(void)
//没有报错,但是进入了死循环
{
	delay_ms(10);
	//消抖
	if(KEY1 == 0)
	{
		BEEP = !BEEP;
	}
	EXTI->PR = 1<<0;
	//清除LINE0的中断标志位
}

void EXTI3_IRQHandler(void)
{

	delay_ms(10);
	if(KEY2 == 0)
	{
		
		LED1 = !LED1;
	}
	EXTI->PR = 1<<3;
}

void EXTI2_IRQHandler(void)
{
	
	delay_ms(10);
	if(KEY3 == 0)
	{
		
		LED2 = !LED2;
	}
	EXTI->PR = 1<<2;
}

void EXTI1_IRQHandler(void)
{
	
	delay_ms(10);
	if(KEY4 == 0)
	{
		
		LED3 = !LED3;
	}
	EXTI->PR = 1<<1;
}


void EXTIX_Init(void)
//外部中断初始化程序
//初始化PA0/PE0/PE3/PE4为中断输入
{
	KEY_Init();
	Ex_NVIC_Config(GPIO_A,0,FTIR);
	//PA0 下降沿触发
	Ex_NVIC_Config(GPIO_C,3,FTIR);
	//PC3 下降沿触发
	Ex_NVIC_Config(GPIO_C,2,FTIR);
	//PC2 下降沿触发
	Ex_NVIC_Config(GPIO_C,1,FTIR);
	//PC1 下降沿触发
	MY_NVIC_Init(2,3,EXTI0_IRQn,2);
	//抢占2,子优先级3 因为是PA0 所以中断
	//源为EXTI0_IRQn,组2,下面同理
	MY_NVIC_Init(2,2,EXTI3_IRQn,2);

	MY_NVIC_Init(2,1,EXTI2_IRQn,2);
	
	MY_NVIC_Init(2,0,EXTI1_IRQn,2);
	
}

在这里插入代码片

外部中断HAL库

外部中断操作HAL库函数分布文件:

头文件:stm32f1xx_hal_gpio.h
源文件:stm32f1xx_hal_gpio.c

头文件:stm32f1xx_hal_cortex.h
源文件:stm32f1xx_hal_cortex.c

重要函数

初始化函数

void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)

设置中断优先级分组

void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)

设置中断优先级

void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)

HAL_NVIC_SetPriority函数:设置中断优先级,函数有三个形参,作用分别是选择中断源,抢占优先级,响应优先级

使能中断

void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
HAL_NVIC_EnableIRQ函数:使能中断,函数有一个形参,选定中断源。

HAL外部中断API,中断中调用

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)

外部中断用户回调

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

HAL库代码

main.c

#include "MyIncludes.h"

void GPIO_EXTI_ISR(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == GPIO_PIN_0)
  //如果指向GPIO_PIN_0,也是就key1按下
  {
   LED_Open(LED1);
   LED_Open(LED2);
  }
  if(GPIO_Pin == GPIO_PIN_2)
  //key3按下
  {
   LED_Close(LED1);
   LED_Close(LED2);
  }
}

int main()
{
  System_Init();
  //系统初始化
  LED_Init();
  //LED初始化
  SysTick_Init(NULL);
  //Systic_INit滴答定时器关闭
  Exti_Init(EXTI_LINE0,GPIO_EXTI_ISR);
  Exti_Init(EXTI_LINE2,GPIO_EXTI_ISR);
  //中断初始化,外部中断 0 和 2,使用了函数指针
  //指向了GPIO_EXTI_ISR()函数
  while(1)
  {
  
  }
}

Exti.h

#ifndef __EXTI_H_
#define __EXTI_H_

#include "stm32f1xx.h"
#include "stm32_types.h"
#include "stm32f1xx_hal.h"

enum
{
 EXTI_LINE0 = 0,
 EXTI_LINE1,
 EXTI_LINE2,
 EXTI_LINE3,
 EXTI_LINE4,
 EXTI_LINE5,
 EXTI_LINE6,
 EXTI_LINE7,
 EXTI_LINE8,
 EXTI_LINE9,
 EXTI_LINE10,
 EXTI_LINE11,
 EXTI_LINE12,
 EXTI_LINE13,
 EXTI_LINE14,
 EXTI_LINE15,
};
//枚举0-15外部中断

typedef struct
{
  void (*exti_isr)(uint16_t GPIO_Pin);
}_EXTI_ISR;
//函数指针先指向ISR,然后指向main.c中的
//void GPIO_EXTI_ISR(uint16_t GPIO_Pin);

void Exti_Init(uint8_t exti_line,void(*ISR)(uint16_t GPIO_Pin));
//外部中断初始化函数声明
#endif

Exti.c

#include "Exti.h"

_EXTI_ISR Exti_ISR;
//结构体声明变量

void Exti_Init(uint8_t exti_line,void (*ISR)(uint16_t GPIO_Pin))
{
 GPIO_InitTypeDef GPIO_InitStruct;
 Exti_ISR.exti_isr = ISR;
 //函数指针指向ISR,也就是最终指向
 //void GPIO_EXTI_ISR(uint16_t GPIO_Pin);
 
 switch(exti_line)
 {
   case EXTI_LINE0:
   __GPIOA_CLK_ENABLE();
   //使能GPIOA时钟  因为按键key1 是PA0

   GPIO_InitStruct.Pin = GPIO_PIN_0;
   GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
   //下降沿触发
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   //外部电路无上拉或下拉激活
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
   //高速
   HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
   //初始化GPIO
   HAL_NVIC_SetPriority(EXTI0_IRQn,0x0f,0);
   //设置中断优先级
   //三个参数   
   //选定中断源 EXTI0_IRQn
   //设置抢占优先级 0x0f  也就是 1111  4位
   //设置响应优先级  0 
   //判断中断的优先级,先看抢占优先级,抢占优先级高的中断
   //优先级别高。抢占优先级相同的情况下,先执行响应优先高的
   //的。抢占优先级和响应优先级相同的情况下,根据中断向量
   //表确定。    
   HAL_NVIC_EnableIRQ(EXTI0_IRQn);
   //使能中断
   //选定中断源
   break;
   
   case EXTI_LINE1:
   __GPIOC_CLK_ENABLE();

   GPIO_InitStruct.Pin = GPIO_PIN_1;
   GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
   HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);
   HAL_NVIC_SetPriority(EXTI1_IRQn,0x0f,0);
   HAL_NVIC_EnableIRQ(EXTI1_IRQn);
   break;

   case EXTI_LINE2:
   __GPIOC_CLK_ENABLE();

   GPIO_InitStruct.Pin = GPIO_PIN_2;
   GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
   HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);
   HAL_NVIC_SetPriority(EXTI2_IRQn,0x0f,0);
   HAL_NVIC_EnableIRQ(EXTI2_IRQn);
   break;

   case EXTI_LINE3:
   __GPIOC_CLK_ENABLE();

   GPIO_InitStruct.Pin = GPIO_PIN_3;
   GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
   HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);
   HAL_NVIC_SetPriority(EXTI3_IRQn,0x0f,0);
   HAL_NVIC_EnableIRQ(EXTI3_IRQn);
   break;

 }
}

void EXTI0_IRQHandler(void)
 //外部中断服务函数,用来响应外部中断触发
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
 //作用:1:清楚中断标记位
// 2:调用回调函数
}

void EXTI1_IRQHandler(void)
{
 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
}

void EXTI2_IRQHandler(void)
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
}

void EXTI3_IRQHandler(void)
{
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(Exti_ISR.exti_isr != NULL)
  Exti_ISR.exti_isr(GPIO_Pin);
  //外部中断用户回调
  //可以理解中断函数具体要响应的动作
}
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值