开场白:
上一节讲了在主函数中利用累计主循环次数来实现独立按键的检测,但是它也有一个小小的不足,随着在主函数中任务量的增加,为了保证去抖动延时的时间一致性,要适当调整一下去抖动的时间阀值const_key_time1。如何解决这个问题呢?这一节教大家在主函数中利用累计定时中断的次数来实现独立按键的检测,可以有效地避免这个问题。要教会大家一个知识点:如何在上一节的基础上,略作修改,就可以在主函数中,利用累计定时中断的次数来实现去抖动的延时。
具体内容,请看源代码讲解。
(1)硬件平台:基于朱兆祺51单片机学习板。用矩阵键盘中的S1和S5号键作为独立按键,记得把输出线P0.4一直输出低电平,模拟独立按键的触发地GND。
(2)实现功能:有两个独立按键,每按一个独立按键,蜂鸣器发出“滴”的一声后就停。
(3)源代码讲解如下:
#include "REG52.H"
#define const_voice_short 40 //蜂鸣器短叫的持续时间
/* 注释一:
* 调整抖动时间阀值的大小,可以更改按键的触发灵敏度。
* 去抖动的时间本质上等于累计定时中断次数的时间。
*/
#define const_key_time1 30 //按键去抖动延时的时间
#define const_key_time2 30 //按键去抖动延时的时间
void initial_myself();
void initial_peripheral();
void delay_long(unsigned int uiDelaylong);
void T0_time(); //定时中断函数
void key_service(); //按键服务的应用程序
void key_scan(); //按键扫描函数
sbit key_sr1=P0^0; //对应朱兆祺学习板的S1键
sbit key_sr2=P0^1; //对应朱兆祺学习板的S5键
sbit key_gnd_dr=P0^4; //模拟独立按键的地GND,因此必须一直输出低电平
sbit beep_dr=P2^7; //蜂鸣器的驱动IO口
unsigned char ucKeySec=0; //被触发的按键编号
unsigned char ucKeyStartFlag1=0; //启动定时中断计数的开关
unsigned int uiKeyTimeCnt1=0; //按键去抖动延时计数器
unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志
unsigned char ucKeyStartFlag2=0; //启动定时中断计数的开关
unsigned int uiKeyTimeCnt2=0; //按键去抖动延时计数器
unsigned char ucKeyLock2=0; //按键触发后自锁的变量标志
unsigned int uiVoiceCnt=0; //蜂鸣器鸣叫的持续时间计数器
void main()
{
initial_myself();
delay_long(100);
initial_peripheral();
while(1)
{
key_scan(); //按键扫描函数
key_service(); //按键服务的应用程序
}
}
void key_scan()//按键扫描函数
{
/* 注释二:
* 独立按键扫描的详细过程:
* 第一步:平时没有按键被触发时,按键的自锁标志,计时器开关和去抖动延时计数器一直被清零。
* 第二步:一旦有按键被按下,启动计时器,去抖动延时计数器开始在定时中断函数里累加,在还没累加到
* 阀值const_key_time1时,如果在这期间由于受外界干扰或者按键抖动,而使
* IO口突然瞬间触发成高电平,这个时候马上停止计时,并且把延时计数器uiKeyTimeCnt1
* 清零了,这个过程非常巧妙,非常有效地去除瞬间的杂波干扰。这是我实战中摸索出来的。
* 以后凡是用到开关感应器的时候,都可以用类似这样的方法去干扰。
* 第三步:如果按键按下的时间超过了阀值const_key_time1,则触发按键,把编号ucKeySec赋值。
* 同时,马上把自锁标志ucKeyLock1置位,防止按住按键不松手后一直触发。
* 第四步:等按键松开后,自锁标志ucKeyLock1及时清零,为下一次自锁做准备。
* 第五步:以上整个过程,就是识别按键IO口下降沿触发的过程。
*/
if(key_sr1==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
ucKeyLock1=0; //按键自锁标志清零
ucKeyStartFlag1=0; //停止计数器
uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
}
else if(ucKeyLock1==0)//有按键按下,且是第一次被按下
{
ucKeyStartFlag1=1; //启动计数器
if(uiKeyTimeCnt1>const_key_time1)
{
ucKeyStartFlag1=0; //停止计数器
uiKeyTimeCnt1=0;
ucKeyLock1=1; //自锁按键置位,避免一直触发
ucKeySec=1; //触发1号键
}
}
if(key_sr2==1)
{
ucKeyLock2=0;
ucKeyStartFlag2=0; //停止计数器
uiKeyTimeCnt2=0;
}
else if(ucKeyLock2==0)
{
ucKeyStartFlag2=1; //启动计数器
if(uiKeyTimeCnt2>const_key_time2)
{
ucKeyStartFlag2=0; //停止计数器
uiKeyTimeCnt2=0;
ucKeyLock2=1;
ucKeySec=2; //触发2号键
}
}
}
void key_service() //第三区 按键服务的应用程序
{
switch(ucKeySec) //按键服务状态切换
{
case 1:// 1号键 对应朱兆祺学习板的S1键
uiVoiceCnt=const_voice_short; //按键声音触发,滴一声就停。
ucKeySec=0; //响应按键服务处理程序后,按键编号清零,避免一致触发
break;
case 2:// 2号键 对应朱兆祺学习板的S5键
uiVoiceCnt=const_voice_short; //按键声音触发,滴一声就停。
ucKeySec=0; //响应按键服务处理程序后,按键编号清零,避免一致触发
break;
}
}
void T0_time() interrupt 1
{
TF0=0; //清除中断标志
TR0=0; //关中断
if(ucKeyStartFlag1==1)//启动计数器
{
if(uiKeyTimeCnt1<0xffff) //防止计数器超范围
{
uiKeyTimeCnt1++;
}
}
if(ucKeyStartFlag2==1)//启动计数器
{
if(uiKeyTimeCnt2<0xffff) //防止计数器超范围
{
uiKeyTimeCnt2++;
}
}
if(uiVoiceCnt!=0)
{
uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫
beep_dr=0; //蜂鸣器是PNP三极管控制,低电平就开始鸣叫。
}
else
{
; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。
beep_dr=1; //蜂鸣器是PNP三极管控制,高电平就停止鸣叫。
}
TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
TL0=0x2f;
TR0=1; //开中断
}
void delay_long(unsigned int uiDelayLong)
{
unsigned int i;
unsigned int j;
for(i=0;i
关键字:主函数 定时中断 检测按键
引用地址:第七节:在主函数中利用累计定时中断的次数来检测按键
{
for(j=0;j<500;j++) //内嵌循环的空指令数量
{
; //一个分号相当于执行一条空语句
}
}
}
void initial_myself() //第一区 初始化单片机
{
/* 注释三:
* 矩阵键盘也可以做独立按键,前提是把某一根公共输出线输出低电平,
* 模拟独立按键的触发地,本程序中,把key_gnd_dr输出低电平。
* 朱兆祺51学习板的S1和S5两个按键就是本程序中用到的两个独立按键。
*/
key_gnd_dr=0; //模拟独立按键的地GND,因此必须一直输出低电平
beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。
TMOD=0x01; //设置定时器0为工作方式1
TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
TL0=0x2f;
}
void initial_peripheral() //第二区 初始化外围
{
EA=1; //开总中断
ET0=1; //允许定时中断
TR0=1; //启动定时中断
}
总结陈词:
本节程序已经展示了在主函数中,利用累计定时中断次数来实现独立按键的检测。这种方法我也经常在实战用应用,但是如果在某些项目中,需要在主函数里间歇性地执行一些一气呵成的耗时任务,这种方法就不是很实用,因为当主函数正在处理一气呵成的耗时任务时,这个时候如果有按键按下来,就有可能没有及时被响应到而遗漏了。那有什么方法可以解决这类项目中遇到的问题?欲知详情,请听下回分解-----在定时中断函数里执行独立按键的扫描程序。
上一篇:第六节:在主函数中利用累计主循环次数来检测独立按键
下一篇:第八节:在定时中断函数里执行独立按键的扫描程序
推荐阅读最新更新时间:2024-03-16 14:47
飞思卡尔那些事之定时中断(PIT)
前言: 上次说到因为源于对英文的恐惧,没有阅读英文DATASHEET,想当然的认为XS128单片机中的定时器模块也和DG128中定时器模块一样。结果造成了致命性的错误,最后在疯狂的熬夜中才将问题检测到。 当然,找到问题,解决起来就简单多了。后头拿起DATASHEET狂肯,终于有所收获,同时也知道了在XS128单片机中用于定时的另一个模块:PIT(定时中断)。为了测试一下定时中断的,同时也解决之前单片机一直没办法进入中断的问题,特写了一个简单的基于定时器中断的闪烁灯程序。 目的: 1、学习使用XS128PIT模块。 2、测试XS128核心板的中断木块。 功能描述: 通过定时中断实现500MS定时
[单片机]
Stm32定时器中断使LED灯闪烁
知识点: Stm32共有11个定时器: 1.两个高级定时器:TIM1、TIM8-------------------------APB2 2.四个通用定时器:TIM2~TIM5-------------------------APB1 3.两个基本定时器:TIM6、TIM7-------------------------APB1 4.两个看门狗 5.一个系统嘀嗒定时器(SysTick) 主程序main.c: /* *说明: *PA0:KEY1;PA1:KEY2; *PA2:LED1;PA3:LED2; *PA9:USART1_TX;PA10:USART1_RX */ #inclu
[单片机]
定时器中断---那些年我们一起玩mini2440(arm9)裸机
(时钟体系) 时钟概念: ★时钟脉冲:一个按一定电压幅度,一定时间间隔连续发出的脉冲信号; ★时钟频率:在单位时间(如:1秒)内产生的时钟秒冲数; 时钟的作用: 时钟信号是时序逻辑的基础,它用于决定逻辑单元中的状态何时更新。数字芯片中众多的晶体管都工作在开关状态,它们的导通和关断动作无不是按照时钟信号的节奏进行的。 时钟的作用(简洁版) 系统中的设备需要有个时间来和它进行同步—即靠时钟! 时钟的产生-晶振 晶振:晶体振荡器,是用石英晶体精密切割做成。 优点:振荡频率非常稳定;振荡频率很准确;结构简单、噪声低。 缺点:生产成本高,交货周期较长,不利于客户加快产品上市时间,而且难以获得非常标准的频率。 时钟产生-PLL P
[单片机]
简要理解MSP430的中断(以IO和定时器为例)
感觉应该会有很多刚刚学单片机的人跟我一样最初对中断有挺大疑惑,今天就简单写一写目前我对于中断的理解吧。 我呢首先接触的是FPGA,由于FPGA是并行运算,所以里面是没有中断的。而MSP430是串行运算,程序只能一个一个执行,于是在430中需要中断。 一、基本 那么什么是中断呢。我们可以认为是放下目前要做的事A,去做另外的事B,做完B后再回来继续做A。比如说我们要写一个程序,中途渴了要去喝水,我们喝完水后再继续写程序。停止写程序就相当于中断,而喝水就相当于是中断里面做的事情。中断里面做的事情就是中断函数。 把它类比到函数中,写程序就相当于main函数,那么去喝水就相当于是中断函数。 430中的IO中的一部分、定时器、
[单片机]
MSP430定时器、中断
一、实现功能 实现功能: oled显示,通过定时器实现每1s时间定时,同时中断控制按键 /* * 功能:实现定时器控制数字 oled显示 * 实现中断控制按键 * Created on: 2021年7月29日 * Author: Duck */ #include msp430.h #include oled.h #include type.h int time=0; int nub=10; void lnti_DIRP(); void main(void) { WDTCTL = WDTPW + WDTHOLD; lnti_DIRP(); TA1CCR0=49999; u16
[单片机]
STM32——如何配置通用定时器中断
STM32的定时器 STM32F103ZET6一共有8个定时器,其中分别为: 高级定时器(TIM1、TIM8);通用定时器(TIM2、TIM3、TIM4、TIM5);基本定时器(TIM6、TIM7)。 除非APB1的分频系数是1,否则通用定时器的时钟等于APB1时钟的2倍。 默认调用SystemInit函数情况下: SYSCLK=72M AHB时钟=72M APB1时钟=36M 所以APB1的分频系数=AHB/APB1时钟=2 所以,通用定时器时钟CK_INT=2*36M=72M 定时器中断的一般步骤 实例要求:通过TIM3的中断来控制led1的亮灭 硬件:LED——GPIOB,GPIO_Pin_5 1、使能
[单片机]
STM32F1x系列——定时器中断
一 通用定时器的工作过程如下图: 二 计数器模式: (1)向上计数模式:计数器从0计数到自动加载值,然后重新从0开始计数并且产生一个计数器溢出事件 (2)向下计数模式:计数器从自动装入的值开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出的事件 (3)中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1,并且产生一个计数器溢出事件,然后再从0开始计数 通用定时器常用寄存器和库函数: (1)定时器使能函数:void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) (2)定
[单片机]
基于按键触发方式的PDA寿命检测系统
摘要:开发了一种基于按触发方式的PDA产品寿命检测系统。详细介绍了该系统的功能、工作原理、设计方案及硬件结构;并针对实时性较强的多任务程序设计,介绍了集中调用、参数返回的程序调用方法。实际应用表明,该系统安全性高,稳定可靠、操作简单灵活。
关键词:按键触发 接触力检测 界面转换
由于PDA产品外观小巧、操作方便、便于携带,使其深受消费者的青睐。有些袼顺使用过程中经常出现屏幕损坏、按键失效等现象,导致产品的寿命达不到规定要求。所以作为PDA产品关键部件的屏幕,其寿命往往决定PDA产品的使用寿命,而作为易损件的按键也是限制PDA产品寿命的一个瓶颈。本文研制的检测系统可用来检测PDA产品在规定的极限温度和湿度环境中按键的疲劳寿命。
[测试测量]
小广播
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐
最新单片机文章
更多精选电路图
更多热门文章
更多每日新闻
更多往期活动
11月22日历史上的今天
厂商技术中心