STM32入门开发实战(六)——射式红外传感器计次操作详解

目录

  • 一、项目准备
  • 1. 工程模板
  • 2. 器件接线
  • 二、外部中断
  • 三、计数传感器模块
  • CountSensor.c
  • CountSensor.h
  • 四、遮光计数
  • 一、项目准备

    1. 工程模板

      本篇项目所用模板包含以下模块,声明函数见头文件,模块添加和函数功能详见往期记录。
    请添加图片描述

    2. 器件接线

      主装置:ST-Link仿真器,STM32系统板,MB102面包板,OLED显示屏(接线详见往期记录)

      除了A15B3B4JLINK的调试端口,其他端口可随意使用。各类器件默认接线方式如下。

    器件 端口/电源
    3.3/VCC +
    GND
    OLED-SCL B8
    OLED-SDA B9
    Sensor-DO B13

      增加模块:对射式红外传感器(B13端口)

    请添加图片描述
      观察传感器,默认输出高电平,开关指示灯点亮;挡光片遮住红外射线时,输出低电平,开关指示灯熄灭

    二、外部中断

      在单片机执行程序的过程中,有时会出现特定触发条件,使得CPU暂时停止当前程序的执行,转而去执行处理该事件的程序,事件处理完毕后再返回原程序继续执行

      这个过程被称为中断,触发条件称为中断源,紧急处理的程序称为中断程序,中断的发生需要经过响应处理返回三个阶段。中断源可以来自外部或者内部,中断也可分为硬件中断软件中断

      当有多个中断源申请中断时,会根据中断优先级裁决,给出响应顺序。当中断程序运行时,接收到了更高优先级的中断申请,会再次触发中断,这就是中断嵌套

    请添加图片描述

      当外部设备传来突变信号时,如果不及时处理会导致数据覆盖丢失,这时我们希望CPU能执行外部中断,也就是本项目的构建原理:

    1. 开启时钟RCC,保证以下外设正常工作;
    2. 配置通用型输入输出端口GPIO,接收红外传感器的信号;
    3. 配置复用型输入输出端口AFIO,选择中断引脚传入数据;
    4. 配置外部中断事件控制器EXTI,边沿检测信号,发送中断申请;
    5. 配置嵌套中断向量控制器NVIC,分配优先级以管理中断;
    6. 中央处理器CPU执行中断。

    请添加图片描述
      其中,AFIO外设充当数据选择器的作用,所以相同的引脚是不能同时触发中断的,例如,GPIOA1GPIOB1GPIOC1的信号都会被导入中断通道1

      而AFIO外设的中断优先级优先级寄存器4(0~15)决定,抢占优先级高的可以中断嵌套响应优先级高的可以优先排队,两者均相同则按中断号排队。

    分组 位数 抢占优先级取值 响应优先级取值
    0 0 0 0~15
    1 1 0~1 0~7
    2 2 0~3 0~3
    3 3 0~7 0~1
    4 4 0~15 0

    三、计数传感器模块

      装置接入电脑后,由于GPIO外设配置为上拉输入模式,传感器会默认向B13端口输出高电平,该信号经AFIO外设由13通道向内传递,由于EXTI外设配置为下降沿触发,所以仅当电平下降时触发中断

      当挡光片遮住红外射线时,输出转为低电平,中断请求发送至NVIC内核外设(由于只设置了一个中断,优先级可在范围内随意设定),状态寄存器标志位1

      主程序暂停,执行中断程序EXTI15_10_IRQHandler(void),计数增加后,待B13端口输入电平恢复正常,挡光片已移开,再重置标志位,主程序继续执行CountSensor_Get(void),并更新计数。

      当然,与按键抖动同理,挡光速度不够快也会产生电平抖动,导致一次挡光产生多个下降沿

      此外,该中断程序调用的函数在模块内部运行,无需在头文件向外部声明。

    CountSensor.c

    #include "stm32f10x.h"
    
    uint16_t CountSensor_Count;		// 次数
    
    // 计数传感器初始化
    void CountSensor_Init(void)
    {
    	// 开启外设时钟:外设EXTI、NVIC除外,内核外设不受RCC控制
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	// 外设GPIOB
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	// 外设AFIO
    	
    	// 配置结构体参数
    	GPIO_InitTypeDef GPIO_InitStructure;
     	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;			// 上拉输入模式:默认高电平
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 最大速度50MHz
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;				// 13号引脚
    	// 初始化PB13端口
     	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	
    	
    	// 配置中断线路:13号
    	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource13);
    	
     	// 配置结构体参数
    	EXTI_InitTypeDef EXTI_InitStructure;
     	EXTI_InitStructure.EXTI_Line = EXTI_Line13;				// 13号中断线路
    	EXTI_InitStructure.EXTI_LineCmd = ENABLE;				// 中断线状态:使能
    	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;		// 中断模式	
    	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;	// 下降沿触发
    	// 初始化外部中断事件控制器
     	EXTI_Init(&EXTI_InitStructure);
    	
    	// 配置中断优先级:分组2
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	
    	// 配置结构体参数
    	NVIC_InitTypeDef NVIC_InitStructure;
     	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;		// 中断请求通道:10~15号
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				// 中断请求通道状态:使能
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	// 抢占优先级:1	
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			// 响应优先级:1
    	// 初始化嵌套中断向量控制器:10~15号中断请求通道
     	NVIC_Init(&NVIC_InitStructure);
    }
    
    // 中断请求通道控制
    void EXTI15_10_IRQHandler(void)
    {
    	// 检查中断线请求状态寄存器的标志位
    	if(EXTI_GetITStatus(EXTI_Line13) == SET)	// 14号中断线:中断源触发
    	{
    		CountSensor_Count ++;									// 计次
    		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13)==0);	// 等待输入电平恢复
    		EXTI_ClearITPendingBit(EXTI_Line13);					// 重置标志位
    	}
    }
    
    // 获取统计次数
    uint16_t CountSensor_Get(void)
    {
    	return CountSensor_Count;
    }
    
    

    CountSensor.h

    #ifndef __COUNTSENSOR_H
    #define __COUNTSENSOR_H
    
    void CountSensor_Init(void);
    uint16_t CountSensor_Get(void);
    
    #endif
    
    

    四、遮光计数

    #include "stm32f10x.h"		// 器件模块
    #include "OLED.h"			// OLED模块
    #include "CountSensor.h"	// 计数传感器模块
    
    int main(void)
    {	
    	// 初始化
    	OLED_Init();
    	CountSensor_Init();
    	
    	// 显示计数
    	OLED_ShowString(1, 1, "Count:");
    	while(1)
    	{
    		OLED_ShowNum(1, 7, CountSensor_Get(), 5);
    	}
    }
    
    

    作者:dandellion_

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32入门开发实战(六)——射式红外传感器计次操作详解

    发表回复