51单片机实现独立按键的双击按键触发

发布者:dswecd最新更新时间:2021-11-22 关键字:51单片机  独立按键 手机看文章 扫描二维码
随时随地手机看文章

一、使用proteus绘制简单的电路图,用于后续仿真

二、编写程序


/********************************************************************************************************************

----@Project:Independent-KEY

----@File:main.c

----@Edit:ZHQ

----@Version:V1.0

----@CreationTime:20200506

----@ModifiedTime:20200506

----@Description:有两个独立按键,每双击一个独立按键,蜂鸣器发出“滴”的一声后就停。

----单片机:AT89C52

********************************************************************************************************************/

#include "reg52.h"

/*——————宏定义——————*/

#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   /*1ms timer calculation method in 12Tmode*/

 

#define const_voice_short  80   /*蜂鸣器短叫的持续时间*/

 

#define const_key_time1   60  /*按键去抖动延时的时间*/

#define const_key_time2   60  /*按键去抖动延时的时间*/

 

#define const_interval_time1   600  /*连续两次按键之间的有效时间差*/

#define const_interval_time2   600  /*连续两次按键之间的有效时间差*/

 

/*——————变量函数定义及声明——————*/

/*定义按键S1*/

sbit Key_S1 = P0^0;

/*定义按键S2*/

sbit Key_S2 = P0^1;

/*定义蜂鸣器*/

sbit BUZZER = P2^7;

 

unsigned char ucKeySec = 0;   /*被触发的按键编号*/

 

unsigned int  uiKeyTimeCnt1 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock1 = 0; /*按键触发后自锁的变量标志*/

unsigned char ucKeyTouchCnt1 = 0; /*按键按下的次数记录*/

unsigned int  uiKeyIntervalCnt1 = 0; /*按键间隔的时间计数器*/

 

unsigned int  uiKeyTimeCnt2 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock2 = 0; /*按键触发后自锁的变量标志*/

unsigned char ucKeyTouchCnt2 = 0; /*按键按下的次数记录*/

unsigned int  uiKeyIntervalCnt2 = 0; /*按键间隔的时间计数器*/

 

unsigned int  uiVoiceCnt = 0;  /*蜂鸣器鸣叫的持续时间计数器*/

 

 

/**

* @brief  定时器0初始化函数

* @param  无

* @retval 初始化T0

**/

void Init_T0(void)

{

TMOD = 0x01;                    /*set timer0 as mode1 (16-bit)*/

TL0 = T1MS;                     /*initial timer0 low byte*/

TH0 = T1MS >> 8;                /*initial timer0 high byte*/

}

/**

* @brief  外围初始化函数

* @param  无

* @retval 初始化外围

**/

void Init_Peripheral(void)

{

ET0 = 1;/*允许定时中断*/

TR0 = 1;/*启动定时中断*/

EA = 1;/*开总中断*/

 

}

 

/**

* @brief  初始化函数

* @param  无

* @retval 初始化单片机

**/

voidInit(void)

{

Init_T0();

BUZZER = 1;

}

/**

* @brief  扫描按键函数

* @param  无

* @retval 独立双击按键扫描的详细过程:

* 第一步:平时没有按键被触发时,按键的自锁标志,去抖动延时计数器一直被清零。

*         如果之前已经有按键触发过一次,那么启动时间间隔计数器uiKeyIntervalCnt1,

*         在这个允许的时间差范围内,如果一直没有第二次按键触发,则把累加按键触发的

*         次数ucKeyTouchCnt1也清零。

* 第二步:一旦有按键被按下,去抖动延时计数器开始在定时中断函数里累加,在还没累加到

*         阀值const_key_time1时,如果在这期间由于受外界干扰或者按键抖动,而使

*         IO口突然瞬间触发成高电平,这个时候马上把延时计数器uiKeyTimeCnt1

*         清零了,这个过程非常巧妙,非常有效地去除瞬间的杂波干扰。

*         以后凡是用到开关感应器的时候,都可以用类似这样的方法去干扰。

* 第三步:如果按键按下的时间超过了阀值const_key_time1,马上把自锁标志ucKeyLock1置位,

*         防止按住按键不松手后一直触发。与此同时,累加一次按键次数,如果按键次数累加有两次以上,

*         则认为触发双击按键,并把编号ucKeySec赋值。 

* 第四步:等按键松开后,自锁标志ucKeyLock1及时清零,为下一次自锁做准备。并且累加间隔时间,

*         防止两次按键的间隔时间太长。

* 第五步:以上整个过程,就是识别按键IO口下降沿触发的过程。

**/

void Key_Scan(void)

{

/*扫描S1*/

if(Key_S1 == 1)/*如果没有键按下(高电平),将一些标志位及时清零*/

{

ucKeyLock1 = 0;/*自锁标志位清0*/

uiKeyTimeCnt1 = 0;/*按键去抖动延时计数器清零*/

if(ucKeyTouchCnt1 > 0)/*如果之前触发过一次,再来一次就构成双击了*/

{

uiKeyIntervalCnt1 ++;/*按键间隔的时间计数器累加*/

if(uiKeyIntervalCnt1 > const_interval_time1)/*超过最大允许间隔*/

{

uiKeyIntervalCnt1 = 0;

ucKeyTouchCnt1 = 0; /*清零按键的按下的次数*/

}

}

}

else if(ucKeyLock1 == 0)/*如果有按键按下,且是第一次按下*/

{

uiKeyTimeCnt1 ++;

if(uiKeyTimeCnt1 > const_key_time1)

{

uiKeyTimeCnt1 = 0;

ucKeyLock1 = 1;/*自锁标志位置位,避免一直触发*/

uiKeyIntervalCnt1 = 0;/*按键有效间隔的时间计数器清零,松开后计数*/

ucKeyTouchCnt1 ++; /*按键触发一次*/

if(ucKeyTouchCnt1 > 1)/*连续被按了两次以上*/

{

ucKeyTouchCnt1 = 0;

ucKeySec = 1; /*触发S1*/

}

}

}

/*扫描S2*/

if(Key_S2 == 1)/*如果没有键按下(高电平),将一些标志位及时清零*/

{

ucKeyLock2 = 0;/*自锁标志位清0*/

uiKeyTimeCnt2 = 0;/*按键去抖动延时计数器清零*/

if(ucKeyTouchCnt2 > 0)/*如果之前触发过一次,再来一次就构成双击了*/

{

uiKeyIntervalCnt2 ++;/*按键间隔的时间计数器累加*/

if(uiKeyIntervalCnt2 > const_interval_time2)/*超过最大允许间隔*/

{

uiKeyIntervalCnt2 = 0;

ucKeyTouchCnt2 = 0; /*清零按键的按下的次数*/

}

}

}

else if(ucKeyLock2 == 0)/*如果有按键按下,且是第一次按下*/

{

uiKeyTimeCnt2 ++;

if(uiKeyTimeCnt2 > const_key_time2)

{

uiKeyTimeCnt2 = 0;

ucKeyLock2 = 1;/*自锁标志位置位,避免一直触发*/

uiKeyIntervalCnt2 = 0;/*按键有效间隔的时间计数器清零,松开后计数*/

ucKeyTouchCnt2 ++; /*按键触发一次*/

if(ucKeyTouchCnt2 > 1)/*连续被按了两次以上*/

{

ucKeyTouchCnt2 = 0;

ucKeySec = 2; /*触发S2*/

}

}

}

}

/**

* @brief  按键服务函数

* @param  无

* @retval 根据扫描得到的值,进行数据处理

**/

void key_Service(void)

{

switch(ucKeySec)

{

case 1: /*S1双击*/

uiVoiceCnt = const_voice_short;  /*蜂鸣器短叫*/

ucKeySec = 0; /*响应按键服务处理程序后,按键编号清零,避免一致触发*/

break;

case 2:/*S2双击*/

uiVoiceCnt = const_voice_short;  /*蜂鸣器短叫*/

ucKeySec = 0; 

break;

}

}

/**

* @brief  定时器0中断函数

* @param  无

* @retval 无

**/

void ISR_T0(void)interrupt 1

{

TF0 = 0;  /*清除中断标志*/

  TR0 = 0; /*关中断*/

/*扫描按键*/

Key_Scan();

if(0 != uiVoiceCnt)

{

uiVoiceCnt --;

BUZZER = 0;

}

else

{

BUZZER = 1;

}

TL0 = T1MS;                     /*initial timer0 low byte*/

TH0 = T1MS >> 8;                /*initial timer0 high byte*/

  TR0 = 1; /*开中断*/

}

/**

* @brief  延时函数

* @param  无

* @retval 无

**/

void Delay_Long(unsigned int uiDelayLong)

{

   unsigned int i;

   unsigned int j;

   for(i=0;i   {

      for(j=0;j<500;j++)  /*内嵌循环的空指令数量*/

          {

             ; /*一个分号相当于执行一条空语句*/

          }

   }

}

/*——————主函数——————*/

/**

* @brief  主函数

* @param  无

* @retval 实现LED灯闪烁

**/

void main()

{

/*单片机初始化*/

Init();

/*延时,延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定*/

Delay_Long(100);

/*单片机外围初始化*/

Init_Peripheral();

while(1)

{

 

/*按键服务函数*/

key_Service();

}

}

 

三、仿真实现

关键字:51单片机  独立按键 引用地址:51单片机实现独立按键的双击按键触发

上一篇:51单片机实现两个独立按键的组合按键触发
下一篇:51单片机在定时中断函数里执行独立按键的扫描程序

推荐阅读最新更新时间:2024-11-02 20:56

基于C51单片机的汽车嵌入式车载防盗系统设计方案
1.引言 目前防盗器市场的主流产品是电子式防盗器,分为单向防盗器和双向防盗器,这两种防盗器都是车主通过遥控器来控制汽车,双向防盗器可以把车辆的真实状况反馈给车主。 GPS汽车防盗器依托全球定位系统,它将报警信息和报警车辆所在位置无声地传送到报警中心。由于车主不能直接控制车辆,价格和使用费用较高,使其推广应用受到很大限制,目前还没有普遍使用。GSM汽车双向防盗器是网络式防盗器的后起之秀,它依托全球GSM网络,车主可直接通过手机接受报警和控制车辆,性能价格比较好,它代表着汽车防盗器的发展趋势,自推出以来收到客户的青睐。 本文提出的汽车嵌入式车载防盗系统属于GSM防盗系统,没有采用昂贵的GPS模块,CPU采用了C51单片机,市场价
[单片机]
基于C<font color='red'>51单片机</font>的汽车嵌入式车载防盗系统设计方案
C51单片机的压缩BCD码相加程序
设被加数 NA 及加数 NB 均为三字节压缩BCD码,分别存放于内部 RAM 的 20H~22H 及 30H~32H 单元中,低位在前,高位在后。 要求计算两数之和,并将和存放到内部 RAM 中 3FH~42H 单元,仍然是低位在前,高位在后。 编写完整的汇编语言源程序。 ;---------------------------------------------------------------------- 最佳答案: ;这个程序当然是楼主要求的C51单片机程序。 ;下面增加一些调试时使用的数据。 ORG 0000H MOV 20H, #12H ;假设被加数NA是563412 MOV 21H, #34H
[单片机]
MCS-51单片机引脚功能介绍
40只引脚双列直插封装(DIP)。40只引脚按功能分为3类: (1)电源及时钟引脚: Vcc、Vss;XTAL1、XTAL2。 (2)控制引脚: PSEN*、EA* 、ALE、RESET (即RST)。 (3)I/O口引脚:P0、P1、P2、P3,为4个8位I/O口的外部引脚。 2.2.1 电源及时钟引脚 1.电源引脚 (1)Vcc(40脚):+5V电源; (2)Vss(20脚):接地。 2.时钟引脚 (1)XTAL1(19脚):如果采用外接晶体振荡器时,此引脚应接地。 (2)XTAL2(18脚):接外部晶体的另一端。 2.2.2 控制引脚 提供控制信号,有的引脚还具有复用功能。 (1) RST/
[单片机]
MCS-<font color='red'>51单片机</font>引脚功能介绍
51单片机入门之六:1602液晶显示
本部分主要介绍1602液晶显示,显示内容为“Hello,Welcome to my site,my friends.”。 原理图如下: 程序如下: #include reg52.h #define uchar unsigned char #define uint unsigned int sbit RS=P3^0; //数据/命令选择端(H/L) sbit EN=P3^2; //使能端 sbit RW=P3^1; //读/写选择端(H/L),本文章只写,所以该端口供低电平 sbit wela=P3^3;//锁存器位选信号 uchar table1 = Hello,Welcome to my ;//字符表1 uchar tabl
[单片机]
<font color='red'>51单片机</font>入门之六:1602液晶显示
基于ADC0809和51单片机的多路数据采集系统设计
“数据采集”是指将温度、压力、流量、位移等模拟物理量采集并转换成数字量后,再由计算机进行存储、处理、显示和打印的过程,相应的系统称为数据采集系统。 本文的主要任务是对0~5V的直流电压进行测量并送到远端的PC机上进行显示。由于采集的是直流信号,对于缓慢变化的信号不必加采样保持电路,因此选用市面上比较常见的逐次逼近型ADC0809芯片,该芯片转换速度快,价格低廉,可以直接将直流电压转换为计算机可以处理的数字量。同时选用低功耗的LCD显示器件来满足其在终端显示采集结果的需求。终端键盘控制采用尽可能少的键来实现控制功能,为了防止键盘不用时的误操作,设计时还设置了锁键功能,在键盘的输入消抖方面,则采用软件消抖方法来降低硬件开销,提高
[单片机]
基于ADC0809和<font color='red'>51单片机</font>的多路数据采集系统设计
51单片机学习总结系列(0)之单片机最小系统
学习51单片机接近两年了,最近总结一下51单片机学习,加上明年3月报了蓝桥杯大赛单片机类,也算是对比赛的准备。后续主要以蓝桥杯配的板子CT107D更新,还会加上平时遇到板子的模块以及自己做的一些小项目,每周保持更新,如果以下内容有问题,欢迎指正。(782373034@qq.com) 对于一个初学者来说,我个人认为第一个要了解的就是单片机最小系统,任何开发板也是在此基础上外加一系列外围电路模块。所以足以说明它的重要性。 下面先贴出51单片机最小系统图。 如图中所示,51单片机最小系统包括复位电路、时钟电路、EA拉高。图中P0口接了一个10K上拉电阻,主要是P0口驱动能力比较弱。下面分析最小系统各个部分。 时钟电路:单
[单片机]
<font color='red'>51单片机</font>学习总结系列(0)之单片机最小系统
51单片机-数据类型强制转换
1.实用性改善 为了使上一讲的功能更加完善,我们编写新的实用型的代码,效果是让数码管显示的数就是输入引脚高电平持续的微秒数,最高能捕获到999999微秒。如果高电平持续的时间超出这个取值范围,那么数码管不够显示,所以超出范围的话我们就让6个数码管显示 FFFFFF。 因为计数器计时到65535之后就会产生溢出,也就是超过71ms就会溢出一次,我们知道计数器溢出也是会产生中断的,所以在中断函数里我们实现让变量x简单的自加1表明时间过去了71毫秒左右。 假设高电平持续的时间有75毫秒左右,那么得出最后的微秒数就是 x*71111+(TH0*256+TL0)*(12/11059200)*1000000; 现在我们首
[单片机]
51单片机I2C总线代码
I2C总线相关函数: void I2Cstart()//开始标志 { SDA=1; SCL=1; SDA=0; delay1ms(4); SCL=0; delay1ms(4); } void I2Cstop()//结束标志 { SCL=0; delay1ms(4); SDA=0; delay1ms(4); SCL=1; delay1ms(4); SDA=1; delay1ms(4); } unsigned char I2Creadack() { unsigned char i,byte; byte=0; for(i=0;i 8;i++) { SCL=0; SDA=1; delay1ms(4
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved