嵌入式-EXTI的工作原理和按钮实验-Day19
一、EXTI的工作原理
1.EXTI模块简介
简单就说就是用来捕捉信号的变化(信号的上升(沿)或者下降(沿))并输出中断
2.EXTI应用举例
前面DAY15做了一个按钮实验,那里因为我们专门要实现当按钮松开的时候实现灯的亮/灭,那里使用的是时刻判断两个变量是否不相等,不相等表明电压变化了,并且电压如果是高电压表示当前按钮松开了(变量分别记录之前的电压和当前的电压)
这里可以很方便的使用EXTI去判断是否是上升沿,是的话就直接产生中断然后在中断响应函数里面编写函数就行,就不用前面那么麻烦了

3.线的概念
4.线的内部结构
简单来看就是左边有一个AFIO的复用器,就是用来把EXTI的每个线分配给某个GPIOx
之后经过边沿检测电路(就是用来检测是上升沿还是下降沿),之后有三条路,上声沿到开关再到中断,还有下降沿类似,以及还有一个是双(只要是变化的,即但凡有一个是上升或者下降的就产生中断)
注意:这个中断也可以使用软件方式来控制,即代码输出1使其产生中断
二、按钮实验
1.实验目的
按左边的按钮实线点亮,右边的按钮实现熄灭
2.搭建电路

3.初始化板载LED和按钮
板载LED就是初始化为输出开漏
按钮的话就是初始化两按钮对应的引脚都为输入上拉
4.给EXTI线分配输入的引脚(即信号是从哪传进来的)
就是使用复用器(前面学过是用来复用映射的),为当前的EXTI的线分配GPIOx,以及选择GPIO的某条引脚与其连接

4.配置EXTI线的模块
因为是有两按钮,即单片机外面传输进行的信号有两个渠道,所以说需要分配两条EXTI的线

5.配置NVIC下的中断
这里唯一一个值得注意的是,线五和线六同属于一个中断,所以不用配置两个中断,一个就行了。
首先,注意这个NVIC这个片上外设比较特殊,他中断开关的配置是在自身的定义里面,不像前面的USART一样要专门闭合中断的开关,所以这里直接就配置NVIC就行(即规则+抢占和子优先级的值+闭合NVIC的开关)
6.编写中断响应函数
这里需要判断你这个中断是哪个线触发的,所以使用下面的标志位去判断。
还有一件事,使用完中断后一定要关闭,即clear,因为他两共用一个中断(前面提到过),你触发了,别人也想要触发啊,你触发不关闭,就导致这个中断独属于你,别人用不了。
举例:那假设这个属于线5的中断一直开着,那就是你不管按啥按钮,虽然都触发了中断,但是因为线5导致中断响应,既而引起了亮灯,但是你没关中断,就导致你这个if判断下的标志位(线5产生的中断==1)是一直成立的,所以两按钮不管按哪个都是亮的
7.代码
#include "stm32f10x.h"
#include "Delay.h"void My_BoardLed_Init(void);
void My_USART_Init(void);
uint16_t adjustDelay=100;
void USART1_IRQHandler(void);
void App_Button_Init(void);
void EXTI9_5_IRQHandler(void);//实验目的,两按钮分别在松开的时候实现灯的亮/灭int main(void)
{//首先就是配置中断的时候标志的中断规则NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//初始化亮灯My_BoardLed_Init();//初始化两个按钮App_Button_Init();while(1){GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);Delay(adjustDelay);GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);Delay(adjustDelay);}
}void App_Button_Init(){//首先使用按钮的初始化封装函数来实现RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStruct={0};GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;GPIO_Init(GPIOC,&GPIO_InitStruct);GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;GPIO_Init(GPIOC,&GPIO_InitStruct);//初始化后当按钮按下,信号传输进来,此时也要传输到EXTI线上//所以配置EXTI//首先给EXTI的两条线复用分配输入的引脚//启用复用AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);//分配完后,初始化EXTIEXTI_InitTypeDef EXTI_InitStruct={0};EXTI_InitStruct.EXTI_Line=EXTI_Line5;EXTI_InitStruct.EXTI_LineCmd=ENABLE;EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Rising;EXTI_Init(&EXTI_InitStruct);EXTI_InitStruct.EXTI_Line=EXTI_Line6;EXTI_InitStruct.EXTI_LineCmd=ENABLE;EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Rising;EXTI_Init(&EXTI_InitStruct);//配置中断NVIC_InitTypeDef NVIC_InitStruct={0};NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStruct);}//配置中断响应函数
void EXTI9_5_IRQHandler(){//如果接收到线5的中断就亮灯,否则线6的则灭灯if(EXTI_GetFlagStatus(EXTI_Line5)==SET){EXTI_ClearFlag(EXTI_Line5);GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);}else if(EXTI_GetFlagStatus(EXTI_Line6)==SET){EXTI_ClearFlag(EXTI_Line5);GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);}}//初始化板载LED
void My_BoardLed_Init(){//GPIO的引脚13初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);GPIO_InitTypeDef GPIO_InitStruct={0};GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;GPIO_Init(GPIOC,&GPIO_InitStruct);}
void My_USART_Init(){//初始化IORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStruct={0};GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化本身RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//五个USART_InitTypeDef USART_InitStruct={0};USART_InitStruct.USART_BaudRate=115200;USART_InitStruct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;USART_InitStruct.USART_Parity=USART_Parity_No;USART_InitStruct.USART_StopBits=USART_StopBits_1;USART_InitStruct.USART_WordLength=8;USART_Init(USART1,&USART_InitStruct);//开启USARTUSART_Cmd(USART1,ENABLE);//开启中断USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//给每个中断配置NVIC模块下的中断配置NVIC_InitTypeDef NVIC_InitStruct={0};NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStruct);}
void USART1_IRQHandler(void){if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){uint8_t temp=USART_ReceiveData(USART1);if(temp==0){adjustDelay=10000;}else if(temp==1){adjustDelay=1000;}else if(temp==2){adjustDelay=100;}}}