芯嵌STM32:对STM32中断理解的补充

       初学者看到中断,头就大了。很多朋友学习51单片机,都学在了表面,不敢深入的其中一个原因就是惧怕、抵触中断、串口之类。只是,这是走技术必经之路。

       所有CPU的中断,一般都要处理两个方面的内容。

首先,要从CPU芯片层面来看,中断需要对应的向量表管理和中断优先级的选择,大家可以思考这样的场景,在某一个时刻,内部定时器中断正在运行,突然,来了一个更加紧急的外部IO引脚中断,告知一个紧急情况。那就必须暂停定时器中断,先执行IO引脚中断。这就是外部IO引脚中断优先级比定时器中断优先级高导致的。这在stm32中是通过NVIC(中断控制器)来实现。

其次,对于某个片内外设,或者内核的中断,为了让它工作,必须先让它先进入准备状态,然后在特定条件下触发它。这就涉及两个问题:1)让它随时处于准备状态——这就告知我们需要先初始化它;2)在特定条件下触发中断——这个就看外部给不给力。

以上,我们只是让大家稍微理解下中断的配置。下面,我们开始讲解stm32的中断。

针对STM32F103XX,总共有60个可屏蔽的中断通道,16个可编程的优先等级。注意,后者就是刚才讲的第一个方面的内容,即NVIC(中断控制器)实现的部分。前者是刚才讲的第二个方面内容,也就是平时所说的外部中断(通道)。

       先看NVIC。这部分是有专门的寄存器管理的。最重要的一个寄存器是IPR[15],它的功能是,将众多的中断通道进行优先等级划分。每个中断使用4bit位来控制自己的优先级别。这种优先级别又分为抢占优先级和子优先级两种。通俗点说,每个正在使用的中断,都要设置其抢占优先级和子优先级,前者优先于后者。并且其数字越小,优先级别越高。举例:

       假设一个外部中断,其抢占优先级为2,子优先级为2;定时器中断,其抢占优先级为1,子优先级为2。那么先比较抢占优先级,外部中断的抢占优先级2大于定时器的抢占优先级1,因此定时器中断会优先执行。如果抢占优先级别一样,就看子优先级。

       以上这种机制怎么实现呢?STM32内部有一个SCB->AIRCR寄存器,将抢占优先级和子优先级进行了分组,分5组,如下所示:

 

       现在,我们设置优先级的时候,可以先设置组别。比如设置第2组,那么,对应的,一共有2个抢占优先级别可选,有2个子优先级可选。而设置第几个分组,由函数来实现:

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

       知道分组后,再进行具体的优先级设定,比如抢占优先级设为2,子优先级设为2,可按如下方法:

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2;              NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

       以上就是NVIC的设置。当然,具体程序实现时,还需要确定是哪个通道要中断,并且使能它。

       下面来看某一个中断通道(比如外部中断)的中断设置。

       STM32中,每个IO口都可以作为一个外部中断入口。每个GPIO16个,就有16个外部中断入口。。。而一个STM32GPIOA,GPIOB, GPIOC,。。。好多。。。那要设置无数个。。。??不是的。STM32只设置了16个,即只有0-15个中断线,所有的GPIO共用,如下表所示:

 

       原来,只要是第0IO引脚的中断线,GPIOA/GPIOB/GPIOC….都共用它。同理,第1IO引脚,第2IO引脚。。。第15IO引脚,都共用。。。这样,stm32就只需要19个外部中断线:

线 0~15:对应外部 IO 口的输入中断。

线 16:连接到PVD输出。

线 17:连接到RTC闹钟事件。

线 18:连接到USB唤醒事件。

那如果我想设置GPIOA.3这个引脚作为外部中断入口,怎么设置呢?很简单,我们先选中这个引脚,然后配置这个引脚的中断属性。选中引脚,使用函数:

GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_tGPIO_PinSource);

比如要选中GPIOA.3,只要:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,  GPIO_PinSource3);

中断属性设置呢?如下:

EXTI_InitStructure.EXTI_Line = EXTI_Line03;       //GPIOA3引脚通道

EXTI_InitStructure.EXTI_Mode =EXTI_Mode_Interrupt;   //中断模式

EXTI_InitStructure.EXTI_Trigger =EXTI_Trigger_Falling;     //下降沿触发

 

讲到这里,大家应该对中断有所了解了。具体理解还是要实践操作编程才可以。编程时候需要注意的是,如果同时想设置两个以上的外部IO引脚作为中断入口,那么程序初始化时,一定要分开写。不能这样写

EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;

而应该分开写:

EXTI_InitStructure.EXTI_Line = EXTI_Line0;

……

EXTI_InitStructure.EXTI_Line = EXTI_Line1

……

如果你对中断的理解还有不明白的地方,请直接到我们的网站:www.51stm32.com ,进行讨论。我们将会尽快给您做出答复。

posted @ 2013-07-19 23:56  haibian826  阅读(351)  评论(0编辑  收藏  举报