一.EXTI模块简介
EXTI模块也是单片机上的片上外设
GPIO模块和EXTI模块的关系
EXTI检测是电压的变化(上升沿和下降沿),不检测电压的高低
当电压发生变化时会被EXTI模块捕捉——>EXTI模块向外产生中断(中断中有对输入信号的处理函数)
总结:EXTI模块是捕捉输入信号的变化,并产生中断
二.EXTI应用举例
灯的亮灭状态,按钮按下不变,松开按钮才切换。
在过去如何捕捉按钮变化的瞬间:按钮按下时,GPIO引脚上电压由高(板载LED初始为高电压)变低(按钮按下时,GPIO接地,变为低电压)。这种可以通过while循环实现,把按钮上次的值记录在变量previous中,把按钮当前的值记录在变量current中,当两个变量不相同时,按钮状态发生改变。previous=1,current=0时,按钮按下;previous=0,current=1时,按钮松开。
EXTI:捕捉电压变化,产生中断,在中断函数中切换LED的亮灭状态
三.线的概念
在EXTI线x里共有20条,
GPIO引脚可以通过最多16条线产生16种不同的中断信号
四.线的内部
硬件触发需要电压变化
软件触发只需往对应位置写0/1
五.EXTI按钮实验
1.接线图
2.初始化板载LED,初始化按钮
void App_LED_Init(void); void App_Button_Init(void); void App_LED_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitTypeDef GPIO_LED; GPIO_LED.GPIO_Pin=GPIO_Pin_13; GPIO_LED.GPIO_Mode=GPIO_Mode_Out_OD; GPIO_LED.GPIO_Speed=GPIO_Speed_2MHz; GPIO_Init(GPIOC,&GPIO_LED); GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); } void App_Button_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_Button; //PA5 GPIO_Button.GPIO_Pin=GPIO_Pin_5; GPIO_Button.GPIO_Mode=GPIO_Mode_IPU; GPIO_Init(GPIOC,&GPIO_Button); //PA6 GPIO_Button.GPIO_Pin=GPIO_Pin_6; GPIO_Button.GPIO_Mode=GPIO_Mode_IPU; GPIO_Init(GPIOC,&GPIO_Button); // 开启AFIO的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 线5选择端口A GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5); // 线6选择端口A GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6); }3.分配EXTI线
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, // 端口号 // GPIO_PortSourceGPIOA, GPIO_PortSourceGPIOB // GPIO_PortSourceGPIOC, GPIO_PortSourceGPIOD uint8_t GPIO_PinSource); // 线编号 // GPIO_PinSource0 ~ GPIO_PinSource15// 开启AFIO的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 线5选择端口A GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5); // 线6选择端口A GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);4.配置EXTI线参数
void App_EXIT(void); void App_EXIT(void) { //EXTI_Line5 EXTI_InitTypeDef EXTI_LED; EXTI_LED.EXTI_Line=EXTI_Line_5; EXTI_LED.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_LED.EXTI_Trigger=EXTI_Trigger_Rising; EXTI_LED.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_LED); //EXTI_Line6 EXTI_InitTypeDef EXTI_LED; EXTI_LED.EXTI_Line=EXTI_Line_6; EXTI_LED.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_LED.EXTI_Trigger=EXTI_Trigger_Rising; EXTI_LED.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_LED); }5.配置NVIC模块
先中断分组(放在最前面)
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置中断分组 App_LED_Init(); App_Button_Init(); App_EXIT(); while(1) { } }再配置中断
查询中断名称
打开头文件--Ctrl+F 打开检索--查找eunm IRQn--在枚举里找到对应中断的名称
//配置中断 NVIC_InitTypeDef NVIC_LED; NVIC_LED.NVIC_IRQChannel=EXTI9_5_IRQn;//中断名称 NVIC_LED.NVIC_IRQChannelPreemptionPriority=0;//中断优先级 NVIC_LED.NVIC_IRQChannelSubPriority=0;//中断子优先级 NVIC_LED.NVIC_IRQChannelCmd=ENABLE;//闭合开关 NVIC_Init(&NVIC_LED);6.编译中断响应函数
通过判断EXTI线标志位的值判断那条线触发中断
清除标志位:向图红圈位置标志位写0(因为触发后为1)
void EXTI9_5_IRQHandler(void){ if(EXTI_GetFlagStatus(EXTI_Line5) == SET) { // 线5触发的中断 EXTI_ClearFlag(EXTI_Line5); // 清除中断标志位 GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET); // 亮灯 } if(EXTI_GetFlagStatus(EXTI_Line6) == SET) { // 线6触发的中断 EXTI_ClearFlag(EXTI_Line6); // 清除中断标志位 GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET); // 灭灯 } }#include "stm32f10x.h" void App_LED_Init(void); void App_Button_Init(void); void App_EXIT(void); int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置中断分组 App_LED_Init(); App_Button_Init(); App_EXIT(); while(1) { } } void App_LED_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitTypeDef GPIO_LED; GPIO_LED.GPIO_Pin=GPIO_Pin_13; GPIO_LED.GPIO_Mode=GPIO_Mode_Out_OD; GPIO_LED.GPIO_Speed=GPIO_Speed_2MHz; GPIO_Init(GPIOC,&GPIO_LED); GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); } void App_Button_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_Button; //PA5 GPIO_Button.GPIO_Pin=GPIO_Pin_5; GPIO_Button.GPIO_Mode=GPIO_Mode_IPU; GPIO_Init(GPIOC,&GPIO_Button); //PA6 GPIO_Button.GPIO_Pin=GPIO_Pin_6; GPIO_Button.GPIO_Mode=GPIO_Mode_IPU; GPIO_Init(GPIOC,&GPIO_Button); // 开启AFIO的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 线5选择端口A GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5); // 线6选择端口A GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6); } void App_EXIT(void) { //EXTI_Line5 EXTI_InitTypeDef EXTI_LED; EXTI_LED.EXTI_Line=EXTI_Line5; EXTI_LED.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_LED.EXTI_Trigger=EXTI_Trigger_Rising; EXTI_LED.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_LED); //EXTI_Line6 EXTI_LED.EXTI_Line=EXTI_Line6; EXTI_LED.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_LED.EXTI_Trigger=EXTI_Trigger_Rising; EXTI_LED.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_LED); //配置中断 NVIC_InitTypeDef NVIC_LED; NVIC_LED.NVIC_IRQChannel=EXTI9_5_IRQn; NVIC_LED.NVIC_IRQChannelPreemptionPriority=0; NVIC_LED.NVIC_IRQChannelSubPriority=0; NVIC_LED.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_LED); } void EXTI9_5_IRQHandler(void){ if(EXTI_GetFlagStatus(EXTI_Line5) == SET) { // 线5触发的中断 EXTI_ClearFlag(EXTI_Line5); // 清除中断标志位 GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET); // 亮灯 } if(EXTI_GetFlagStatus(EXTI_Line6) == SET) { // 线6触发的中断 EXTI_ClearFlag(EXTI_Line6); // 清除中断标志位 GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET); // 灭灯 } }