目录
1.STM32中断系统介绍
1.STM32的NVIC(嵌套向量中断控制器)有82个可屏蔽中断(可以设置优先级)和13个系统中断
2.NVIC采用4位二进制数来设置中断优先级,分为抢占优先级和次优先级两段,中断的数字越小,代表中断的优先级越高。
分段:
抢占优先级 | 次优先级 |
---|---|
0位 | 4位 |
1位 | 3位 |
2位 | 2位 |
3位 | 1位 |
4位 | 0位 |
一般只用抢占优先级。
3. (1)如果抢占优先级与次优先级相同则谁先发生谁就先执行。
(2)高抢占优先级的中断可以打断正在执行的底抢占优先级的中断函数。
(3)如果抢占优先级相同,则高次优先级的中断不能打断正在执行的底次优先级的中断函数
4. 外部中断框图
过程:首先,框图中的20是代表着有20根线,互联型产品有20根中断线(如F107),其他产品有19中断根线(如F103)。寄存器连接到总线上,受cpu控制,当我们设置中断触发类型是上升沿触发,EXTI中断线选择1时(比如选择PA1),上升沿触发选择寄存器对应位就会置 “1”,代表允许对应中断线上升沿触发,边沿检测电路检测到上升沿时就会输出高电平,经过或门输出高电平,请求挂起寄存器对应位被置1,同时由于中断屏蔽寄存器已经设置了对应中断线的中断,对应位置1,经过与门输出高电平给NVIC中断控制器,接着运行中断处理函数。对应寄存器的介绍可以查看数据手册 9.2
除此之外,事件屏蔽寄存器是外设自行控制,与边沿检测电路和上下降沿触发选择寄存器配合输出到脉冲发生器。软件中断事件寄存器是选择软件触发中断。
5. EXTI_0 - EXTI15,这16根中断线,每根中断线只能选择多个端口中的一个,不可共用。例如选择PA0为EXTI0的中断输入线,则PB0不能作为中断输入线。
6.不是所有的中断线都有自己的ISR中断函数,例如EXTI0-EXTI4,都有自己对应的中断函数EXTIx_IRQHandle,但是EXTI5-EXTI9,共用一个ISR中断函数EXTI9_5_IRQHandle,EXTI10-EXTI15,共用一个ISR中断函数EXTI15_10_IRQHandle。
7. EXTI16-EXTI22连接的是外设事件信号,这七个中断线都有自己对应的ISR中断函数。
2.STM32_HAL库中断函数
点击STM32f1xx_HAL_Cortex.h查看NVIC配置函数,这些在CubeMx中是配置好的,知道就好,标准库的话这些得自己初始化。
2.1 void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);
设置优先级组别
PriorityGroup:NVIC_PRIORITYGROUP_0 : 0bit 抢 4bit 次
NVIC_PRIORITYGROUP_1 : 1bit 抢 3bit 次
NVIC_PRIORITYGROUP_2 : 2bit 抢 2bit 次
NVIC_PRIORITYGROUP_3 : 3bit 抢 1bit 次
NVIC_PRIORITYGROUP_4 : 4bit 抢 0bit 次
2.2 void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority);
设置指定中断的抢占优先级和次优先级
IRQn :在STM32f103xb.h中有M3内核中段和外部中断,右键跳转
PreemptPriority :抢占优先级 0- 15 根据优先级组别来写
SubPriority :次优先级 0 - 15 根据优先级组别来写
2.3 void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
使能指定中断
IRQn :在STM32f103xb.h中有M3内核中段和外部中断,右键跳转
2.4 void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);
失能指定中断
IRQn :在STM32f103xb.h中有M3内核中段和外部中断,右键跳转
2.5 void HAL_NVIC_SystemReset(void);
复位mcu
2.6 uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
初始化系统定时器及其中断,并启动系统滴答定时器,用于初始化
TicksNumb:中断间隔,中断触发时间
一般:HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)
SystemCoreClock :系统时钟 比如72MHZ uwTickFreq :中断间隔 比如 1 = 1ms
该函数在HAL_Init()中和SystemClock_Config()都初始化过,但是要注意,在SystemClock_Config中才是最终确定的SystemClock的中断间隔。
具体看:【STM32】HAL库-系统滴答定时器SysTick_systick hal-CSDN博客
点开stm32f1xx_hal_gpio.h可以查看与外部中断有关的函数,这些CubeMx自己配置好了,可以不用管,了解功能即可。
#define __HAL_GPIO_EXTI_GET_FLAG(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))
宏定义函数,该函数是检查是否设置了指定的EXTI行标志。
__EXTI_LINE__:GPIO_PIN_x x:(0-15)
#define __HAL_GPIO_EXTI_CLEAR_FLAG(__EXTI_LINE__) (EXTI->PR = (__EXTI_LINE__))
宏定义函数,清除EXTI的行挂起标志 , 在ISR中断函数中用该函数清除挂起标志位(就是上面框图中的请求挂起寄存器的标志位)
__EXTI_LINE__:GPIO_PIN_x x:(0-15)
#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))与
#define __HAL_GPIO_EXTI_CLEAR_IT(__EXTI_LINE__) (EXTI->PR = (__EXTI_LINE__))
与上面的两个函数功能相同。
最后:
#define __HAL_GPIO_EXTI_GENERATE_SWIT(__EXTI_LINE__) (EXTI->SWIER |= (__EXTI_LINE__))
宏定义函数,在选定的EXTI行上生成软件中断 ,就是开启软件中断,很少用。
__EXTI_LINE__:GPIO_PIN_x x:(0-15)
最后:打开stm32f1xx_hal_gpio.h这两个是比较重要的函数,其实就是一个函数。
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
这个函数用到了上面的两个宏定义函数一个是判断是否触发外部中断,一个是清楚挂起标志位。然后进入HAL_GPIO_EXTI_Callback(GPIO_Pin)这个函数,也就是第二个函数。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);---中断回调函数
这个函数是一个_weak弱函数,所以可以自己重新写一个一样的函数,就只是把_weak去掉,然后自己写中断函数的内容。
配置完CubeMX后要做的就是写这个中断函数内容。
3.CubeMX配置及应用
实验:使用按键来控制led灯的亮灭:
使用PB0作为KEY,使用PC13作为LED,时钟选择HSE
注意:如果使用swd进行调试下载,千万别忘了把Debug选择swd,否则将没配置SWD的程序下进去后再次下载就会找不到下载器了,真遇到这种情况时,如果自己的板子上留出了Boot0和Boot1的引脚,用跳帽将Boot0置1再下载:
点击NVIC修改优先级:
这里把系统时钟的优先级调高了,因为中断中要使用延时函数,不调高的话会卡死。
GPIO配置根据自己的硬件来:
时钟树选择72MHZ:
点击生成代码。
提示:如果想基于自己上次的工程模板创建CubeMX工程,可以点击该选项,新创建文件夹修改一下名字即可。
打开keil后,找到stm32f1xx_it.c打开
找到:
打开HAL_GPIO_EXTI_IRQHandler(KEY1_Pin) 函数中已经写好了清楚标志,所以只写中断内容就好了。
所以找个位置把HAL_GPIO_EXTI_Callback(GPIO_Pin)再写一遍就好了
我选择了在gpio.c中复写。
这样按键按下一次led就会改变一次状态 ,一直按着不变。