上一节学会配置NVIC,以及NVIC分组后,这一节继续看中断的一部分,(芯片)外部中断/事件
一. 中断和事件
1. 先说什么是外部?指的是Air32F103芯片的外部,与之相对应的内部中断是例如定时器TIM,这个是芯片以内,内核以外的外设。
2. 中断和事件的区别是什么?
- 中断Interrupt:触发后会引起芯片内部的中断NVIC,进而调取中断函数执行
- 事件Event:触发后会在GPIO生成脉冲信号
因为中断和事件的不同控制线,所以后面会分别有与之对应的寄存器用来使能它们。
注意:EXTI在时钟APB2上!!!记得开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
二. 外部中断/事件控制器 - EXTI - External interrupt/event controller)
有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求。
中断/事件线EXTI | 输入源 |
EXTI0 | Px0 (x可为ABCDEFG) |
EXTI1 | Px1 (x可为ABCDEFG) |
EXTI2 | Px2 (x可为ABCDEFG) |
EXTI3 | Px3 (x可为ABCDEFG) |
EXTI4 | Px4 (x可为ABCDEFG) |
EXTI5 | Px5 (x可为ABCDEFG) |
EXTI6 | Px6 (x可为ABCDEFG) |
EXTI7 | Px7 (x可为ABCDEFG) |
EXTI8 | Px8 (x可为ABCDEFG) |
EXTI9 | Px9 (x可为ABCDEFG) |
EXTI10 | Px10 (x可为ABCDEFG) |
EXTI11 | Px11 (x可为ABCDEFG) |
EXTI12 | Px12 (x可为ABCDEFG) |
EXTI13 | Px13 (x可为ABCDEFG) |
EXTI14 | Px14 (x可为ABCDEFG) |
EXTI15 | Px15 (x可为ABCDEFG) |
EXTI16 | 连接到PVD输出 |
EXTI17 | 连接到RTC闹钟事件 |
EXTI18 | 连接到USB唤醒事件 |
所有19个中断/事件线(0-18)都在这里了。STM32有20个,互联型产品多了个EXTI20,以太网唤醒事件。
想要使能对应的中断线,要配置AFIO_EXTICRx(x为0-4),EXTIy(y为0-15),对应GPIO的16个IO口,
[15:12] | [11:8] | [7:4] | [3:0] | |
AFIO_EXTICR1 | EXTI3 | EXTI2 | EXTI1 | EXTI0 |
AFIO_EXTICR2 | EXTI7 | EXTI6 | EXTI5 | EXTI4 |
AFIO_EXTICR3 | EXTI11 | EXTI10 | EXTI9 | EXTI8 |
AFIO_EXTICR4 | EXTI15 | EXTI14 | EXTI13 | EXTI12 |
EXTIy的值4位bit,可以决定是哪个GPIO
0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 |
PA[y] | PB[y] | PC[y] | PD[y] | PE[y] | PF[y] | PG[y] |
例如我要使用PB4:
我要找到AFIO_EXTICR2中的EXTI4(bit[3:0]),把它配置成0001
外部通用IO中断镜像:
三. 外部中断信号流向(重要)
EXTI0-15的信号流示意图为
1. 输入线:外部GPIO信号流入
2. 边沿检测电路:2选1,上升沿触发还是下降沿触发
3. 软件中断事件存储器:1个或门,接收来自
- 2号边沿检测线路的信号,
- 软件中断时间寄存器的信号,写1,将EXTI_PR对应的中断挂起位值1;注:清EXTI_PR挂起位时,也将相应清除EXTI_SWIER的对应位为0;改变边沿极性也能清0
与门的好处是有1为1,无论边沿有信号还是EXTI_SWIER有1,都将传递到下一步。
外部中断事件部分 :
4. 与门,上一步3号的信号,和EXTI_EMR的结果做与操作,两个都是1后,进入脉冲发生器5.
5. 脉冲发生器产生脉冲信号6。脉冲发生器产生的信号主要用于内部TIM或者ADC触发使用!
内部中断部分:
4. 与门,上一步3号的信号,和EXTI_IMR的结果做与操作,两个都是1后,进入NVIC控制器。并把EXTI_PR置1
5. 进入内部中断函数。我们这次用中断实验。
总结:外部信号可触发内部中断(如中断函数)和外部中断事件(如脉冲),关键在于EXTI_IMR和EMR的配置。
四. 标准库函数设置:
实验:PA0管脚接地后产生中断(IMR相关!!!),熄灭LED。
和事件无关!!!
1. 初始化IO口
2. 开时钟
3. 设置EXTI外部中断
相关库函数文件air32f10x.c air32f10x.h
主要看下设置外部中断的库函数:
void EXTI_DeInit(void); - Deinitializes the EXTI peripheral registers to their default reset values. 将EXTI外设寄存器初始化为其默认重置值
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); - Initializes the EXTI peripheral according to the specified parameters in the EXTI_InitStruct.根据EXTI_InitStruct中指定的参数初始化EXTI外设。初始化EXTI结构体,并将参数写入寄存器,常用*
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct); - Fills each EXTI_InitStruct member with its reset value.用重置值填充每个EXTI_InitStruct成员。只填充了结构体,还没有将参数写入到寄存器中(xxx_Init)
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line); - Generates a Software interrupt.产生一个软件中断 。 可以通过软件程序手动产生中断信号,手动开启中断,非常方便。
成对使用的中断标志位检测和中断标志位清除函数
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line); - Checks whether the specified EXTI line flag is set or not 检查是否设置了指定的EXTI行标志
void EXTI_ClearFlag(uint32_t EXTI_Line); - Clears the EXTI's line pending flags. 清除EXTI的行挂起标志。
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line); - Checks whether the specified EXTI line is asserted or not.检查指定的EXTI行是否被断言
void EXTI_ClearITPendingBit(uint32_t EXTI_Line); - Clears the EXTI's line pending bits.清除EXTI的行挂起位。
对比发现 EXTI_GetFlagStatus 和 EXTI_GetITStatus 相比
EXTI_GetITStatus判断是否发生中断的判断条件多了1个:
(EXTI->IMR & EXTI_Line) != (uint32_t)RESET
即验证了是否使能了中断。而EXTI_GetFlagStatus不检查。所以后续我们使用中断函数时,进入函数后,要使用GetITStatus来检查中断是否发生。如果我们没有开启中断使能IMR对应位没有置1,EXTI_GetFlagStatus也会返回SET。。。。
PA0按键GPIO初始化。结构体赋值,开时钟APB2->GPIOA。
void KEY_Config(void)
{
GPIO_InitTypeDef GPIO_InitiateStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitiateStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitiateStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitiateStructure);
}
EXTI配置,结构体赋值,开时钟APB2->AFIO
void EXTI_Config(void)
{
EXTI_InitTypeDef EXTI_IntiateStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
EXTI_IntiateStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_IntiateStructure.EXTI_Line = EXTI_Line0;
EXTI_IntiateStructure.EXTI_Trigger =EXTI_Trigger_Rising ;
EXTI_IntiateStructure.EXTI_LineCmd =ENABLE ;
EXTI_Init(&EXTI_IntiateStructure);
}