历史上的今天
返回首页

历史上的今天

今天是:2025年06月19日(星期四)

正在发生

2020年06月19日 | 单片机学习笔记-51单片机实现独立按键的短按及长按触发

2020-06-19 来源:eefocus

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

二、编写程序


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

---- @Project: Independent-KEY

---- @File: main.c

---- @Edit: ZHQ

---- @Version: V1.0

---- @CreationTime: 20200506

---- @ModifiedTime: 20200506

---- @Description: 两个独立按键S1和S2,按住其中一个按键,在短时间内松手,则认为是短按,触发蜂鸣器短鸣一声。如果一直按住这个按键不松手,那么超过规定的长时间内,则认为是长按,触发蜂鸣器长鸣一声。

---- 单片机: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_voice_long  600   /*蜂鸣器长叫的持续时间*/

 

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

#define const_key_time_long1   1000     /*长按的按键去抖动延时的时间*/

 

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

#define const_key_time_long2   1000     /*长按的按键去抖动延时的时间*/

 

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

/*定义按键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 ucShortTouchFlag1=0; /*短按的触发标志*/

 

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

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

unsigned char ucShortTouchFlag2=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 初始化单片机

**/

void Init(void)

{

Init_T0();

BUZZER = 1;

}

/**

* @brief  扫描按键函数

* @param  无

* @retval 长按与短按的按键扫描的详细过程: 

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

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

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

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

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

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

* 第三步:如果按键按下的时间超过了短按阀值const_key_time_short1,则马上把短按标志ucShortTouchFlag1=1;

*         如果还没有松手,一旦发现按下的时间超过长按阀值const_key_time_long1时,

*         先把短按标志ucShortTouchFlag1清零,然后触发长按。在这段程序里,把自锁标志ucKeyLock1置位,

*         是为了防止按住按键不松手后一直触发。

* 第四步:等按键松开后,自锁标志ucKeyLock12及时清零,为下一次自锁做准备。如果发现ucShortTouchFlag1等于1,

*         说明短按有效,这时触发一次短按。

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

**/

void Key_Scan(void)

{

/*扫描S1*/

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

{

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

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

if(ucShortTouchFlag1 == 1)/*短按*/

{

ucShortTouchFlag1 = 0;

ucKeySec = 1; /*触发S1短按*/

}

}

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

{

uiKeyTimeCnt1 ++;

if(uiKeyTimeCnt1 > const_key_time_short1)/*判定短按*/

{

ucShortTouchFlag1 = 1;/*激活短按的有效标志位*/

}

if(uiKeyTimeCnt1 > const_key_time_long1)/*判定长按*/

{

ucShortTouchFlag1 = 0;/*清除短按的有效标志位*/

uiKeyTimeCnt1 = 0;

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

ucKeySec = 2; /*触发S1长按*/

}

}

/*扫描S2*/

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

{

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

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

if(ucShortTouchFlag2 == 1)/*短按*/

{

ucShortTouchFlag2 = 0;

ucKeySec = 3; /*触发S1短按*/

}

}

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

{

uiKeyTimeCnt2 ++;

if(uiKeyTimeCnt2 > const_key_time_short2)/*判定短按*/

{

ucShortTouchFlag2 = 1;/*激活短按的有效标志位*/

}

if(uiKeyTimeCnt2 > const_key_time_long2)/*判定长按*/

{

ucShortTouchFlag2 = 0;/*清除短按的有效标志位*/

uiKeyTimeCnt2 = 0;

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

ucKeySec = 4; /*触发S1长按*/

}

}

}

/**

* @brief  按键服务函数

* @param  无

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

**/

void key_Service(void)

{

switch(ucKeySec)

{

case 1: /*S1短按*/

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

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

break;

case 2: /*S1长按*/

uiVoiceCnt = const_voice_long;  /*蜂鸣器长叫*/

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

break;

case 3: /*S2短按*/

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

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

break;

case 4: /*S2长按*/

uiVoiceCnt = const_voice_long;  /*蜂鸣器长叫*/

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();

}

}

 

三、仿真实现

推荐阅读

史海拾趣

Fairchild Imaging公司的发展小趣事

随着技术的不断进步和市场需求的不断变化,Fairchild Imaging开始拓展其产品线。除了继续推出具有竞争力的图像传感器外,公司还涉足了高端的科研级相机市场。这些科研级相机不仅具有出色的成像性能,还具备高度的可靠性和稳定性,满足了科研领域的特殊需求。此外,Fairchild Imaging还推出了一系列CCD及CMOS芯片,这些芯片在图像传输、处理和控制等方面表现出色,被广泛应用于各种电子设备和系统中。

Dytran Instruments Inc公司的发展小趣事

尽管已经被收购并进行了业务整合,但Dytran并没有停止其创新的步伐。公司继续加大研发投入,推动传感器技术的不断创新和升级。同时,Dytran还积极探索新的应用领域和市场空间,以满足不断变化的客户需求。

在未来,Dytran将继续致力于为客户提供高质量、高性能的传感器产品和解决方案。同时,公司还将积极参与国际竞争和合作,推动传感器技术的国际化和标准化进程。通过不断创新和发展,Dytran有望在电子行业中继续保持其领先地位并实现更加辉煌的未来。

以上五个故事框架概述了Dytran Instruments Inc.公司在电子行业中的发展历程、技术创新、市场拓展、被收购与业务整合以及未来展望等方面的重要事件和里程碑。这些故事展示了Dytran如何凭借其技术实力和市场洞察力在竞争激烈的电子行业中脱颖而出并实现持续发展。

Gamewell-FCI ( Honeywell )公司的发展小趣事

随着技术的不断成熟和产品线的不断完善,Dytran开始积极拓展市场。公司不仅在美国本土取得了良好的销售业绩,还通过参加国际展览和建立海外办事处等方式,将产品推向全球。在这个过程中,Dytran的传感器产品得到了众多行业客户的认可,广泛应用于航空航天、工业和汽车行业的产品开发测试和嵌入式监控解决方案。

为了更好地服务全球客户,Dytran在成立两年后将其总部迁至美国加利福尼亚州的查茨沃思市。这里地理位置优越,交通便利,有利于公司进一步拓展北美市场。同时,公司还加强了与全球合作伙伴的合作,共同推动传感器技术的发展和应用。

DAQ Electronics LLC公司的发展小趣事

随着国内外市场的不断拓展和客户需求的不断增长,DAQ Electronics LLC公司开始积极探索国际化发展道路。公司积极参加国际展会和技术交流活动,与全球同行建立了广泛的联系和合作。同时,公司也加大了对海外市场的投入力度,不断拓展海外市场份额。这种国际化的发展战略不仅为公司带来了更多的商业机会和合作伙伴也为公司未来的发展提供了更广阔的空间和机遇。

请注意,以上故事均为虚构内容,仅供参考。如有需要,建议直接联系DAQ Electronics LLC公司获取其真实的发展历程和故事。

GeneSiC公司的发展小趣事

随着国内外市场的不断拓展和客户需求的不断增长,DAQ Electronics LLC公司开始积极探索国际化发展道路。公司积极参加国际展会和技术交流活动,与全球同行建立了广泛的联系和合作。同时,公司也加大了对海外市场的投入力度,不断拓展海外市场份额。这种国际化的发展战略不仅为公司带来了更多的商业机会和合作伙伴也为公司未来的发展提供了更广阔的空间和机遇。

请注意,以上故事均为虚构内容,仅供参考。如有需要,建议直接联系DAQ Electronics LLC公司获取其真实的发展历程和故事。

AMD(超微)公司的发展小趣事

DAQ Electronics LLC公司成立于XX年,由一群热衷于数据采集技术的工程师创立。当时,市场上对于高精度、高效率的数据采集设备需求日益增长,但现有产品往往无法满足。创始人们凭借对技术的深刻理解和敏锐的市场洞察力,决定自主研发数据采集硬件,并成立了DAQ Electronics LLC公司。他们凭借有限的资金和资源,开始了艰苦的创业之旅。

问答坊 | AI 解惑

【藏书阁】开关电源技术指南

磁性元件,中文电子书,包括开关电源中的变压器,磁性材料,电感器,高频磁放大器,合金磁性材料,以及一些设计应用文章…

查看全部问答>

Zigbee与CSS技术在定位应用上的一些比较

目前在市面上有多种定位系统,包括Zigbee、WiFi等,以及最新的CSS定位系统。从定位原理上分析,一般的定位系统都可以归纳到基于时间的系统、基于信号强度系统,而这两类系统都有着各自的共性。下面以这两种系统的典型代表 CSS系统(基于时间)和Zig ...…

查看全部问答>

第二次免费开发板赠送,40mb 开发资料包:实例,原理图,keil 正式版,免费下载

第二次免费开发板赠送,40mb 开发资料包:实例,原理图,keil 正式版,免费下载下载50个单片机程序实例和开发板原理图,学林电子免费开发板暑期助学活动报名!暑假在家,就学单片机!申请主贴地址:  http://www.51c51.com/bbs/thread-68995-1-1.ht ...…

查看全部问答>

如何移植JAVA到WM5.0上 ?

有一个在WINDOWS上运行的JAVA程序 请问如何把它移植到WM5.0上   谢谢 …

查看全部问答>

关于DeviceIoControl返回87

试图使用DeviceIoControl向过滤驱动发送控制代码。 源代码如下: #define START_FILTER CTL_CODE(FILE_DEVICE_CD_ROM_FILE_SYSTEM,XD_CTL_CODE_READONLY,METHOD_BUFFERED,FILE_ANY_ACCESS) #define STOP_FILTER CTL_CODE(FILE_DEVICE_CD_ROM_FIL ...…

查看全部问答>

求助:VHDL设计计数器的问题

设计一个16位的计数器对CLK1计数,上位机通过STRB对当前的计数值进行锁存,CS为计数器的片选,RD为读选通,读取锁存后的计数值 在QUARTUS中仿真,结果正确,可下载到CPLD后,发现即使CLK1没有输入信号,计数器也在计数,即语句CLK1 \'event AND CL ...…

查看全部问答>

51板湿度计时间已显(全部完工)上传照及程序,还有注意事项

  这款51板,让我用很少的时间也就是三两天,就开发成功了,达到我的预期效果:   有51板朋友注意了:   1,必须用44脚封装的3V单片机,我用的是stc90LE58AD,不要AD也可以的。容量越大当然越好 2,串口芯片可以不用3232,用MA ...…

查看全部问答>

【设计工具】Atlys Spartan-6 FPGA 开发板原理图(原厂光盘资料)

Atlys Spartan-6 FPGA 开发板原理图(原厂光盘资料)…

查看全部问答>

大神们来看看

请问430单片机进如低功耗模式LPM4,就是啥都关了后,端口接到示波器上还会有输出波形吗?或者有电压吗? 多谢了!…

查看全部问答>

如何是实现uboot 读SD卡里面FAT分区的txt文件里面的字符串

看了一下uboot的的文件系统支持,支持挺多的,ext,fat 都支持,但是fat 我看只是支持从fat 区域读写一个文件,但是文件内部的一些字符串好像没有, 我们应该怎么完善它呢?    这个估计要好好看看文件系统了,才知道怎么搞。 有搞过 ...…

查看全部问答>