×
单片机 > 单片机程序设计 > 详情

单片机学习笔记-51单片机实现独立按键的短按及长按触发

发布时间:2024-05-20 发布时间:
|

一、使用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();

}

}

三、仿真实现


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈AVR中定时器几种工作模式