STM32GPIO的输入——按键控制LED&光敏传感器控制蜂鸣器(3-3)

目录

一、按键介绍

二、传感器模块介绍 

三、硬件电路

四、按键控制LED

1、硬件接线图

2、新建Hardware文件夹

3、常用GPIO的读取函数

4、程序

5、实物展示

五、光敏传感器控制蜂鸣器

1、硬件接线图

2、程序

3、实物展示


一、按键介绍

        按键:最常见的输入设备,按下导通,松手断开。

        下面这个图就是江科大套件中的按键实物图,左边白色的是按钮,右边是它的两个月引脚,按下去的时候,下面两个引脚是接通的,松手后,这两个引脚就自动断开了。

        按键抖动:由于按键内部使用的是机械式弹簧片来进行通断的,所以在按下和松手的瞬间会伴随有一连串的抖动。

        通过下面的波形可以看到,假设按键没按下是高电平,按下了就是低电平,在按下的瞬间,信号由高电平变为低电平时,就会来回抖动几下,这个抖动会比较快,通常在5~10ms之间,人眼是分辨不出来的,但是对于高速运行的单片机而言,5~10ms的时间还是很漫长的,所以我们要对这个抖动进行过滤,否则就会出现按键按一下,单片机却反映了多次的现象,另外在按键松手的时候,也会有一小段时间的抖动,这个在程序中也要注意过滤一下。

        最简单的过滤方法,就是加一段延时,把这个抖动时间耗过去了,这样就没问题了。 


二、传感器模块介绍 

        在江科大的套件中,一共提供了四种传感器模块,分别是光敏电阻传感器,热敏电阻传感器,对射式红外传感器,反射式红外传感器,它们的电路结构和工作原理都差不多。

        传感器模块:上面四种传感器元件的电阻会随外界模拟量的变化而变化,比如光线越强,光敏电阻的阻值就越小,温度越高,热敏电阻的阻值就越小,红外光线越强,红外接收管的阻值就越小,但是电阻的变化不容易直接被观察,所以通常将传感器元件与定值电阻进行串联分压,即可得到模拟电压的输出,对电路来说,检测电压就非常容易了。另外这些模块还可以通过电压比较器,来对这个模拟电压进行二值化,即可得到数字电压输出。

        上面就是传感器模块的基本电路,右下角的N1就是传感器元件所代表的可变电阻,它的阻值可以根据环境的光线、温度等模拟量进行变化,上面的R1,是和N1进行分压的定值电阻,R1和N1串联,一端接在VCC正极,一端接在GND负极,这就构成了基本的分压电路。左边的C2是一个滤波电容,它是为了给中间的电压输出进行滤波的,用来滤除一些干扰,保证输出电压波形的平滑。

        用上下拉电阻的思维来分析一下传感器电阻的阻值变化对输出电压的影响,当这个N1阻值变小时,下拉作用就会增强,中间的AO端的电压就会被拉低,极端情况下,N1阻值为0,AO输出被完全下拉,输出0V;当N1阻值变大,下拉作用就会减弱,中间的引脚由于R1的上拉作用,电压就会升高,极端情况下,N1阻值无穷大,相当于断路,输出电压被R1拉高至VCC。

        在两个电阻的分压下,AO就是我们想要的模拟电压输出,AO电压就直接通过排针输出了,如下图所示。

        右边这里还有两个指示灯电路,左边是电源指示灯,通电就亮,右边是DO输出指示灯,它可以指示DO的输出电平,低电平亮,高电平熄灭,再右边DO这里还多了个R5上拉电阻,这个是为了保证默认输出为高电平,然后就是最右边P1的排针,分别是VCC、GND、DO和AO。

        这个模块还支持数字输出,这个数字输出就是对AO进行二值化的输出,这里二值化是通过下图这个芯片LM393来完成的,这个LM393是一个电压比较器芯片,里面有两个独立的电压比较器电路,然后剩下的是VCC和GND供电,VCC就接到了电路的VCC,GND也接到了电路的GND,这里左边还有一个电容,是一个电源供电的滤波电容,这个电压比较器其实就是一个运算放大器。

        实际应用情况,这里同向输入端IN+接到了AO这里,就是模拟电压端,IN-接了一个电位器,这个电位器的接法也是分压电阻的原理,拧动电位器,IN-就会生成一个可调的阈值电压,两个电压进行比较,最终输出结果就是DO,数字电压输出,DO最终就接到了引脚的输出端,这就是数字电压的由来。

        以上就是四个传感器模块,对于左数第一个光敏电阻传感器来说,这个N1就是光敏电阻;对于第二个热敏电阻传感器来说,这个N1就是热敏电阻。
        对于第三个红外传感器来说,这个N1就是一个红外接收管,当然对应还会多一个点亮红外发射管的电路,发射管发射红外光,接收管接收红外光,模拟电压就表示的是接收光的强度,电位器是直接换成了两个电阻进行分压,这样数字输出就是固定阈值的二值化了, 这个模块通常用来检测通断,所以阈值也不需要过多的调整。
        最后一个模块也是一个红外发射管和接收管,只不过它是向下发射红外光的,然后检测反射光的,这个可以用来做寻迹小车。


三、硬件电路

        按键的硬件电路,共四种接法,上面两个是下接按键的方式,下面两个是上接按键的方式,一般来说,按键都是用上两种方式,也就是下接的方式,这个原因跟LED的接法类似,是电路设计的习惯和规范。

        第一个图是按键最常用的接法,在这里随便选取一个GPIO口,比如PA0,然后通过K1接到地,然后通过K1接到地,当按键按下时,PA0被直接下拉到GND,此时读取PA0口的电压就是低电平,当按键松手时,PA0被悬空,所以这种接法下,必须要求PA0是上拉输入的模式,否则就会出现引脚电压不确定的错误现象,如果PA0是上拉输入模式,引脚悬空时,PA0默认为高电平,所以上拉模式下,下按键,引脚为低电平,松开按键,引脚为高电平,本课程也是采用这个接法。

        第二个图相比较第一个图,这里外部接了一个上拉电阻,这个上拉可以想象成一个弹簧,把这个端口向上拉,当按键松手时,引脚由于上拉作用,自然保持为高电平,当按键按下时,引脚直接接到GND,也就是一股无穷大的力把这个引脚往下拉,所以引脚为低电平,这种状态下,引脚不会出现悬空状态,所以此时PA0引脚可以配置为浮空输入或者上拉输入

        第三个图中,PA0通过按键接到3.3V,必须要求PA0配置成下拉输入的模式当按键按下时,引脚为高电平,松手时,引脚回到默认值低电平

        第四个图就是在第三个图基础上下拉一个电阻,这个接法PA0需要配置成下拉输入模式或者浮空输入模式

        上图为传感器模块电路,VCC接3.3V,GND接GND,用于供电,DO数字输出随便接一个端口,比如PA0,用于读取数字量,AO模拟输出之后学到ADC模数转换器的时候再用,现在暂时不用接。 


四、按键控制LED

1、硬件接线图

2、新建Hardware文件夹

Hardware文件夹用来存放硬件驱动的.c和.h文件,按之前步骤添加文件夹。

 

然后将之间控制LED的程序,模块化后将其.c和.h文件放入Hardware文件夹中。

在Keil软件中,右键Hardware文件夹,选择增加文件,分别选择.c和.h文件,改名为LED,然后在最后的Location中,点击最右边的三个点,把路径选择为Hardware文件夹。

这样就增加成功了LED的模块化文件,接下来编辑.c文件。

如果在编辑过程中,没有显示代码提示,可以按下快捷键Ctrl+Alt+空格,如果还没有显示,可以看看输入法设置是否快捷键冲突了。

在每个文件输入完程序后,记得再最后多留一个空格行,不然可能会出现警告。

下面编辑.h文件,编辑完成后,在头文件用#include声明,即可在主函数中调用LED模块。

如果出现警告或者错误,可能是软件还没有检测到刚刚编写的模块,编译一下,如果是0错误,0警告,就没问题的。

由上面步骤,同样可以把按键模块Key加入到Hardware文件夹中,程序放下面。

3、常用GPIO的读取函数

1.uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

这个函数是用来读取输入数据寄存器某一个端口的输入值,参数是GPIOx和GPIO_Pin,用来指定某一个端口。

返回值是uint8_t,代表这个端口的高低电平。


2.uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

这个函数比上一个函数少了一个Bit,它是用来读取整个输入数据寄存器的,参数只有一个GPIOx,用来指定外设。

返回值是uint16_t,是一个16位的数据,每一位代表一个端口值。


3.uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

这个函数是用来读取输出数据寄存器的某一位,所以它并不是用来读取端口的输入数据的,这个函数一般用于输出模式下,用来看一下自己输出的是什么。


4.uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

这个函数比上一个函数少了一个Bit,是用来读取整个输出寄存器的。

4、程序

主函数

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

uint8_t KeyNum;

int main(void)													
{
	LED_Init();
	Key_Init();
	while(1)
	{
		KeyNum = Key_GetNum();
		if(KeyNum == 1)
		{
			LED1_Turn();
		}
		if(KeyNum == 2)
		{
			LED2_Turn();
		}
	}
}

LED模块

#include "stm32f10x.h"                  // Device header


/**
  * @brief  LED初始化
  * @param  无
  * @retval 无
  */

void LED_Init(void)												
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);		//使能时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;                		//定义结构体变量
																//GPIO_InitTypeDef结构体类型,
																//GPIO_InitStructure名字
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   			//GPIO模式选择
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;      //GPIO引脚选择
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   		//GPIO传输速度选择
	GPIO_Init(GPIOA, &GPIO_InitStructure);              		//调用Init函数

	 GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}


/**
  * @brief  点亮LED1
  * @param  无
  * @retval 无
  */

void LED1_ON(void)												
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}


/**
  * @brief  熄灭LED1
  * @param  无
  * @retval 无
  */

void LED1_OFF(void)												
{
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}


/**
  * @brief  取反LED1
  * @param  无
  * @retval 无
  */

void LED1_Turn(void)											
{
	if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)			//读取当前的端口输出状态
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_1);						//如果当前输出0,就置1
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);						//如果当前输出1,就清0
	}
}

/**
  * @brief  点亮LED2
  * @param  无
  * @retval 无
  */

void LED2_ON(void)												
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}

/**
  * @brief  熄灭LED2
  * @param  无
  * @retval 无
  */

void LED2_OFF(void)												
{
	GPIO_SetBits(GPIOA, GPIO_Pin_2);
}

/**
  * @brief  取反LED2
  * @param  无
  * @retval 无
  */

void LED2_Turn(void)											
{
	if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)			//读取当前的端口输出状态
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);						//如果当前输出0,就置1
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);						//如果当前输出1,就清0
	}
}

Key模块

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


/**
  * @brief  按键初始化
  * @param  无
  * @retval 无
  */

void Key_Init(void)												
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;                		//定义结构体变量
																//GPIO_InitTypeDef结构体类型,
																//GPIO_InitStructure名字
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   			//GPIO模式选择
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;     //GPIO引脚选择
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   		//GPIO传输速度选择
	GPIO_Init(GPIOB, &GPIO_InitStructure);              		//调用Init函数

}


/**
  * @brief  获取按键值
  * @param  无
  * @retval KeyNum,按键按下的按键值,范围1~2
  */

uint8_t Key_GetNum(void)										
{
	uint8_t KeyNum = 0;
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0 )			//读取PB1端口的输入值,返回值为1或0
	{
		Delay_ms(20);											//消除按键抖动
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);	//如果按键一直按下是0,则一直循环
																//如果按键松手,则向下运行程序
		Delay_ms(20);
		KeyNum = 1;
	}
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0 )			//读取PB11端口的输入值,返回值为1或0
	{
		Delay_ms(20);											
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);	
																
		Delay_ms(20);
		KeyNum = 2;
	}
	
	return KeyNum;
}		
	


5、实物展示

按键控制LED


五、光敏传感器控制蜂鸣器

1、硬件接线图

2、程序

主函数

#include "stm32f10x.h"                  						// Device header
#include "Delay.h" 
#include "Buzzer.h"
#include "LightSensor.h"


int main(void)													
{
	Buzzer_Init();
	LightSensor_Init();
	
	while(1)
	{
		if(LightSensor_Get() == 1)			//光线暗时, 光敏传感器向端口输入1
		{
			Buzzer_ON();
		}
		else								//光线亮时, 光敏传感器向端口输入0
		{	
			Buzzer_OFF();					
		}
	}
}

将蜂鸣器模块添加至Hardware文件夹中。

蜂鸣器模块

#include "stm32f10x.h"                  // Device header

/**
  * @brief  蜂鸣器初始化
  * @param  无
  * @retval 无
  */

void Buzzer_Init(void)												
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//使能时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;                		//定义结构体变量
																//GPIO_InitTypeDef结构体类型,
																//GPIO_InitStructure名字
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   			//GPIO模式选择
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;      			//GPIO引脚选择
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   		//GPIO传输速度选择
	GPIO_Init(GPIOB, &GPIO_InitStructure);              		//调用Init函数

	 GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

/**
  * @brief  打开蜂鸣器
  * @param  无
  * @retval 无
  */

void Buzzer_ON(void)												
{
	GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}


/**
  * @brief  关闭蜂鸣器
  * @param  无
  * @retval 无
  */

void Buzzer_OFF(void)												
{
	GPIO_SetBits(GPIOB, GPIO_Pin_12);
}


/**
  * @brief  蜂鸣器取反
  * @param  无
  * @retval 无
  */

void Buzzer_Turn(void)											
{
	if(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0)				//读取当前的端口输出状态
	{
		GPIO_SetBits(GPIOB, GPIO_Pin_12);							//如果当前输出0,就置1
	}
	else
	{
		GPIO_ResetBits(GPIOB, GPIO_Pin_12);							//如果当前输出1,就清0
	}
}

将光敏传感器模块添加至Hardware文件夹中。

光敏传感器模块

#include "stm32f10x.h"                  // Device header

/**
  * @brief  光敏传感器初始化
  * @param  无
  * @retval 无
  */

void LightSensor_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//使能时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;                		//定义结构体变量
																//GPIO_InitTypeDef结构体类型,
																//GPIO_InitStructure名字
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   			//GPIO模式选择
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;      			//GPIO引脚选择
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   		//GPIO传输速度选择
	GPIO_Init(GPIOB, &GPIO_InitStructure);              		//调用Init函数

}


/**
  * @brief  读取光敏传感器输入状态
  * @param  无
  * @retval PB13输入值,光线暗时, 光敏传感器向端口输入1,光线亮时, 光敏传感器向端口输入0
  */

uint8_t LightSensor_Get(void)
{
	return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);			//返回当前端口的输入状态值
}

3、实物展示

光敏传感器控制蜂鸣器

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

剑鞘的流苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值