NVIC和EXTI

NVIC和EXTINVIC:NestVectorInterruptController,嵌套中断向量控制器,是用来管理中断嵌套的,核心任务在于其优先级的管理。NVIC给每个中断赋予先占优先级(抢占优先级)和次占优先级(响应优先级)。CM3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。但STM32并没有使用CM3内核的全部东西,而是只用了它的一部分,STM

大家好,又见面了,我是你们的朋友全栈君。

NVICNest Vector Interrupt Controller,嵌套中断向量控制器,是用来管理中断嵌套的,核心任务在于其优先级的管理。NVIC给每个中断赋予先占优先级(抢占优先级)和次占优先级(响应优先级)。

CM3 内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。但STM32并没有使用CM3内核的全部东西,而是只用了它的一部分,STM3276 个中断,包括16 个内核中断和60 个可屏蔽中断,具有16级可编程的中断优先级。而我们常用的就是这60个可屏蔽中断。

STM32CM3内核的中断向量表进行了重新编排,将编号-36的中断向量定义为系统异常,编号为负的内核异常不能被设置优先级,从编号7开始为外部中断,这些中断优先级都是可以自行设置的。

EXTIExternal Interrupt,外部中断,通过GPIO检查输入脉冲,引起中断时间,打断原来的代码执行流程,进入到中断服务函数中进行处理,处理完后再返回中断之前的代码中执行。

STM32 EXTI控制器支持19个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM3219 个外部中断为 :
线 0~15:对应外部IO口的输入中断。
线 16:连接到PVD输出。
线 17:连接到RTC闹钟事件。
线 18:连接到USB唤醒事件。

 

EXTI中断步骤:

① 配置端口为输入模式

② 开启与该IO口相对应的线上中断/事件,并设置触发条件

③ 配置中断分组(NVIC)并使能中断

④ 中断函数

 

一、配置端口为输入模式

void GPIOA_Init(void)

{

   GPIO_DeInit(GPIOA);

RCC->APB2ENR|=1<<2;     //使能PORTA时钟

GPIOA->CRL&=0XFFFFFFF0;//PA0设置成上拉输入   

GPIOA->CRL|=0X00000008;   

}

在对端口进行任何操作之前,必须打开对应的时钟信号,其设置才能生效。这里使

用了GPIOA.00 端口作为中断0输入,作为输入时一般我们设置为上拉输入,如果要

设置成浮空输入的话,外部一定要加上拉电阻,这样对于过滤输入波动很有益处(

设在电压在3.3-2.0之间进行波动,时间上没尝试按键操作,因为一旦有按键,就应

该为0,那么接了上拉的话,除非产生了低电平,否则小波动都会被拉高过滤掉)

 

二、开启与该IO口相对应的线上中断/事件,并设置触发条件

这一步封装在函数void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)中,可以直接调用,例如:Ex_NVIC_Config(GPIO_A,0,RTIR); //设置PA0上升沿触发

  Ex_NVIC_Config(GPIO_A,13,FTIR);//设置PA13)下降沿触发

该函数为 Ex_NVIC_Config,该函数有3个参数:GPIOxGPIOA~G0~6),在sys.h里面有定义。代表要配置的IO口。BITx则代表这个IO口的第几位。TRIM为触发方式,低2位有效(0x01代表下降触发;0x02代表上升沿触发;0x03代表任意电平触发)。其代码如下:
/**************************

该函数只针对GPIOA~G;不包括PVDRTCUSB唤醒这三个,参数:GPIOA~G0~6),代表GPIOA~G;BITx:需要使能的位;TRIM:触发模式,1,上升沿;2,下降沿;3,任意电平触发;该函数一次只能配置1IO 口,多个IO 口,需多次调用,该函数会自动开启对应中断,以及屏蔽线

***************************/

void Ex_NVIC_Config(u8 GPIOxu8 BITxu8 TRIM)
{

u8 EXTADDR;
u8 EXTOFFSET;
EXTADDR=BITx/4;//得到中断寄存器组的编号
EXTOFFSET=(BITx%4)*4;
RCC->APB2ENR|=0x01;//使能IO复用时钟
AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET;//EXTI.BITx映射到GPIOx.BITx
//自动设置
EXTI->IMR|=1<<BITx;//开启line BITx上的中断
EXTI->EMR|=1<<BITx;//不屏蔽lineBITx上的事件
if(TRIM&0x01)EXTI->FTSR|=1<<BITx;//lineBITx 上事件下降沿触发
if(TRIM&0x02)EXTI->RTSR|=1<<BITx;//lineBITx 上事件上升降沿触发
}

EXTICR(External interrupt configuration register)即外部中断配置寄存器。

因为STM32 任何一个IO口都可以配置成中断输入口,但是IO口的数目远大于中断线数(16个),所以我们需要选择哪一个中断是经由那个IO口输入的。于是STM32就这样设计,GPIOA~GPIOG[15:0]分别对应中断线15~0。这样每个中断线对应了最多7IO 口,以线0为例:它对应了GPIOA.0PIOB.0GPIOC.0GPIOD.0GPIOE.0GPIOF.0GPIOG.0。而中断线每次只能连接到1IO 口上,这样就需要EXTICR来决定对应的中断线配置到哪个GPIO上了。寄存器EXTIR有四组,在书写时要注意。具体对应关系如下:0000: PA[x] pin0001: PB[x] pin0010: PC[x] pin0011: PD[x] pin0100: PE[x] pin0101: PF[x] pin0110: PG[x] pin。假设我们需要设定外部中断0GPIOA_0来控制,那么我就可以写成AFIO->EXTIR[0] |=0X00;  

NVIC和EXTINVIC和EXTI

Ex_NVIC_Config,首先根据GPIOx的位得到中断寄存器组的编号,即EXTICR的编号,在EXTICR里面配置中断线应该配置到GPIOx的哪个位。然后使能该位的中断及事件,最后配置触发方式。这样就完成了外部中断的的配置了。从代码中可以看到该函数默认是开启中断和事件的。其次还要注意的一点就是该函数一次只能配置一个IO口,如果你有多个IO口需要配置,则多次调用这个函数就可以了。

三、配置中断分组(NVIC)并使能中断

这一步封装在函数void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)里面可以直接调用,例如

MY_NVIC_Init(2,2,EXTI0_IRQChannel,2);    //抢占2,子优先级2,组2
    NVIC 设置函数MY_NVIC_Init,该函数有4个参数,分别为:NVIC_PreemptionPriorityNVIC_SubPriorityNVIC_ChannelNVIC_Group。第一个参数NVIC_PreemptionPriority为中断抢占优先级数值,第二个参数NVIC_SubPriority为中断子优先级数值,前两个参数的值必须在规定范围内,否则也可能产生意想不到的错误。第三个参数NVIC_Channel为中断的编号(范围为0~59),最后一个参数NVIC_Group为中断分组设置(范围为0~4)。

/********************设置NVIC****************
*NVIC_PreemptionPriority:抢占优先级
*//NVIC_SubPriority :响应优先级
*NVIC_Channel :中断编号
*NVIC_Group :中断分组 0~4
*注意优先级不能超过设定的组的范围!否则会有意想不到的错误
*组划分:
*0:0 位抢占优先级,4 位响应优先级
*1:1 位抢占优先级,3 位响应优先级
*2:2 位抢占优先级,2 位响应优先级
*3:3 位抢占优先级,1 位响应优先级
*4:4 位抢占优先级,0 位响应优先级
*NVIC_SubPriority NVIC_PreemptionPriority的原则是,数值越小,越优先

************************************/
void MY_NVIC_Init(u8 NVIC_PreemptionPriorityu8 NVIC_SubPriorityu8NVIC_Channelu8 NVIC_Group)
{

  u32 temp;
  u8 IPRADDR=NVIC_Channel/4; //每组只能存4个,得到组地址
  u8 IPROFFSET=NVIC_Channel%4;//在组内的偏移
  IPROFFSET=IPROFFSET*8+4; //得到偏移的确切位置
  MY_NVIC_PriorityGroupConfig(NVIC_Group);//设置分组
  temp=NVIC_PreemptionPriority<<(4-NVIC_Group);
  temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
  temp&=0xf;//取低四位

if(NVIC_Channel<32)NVIC->ISER[0]|=1<<NVIC_Channel;//使能中断位(要清除的话,相反操作就OK)
   else

NVIC->ISER[1]|=1<<(NVIC_Channel-32);
NVIC->IPR[IPRADDR]|=temp<<IPROFFSET;//设置响应优先级和抢断优先级
}

MY_NVIC_PriorityGroupConfigNVIC的分组函数,该函数的参数NVIC_Group为要设置的分组号,可选范围为0~4,总共5组:EXTI0EXTI1EXTI2EXTI3EXTI4Line0~Line4EXTI15_10Line15~Line10EXTI9_5Line9~Line5。如果参数非法,将可能导致不可预料的结果。

/***************设置NVIC分组*****************
*NVIC_Group:NVIC 分组 0~4总共5

************************************/

void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
{

  u32 temptemp1;
  temp1=(~NVIC_Group)&0x07;//取后三位

temp1<<=8;

temp=SCB->AIRCR; //读取先前的设置

temp&=0X0000F8FF; //清空先前分组

temp|=0X05FA0000; //写入钥匙

temp|=temp1;

SCB->AIRCR=temp; //设置分组
}

MY_NVIC_PriorityGroupConfig 函数设置中断优先级分组的思路:STM325 个分组是通过设置SCB->AIRCRBIT[10:8]来实现的,SCB->AIRCR的修改需要通过在高16位写入0X05FA这个密钥才能修改的,故在设置AIRCR之前,应该把密钥加入到要写入的内容的高16位,以保证能正常的写入AIRCR。在修改AIRCR的时候,我们一般采用读->->写的步骤,来实现不改变AIRCR原来的其他设置。MY_NVIC_PriorityGroupConfig分组函数在每个系统里面只要设置一次就够了,设置多次,则是以最后的那一次为准。但是只要多次设置的组号都是一样,就没事。否则前面设置的中断会因为后面组的变化优先级会发生改变,这点在使用的时候要特别注意!一个系统代码里面,所有的中断分组都要统一,以上代码对要配置的中断号默认是开启中断的。也就是ISER中的值设置为1了。

四、中断函数

A.  中断函数名的书写有要求,否则会找不到中断入口。

stm32f10x_it.c是专门用来存放中断服务函数的。

3.5 库函数之前,在stm32f10x_it.c中就预先写好了个外部中断的函数名称,我们只要将对应的执行过程填充进去就可以。

3.5库函数中,文件中默认只有几个福安与系统异常的中断服务函数,而且都是空函数,在需要的时候自行编写。但是中断服务函数名是不可以自己定义,中断服务函数的名字必须要与启动文件startup_stm32f10x_hd.s中的中断向量表中定义一致。

B. 在进入中断后我们需要做的动作有 2 部,一次执行中断过程,2 是清除中断挂起标识,因为执行完毕了。如果不清除中断挂起标识,则无法再次进入中断。

例程:

void EXTI0_IRQHandler(void)

{

 delayMs(10);

  if(((GPIOA->IDR)&0x01)==0)

 {

      while(((GPIOA->IDR)&0x01)==1);            

      GPIOA->ODR  = ~(GPIOA->ODR&0X02);

         EXTI->PR=1;    

   }     

}

这里 EXTI->PR=1,即想中断挂起寄存器中写1,清除中断

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/140280.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号