STM32_08_中断(☆☆☆)

中断介绍

中断和轮询

中断的硬件连接

EXTI0

  • 类似这种梯形就是多选一,例如PB1这个引脚的电平变化会映射到EXTI1硬联。
  • STM32 通过SYSCFG(或 F1 系列的 AFIO)的 EXTICR 配置寄存器,将特定 GPIO 引脚(如 PA0、PB1 等)"绑定" 到对应的 EXTI 中断线(EXTIn);当该引脚发生电平变化(上升沿、下降沿等)时,就会触发对应 EXTI 线,进而产生中断请求或事件信号。
  • 通过AFIO_EXTICRx配置GPIO线上的外部中断/事件,而如果想让GPIO线映射过来,首先要使能AFIO时钟。
  1. GPIO变化过程映射到EXTI线上
    打开AFIO时钟
  2. EXTI控制器内部
    上升沿/下降沿
    中断/事件
    清除中断到来位
    使能中断 - 不能屏蔽

NVIC介绍

NVIC中断优先级

速记:抢占式优先级是主优先级,响应优先级是子优先级。

  1. 中断A:主1子0
    中断B:主0子2
    -> 同时到 -> B
  2. 中断A:主1子0
    中断B:主0子2
    -> A先到,执行, B到了 -> B会抢占A的资源
  3. 中断A:主1子0
    中断B:主1子2
    -> 同时到 -> A先执行
  4. 中断A:主1子0
    中断B:主1子2
    -> B先到, 执行, A到了 -> A不会抢占B的资源
  5. 中断A:主1子2
    中断B:主1子2
    -> 同时到 -> 看表(谁在前谁先运行)

4bit:

主4子0

主:0-15子: ( < 2的n次方)
主3子1
主:0-7子:0-1
主2子2
主:0-3子:0-3
主1子3
主:0-1子:0-7

主0子4

主: 子:0-15

外部EXTI配置

中断处理

思考:

PA0 - EXTI0 - EXTI - NVIC - CPU

谁触发的中断?

EXTI0触发的中断 ,并不是PA0,是PA0映射到了EXTI0,EXTI0一步步触发的中断。

stm32 - 中断处理函数 - 名字定好了 - 启动文件中

打开启动文件: XXX_IRQHandler

EXTI0_IRQHandler

1.中断处理函数

2.EXIT0触发的中断调用该函数

中断处理函数没有定义, 需要开发人员自定义

中断处理流程

中断处理函数

1.APP/EXTI目录

2.APP/EXTI

新建exti.c exti.h

3.添加工程组/ C/C++头文件路径

4.工程组添加 stm32f10x_exti.c - EXTI库函数

KEY0按键

相关库函数和结构体

代码示例:

KEY0按键

思路:

KEY0一旦按下,GPIOE4就映射到了EXTI4上,然后会有一个下降沿,EXTI4设置中断模式,又能检测下降沿,然后发送一个中断信号到NVIC,NVIC发现是EXTI4的中断,给你分配了一个主优先级和子优先级,然后NVIC把中断信号发送到CPU里。

相关库函数和结构体

代码示例:

注意:

EXTI和NVIC有时钟,但是它们自动使能。IRQn在stm32f10x.h头文件的第167行,下面就是各个中断源。

xxxx_IRQn - 中断源 - 谁触发的中断 -

NVIC_InitTypeDef - IRQChannel - 赋值

接下来调用中断处理函数

实战演练

代码示例:

exti.h:

cpp 复制代码
// exti.h
#ifndef __EXTI_H__
#define __EXTI_H__

#include "stm32f10x.h"

// KEY0
extern void My_EXTI_Init(void);
#endif

exti.c:

cpp 复制代码
// exti.c
#include "exti.h"
#include "systick.h"
#include "beep.h"
#include "key.h"
// 
// 中断的初始化 - 发送中断的流程
// KEY0 - GPIOE4
// KEY0 - GPIOE4 - EXTI4 - EXTI控制器 - NVIC - CPU核
//
void My_EXTI_Init(void){
	// 1.KEY0 - 配置为上拉输入
	
	// 2.GPIOE4映射到EXTI4上
	// 2.1打开AFIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	// 2.2将GPIOE3映射到EXTI4上
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);

	// 3.EXTI控制器的配置
	// EXTI4 - 中断模式 - 下降沿触发
	EXTI_InitTypeDef EXTI_Config;
	EXTI_Config.EXTI_Line = EXTI_Line4;							 // EXTI4
	EXTI_Config.EXTI_Mode = EXTI_Mode_Interrupt;		 // 中断模式
	EXTI_Config.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿
	EXTI_Config.EXTI_LineCmd = ENABLE;							 // 使能
	EXTI_Init(&EXTI_Config);
	
	// 4.NVIC控制器的配置
	// EXTI4触发的中断 - 主1 - 子2 - 使能
	NVIC_InitTypeDef NVIC_Config; 
	NVIC_Config.NVIC_IRQChannel = EXTI4_IRQn; // EXTI4触发的中断
	NVIC_Config.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_Config.NVIC_IRQChannelSubPriority = 2;
	NVIC_Config.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_Config);
}
//
// 中断处理函数到启动文件(.s)中找
// 中断处理函数
// 触发该函数 - KEY0按下 - 蜂鸣器控制
//
void EXTI4_IRQHandler(void){
	// 判断是否是EXTI4触发的中断
	if(EXTI_GetITStatus(EXTI_Line4) == SET){
		// 业务处理
		delay_ms(10); // 去抖动
		if(KEY0 == 0)
			BEEP = !BEEP;
	}
	// 清除中断到来位
	EXTI_ClearITPendingBit(EXTI_Line4);
}

main.c:

cpp 复制代码
// main.c 
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "system.h"
#include "systick.h"
#include "key.h"
#include "exti.h"

int main(void)
{
	// |--|--|
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	// LED初始化 
	LED_Init();
	// BEEP初始化 
	BEEP_Init();
	// systick初始化 
	Systick_Init();
	// KEY初始化
	KEY_Init();
	// EXTI初始化
	// 作用:按下KEY0 - EXTI4 - EXTI -NVIC -> 中断信号 -> CPU核
	My_EXTI_Init();
	
	while(1)
	{
		// 业务逻辑 - 做其他事情
		LED1 = !LED1;
		delay_ms(1000);
	}
	// 启动文件 - main函数 - 初始化 - while(1)
	// while(1) -------(1)-----------------> 执行
	//								 ^CPU核
	// 								/
	// 按下KEY0->中断信号
	//										CPU核从(1)停止 -> 执行中断处理函数
	//																		EXTI4_IRQHandler
	//																    执行完返回(1)继续
}

补充:

  1. 和中断相关的三类函数:
    xxx_ITConfig - 打开/关闭控制器的某个中断
    xxx_GetITStatus - 判断某个中断是否到来
    xxx_ClearITPendingBit - 中断中断到来位
  2. EXTI_GetITStatus(EXTI_Line4) == SET的作用
    例如:
    EXTI6触发了中断, 调用其中断处理函数
    // EXTI5 6 7 8 9 触发的中断调用该函数
    // 问 - 是哪个硬件线触发的中断调用的该函数
    void EXTI9_5_IRQHandler(void){
    if(EXTI_GetITStatus(EXTI_Line5) == SET){...}
    else if(EXTI_GetITStatus(EXTI_Line6) == SET){...}
    else if(EXTI_GetITStatus(EXTI_Line7) == SET){...}
    else if(EXTI_GetITStatus(EXTI_Line8) == SET){...}
    else if(EXTI_GetITStatus(EXTI_Line9) == SET){...}
    }

拓展:

循环开关灯,按下key0触发中断,开启蜂鸣器;按下key_up触发中断,关闭蜂鸣器。

KEY_UP使用中断来触发:

PA0 - 下拉输入

低电平 - 高电平 - 低电平

检测 - 上升沿

谁触发的中断 - EXTI0

初始化函数:

1.PA0 映射到EXTI0

2.EXTI配置 - EXTI0, 中断模式, 上升沿, 使能

3.NVIC配置 - EXTI0, 主1, 子0, 使能

中断处理函数:

EXTI0_IRQHandler

exti.c:

cpp 复制代码
// exti.c
#include "exti.h"
#include "systick.h"
#include "beep.h"
#include "key.h"
// 
// 中断的初始化 - 发送中断的流程
// KEY0 - GPIOE4
// KEY0 - GPIOE4 - EXTI4 - EXTI控制器 - NVIC - CPU核
// KEY_UP - GPIOA0 - EXTI0 - EXTI控制器 - NVIC - CPU核
//
void My_EXTI_Init(void){
	// 1.KEY0 - 配置为上拉输入
	// 1.2KEY_UP配置为下拉输入
	// 2.GPIOE4映射到EXTI4上
	// 2.1打开AFIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	// 2.2将GPIOE3映射到EXTI4上
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);
	// 2.2将GPIOA0映射到EXTI0上
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
	
	// 3.EXTI控制器的配置
	// EXTI4 - 中断模式 - 下降沿触发
	EXTI_InitTypeDef EXTI_Config;
	EXTI_Config.EXTI_Line = EXTI_Line4;							 // EXTI4
	EXTI_Config.EXTI_Mode = EXTI_Mode_Interrupt;		 // 中断模式
	EXTI_Config.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿
	EXTI_Config.EXTI_LineCmd = ENABLE;							 // 使能
	EXTI_Init(&EXTI_Config);
	// 3.2EXTI0 - 中断模式 - 上升沿触发
	EXTI_Config.EXTI_Line = EXTI_Line0;
	EXTI_Config.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_Config.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_Config.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_Config);
	
	// 4.NVIC控制器的配置
	// EXTI4触发的中断 - 主1 - 子2 - 使能
	NVIC_InitTypeDef NVIC_Config; 
	NVIC_Config.NVIC_IRQChannel = EXTI4_IRQn; // EXTI4触发的中断
	NVIC_Config.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_Config.NVIC_IRQChannelSubPriority = 2;
	NVIC_Config.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_Config);
	
	// 4.2EXTI0触发的中断 - 主1 - 子0 - 使能
	NVIC_Config.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_Config.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_Config.NVIC_IRQChannelSubPriority = 0;
	NVIC_Config.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_Config);
}
//
// 中断处理函数到启动文件(.s)中找
// 中断处理函数
// 触发该函数 - KEY0按下 - 蜂鸣器控制
//
void EXTI4_IRQHandler(void){
	// 判断是否是EXTI4触发的中断
	if(EXTI_GetITStatus(EXTI_Line4) == SET){
		// 业务处理
		delay_ms(10); // 去抖动
		if(KEY0 == 0)
			BEEP = 1;
	}
	// 清除中断到来位
	EXTI_ClearITPendingBit(EXTI_Line4);
}
	
void EXTI0_IRQHandler(void){
	// 判断是否是EXTI0触发的中断
	if(EXTI_GetITStatus(EXTI_Line0) == SET){
		// 业务处理
		delay_ms(10);
		if(KEY_UP == 1)
			BEEP = 0;
	}
		// 清除中断到来位
	EXTI_ClearITPendingBit(EXTI_Line0);
}

	

main.c:

cpp 复制代码
// main.c 
#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "system.h"
#include "systick.h"
#include "key.h"
#include "exti.h"

int main(void)
{
	// |--|--|
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	// |--|--|
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	// LED初始化 
	LED_Init();
	// BEEP初始化 
	BEEP_Init();
	// systick初始化 
	Systick_Init();
	// KEY初始化
	KEY_Init();
	// EXTI初始化
	// 作用:按下KEY0 - EXTI4 - EXTI -NVIC -> 中断信号 -> CPU核
	My_EXTI_Init();
	
	while(1)
	{
		// 业务逻辑 - 做其他事情
		LED1 = !LED1;
		delay_ms(1000);
	}
	// 启动文件 - main函数 - 初始化 - while(1)
	// while(1) -------(1)-----------------> 执行
	//								 ^CPU核
	// 								/
	// 按下KEY0->中断信号
	//										CPU核从(1)停止 -> 执行中断处理函数
	//																		EXTI4_IRQHandler
	//																    执行完返回(1)继续
}
相关推荐
沐欣工作室_lvyiyi4 小时前
基于单片机的智能奶茶机(论文+源码)
单片机·嵌入式硬件·毕业设计·智能奶茶机
俊昭喜喜里4 小时前
stm32中的位带操作的使用意义
stm32·单片机·嵌入式硬件
晶振厂家-晶发电子8 天前
晶振在5G时代的角色:高精度时钟的核心支撑
单片机·嵌入式硬件·5g·晶振·电子元器件·晶振知识
F137298015578 天前
WD5030A 芯片,12V降5V,输出电流12A,电路设计
stm32·单片机·嵌入式硬件·汽车·51单片机
小莞尔8 天前
【51单片机】【protues仿真】基于51单片机的篮球计时计分器系统
c语言·stm32·单片机·嵌入式硬件·51单片机
三佛科技-187366133978 天前
分享机械键盘MCU解决方案
单片机·嵌入式硬件·计算机外设
李永奉8 天前
51单片机-使用IIC通信协议实现EEPROM模块教程
单片机·嵌入式硬件·51单片机
工大一只猿8 天前
51单片机学习
嵌入式硬件·学习·51单片机
小莞尔8 天前
【51单片机】【protues仿真】 基于51单片机八路抢答器系统
c语言·开发语言·单片机·嵌入式硬件·51单片机