按键实验

  • 描述
  • 用到的相关寄存器
    • GPIO
      • IDR
      • ODR
    • RCC
  • 确定位置
    • LED灯
    • 蜂鸣器
    • 按键
  • 程序及分析
    • 不支持连续按
      • 视频展示
    • 支持连续按
      • 视频展示
  • 总结

描述

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

用到的相关寄存器

GPIO

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

IDR

叫做端口数据输入寄存器(GPIOX_IDR),读取它的信息就能获得IO口上的状态,是作输入使用的。

这是它每一位的对应关系,可以看到,IDR寄存器是一个32位的寄存器,但是只有低16位在使用,而且是只读类型的,高16位保留,如果读的话结果就是0。低16位从0到15对应的该组IO口标号从0到15引脚上的数据信息,而且只能以16位的形式读取数据。

ODR

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

RCC

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

确定位置

LED灯

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

蜂鸣器

我们来看开发板原理图。

可以将BEEP看作是蜂鸣器,它与PB8相连。

这是它的具体电路,当BEEP是低电平时,蜂鸣器不会响,当BEEP是高电平时,通过三极管的放大作用,就会使蜂鸣器发出响声。

按键


可以看到,按键KEY0与PE4相连,按键KEY1与PE3相连,按键KEY2与PE2相连。

按键WK_UP与PA0相连。

根据按键的电路图可以发现,KEY0,KEY1,KEY2这三个按键的另一端是和地相连接的,也就是当按键按下去时是低电平,未按下时是高电平,所以这3个键采用上拉输入模式。
WK_UP键的另一端连接的是3.3V的高电平,当键按下去时是高电平,未按下时是低电平,所以采用下拉输入模式。

程序及分析

不支持连续按

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

#ifndef __LED_H
#define __LED_Hvoid 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;//引脚5GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//输出最大速度是50MHZGPIO_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_Hvoid 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;//引脚5GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//输出最大速度是50MHZGPIO_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;//储存键的状态,没有键按下时是1if(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;//有键按下,储存为0if(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;//没有键按下,储存1return 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;//反转LED0break;case KEY2_PRES:LED1=!LED1;//反转LED1break;case WK_UP_PRES:beep=!beep;//蜂鸣器状态反转break;}}elsedelay_ms(10);//每隔10ms扫描一次键盘}
}

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

视频展示

不支持连续按键

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

支持连续按

uint8_t KEY_Scan()
{static uint8_t key = 1;//储存键的状态,没有键按下时是1if(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;//有键按下,储存为0if(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;//没有键按下,储存1return 0;//没有键按下,返回0
}

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

视频展示

支持连续按键

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

总结

该实验使用的外设主要就是GPIO,LED灯和蜂鸣器是IO口的输出,按键是IO口的输入,掌握好IO口相关的知识就很容易做出来。

控制LED灯和蜂鸣器的按键实验相关推荐

  1. 【51单片机Task】:led十六进制控制led灯详解、按键控制流水灯、跑马灯等任务

    学习目标: 学习普中51单片机的按键控制led灯. 电路图:                      学习内容:         LED灯的十六进制怎么算???         在这给大家算一下:首 ...

  2. Chapter002-FPGA学习之按键控制LED灯和蜂鸣器

    硬件原理 在正点原子开发板中,LED模块高电平驱动,蜂鸣器也是高电平驱动,按键按下,对应引脚为低电平: 原理图如下: 以上设备与FPGA引脚的对照表如下: 设备 引脚名称 对应FPGA引脚 按键 PL ...

  3. 按键控制led灯亮灭c语言实验报告,通过按键控制LED灯的实验

    通过查看开发板的核心电路原理图,加上查阅SUMSANG 2440的datasheed得知四个按键K1,K2,K3,K4对应GPF中的GPF1,GPF4,GPF2,GPF0.将这四个引脚配置为输入模式, ...

  4. 按键控制led灯python程序_按键控制led灯

    //通过按键控制对应的led灯亮灭,按一下亮,再按一下灭,消抖时间20ms module key_led ( input clk , rst_n, input [2:0]key , output  l ...

  5. led计数电路实验报告_「正点原子FPGA连载」第八章 按键控制LED灯实验

    1)实验平台:正点原子开拓者FPGA开发板 2)本实例源码下载:请移步正点原子官网 第八章 按键控制LED灯实验 按键是常用的一种控制器件.生活中我们可以见到各种形式的按键,由于其结构简单,成本低廉等 ...

  6. verilog学习笔记- 10)按键控制 LED 灯实验

    目录 简介: 实验任务: 硬件设计: 程序设计: 下载验证 : 总结与反思: 简介: 按键开关是一种电子开关,属于电子元器件类.我们的开发板上有两种按键开关:第一种是本实验所使用的轻触式按键开关,使用 ...

  7. 驱动——按键中断控制LED灯实验

    三个按键实现按键中断 要求:按键按一下灯亮,再按一下灯灭 注:由于开发板位置,为了方便一一对应观察,采用key1控制LED3,key2控制LED2,key3控制LED1 0.添加相关设备树节点信息 ① ...

  8. cc2530 按键中断实验——按键控制LED灯的亮灭

    在本次学习中,主要通过外部中断来控制LED的亮灭. 首先,先查看相关电路图.由图可知,当CC2530端口1的1号引脚输出低电平时,LED3将被点亮,当按键31按下时,端口1的1号引脚将为低电平,抬起时 ...

  9. 利用Proteus仿真STM32实现按键控制LED灯设计

    1. 前言 Proteus是英国著名的EDA工具(仿真软件),从原理图布图.代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计.是世界上唯一将电路仿真软件.PC ...

最新文章

  1. android this context,Android應用開發中關於this.context=context的理解
  2. 国家卫健委发布第一版新冠疫苗接种技术指南
  3. [转]opensuse 更新源
  4. 月薪6万的腾讯产品经理是什么水平?
  5. tp3.2php开启事务,ThinkPHP 3.2.2实现事务操作的方法
  6. 局域网屏幕共享软件 推荐_局域网共享软件,详细教您局域网共享软件如何使用...
  7. 为什么需要动态SQL
  8. for相关 java_Java学习之for循环相关知识梳理
  9. vue2.0 引用qrcode.js实现获取改变二维码的样式
  10. wordpress python 采集_Python3利用Selenium3模拟wordpress博客登陆
  11. C#操作Word(转)0
  12. # 定义四边形_对特殊平行四边形核心梳理,拓展提升思维
  13. java 修改win7系统时间_win7如何禁止更改系统时间
  14. Ubuntu18.04安装COMSOL 5.3a
  15. PCB layout的基本原则
  16. 一些常用的物理特殊符号的读法
  17. xheditor html5,Flask项目集成富文本编辑器XHEditor
  18. UberAir飞行汽车:一键乘坐飞机会变成现实吗
  19. 动手学深度学习(六、卷积神经网络)
  20. 走向面试之数据库基础:一、你必知必会的SQL语句练习-Part 2

热门文章

  1. PS2019仿制图章工具、图案图章工具
  2. 企业内部搭建OpenVirtualPrivateNetwork快速入门
  3. 关于计算机的趣味小知识,10个非常有意思的趣味知识和科学事实
  4. 数据结构课设 - 平衡二叉树的演示
  5. css简单样式(旋转正方形、纸片旋转、轮播图3D、简单轮播图)
  6. android 【禁止横屏和竖屏切换】
  7. 《C系列-实践相关》C语言十
  8. wordExport导出word时关于echarts图表生成图片的解决方案
  9. 金蝶协同办公平台任意文件下载漏洞(无需登录)
  10. hyper-v虚拟机的基本使用