一. 外部中断/事件控制器 (EXTI)
什么是中断?中断就是打断程序执行顺序的外部输入
什么是事件?事件是外部输入会触发的事件.比如唤醒
EXTI是专门控制外部中断/事件的控制器
简单来讲
- EXTI有20根外部输入线, 这20根外部中断线可以选择特定的一个输入源给EXTI输入中断信号(见下图)
- EXTI能设定是中断还是事件
- EXTI能控制是上升沿还是下降沿触发
- 并能使能/失能
关于20根输入线:
二. 初始化 EXTI控制器 //EXTI_Init()
使用EXTI要先用RCC初始化 APB2上的AFIO
//开启EXTI时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
我们可以调用进行初始化
这里我们看到一个结构体: EXTI_InitTypeDef
- EXTI_InitTypeDef的第一个参数: EXTI_Line
- EXTI_InitTypeDef的第二个参数: EXTI_Mode
- EXTI_InitTypeDef的第三个参数:EXTI_Trigger
- EXTI_InitTypeDef的第四个参数:EXTI_LineCmd
可选 ENABLE / DISABLE
三. GPIO引脚配置 GPIO_EXTILineConfig()
上面的函数EXTI_Init()针对特定中断线进行了初始化
如何选择特定的GPIO引脚作为中断线输入呢?
四. 按键中断全过程
- 开GPIO时钟
- 初始化GPIO
- 将GPIO管脚与EXTI建立输入线
- 开EXTI时钟
- 初始化EXTI
- 选择的NVIC的解析政策 NVIC_PriorityGroupConfig()
- 初始化NVIC来接收EXTI传来的中断
- 写中断服务函数(在服务函数中要重置中断)
- 写main函数调用初始化函数
接下来是一个完整的按键中断的例子
建立一个psb_exti.h
和一个psb_exti.c
存放exti相关的内容
psb_exti.h
#ifndef __PSB_EXTI_H
#define __PSB_EXTI_H
#include "stm32f10x.h"
#define K1_GPIO GPIOA
#define K1_GPIO_Pin GPIO_Pin_0
#define K1_GPIO_CLK RCC_APB2Periph_GPIOA
#define K1_EXTI_PortSource GPIO_PortSourceGPIOA
#define K1_EXTI_PinSource GPIO_PinSource0
#define K1_EXTI_Line EXTI_Line0
void KEY1_IRQ_Init(void);
#endif /*__PSB_EXTI_H*/
psb_exti.c.
#include "psb_exti.h"
static void EXTI_NVIC_Config(void) //加static是为了此方法限定本文件使用
{
NVIC_InitTypeDef NVIC_InitStruct; //创建结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //优先级分组政策选择中断组1
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; //中断源选择: EXTI的0号线中断
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//主优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 7;//次优先级
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE; //使能
NVIC_Init(&NVIC_InitStruct); //初始化
}
void KEY1_IRQ_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct_K1; //创建一个GPIO_InitTypeDef类型的数据
EXTI_InitTypeDef EXTI_InitStruct; //创建一个EXTI_InitTypeDef类型的数据
//初始化EXTI的中断优先级
EXTI_NVIC_Config();
//GPIO开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIO时钟
//初始化GPIO
GPIO_InitStruct_K1.GPIO_Pin = K1_GPIO_Pin; //给这个数据的参数赋值
GPIO_InitStruct_K1.GPIO_Mode = GPIO_Mode_IN_FLOATING;//给这个数据的参数赋值
GPIO_InitStruct_K1.GPIO_Speed = GPIO_Speed_50MHz;//给这个数据的参数赋值
GPIO_Init(K1_GPIO, &GPIO_InitStruct_K1);//初始化外设GPIOx寄存器
//将KEY1的GPIO管脚与EXTI连起来
GPIO_EXTILineConfig(K1_EXTI_PortSource, K1_EXTI_PinSource);// 将KEY1的GPIO管脚与EXTI连起来
//开启EXTI时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//初始化EXTI的输入线
EXTI_InitStruct.EXTI_Line = K1_EXTI_Line;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(& EXTI_InitStruct);
}
stm32f10x_it.c
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
LED_G_TOOGLE
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
main.c