当前位置: 首页 > news >正文

2.外部中断(EXTI)

理论

NVIC:嵌套向量中断控制器(解释教程)

外部通用中断线(EXTI0~EXTI15):每个GPIO设置成中断模式,与中断控制器连接的线

外部中断触发方式

上升沿触发、下降沿触发、双边沿触发

外部中断触发函数

在stm32f1xx_it.c文件里(大概204行)

中断触发函数
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler

解析

解析初始化中断过程

  //gpio.c中58/*Configure GPIO pins : PEPin PEPin */GPIO_InitStruct.Pin = EXTI_Key1_Pin|EXTI_Key2_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);	//将上面三行代码的数据传入这个函数解析初始化//stm32f1xx_hal_gpio.c中286
/*--------------------- EXTI Mode Configuration ------------------------*/
/* Configure the External Interrupt or event for the current IO */
if ((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
{
/* Enable AFIO Clock */
__HAL_RCC_AFIO_CLK_ENABLE();	//打开复用时钟
temp = AFIO->EXTICR[position >> 2u];
CLEAR_BIT(temp, (0x0Fu) << (4u * (position & 0x03u)));
SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4u * (position & 0x03u)));
AFIO->EXTICR[position >> 2u] = temp;	//把固定引脚设置成复用模式(如复用成外部中断)//配置上升沿还是下降沿
/* Enable or disable the rising trigger */
if ((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
{SET_BIT(EXTI->RTSR, iocurrent);
}
else
{CLEAR_BIT(EXTI->RTSR, iocurrent);
}/* Enable or disable the falling trigger */
if ((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
{SET_BIT(EXTI->FTSR, iocurrent);
}
else
{CLEAR_BIT(EXTI->FTSR, iocurrent);
}/* Configure the event mask */
if ((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
{SET_BIT(EXTI->EMR, iocurrent);
}
else
{CLEAR_BIT(EXTI->EMR, iocurrent);
}//打开或关闭中断
/* Configure the interrupt mask */
if ((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
{SET_BIT(EXTI->IMR, iocurrent);
}
else
{CLEAR_BIT(EXTI->IMR, iocurrent);
}

中断实现过程

  1. 确认中断
  2. 清除中断标志位
  3. 执行中断回调函数

图示

//stm32f1xx_it.:大概204行
void EXTI3_IRQHandler(void)		//中断入口函数
{/* USER CODE BEGIN EXTI3_IRQn 0 *//* USER CODE END EXTI3_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(EXTI_Key1_Pin);	//在库函数不能写/* USER CODE BEGIN EXTI3_IRQn 1 *//* USER CODE END EXTI3_IRQn 1 */
}void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)	//stm32f1xx_hal_gpio.c:大概546行
{/* EXTI line interrupt detected */if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)	//判断有没有中断触发(有:1,没:0){__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);		//若进来则为1,为1则清除中断标志位HAL_GPIO_EXTI_Callback(GPIO_Pin);	//回调函数(Callback),执行函数}
}//stm32f1xx_hal_gpio.h中190
#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))	//挂起寄存器(EXTI_PR)(参考手册140) 有没有中断触发//stm32f1xx_hal_gpio.h中198
#define __HAL_GPIO_EXTI_CLEAR_IT(__EXTI_LINE__) (EXTI->PR = (__EXTI_LINE__))	//赋值,(参考手册140)//调用这个函数,__weak:弱声明,若别文件也有相同的函数,优先调用没有弱声明
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)	//stm32f1xx_hal_gpio.c:大概561行
{/* Prevent unused argument(s) compilation warning */UNUSED(GPIO_Pin);/* NOTE: This function Should not be modified, when the callback is needed,the HAL_GPIO_EXTI_Callback could be implemented in the user file*/
}

若相同有一个PA0设置了中断,别的PB0等等都不能设置成中断

解析图

代码编写

实验:按键PE3控制蜂鸣器(PB8)、按键PE4控制LED灯(PB5)

Cube IDE代码

Cube IDE中编写

LED灯、蜂鸣器、按键配置

LED灯、蜂鸣器配置,上一篇已经说过,地址

按键设置下降沿触发(也可上升沿触发),GPIO Pull-up/Pull-down:设置上拉,空闲状态为高电平

按键没按下时高电平,按下时有下降沿和上升沿,所以两个触发都可,按键这里是中断触发功能,不是GPIO输入功能

按键设置图

配置NVIC(嵌套向量中断控制器)

配置NVIC

调节不同中断优先级(数字越小优先级越高)

若抢占优先级相同,比较子优先级

中断优先级

调节多少bit对应代码在:

HAL_Init();	//main.c(74)//HAL_StatusTypeDef HAL_Init(void)中的
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);	//stm32f1xx_hal.c(157)
代码

main.c:144行(在mian函数外任意一个 /* USER CODE BEGIN / / USER CODE END */中)

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{//若需要延时需要将延时中断优先级比外部中断优先级高,优先级高才可以打断低优先级HAL_Delay(10);if(HAL_GPIO_ReadPin(EXTI_Key1_GPIO_Port, EXTI_Key1_Pin) == 0)	//读引脚,相同=0,不同=1{HAL_GPIO_TogglePin(BEEP_GPIO_Port, BEEP_Pin);}if(HAL_GPIO_ReadPin(EXTI_Key2_GPIO_Port, EXTI_Key2_Pin) == 0){HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);}
}

中断处理程序要少用延时的原因
中断处理的要求是即时处理,尽快退出。如果在中断中使用延时函数或者使用IO阻塞函数,会影响到系统的实时性。如果下次中断来临,延时或者阻塞还没结束,那么就永远在中断里死循环了。
因此,对于中断处理程序的要求是:
    短小精悍,不要处理过多任务
    不使用延时函数或者IO阻塞的函数

Keil代码

需要修改的地方如下:

mian.c(144)

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{//若需要延时需要将延时中断优先级比外部中断优先级高,优先级高才可以打断低优先级HAL_Delay(10);if(HAL_GPIO_ReadPin(EXTI_Key1_GPIO_Port, EXTI_Key1_Pin) == 0)	//读引脚,相同=0,不同=1{HAL_GPIO_TogglePin(BEEP_GPIO_Port, BEEP_Pin);}if(HAL_GPIO_ReadPin(EXTI_Key2_GPIO_Port, EXTI_Key2_Pin) == 0){HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);}
}

main.h(60)

#define EXTI_Key1_Pin GPIO_PIN_3
#define EXTI_Key1_GPIO_Port GPIOE
#define EXTI_Key1_EXTI_IRQn EXTI3_IRQn
#define EXTI_Key2_Pin GPIO_PIN_4
#define EXTI_Key2_GPIO_Port GPIOE
#define EXTI_Key2_EXTI_IRQn EXTI4_IRQn
#define LED1_Pin GPIO_PIN_5
#define LED1_GPIO_Port GPIOB
#define BEEP_Pin GPIO_PIN_8
#define BEEP_GPIO_Port GPIOB

gpio.c(42)

void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_RESET);/*Configure GPIO pins : PEPin PEPin */GPIO_InitStruct.Pin = EXTI_Key1_Pin|EXTI_Key2_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);/*Configure GPIO pins : PBPin PBPin */GPIO_InitStruct.Pin = LED1_Pin|BEEP_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0);HAL_NVIC_EnableIRQ(EXTI3_IRQn);HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0);HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}

stm32f1xx_hal_it.c(204)

void EXTI3_IRQHandler(void)
{/* USER CODE BEGIN EXTI3_IRQn 0 *//* USER CODE END EXTI3_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(EXTI_Key1_Pin);/* USER CODE BEGIN EXTI3_IRQn 1 *//* USER CODE END EXTI3_IRQn 1 */
}void EXTI4_IRQHandler(void)
{/* USER CODE BEGIN EXTI4_IRQn 0 *//* USER CODE END EXTI4_IRQn 0 */HAL_GPIO_EXTI_IRQHandler(EXTI_Key2_Pin);/* USER CODE BEGIN EXTI4_IRQn 1 *//* USER CODE END EXTI4_IRQn 1 */
}

修改延时中断优先级

HAL_Init();	//main.c(74)//HAL_StatusTypeDef HAL_Init(void)中的
HAL_InitTick(TICK_INT_PRIORITY);	//stm32f1xx_hal.c(160)//进入参数里修改
#define  TICK_INT_PRIORITY            1U	//stm32f1xx_hal_conf.h(132)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 猫头虎分享:从零开始掌握ChatGPT的实用技巧与多样应用
  • ​十个常见的 Python 脚本 (详细介绍 + 代码举例)
  • Python网络爬虫面试题3
  • uniapp0基础编写安卓原生插件和调用第三方jar包(Ch34的jar包)和如何解决android 如何Application初始化
  • 【golang】Golang手写元组 tuple | golang tuple
  • Oracle(42) 什么是动态SQL?
  • 24暑假算法刷题 | Day27 | 贪心算法 I | LeetCode 455. 分发饼干,376. 摆动序列,53. 最大子数组和
  • comfyui老照片修复工作流,直接复制到comfyui中即可使用
  • JavaScript基础——JavaScript变量名称命名规范
  • 【Golang 面试 - 进阶题】每日 3 题(六)
  • 【Java】Java swing 民宿管理系统 GUI(源码+可视化界面)【独一无二】
  • 基于YOLOv8的高压输电线路异物检测系统
  • 笔试练习day2
  • git操作流程笔记
  • 程序员找工作之数据结构面试题总结分析
  • CAP理论的例子讲解
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • golang 发送GET和POST示例
  • Iterator 和 for...of 循环
  • javascript从右向左截取指定位数字符的3种方法
  • Java编程基础24——递归练习
  • mac修复ab及siege安装
  • Median of Two Sorted Arrays
  • php ci框架整合银盛支付
  • vue 配置sass、scss全局变量
  • Vue.js源码(2):初探List Rendering
  • Web Storage相关
  • 关于for循环的简单归纳
  • 后端_ThinkPHP5
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 盘点那些不知名却常用的 Git 操作
  • 我的业余项目总结
  • 学习JavaScript数据结构与算法 — 树
  • 学习Vue.js的五个小例子
  • 一起参Ember.js讨论、问答社区。
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ​力扣解法汇总946-验证栈序列
  • #APPINVENTOR学习记录
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #微信小程序:微信小程序常见的配置传旨
  • (libusb) usb口自动刷新
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (多级缓存)缓存同步
  • (二)c52学习之旅-简单了解单片机
  • (分布式缓存)Redis持久化
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (转载)Google Chrome调试JS
  • .bat批处理(三):变量声明、设置、拼接、截取
  • .net mvc 获取url中controller和action