中断框图
一.中断
中断:当有中断请求时,CPU会停止处理当前的任务,转而去处理中断任务。
中断输入线有19/20根(互联型号20根)。
分类:系统异常(10个)和外部中断(60个)
F103 系统异常清单
二.NVIC
中断,我们首先要了解NVIC(嵌套向量中断控制器) 。
属于内核中的外设,控制着整个芯片中断相关的功能。比较主优先级和子优先级,谁的数字小谁的优先级越高,若主优先级和子优先级都相同,则比较硬件中断编号。
1.寄存器
在配置中断的时候我们一般只用 ISER、ICER 和 IP 这三个寄存器,ISER 用来使能中断,ICER 用 来失能中断,IP 用来设置中断优先级。
固件库文件 core_cm3.h 的固件库函数一般不用。
2.优先级
<1>定义
NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx,用来配置外部中断的优先级,IPR 宽度为 8bit,在 F103 中,只使用了高 4bit。
用于表达优先级的这 4bit,又被分组成抢占优先级和子优先级。
<2>分组
设置优先级分组可调用库函数 NVIC_PriorityGroupConfig() 实现,有关 NVIC 中断相关的库函数都在库文件 misc.c 和 misc.h 中。
3.中断编程逻辑
- 使能外设某个中断;
- 初始化 NVIC_InitTypeDef 结构体(在misc.h中),配置中断优先级分组,设置抢占优先级和子优先级,使能中断请求。
- 编写中断服务函数。
a.NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样;
b. NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定,具体参考表格优先级分组真值表 优先级分组真值表。
c. NVIC_IRQChannelSubPriority:子优先级,具体的值要根据优先级分组来确定,具体参考表格优先级分组真值表 优先级分组真值表。
d. NVIC_IRQChannelCmd:中断使能(ENABLE)或者失能(DISABLE)。操作的是 NVIC_ISER和 NVIC_ICER 这两个寄存器。
注:中断服务函数,可以理解为中断时CPU要处理的任务。函数名称都在启动文件中,为方便管理一般都会写在it.c里面。
注意:NVIC_PriorityGroupConfig 是整个程序中只需要设置一次。
三.EXTI---外部中断/事件控制器
1.简介
管理了控制器的 20 个中断/事件线。可以实现输入信号的上升沿检测和下降沿的检测,挂载到APB2总线。
中断和事件的区别:
产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
2.中断/事件线
EXTI 有 20 个中断/事件线,每个 GPIO 都可以被设置为输入线。
3.EXTI初始化结构体(stm32f10x_exti.h )
A.EXTI_Line:EXTI 中断/事件线选择,可选 EXTI0 至 EXTI19,可参考表 EXTI 中断 _ 事件线选择。
B. EXTI_Mode:EXTI 模式选择,可选为产生中断 (EXTI_Mode_Interrupt) 或者产生事件 (EXTI_Mode_Event)。
C. EXTI_Trigger:EXTI 边沿触发事件,可选上升沿触发 (EXTI_Trigger_Rising)、下降沿触发 ( EXTI_Trigger_Falling) 或者上升沿和下降沿都触发 ( EXTI_Trigger_Rising_Falling)。
D. EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线 (ENABLE) 或禁用 (DISABLE)。
4.EXTI编程步骤
- 初始化要连接到EXTI的GPIO;
- 初始化EXTI用于产生中断/事件;
- 初始化NVIC,用于处理中断;
- 编写中断服务函数;
- 编写main函数。
注意:NVIC的中断源(IRQ_Channel):中大容量EXTI4_IRQN以上应注意,使用EXTI9-5_IRQN或者EXTI15-10_IRQN。
四.中断实验
按键控制LED的亮灭
exti.c
#include "exti.h"/*** @brief 配置嵌套向量中断控制器NVIC* @param 无* @retval 无*/
static void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;/* 配置NVIC为优先级组1 *//* 提示 NVIC_PriorityGroupConfig() 在整个工程只需要调用一次来配置优先级分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置中断源:按键1 */NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;/* 配置抢占优先级 */NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/* 配置子优先级 */NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;/* 使能中断通道 */NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}/*** @brief 配置 IO为EXTI中断口,并设置中断优先级* @param 无* @retval 无*/
void EXTI_Key_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure;/*开启按键GPIO口的时钟*/RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);/* 配置 NVIC 中断*/NVIC_Configuration();/*--------------------------KEY1配置-----------------------------*//* 选择按键用到的GPIO */ GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;/* 配置为浮空输入 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);/* 选择EXTI的信号源 */GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE); EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;/* EXTI为中断模式 */EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/* 上升沿中断 */EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;/* 使能中断 */ EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
}
exti.h
#ifndef _EXTI_H
#define _EXTI_H#include "stm32f10x.h"//引脚定义
#define KEY1_INT_GPIO_PORT GPIOB
#define KEY1_INT_GPIO_CLK (RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN GPIO_Pin_1
#define KEY1_INT_EXTI_PORTSOURCE GPIO_PortSourceGPIOB
#define KEY1_INT_EXTI_PINSOURCE GPIO_PinSource1
#define KEY1_INT_EXTI_LINE EXTI_Line1
#define KEY1_INT_EXTI_IRQ EXTI1_IRQn#define KEY1_IRQHandler EXTI1_IRQHandlervoid EXTI_Key_Init(void);//注意:这几个中断参数需一致#endif
led.c
#include "led.h"/*** @brief 初始化控制LED的IO* @param 无* @retval 无*/
void led_gpio_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(LED0_GPIO_CLK,ENABLE);//注意需要用到的总线GPIO_InitStruct.GPIO_Pin = LED0_GPIO_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(LED0_GPIO_PORT,&GPIO_InitStruct);GPIO_ResetBits(LED0_GPIO_PORT,LED0_GPIO_PIN);
}
led.h
#ifndef _LED_H
#define _LED_H#include "stm32f10x.h"#define LED0_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED0_GPIO_PORT GPIOB
#define LED0_GPIO_PIN GPIO_Pin_5/******************************************************************************************/
/* LED端口定义 */
#define LED0(x) do{ x ? \GPIO_SetBits(LED0_GPIO_PORT, LED0_GPIO_PIN) : \GPIO_ResetBits(LED0_GPIO_PORT, LED0_GPIO_PIN); \}while(0) /* LED0翻转 */#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态#define LED0_Toggle digitalToggle(LED0_GPIO_PORT,LED0_GPIO_PIN)void led_gpio_Init(void);#endif
stm32f10x_it.c
/********************************************************************************* @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c * @author MCD Application Team* @version V3.6.0* @date 20-September-2021* @brief Main Interrupt Service Routines.* This file provides template for all exceptions handler and * peripherals interrupt service routine.******************************************************************************* @attention** Copyright (c) 2011 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************//* Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"
#include "led.h"
#include "exti.h"/** @addtogroup STM32F10x_StdPeriph_Template* @{*//* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*//******************************************************************************/
/* Cortex-M3 Processor Exceptions Handlers */
/******************************************************************************//*** @brief This function handles NMI exception.* @param None* @retval None*/
void NMI_Handler(void)
{
}/*** @brief This function handles Hard Fault exception.* @param None* @retval None*/
void HardFault_Handler(void)
{/* Go to infinite loop when Hard Fault exception occurs */while (1){}
}/*** @brief This function handles Memory Manage exception.* @param None* @retval None*/
void MemManage_Handler(void)
{/* Go to infinite loop when Memory Manage exception occurs */while (1){}
}/*** @brief This function handles Bus Fault exception.* @param None* @retval None*/
void BusFault_Handler(void)
{/* Go to infinite loop when Bus Fault exception occurs */while (1){}
}/*** @brief This function handles Usage Fault exception.* @param None* @retval None*/
void UsageFault_Handler(void)
{/* Go to infinite loop when Usage Fault exception occurs */while (1){}
}/*** @brief This function handles SVCall exception.* @param None* @retval None*/
void SVC_Handler(void)
{
}/*** @brief This function handles Debug Monitor exception.* @param None* @retval None*/
void DebugMon_Handler(void)
{
}/*** @brief This function handles PendSVC exception.* @param None* @retval None*/
void PendSV_Handler(void)
{
}/*** @brief This function handles SysTick Handler.* @param None* @retval None*/
void SysTick_Handler(void)
{
}void KEY1_IRQHandler(void)
{//确保是否产生了EXTI Line中断if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {// LED1 取反 LED0_Toggle;//清除中断标志位EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); }
}/******************************************************************************/
/* STM32F10x Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f10x_xx.s). */
/******************************************************************************//*** @brief This function handles PPP interrupt request.* @param None* @retval None*/
/*void PPP_IRQHandler(void)
{
}*//*** @}*/
main.c
#include "stm32f10x.h"
#include "led.h"
#include "exti.h"int main()
{led_gpio_Init();/* 初始化EXTI中断,按下按键会触发中断,* 触发中断会进入stm32f4xx_it.c文件中的函数* KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯。*/EXTI_Key_Init();/* 等待中断,由于使用中断方式,CPU不用轮询按键 */while(1){}
}