一、使用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单片机在定时中断函数里执行独立按键的扫描程序
推荐阅读最新更新时间:2024-11-02 20:56
设计资源 培训 开发板 精华推荐
- LTC1735 的典型应用 - 高效率同步降压型开关稳压器
- LT6654AHS6-2.5 升压型输出电流电压基准的典型应用
- 用于工业应用的 LT3973HMS 3.3V 降压转换器的典型应用
- TB67B000FG 三相无刷直流电机驱动器评估板
- AD8506ACBZ-REEL7 四极巴特沃斯滤波器在血糖仪中的典型应用电路
- 具有误差放大器斜率补偿的 LT124XIS8 高速电流模式脉宽调制器的典型应用电路
- 【CW32】我有多少粉
- EVAL-AD7606SDZ,用于评估 AD7606、16 位同步采样、8 通道、SAR ADC 的评估板
- LTC3727EG-1 8.5V/3A、5V/5A 降压型稳压器的典型应用电路
- DC1319BAB、LT3756 用于高压 LED 控制器的演示电路