stm32学习笔记-外部中断

文章目录

  • 1、stm32f103外部中断控制器EXTI。
    • 1.1外部中断的映像
    • 1.2 外部中断/事件的框图
    • 1.3 外部中断的编程。
      • 外部中断配置思路
      • 相关寄存器
      • 相关库函数
    • 1.4 按键中断实例。
  • 2、按键按下的触发方式编程思路
    • 2.1 支持连续按下
    • 2.2 不支持连续
  • 2.3 连续,不连续二合一
  • 遇到的问题

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

1.1外部中断的映像

外部中断只有0~18共19个,那如何给每一个GPIO口配置上中断,通过一个映像把所有具有相同下标的GPIO口映像成相应下标的外部中断。
stm32学习笔记-外部中断_第1张图片

参考手册:
stm32学习笔记-外部中断_第2张图片

1.2 外部中断/事件的框图

stm32学习笔记-外部中断_第3张图片
中断大致过程如下:

  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. 中断服务子程序(判断标志,清除标志)

相关寄存器

stm32学习笔记-外部中断_第4张图片
stm32学习笔记-外部中断_第5张图片
stm32学习笔记-外部中断_第6张图片
stm32学习笔记-外部中断_第7张图片
stm32学习笔记-外部中断_第8张图片

相关库函数

  1. GPIO映射函数:
    stm32学习笔记-外部中断_第9张图片
  2. 外部中断复位配置函数stm32学习笔记-外部中断_第10张图片
  3. 外部中断初始化配置函数stm32学习笔记-外部中断_第11张图片
    stm32学习笔记-外部中断_第12张图片
    stm32学习笔记-外部中断_第13张图片
    stm32学习笔记-外部中断_第14张图片
    stm32学习笔记-外部中断_第15张图片
  4. NVIC配置函数stm32学习笔记-外部中断_第16张图片
  5. NVIC优先级分组函数stm32学习笔记-外部中断_第17张图片
  6. 清除挂起位标志函数(清除挂起寄存器的标志位)

stm32学习笔记-外部中断_第18张图片

1.4 按键中断实例。

电路图
stm32学习笔记-外部中断_第19张图片
代码:

//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 支持连续按下

stm32学习笔记-外部中断_第20张图片

2.2 不支持连续

stm32学习笔记-外部中断_第21张图片

2.3 连续,不连续二合一

思路:

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

stm32学习笔记-外部中断_第22张图片

遇到的问题

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

你可能感兴趣的:(stm32,嵌入式,stm32,单片机)