04:(寄存器开发)使用外部中断按键控制LED

关于外部中断的AFIO,NVIC的基础知识请参考《stm32标准库入门教程》
链接: link

1、选择外部引脚配置

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

在这里插入图片描述
如上图所示:外部中断配置寄存器AFIO_EXTICR(1~4)中选择EXTI(0 ~ 15),在选择好的EXTI中填入对应的数值选择引脚。

本次实验:我们需要对引脚PB0进行外部中断检测,来控制LED灯的亮灭,则选择的寄存器是外部中断配置寄存器1(AFIO_EXTICR1),选择寄存器中的位0~位3(EXTI0)填入数值0001(选择PB0)

实物连接如下图所示:
在这里插入图片描述
具体的配置代码如下:

/* 1. 开启时钟:GPIOB和AFIO */
/* 1.1 GPIOB */
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; 

/* 1.2 AFIO */
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; 

/* 2. 将GPIOB0配置为上拉输入:MODE = 00,CNF = 10,上拉:ODR = 1 */
GPIOB->CRL &= ~GPIO_CRL_MODE0;
GPIOB->CRL &= ~GPIO_CRL_CNF0_0;
GPIOB->CRL |= GPIO_CRL_CNF0_1;
GPIOB->ODR |= GPIO_ODR_ODR0;//ODR = 1:表示上拉

/* 3. 配置AFIO ,选用EXTI0*/
AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PB;//其中EXTIR[0]是EXTIR数组的第一个元素,
										 //AFIO_EXTICR1_EXTI0_PB = 0001

2、上升沿触发/下降沿触发

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

/* 1. 配置EXTI:下降沿触发,使能EXTI中断屏蔽 */
EXTI->FTSR |= EXTI_FTSR_TR0;//配置为下降沿触发
EXTI->IMR |= EXTI_IMR_MR0;//使能EXTI开关,只有使能这个开关中断信号才能传递到NVIC

3、NVIC的配置

NVIC是中断管理器,将请求来的中断进行优先级分组等操作。NVIC和RCC是处于CPU内部,挂载在系统总线AHB上面的,单片机一上电AHB的时钟信号都开启了的,所以不需要我们在用代码开启时钟,关于总线时钟可以参考《stm32标准库入门教程》中的时钟树那一篇。
由于NVIC在参考手册里面没有关于它的寄存器介绍,但是在core_cm3.c的文件里面有关于NVIC的配置函数,如下图所示:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述其中中断源的来源如下图所示:
在这里插入图片描述
由上图得出,中断源和下图的中断向量表的排序是一比一对应的。
在这里插入图片描述
在这里插入图片描述
如上图中断向量表所示:表中黑色部分的中断源是由CPU内部产生的,而其他的都是由片上外设产生的,若没有配置NVIC的优先级,那么则按照表中的默认优先级进行执行中断。其他黑色部分的中断源来自于CPU内部,则无需在使能NVIC_EnableIRQ(),因为只有前面位置值为正数才需要使能NVIC_EnableIRQ()。
在这里插入图片描述

/* 5. 配置NVIC  */
/* 5.1 优先级分组*/
NVIC_SetPriorityGrouping(0x04);//设置4位抢占优先级,0位子优先级

/* 5.2 优先级赋值*/
NVIC_SetPriority(EXTI0_IRQn,0);

/* 5.3 使能中断源请求*/
NVIC_EnableIRQ(EXTI0_IRQn);

综上的分析:总结的外部中断的大体结构如下图所示:

在这里插入图片描述

4、完整代码

①Key.c的文件代码如下:

#include "stm32f10x.h"                  // Device header
#include "Key.h"  
#include "LED.h"
#include "Delay.h"
/*
 * 引脚的初始化:
 * 1、给按键对应的引脚IO口工作模式:上拉输入
 * 2、配置AFIO(复用外部中断)
 * 3、配置EXTI(外部中断控制器)
 * 4、配置NVIC
 */
 
 void Key_EXTI_Init(void)
 {
   /* 1. 开启时钟:GPIOB和AFIO */
   /* 1.1 GPIOB */
   RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; 
   /* 1.2 AFIO */
   RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; 
   
   /* 2. 将GPIOB0配置为上拉输入:MODE = 00,CNF = 10,上拉:ODR = 1 */
   GPIOB->CRL &= ~GPIO_CRL_MODE0;
   GPIOB->CRL &= ~GPIO_CRL_CNF0_0;
   GPIOB->CRL |= GPIO_CRL_CNF0_1;
   
   GPIOB->ODR |= GPIO_ODR_ODR0;//ODR = 1:表示上拉
   
   /* 3. 配置AFIO ,选用EXTI0*/
   AFIO->EXTICR[0] |= AFIO_EXTICR1_EXTI0_PB; 
   
   /* 4. 配置EXTI:下降沿触发,使能EXTI中断屏蔽 */
   EXTI->FTSR |= EXTI_FTSR_TR0;
   EXTI->IMR |= EXTI_IMR_MR0;
   
   /* 5. 配置NVIC  */
   /* 5.1 优先级分组*/
   NVIC_SetPriorityGrouping(0x04);
   /* 5.2 优先级赋值*/
   NVIC_SetPriority(EXTI0_IRQn,0);
   /* 5.3 使能中断请求*/
   NVIC_EnableIRQ(EXTI0_IRQn);
 }
 
 
 /*
  * 中断服务函数:按下按键时,执行一次中断函数
  */
void EXTI0_IRQHandler(void)
{
  /* 除中断挂起标志位 */
  EXTI->PR |= EXTI_PR_PR0;
  
  Delay_ms(10);//在中断里面添加延迟是不被允许的,但是这里是学习中断,我们忽略
  
  if((GPIOB->IDR & GPIO_IDR_IDR0) != 0)//检测输入引脚是否被真的按下
  {
    //不等于0说明还在抖动
  }
  else
  {
    /* LED0翻转 */
    LED_Turn(LED0);
  }
}

②LED.c文件的代码如下:

#include "stm32f10x.h"                  // Device header
#include "LED.h"

/*
 * PA0~PA7引脚的初始化
 */
void LED_Init(uint32_t PA_x)
{
	/* 1. 打开GPIOA的时钟 */
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
	
	/* 2. 将PA0~PA7配置为通用输出开漏模式  */
	if(PA_x != PA_ALL)
	{
		GPIOA->CRL |= PA_x; 
		GPIOA->CRL &= ~(PA_x << 2);
	}else{
		GPIOA->CRL |= PA_ALL;
		GPIOA->CRL &= PA_ALL;
	}
}

/*
 * 点亮LEDx
 */
void LED_ON(uint16_t LEDx)
{
	GPIOA->ODR |= LEDx;
}


/*
 * 熄灭LEDx
 */
void LED_OFF(uint16_t LEDx)
{
	GPIOA->ODR &= ~LEDx;
}


/*
 * 翻转LEDx
 */
void LED_Turn(uint16_t LEDx)
{
	/* 如果是关闭那么就打开,如果是打开那么就关闭 */
	if((GPIOA->ODR & LEDx) == 0)//关闭
	{
		LED_ON(LEDx);
	}else{
		LED_OFF(LEDx);
	}
}

③LED.h的文件代码如下:

#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"                  // Device header

#define PA_0  0x00000003 //GPIO_CRH_MODE0
#define PA_1  0x00000030 //GPIO_CRH_MODE1
#define PA_2  0x00000300 //GPIO_CRH_MODE2
#define PA_3  0x00003000 //GPIO_CRH_MODE3
#define PA_4  0x00030000 //GPIO_CRH_MODE4
#define PA_5  0x00300000 //GPIO_CRH_MODE5
#define PA_6  0x03000000 //GPIO_CRH_MODE6
#define PA_7  0x30000000 //GPIO_CRH_MODE7
#define PA_ALL  0x33333333 //GPIO_CRH_MODE

#define LED0 GPIO_ODR_ODR0
#define LED1 GPIO_ODR_ODR1
#define LED2 GPIO_ODR_ODR2
#define LED3 GPIO_ODR_ODR3
#define LED4 GPIO_ODR_ODR4
#define LED5 GPIO_ODR_ODR5
#define LED6 GPIO_ODR_ODR6
#define LED7 GPIO_ODR_ODR7

void LED_Init(uint32_t PA_x);
void LED_ON(uint16_t LEDx);
void LED_OFF(uint16_t LEDx);
void LED_Turn(uint16_t LEDx);

#endif

④主函数文件的代码如下:

#include "stm32f10x.h"                
#include "Delay.h"
#include "LED.h"
#include "Key.h"

/*
	使用外部中断按键控制LED
*/
int main(void)
{
	LED_Init(PA_0);//初始化PA0引脚
	Key_EXTI_Init();//初始化PB0引脚的EXTI
  
	while(1)
	{
        
	}
}

实物演示效果如下:

外部中断

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值