标题:
51单片机怎样用按键控制长短按切换界面,求程序思路
[打印本页]
作者:
lzj23642008
时间:
2019-7-29 17:09
标题:
51单片机怎样用按键控制长短按切换界面,求程序思路
我要用两个按键k1,k2。长按K2,切换到设置界面,短按K2切换到常规界面。弄了好久没有弄好,请高手帮忙指导一下,谢谢!
作者:
1339337425
时间:
2019-7-29 19:54
请工程化,定制化你的单片机代码
http://www.51hei.com/bbs/dpj-162218-1.html
(出处: 单片机论坛)
作者:
xianfajushi
时间:
2019-7-29 20:44
一般使用状态进行切换,你是怎么弄的不行?
作者:
wulin
时间:
2019-7-29 21:18
如果K2只是用于切换界面不必采用长短按方式,只要设置一个标志随操作取反即可。如果K2是多功能键才有必要分长短按。给你一个简单实用的长短按示例程序参考,希望对你有所帮助。
#include <REG51.H>
#define uint unsigned int
#define uchar unsigned char
#define key_S 20 //宏定义短按(20ms)
#define key_L key_S*50 //宏定义长按(1s)
sbit key1=P3^5;
sbit key2=P3^6;
sbit LED1=P1^0;
sbit LED2=P1^2;
sbit LED3=P1^4;
sbit LED4=P1^6;
uchar KeySec=0;
void Timer0Init()//1毫秒@12.000MHz
{
TMOD= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1; //开总中断
ET0=1; //开定时器0中断
}
void keyscan() //按键扫描
{
static uint count1=0; //计数变量
static uint count2=0; //计数变量
if(!key1)
{
count1++;
if(count1==key_L) //长按
KeySec=2; //输出键值2
if(count1>key_L) //防止count溢出
count1=key_L+1;
}
else //按键抬起
{
if(count1>key_S && count1<key_L)//短按
KeySec=1; //输出键值1
count1=0; //count清0
}
if(!key2)
{
count2++;
if(count2==key_L) //长按
KeySec=4; //输出键值4
if(count2>key_L) //防止count溢出
count2=key_L+1;
}
else //按键抬起
{
if(count2>key_S && count2<key_L)//短按
KeySec=3; //输出键值3
count2=0; //count清0
}
}
void key_service() //按键服务程序
{
switch(KeySec) //按键服务状态切换
{
case 1:LED2=!LED2;KeySec=0;break;
case 2:LED1=!LED1;KeySec=0;break;
case 3:LED4=!LED4;KeySec=0;break;
case 4:LED3=!LED3;KeySec=0;break;
default: break;
}
}
void main()
{
Timer0Init(); //初始化定时器
while(1)
{
key_service(); //按键服务程序
}
}
void timer0() interrupt 1//1毫秒@12.000MHz
{
TL0 = 0x18; //设置定时重装值
TH0 = 0xFC; //设置定时重装值
keyscan(); //按键扫描程序
}
复制代码
作者:
Jun默默淡定
时间:
2019-7-29 22:34
这个可以用定时器来操作,假设K2按下的时间超过2S进入设置界面。配置好定时器计时计数,当检测到K2按下时开启计时。比如说100ms来一次中断,计数值temp++,当来20次中断后时间就为2S。判断按键松开时temp的值是否大于20?当temp的值大于20就进入你所说的设置界面,小于20就进入页面切换。这样的小程序用51来操作很容易,但是要注意定时器计数器的初值装载的问题,还有就是51单片机所用的晶振。12MHz的晶振和11.0592MHz的初值装载是不一样的。没看懂的话就要回去看看51的定时器的知识了
作者:
cjm82
时间:
2019-7-29 23:59
随手写的,就写了1个按键长按短按不同功能,不保证没BUG.注释标得也自认为是清楚了,你对着你想要的修改调试下应该就可以了.
#define Long_Push_Time n //长按功能按键时长(n乘以定时器中断周期)
#define Short_Push_Time m //短按功能按键时间,需注意必须n 大于 m
sbit KEY = Px^x; //按键IO口定义
bit Flag_Short_Push_Funcation = 0; //短按触发标志
bit Flag_Long_Push_Funcation = 0; //长按触发标志
bit Flag_KEY_Pushed = 0; //按键曾经按下标志
void Init_T0() //定时器中断设置
{
.....
}
void Short_Push_Prog()
{
..........
}
void Long_Push_Prog()
{
............
}
void mian()
{
Init_T0();
while(1)
{
if(Flag_Short_Push_Funcation) //如果短按功能被置1
{
Short_Push_Prog(); //执行短按功能对应的函数
Flag_Short_Push_Funcation = 0; //清短按功能标志.
}
if(Flag_Long_Push_Funcation) //长按功能,跟上面类同.
{
Long_Push_Prog();
Flag_Long_Push_Funcation = 0;
}
}
}
void T0_ISR() interrupt 1
{
TH0 = XXXX;
TL0 = XXXX;
if(!KEY) //按键按下
{
KEY_CNT++; //开始计时
Flag_KEY_Pushed= 1; //按键已经按过的标志置1
Flag_Short_Push_Funcation = 0; //短按无效
Flag_Long_Push_Funcation = 0; //长按无效
}
if(KEY && Flag_KEY_Pushed == 1 && KEY_CNT < Short_Push_Time)
/*如果按键没有按下但按键曾经按下,可是按下时间很短,不足以触发短按的设定时间,则认为是干扰*/
{
Flag_KEY_Pushed= 0; //清按键曾经按下标志
KEY_CNT = 0; //清按键按下计时变量
Flag_Short_Push_Funcation = 0; //短按无效
Flag_Long_Push_Funcation = 0; //长按无效
return; //如判断为干扰,则下面的代码无须执行,直接跳出.
}
if(KEY && Flag_KEY_Pushed == 1 && KEY_CNT>=Short_Push_Time &&
KEY_CNT < Long_Push_Time)
/*如果按键没有按下, 但按键已经按过(用来判断按过后弹起),
并且曾经按下时间超过 设定短按时间且不超过长按时间*/
{
Flag_Short_Push_Funcation = 1; //短按功能有效
Flag_Long_Push_Funcation = 0; //长按功能无效
KEY_CNT = 0; //清按键计时变量
Flag_KEY_Pushed= 0; //清按键曾经按下标志
return; //判断完成,直接跳出
}
}
if(KEY && Flag_KEY_Pushed == 1 && KEY_CNT>=Long_Push_Time )
/*如果按键没有按下, 但按键已经按过(用来判断按过后弹起),
且曾经按下时间超过 长按时间*/
{
Flag_Short_Push_Funcation = 0; //短按功能无效
Flag_Long_Push_Funcation = 1; //长按功能有效
KEY_CNT = 0; //清按键计时变量
Flag_KEY_Pushed= 0; //清按键曾经按下标志
}
}
作者:
aaaaaa。
时间:
2019-7-30 08:27
cjm82 发表于 2019-7-29 23:59
随手写的,就写了1个按键长按短按不同功能,不保证没BUG.注释标得也自认为是清楚了,你对着你想要的修改调试下 ...
谢谢分享
作者:
yzwzfyz
时间:
2019-7-30 08:31
要点:做一个计数器CJ来判定长按与短按,CJ的规则如下:
1、CJ计数只发生于定时器的中断服务程序中,每次中断+1,计满不再计,即不回0。
2、CJ计数只发生于键按下的时候,未按下不计。
3、做一个键状态判定触发标记:B_OK,如果键未按下,但CJ<>0,则置B_OK=1,表示是判断键状态的时候了。
4、当B_OK=1,判断键状态的界定法则是:CJ<某个值为短按,CJ>某个值为长按,某个值是多少由你决定。建议事先将长短两个界定值放置在某个寄存器中,这样可以随意变更界定值。
5、状态界定完成后将:B_OK清0、CJ清0以备下次再界定。
作者:
yzwzfyz
时间:
2019-7-30 08:40
设置界面、常规界面各做一个标记如:B_SET、B_NOR。在哪个界面哪个置1。再多的界面也这样做。如果只有两个界面可以只用一个标记。界面分层叠进叠退时还需要增加次序(层面记忆),这里不说了。
长按以后的动作是:B_SET=1、其它B_NOR=0。
短按以后的动作是:B_NOR=1、其它B_SET=0。
作者:
yzwzfyz
时间:
2019-7-30 08:41
界面的切换,发生于B_SET、B_NOR有变化的时候。
作者:
wj_yuq
时间:
2019-7-30 10:47
参考文章“请工程化,定制化你的单片机代码”,用中断服务对按下键进行计数,根据计数的多少便可换算时间长短、便可根据不同时间长短执行不同的程序了。
作者:
月之光芒
时间:
2019-7-30 15:31
用定时器做,按下按钮开始计数,放开按钮结束计数,按钮函数里面要加个防抖延时
作者:
lzj23642008
时间:
2019-8-1 16:47
谢谢!
作者:
lzj23642008
时间:
2019-8-2 16:45
cjm82 发表于 2019-7-29 23:59
随手写的,就写了1个按键长按短按不同功能,不保证没BUG.注释标得也自认为是清楚了,你对着你想要的修改调试下 ...
Init_T0,void Short_Push_Prog(),void Long_Push_Prog().里边的内容能否帮忙提供一下.谢谢!
作者:
小刘子啊咿呀哟
时间:
2019-8-4 10:47
当按键按下时,开启定时器,并且在定时器中断里面用一个变量来计数,当按键松开时再来判断计数时间,如果小于0.5s,则判断为短按,标志位给0,如果大于0.5s,标志位给1,然后根据标志位进行界面切换。定时器的计数时间要设置一个上限,否则如果时间太长可能会溢出,判断按键按下或松开,可以用经典的三行代码,其中有两个变量,一个变量是用来判断按键的“下降沿”(其实准确来说并不能定义为下降沿,只是按键按下时,第一遍执行程序时,对应的位会发生改变,当执行第二遍时就又变为0,有点类似于static的作用),另一个变量是用来检测按键是否为按下状态,可以用这两个变量来判断按键按下和松开,从而开启或改变定时器,读取计数值,读取完计数值后需要将计数值清零,否则,第二次按下按键时则判断不了短按。
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1