历史上的今天

今天是:2024年11月12日(星期二)

2021年11月12日 | 51单片机实现按住一个独立按键不松手的加速匀速触发

发布者:星尘散落 来源: eefocus关键字:51单片机  独立按键 手机看文章 扫描二维码
随时随地手机看文章

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

二、编写程序


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

---- @Project: Independent-KEY

---- @File: main.c

---- @Edit: ZHQ

---- @Version: V1.0

---- @CreationTime: 20200508

---- @ModifiedTime: 20200508

---- @Description: 两个独立按键S1和S2,S1键作为加键。S2键做为减键。每按一次S1键则被设置参数uiSetNumber自加1。如果按住S1键不松手超过1秒钟,被设置参数uiSetNumber以不断变快的时间间隔往上自加1,这个称为加速触发的功能,直到到达极限值,则以固定的速度加1,这个过程叫匀速。S2作为减法按键,每触发一次,uiSetNumber就减1,其加速和匀速触发功能跟S1按键一样。当被设置参数uiSetNumber小于500的时候,LED灯灭;当大于或者等于500的时候,LED灯亮。需要注意的是:

---- 第一步:每次按下去触发一次单击按键,如果按下去到松手的时间不超过1秒,则不会进入连续加速触发模式。

---- 第二步:如果按下去不松手的时间超过1秒,则进入连续加速触发模式。按键触发节奏不断加快,蜂鸣器鸣叫的节奏也不断加快。直到它们都到达一个极限值,然后以此极限值间隔匀速触发。在刚开始加速的时候,按键触发与蜂鸣器触发的步骤是一致的,等它们任意一个达到极限值的时候,急促的声音跟按键的触发不一致,并不是蜂鸣器每叫一次,按键就触发一次。实际上加速到最后,按键触发的速度远远比蜂鸣器的触发速度快。

---- 单片机: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_time_1s   800     /*1秒钟的时间需要的定时中断次数*/

 

#define const_initial_set 480 /*连续触发模式的时候,按键刚开始的间隔触发时间*/

#define const_min_level 90 /*连续触发模式的时候,按键经过加速后,如果一旦发现小于这个值,则直接变到最后的间隔触发时间*/

#define const_sub_dt 30 /*按键的"加速度",相当于按键间隔时间每次的变化量*/

 

#define const_last_min_set 15 /*连续触发模式的时候,按键经过加速后,最后的间隔触发时间*/

#define const_syn_min_level 90 /*产生同步声音的最小阀值 这个时间必须要比蜂鸣器的时间略长一点。*/

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

/*定义按键S1*/

sbit Key_S1 = P0^0;

/*定义按键S2*/

sbit Key_S2 = P0^1;

/*定义蜂鸣器*/

sbit BUZZER = P2^7;

/*定义LED*/

sbit LED = P3^5;

 

unsigned char ucKeySec = 0;   /*被触发的按键编号*/

 

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

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

unsigned int uiKeyCtntyCnt1 = 0; /*按键连续触发的间隔延时计数器*/

 

unsigned int  uiSynCtntyCnt1 = 0;   /*产生按键同步声音的计数器*/

unsigned int  uiCtntyTimeSet1 = const_initial_set; /*按键每次触发的时间间隔,这数值不断变小,导致速度不断加快*/

unsigned int  uiCtntySynSet1 = const_initial_set;/*同步声音的时间间隔,这数值不断变小,导致速度不断加快*/

unsigned char ucCtntyFlag1 = 0;  /*是否处于连续加速触发模式的标志位*/

 

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

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

unsigned int uiKeyCtntyCnt2 = 0; /*按键连续触发的间隔延时计数器*/

 

unsigned int  uiSynCtntyCnt2 = 0;   /*产生按键同步声音的计数器*/

unsigned int  uiCtntyTimeSet2 = const_initial_set; /*按键每次触发的时间间隔,这数值不断变小,导致速度不断加快*/

unsigned int  uiCtntySynSet2 = const_initial_set;/*同步声音的时间间隔,这数值不断变小,导致速度不断加快*/

unsigned char ucCtntyFlag2 = 0;  /*是否处于连续加速触发模式的标志位*/

 

unsigned int  uiVoiceCnt = 0;  /*蜂鸣器鸣叫的持续时间计数器*/

 

unsigned int  uiSetNumber = 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)

{

BUZZER = 1;

LED = 0;

Init_T0();

}

/**

* @brief  扫描按键函数

* @param  无

* @retval 独立按键连续加速扫描的过程:

* 第一步:每次按下去触发一次单击按键,如果按下去到松手的时间不超过1秒,则不会进入连续加速触发模式。

* 第二步:如果按下去不松手的时间超过1秒,则进入连续加速触发模式。按键触发节奏不断加快,蜂鸣器鸣叫的节奏

*         也不断加快。直到它们都到达一个极限值,然后以此极限值间隔匀速触发。在刚开始加速的时候,按键触发与

*         蜂鸣器触发的步骤是一致的,等它们任意一个达到极限值的时候,急促的声音跟按键的触发不一致,并不是

*         蜂鸣器每叫一次,按键就触发一次。实际上加速到最后,按键触发的速度远远比蜂鸣器的触发速度快。

**/

void Key_Scan(void)

{

/*扫描S1*/

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

{

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

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

uiKeyCtntyCnt1 = 0; /*按键连续加速的时间间隔延时计数器清零*/

uiSynCtntyCnt1 = 0; /*蜂鸣器连续加速的时间间隔延时计数器清零*/

uiCtntyTimeSet1 = const_initial_set; /*按键每次触发的时间间隔初始值,这数值不断变小,导致速度不断加快*/

uiCtntySynSet1 = const_initial_set; /*同步声音的时间间隔初始值,这数值不断变小,导致鸣叫的节奏不断加快*/

}

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

{

uiKeyTimeCnt1 ++;

if(uiKeyTimeCnt1 > const_key_time1)/*判定按下*/

{

uiKeyTimeCnt1 = 0;

ucKeyLock1 = 1;

ucCtntyFlag1 = 0; /*连续加速触发模式标志位 0代表单击  1代表连续加速触发*/

ucKeySec = 1;    /*触发S1*/

}

}

else if(uiKeyTimeCnt1 < const_time_1s)/*按键已按下,按键去抖动延时计数器自增到1s*/

{

uiKeyTimeCnt1 ++;

}

else/*按住累加到1秒后仍然不放手,这个时候进入有节奏的连续触发*/

{

uiKeyCtntyCnt1 ++;/*连续触发延时计数器累加*/

if(uiKeyCtntyCnt1 > uiCtntyTimeSet1)/*按住没松手,每隔一段uiCtntyTimeSet1时间按键就触发一次,而且uiCtntyTimeSet1不断减小,速度就越来越快*/

{

if(uiCtntyTimeSet1 > const_min_level)

{

/*uiCtntyTimeSet1不断减小,速度就越来越快*/

uiCtntyTimeSet1 = uiCtntyTimeSet1 - const_sub_dt;

}

else

{

/*达到极限值,则稳定为固定值*/

uiCtntyTimeSet1 = const_last_min_set;

}

uiKeyCtntyCnt1 = 0;

ucCtntyFlag1 = 1; /*进入连续加速触发模式*/

ucKeySec = 1;    /*触发S1*/

}

uiSynCtntyCnt1 ++; /*蜂鸣器连续触发延时计数器累加*/

if(uiSynCtntyCnt1 > uiCtntySynSet1) /*按住没松手,每隔一段uiCtntySynSet1时间蜂鸣器就触发一次,而且uiCtntySynSet1不断减小,鸣叫的节奏就越来越快*/

{

uiCtntySynSet1 = uiCtntySynSet1 - const_sub_dt;

if(uiCtntySynSet1 < const_syn_min_level)

{

uiCtntySynSet1 = const_syn_min_level;

}

uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/

uiSynCtntyCnt1 = 0;

}

}

/*扫描S2*/

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

{

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

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

uiKeyCtntyCnt2 = 0; /*按键连续加速的时间间隔延时计数器清零*/

uiSynCtntyCnt2 = 0; /*蜂鸣器连续加速的时间间隔延时计数器清零*/

uiCtntyTimeSet2 = const_initial_set; /*按键每次触发的时间间隔初始值,这数值不断变小,导致速度不断加快*/

uiCtntySynSet2 = const_initial_set; /*同步声音的时间间隔初始值,这数值不断变小,导致鸣叫的节奏不断加快*/

}

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

{

uiKeyTimeCnt2 ++;

if(uiKeyTimeCnt2 > const_key_time2)/*判定按下*/

{

uiKeyTimeCnt2 = 0;

ucKeyLock2 = 1;

ucCtntyFlag2 = 0; /*连续加速触发模式标志位 0代表单击  1代表连续加速触发*/

ucKeySec = 2;    /*触发S2*/

}

}

else if(uiKeyTimeCnt2 < const_time_1s)/*按键已按下,按键去抖动延时计数器自增到1s*/

{

uiKeyTimeCnt2 ++;

}

else/*按住累加到1秒后仍然不放手,这个时候进入有节奏的连续触发*/

{

uiKeyCtntyCnt2 ++;/*连续触发延时计数器累加*/

if(uiKeyCtntyCnt2 > uiCtntyTimeSet2)/*按住没松手,每隔一段uiCtntyTimeSet1时间按键就触发一次,而且uiCtntyTimeSet2不断减小,速度就越来越快*/

{

if(uiCtntyTimeSet2 > const_min_level)

{

/*uiCtntyTimeSet1不断减小,速度就越来越快*/

uiCtntyTimeSet2 = uiCtntyTimeSet2 - const_sub_dt;

}

else

{

/*达到极限值,则稳定为固定值*/

uiCtntyTimeSet2 = const_last_min_set;

}

uiKeyCtntyCnt2 = 0;

ucCtntyFlag2 = 1; /*进入连续加速触发模式*/

ucKeySec = 2;    /*触发S2*/

}

uiSynCtntyCnt2 ++; /*蜂鸣器连续触发延时计数器累加*/

if(uiSynCtntyCnt2 > uiCtntySynSet2) /*按住没松手,每隔一段uiCtntySynSet2时间蜂鸣器就触发一次,而且uiCtntySynSet2不断减小,鸣叫的节奏就越来越快*/

{

uiCtntySynSet2 = uiCtntySynSet2 - const_sub_dt;

if(uiCtntySynSet2 < const_syn_min_level)

{

uiCtntySynSet2 = const_syn_min_level;

}

uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/

uiSynCtntyCnt2 = 0;

}

}

 

}

/**

* @brief  按键服务函数

* @param  无

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

**/

void key_Service(void)

{

switch(ucKeySec)

{

case 1: /*S1,连续加*/

uiSetNumber++;/*被设置的参数连续往上加*/

if(uiSetNumber > 1000)/*最大1000*/

{

uiSetNumber = 1000;

}

if(ucCtntyFlag1 == 0) /*如果是在单击按键的情况下,则蜂鸣器鸣叫,否则蜂鸣器在按键扫描key_scan里鸣叫*/

{

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

}

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

break;

case 2: /*S2,连续减*/

uiSetNumber--;/*被设置的参数连续往下减*/

if(uiSetNumber > 1000)/*最小0,0 - 1 = 0xff > 1000*/

{

uiSetNumber = 0;

}

if(ucCtntyFlag2 == 0) /*如果是在单击按键的情况下,则蜂鸣器鸣叫,否则蜂鸣器在按键扫描key_scan里鸣叫*/

{

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

}

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

break;

}

}

/**

* @brief  LED函数

* @param  无

* @retval 控制LED亮灭

**/

void Led_Run(void)  /*led灯的应用程序*/

{

   if(uiSetNumber < 500)  /*如果被设置的参数uiSetNumber小于500,LED灯则灭。否则亮。*/

   {

      LED = 0;  /*灭*/

   }

   else

   {

      LED = 1;  /*亮*/

   }

}

/**

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

/*LED函数*/

Led_Run();

}

}

 

注:编程过程中遇到个小插曲,有个“>”写成了“<”。这种问题编译器不会报错,但现象就是不对,很多这种小细节,往往能影响到大局。


三、仿真实现

关键字:51单片机  独立按键 引用地址:51单片机实现按住一个独立按键不松手的加速匀速触发

上一篇:51单片机实现矩阵键盘的单个触发
下一篇:51单片机实现按住一个独立按键不松手的连续步进触发

推荐阅读

东北地区规模最大的工业机器人实训基地,11月9日在沈阳永安机床小镇落成。这意味着,辽宁智能制造从此有了培养大量智能技术人才的实战场地,从而助力新一轮东北振兴。 当日记者在位于沈阳市于洪区的机床小镇,见证了辽宁智能制造应用示范基地即工业机器人实训基地落成。活动中展示了国内领先数控在智能制造领域的先进技术,尤其是机器人舞狮让人赞叹不...
第一次做。都是用的avr单片机ATMEGA16仿真。。有3个按键控制流水灯程序 和1个单片机按键抗干扰,左右按键要松开才行.单片机源码:#include <iom16v.h>void delay(unsigned int x){ int i,j; for(i=0;i<x;i++) for(j=0;j<1141;j++);}void button(int i){if((PINC&(1<<PC0))==0){delay(20);if((PINC&(1<<PC0))==0){up(i);}while((PINC&(1<<...
Maxim Integrated Products, Inc (NASDAQ: MXIM) 宣布推出MAX77655单电感多输出(SIMO)电源管理IC (PMIC),以最高功率密度实现新的技术突破,适用于尺寸极小的下一代设备。与最接近的竞争方案相比,该款PMIC将方案尺寸缩小70%,4路升/降压转换通道可提供700mA电流,且仅需一个外部电感,总方案尺寸仅为17mm2。 ...
示波器探头是示波器使用过程中不可或缺的一部分,主要是作为承载信号传输的链路,将待测信号完整可靠的传输至示波器,以进一步进行测量分析。示波器探头又根据不同应用分为电流探头、差分探头、高压探头、单端探头等,今天安泰测试就给大家分享一下用于差分伏地信号测试的示波器高压差分探头原理及调节注意事项:示波器“差分”探头是指带有两个输入端口(...

史海拾趣

问答坊 | AI 解惑

LDO和DC-DC器件的区别

DCDC的意思是直流变(到)直流(不同直流电源值的转换),只要符合这个定义都可以叫DCDC转换器,包括LDO。但是一般的说法是把直流变(到)直流由开关方式实现的器件叫DCDC。     LDO是低压降的意思,这有一段说明:低压降(LDO ...…

查看全部问答∨

HT1380串行时钟芯片

HT1380串行时钟芯片一般来说,HT系列的芯片在串行口的应用一直以来就是很好的在单片机 这个领域,串行时钟一直占着很重要的位置…

查看全部问答∨

Introduction to NI VeriStand

Introduction to NI VeriStand…

查看全部问答∨

工程师们看过来——电气测量时,聪明人所做的10件糊涂事

本人搜集到的一篇很好的文章,因此转载给各位大虾,希望对工程师们有所帮助: 何靠与电打交道来谋生的人很快都会对任何“带电”的物体生出理性的敬意,哪怕是“带电”的机会很小。然而,需要按时完成一项工作或者使某个关键设备恢复联机的紧迫压力 ...…

查看全部问答∨

evc托盘编程

使用evc4.0编写一个系统托盘,就是我的程序起来之后,不显示对话框,自动出现一个图标到右下角,通过双机图标,可以弹出对话框。 右键单击右下角图标,可以弹出一个菜单。 不知道如何实现这些功能,请兄弟姐妹们帮个忙!…

查看全部问答∨

请高手帮忙~~~在EVC下的2个函数没定义.

error C2065: \'GetRunningObjectTable\' : undeclared identifier error C2065: \'CreateItemMoniker\' : undeclared identifier 我用的是EVC 4.0+SP4…

查看全部问答∨

STM32的驱动库好用吗?效率高吗?优化的吗?准备上STM32

    N多年没买过开发板了,也没用过仿真器了。都是用软件编译调试好,直接ISP,然后通过串口命令开启调试信息的输出。    昨天买了块STM32F103全功能型开发板,他们的办事效率真低(深圳到广州通常当 ...…

查看全部问答∨

求IAR Embedded Workbench for MCS-51 完整版

各位高手,小弟求IAR Embedded Workbench for MCS-51完整版,有哪位高人有,能否分享一下。我的邮箱jinghongchen@126.com…

查看全部问答∨

猎头招聘

世界500强招聘压力传感器SAE,如有兴趣可发简历至:aerie.song@seek-jobs.com.cn 要求:至少五年以上相关工作经验,英文流利。…

查看全部问答∨

串口调试可能用到的小工具

串口调试精灵 串口调试时可以用的到…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved