相关链接
理论知识
中断系统
中断: 在主程序运行过程中,出现了特定的中断触发条件(中断源), 使得CPU暂停当前正在运行的程序,转而处
理中断程序,处理完成后又返回原来被暂停的位置继续运行.
中断优先级: 当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先相应更加紧急的中断源.
中断嵌套: 当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而处理新的中断程序,处理完成后依次进行返回.
中断执行流程
中断执行流程图如下图所示:

NVIC的基本结构

NVIC优先级分组
EXTI简介
外部中断(External Interrupt)是指来自外部设备或信号的中断请求。
EXTI可以监测GPIO口的电平信号,当其指定的GPIO口电平发生变化时,EXTI将立即向NVIC发出中断申请,
经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序.
支持的触发方式有:上升沿/下降沿/双边沿/软件触发。
支持的GPIO口: 所有GPIO口均可触发外部中断但是相同的Pin不能同时触发中断(如PA0和PB0不能同时触发中断).
通道数: 16个GPIO_Pin,外加PVD输出,RTC闹钟,USB唤醒,以太网唤醒.
触发响应方式: 中断响应/事件响应(用来触发其他外设的事件).
EXTI的基本结构

- 经过AFIO选择后仅有16路GPIO口可以触发EXTI中断,所以PA0和PB0不可以同时触发中断.
- EXTI9_5和EXTI15_10需要通过标志位来区分是哪个GPIO口触发的中断.
- EXTI给其他外设的中断为事件响应
AFIO结构图如下:

通过数据选择器来将PA0~PG0选择其中一条线到EXTI0.
EXTI框图如下:

- 输入线进入边沿监测电路,选择上升沿/下降沿/双边沿触发.
- 边沿监测电路信号和软件中断事件寄存器一起进入逻辑或门
- 触发信号通过逻辑或门后分两路,上面一路触发中断,下面一路触发事件.
- 触发中断会置请求挂起寄存器, 请求挂起寄存器和中断屏蔽器一起进入逻辑与门,进入NVIC中断控制器.
- 触发事件和事件屏蔽寄存器一起进入逻辑与门,再通过脉冲发生器用来触发其他外设.
实验测试
实验目标: 使用火焰传感器监测火焰并通过OLED屏显示火焰警报
硬件连接
OLED连接
- SCK 接 PG12
- SDA 接 PD5
- RES 接 PD4
- DC 接 PD15
- CS 接 PD1
火焰传感器连接
火焰传感器
实物如图所示

资料链接 : 火焰传感器链接
传感器型号: 3针版
当火焰强度超过阈值时,输出低电平,否则输出高电平,所以需要配置为下降沿触发
程序设计
在fire.c
文件中编写如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include "stm32f10x.h" #include "stm32f10x_exti.h"
uint16_t FireState = 0;
void Fire_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line14; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); }
uint16_t FireState_Get(void) { return FireState; }
void FireState_Clear(void) { FireState = 0; }
void EXTI15_10_IRQHandler(void) { if (SET == EXTI_GetITStatus(EXTI_Line14)) { FireState = 1; EXTI_ClearITPendingBit(EXTI_Line14); } }
|
在fire.h
文件中编写如下代码
1 2 3 4 5 6 7 8 9
| #ifndef __FIRE_H #define __FIRE_H
void Fire_Init(void); uint16_t FireState_Get(void); void FireState_Clear(void);
#endif
|
在main.c
文件中编写如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include "stm32f10x.h" #include "stm32f10x_exti.h" #include "delay.h" #include "sys.h" #include "oled.h" #include "bmp.h" #include "fire.h"
int main(void) { delay_init(); OLED_Init(); Fire_Init(); while(1) { if (1 == FireState_Get()) { OLED_Clear(); OLED_ShowString(1, 1, "Fire Warning", 16); OLED_Refresh(); delay_ms(5000); FireState_Clear(); OLED_Clear(); } else if (0 == FireState_Get()) { OLED_Clear(); OLED_ShowString(1, 1, "Stand By", 16); OLED_Refresh(); delay_ms(5000); OLED_Clear(); } else { OLED_Clear(); OLED_ShowString(1, 1, "Sensor Error", 16); OLED_Refresh(); delay_ms(5000); OLED_Clear(); } } }
|