STM32-自学笔记(13.NVIC和外部中断)

发布者:DazzlingSpirit最新更新时间:2022-04-15 来源: eefocus关键字:STM32  NVIC  外部中断 手机看文章 扫描二维码
随时随地手机看文章

1.NVIC,嵌套中断向量控制器。(通俗点理解就是,许多中断向量交织在一起,形成一个向量网)

和SysTick定时器一样,NVIC属于ARM Cortex-M3内核的内部设备之一,与基于此内核的控制器并无直接联系,就是说任何一款基于ARM Cortex-M3内核的微控制器都带有NVIC.

作用:用来管理中断嵌套的,主要在于优先级的管理。嵌套是什莫?,先回忆一下中断的几个概念。


  • 中断响应:当某个中断来临,会将相应的中断标志位置位。当CPU查询到这个置位的标志位时,将响应此中断,并执行相应的中断服务函数。


  • 中断优先级:每个中断都具有其优先级,其相互之间的优先关系一般以优先级编号较小者拥有较高优先级。而大家容易忽略的是,优先级又分为两种:查询优先级和执行优先级。


  • 查询优先级和执行优先级:当某一时刻有两个或以上中断处于挂起状态,这首先执行执行优先级较高的中断。若执行优先级一致,则首先执行查询优先级较高的中断。查询优先级一般以该中断向量在中断向量表中的位置决定。


  • 中断嵌套:当某个执行优先级较低的中断服务在执行时另一个执行优先级较高的中断来临,则当前优先级较低的中断被打断,CPU转而执行较高优先级的中断服务。


  • 中断挂起:当某个执行较高优先级的中断服务在执行时,另一个优先级较低的中断来临,则因为优先级的关系,较低优先级中断无法立即响应,则进入挂起状态(等待执行)。


2.外部中断(EXTI),STM32的外部中断资源是非常丰富的,其每一个GPIO口都可以设置为一个EXTI通道。每个输入通道可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入通道都可以被独立的屏蔽。挂起寄存器会保持着某个通道的中断请求。


STM32一共为GPIO配备了19个中断通道,但其中只有16个是由用户自由支配的,分别为EXTI0~EXTI15通道,而EXTI16~EXTI18通道分配给了STM32的RTC、PVD以及USB使用。


  • 每个中断事件都有独立的触发位和屏蔽位

  • 每个中断通道都有专用的状态位

  • 支持多达19个中断源请求

  • 可以检测到脉冲宽度低于APB2时钟宽度的外部信号


实验设计:

配置3个STM32的外部中断,分别为EXTI0、EXTI1、EXTI2,并分别赋予他们从低到高的先占优先级。首先触发EXTI0中断,并在其中断服务返回之前触发EXTI1中断,同样在EXTI1中断返回之前触发EXTI2中断。按照此流程,程序应该发生了2次中断嵌套,并且在EXTI2中断服务完成之后,依EXTI2---EXTI1---EXTI0的次序进行中断返回。以上过程使用串口向上位机打印信息。

硬件电路:

一个按键和STM32微控制器相连接。还有也需要USART的电平转换电路。

软件设计(程序设计)

设计要点:这个实验重点涉及NVIC 和 EXTI的初始化工作

  • 配置RCC寄存器组,开启GPIOA和AFIO时钟。

  • 配置GPIOA.0、GPIOA.1和GPIOA.2位浮空输入模式,并将齐分别设置为外部中断EXTI0、EXTI1、EXTI2的输入通道。

  • 配置NVIC,使用优先级分组2,并赋予:EXTI0,2级先占优先级,0级次占优先级;EXTI1,1级先占优先级,0级次占优先级;EXTI2,0级先占优先级,0级次占优先级;

  • 开启EXTI0、EXTI1、EXTI2中断,并在下降沿时触发中断。

  • 配置USART。


主函数  main.c


#include"stm32f10x_lib.h"

 

#include"stdio.h"

 

void RCC_Configuration (void);

 

void GPIO_Configuration (void);

 

void NVIC_Configuration (void);

 

void EXTI_Configuration (void);

 

void USART_Configuration (void);

 

int main (void)

 

{

 

RCC_Configuration ();                  //设置系统时钟

 

GPIO_Configuration ();                 //设置GPIO端口

 

NVIC_Configuration ();                 //设置NVIC

 

EXTI_Configuration ();                 //设置EXTI

 

USART_Configuration ();                //设置USART

 

while(1);

 

}

设置系统各部分时钟  RCC_Configuration


void RCC_Configuration(void)

 

{

 

ErrorStatus HSEStartUpStatus;      //定义枚举类型变量 HSEStartUpStatus

 

RCC_DeInit();                     //复位系统时钟设置

 

RCC_HSEConfig(RCC_HSE_ON);         //开启HSE

 

HSEStatrtUpStatus=RCC_WaitForHSEStartUp();   //等待HSE起振并稳定

 

if(HSEStatrtUpStatus==SUCCESS)     //判断HSE是否起振成功,是则进入if()内部

 

{

 

RCC_HCLKConfig(RCC_SYSCLK_Div1);   //选择HCLK(AHB)时钟源为SYSCLK分频

 

RCC_PCLK2Config(RCC_HCLK_Div1);    //选择PCLK2时钟源为HCLK(AHB)1分频

 

RCC_PCLK1Config(RCC_HCLK_Div2);    //选择PCLK1时钟源为HCLK(AHB)2分频

 

FLASH_SetLatency(FLASH_Latency_2);  //设置Flash延时周期数为2

 

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);   //使能Flash预取缓存

 

//选择PLL时钟源为 HSE 1 分频,倍频数为9,则PLL=8MHz *9=72MHz

 

RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);

 

RCC_PLLCmd(ENABLE);                  //使能PLL

 

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);  //等待PLL输出稳定

 

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);    //选择SYSCLK时钟源为PLL

 

while(RCC_GetSYSCLKSource()!=0x08);      //等待PLL成为SYSCLK时钟源

 

}

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);    //打开APB2总线上的GPIOA、USART1、AFIO时钟

 

}

 

设置各GPIO端口功能  GPIO_Configuration


void GPIO_Configuration(void)

 

{

 

GPIO_InitTypeDef GPIO_InitStructure;

//设置PA.0、PA.1、PA.2为浮空输入

 

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;

 

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

 

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

//定义PA.0为外部中断0输入通道(EXTI)

 

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

 

//定义PA.1为外部中断0输入通道(EXTI1)

 

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);

 

//定义PA.2为外部中断2输入通道(EXTI2)

 

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource2);

 

//设置USART1的Tx脚(PA.9)为第二功能推挽输出,最大翻转频率为50MHz

 

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;

 

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

 

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

 

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

//设置USART1的Rx脚(PA.10)为浮空输入脚

 

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;

 

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

 

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

}

设置NVIC参数   NVIC_Configuration


void NVIC_Configuration (void)

 

{

 

//定义NVIC初始化结构体NVIC_InitStructure

 

NVIC_InitTypeDef NVIC_InitSturcture;

 

//#ifdef、#else、#endif结构的作用是根据预编译条件决定中断向量表起始地址

 

#ifdef  

 

//中断向量表起始地址从0x20000000开始

 

NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);

 

#else

 

//中断向量表起始地址从0x80000000开始

 

NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);

 

#endif

 

//选择NVIC优先级分组2

 

NVIC_PriorotyGroupConfig(NVIC_PriorotyGroup_2);

 

//使能EXTI0通道,2级先占优先级,0级次占优先级

 

NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQChannel;

 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;

 

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

 

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

 

NVIC_Init(&NVIC_InitStructure);

 

 

//使能EXTI1通道,1级先占优先级,0级次占优先级

 

NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQChannel;

 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;

 

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

 

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

 

NVIC_Init(&NVIC_InitStructure);

 

//使能EXTI2通道,0级先占优先级,0级次占优先级

 

NVIC_InitStructure.NVIC_IRQChannel=EXTI2_IRQChannel;

 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;

 

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

 

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

 

NVIC_Init(&NVIC_InitStructure);

 

}

 

设置EXTI参数  EXTI_Configuration


void EXTI_Configuration (void)

 

{

 

//定义EXTI初始化结构体EXTI_InitStructure

 

EXTI_InitTypeDef EXTI_InitStructure;

 

//设置外部中断0、1、2通道在下降沿是触发中断

 

EXTI_InitStructure.EXTI_Line=EXTI_Line0 | EXTI_Line1 | EXTI_Line2;

 

EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;

 

EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;

 

EXTI_InitStructure.EXTI_LineCmd=ENABLE;

 

EXTI_Init(&EXTI_InitStructure);

 

}

设置USART1  USART_Configuration


void USART_Configuration(void)

 

{

 

USART_InitTypeDef USART_InitStructure;       //定义USART初始化结构体USART_InitStructure

 

USART_ClockInitTypeDef USART_ClockInitStructure;  //定义USART初始化结构体USART_ClockInitStructure

 

//波特率为9600bps;8位数据长度,1个停止位,无检验位;禁用硬件流控制;禁止USART时钟;时钟极性低;在第2个边沿捕获数据;最后一位数据的时钟脉冲不从SCLK输出

 

USART_InitStructure.USART_BaudRate=9600;

 

USART_InitStructure.USART_WordLength=USART_WordLength_8b;

 

USART_InitStructure.USART_StopBits=USART_StopBits_1;

 

USART_InitStructure.USART_Parity=USART_Parity_NO;

 

USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;

 

USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;

 

USART_Init(USART1,&USART_InitStructure);

 

USART_Cmd(USART1,ENABLE);         //使能USART1

 

}

将printf函数重定位到USART1   fputc


int fputc (int ch,FILE*f)

 

UASRT_SendData(USART1,(u8)ch);

 

while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);

 

return ch;

中断服务程序


头文件


#include "stm32f10x_it.h"

 

#include"stdio.h"

外部中断0中断服务函数       EXTI0_IRQHandler


void EXTI0_IRQHandler (void)

 

{

 

printf("rnEXTI IRQHandler enter.rn");

 

//触发外部中断1

 

EXTI_GenerateSWInterrupt(EXTI_Line1);

 

printf("rnEXTI IRQHandler return.rn");

 

EXTI_ClearFlag(EXTI_Line0);

 

}

外部中断1中断服务函数      EXTI1_IRQHandler


void EXTI0_IRQHandler (void)

 

{

 

printf("rnEXTI1 IRQHandler enter.rn");

 

//触发外部中断2

 

EXTI_GenerateSWInterrupt(EXTI_Line2);

 

printf("rnEXTI1 IRQHandler return.rn");

 

EXTI_ClearFlag(EXTI_Line1);

 

}

 

外部中断2中断服务函数      EXTI2_IRQHandler


void EXTI0_IRQHandler (void)

 

{

 

printf("rnEXTI2 IRQHandler enter.rn");

 

printf("rnEXTI2 IRQHandler return.rn");

 

EXTI_ClearFlag(EXTI_Line2);

 

}


注意事项:

  1. 程序中EXTI0使用手动触发的方式,但EXTI1和EXTI2使用了软件触发的方式。

  2. 请一定要打开AFIO时钟。

  3. 虽然EXTI1和EXTI2使用了软件触发的方式,但是他们所对应的引脚设置以及中断触发方式的设置仍然是不可缺少的。

  4. 本程序中使用了优先级分组2,一共可以支持4个先占优先级,四个次占优先级。谨记,在设置设备中断优先级的时候,不要越出优先组所能分配的最大数量,否则将会产生不可预知的问题。

  5. 进入EXTI中断之后,要在其退出之前手动清除中断标志,否则中断会一直请求。


关键字:STM32  NVIC  外部中断 引用地址:STM32-自学笔记(13.NVIC和外部中断)

上一篇:STM32自学笔记(1.什么是STM32)
下一篇:STM32-自学笔记(14.NVIC和外部中断,程序用到的库函数介绍)

推荐阅读最新更新时间:2024-11-16 22:40

STM32串口通信USART(二)---DMA方式
刚接触到DMA的时候,一头雾水,只知道方便、快捷,但不知道该怎么使用,后来弄明白原理之后就轻松了很多,但理解的还不是很透,所以希望把自己的理解写出来,和大家分享一下! 形象的说,DMA就像一个快递中转站,负责把数据从始发地搬到目的地,只要他负责的仓库有货,他就开始搬运,没货就等着,除非你把它关了。就像机器人搬东西一样,首先要告诉它从哪搬,搬到哪?东西有多大?需要搬几趟?需要搬运的东西是不是都在一起?搬完后是不是扔在那就行了,还是要放好? 到芯片里,数据就是货物,把数据从一个地方移到另一个地方。你只要告诉它怎么移到就行了,就像控制一个机器人一样。并不是多有的外设都能有机会使用DMA通道,而且,一条通道上被外设使用后,通道上的
[单片机]
<font color='red'>STM32</font>串口通信USART(二)---DMA方式
STM32的USART1与USART2模块串行数据通讯功能
STM32的USART1与USART2模块支持多种功能,包括IrDA红外、Smart Card(IC卡)等。本文就其串行数据通讯功能进行讲解。 USART功能图: 一般情况串口都采用异步方式通讯,因此本文只讲解异步通讯方式(UART)。异步模式下串口采用Tx、Rx两线,其数据模式如图: 上图为数据长度为8位(包括1位校验)的情形。位数据的意义: 总线空闲 :空闲时线上为高电平。 起始位 :一位逻辑0信号帧,代表传输开始。 数据位 :可以为7位或8位数据。低位开始传输 校验位: 若启用,使得逻辑1的位数应为偶数(偶校验)或奇数(奇校验)。若不启用,该位由一位数据帧替代(多一位数据)。 停止位:
[单片机]
<font color='red'>STM32</font>的USART1与USART2模块串行数据通讯功能
对比STM32各系列产品特性和外设兼容性
在考虑更换STM32,且跨系列更换,可以看看下面各系列的对比图。 STM32产品系列特性比较 下面是STM32F0、F1、F2、F4、L1各产品系列的特性进行对比: 3 外设兼容性分析对比 对STM32进行过研究的朋友,特别是使用过寄存器开发的朋友应该很明白STM32片上外设,进行过对比的朋友,会发现,各系列MCU的片上外设很多相似之处,甚至完全一样。 下面将F1分别和F0、F2、F4、L1对比一下,大家看看有哪些差异。 1.STM32 F1 与 F0 系列外设兼容性分析对比 2.STM32 F1 与 F2 系列外设兼容性分析对比 3.STM32 F1 与 F4 系列外设兼容性分析对比 4.STM32 F
[单片机]
对比<font color='red'>STM32</font>各系列产品特性和外设兼容性
基于STM32的步进电机实验
步进电机介绍 步进电机是将电脉冲信号转变为角位移或线位移的开环控制元步进电机件。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度,称为“步距角”,它的旋转是以固定的角度一步一步运行的。可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。 步进电机基础知识 步进电机参数说明 四相步进电机有两种运行方式 1.四相四拍;2.四相八拍。 拍数 指电机转过一个齿距角所需脉冲数,通俗的来讲拍数指的是步进电机运行时每转一个齿距所需
[单片机]
基于<font color='red'>STM32</font>的步进电机实验
STM32笔记(五)RTC的初始化
这次是RTC的笔记:) RTC这东西晕晕的,因为一个模块涉及到了RTC,BKP,RCC多个模块,之间的关系让人有点模糊 入门的知识请大家看手册,我来总结: 总之,RTC只是个能靠电池维持运行的32位定时器over! 所以,使用时要注意以下问题: 1. 上电后要检查备份电池有没有断过电。如何检查? 恩,RTC的示例代码中已经明示: 往备份域寄存器中写一个特殊的字符,备份域寄存器是和RTC一起在断电下能保存数据的。 上电后检查下这个特殊字符是否还存在,如果存在,ok,RTC的数据应该也没丢,不需要重新配置它 如果那个特殊字符丢了,那RTC的定时器数据一定也丢了,那我们要重新来配置RTC了 这个过程包括时钟使能、R
[单片机]
STM32F2系列的EXTI使用
1.外部中断事件线的映射 140个GPIO连接到了16个外部中断/事件线,如下图所示: GPIO与外部中断/事件线关联图 另外7个外部中断/事件线分别连接: EXTI Line 16:PVD输出; EXTI Line 17:RTC报警事件; EXTI Line 18:USB OTG FS唤醒事件; EXTI Line 19:以太网唤醒事件; EXTI Line 20:USB OTG HS唤醒事件; EXTI Line 21:RTC Tamper and TimeStamp事件 EXTI Line 22:RTC唤醒事件。 2.EXTI与SYSCFG(System configuration
[单片机]
STM32F2系列的<font color='red'>EXTI</font>使用
STM32 GPIO引脚模式配置
STM32单片机中,GPIO引脚可以配置为较多的模式,本文将对此方面进行介绍。 一、输入/输出模式 二、输出模式 GPIO输出模式下,几种速度的区别: (1). GPIO 引脚速度: GPIO引脚速度主要有三种:2MHz、10MHz、 50MHz。 引脚速度又称输出驱动电路的响应速度, GPIO的引脚速度跟应用相匹配,速度配置越高,噪声越大,功耗越大。带宽速度高的驱动器耗电大、噪声也大,带宽低的驱动器耗电小、噪声也小。使用合适的驱动器可以降低功耗和噪声。 (2). GPIO的翻转速度 输入/输出寄存器的0 ,1 值反映到外部引脚(APB2上)高低电平的速度.手册上指出GPIO最大翻转速度可达18M
[单片机]
STM32之TFT-LCD液晶
TFT-LCD即薄膜晶体管液晶显示器。其英文全称为:Thin Film Transistor-Liquid Crystal Display。TFT-LCD与无源TN-LCD、STN-LCD的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。TFT-LCD也被叫做真彩液晶显示器。 TFT液晶原理: *背光模组:提供光源 *上下偏光片,TFT Glass Substrate, 液晶:形成偏振光,控制光线的通过与否 *彩色滤光片:提供TFT LCD R/G/B(三原色)的来源 *ITO透明导电层:提供透明的导电通路
[单片机]
<font color='red'>STM32</font>之TFT-LCD液晶
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved