目录
中断是什么
在处理事件的时候有两种方式:轮询和中断。
轮询
顾名思义,就是每轮都询问一次。比如while循环的每一次,就会执行检查,1.此处串口是否有数据到来。2.每次都检测一下引脚状态,是否为低电平。在有大量事件发生时,cpu按照事件到来的先后顺序依次执行,不考虑时间的紧急性和事件大小,也就是不考虑时间的优先级。
中断
中断也是一种对于数据获取的调度方式。通过中断源来提醒CPU,数据已经更新,可以读取新数据。给每个事件设置优先级,在有大量事件发生时,cpu按照事件的优先级率先完成紧急性事件和处理时间短的事件。
中断调用情况
CPU对于调度频次不高的任务(函数),或者特别紧急的任务(刹车制动这种) 给出的一种任务执行关系,这种关系的本质就是函数功能一旦出现,就要立即实施。这两种形式的任务一般都以中断形式调度,对于上一种任 务,优势在于提升系统运行速率,后一种提升了系统的实时性。 中断是一种芯片的内部的宝贵资源,数量是十分有限的。
中断的分类
内部资源根据硬件细节不同分出内部中断,和外部中断两种。
内部中断(TIM、UART等)
CPU内部有一个硬件结构叫做NVIC,也叫做中断管理控制器, NVIC管理着很多引脚,当特定事件发生时,会给NVIC发送一个信号,NVIC调用相应的中断函数传给CPU让其执行。
tim.c
#include "stm32f4xx.h" // Device header
#include "stdio.h"
//定时器的初始化
void Time_Init()
{
//时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//1
//参数配置,84M 84 000 000
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//3
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//4
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=(5000-1);//工作量(路程),每一趟执行一次中断
TIM_TimeBaseInitStruct.TIM_Prescaler=(8400-1);//84M除以8400=10 000,工作速度(10 000/s)
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//2
//让定时器开始工作
TIM_Cmd(TIM2,ENABLE);
//定时器开启中断,看到TIM_Period,数到头,给NVIC说一声
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//中断分组
//分组方式,2位给抢占优先级,2位给响应优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//从此处判断核心需求数量(2)
//NVIC参数配置
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStruct);
}
void TIM2_IRQHandler()
{
//信号判断,中断进一步确认
if(TIM_GetITStatus(TIM2,TIM_IT_Update))
{
printf("not apple tree!\n");
}
//中断信号清除
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
tim.h
#include "stm32f4xx.h" // Device header
void Time_Init();
外部中断EXTI
上图紫色线路为轮询机制。黑色线路部分为内部中断。红色线路部分为外部中断NVIC处理的是中断信号,不是电平信号。
为什么GPIO需要接入EXTI产生中断信号,而不直接连到NVIC上?
usart,TIM,IIC这些芯片 内部器件本身就可以产生中断信号,因此就可以直接与NVIC连接。但是,光突突的GPIO本身就是一根电线,肯定不具备产生中断信号的功能。因此连接 EXTI,依靠EXTI产生中断信号。 原因2:中断通达数量比较少,EXTI的多路复选的功能扩充了接口。一个EXTI可 以接16个GPIO引脚呢。
exti.c
#include "stm32f4xx.h" // Device header
#include "BitBand.h"
#include "stdio.h"
#include "delay.h"
void exti_key_init()
{
//时钟配置
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
//给GPIO参数配置
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_2;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
GPIO_Init(GPIOE,&GPIO_InitStruct);
//把GPIOE组的第2个引脚连接到EXTI2
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);
//把GPIOE组的第3个引脚连接到EXTI3
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);
//EXTI参数配置
//告诉EXTI2、3,看见上升沿,就给NVIC发送中断信号
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line2|EXTI_Line3;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStruct);
//分组方式,2位给抢占优先级,2位给响应优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//从此处判断核心需求数量(2)
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=EXTI2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStruct);
//分组方式,2位给抢占优先级,2位给响应优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);//从此处判断核心需求数量(2)
NVIC_InitStruct.NVIC_IRQChannel=EXTI3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStruct);
}
//中断服务子函数,给EXTI2服务
void EXTI2_IRQHandler()
{
if(EXTI_GetITStatus(EXTI_Line2))
{
printf("key2 apple tree\n");
}
EXTI_ClearITPendingBit(EXTI_Line2);
}
//中断服务子函数,给EXTI3服务
void EXTI3_IRQHandler()
{
if(EXTI_GetITStatus(EXTI_Line3))
{
printf("key3 apple tree\n");
}
EXTI_ClearITPendingBit(EXTI_Line3);
}
exti.h
#include "stm32f4xx.h" // Device header
void exti_key_init();