STM32外部中断(红外传感器与旋转编码器计数案例)



一、介绍部分

简介中断系统

在这里插入图片描述

中断执行流程

在这里插入图片描述

STM32中断

在这里插入图片描述
在这里插入图片描述
此地址是用于编译器来跳转到中断函数的地址

NVIC基本结构

NVIC作用是为CPU分配各个中断优先级,然后直接告诉CPU先执行的中断函数。

在这里插入图片描述

NVIC优先级分组

在这里插入图片描述

外部中断

外部中断简介

在这里插入图片描述

外部中断基本结构

在这里插入图片描述

外部中断的流程

**

AFIO先从GPIOA、GPIOB、GPIOC中选择16个不同Pin值的引脚(如不能同时有GPIOA 的PIN_1或GPIOB的PIN_1),以此来选出16个中断通道,然后选择这些中断是否是跳转到其他外设,不是的话就会通过NVIC来配置要打开的中断通道、中断通道的优先级,最后按照优先级顺序依次交予CPU执行

**

AFIO

在这里插入图片描述

EXTI框图

在这里插入图片描述

相关外设介绍

旋转编码器介绍

在这里插入图片描述

硬件电路

在这里插入图片描述

对射式红外传感器

两个面板对射红外线,被遮挡恢复一次后就会产生一个电平变化。
在这里插入图片描述

二、代码实现

对射式红外传感器计次

让对射式红外传感器每被遮挡一次时,让OLED显示的数字+1

连接电路

在这里插入图片描述

封装红外传感器与中断函数

IRSensor.c

#include "stm32f10x.h"                  // Device header
// 初始化
void IRSensor_Init(void){
	// 配置时钟(红外传感器与外部中断所需)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	// 初始化端口
	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_InitTypeDef EXTI_InitStructure;
	// 选择中断线,14号端口对应14号线
	EXTI_InitStructure.EXTI_Line = EXTI_Line14;
	// 是否开启这条中断线
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	// 中断模式还是事件模式
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	// 触发方式,下降沿触发
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	// 设置中断优先级组
	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;
	// 相应优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
}
// 用于计数
uint16_t Count = 0;
// 获取计数器的值
uint16_t GetCount(void){
	return Count;
}

// 中断函数
void EXTI15_10_IRQHandler(void){
	// 获取中断线是否打开
	if(EXTI_GetITStatus(EXTI_Line14) == SET){
		// 如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0){
			// 计数器+1
			Count++;
		}
		// 清除中断
		EXTI_ClearITPendingBit(EXTI_Line14);
	}
}

主函数main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "IRSensor.h"

int main(void)
{
	OLED_Init();
	IRSensor_Init();
	OLED_ShowString(1,1,"Count:");
	while (1)
	{
		OLED_ShowNum(2,1,GetCount(),4);
	}
}

旋转编码器计数

连接电路

在这里插入图片描述

封装旋转编码器函数、外部中断函数

有多条中断线时,要分别初始化,不能有相同的优先级,不过定义的初始化结构体可以重复使用。

Encoder.c内容

#include "stm32f10x.h"                  // Device header

uint16_t EncoderCount;
void Encoder_Init(void){
	// 配置时钟(红外传感器与外部中断所需)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	// 初始化端口
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	// 配置AFIO引脚选择
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
	
	EXTI_InitTypeDef EXTI_InitStructure;
	// 选择中断线
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
	// 是否开启这条中断线
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	// 中断模式还是事件模式
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	// 触发方式,下降沿触发
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	// 设置中断优先级组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	// 为两个通道分别初始化配置优先级
	NVIC_InitTypeDef NVIC_InitStructure;
	// 中断通道
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
	// 是否打开通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	// 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	// 相应优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	// 中断通道
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
	// 是否打开通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	// 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	// 相应优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&NVIC_InitStructure);
}

// 获取计数数据
uint16_t Encoder_Get(void){
	uint16_t Temp;
	Temp = EncoderCount;
	EncoderCount = 0;
	return Temp;
}

// 中断函数
void EXTI0_IRQHandler(void){
	if(EXTI_GetITStatus(EXTI_Line0) == SET){
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
			EncoderCount++;
		// 清除此中断通道标志
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}
void EXTI1_IRQHandler(void){
	if(EXTI_GetITStatus(EXTI_Line1) == SET){
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0) == 0)
			EncoderCount--;
		// 清除此中断通道标志
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}

主函数main.c内容

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Encoder.h"

int16_t Num;
int main(void)
{
	OLED_Init();
	Encoder_Init();
	OLED_ShowString(1,1,"Num:");
	while (1)
	{
		// 每次的数加旋转的数
		Num += Encoder_Get();
		OLED_ShowSignedNum(2,1,Num,5);
	}
}


补充

两种获取中断标志与清除标志函数
前两中适用于普通函数执行
后两种适用于中断函数中执行

// 获取中断线标志
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
// 清除此中断线标志
void EXTI_ClearFlag(uint32_t EXTI_Line);
// 获取中断线标志
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
// 清除此中断线标志
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

中断函数可以在开始文件中寻找
在这里插入图片描述

  • 36
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32外部中断编码器是一种常见的应用场景,可以用于监测外部事件的触发和计数编码器是一种用于测量物理运动的装置,通常用于测量转速、角度和位置等参数。STM32外部中断编码器使用GPIO引脚作为输入接口,通过编码器产生的脉冲信号来触发外部中断。下面是一个简要的编码器外部中断的编程示例。 首先,需要在STM32的GPIO引脚上进行配置,将其设置为外部中断输入模式。通过RCC_ClkInitStruct结构体对外部中断的时钟进行初始化,然后对相应的GPIO引脚进行配置,设置为中断输入模式。 接下来,需要配置外部中断的触发方式。可以选择边沿触发方式或者电平触发方式。编码器通常使用边沿触发方式,这样每一次脉冲的上升沿或下降沿都会触发中断。使用EXTI_InitStructure结构体对外部中断进行配置。 在主程序中,可以编写相应的中断服务子程序(ISR)来处理外部中断。当编码器的脉冲信号触发中断时,ISR会被自动调用。在ISR中,可以进行相应的处理,例如计数器的自增、反向检测等。编码器一般具有两个输出信号(A、B相),可以通过读取GPIO引脚的状态来确定脉冲方向。 最后,在主程序中,可以读取计数器的值来获取编码器计数结果。可以根据需要进行数据处理和显示。 总之,STM32外部中断编码器是一种常见的应用,可以通过编程实现外部中断的触发和计数功能。通过合理的配置和编程,可以实现精准、稳定的应用效果。以上是对STM32外部中断编码器的简要介绍和编码示例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值