异常类型
系统异常(体现在内核)
外部中断(体现在外设)
NVIC简介
NVIC是嵌套向量中断控制器,属于内核外设,
优先级的定义
中断编程
1.使能中断请求
先配置外设的使能中断请求位,再配置NVIC的中断使能寄存器。
比须两个都使能,才能顺利地收到外设的中断请求。
2.配置中断优先级分组
3.配置NVIC寄存器,初始化NVIC_InitTypeDef
- 指定中断源
- 配置抢占优先级
- 配置子优先级
- 配置NVIC中断使能信号
4.编写中断服务函数
中断服务函数名
与启动文件中定义的中断服务函数名相同
中断服务函数位置
为了便于管理,中断服务函数全部放在stm32f10x_it.c文件中
EXTI简介
(External interrupt/event controller)外部中断/事件控制器,当GPIO电平发生跳变时,由EXTI来产生中断,再交给NVIC。
我们先来看EXTI框图,从框图的右下角可以看到一个输入线,中断就是从输入线进入EXTI的。
输入线总共有多少?
通过图中可以看到,输入线一共有20根,所以共由20个中断输入源,每一条输入线可以对应很多个端口
EXTI具体寄存器配置
通过配置EXTI上升沿或者下降沿触发选择寄存器,边缘检测电路就会对上升沿或下降沿进行检测,并输入1,
编程要点
初始化要连接到EXTI的GPIO
void GPIO_LED_Config()
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_IOPBEN, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
}
void GPIO_KEY1_Config()
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_IOPAEN, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
GPIO的初始化没什么好讲的,已经写过很多次了
初始化EXTI用于产生中断/事件
void EXTI_Config()
{
EXTI_InitTypeDef EXTI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_AFIOEN, ENABLE); // 在配置EXTI使能信号时,我没有在结构体中找到EXTI,只找到AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);//选择中断输入线
EXTI_InitStruct.EXTI_Line = EXTI_Line0; // 中断/事件线
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//配置模式为中断
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;//配置触发方式
EXTI_InitStruct.EXTI_LineCmd = ENABLE;//使能中断线
EXTI_Init(&EXTI_InitStruct);
}
在初始化EXTI时,往往容易漏掉选择中断输入线,这个需要额外注意。
其余配置与GPIO的配置流程差不多,定义结构体变量,对结构体内的属性进行赋值就行了。
初始化NVIC,用于处理中断
// 初始化完EXTI后,初始化NVIC
void NVIC_Config()
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//中断分组容易漏掉
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // 配置中断源
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;//配置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;//配置子优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能中断源
NVIC_Init(&NVIC_InitStruct);
}
编写中断服务函数
void EXTI0_IRQHandler()
{
if (EXTI_GetITStatus(EXTI_Line0) != RESET)//当中断线中发生中断
{
//LED灯状态翻转,由亮转灭、由灭转亮
if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
GPIO_SetBits(GPIOB, GPIO_Pin_1);
}
else
{
GPIO_ResetBits(GPIOB, GPIO_Pin_1);
}
}
EXTI_ClearITPendingBit(EXTI_Line0);//清楚中断线的中断状态
}
中断服务函数需要写在stm32f10x_it.c文件中,并且函数名需要与启动文件中定义的中断名称一致。
main函数
int main()
{
GPIO_LED_Config();
GPIO_KEY1_Config();
EXTI_Config();
NVIC_Config();
}
在main函数中,只需要对上面几个函数进行调用就行了