单片机原理及应用:独立式键盘控制LED与多功能按键识别

今天来介绍另一个外设——按键与LED的配合工作,与开关不同,按键需要注意消除抖动带来的影响,代码逻辑也会更复杂一写,下面先为大家介绍独立式键盘的相关知识。

单片机的独立式键盘指的是一种不依赖于计算机或其他外部设备的键盘输入方式,由若干按键按照一定的规则组成,每一个按键实质就是一个按钮开关。而独立式键盘的各键相互独立,每个按键各接一条I/O口线,通过检测I/O输入线的电平状态,很容易地判断哪个按键被按下。

当无键按下时,通过上拉电阻,P0的 8 个I/O口引脚被上拉为高电平“ 1 ”;如果有键按下,将使对
应该键接的I/O口引脚,通过该键接地,信息为“0 ” 。
与开关不同,机械式按键在按下或释放时,由于机械弹性作用的影响 常伴随一定时间的触点机械抖 动, 然后才能稳定下来。 若有抖动,按键按下会被错误地认为是多次操作。 所以我们要在代码中执行消抖程序。
消抖程序的原理是 在检测到有按键按下时执行一个10ms左右的延时程序;再确认该键电平是否仍保持闭合状态电平,若仍保持闭合状态电平,则确认该键处于闭合状态,从而消除抖动的影响。我现在以8位独立式键盘控制LED灯点亮作为案例,代码如下:
#include <reg52.h>     
void delay10ms(void)     //延时消抖程序,第三种delay,数量级为5~10k
{ 
   unsigned char i,j; 
   for(i=40;i>0;i--) 
     for(j=250;j>0;j--); 
} 
void main()         
{
  unsigned char x;
  P1=0xff;          //led全灭
  x=0;
  while(1)
  {
	while(x==0)     //无键被按下执行死循环,有键被按下才往下走
	{x=P0;             //第一次进入循环给x赋值,没有异常再取反恢复原值
     x=~x;}
    delay10ms();      //消抖
    x=P0;               //再次读键盘状态
	x=~x;
    if(x==0) continue;//如果无键按下则认为是按键抖动,重新扫描键盘 
	 
    switch(x)           //根据键值点亮对应的发光二极管
    {
      case 0x01: P1=0xfe; break;    //点亮第一个发光二极管
      case 0x02: P1=0xfd; break;    //点亮第二个发光二极管
      case 0x04: P1=0xfb; break;   //点亮第三个发光二极管
      case 0x08: P1=0xf7; break;   //点亮第四个发光二极管
      case 0x10: P1=0xef; break;   //点亮第五个发光二极管
      case 0x20: P1=0xdf; break;    //点亮第六个发光二极管
      case 0x40: P1=0xbf; break;   //点亮第七个发光二极管
      case 0x80: P1=0x7f; break;    //点亮第八个发光二极管
      default: break;
    }
  }
}
#include<reg52.h> 
   
sbit S1=P1^0;        		//将S1位定义为P1.0引脚
sbit S2=P1^1;        		//将S2位定义为P1.1引脚
sbit S3=P1^2;        		//将S3位定义为P1.2引脚
sbit S4=P1^3;        		//将S4位定义为P1.3引脚

unsigned char keyval;  		//定义键值储存变量单元

void led_delay(void);//第一种延时函数,流水灯延时
void delay10ms(void);//按键消抖
void key_scan(void)	;//键盘扫描
void ledstate();	 //switch封装,也可以写在主函数中
//void key(void);		 
//灯的四种变化
void forward(void);	//从上至下
void backward(void);//从下至上
void Alter(void);	//高四位与低四位互闪
void blink (void);	//全闪


void main(void)  	
{
  	keyval=0;       //键值初始化为0
 	while(1)
{		//key();
		key_scan();  			//调用键盘扫描函数
		ledstate();				//调用灯光执行程序
	}
}
void key_scan(void)			//函数功能:键盘扫描
{
 	P1=0xff;
	if((P1&0x0f)!=0x0f)   		//检测到有键按下
	{
		delay10ms();  		//延时10ms再去检测
		if(S1==0) keyval=1;    		//按键k1被按下
		if(S2==0) keyval=2;     		//按键k2被按下
		if(S3==0) keyval=3;     		//按键k3被按下
		if(S4==0) keyval=4;     		//按键k4被按下	
	}
		 
}
void forward(void)	//函数功能:正向流水点亮LED
{
	P3=0xfe; led_delay();        		//LED0亮
	P3=0xfd; led_delay();         		//LED1亮
	P3=0xfb; led_delay();         		//LED2亮
	P3=0xf7; led_delay();         		//LED3亮
	P3=0xef; led_delay();         		//LED4亮
	P3=0xdf; led_delay();         		//LED5亮
	P3=0xbf; led_delay();         		//LED6亮
	P3=0x7f; led_delay(); 				//LED7亮
 } 
void backward(void)		//函数:反向流水点亮LED
{
    P3=0x7f; led_delay();        		//LED7亮
	P3=0xbf; led_delay();        		//LED6亮
	P3=0xdf; led_delay();         		//LED5亮
	P3=0xef; led_delay();          		//LED4亮
	P3=0xf7; led_delay();         		//LED3亮
	P3=0xfb; led_delay();          		//LED2亮
	P3=0xfd; led_delay();        		//LED1亮
	P3=0xfe; led_delay();       		//LED0亮
}
void Alter(void)		//函数:交替点亮高4位与低4位LED
{
	P3=0x0f;
  	led_delay();
  	P3=0xf0;
  	led_delay();
}
void blink (void)		//函数:闪烁点亮LED
{
  	P3=0xff;
  	led_delay();
	P3=0x00;
  	led_delay();
} 
void led_delay(void)			//函数:延时
{
   unsigned char i,j;
	for(i=0;i<220;i++)
	for(j=0;j<220;j++)
	    ;
}
void delay10ms(void)	//函数:软件消抖延时10ms
{
	unsigned char i,j;
	for(i=0;i<100;i++)
	for(j=0;j<100;j++);
}
void ledstate()
{
		switch(keyval)
		{
		case 1:forward();	//键值为1,调用正向流水点亮函数
		break;
		case 2:backward();	//键值为2,调用反向流水点亮函数
		break;
		case 3:Alter();	//键值为3,调用高、低4位交替点亮函数
		break;
		case 4:blink ();	//键值为4,调用闪烁点亮函数
		break;
		}
} 
//键盘扫描和灯光操作可以合并为一个函数,还能省下sbit命名
/*void key(void)
{
P1=0xff;
if((P1&0x0f)!=0x0f)
{delay10ms();
switch(~(P1&0x0f))
      {case 0xf1:forward();	//键值为1,调用正向流水点亮函数
		break;
		case 0xf2:backward();	//键值为2,调用反向流水点亮函数
		break;
		case 0xf4:Alter();	//键值为3,调用高、低4位交替点亮函数
		break;
		case 0xf8:blink ();	//键值为4,调用闪烁点亮函数
		break; }
		}
	} */

 这里给大家展示了两个程序,第一个实例就是先检测按键的状态,然后用switch语句判断哪个键被按下,之后执行相应的点亮程序。第二个实例是把之前学过的LED点亮状态都封装成函数,然后在主程序里根据键盘的值执行相应的操作。

实例仿真1

实例仿真2

有两点需要注意

  1. delay10ms是到目前为止我们学习的第三个延时函数,作用是消抖,数量级为5~10k。 
  2. 为了节省空间,按键个数一般少于8个,需要用按位与“&”屏蔽不需要的引脚来防止异常电位

按键控制LED点亮

下面是多功能按键控制LED的案例,与前文不同,该案例是通过记录按键按下的次数来改变LED状态的。,在这种情况下,就需要考虑按住按键不松手的情况,以免一直进行灯光切换。

#include <reg52.h>
sbit key=P3^0; 
unsigned char ID; 
void delay10ms(void) 
{ 
  	unsigned char i,j; 
  	for(i=20;i>0;i--) 
    	for(j=248;j>0;j--); 
} 
void keyonoff()
{
		if(key==0) 		  //检测按键被按下
		{
			delay10ms();  //去抖
      		if(key==0) 
      		{ 
        		ID++;
				while(key==0); 	//防止按住不松手,等待按键释放  
        		if(ID==4) 
        		{ 
          			ID=0; 
        		} 
        		
			} 
    	}
}
void displayled()
{
    	switch(ID) 
    	{
  			case 0: P1=0x0e;break; 	//点亮D1,熄灭其它LED
      		case 1: P1=0x0d;break; 	//点亮D2,熄灭其它LED
      		case 2: P1=0x0b;break; 	//点亮D3,熄灭其它LED
      		case 3: P1=0x07;break; 	//点亮D4,熄灭其它LED
    	}  	//end switch
}
void main(void) 
{ 	P1=0x0f;
	while(1) 
  	{ 
		//按键识别程序
 		keyonoff();
		//根据按键结果,输出程序
		displayled();
  	}    	
}      		

这个模式在没有按键被按下的情况下点亮第一个LED作为标志,大家也可以自行更改case的值设置双击或全灭等操作,或者把前文封装的函数放在switch里执行更多的功能。

多功能按键控制LED点亮

 以上就是按键控制LED灯点亮的过程,之后会介绍按键控制数码管显示的案例。谢谢大家。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/288595.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java 第19章 IO流 课堂练习+本章作业

文章目录 Buffered流拷贝二进制文件创建文件写入文本读取文本文件存读Properties文件 Buffered流拷贝二进制文件 package com.hspedu.chapter19.outputStream;import java.io.*;public class BufferedCopy02 {public static void main(String[] args) {String srcFilePath &q…

【技巧】IDEA 使用小技巧(三)

IDEA 使用小技巧&#xff08;三&#xff09; 配置目录Ctrl 鼠标方法缩小字体 配置目录 IDEA 在使用的过程中会在 C 盘的用户目录下写入相关配置&#xff0c;目录如下&#xff1a; "C:\Users\个人用户名\AppData\Local\JetBrains" "C:\Users\个人用户名\AppDa…

AutoPDMS的工程文件突然不见了……

1.用户好不容易一个工程的应力分析计算通过&#xff0c;不料&#xff0c;第二天使用时提示以下信息&#xff0c;对用户来说简直如同噩梦降临。 分析&#xff1a;要么用户移动了文件&#xff0c;要么用户删除了文件&#xff0c;用户两者都否定。无论怎么样文件不会莫名不见了&am…

opencv入门到精通——图像梯度

目录 目标 理论 1. Sobel 和 Scharr 算子 2. Laplacian 算子 代码 一个重要事项 目标 在本章中&#xff0c;我们将学习&#xff1a; 查找图像梯度&#xff0c;边缘等 我们将看到以下函数&#xff1a;cv.Sobel()&#xff0c;cv.Scharr()&#xff0c;cv.Laplacian()等 理…

Ansible、Saltstack、Puppet自动化运维工具介绍

一、自动化运维工具的选择 1、为什么要用自动化运维工具&#xff1f; 运维的痛点: 海量的设备越来越多&#xff0c;每台设备单独管理需要投入更多人力&#xff1b; 传统运维效率低&#xff0c;大多工作人为完成&#xff1b; 传统运维工作繁琐&#xff0c;人工操作容易出错…

paddle v4 hubserving 部署

环境准备&#xff1a;https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.7/deploy/hubserving#24-%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1 服务器启动命令 hub serving start -c deploy/hubserving/ocr_system/config.json客户端请求 python tools/test_hubserving.…

黑马程序员SSM框架-Maven进阶

视频链接&#xff1a;Maven-01-分模块开发的意义_哔哩哔哩_bilibili 分模块开发与设计 分模块开发意义 分模块开发 依赖管理 依赖传递 依赖传递冲突问题 可以点击红框按钮查看依赖情况。 可选依赖和排除依赖 继承和聚合 聚合 聚合工程开发 继承 聚合和继承的区别 属性 属性…

[Vulnhub靶机] DriftingBlues: 2

[Vulnhub靶机] DriftingBlues: 2靶机渗透思路及方法&#xff08;个人分享&#xff09; 靶机下载地址&#xff1a; https://download.vulnhub.com/driftingblues/driftingblues2.ova 靶机地址&#xff1a;192.168.67.21 攻击机地址&#xff1a;192.168.67.3 一、信息收集 1.…

用PHP搭建一个绘画API

【腾讯云AI绘画】用PHP搭建一个绘画API 大家好&#xff01;今天我要给大家推荐的是如何用PHP搭建一个绘画API&#xff0c;让你的网站或应用瞬间拥有强大的绘画能力&#xff01;无论你是想要让用户在网页上绘制自己的创意&#xff0c;还是想要实现自动绘画生成特效&#xff0c;这…

SpringBoot 集成支付宝支付

网页操作步骤 1.进入支付宝开发平台—沙箱环境 使用开发者账号登录开放平台控制平台 2.点击沙箱进入沙箱环境 说明&#xff1a;沙箱环境支持的产品&#xff0c;可以在沙箱控制台 沙箱应用 > 产品列表 中查看。 3.进入沙箱&#xff0c;配置接口加签方式 在沙箱进行调试前…

Alibaba Cloud Linux镜像操作系统详解(全方位解析)

Alibaba Cloud Linux是基于龙蜥社区OpenAnolis龙蜥操作系统Anolis OS的阿里云发行版&#xff0c;针对阿里云服务器ECS做了大量深度优化&#xff0c;Alibaba Cloud Linux由阿里云官方免费提供长期支持和维护LTS&#xff0c;Alibaba Cloud Linux完全兼容CentOS/RHEL生态和操作方式…

RocketMQ5.0顺序消息设计实现

前言 顺序消息是 RocketMQ 提供的一种高级消息类型&#xff0c;支持消费者按照发送消息的先后顺序获取消息&#xff0c;从而实现业务场景中的顺序处理。 顺序消息的顺序关系通过消息组&#xff08;MessageGroup&#xff09;判定和识别&#xff0c;发送顺序消息时需要为每条消息…

【响应式编程-01】Lambda表达式初体验

一、简要描述 Lambda初体验Lambda表达式的语法格式Lambda表达式应用举例Lambda表达式底层实现 二、什么是Lambda表达式 Java8新特性&#xff0c;来源于数学中的λ[l:mdə]演算 是一套关于函数(f(x))定义、输入量、输出量的计算方案 Lambda表达式 -> 函数 使代码变得简洁…

【AI】DETR模型可视化操作

Detr作为目标检测的算法&#xff0c;不同于之前算法的就是注意力机制&#xff0c;注意力机制能够直观看出来模型对图像关注的点&#xff0c;这个直观到底怎么直观呢&#xff0c;我们只听别人说肯定是不行的&#xff0c;上手测试才是最好的方式&#xff0c;像论文中插图那样的使…

jQuery框架

1.1、jQuery简介 jQuery 是一个高效、精简并且功能丰富的 JavaScript 工具库。它提供的 API 易于使用且兼容众多浏览器&#xff0c;这让诸如 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作更加简单。目前超过90%的网站都使用了jQuery库&#xff0c;jQuery的宗旨&#xff1…

CMake入门教程【核心篇】添加应用程序(add_executable)

&#x1f608;「CSDN主页」&#xff1a;传送门 &#x1f608;「Bilibil首页」&#xff1a;传送门 &#x1f608;「本文的内容」&#xff1a;CMake入门教程 &#x1f608;「动动你的小手」&#xff1a;点赞&#x1f44d;收藏⭐️评论&#x1f4dd; 文章目录 1. 概述2. 使用方法2…

Linux 的引导与服务控制

一 开机启动过程 bios加电自检-->mbr-->grub-->加载内核文件-->启动进程 1 bios家电自检 检测硬件是否正常&#xff0c;然后根据bios中的启动项设置&#xff0c;去找内核文件 2 mbr 因为grup太大,第一个扇区存不下所有的grub程序&#xff0c;所以分为2部分指…

视频剪辑高手实战:批量置入随机封面,高效制作

随着数字媒体时代的到来&#xff0c;视频内容已成为日常生活中不可或缺的一部分。无论是社交媒体、新闻、教育还是娱乐&#xff0c;视频都以其独特的魅力吸引着眼球。高质量的视频内容要经过精细的剪辑和包装。现在来讲解云炫AI智剪如何通过批量置入随机封面&#xff0c;高效制…

鸿蒙HarmonyOs:为什么不支持热更新?

学习了一段时间的鸿蒙开发&#xff0c;发现鸿蒙开发还是比较简单的&#xff0c;今天突然心血来潮&#xff0c;研究了一下鸿蒙热更新&#xff0c;最终得出的结论是鸿蒙暂时不支持热更新。 鸿蒙app开发主要是利用的ArkTs语言&#xff0c;ArkTs又是基于TypeScript语言的&#xff0…

Linux network — 网络层收发包流程及 Netfilter 框架浅析

Linux network — 网络层收发包流程及 Netfilter 框架浅析 1. 前言2. 基础网络知识2.1 网络分层模型2.2 数据包协议分层2.3 sk_buff 结构2.4 收发包整体框架 3. 网络层&#xff08;IPv4&#xff09;收发包流程4. Netfilter 框架4.1 IPv4 网络层的 Netfilter Hook 点4.2 iptable…