【stm32】对射式红外传感器计次以及旋转编码器计次

对射式红外传感器计次

1. 将传感器的功能分装在一个模块里CountsSenser

2.配置外部中断

1.配置RCC,将涉及的外设的时钟都打开

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

3.配置AFIO,选择前面使用的一路GPIO,连接到后面的EXTI

4.配置EXTI,选择边沿触发方式

5.配置NVIC,给中断选择一个合适的优先级

c 复制代码
void GPIO_AFIODeInit(void);

复位AFIO

c 复制代码
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

锁定GPIO引脚配置,防止意外更改

c 复制代码
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_EventOutputCmd(FunctionalState NewState);

配置AFIO的事件输出功能

c 复制代码
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

用来进行引脚重映射,第一个参数可以选择重映射的方式,第二个参数是新的状态

c 复制代码
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

配置AFIO的数据选择器,选择想要的中断引脚

EXTI库函数

c 复制代码
void EXTI_DeInit(void);

把Exti的配置都清除,恢复成上电默认的状态

c 复制代码
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

可以根据这个结构体里的参数配置EXTI外设,初始化EXTI

c 复制代码
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);

可以把参数传递的结构体变量赋一个默认值

c 复制代码
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);

软件触发外部中断

在外设运行的过程中,会产生一些状态标志位,放在状态寄存器中,当程序想要看到这些标志位时,就可以用下面四个函数:

在主程序里:

c 复制代码
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);

可以获取指定的标志位是否被置1

c 复制代码
void EXTI_ClearFlag(uint32_t EXTI_Line);

可以对置1的标志位进行清除

在中断函数里:

c 复制代码
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);

获取中断标志位是否被置1

返回值为SET/RESET

c 复制代码
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

清除中断挂起标志位

NVIC库函数

c 复制代码
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

用来中断分组,参数是中断分组的方式

分组方式整个芯片只能用一种,按理说分组代码整个工程只需要执行一次就行;如果将它放在模块里面进行分组,要确保每个模块分组都选的是同一个;也可以将它放在主函数的最开始,这样模块里就不用再分组了

c 复制代码
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

根据结构体里面指定的参数初始化NVIC

c 复制代码
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);

设置中断向量表

c 复制代码
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);

系统低功耗配置

代码:

c 复制代码
void CountSenser_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB , &GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB , GPIO_PinSource14);
	
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = EXTI_Line14 ;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStruct);
	
	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);
}

中断函数

中断函数的名字是固定的,每个中断通道都对应一个中断函数,中断函数的名字参考启动函数,其中以

IRQHandler结尾的字符串就是中断函数的名字

c 复制代码
void EXTI15_10_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line14) == SET)
	{
		CountSensor_Count ++;
		EXTI_ClearITPendingBit(EXTI_Line14);
	}
}

旋转编码器计次

新建Encoder.c和Encoder.h

例:旋转编码器接PB0和PB1

Encoder.c

c 复制代码
int16_t Encoder_Count;

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_IPD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB , &GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB , GPIO_PinSource0);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB , GPIO_PinSource1);
	
	
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line = EXTI_Line0 | EXTI_Line1;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStruct);
	
	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);
}

int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = Encoder_Count;
	Encoder_Count = 0;
	return Temp;
}
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0) == SET)
	{
		if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
		{
			Encoder_Count --;
		}
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}

void EXTI1_IRQHandler(void)
{
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
		{
			Encoder_Count ++;
		}
	if(EXTI_GetITStatus(EXTI_Line1) == SET)
	{
		EXTI_ClearITPendingBit(EXTI_Line1);
	}
}

main.c

c 复制代码
int16_t Num;

int main(void)
{
	OLED_Init();
	Encoder_Init();
	
	while(1)
	{
		Num += Encoder_Get();
		OLED_ShowSignedNum(1, 5, Num, 5);
	}
}

注:
1.中断函数里,最好不要执行耗时过长的代码,中断函数要简短快速,不要刚进中断就执行Delay,因为中断是处理突发的事情,如果为了一个突发的事情待在中断里不出来了,主程序就会收到严重阻塞

2.最好不要在中断函数和主函数调用相同的函数或者操作同一个硬件,尤其是硬件相关的函数,在实现功能的时候,可以在中断里操作变量或者标志位,当中断返回时,再对这个变量进行显示和操作,这样既能保证中断函数的简短快速,又能保证不产生冲突的硬件操作

注:

该文章为b站江协课程,为笔记

相关推荐
辰哥单片机设计2 分钟前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件
風清掦1 小时前
【江科大STM32学习笔记-05】EXTI外部中断11
笔记·stm32·学习
小龙报1 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机
范纹杉想快点毕业1 小时前
嵌入式与单片机开发核心学习指南——从思维转变到第一性原理的深度实践
单片机·嵌入式硬件
Industio_触觉智能1 小时前
瑞芯微RK3566开发板规格书,详细参数配置,型号EVB3566-V1,基于RK3566核心板SOM3566邮票孔封装
嵌入式硬件·开发板·rk3568·rk3566·核心板·瑞芯微
czwxkn2 小时前
4STM32(stdl)TIM定时器
stm32·单片机·嵌入式硬件
Love Song残响2 小时前
NVIDIA显卡终极优化指南
stm32·单片机·嵌入式硬件
qq_672592752 小时前
电源芯片为什么发热
单片机·嵌入式硬件
天天爱吃肉82182 小时前
【跨界封神|周杰伦×王传福(陶晶莹主持):音乐创作与新能源NVH测试,底层逻辑竟完全同源!(新人必看入行指南)】
python·嵌入式硬件·算法·汽车
国科安芯3 小时前
抗辐照MCU在精密时频系统中的单粒子效应评估与可靠性验证
单片机·嵌入式硬件·架构·制造·安全性测试