看不懂可以先跳过,看完后边就懂了。
NVIC就是嵌套向量中断控制器。说白了,就是控制一大堆中断的东西。比如外部中断,或者发生异常以后怎么处理的中断。
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */
BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */
UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */
SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */
DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */
PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */
SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */
/****** STM32 specific Interrupt Numbers *********************************************************/
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
TAMPER_IRQn = 2, /*!< Tamper Interrupt */
RTC_IRQn = 3, /*!< RTC global Interrupt */
FLASH_IRQn = 4, /*!< FLASH global Interrupt */
RCC_IRQn = 5, /*!< RCC global Interrupt */
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */
DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */
DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */
DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */
DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */
DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */
DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */
DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */
里边有几个优先级为负数,高于普通中断优先级,且优先级不可配置。
我们之前说的优先级设置,抢占优先级啥的,说的就是NVIC里边的这些哪个优先级高哪个优先级低,除了外部中断还有很多,千万不要以为只是设置外部中断来了先处理哪个。比如我正在外部中断,突然来了个优先级更高的,我就先处理他。这就是中断嵌套
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
这句其实就是让你选择你在配置NVIC里边的哪个东西,配置好了以后才能进行下一步。外部中断0只是NVIC里边的一个。stm32的中断贼多
其实配置就4步:
NVIC_Configuration()这个函数是咱们自己写的,就是用来配置NVIC的。NVIC这个东西是写在core_cm3内核里的。所以stm32的手册里没咋详细写。还是老样子,我们要定义一个东西的话,就先定义一个关于他的结构体。人家已经给定义好了,在misc.h里边。这个文件主要放这些杂七杂八的
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.h file) */
//这个是设置你在配置哪个中断口。这里是配置的EXTI0中断,
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
//这个是设置主优先级
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
//这个就是次优先级
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
//这个是使能的,你要用了就把他配置成1,就可以用了。
} NVIC_InitTypeDef;
我们看具体的步骤:
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Set the Vector Table base location at 0x08000000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
//这一句是设置你的代码从哪启动,是从ram还是flash
/* Configure one bit for preemption priority */
// 2个抢占优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//这个是设置抢占优先级的,看上一篇文章就行了
/* Enable the EXTI0 Interrupt */
//开始配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
//外部中断线0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0(最高)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//次优先级(最高)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//使能
NVIC_Init(&NVIC_InitStructure);
//初始化
}
就是这么简单
这个是老生常谈了,很简单就两个函数,一个rcc,一个gpio。
注意,如果a0做了中断,那么bcdef的0就不行,因为只能有一个。
void RCC_Configuration(void)
{
// 起始代码中已经调用SystemInit将主时钟设置为72M
// 所以这里RCC就直接使能时钟就行了
//gpioa0接按键,gpiob1接灯
/* Enable Key Button GPIO Port, GPIO_LED and AFIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB| RCC_APB2Periph_AFIO, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//gpioa0接按键,gpiob1接灯
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET); // 默认输出0让LED亮
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //配置浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
GPIO的配置,点灯的那个设置成推挽输出,中断的那个设置成浮空输入
我是在主函数里配置的,配置完直接用。所以先调用这三句,让别的工作都准备好
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
一样的套路,先配置结构体,然后直接把他放进初始化函数里就行
int main(void)
{
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
//把哪个口的哪个线连接起来,意思就是在中断线中选一根给他连起来
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
//选定0号线
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
//中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
//下降沿
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
//使能
EXTI_Init(&EXTI_InitStructure);
//初始化
EXTI_GenerateSWInterrupt(EXTI_Line0);
//人工设置出一次中断,主要为了试一试。
while(1);
return 0;
}
这里。这个文件相当于是自己创建的,因为在startup里边他定义了一堆中断向量指向的中断处理程序。但是里边啥也没有,就一个死循环。我们用到哪个中断处理程序,就在it这个文件里自己写一个函数,把他之前的就相当于自动覆盖掉了
*主中断服务例程。
*此文件为所有异常处理程序和提供模板
外围设备中断服务程序。
大家明白了吧,这个文件是没有的,得你自己写。不过一般网上都有模板,套就完了。官方例程里也有。
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_1, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1))));
EXTI_ClearITPendingBit(EXTI_Line0);
//delayInterrupt();
}
}
我在里边写了个外部中断0的处理程序。很简单,就是先检测一下中断是否真的发生,也就是中断标志位是否挂起,然后把灯口取反,让他达到相反的状态,最后清除标志位。一定要记得清除,不然他的感觉就是一直在中断。
就这四步。非常简单。四步走即可。
————————————————————————————
1.一个中断线只能有一个中断口,意思就是如果你A0接的中断,那么你B0啥的就不能接中断,没意义。想接搞到B1上去。
2.这么多各种各样的函数名别写错
3.最后几个中断线系统内部用了,咱们别用。