STM32——中断(外部中断、定时器中断)

STM32F407芯片支持82个可屏蔽中断

NVIC:嵌套向量中断控制器,控制芯片中断相关功能。由于ARM给NVIC预留了非常多的功能,但是对于使用M4内核设计芯片的公司可能就不需要这么多功能,于是就需要在NVIC上进行裁剪。ST公司的STM32F407芯片内部中断数量就是NVIC裁剪后的结果。

STM32F407芯片支持82个可屏蔽中断通道,每个中断通道都具备自己的中断优先级控制字节(8位,但是STM32F407中只使用4位,高4位有效),用于表达优先级的高4位又被为组成抢占式优先级和响应优先级,通常也把响应优先级称为“亚优先级”或“副优先级”,每个中断源都需要被指定这两种优先级。
高抢占式优先级的中断事件会打断当前的主程序或者中断程序运行,俗称中断嵌套。在抢占式优先级相同的情况下,高响应优先级的中断优先被响应。
两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理那一个。

STM32F407中指定中断优先级的寄存器位有4位,这4位的分组方式如下:
在这里插入图片描述
中断配置步骤:

//要使用中断我们就需要先配置它,通常都需经过这几步:
//(1)使能外设某个中断
//(2)设置中断优先级分组,初始化 NVIC_InitTypeDef 结构体
typedef struct
{
  uint8_t NVIC_IRQChannel;                    //中断源
  uint8_t NVIC_IRQChannelPreemptionPriority;  //抢占优先级
  uint8_t NVIC_IRQChannelSubPriority;         //响应优先级
  FunctionalState NVIC_IRQChannelCmd;         //中断使能或失能   
} NVIC_InitTypeDef;

//(3)编写中断服务函数

EXTI简介
STM32F4外部中断/事件控制器(EXTI)包含多达 23 个用于产生事件/中断请求的边沿检测器。EXTI的每根输入线都可单独进行配置,以选择类型(中断或事件)和相应的触发事件(上升沿触发、下降沿触发或边沿触发),还可单独屏蔽。
EXTI结构框图:
在这里插入图片描述
外部中断事件的映射
STM32F4的EXTI具有23个中断/事件线。
在这里插入图片描述
EXTI0-15:
在这里插入图片描述
外部中断配置步骤:
要使用外部中断我们就需要先配置它,通常都需经过这几步:
(1)使能IO口时钟,配置IO口模式为输入

(2)开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//使能SYSCFG时钟
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);

(3)配置中断分组(NVIC),使能中断

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//EXTI0中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器

(4)初始化EXTI,选择触发方式

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
typedef struct
{
  uint32_t EXTI_Line;               //中断/事件线
  EXTIMode_TypeDef EXTI_Mode;       //EXTI模式
  EXTITrigger_TypeDef EXTI_Trigger; //EXTI触发方式
  FunctionalState EXTI_LineCmd;     //中断线使能或失能 
}EXTI_InitTypeDef;

(5)编写EXTI中断服务函数
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler (包含5、6、7、8、9)
EXTI15_10_IRQHandler(包含10、11、12、13、14、15)

使用外部中断来控制led亮灭
外部中断源文件:
exti.c

void My_EXTI_Init(void)
{   
	NVIC_InitTypeDef NVIC_InitStructure;        //定义NVIC结构体
	EXTI_InitTypeDef  EXTI_InitStructure;      //定义EXTI结构体
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);       //使能IO口时钟
	
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);    //打开SYSCFG时钟 该函数定义位于stm32f4xx_syscfg.c中
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);    //打开SYSCFG时钟是配置GPIO中断线映射的前提
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);
	
	
	//EXTI0 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//EXTI0中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	
	//EXTI2 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//EXTI2中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	
	//EXTI3 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//EXTI3中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	//EXTI4 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//EXTI4中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	//初始化线上中断,设置KEY_UP触发条件
	EXTI_InitStructure.EXTI_Line=EXTI_Line0;    //中断线的标号
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;     //选择模式(中断或事件)
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   //根据按键电路选择触发方式
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;               //使能标志位
	EXTI_Init(&EXTI_InitStructure);
	
	//初始化线上中断,设置KEY_LEFT KEY_DOWN KEY_RIGHT触发条件
	EXTI_InitStructure.EXTI_Line=EXTI_Line2|EXTI_Line3|EXTI_Line4; 
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
}


//设置各个按键的中断函数
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0)==1)     //读取中断标志位
	{
		myDelay_ms(10);
		if(K_UP==1)
		{
			led2=0;
		}	
	}
	EXTI_ClearITPendingBit(EXTI_Line0);    //清除中断标志位
}

void EXTI3_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line3)==1)
	{
		myDelay_ms(10);
		if(K_DOWN==0)
		{	
			led2=1;
		}
		
	}
	EXTI_ClearITPendingBit(EXTI_Line3);
}

void EXTI2_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line2)==1)
	{
		myDelay_ms(10);
		if(K_RIGHT==0)
		{
			led1=0;
		}
		
	}
	EXTI_ClearITPendingBit(EXTI_Line2);
}

void EXTI4_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line4)==1)
	{
		myDelay_ms(10);
		if(K_LEFT==0)
		{
			led1=1;
		}
		
	}
	EXTI_ClearITPendingBit(EXTI_Line4);
}



主函数:

int main()
{
	u8 i=0;
	SysTick_Init(168);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
	LED_Init();
	
	KEY_Init();
	My_EXTI_Init();  //外部中断初始化
	while(1)
	{
		led1 = 0;
		myDelay_ms(300);
		led1 = 1;
		myDelay_ms(300);
	}
}

定时器中断:
STM32F407定时器由两个基本定时器(TIM6、TIM7)、10个通用定时器(TIM2-TIM5,TIM9-TIM14)和两个高级定时器(TIM1、TIM8)组成。通用定时器在 基本定时器的基础上扩展而来,增加了输入捕获与输出比较等功能。高级定时器又是在通用定时器基础上扩展而来,增加了可编程死区互补输出,重复计数器,带刹车(断路)功能,这些功能主要针对工业电机控制。

通用定时器:
STM32F4的通用定时器包含一个 16 位或 32 位自动重载计数器(CNT),该计数器由可编程预分频器(PSC)驱动。STM32F4的通用定时器可用于多种用途,包括测量输入信号的脉冲宽度(输入捕获)或者生成输出波形(输出比较和PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32F4 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
在这里插入图片描述
在这里插入图片描述

通用定时器结构框图
通用定时器是总线时钟的两倍。
在这里插入图片描述
通用定时器配置步骤:
在这里插入图片描述
在这里插入图片描述
固件库中还有两个函数是用来读取状态标志位以及清除中断标志位,函数分别为TIM_GetFlagStatus和TIM_ClearFlag。
定时器时钟:
TIM4时钟:
由于TIM4挂接在APB2上,根据时钟树可以看出外部时钟8MHz经过PLL的M(8)分频,N(336)倍频和P分频(8)得到的42MHz频率,如果APB中的presc不为1所以需要2倍频所以TIM4的时钟为84MHz。
在这里插入图片描述

使用定时器中断控制灯闪烁:

#include "time.h"
#include "led.h"
#include "sysTick.h"

 void TIM_Init(u16 per,u16 psc)
{
	    TIM_TimeBaseInitTypeDef  TIMBaseInitStructure;     //定义定时器结构体
	    NVIC_InitTypeDef NVIC_InitStructure;               //定义NVIC结构体
	
			RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);    //注意TIM4的时钟是APB1时钟的两倍
	
	    TIMBaseInitStructure.TIM_Period =per;  //自动重装载值  周期
  	  TIMBaseInitStructure.TIM_Prescaler = psc;   //预分频系数(时钟源)
	    TIMBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;   //时钟分割,时钟分频 通常不需要修改
			TIMBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数模式选择向上计数
      TIM_TimeBaseInit(TIM4,&TIMBaseInitStructure);   //初始化定时器中断
	    TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);    //设置定时器中断类型
		  TIM_ClearFlag(TIM4,TIM_IT_Update);   //	**保证中断标志位为空**
	
	
	    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//TIM4中断通道
			NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
			NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级
			NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
			NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
			
	    TIM_Cmd(TIM4,ENABLE);     //使能定时器
	    
}

void TIM4_IRQHandler(void)     //定时器4中断函数
{
			if(TIM_GetITStatus(TIM4,TIM_IT_Update)){
						led2 = !led2;
			}
			TIM_ClearFlag(TIM4,TIM_IT_Update);
}



主函数:

#include "led.h"
#include "system.h"
#include "SysTick.h"
#include "key.h"
#include "time.h"


int main()
{
	
	SysTick_Init(168);
	LED_Init();
	TIM_Init(5000-1,8400-1); //从0开始所以-1;TIM4的时钟是84MHz,通过8400分频之后是10000Hz也就是0.1ms,所以500ms需要5000次计数
	while(1)
	{
		led1 = 0;
	}
	
}

参考博文

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值