中断控制——NVIC和EXTI

NVIC

对外设的控制方式,一般是四种,即:轮询,中断,DMA,通道。
rbt6开发板不存在通道控制器。所以,控制方法就是轮询和中断以及DMA。

中断一般会分为异常和外部的中断,异常是体现在内核的水平,主要就是指内核的外设,如系统滴答定时器等等。但在操作时,异常和中断并没有什么不同,一般统一处理。最典型的中断就是复位,也是优先级最高的中断。

这里,就是介绍如何使用中断控制。控制中断一般需要使用内核外设嵌套中断向量控制器(NVIC);内核外设的寄存器定义是在core_cm3.h当中,对内核外设函数的定义一般在misc.c中。一般只使用NVIC的IPRx控制器,来设置中断的优先级。先比较主优先级,相同的话比较子优先级,还是相同,比较硬件中断编号,硬件中断编号就是STM32中文参考手册_V10第9章的中断优先表。
同时,ARM公司规定,中断优先级是8位的,而ST公司在使用时,则只使用了4位。
在这里插入图片描述图中SCB的内容在misc.h中也有

那么,怎么写中断呢?
初始化NVIC一般有3个步骤:

1.配置中断优先级
使用函数void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
具体查看misc.c文件。
2.配置NVIC寄存器
使用函数void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
3.编写中断服务函数
一般是在"stm32f10x_it.c"当中集中写中断服务函数。切记的是,函数名必须和启动文件中定义的中断向量表名字相同。

EXTI
NVIC处理中断,EXTI(外部中断/事件控制器)管理外部中断。
中断产生的步骤:外设产生中断信号->交给EXTI->交给内核的NVIC处理中断
在这里插入图片描述
由上图可知,最开始是输入线输入中断信号,那么,中断信号线有哪些?
由下图可知,有EXTI【0-15】共16根输入线,此外还有4根输入线,是:
● EXTI线16连接到PVD输出
● EXTI线17连接到RTC闹钟事件
● EXTI线18连接到USB唤醒事件
● EXTI线19连接到以太网唤醒事件(只适用于互联型产品)
前16根输入线是选择GPIO引脚作为输入,后四个输入线是特殊功能。
因此,可以得到一个结论:**EXTI可以管理20个外部中断。**上图中引线上标注的20就是这个意思。

在这里插入图片描述
其中,输入线EXTI【0-15】通过 外部中断配置寄存器 AFIO_EXTICR 1-4共4个寄存器来配置,每个寄存器低16位配置4个输入线。
当我们按下按键,比如按下K1键,是PA0电平出现变化,从低电平变成高电平,产生一个上升沿,按键松开,产生一个下降沿。此时应该配置上升沿触发选择寄存器(EXTI_RTSR)和下降沿触发选择寄存器(EXTI_FTSR),设置为1时,表示允许输入线x上的上/下降沿触发(中断和事件);这俩个寄存器的低20位,分别对应20根输入线。

输入线和边沿触发寄存器配置好以后,边沿检测电路就会检测是否对应的输入线有边沿触发;如果有,会产生一个脉冲,到达一个或门,或门另一端是软件中断事件寄存器,
也是低20位对应20根输入线,每一个位的配置如下:
当该位为’0’时,写入’1’的话,根据图中所示,会设置EXTI_PR(挂起寄存器)中相应的挂起位也为1,EXTI_PR中写入1表示发生了选择的触发请求。在这里可以发现是走了俩条路,向上是中断,向下是事件。然后是分别和中断屏蔽寄存器(EXTI_IMR),事件屏蔽寄存器(EXTI_EMR)作与操作,如果是屏蔽了事件,打开了中断,那么就会把这个中断输出到NVIC当中。最后交给内核,执行中断服务函数。

初始化EXIT的方法:
1.、EXTI初始化
typedef struct
{
uint32_t EXTI_Line; //选择位线是为以后配置中断配置寄存器 做准备
EXTIMode_TypeDef EXTI_Mode; //是中断还是事件
EXTITrigger_TypeDef EXTI_Trigger; //是上升沿,下降沿还是都有
FunctionalState EXTI_LineCmd;//使能
}EXTI_InitTypeDef;
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
2.选择GPIO线作为EXTI输入线。
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

uint8_t GPIO_PortSource: GPIO_PortSourceGPIOx where x can be (A…G).
uint8_t GPIO_PinSource: GPIO_PinSourcex where x can be (0…15).

实现一个中断的编程方法:
1.初始化中断的GPIO
2.初始化EXTI
3.初始化NVIC

exits.h

#ifndef	 _EXTIS_H
#define  _EXTIS_H
#include "stm32f10x.h"
#define KEY1_GPIO_Pin    GPIO_Pin_0
#define KEY1_GPIO_PORT   GPIOA
#define KEY1_GPIO_CLK    RCC_APB2Periph_GPIOA
static void NVIC_Config(void);
void EXIT_KEY(void);
#endif

exits.c

#include "extis.h"

static void NVIC_Config()//static的作用:表示这个函数只能在本文件调用,其他文件不能调用

{
	NVIC_InitTypeDef NVIC_InitStruct;

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//选择主优先级组
	NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn;	 //中断源
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//主优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=	1; //子优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//使能NVIC
	
	NVIC_Init(&NVIC_InitStruct);//设置中断源的中断优先级
}


void EXIT_KEY()
{

	GPIO_InitTypeDef GPIO_InitStruct;
	EXTI_InitTypeDef EXIT_InitStruct;

//初始化NVIC
  	NVIC_Config();
//初始化按键的GPIO
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //打开按键的时钟
	GPIO_InitStruct.GPIO_Pin=  KEY1_GPIO_Pin;
	GPIO_InitStruct.GPIO_Mode= GPIO_Mode_IPU;
	GPIO_Init(KEY1_GPIO_PORT,&GPIO_InitStruct);
//初始化EXTI
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	//打开外部中断的时钟
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA , GPIO_PinSource0); //设置EXIT的输入线是PA0
	EXIT_InitStruct.EXTI_Line=EXTI_Line0;		   //选择输入线是EXIT0
	EXIT_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //选择EXIT的模式为中断
	EXIT_InitStruct.EXTI_Trigger=EXTI_Trigger_Rising_Falling;
	//EXTI_Trigger_Rising_Falling:按下和释放各产生一次中断
	//EXTI_Trigger_Rising        :只有按下才产生中断
	//EXTI_Trigger_Falling		 :只有释放按键才产生中断
	EXIT_InitStruct.EXTI_LineCmd =ENABLE;
	EXTI_Init(&EXIT_InitStruct);	 //初始化EXTI
//接下来应该写中断服务函数,在 stm32f10x_it.c中写,
//函数名在startup_stm32f10x_md.s中找

}

在"stm32f10x_it.c"中添加中断服务函数

void EXTI0_IRQHandler()
{
	if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
	{
		LED_R;
	}
	EXTI_ClearITPendingBit(EXTI_Line0);
}

在"stm32f10x_it.h"中添加头文件和函数声明

#include "extis.h"
#include "led.h"
void EXTI0_IRQHandler(void);

led.h

#ifndef	 _LED_H
#define  _LED_H
#include "stm32f10x.h"   
#define LED0_GPIO_Pin    GPIO_Pin_8
#define LED0_GPIO_PORT   GPIOC
#define LED0_GPIO_CLK    RCC_APB2Periph_GPIOC
#define LED_R      (LED0_GPIO_PORT->ODR^=LED0_GPIO_Pin)	//实现lED的反转
void LED_GPIO_Config(void);
#endif

led.c

#include "led.h"

void LED_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

	GPIO_InitStruct.GPIO_Pin=  LED0_GPIO_Pin;
	GPIO_InitStruct.GPIO_Mode= GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(LED0_GPIO_PORT,&GPIO_InitStruct);
}

main.c

#include "stm32f10x.h"
#include "led.h"
#include "extis.h"
int main()
{
	LED_GPIO_Config();
	EXIT_KEY();
	while(1)
	{
		;//让程序一直执行下去,直到产生中断,而不是一初始化完就结束了程序
	}

}

  • 23
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值