51单片机编程应用(C语言):独立按键

news2024/11/27 14:50:15

目录

1.独立按键介绍

2.独立按键控制LED亮灭

1.1按下时LED亮,松手LED灭(按一次执行亮灭)

    1.2首先按下时无操作,松手时LED亮(再按下无操作,所以LED亮),松手LED灭(松手时执行取反操作)(按两次执行亮灭)

        1.3.独立按键控制LED按二进制递增亮

        1.4.两个独立按键控制LED移位,左移,右移

1.5:一个独立按键控制流水灯方向

方法一:一个代码编程所有:

方法2:模块化编程,


1.独立按键介绍

独立按键的原理图:

 所有单片机I/O口上电时都是默认高电平,独立按键没有按下,就是高电平,按下时,外部接地时强下拉,与地相接,I/O就会变为低电平,这里讲一下什么是I/O口,I/O口也叫input/output口,输入输出口,cpu可以给寄存器写值,比如上一节LED灯,CPU写值给寄存器,,由于单片机内部是弱上拉,所以要加驱动器加强电流,最后连接到I/O口,寄存器通过数据总线把值给I/O口此时I/O口就是output,input刚好就是相反的操作,比如I/O口读取外部信息,把值给寄存器,CPU再识别寄存器的值,

讲一下编程的命名问题,前面我们讲了sbit,对单个I/O口命名,就像一个人一样,要有名字,不过称呼一个人是不是也可以取外号啊,C51编程就给了这样的命名规则,

#include <REGX52.H>这个函数就相当于父母一样,里面对I/O口八位或单个I/O都命名了,

 我们用单个I/O口就直接用P0_0,P0_0就像父母给的名字一样,但是也可以外号称呼,sbit LED=P2^0,此时LED就是外号,LED和P2_0都可以指向P2^0口(看成一个人)

记住:sbit LED=P2_0;是错的,把名字给外号显然不是喊你,P2^1=0;也是错的,赋值就像别人要称呼你,称呼你喊你的名字,肯定不是叫哎,这个人吧

 

延时消抖 

 

主要原因还是单片机运算速度太快了,us级别,这些抖动他是可以识别出来的, 比如上面这个图,你按一下,由于有抖动,出现高-低--高--低--高--低...这样的话单片机会误以为你按了5/6下,

 实际上你就按了一下,所以这样的操作就会与人们期望的不符,所以我们延时一段时间来消除抖动,按下与松手都加个延时,当然也可以加一个电路消抖动,(有点麻烦)

2.独立按键控制LED亮灭

1.1按下时LED亮,松手LED灭(按一次执行亮灭)

最终代码如下:

#include <REGX52.H>
sbit LED=P2^0;
void Delay1ms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
  while(xms)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	xms--;
  }
}

void main()
{
	
	while(1)
	{
		if(P3_1==0)//按下
		{
			Delay1ms(20);//消抖,真正的按下
			P2_0=0;
		}
		else//松手
		{
            Delay1ms(20);
			LED=0;
		}
	}
}

    1.2首先按下时无操作,松手时LED亮(再按下无操作,所以LED亮),松手LED灭(松手时执行取反操作)(按两次执行亮灭)

   代码如下:

#include <REGX52.H>
sbit LED=P2^0;
void Delay1ms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
  while(xms)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	xms--;
  }
}

void main()
{
	
	while(1)
	{
		if(P3_1==0)
		{
			Delay1ms(20);//消抖,确定按下
		}
		else
		{
			Delay1ms(20);//消抖,确定松手
			LED=~LED;
			while(P3_1==1);
		}
	}
}

这段代码的现象是没有按之前,LED从1变为0;LED亮, 如果没有按独立按键,LED就一直亮,按下独立按键,没有任何反应,松手LED从0变为1,LED灭,一直是灭的状态,假如没有while(P3_1==1);这句,现象是LED一直在闪烁,无论按不按,都是闪烁,为什么呢,P3_1默认为高电平,一上电,我们没有按开关,执行else语句,LED=~LED,10101010.......延迟20ms的闪烁,按了就是多了延迟,只是增加了闪烁时间不同而已,有了这句话之后,松手的话,死循环,一直不执行,保持着了LED的状态,而不要让他一直变,

最后按一下松手执行下面操作,

亮----灭-----亮------灭.....

当然下面代码可以执行下面现象.

灭-----亮------灭.....亮........

void main()
{
	
	while(1)
	{
		if(P3_1==0)
		{
			Delay1ms(20);
		    while(P3_1==0);
			Delay1ms(20);
			LED=~LED;
		}
	}
}

没有按下,不执行任何操作,保持原有状态 ,按下时,一直按着的话,就什么都不操作,执行while语句,一旦松手,跳出while语句,LED取反,再跳出if语句

        1.3.独立按键控制LED按二进制递增亮

 引入中间变量LEDNum,为什么呢,因为P2 ++,上电默认是不是1111 1111,加1变为0000 0000,全部亮,加一0000 0001,刚好与我们的预想的相反,而P2取反,就会1111 1111,变为0000 0000,取反you变为1111 1111,无法达到我们的效果,而引入中间变量LEDNum,LEDNum把值存起来,再给P2赋值就完美的解决了这一点,比如char类型刚好一个字节,存8位,

按下一次按键后LEDNum从0000 0000加加后变为0000 0001,取反1111 1110,给P2口,刚好第一个灯亮,而且LEDNum的值不会因为赋给P2而变成P2的值,还是 0000 0001,加一0000 0010 取反 1111 1101 给P2,刚好点亮第二个灯,依次循环,实现了用灯表示二进制,

#include <REGX52.H>
 
void Delay(unsigned int xms)		
{
	unsigned char i, j;
 
	while(xms){
		i = 2;
		j = 239;
		do
		{
				while (--j);
			
		} while (--i);
		xms--;
	}
}
 
void main()
{
	unsigned char LEDNum=0; 
    while(1)
    {
      if(P3_1==0)
      {
      Delay(20);
      while(P3_1==0);
      Delay(20);
		   LEDNum++;
		  P2=~ LEDNum;
      }
	
    }
}

        1.4.两个独立按键控制LED移位,左移,右移

   方法一:

0000 0001    0x01<<0

0000 0010    0x01<<1

0000 0100    0x01<<2

0000 1000   0x01<<3

..............

0 1 2 3 4定义为LEDNum,每按一下加一,加到7,LEDNum回到0,加个if语句。if(LEDNum>=8),LEDNum=0,因为LEDNum=7时,继续执行i++,

P2口应该与上面写的是反的,再取反操作。

代码如下

#include <REGX52.H>
 
unsigned char LEDNum;
 
void Delay(unsigned int xms)		
{
	unsigned char i, j;
 
	while(xms){
		i = 2;
		j = 239;
		do
		{
				while (--j);
			
		} while (--i);
		xms--;
	}
}
 
void main()
{
	
	while(1)
	{
		if(P3_1==0)
		{
			Delay(20);
			while(P3_1==0);
			Delay(20);
			
			if(LEDNum>=8) 
				LEDNum=0;
			
			P2=~(0x01<<LEDNum);
			LEDNum++;
				
		}
		
		if(P3_0==0)//??????
		{
			Delay(20);
			while(P3_0==0);
			Delay(20);
			
			if(LEDNum==0)//???????
				LEDNum=7;
			else
				LEDNum--;
			
			P2=~(0x01<<LEDNum);
		}
	}
}
 

注意:LEDNum是无符号型,最大值 255,LEDNum--的话,减到0,再减一的话,变成255,这就是越界。所以减到0我们重新让他变为7,

方法二:

 每按一次独立按键,P2的数值变化如下

P2:    1111 1111    上电时,           我们用左移操作时,最低位是不是补0,我们在或上0x01,补成1

          1111 1110     按一次按键    P2左移1位 ,此时P2=1111 1110

          1111 1101     按两次按键    P2左移1位后或上0000 0001,

          1111 1011     按三次按键    P2左移1位后或上0000 0001

          ...............

#include <REGX52.H>
void Delay(unsigned int xms)		
{
	unsigned char i, j;
 
	while(xms){
		i = 2;
		j = 239;
		do
		{
				while (--j);
			
		} while (--i);
		xms--;
	}
}
 
void main()
{   
		P2=0xFE;
	    while(1)
	    {
		if(P3_1==0)
		{
			Delay(20);
			while(P3_1==0);
			Delay(20);
			P2=P2<<1|0x01;
			if(P2==0xFF)
	        {
				P2=0xFE;
	        }
				
		}
		
		if(P3_0==0)
		{
			Delay(20);
			while(P3_0==0);
			Delay(20);
			P2=P2>>1|0x80;
			if(P2==0xFF)
	        {
				P2=0x7F;
	        }
		}
	}
}
 

1.5:一个独立按键控制流水灯方向

 代码如下:

方法一:一个代码编程所有:
#include <REGX52.H>
#include <INTRINS.H>  //导入头文件
unsigned char LEDNum;
unsigned int count;
void Delay1ms(unsigned int xms)		//@11.0592MHz   //延时函数
{
	unsigned char i, j;
	while (xms--)
	{
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
 
	}
}
 
void main()
{
	while(1)
	{
		if(P3_1==0)
		{
			Delay1ms(20);
			while(P3_1==0);
			Delay1ms(20); //软件消抖
			P2=0xFE;
			Delay1ms(500);
			LEDNum = 0xFE;
			while(1)
			{
				while(count == 0) //当count为0时进入此循环
				{
					LEDNum =_crol_(LEDNum,1);
					P2 = LEDNum;
					Delay1ms(500);//1
					if(P3_1==0)
					{
						Delay1ms(20);
						while(P3_1==0);
						Delay1ms(20);
						count = 1; //再次按下K1改变count值使进入逻辑右移
					}
				}
				while(count == 1) //当count为1时进入此循环
				{
					LEDNum =_cror_(LEDNum,1);
					P2 = LEDNum;
					Delay1ms(500);
					if(P3_1==0)
					{
						Delay1ms(20);
						while(P3_1==0);
						Delay1ms(20);
						count = 0; //再次按下K1改变count值使进入逻辑左移

					}
				}
			}			
		}
	}
}
方法2:模块化编程,

后面我们专门写一期怎么模块化编程,下面针对这个题进行一次模块化编程,涉及内容有中断,定时器,后面所以讲到了会一一再解释这里的所有代码的具体含义。

main.c

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
 
unsigned char KeyNum,LEDMode;
 
void main()
{
	P2=0xFE;
	Timer0Init();
	while(1)
	{
		KeyNum=Key();		//获取独立按键键码
		if(KeyNum!=0)			//如果按键按下
		{
			//if(KeyNum==1)	//如果K1按键按下
			//{
				LEDMode++;	//模式切换
				if(LEDMode>=2)LEDMode=0;
			//}
		}
	}
}
 
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;		//T0Count计次,对中断频率进行分频
	if(T0Count>=500)//分频500次,500ms
	{
		T0Count=0;
		if(LEDMode==0)			//模式判断
			P2=_crol_(P2,1);	//LED输出    
			//_crol_循环左移
		if(LEDMode==1)
			P2=_cror_(P2,1);
		  //_cror_循环右移
	}
}

Timer0.c :

#include <REGX52.H>
 
/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}
 
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		
	}
}
*/

Timer0.h :

#ifndef __TIMER0_H__
#define __TIMER0_H__
 
void Timer0Init(void);
 
#endif

Key.c :

#include <REGX52.H>
#include "Delay.h"
 
/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
  */
unsigned char Key()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
	
	return KeyNumber;
}

Key.h :

#ifndef __KEY_H__
#define __KEY_H__
 
unsigned char Key();
 
#endif

Delay.c :

void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}
 

Delay.h :

#ifndef __DELAY_H__
#define __DELAY_H__
 
void Delay(unsigned int xms);
 
#endif

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win10系统安装gradle

最近在搭建spring的源码时&#xff0c;需要gradle来进行来进行包的管理&#xff0c;这里顺便说一下gradle的配置。说明一下&#xff0c;这里使用的gradle的版本是7.5.1。 1.下载gradle 从https://gradle.org/releases/ 选择的版本7.5.1下载。 2.解压安装gradle 在本机上某…

医疗设备产品维修维护服务培训模式

医疗器械产业的发展一方面带动了经济的发展,但同时也带来了一些社会问题。这是由于医疗器械产品与患者的健康息息相关,不良事件的发生会带来负面的社会影响,如曾经发生的婴儿恒温箱变成“烤箱”伤害婴儿,置换的膝关节在体内腐蚀释放重金属损伤神经等。将医疗器械的风险降至最低…

Mac 上终端配置

Mac 上终端配置 初始化了一下自己的 mac 笔记本&#xff0c;所以重新记一下终端配置&#xff0c;最终的完成版的需求是这样的&#xff1a; 存在的指令需要显示绿色进行提示&#xff1a; 不存在的指令则是显示红色进行提示&#xff1a; 同时具备对指令进行提示 一个看起来…

vue前端html导出pdf

package.json中添加依赖 调用方&#xff1a; import htmlToPdf from ../../../utils/file/htmlToPdf.js// 下载方法&#xff0c;pdfDownloadDpi为onClickDownLoad() {htmlToPdf.getPdf(标题1, jsfgyzcpgxmShow, this.pdfDownloadDpi)}htmlToPdf.js // 页面导出为pdf格式 imp…

Python tkinter (10) ——Combobox控件

本文主要是Python tkinter Combobox下拉控件介绍及使用示例。 tkinter系列文章 python tkinter窗口简单实现 Python tkinter (1) —— Label标签 Python tkinter (2) —— Button标签 Python tkinter (3) —— Entry标签 Python tkinter (4) —— Text控件 Python tkinte…

【算法与数据结构】300、LeetCode最长递增子序列

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;   程序如下&#xff1a; class Solution { public:int lengthOfLIS(vector<int>& nums)…

phpMyAdmin 未授权Getshell

前言 做渗透测试的时候偶然发现&#xff0c;phpmyadmin少见的打法&#xff0c;以下就用靶场进行演示了。 0x01漏洞发现 环境搭建使用metasploitable2,可在网上搜索下载&#xff0c;搭建很简单这里不多说了。 发现phpmyadmin&#xff0c;如果这个时候无法登陆&#xff0c;且也…

Spring Boot 整合 Redis 使用教程

作为开发者&#xff0c;相信大家都知道 Redis 的重要性。Redis 是使用 C 语言开发的一个高性能键值对数据库&#xff0c;是互联网技术领域使用最为广泛的存储中间件&#xff0c;它是「Remote Dictionary Service」的首字母缩写&#xff0c;也就是「远程字典服务」。 Redis 以超…

【AI视野·今日Sound 声学论文速览 第四十八期】Mon, 15 Jan 2024

AI视野今日CS.Sound 声学论文速览 Mon, 15 Jan 2024 Totally 5 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers LCB-net: Long-Context Biasing for Audio-Visual Speech Recognition Authors Fan Yu, Haoxu Wang, Xian Shi, Shiliang Zhang在线会议和…

VUE PC端可拖动悬浮按钮

一、实现效果&#xff1a; 二、FloatButton.vue <template><div><div class"sssss"><div class"callback float" mousedown"down" touchstart"down" mousemove"move" touchmove"move" mous…

Python爬虫学习之解析_jsonpath

一、jsonpath的基本使用 import json import jsonpath obj json.load(open(json文件,r,encodingutf-8)) ret jsonpath.jsonpath(obj,jsonpath语法) 二、jsonpath语法 e.g. import json import jsonpathobj json.load(open(jsonpath.json,r,encodingutf-8))#书店所有的书的作…

HashCat 恢复Excel、Word、PPT密码保姆教程

HashCat 恢复Excel、Word、PPT密码 一、流程 整体需要两个步骤 先用office2john.py获取下文件的hash值 python office2john.py 1.xlsx > hash这个命令需要你电脑有python环境&#xff0c;然后在cmd命令窗口中执行此命令就行 文件链接&#xff1a;https://github.com/magnu…

Spring-集成Web

一、引子 前面我们在Spring集成Junit中为读者引出了Spring善于集成其它框架的优势&#xff0c;而Spring项目不可能仅限于小范围的某个方法的测试&#xff0c;终究会落脚于Web项目上。于是&#xff0c;我们就从这里正式进入Spring集成Web的话题。由于笔者会从原生的Java Web开发…

Kotlin中的内置函数-apply、let

在使用Kotlin的过程中会经常用到其内置函数&#xff0c;包括apply&#xff0c;let&#xff0c;run&#xff0c;with&#xff0c;also&#xff0c;takeIf,takeUnless函数等&#xff0c;想要更好熟悉Kotlin&#xff0c;这些函数必须烂熟于心&#xff0c;接下来让我们来逐步了解&a…

7.1、一致公钥密码系统

7.1、一致公钥密码系统 一、引言 在本节中&#xff0c;我们将描述一个真实公钥密码系统的玩具模型。这个模型与维数为 2 的格有着意想不到的联系&#xff0c;由于维数太低&#xff0c;因此存在致命漏洞。不过&#xff0c;它也是一个具有启发性的例子&#xff0c;说明了即使基…

【Pytorch】CNN中的Attention

目录 更大层面上的Attention在attention中&#xff0c;怎么分区channel-wise还是spatial-wise举一个Spatial-Channel Attention的例子 使用广泛的Dot-product Attentionattention机制中的query,key,value的概念解释Attention的一个例子 更大层面上的Attention 在attention中&a…

网络服务综合实验项目

目录 实验要求 运行环境 基础配置 业务需求 实验步骤 一、基础配置 1.1、配置静态IP 1.1.1、 在192.168.159.130中配置 1.1.2、 在192.168.159.131中配置 ​编辑 1.2、修改主机名及hosts映射 1.2.1、在192.168.159.130中配置 1.2.2、 编辑配置hosts文件 1.2.3、重启…

1. 两数之和(C++)(map)(哈希算法)

✨欢迎来到脑子不好的小菜鸟的文章✨ &#x1f388;创作不易&#xff0c;麻烦点点赞哦&#x1f388; 所属专栏&#xff1a;刷题 我的主页&#xff1a;脑子不好的小菜鸟 文章特点&#xff1a;关键点和步骤讲解放在 代码相应位置 前提&#xff1a; 看本文章之前&#xff0c;建…

前端开发项目技术总结

前端 vue框架简单学了一遍&#xff0c;也做了demo&#xff0c;主要学了创建项目、路由、状态管理、UI组件库等。 最近在做前端的项目&#xff0c;总结一些开发遇到的问题和解决方案 数据绑定模型 vue框架的标签 :data 和prop标签 data绑定对应的模型&#xff0c;prop是对应…

【C++杂货铺】详解类和对象 [下]

个人博客&#xff1a;代码菌-CSDN博客 专栏&#xff1a;C杂货铺_代码菌的博客-CSDN博客 目录 &#x1f308;前言&#x1f308; &#x1f4c1; 初始化列表&#xff08;灰常重要&#xff09; &#x1f4c2; 引入 &#x1f4c2; 概念 &#x1f4c2; 特性 &#x1f4c1; 拓展构…