【STM32】控制LED灯和蜂鸣器的按键实验

这篇具有很好参考价值的文章主要介绍了【STM32】控制LED灯和蜂鸣器的按键实验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🐱作者:一只大喵咪1201
🐱专栏:《STM32学习》
🔥格言:你只管努力,剩下的交给时间!
stm32f103zet6触摸版控制蜂鸣器,STM32学习,单片机,stm32,嵌入式硬件

描述

本喵这次介绍的实验是按键实验,同样使用STM32F103ZE型号的芯片,在开发板上有4个按键,实验目的是每按一个按键就会让LED灯或者是蜂鸣器的工作状态发生反转,下面本喵来详细介绍。

用到的相关寄存器

GPIO

IO口在单片机的使用中是最多的,此次实验用到了LED灯,蜂鸣器,以及3个按键,所以也使用到了IO口。

IDR

叫做端口数据输入寄存器(GPIOX_IDR),读取它的信息就能获得IO口上的状态,是作输入使用的。
stm32f103zet6触摸版控制蜂鸣器,STM32学习,单片机,stm32,嵌入式硬件
这是它每一位的对应关系,可以看到,IDR寄存器是一个32位的寄存器,但是只有低16位在使用,而且是只读类型的,高16位保留,如果读的话结果就是0。低16位从0到15对应的该组IO口标号从0到15引脚上的数据信息,而且只能以16位的形式读取数据。

ODR

LED灯和蜂鸣器的使用会用到端口数据输出寄存器(GPIOX_ODR),在跑马灯实验中曾详细介绍过GPIO里一些寄存器的使用,有兴趣的小伙伴可以移步到跑马灯实验这篇文章中参考一下。

RCC

时钟的配置是使用任何一个外设都要设置的,这里也不例外,同样在跑马灯实验这篇文章中讲述过时钟使能的配置。

确定位置

LED灯

LED0与PB5相连,LED1与PE5相连,详情参考跑马灯实验这篇文章。

蜂鸣器

我们来看开发板原理图。
stm32f103zet6触摸版控制蜂鸣器,STM32学习,单片机,stm32,嵌入式硬件
可以将BEEP看作是蜂鸣器,它与PB8相连。
stm32f103zet6触摸版控制蜂鸣器,STM32学习,单片机,stm32,嵌入式硬件
这是它的具体电路,当BEEP是低电平时,蜂鸣器不会响,当BEEP是高电平时,通过三极管的放大作用,就会使蜂鸣器发出响声。

按键

stm32f103zet6触摸版控制蜂鸣器,STM32学习,单片机,stm32,嵌入式硬件
可以看到,按键KEY0与PE4相连,按键KEY1与PE3相连,按键KEY2与PE2相连。
stm32f103zet6触摸版控制蜂鸣器,STM32学习,单片机,stm32,嵌入式硬件
按键WK_UP与PA0相连。
stm32f103zet6触摸版控制蜂鸣器,STM32学习,单片机,stm32,嵌入式硬件
根据按键的电路图可以发现,KEY0,KEY1,KEY2这三个按键的另一端是和地相连接的,也就是当按键按下去时是低电平,未按下时是高电平,所以这3个键采用上拉输入模式。
WK_UP键的另一端连接的是3.3V的高电平,当键按下去时是高电平,未按下时是低电平,所以采用下拉输入模式。

程序及分析

不支持连续按

当有键按下并且没有松开,只作一次键输入,不当作连续输入。
led.h中的代码

#ifndef __LED_H
#define __LED_H

void LED_Init(void);

#endif


led.c中的代码

#include "stm32f10x.h"//顶级头文件引用
#include "led.h"

void LED_Init()
{
	GPIO_InitTypeDef GPIO_InitStruct;//创建GPIO结构体变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE,ENABLE);//PB组和PE组IO口时钟使能
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//引脚5
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//输出最大速度是50MHZ
	
	GPIO_Init(GPIOB,&GPIO_InitStruct);//PB5初始化
	GPIO_SetBits(GPIOB,GPIO_Pin_5);//PB5初始化为高电平,LED0灭
	
	GPIO_Init(GPIOE,&GPIO_InitStruct);//PE5初始化
	GPIO_SetBits(GPIOE,GPIO_Pin_5);//PE5初始化为高电平,LED1灭
}

beep.h中的代码

#ifndef __BEEP_H
#define __BEEP_H

void BEEP_Init(void);

#endif

beep.c中的代码

#include "stm32f10x.h"//顶级头文件引用
#include "beep.h"

void BEEP_Init()
{
	GPIO_InitTypeDef GPIO_InitStruct;//创建GPIO结构体变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//在LED初始化函数中已经将PB组IO口使能过了,这里可以不使能
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;//引脚5
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//输出最大速度是50MHZ
	
	GPIO_Init(GPIOB,&GPIO_InitStruct);//PB8初始化
	GPIO_ResetBits(GPIOB,GPIO_Pin_8);//PB5初始化为低电平,蜂鸣器不响
}

key.h中的代码

#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"//引用顶级头文件
#include "sys.h"//使用位带操作的头文件
#define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)
#define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//宏定义按键名就是IO的值

#define KEY0_PRES 1
#define KEY1_PRES 2
#define KEY2_PRES 3
#define WK_UP_PRES 4//定义键按下后返回的值

#define LED0 PBout(5)
#define LED1 PEout(5)
#define beep PBout(8)//使用位带操作加宏定义,直接对硬件名字进行操作

void KEY_Init(void);

uint8_t KEY_Scan(void);//键盘扫描函数
#endif

这里充分使用了宏定义,将每个硬件的名字都赋予了意义,在主程序中直接对硬件名字操作以及使用就可以。
为了方便改变LED灯以及蜂鸣器的状态,我们使用位带操作的方法,这样就可以直接对LED灯以及蜂鸣器的状态进行取反。
其中unit8_t类型的变量是STM32固件库中定义的变量类型。

typedef unsigned          char uint8_t;

可以看到,它的本质是一个无符号的char类型,大小只有一个字节。因为STM32的空间比较小,尽量使用占内存较小的变量。

key.c中的代码

#include "stm32f10x.h"
#include "delay.h"
#include "key.h"

void KEY_Init()
{
	GPIO_InitTypeDef GPIO_InitStruct;//创建GPIO结构体变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOA,ENABLE);//使能PE和PA组IO口
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//设置成上拉输入
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_3|GPIO_Pin_2;//PE4,PE3,PE2引脚,也就是KEY0,KEY1,KEY2按键
	
	GPIO_Init(GPIOE,&GPIO_InitStruct);//按键初始化为上拉输入
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;//设置为下拉输入
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;//PA引脚,也就是WK_UP按键
	
	GPIO_Init(GPIOA,&GPIO_InitStruct);//按键初始化为下拉输入
}

uint8_t KEY_Scan()
{
	static uint8_t key = 1;//储存键的状态,没有键按下时是1
	if(key&&(KEY0==0|KEY1==0|KEY2==0|WK_UP==1))//是否有键按下
	{
		delay_ms(10);//延时消抖
		if(key&&(KEY0==0|KEY1==0|KEY2==0|WK_UP==1))//是否真的有键按下
		{
			key=0;//有键按下,储存为0
			if(KEY0==0)
				return KEY0_PRES;//KEY0按下
			else if(KEY1==0)
				return KEY1_PRES;//KEY1按下
			else if(KEY2==0)
				return KEY2_PRES;//KEY2按下
			else if(WK_UP==1)//最好加上if,如果只有else的话可除了前面三个键的情况还可能有其他情况干扰WK_UP键的状态
				return WK_UP_PRES;//WK_UP按下
		}
	}
	else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)//为了会更加灵敏
		key=1;//没有键按下,储存1
	return 0;//没有键按下,返回0
}

键盘扫描函数的功能就是扫描每个与硬件相连按键的IO口的状况,然后通过这个状况来判断是否有键按下,不同的键按下对应着不同的处理。
注意:
判断按键是否按下时,需要进行消抖处理,通常消抖都是通过延时消抖,还可以采用消抖电路来消抖。
消抖的原因:
由于外界干扰,以及按键上的弹簧产生的机械作用,按键上的电平会在没有人按下的时候发生微小的变化,如果不作消抖处理,CPU就会将这些由其他因素引起的电平变化当作是键输入来处理,这样就产生了BUG,所以我们要进行消抖。
当检测到按键上有电平变化时,进行延时处理,一般10ms就够。如果是其他因素引起的电平变化,10ms之内就电平就会恢复,如果是用户按键导致的电平变化,那么在这10ms内就不会恢复到原来的电平状态,就可以认为是有键输入,并且进行相应的处理。
是不是有个疑问?
如果我在10ms内按下键并松开,是不是CPU就不会当作键输入处理?
是这样的,只要你手速够快,就可以骗过CPU,但是我们平常按键时,按一下并松开的时长肯定会超过10ms的。
让按键更加灵敏

else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)

这是判断没有键输入的语句,这种情况是与有键输入的情况对立的。如果写成只有一个else就笼统的概括没有键输入的情况,这样就会导致按键不灵敏,有时候需要按好几次才会出现对应的反应。

main.c中的代码

#include "led.h"
#include "beep.h"

int main()
{
	delay_init();//延时初始化
	
	LED_Init();//led初始化
	
	BEEP_Init();//蜂鸣器初始化
	
	KEY_Init();//按键初始化
	
	while(1)
	{
		uint8_t ret=KEY_Scan();
		if(ret)
		{
			switch(ret)
			{
				case KEY0_PRES:
					LED0=!LED0;
					LED1=!LED1;//同时反转俩个LED灯
					break;
				case KEY1_PRES:
					LED0=!LED0;//反转LED0
					break;
				case KEY2_PRES:
					LED1=!LED1;//反转LED1
					break;
				case WK_UP_PRES:
					beep=!beep;//蜂鸣器状态反转
					break;
			}
		}
		else
			delay_ms(10);//每隔10ms扫描一次键盘
	}
}

当按下右键时,同时控制俩个LED灯的状态发生反转,当按下下键和左键则分别只控制一个LED灯的状态发生反转,当按下上键时,蜂鸣器的状态发生反转。

视频展示

不支持连续按键

上电后,初始化状态是LED灯不亮,蜂鸣器不响,当有键输入后LED以及蜂鸣器的状态会发生改变。
连续按键也就是按着一个键不动的时候,LED以及蜂鸣器的状态不会发生改变,仅作一次键输入处理。

支持连续按

uint8_t KEY_Scan()
{
	static uint8_t key = 1;//储存键的状态,没有键按下时是1
	if(key&&(KEY0==0|KEY1==0|KEY2==0|WK_UP==1))//是否有键按下
	{
		delay_ms(10);//延时消抖
		if(key&&(KEY0==0|KEY1==0|KEY2==0|WK_UP==1))//是否真的有键按下
		{
			//key=0;//有键按下,储存为0
			if(KEY0==0)
				return KEY0_PRES;//KEY0按下
			else if(KEY1==0)
				return KEY1_PRES;//KEY1按下
			else if(KEY2==0)
				return KEY2_PRES;//KEY2按下
			else if(WK_UP==1)//最好加上if,如果只有else的话可除了前面三个键的情况还可能有其他情况干扰WK_UP键的状态
				return WK_UP_PRES;//WK_UP按下
		}
	}
	else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)
		key=1;//没有键按下,储存1
	return 0;//没有键按下,返回0
}

支持连续按只需要将key=0注释掉就可以,此时,键是否按下就不会参照前一次按键的状态,一只按照不放就是一只都有键输入处理,就像家里的遥控器调音量一样,按照音量键不放音量就会不停的发生变化。

视频展示

支持连续按键

当连续按键,也就是按着一个键不放的时候,LED灯会有轻微的闪烁,其实LED灯的状态是在不停的连续变化的,由于变化的太快,只能看到轻微的闪烁。当按着控制蜂鸣器的按键不放时,可以听到蜂鸣器的响声不是连续的,而是有一些断续,这也说明蜂鸣器的状态在不停的发生改变,由于改变的太快,只能听到就轻微的间隔。

总结

该实验使用的外设主要就是GPIO,LED灯和蜂鸣器是IO口的输出,按键是IO口的输入,掌握好IO口相关的知识就很容易做出来。文章来源地址https://www.toymoban.com/news/detail-773071.html

到了这里,关于【STM32】控制LED灯和蜂鸣器的按键实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • verilog学习笔记- 11)按键控制蜂鸣器实验

    蜂鸣器按照驱动方式主要分为有源蜂鸣器和无源蜂鸣器,其主要区别为蜂鸣器内部是否含有震荡源。一般的有源蜂鸣器内部自带了震荡源,只要通电就会发声。而无源蜂鸣器由于不含内部震荡源,需要外接震荡信号才能发声。                                          

    2024年02月02日
    浏览(39)
  • (STM32基础)STM32实现LED闪烁&LED流水灯&蜂鸣器

    1、按照新建工程步骤创建工程,新建start、library、user三个文件夹,从固件库添加相应文件 2、keilkil小程序用来清理listings和objects文件夹中编译产生的中间文件,以后需要打包工程的话可以先用keilkill先清理,这样文件夹会大大缩小所占内存。 在library中可以查看外设函数库,

    2024年02月07日
    浏览(56)
  • ARM_day9 按钮控制LED灯、蜂鸣器、风扇实验

    key.h key.c   do_irq.c main.c  

    2024年02月07日
    浏览(43)
  • 【STM32】STM32学习笔记-LED闪烁 LED流水灯 蜂鸣器(06-2)

    电路图示例1 电路图示例2 main.c 接线图如下图所示: 点击下载,现象为LED闪烁。 main.c main.c stm32F103工程模板 01-LED闪烁.rar 02-LED流水灯.rar 03-蜂鸣器示例程序.rar 参考: 【STM32】江科大STM32学习笔记汇总

    2024年03月19日
    浏览(57)
  • 3、stm32:GPIO输出——LED闪烁、LED流水灯、蜂鸣器

    目录 一、GPIO简介 二、GPIO基本结构 三、GPIO模式 四、GPIO常用寄存器 (1)端口配置低高寄存器(GPIOx_CRL/GPIOx_CRH)(x=A…E) (2)端口输入数据寄存器(GPIOx_IDR)(x=A…E) (3)端口输出数据寄存器(GPIOx_ODR)(x=A…E) (4)端口位设置/清除寄存器(GPIOx_BERR)(x=A…E) (5)端口位清除寄存器(GP

    2024年02月09日
    浏览(44)
  • 【STM32 基础实验蜂鸣器发声】

    蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。 BUZZER蜂鸣器的分类: 1、按其驱动方式的原理分,可分为: 有源蜂鸣器 (内含驱动线路,也叫

    2024年02月01日
    浏览(47)
  • 【STM32学习笔记】(10)——蜂鸣器实验详解

    蜂鸣器是一种一体化结构的电子讯响器,采用 直流电压 供电,广泛应用于计算机、打印机、复印机、报警器、 电子玩具 、汽车电子设备、电话机、 定时器 等电子产品中作发声器件。蜂鸣器主要分为 压电式蜂鸣器 和 电磁式蜂鸣器 两种类型。蜂鸣器在电路中用字母 “H”

    2024年02月06日
    浏览(41)
  • 学习笔记|认识蜂鸣器|控制原理|电磁炉LED实战|逻辑运算|STC32G单片机视频开发教程(冲哥)|第八集(上):蜂鸣器应用

    反面包上黑胶的是有源蜂鸣器。 在背面裸露的一块线路板的是无源蜂鸣器。 YX55675-无源蜂鸣器模块的资料 提取码:nl73 1、有源蜂鸣器内部带震荡源,所以只要一通电就会叫(一边高电平,一边低电平),而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫(必须不断给高

    2024年02月11日
    浏览(56)
  • STM32 HAL库实现三位数码管显示(74HC595+按键+蜂鸣器)

    1、加强数码管学习,实现数码显示变量数据(三位数的显示); 2、3位数码+2个按键+蜂鸣器实现模拟电磁炉功率调节及显示; 关于74HC595的STM32F103的驱动以及数码的显示等请查阅我写的上一篇博客:https://blog.csdn.net/luojuan198780/article/details/136653377 实验效果参考下面网址视频:

    2024年03月17日
    浏览(84)
  • 基于stm32F103的蜂鸣器周期发声实验

    蜂鸣器作为一种声音报警器件,应用广泛。本实验基于stm32F103单片机,通过控制蜂鸣器的IO口电平电压,使其周期性地进行电平翻转,从而驱动蜂鸣器发出周期性的鸣叫声。该实验主要运用了stm32的GPIO和定时器TIM的相关功能,不仅可以巩固这些外设的使用,也可以通过改变时间参数,控

    2024年02月21日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包