EXTI是片上外设 NVIC是cpu内的外设 回忆起之前的GPIO和AFIO 我们是如何检测按键按下的 我们是一直用while循环读取IDR寄存器的对应位置的值 一直检测判断按键是否被按下
那么是否有第二种方式检测按键是否被按下了呢?
通过EXTI 当EXTI检测到按键的电平发生变化 就会触发一个中断 送到NVIC进行相应的处理 就会触发相应的中断函数
EXTI的作用就是检测外部信号的变化由此产生中断
首先外部输入一个信号 信号有上升沿和下降沿 经过边路检测分为上升沿和下降沿还有双边沿三路信号 通过边沿的选择选择是哪路信号传入下一个的或门 (这里举例的是边沿选择选择的是上升沿)进入到或门后要看中断是否屏蔽如果没有屏蔽就接着往下传输 到脉冲位产生中断 看中断挂起 脉冲置为为1 无法自己清零 需要手动清零手动清零后电平型中断就为0 还有上升沿信号传入后还可以变为事件
中断的模型就是片上外社产生一个中断传输到NVIC(CPU内)然后进行中断仲裁 然后通过后执行相应的中断函数 有CPU的参与
事件就是外部产生一个终端信号给与EXTI产生事件给部件将部件从睡眠模式中唤醒 不需要CPU的介入
检测多路信号 就是多个这样的结构同时检测多路信号的输入
EXTI的20路信号有什么用?
1.让所有IO具备触发中断的能力
EXTI具有19个通道 一个通道对应abcde…的第0个io口 依次类推所有的io口都连接到了EXTI上都具备了触发中断的能力 当每一个 如PA0口连接到EXTI0时其他都不能连接了
只用EXTI的16个通道作为IO引脚的触发 其他四个通道具有特殊的功能
每一列对应的都是一个通道 TP0这一列对应的就是第1个通道
…
这里以EXTI0为列子 如果想上升沿TR0就写1 (上面) 下面的TR0就写0 如果想双沿触发就全部写1
中断屏蔽寄存器对应着开关 对应的通道的寄存器位写0就断开 写1就闭合事件屏蔽寄存器也是如此
第一个line参数是要哪一个EXTI的通道 第二个参数Mode是要什么模式 是中断模式 触发中断 传输到NVIC还是要事件模式 唤醒部件 第三个参数Trigger什么触发模式 上升还是下降还是双边 第四个参数linecmd是 是否要开启中断或者事件屏蔽如果选择的是事件模式就是控制下面的事件屏蔽开关 如果选择的是中断模式那么控制的就是上面的中断屏蔽开关
声明一个结构体变量 然后填表把相应的值填进去
第一个函数EXTI_Init是上面的函数 第二个函数Generate 返回值是空 传入的值是通道号(后面的也是如此) 通过调用这个函数(编程接口)可以产生软件中断就是在软件触发哪里可以产生一个脉冲信号触发一个中断
第三个函数getflag 获取标志位的值 1位set 0为reset 会返回值1或者0
第四个函数clearflag是清除标志位当信号传输到中断挂起位置时候产生的是一个电平型的信号 需要手动清零
第五个函数getstatus 是需要中断屏蔽和中断挂起为1才会为1(需要使能这个中断同时出触发这个中断)同样也会返回值 0或者1 reset或set
最后一个函数同样也是清除标志位 但是会经常用的就是这个函数 这个函数和第三个完全一样 但是由于名字会经常使用这个函数清除标志位
回忆一下之前按钮的编程时使用while语句一直检测previous(之前的电平)和current(当前的电平)的值然后判断两个值是否相等来判断按键是否按下或松开(按键按下或者松开previous和current的值都不会相同) 一直循环的去检测两个值 使用中断来实现按键编程
选择上升沿触发 因为我们要按键松开才该改变灯的电平就是从0电位到1电位 是一个上升沿 然后要使用PA0 PA1两个IO口所以EXTI要使用EXTI0和EXTI1两个通道
编程思路梳理
首先要使用按钮就要初始化两个io端口 然后要配置AFIO使得端口PA0和PA1连接到EXTI0 和EXTI1(也就是EXTI的IO映射)
然后EXTI0和EXTI1会分别产生两路中断传输到NVIC 接着配置NVIC
先配置中断屏蔽先把开关打开 然后配置中断优先级 配置几个位给抢占优先级和子优先级
(红色虚线的位置)
去头文件中搜这个结构体 EXTI_InitTypeDef在头文件中找每一个要填表的值 搜索后面的ctrl+f搜索填入表中每一行对应的值如第一行
![在这里插入图片描述](https://img-blog.csdnimg.cn/f1daeb5f597a4f7aa7ff35668528fd24.png)
中断函数的名称要在stm32中启动文件中寻找
这就是个弱方法 就是先占名然后用重名的函数覆盖掉
点灯就是写0就亮起 写1就熄灭
#include "stm32f10x.h"
#include "stm32f10x_pal.h"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
PAL_Init();
// 1. 初始化IO引脚
// 将PA0和PA1分别设置为输入上拉模式
// 开启GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// PA0, PA1
GPIO_InitTypeDef GPIOInitStruct;
GPIOInitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIOInitStruct);
// 2. 配置EXTI的引脚映射
// 开启AFIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// PA0 -> EXTI0
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
// PA1 -> EXTI1
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
// 3. 初始化EXTI
// 3.1. 初始化EXTI0
EXTI_InitTypeDef EXTIInitStruct;
EXTIInitStruct.EXTI_Line = EXTI_Line0;
EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTIInitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTIInitStruct);
// 3.2. 初始化EXTI1
EXTIInitStruct.EXTI_Line = EXTI_Line1;
EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTIInitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTIInitStruct);
// 4. 初始化NVIC
NVIC_InitTypeDef NVICInitStruct;
// 4.1. EXTI0
NVICInitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVICInitStruct.NVIC_IRQChannelSubPriority = 0;
NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVICInitStruct);
// 4.2. EXTI1
NVICInitStruct.NVIC_IRQChannel = EXTI1_IRQn;
NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVICInitStruct.NVIC_IRQChannelSubPriority = 0;
NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVICInitStruct);
// 5. 初始化PC13
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIOInitStruct.GPIO_Pin = GPIO_Pin_13;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD; // Open-drain
GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIOInitStruct);
while(1)
{
}
}
void EXTI0_IRQHandler(void)
{
// 清除中断
EXTI_ClearITPendingBit(EXTI_Line0);
// 点亮LED PC13 <- 0
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
}
void EXTI1_IRQHandler(void)
{
// 清除中断
EXTI_ClearITPendingBit(EXTI_Line1);
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
}