stm32学习笔记-外部中断

1、stm32f103外部中断控制器EXTI。

1.1外部中断的映像

外部中断只有0~18共19个,那如何给每一个GPIO口配置上中断,通过一个映像把所有具有相同下标的GPIO口映像成相应下标的外部中断。
在这里插入图片描述

参考手册:
在这里插入图片描述

1.2 外部中断/事件的框图

在这里插入图片描述
中断大致过程如下:

  1. 通过配置 上升沿/下降沿触发选择寄存器 选择 边沿检测电路 所要检测的边沿跳变。
  2. 边沿检测电路 根据 输入线 是否有相应的边沿跳变,检测到则输出信号1,否则输出信号0。
  3. 通过一个 或门,或门 以 边沿检测电路软件中断事件寄存器(中断事件可以通过软件产生) 作为输入。两者之一有一个产生信号1,或门就输出信号1。
  4. 或门输出的信号1。输出的信号1发至 请求挂起寄存器
  5. 请求挂起寄存器对应寄存器的位置1,然后请求挂起寄存器会产生一个信号1。(不懂,这里暂略)
  6. 请求挂起寄存器、中断屏蔽寄存器同时输出信号1,则发生信号1到NVIC中断控制器。(注意:这里可以看出中断屏蔽也就是一个与操作。)

事件大致过程如下:

  1. 通过配置 上升沿/下降沿触发选择寄存器 选择 边沿检测电路 所要检测的边沿跳变。
  2. 边沿检测电路 根据 输入线 是否有相应的边沿跳变,检测到则输出信号1,否则输出信号0。
  3. 通过一个 或门,或门 以 边沿检测电路软件中断事件寄存器(中断事件可以通过软件产生) 作为输入。两者之一有一个产生信号1,或门就输出信号1。
  4. 或门输出的信号1。若事件屏蔽寄存器也产生信号1,则产生一个信号1发至脉冲发生器,脉冲发生器产生脉冲。

1.3 外部中断的编程。

外部中断配置思路

思路:

  1. 时钟配置(GPIO时钟、AFIO时钟)
  2. GPIO配置(中断功能,映射)
  3. EXTI配置(触发方式,中断使能,)
  4. NVIC配置(优先级分组,中断使能)
  5. 中断服务子程序(判断标志,清除标志)

相关寄存器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相关库函数

  1. GPIO映射函数:
    在这里插入图片描述
  2. 外部中断复位配置函数在这里插入图片描述
  3. 外部中断初始化配置函数在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  4. NVIC配置函数在这里插入图片描述
  5. NVIC优先级分组函数在这里插入图片描述
  6. 清除挂起位标志函数(清除挂起寄存器的标志位)

在这里插入图片描述

1.4 按键中断实例。

电路图
在这里插入图片描述
代码:

//exti.c
#include "exti.h"


void KEY_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOA,ENABLE);	//使能复用功能时钟
	
	GPIO_InitTypeDef gpiost;
	gpiost.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_3;
	gpiost.GPIO_Speed = GPIO_Speed_50MHz;
	gpiost.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOE,&gpiost);
	
	gpiost.GPIO_Pin = GPIO_Pin_0;
	gpiost.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOA,&gpiost);
	
}

void exti_init(void)
{
	EXTI_InitTypeDef extist;
	NVIC_InitTypeDef nvicst;
	KEY_Init();
	
	
	
	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟
	
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
	extist.EXTI_Line = EXTI_Line3;
	extist.EXTI_Mode = EXTI_Mode_Interrupt;
	extist.EXTI_Trigger = EXTI_Trigger_Falling;
	extist.EXTI_LineCmd = ENABLE;
	EXTI_Init(&extist);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);
	extist.EXTI_Line = EXTI_Line4;
	extist.EXTI_Mode = EXTI_Mode_Interrupt;
	extist.EXTI_Trigger = EXTI_Trigger_Falling;
	extist.EXTI_LineCmd = ENABLE;
	EXTI_Init(&extist);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
	extist.EXTI_Line = EXTI_Line0;
	extist.EXTI_Mode = EXTI_Mode_Interrupt;
	extist.EXTI_Trigger = EXTI_Trigger_Rising;
	extist.EXTI_LineCmd = ENABLE;
	EXTI_Init(&extist);
	
	
	nvicst.NVIC_IRQChannel = EXTI3_IRQn;
	nvicst.NVIC_IRQChannelPreemptionPriority = 0x02;
	nvicst.NVIC_IRQChannelSubPriority = 0x02;
	nvicst.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvicst);
	
	nvicst.NVIC_IRQChannel = EXTI4_IRQn;
	nvicst.NVIC_IRQChannelPreemptionPriority = 0x02;
	nvicst.NVIC_IRQChannelSubPriority = 0x01;
	nvicst.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvicst);
	
	nvicst.NVIC_IRQChannel = EXTI0_IRQn;
	nvicst.NVIC_IRQChannelPreemptionPriority = 0x02;
	nvicst.NVIC_IRQChannelSubPriority = 0x03;
	nvicst.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvicst);

}

void EXTI0_IRQHandler(void)
{
	led1 = !led1;
	led2 = !led2;
	EXTI_ClearITPendingBit(EXTI_Line0);
}

void EXTI3_IRQHandler(void)
{
	led1 = !led1;
	EXTI_ClearITPendingBit(EXTI_Line3);
}

void EXTI4_IRQHandler(void)
{
	led2 = !led2;
	EXTI_ClearITPendingBit(EXTI_Line4);
}


//main()函数
int main(void)
{
	Stm32_Clock_Init();
	GPIOB_And_E_Config();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//主优先级0-3共四级,从优先级0-3四级。
	exti_init();
	led1 = 0;
	led2 = 0;

	while(1)
	{
 		//等待外部中断到来		
	}
}

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);这个语句写在主函数好,整个系统执行过程中,只设置一次中断分组。(随意改变会导致 中断管理混乱)

2、按键按下的触发方式编程思路

按键按下可以有 支持连续按下,不支持连续按。

2.1 支持连续按下

在这里插入图片描述

2.2 不支持连续

在这里插入图片描述

2.3 连续,不连续二合一

思路:

  • 定义static KEY_UP=1
  • 判断是否是模式1:连续按下模式?是则标志KEY_UP置1,表示松开
  • 按键被按下?上次松开了则干活,上次没有松开则啥都不干
  • 按键被松开?标志KEY_UP置1,表示松开

在这里插入图片描述

遇到的问题

外部中断3,4,没有反应的问题。
对比了许久才发现是使用初始化EXTI结构体时,或运算出现bug的问题。extist.EXTI_Line = EXTI_Line3|EXTI_Line4;使用这句语句初始化结构体将失败。注意,注意,注意。

  • 24
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值