历史上的今天
今天是: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(); } } 注:编程过程中遇到个小插曲,有个“>”写成了“<”。这种问题编译器不会报错,但现象就是不对,很多这种小细节,往往能影响到大局。 三、仿真实现
史海拾趣
|
vhdl怎么越学越难。超级超级超级郁闷。一个74 161, 74 194 高手帮我指出错误,立即结贴。 由表可知,74161具有以下功能: ① 异步清零。当RD=0时,不管其他输入端的状态如何,不论有无时钟脉冲CP,计数器输出将被直接置零(Q3Q2QlQ0=0000),称为异步清零。 ② 同步并行预置数。当RD=1、LD=0时,在输入 ...… 查看全部问答> |
|
大家好,我刚刚接触VxWorks,现在要从头学习应哪个部分开始学起呢,我现在手上没有vxWorks系统,从网上下了一个要求注册才能用.非常感谢朋友们的参与!… 查看全部问答> |
|
iar430在定时器中断里对一个全局变量不断++变量值总为零 iar 430 在定时器中断里对一个全局变量不断++ 仿真时在中断中怎么这个变量值总为零 有没有遇到同样的问题的呢 谢谢… 查看全部问答> |
|
请问一下LM3S811的可以用什么下载程序呢? 可以用什么仿真呢? 现在只有一个最小系统 [ 本帖最后由 ming1006 于 2013-1-18 13:18 编辑 ]… 查看全部问答> |




