(STM32学习笔记)中断系统 | EXTI外部中断(对射式红外传感器计次&旋转编码器计次(一))

一、对射式红外传感器计次

  • 硬件连线图
    在这里插入图片描述

  • 配置对射式红外传感器初始化函数 (根据EXTI结构图进行配置)

在这里插入图片描述

使用EXIT的配置顺序如下:

1、配置RCC,打开RCC外设的时钟
EXTI和NVIC的时钟自动开启,不需要手动开启。按理来说EXTI作为一个独立外设需要开启时钟,但是寄存器中没有EXTI时钟的控制位,原因可能与EXTI的唤醒功能或者电路设计考量有关。NVIC是内核的外设,内核的外设都不需要手动开启时钟(RCC也只能管理内核外的外设,对内核里的外设没有操作权限)。

2、配置GPIO,选择端口为输入模式

像这种外设使用GPIO的情况,如果不清楚GPIO应该配置为什么模式,可以参考手册。EXTI输入线推荐配置为浮空输入、带上拉输入或带下拉输入,所以配置哪一种都可以。在这里插入图片描述

3、配置AFIO,用于连接后面的EXTI
对于AFIO外设,ST公司没有给它分配专门的库函数文件,它的库函数和GPIO在同一个库函数中。打开 stm32f10x_gpio.h 文件的最后可以找到以下函数(有些函数在GPIO一节没有讲解到,但是也不常用,这里作统一了解):

// 复位AFIO外设,调用后将清除AFIO的全部配置
void GPIO_AFIODeInit(void);	

// 锁定某个GPIO端口的配置
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);	

// 下面两个函数用来配置AFIO的事件输出功能
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_EventOutputCmd(FunctionalState NewState);

// 进行引脚功能重映射
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

// 配置AFIO实现EXTI中断引脚选择
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

// 配置以太网需要用到的函数(本课程没有涉及)
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);

对于本节课使用的 GPIO_EXTILineConfig 函数,它虽然以GPIO开头,但实际上操作的是AFIO的寄存器:

/**
  * @brief  Selects the GPIO pin used as EXTI Line.
  * @param  GPIO_PortSource: selects the GPIO port to be used as source for EXTI lines.
  *   This parameter can be GPIO_PortSourceGPIOx where x can be (A..G).
  * @param  GPIO_PinSource: specifies the EXTI line to be configured.
  *   This parameter can be GPIO_PinSourcex where x can be (0..15).
  * @retval None
  */
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
{
	uint32_t tmp = 0x00;
	/* Check the parameters */
	assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));
	assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));

	tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));
	AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;
	AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));
}


4、配置EXTI。EXIT的库函数及其作用

// 下面三个函数是一个外设的“模板函数”,即基本所有的外设都拥有以下三个函数,定义和用法都类似
// 清除EXTI的所有配置,清除为上电默认状态
void EXTI_DeInit(void);
// 用结构体变量配置EXTI
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
// 给用来参数配置的结构体变量赋一个默认值
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);

// 软件触发外部中断,调用之后,可以触发指定中断线上的中断
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);

// 接下来的四个函数也是一个外设的“模板函数”,用来查看状态寄存器中保存的外设标志位
// 在主程序中查看标志位和清除标志位用下面两个函数,可以查看任意标志位(不触发中断的标志位也可以读取)
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);	// 获取指定的标志位是否被置1
void EXTI_ClearFlag(uint32_t EXTI_Line);	// 对置1的标志位进行清除(如果不清除就会一直触发中断)
// 在中断函数中查看标志位和清除标志位用下面两个函数,它们只能读写与中断有关的标志位,并且对中断是否允许做出判断
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);	// 查看中断标志位是否被置1
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);	// 清除中断挂起标志位

5、配置NVIC。 NVIC是内核的外设,其库函数定义在misc.h 中。库函数定义如下所示:

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);	// 对中断进行分组,配置抢占优先级pre-emption和响应优先级subpriority
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);	// NVIC的初始化函数
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);	// 设置中断向量表
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);	// 系统低功耗配置
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);

  • 中断函数的使用

在启动文件 startup_stm32f10x_md.s 中的中断向量表中可以找到以IRQHandler 结尾的就是中断函数的名称。
在中断函数中,还需要对中断函数进行标志位判断。因为如果选择EXTI15_10_IRQHandler 函数,EXTI15到EXTI10都能进入函数,如果连接EXTI14,我们需要确定是我们想要的中断源(EXTI14)触发了这个函数。使用 EXTI_GetITStatus 函数判断中断标志位,在中断函数中完成相关功能后还需要使用EXTI_ClearITPendingBit函数清除中断挂起标志位。

注意事项:
(1) 在STM32中中断函数的名称都是固定的。中断函数会自动执行,不需要放到 .h 文件里。
(2) 在中断函数中,需要对中断标志位进行清除,否则中断函数一直执行,程序陷入死循环。

详细配置如下:

1、配置RCC,打开外设的时钟
a: 开启GPIOB时钟
b: 开启AFIO时钟

代码:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //开启AFIO时钟

2、配置GPIO,选择端口为输入模式
代码:

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
GPIO_Init(GPIOB,&GPIO_InitStructure);

3、配置AFIO,用于连接后面的EXTI
tips:ST公司没有专门给AFIO封装专用函数库,在GPIO内附带配置了专用函数。

代码:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);

4、配置EXTI初始化
将EXTI的第14个线路配置为中断模式,下降沿触发,然后开启中断。
代码:

EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line14;//配置EXTI的第14个线路,因为引脚接的是B14
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//开启中断EXTI 
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//选择中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发EXTI 
	
EXTI_Init(&EXTI_InitStructure);

5、NVIC初始化配置
给这个中断选择一个合适的优先级,通过NVIC,外部中断信号进入CPU,CPU收到中断信号,才能跳转到中断函数里执行中断程序。

代码:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组
	
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1 ;//抢占优先级,程序只有一个中断,不管先后,直接选优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级,程只有一个中断,不管先后,直接选优先级均为1
NVIC_Init(&NVIC_InitStructure);

代码:

//中断函数:EXTI15_10_IRQHandler()

void  EXTI15_10_IRQHandler(void)// EXTI引脚范围10~15
{
	//判断是否引脚PB14,返回值为SET
	if(EXTI_GetITStatus(EXTI_Line14) == SET)
	{
		
		Count++; //计数
		//清除标志位
		EXTI_ClearITPendingBit(EXTI_Line14);
	}
		
}

CountSensor.c

void CountSensor_Init(void)
{
//第一步 开启所需要使用的外设的时钟,EXTI和NVIC的时钟自动开启
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//第二步 配置GPIO,选择端口为上拉输入模式
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
//第三步  配置AFIO
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);

//第四步  配置EXTI	
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line14;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE; //开启中断
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI配置为中断触发模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
	EXTI_Init(&EXTI_InitStructure);
	
//第五步  配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC中断优先级分组
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE ;//指定中断通道是使能还是失能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1 ;//NVIC配置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//NVIC配置响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	
uint16_t Count;//定义计次变量
void  EXTI15_10_IRQHandler(void)// EXTI引脚范围10~15
{
	//判断是否引脚B14,返回值为SET
	if(EXTI_GetITStatus(EXTI_Line14) == SET)
	{		
		Count++; //计数
		//清除标志位
		EXTI_ClearITPendingBit(EXTI_Line14);
	}
		
}

uint16_t GetCount()
{
	return Count;
}
}

main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "CountSensor.h"

int main()
{
	OLED_Init();
	OLED_ShowString(1, 1, "Count:");	// 显示一个字符串
	CountSensor_Init();
	
	while(1)
	{
		OLED_ShowNum(1, 7, CountSensor_Get(), 5);
	}
}


二、旋转编码器


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值