历史上的今天
今天是: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(); } } 三、仿真实现
史海拾趣
|
目前在市面上有多种定位系统,包括Zigbee、WiFi等,以及最新的CSS定位系统。从定位原理上分析,一般的定位系统都可以归纳到基于时间的系统、基于信号强度系统,而这两类系统都有着各自的共性。下面以这两种系统的典型代表 CSS系统(基于时间)和Zig ...… 查看全部问答> |
|
第二次免费开发板赠送,40mb 开发资料包:实例,原理图,keil 正式版,免费下载 第二次免费开发板赠送,40mb 开发资料包:实例,原理图,keil 正式版,免费下载下载50个单片机程序实例和开发板原理图,学林电子免费开发板暑期助学活动报名!暑假在家,就学单片机!申请主贴地址: http://www.51c51.com/bbs/thread-68995-1-1.ht ...… 查看全部问答> |
|
试图使用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 ...… 查看全部问答> |
|
设计一个16位的计数器对CLK1计数,上位机通过STRB对当前的计数值进行锁存,CS为计数器的片选,RD为读选通,读取锁存后的计数值 在QUARTUS中仿真,结果正确,可下载到CPLD后,发现即使CLK1没有输入信号,计数器也在计数,即语句CLK1 \'event AND CL ...… 查看全部问答> |
|
这款51板,让我用很少的时间也就是三两天,就开发成功了,达到我的预期效果: 有51板朋友注意了: 1,必须用44脚封装的3V单片机,我用的是stc90LE58AD,不要AD也可以的。容量越大当然越好 2,串口芯片可以不用3232,用MA ...… 查看全部问答> |
|
如何是实现uboot 读SD卡里面FAT分区的txt文件里面的字符串 看了一下uboot的的文件系统支持,支持挺多的,ext,fat 都支持,但是fat 我看只是支持从fat 区域读写一个文件,但是文件内部的一些字符串好像没有, 我们应该怎么完善它呢? 这个估计要好好看看文件系统了,才知道怎么搞。 有搞过 ...… 查看全部问答> |




