历史上的今天
返回首页

历史上的今天

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

正在发生

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

2021-11-12 来源:eefocus

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

}

}

 

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


三、仿真实现

推荐阅读

史海拾趣

Control Sciences Inc公司的发展小趣事

随着技术的不断进步,Control Sciences Inc开始寻求更广阔的市场空间。公司积极参与国内外各大电子展会,展示其先进的产品和技术。同时,公司还加大了市场推广力度,与多个知名企业建立了战略合作关系。通过这些努力,Control Sciences Inc的产品逐渐走进了更多的企业和家庭,其品牌影响力也日益增强。

晶群科技(Gem-micro)公司的发展小趣事

Control Sciences Inc公司在电子行业的初期,就以其技术创新而闻名。公司团队不断研发新的控制技术,成功打破了当时行业的局限。他们推出的首款智能控制系统,不仅提高了生产效率,还大大降低了能源消耗,为电子行业带来了巨大的经济效益。这一创新成果使得Control Sciences Inc在业界崭露头角,赢得了众多客户的青睐。

Hitano Enterprise Corp公司的发展小趣事

为了确保产品质量的稳定和可靠,Control Sciences Inc建立了一套完善的质量管理体系。公司从原材料采购、生产过程到产品出厂,都实行了严格的质量控制。同时,公司还引入了先进的质量检测设备和方法,确保每一台产品都符合客户的要求。这一举措使得Control Sciences Inc的产品在市场上赢得了良好的声誉。

HN Electronic Components GmbH & Co Kg公司的发展小趣事

背景:随着公司实力的增强,HN Electronics开始考虑通过并购来扩大规模和市场份额。

发展:公司精心挑选了几家在电子元件制造和系统集成方面具有优势的中小企业进行并购,通过资源整合和优势互补,进一步巩固了市场地位。同时,HN Electronics还向产业链上下游延伸,涉足原材料供应和终端产品制造领域。

关键事件:2015年,HN Electronics成功并购了一家在被动元件领域具有领先地位的企业,这一并购极大地增强了公司的供应链整合能力和市场竞争力。

EWC Controls公司的发展小趣事

随着公司规模的不断扩大和技术实力的增强,EWC Controls公司开始拓展全球市场。公司积极参加国际展会和交流活动,与全球各地的客户建立联系和合作。同时,EWC Controls公司还针对不同国家和地区的市场需求和法律法规要求,对产品进行适应性改进和优化。这些努力使得公司的产品逐渐走向国际市场,并赢得了良好的口碑和市场份额。

Elite公司的发展小趣事

随着科技的不断进步,Elite始终将技术研发作为公司发展的核心驱动力。公司投入大量资金引进先进设备和技术人才,不断提升产品性能和质量。同时,Elite积极拓展国内外市场,通过参加各类展会、建立合作伙伴关系等方式,提高品牌知名度和市场占有率。

问答坊 | AI 解惑

风力发电机结构

机舱:机舱包容着风力发电机的关键设备,包括齿轮箱、发电机。维护人员可以通过风力发电机塔进入机舱。机舱左端是风力发电机转子,即转子叶片及轴。   转子叶片:捉获风,并将风力传送到转子轴心。现代600千瓦风力发电机上,每个转子叶片的测量 ...…

查看全部问答>

vhdl怎么越学越难。超级超级超级郁闷。一个74 161, 74 194 高手帮我指出错误,立即结贴。

由表可知,74161具有以下功能:     ① 异步清零。当RD=0时,不管其他输入端的状态如何,不论有无时钟脉冲CP,计数器输出将被直接置零(Q3Q2QlQ0=0000),称为异步清零。     ② 同步并行预置数。当RD=1、LD=0时,在输入 ...…

查看全部问答>

dm9008AE dm9000A的驱动问题,谢谢了

读写寄存器都没问题,写进去,读出来都是正确的,但是初始化后LED灯就是不亮,也没初始化成功,不知道为什么,谁知道啊,谢谢了…

查看全部问答>

wince5.0 修改NORFlash分区大小

平台为wince5.0 + ep9315 我的实现注册表保存之后,想把分区空间分配大一点,如何实现呢?请高手指教!…

查看全部问答>

键盘源代码

老板不想买pc键盘,想自己做。别的都有办法做,就是键盘里的一块膏药似的芯片里的代码怎么写啊?想请教各位高手大侠们帮帮我。谢谢!…

查看全部问答>

十分钟学会Xilinx FPGA 设计

十分钟学会Xilinx FPGA 设计…

查看全部问答>

初学vxWorks应该从何入手呢

大家好,我刚刚接触VxWorks,现在要从头学习应哪个部分开始学起呢,我现在手上没有vxWorks系统,从网上下了一个要求注册才能用.非常感谢朋友们的参与!…

查看全部问答>

iar430在定时器中断里对一个全局变量不断++变量值总为零

iar 430 在定时器中断里对一个全局变量不断++ 仿真时在中断中怎么这个变量值总为零 有没有遇到同样的问题的呢 谢谢…

查看全部问答>

TI原装全新没用过的触摸板36卖了有人要不

RT TI原装全新没用过的触摸板 需要的留个联系方式吧…

查看全部问答>

请问LM3S811的下载和仿真方式有哪些

请问一下LM3S811的可以用什么下载程序呢?   可以用什么仿真呢?   现在只有一个最小系统 [ 本帖最后由 ming1006 于 2013-1-18 13:18 编辑 ]…

查看全部问答>