STM32
直播中

程成

12年用户 502经验值
私信 关注
[问答]

如何使用NVIC_IRQChannel参数来选择将要配置的中断向量?

如何使用NVIC_IRQChannel参数来选择将要配置的中断向量?

回帖(1)

袁声瑜

2021-11-17 14:20:09

//中断实验--利用按键进行的中断;
//首先分析STM32的中断机制:
/*
    因为STM32的中断如此之多:
    需要一个东西来控制,此时,就运用:NVIC(中断控制器)来操作,不可屏蔽中断(NMI)和外部中断都由它处理。
    但是SYSTICK不是由NVIC来控制的。
*/
/*
库函数中NVIC 的结构体成员:
NVIC_InitTypeDef类型的结构体。这个结构体有4个成员:
NVIC_IRQChannel ---------- 需要配置的中断向量
NVIC_IRQChannelCmd ------- 使能或关闭相应中断向量的中断响应
NVIC_IRQChannelPreemptionPriority ------- 配置相应中断向量抢占优先级
NVIC_IRQChannelSubPriority -------- 配置相应中断向量的响应优先级;


使用:
首先使用NVIC_IRQChannel参数来选择将要配置的中断向量,
用NVIC_IRQChannelCmd参数来进行使能(ENABLE)和关闭(DISABLE)该中断;
NVIC_IRQChannelPreemptionPriority 成员中配置向量的抢占的优先级,
在NVIC_IRQChannelSubPriority 需要配置中断向量的响应优先级。
而在STM32中,最重要是配置其优先级。但是这两种优先级有什么区别和联系呢?


抢占优先级和响应优先级:
STM32的中断具有两个属性,一个为抢占属性,另一个为响应属性,其属性的编号越高表明其优先级越高。


抢占,是指打断其他中断属性,即因为具有这个属性会出现嵌套中断(在执行中断服务函数A的过程中被中断B打断,执行完中断服务函数B再继续服务函数B再继续
执行中断服务函数A),抢占属性由NVIC_IRQChannelPreemptionPriority的参数配置。


而相应属性则应用在抢占属性相同的情况下,当两个中断向量的抢占优先级相同时,如果两个中断同时到达,则先处理响应优先级高的中断,
相应属性由NVIC_IRQCh|annelSubPriority的参数配置。


例如:
中断向量        抢占优先级       响应优先级
A                  0                 0
B                  1                 0
C                  1                 1
此时,若内核正在执行C的中断服务函数,则它能被抢占优先级更高的中断A打断,由于B和C的抢占优先级相同,所以C不能被B打断。
但如果B和C中断是同时到达的,内核就会首先响应优先级更高的B中断。




NVIC的优先级组:
在配置优先级的时候,还要注意一个很重要的问题,即中断种类的数量。NVIC值可以配置16种中断向量的优先级,也就是说,抢占优先级和响应优先级的数量
由一个4位的数字来决定,把这个4位数字分配成抢占优先级部分和响应优先级部分。
有5组分配方式:
第0组:所有4位用来配置响应优先级。即16种中断向量具有不相同的响应优先级。
第1组:最高1位用来配置抢占优先级,低3位用来配置响应优先级。表示2(1次)=2中级别的抢占优先级(0级,1级),有2(3次)=8种响应优先级,即在16种
中断向量之中,有8种中断,其抢占优先级都为0级,而它们的响应优先级分别为0~7,其余8种中断向量的抢占优先级则都为1级,响应优先级分别为0~7.
第2组:2位用来配置抢占优先级,2位用来配置响应优先级。即2(2次)=4种抢占优先级,2(2次)=4种响应优先级。
第3组:高3位用来配置抢占优先级,最低1位用来配置响应优先级。即有8种抢占优先级,2种响应优先级。
第4组:所有4位用来配置抢占优先级,即NVIC配置的想2(4次方)=16种中断向量都是只有抢占优先级没,有响应属性。
*/
/*
EXTI外部中断:
STM32单片机的所有I/O端口都可以配置为EXTI中断模式,用来捕捉外部信号,可以配置为下降沿中断、上升沿中断和上升下降沿中断这三种模式。
STM32的所有GPIO都引入到EXTI外部中断线上,使得所有的GPIO都能作为外部中断的输入源。
观察参考手册原理图可知,PA0~PG0连接到EXTI0,PA1~PG1连接到EXTI1,以此类推,PA15~PG15连接到EXTI15。


注意:PAx~PGx端口的中断事件都连接到了EXTIx,即同一时刻EXTIx只能响应一个端口的事件触发,不能够同一时间响应所有GPIO端口事件,但可以分时复用。
它可以配置为上升沿触发、下降沿触发和双边沿触发。
EXTI最普通的应用就是接上一个按键,设置为下降沿触发,用中断来检测按键。
*/
//根据我自己实验板的原理图有下列代码:
//我的是PC5连接按键,所以选其作为中断线路:


void EXTI_PC5(void)
{
        GPIO_InitTypeDef GPIO_C;
        EXTI_InitTypeDef EXTI_C;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);    //此句是当GPIO口连接到JTAG上时用。
   //GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
       
        NVIC_CON();        //配置并初始化中断控制器
       
        GPIO_C.GPIO_Pin = GPIO_Pin_5;
        GPIO_C.GPIO_Mode= GPIO_Mode_IPU;
        GPIO_Init(GPIOC,&GPIO_C);
       
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
       
        EXTI_C.EXTI_Line=EXTI_Line5;
        EXTI_C.EXTI_Mode=EXTI_Mode_Interrupt;
        EXTI_C.EXTI_Trigger=EXTI_Trigger_Falling;
       
        EXTI_C.EXTI_LineCmd=ENABLE;
        EXTI_Init(&EXTI_C);
}
static void         NVIC_CON(void)
{
        NVIC_InitTypeDef NVIC_X;        //定义一个NVIC类型的结构体变量
       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);                //定义一个分组类型
       
        NVIC_X.NVIC_IRQChannel = EXTI9_5_IRQn;                                //配置中断向量;
        NVIC_X.NVIC_IRQChannelPreemptionPriority = 2;                //配置响应优先级;
        NVIC_X.NVIC_IRQChannelSubPriority = 1;                                //配置抢占优先级;
        NVIC_X.NVIC_IRQChannelCmd = ENABLE;                                        //使能配置;
       
        NVIC_Init(&NVIC_X);        //配置完成进行初始化;
}
GPIO_EXTILineConfig这个函数的意义是:Selects the GPIO pin used as EXTI Line.(选择一个GPIO口作为中断线路)


/*关于STM32中断优先级分组的科普,初学者常见问题解答(Q&A)
http://www.openedv.com/forum.php?mod=viewthread&tid=275496&fromuid=122111
(出处: OpenEdv-开源电子网)
这里总结了一些常见问题,非常好。
*/


//最后main
int main(void)
{
        LED_0();
        LED_1();
        EXTI_PC5();
        while(1);
}


void LED_1(void)
{
        GPIO_InitTypeDef GPIO_A;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
       
        GPIO_A.GPIO_Pin=GPIO_Pin_8;
       
        GPIO_A.GPIO_Mode=GPIO_Mode_Out_PP;

        GPIO_A.GPIO_Speed=3;
       
        GPIO_Init(GPIOA,&GPIO_A);
}
void LED_0(void)
{
        GPIO_InitTypeDef GPIO_D;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
       
        GPIO_D.GPIO_Pin=GPIO_Pin_2;
       
        GPIO_D.GPIO_Mode=GPIO_Mode_Out_PP;

        GPIO_D.GPIO_Speed=3;
       
        GPIO_Init(GPIOD,&GPIO_D);
}
最后,在USER文件夹的:stm32f10x_it.c文件中,还应该加上:


void EXTI9_5_IRQHandler(void)
{int i=1000;
                while(i--);
        //GPIO_SetBits(GPIOA,GPIO_Pin_8);
        if (EXTI_GetITStatus(EXTI_Line5) != RESET) {
               
GPIO_WriteBit(GPIOA, GPIO_Pin_8,  
                (BitAction)((1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_8))));  
                EXTI_ClearITPendingBit(EXTI_Line5);
        }
}
这样在按键是,就能实现LED灯的熄灭和点亮
举报

更多回帖

发帖
×
20
完善资料,
赚取积分