【STM32】NVIC / EXTI / AFIO 介绍

文章目录

  • 中断系统
    • NVIC简介
    • NVIC基本结构
    • NVIC优先级分组
    • EXTI外部中断
    • EXIT基本结构
    • AFIO复用IO口
    • EXTI内部框图
  • AFIO / EXTI / NVIC 相关函数
    • AFIO相关函数
    • EXTI相关函数
    • NVIC相关函数
  • 旋转编码器简介
  • 对射式红外传感器计次
    • 接线图
    • CountSensor(传感器)驱动程序封装
    • main.c 源程序
  • 旋转编码器计次
    • 接线图
    • Encoder驱动程序封装
    • main.c 源程序

中断系统

中断的定义:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行

中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源

中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回

中断执行流程
在这里插入图片描述

NVIC简介

在STM32中,NVIC(Nested Vectored Interrupt Controller)是一个中断控制器,负责管理和处理微控制器的中断

NVIC是一个内核外设,是CPU的小助手

它允许多个中断源以优先级方式响应,使得系统能够快速响应高优先级的中断请求,NVIC支持嵌套中断,即高优先级的中断可以打断低优先级的中断

NVIC的主要功能包括:

  1. 中断向量表:存储所有中断的服务程序地址
  2. 中断优先级管理:允许为不同中断分配不同的优先级,以控制中断的响应顺序
  3. 中断使能和禁用:可以启用或禁用特定的中断
  4. 中断触发方式:支持多种中断触发方式,如上升沿、下降沿等

通过NVIC,STM32能够高效地处理实时事件,提高系统的响应速度和性能

一个形象的比喻:CPU是急诊室的医生,中断源 是需要就诊的病人,NVIC就是医生助手,负责安排病人就诊顺序,如果没有小助手那么医生就既需要看病又需要给病人排队,降低了看病效率,但是有小助手负责根据病人的优先程度排队,医生就只需要负责看病即可

NVIC基本结构

STM32有68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设

使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级

在这里插入图片描述

NVIC优先级分组

  • NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级
  • 抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
分组方式抢占优先级响应优先级
分组00位,取值为04位,取值为0~15
分组11位,取值为0~13位,取值为0~7
分组22位,取值为0~32位,取值为0~3
分组33位,取值为0~71位,取值为0~1
分组44位,取值为0~150位,取值为0

EXTI外部中断

EXTI(External Interrupt/Event Controller)是STM32微控制器中的一个模块,用于处理外部中断和事件,它允许外部信号(如按钮、传感器等)触发中断,从而实现对外部事件的快速响应

  • EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
  • 支持的触发方式:上升沿 / 下降沿 / 双边沿 / 软件触发
  • 支持的GPIO口:所有 GPIO 口,但相同的 Pin 不能同时触发中断(eg. PA1 和 PB1 不能同时触发中断)
  • 通道数:16 个 GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
  • 触发响应方式:中断响应 / 事件响应

EXIT基本结构

在这里插入图片描述

【AFIO说明】
之前介绍过,EXTI模块只有16个GPIO的通道,但是每个GPIO外设都有16个引脚,所以在这里会有一个AFIO中断引脚选择的电路模块
AFIO就是一个数据选择器,它可以在前面的GPIO外设的16个引脚里选择一个连接到后面的EXTI通道里,这就是 “所有的GPIO 口都能触发中断
但是相同的Pin不能同时触发中断” 的原因

AFIO复用IO口

“复用”指的是将同一个输入/输出(I/O)引脚用于多种不同的功能或用途

  • AFIO主要用于引脚复用功能的选择和重定义(也就是数据选择器的作用)
  • 在STM32中,AFIO主要完成两个任务
    1. 复用功能引脚重映射
    2. 中断引脚选择

在这里插入图片描述

EXTI内部框图

在这里插入图片描述

AFIO / EXTI / NVIC 相关函数

AFIO相关函数

//AFIO 没有专门的库函数文件,它的库函数和 GPIO 在一个文件中void GPIO_AFIODeInit(void); 	
//用于复位 AFIO 外设,调用该图数后 AFIO 外设的配就会被全部清除void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//用于锁定GPIO配道,调用该函数,参数指定某个引脚,该引脚的配置就会被锁定,防止意外更改void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_EventOutputCmd(FunctionalState NewState);
//用于配置AFIO的事件输出功能(用的不多)void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
/*用于进行引脚重映射第一个参数:选择重映射的方式第二个参数:新的状态
*/void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
/*用于配置AFIO的数据选择器,选择想要的中断引脚(这个函数虽然是GPIO开头,但是里面操作的AFIO寄存器)第一个参数:GPIO_Portsource是选择某个GPIO外设作为外部中断源第二个参数:GPIO_Pinsource是指定要配置的外部中断线
*/void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);
//和以太网有关(我们的芯片没有以太网外设,所以用不到)

EXTI相关函数

void EXTI_DeInit(void);
//用于清除EXTI配置,恢复成上电默认的状态void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//调用这个函数,可以根据这个结构体里的参数配置EXTI外设
//初始化EXTI主要用的就是这个函数void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
//调用这个函数,可以把参数传递的结构体变量赋一个默认值void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
//用于软件触发外部中断
//调用这个函数,参数给一个指定的中断线,就能软件触发一次外部中断FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
void EXTI_ClearFlag(uint32_t EXTI_Line);ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//用来获取EXTI的中断标志位状态,如果EXTI线有中断发生函数返回“SET”否则返回“RESET”void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//用于清除中断标志位,以便下一次中断能够触发(每次中断程序结束后都应该清除一下中断标志位)

NVIC相关函数

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
//用于中断分组,参数是中断分组的方式
//(在配置中断之前,要先指定一下中断分组)void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
//根据结构体里面指定的参数初始化NVICvoid NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
//用于设置中断向量表void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
//系统低功耗配置

旋转编码器简介

旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向

类型:机械触点式/霍尔传感器式/光栅式

在这里插入图片描述

对射式红外传感器计次

接线图

在这里插入图片描述

CountSensor(传感器)驱动程序封装

CountSensor.c

#include "stm32f10x.h"                  // Device headeruint16_t CountSensor_Count;void CountSensor_Init(void){	//Step1:开启始时钟	//RCC开启始时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	//开启 AFIO 时钟,AFIO 也是 APB2 的外设,RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//EXTI 和 NVIC 两个外设的时钟一直是打开的,不需要再开启时钟了//Step2:配置GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//Step3:配置AFIO//配置AFIO外部中断引脚选择GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//执行完后AFIO的第14个数据选择器就拨好了//这样PB14号引脚的电平信号就可以顺利通过AFIO进入到EXTI电路了//Step4:配置EXTIEXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line14;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);//Step5:配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);
}//中断函数
//在STM32中,中断函数的名字都是固定的,每个中断通道都对应一个中断函数
//中断函数的名字可以参考启动文件
void EXTI15_10_IRQHandler(void){//由于这个函数 EXTI10 到 EXTI15 都能进,所以要先判断一下是不是我们想要的 EXTI14if (EXTI_GetITStatus(EXTI_Line14) == SET){if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0){CountSensor_Count++;}		EXTI_ClearITPendingBit(EXTI_Line14);}
}uint16_t CountSensor_Get(void){return CountSensor_Count;
}

CountSensor.h

#ifndef __COUNT_SENSOR_H
#define __COUNT_SENSOR_Hvoid CountSensor_Init(void);
uint16_t CountSensor_Get(void);#endif

main.c 源程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"int main(void){OLED_Init();CountSensor_Init();OLED_ShowString(1, 1, "Count:");while(1){OLED_ShowNum(1, 7, CountSensor_Get(), 5);}
}

旋转编码器计次

接线图

在这里插入图片描述

Encoder驱动程序封装

Encoder.c

#include "stm32f10x.h"                  // Device headerint16_t Encoder_Count;void Encoder_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStructure);
}int16_t Encoder_Get(void){int16_t Temp;Temp = Encoder_Count;Encoder_Count = 0;return Temp;
}//在A相下降沿和B相低电平时才判断为反转,Encoder_Count--
void EXTI0_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line0) == SET){if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0){Encoder_Count--;}EXTI_ClearITPendingBit(EXTI_Line0);}}//在B相下降沿和A相低电平时才判断为正转,Encoder_Count++
void EXTI1_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line1) == SET){if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0){Encoder_Count++;}EXTI_ClearITPendingBit(EXTI_Line1);}
}

Encoder.h

#ifndef __ENCODER_H
#define __ENCODER_Hvoid Encoder_Init(void);
int16_t Encoder_Get(void);#endif

main.c 源程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Encoder.h"int16_t Num;int main(void){	OLED_Init();Encoder_Init();OLED_ShowString(1, 1, "Num:");	while(1){Num += Encoder_Get();OLED_ShowSignedNum(1, 5, Num, 5);}
}

STM32 专栏文章均参考 《STM32入门教程-2023版 细致讲解 中文字幕》教程视频

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/2994.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux内核大揭秘】程序地址空间

文章目录 什么是程序地址空间地址空间的组成虚拟内存技术 如何理解程序地址空间页表页表的细节关于堆区 在Linux中如何查看各个分段的信息总结 什么是程序地址空间 程序地址空间是一个程序在执行期间可以访问的内存范围。它由操作系统为每个进程分配,以确保进程之间…

nginx代理出现的请求头中获取不到acc_token问题

1.问题 程序开发完成之后,发现页面登录之后,获取不到用户信息。发现时没有获取到token信息。本地程序开发完成,后端服务成功署到服务器。通过云服务器开放对应的端口,使用本地的前端服务,直接连接服务器后端服务&…

WordPress之generatepress主题安装

1.打开主题列表 2.如果没有自己需要主题点击安装新主题 点击安装并启用 3.不喜欢的 主题可以点击主题进去删除 4.主题自定义编辑 打开自定义,可以修改布局,颜色,排版等等

MySQL之JDBC入门详解

01-JDBC入门 一、JDBC概念 jdbc : java database connection , java数据库连接 jdbc是sun公司定义的java程序访问数据库的规范。 二、JDBC操作需要6步 三、入门程序 1、使用eclipse打开一个新的工作空间 2、切换到java视图界面 3、创建java工程:01-jdbc-helloworl…

BackTrader-Commission 06

Backtrader 策略实例,该部分内容通过使用backtrader对常用的策略实例的编写,提高和熟悉backtrader的实际场景的使用。 [Backtrader]实例:均线策略 [Backtrader] 实例:MACD策略 [Backtrader] 实例:KDJ 策略 [Backtrader] 实例:RSI 与 EMA 结合 [Backtrade…

WordPress伪静态设置

为什么要设置WordPress伪静态,搜索引擎优化(SEO)中,静态URL通常被认为更易于搜索引擎爬虫抓取和索引,有助于提高网站的搜索引擎排名。 WordPress伪静态设置方法主要依赖于服务器环境,以下是针对不同服务器…

sublime python出现中文乱码怎么办

一、乱码现象 利用sublime自带编译快捷方式ctrlB会出现中文乱码的情况。 print("没有循环数据!") print("完成循环!") 二、寻找原因 1、由于之前我已经安装了插件ConvertToUTF8,排除文本编码错误问题。 2、相同的代码在插件sublimerepl搭建的…

【ARM Linux 系统稳定性分析入门及渐进 1.2 -- Crash 工具依赖内容】

请阅读:【Linux 维测及Crash使用专栏】 文章目录 Prerequisites1. 内核对象文件2. 内存镜像3. 平台处理器类型4. Linux 内核版本 Prerequisites crash 工具需要依赖下面的内容: 1. 内核对象文件 vmlinux 文件:需要一个 vmlinux 内核对象文件&#xff…

电路设计过程就是波形整形过程

这种说法有一定的道理。在电路设计中,常常需要对输入的电信号波形进行处理和调整,以满足后续电路或系统的要求,这在某种程度上可以理解为波形整形的过程。 例如,在数字电路中,输入的信号可能存在噪声、干扰或者不符合…

计算机视觉-显著性检测实验报告

实验四 显著性检测实验 一、实验目的 掌握多种显著性检测算法的基本原理。学会使用计算机程序实现不同的显著性检测方法。通过对比不同的显著性检测算法,理解各算法的优缺点。分析显著性检测在实际图像处理应用中的效果和局限性。 二、实验内容和要求 1&#x…

05-Dubbo的应用及注册和SPI机制

05-Dubbo的应用及注册和SPI机制 Dubbo 的服务注册中应用级注册优化 Dubbo 的注册中心 Dubbo 支持很多种注册中心,支持的主流注册中心包括:ZooKeeper、Nacos、Redis Dubbo 需要引入注册中心依赖,并且配置注册中心地址,这里以 ZooKe…

【 AI 大模型:重塑软件开发的新势力】

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

南宁周边乡村游微信小程序ssm+论文源码调试讲解

第二章 开发工具及关键技术介绍 2.1微信开发者工具 微信开发者工具现在已经被小程序开发团队开发运行,目前微信开发者工具任然在不断的完善中,在开发小程序时经常要不断的更新。可以使用微信扫码登陆开发者工具,开发者工具将使用这个微信帐号…

ssm校园二手交易管理系统+vue

系统包含:源码论文 所用技术:SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习,获取源码看文章最下面 需要定制看文章最下面 目 录 1 绪论 1 1.1 选题背景 1 1.2 选题意义 1 1.3 研究内容 2 2 系统开发技术 3 2.1 MySQL数…

DB-GPT系列(二):DB-GPT部署(镜像一键部署、源码部署)

一、简介 DB-GPT 是一个开源项目,其将大语言模型 LLM 与数据库紧密结合。该项目主要致力于探索如何让预训练的大规模语言模型(例如 GPT)能够直接与数据库进行交互,从而生成更为准确且信息丰富的回答。 DB-GPT部署后能否直接使用…

掌握 Jest 配置文件:优化单元测试的灵活性与可维护性

引言 在现代软件开发中,单元测试是确保代码质量和稳定性的关键步骤。Jest 是一个广泛使用的 JavaScript 测试框架,提供了丰富的配置选项来优化测试过程。通过配置文件,开发者可以更灵活地控制测试环境,确保测试的可靠性和可维护性…

网络:IP分片和组装

个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言16位标识,3位标志,13位片偏移分片组装总结 前言 对于IP分片和组装的总结 当一个IP数据报的大小超过网络的MTU(最…

Node.js:Express 中间件 CORS 跨域资源共享

Node.js:Express 中间件 & CORS 中间件全局中间件局部中间件分类错误级中间件内置中间件 CORS原理预检请求 中间件 中间件是不直接接收请求,也不直接发送响应,而是在这之间处理一个中间过程的组件。 当一个请求到来,会经过多…

【VScode】中文版ChatGPT编程工具-CodeMoss!教程+示例+快捷键

文章目录 1. 多模型选择2. 编辑快捷键3. 历史记录收藏 CodeMoss使用教程1. 安装CodeMoss插件2. 配置AI模型3. 使用快捷键4. 进行代码优化与解释5. 收藏历史记录 总结与展望 在当今快速发展的编程世界中,开发者们面临着越来越多的挑战。如何提高编程效率,…

LabVIEW适合开发的软件

LabVIEW作为一种图形化编程环境,主要用于测试、测量和控制系统的开发。以下是LabVIEW在不同应用场景中的适用性和优势。 一、测试与测量系统 LabVIEW在测试与测量系统中的应用广泛,是工程测试领域的主流工具之一。利用其强大的数据采集与处理功能&…