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

目录

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;elseLEDNum--;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);//1if(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.hqwc.cn/news/444182.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git系列---远程操作

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 引用 1.理解分布式版本控制…

Android 12.0 应用中监听系统收到的通知

Android 12.0 通知简介https://blog.csdn.net/Smile_729day/article/details/135502031?spm1001.2014.3001.5502 1. 需求 在系统内置应用中或者在第三方应用中,获取Android系统收到的通知的内容. 2. NotificationListenerService 接口 Android 系统预留了专门的API, 即 No…

【脑电信号处理与特征提取】P7-贾会宾:基于EEG/MEG信号的大尺度脑功能网络分析

基于EEG/MEG信号的大尺度脑功能网络分析 Q: 什么是基于EEG/MEG信号的大尺度脑功能网络分析&#xff1f; A: 基于脑电图&#xff08;EEG&#xff09;或脑磁图&#xff08;MEG&#xff09;信号的大尺度脑功能网络分析是一种研究大脑活动的方法&#xff0c;旨在探索脑区之间的功能…

075:vue+mapbox 利用高德地址逆转换,点击地图,弹出地址信息

第075个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中利用高德逆地理编码,点击地图,弹出某点坐标和地址信息。这里要仔细阅读高德地图的逆编码API,同时要注意的是,这种转换在中国很好用,到了欧美国家就不好使了。同时这个底图是天地图的图像和标记。 直接…

Qt 5.9.4 转 Qt 6.6.1 遇到的问题总结(三)

1.QSet: toList 中的toList 函数已不存在&#xff0c;遇到xx->toList改成直接用&#xff0c;如下&#xff1a; 2.开源QWT 图形库中QwtDial中的 setPenWidth 变成 setPenWidthF函数。 3.QDateTime 中无setTime_t 改为了setSecsSinceEpoch函数。 4.QRegExp 类已不存在 可以用Q…

vue3/vue2中自定义指令不可输入小数点.

import { directive } from vueconst noDecimal {mounted(el) {el.addEventListener(keypress, (e) > {if (e.key .) {e.preventDefault() }})} }// 使用自定义指令 directive(no-decimal, noDecimal)使用 标签上添加 v-no-decimal <el-input…

【微服务】Spring Boot集成ELK实用案例

推荐一款我一直在用国内很火的AI网站&#xff0c;包含GPT3.5/4.0、文心一言、通义千问、智谱AI等多个AI模型&#xff0c;支持PC、APP、VScode插件同步使用&#xff0c;点击链接跳转->ChatGPT4.0中文版 一、前言 在现代软件开发中&#xff0c;微服务架构已成为一种流行趋势。…

使用 axios 请求库,设置请求拦截

什么是 axios&#xff1f; 基于promise网络请求库&#xff0c;可以同构&#xff08;同一套代码可以运行在浏览器&#xff09;&#xff0c;在服务端&#xff0c;使用原生node.js的http模块&#xff0c;在客户端&#xff08;浏览器&#xff09;中&#xff0c;使用XMLHttpRequests…

轻松录制视频,WPS录屏功能全攻略

“有人知道wps怎么录屏吗&#xff1f;老师要求我们录制一段视频&#xff0c;是关于课堂教学的&#xff0c;可是我不会录制文档&#xff0c;眼看就快到提交的时间了&#xff0c;现在真的很着急&#xff0c;希望大家帮帮我&#xff01;” 随着信息技术的发展&#xff0c;录制屏幕…

探索设计模式的魅力:精准解读桥接模式-用桥接模式构建可扩展的软件系统

设计模式专栏&#xff1a;http://t.csdnimg.cn/nolNS 目录 一、了解桥接模式&#xff1a;探索抽象和实现的分离 1.1 开-闭原则 1.2 组合/聚合复用原则 1.3 定义 1.4 用意 1.5 基本思想 1.6 组成部分 1.7 桥梁模式的示意性系统的结构图 二、桥接模式的优势&#xff1a…

vue-cli项目运行流程介绍

一、前言 ​ 本文介绍 vue-cli搭建的项目运行流程&#xff0c;基于已经搭建好的基础项目。关于 vue-cli 构建项目的详细流程&#xff0c;可参考博文&#xff1a;使用vue脚手架构建项目 二、main.js 项目运行 会加载入口文件 main.js /* html文件中&#xff0c;通过script …

uWSGI、灰度发布、网站数据指标分析、网站限速

1 案例1&#xff1a;部署Python网站项目 1.1 问题 配置Nginx使其可以将动态访问转交给uWSGI&#xff1a; 1.2 方案 安装Python工具及依赖 安装uWSGI并编写配置文件 1.3 步骤 实现此案例需要按照如下步骤进行。 步骤一&#xff1a; 首先$教学资料目录/python拷贝到虚拟…