bnn1044 发表于 2009-7-20 15:32:34

关于稳定按键问题。涉及消抖,和按键开关。用来做电话免提。

我的电路上是这样连的。IO口直接读按键状态。下拉电阻。按下按键高电平输入。现在要求的功能是。按键按一下电话免提打开拨电话。再按一下免提挂机。用单片机读取这个按键。但是成功率不是很高。有时候挂不了电话。有时候打不开免提。很是头疼。中间用了一个状态机。按键也做了消抖。
程序如下
while(1)
{
Key = Getkey();
if( Key == 11 ){        MeetKey = ~MeetKey;        } 这个是转换状态标志
                           if(Key !=11)
                           {
                                       if( MeetKey & ( Mcu_1062 == 0 ))
                                           {
                                           Led_Blue = 0;
                                           }
                                        if( ( MeetKey == 0 ) & ( Mcu_1062 == 0 ))
                                        {
                                        Led_Blue = 1;
                                        }                                  
                                       if( MeetKey & Mcu_1062 )
                                       {
                                       Meet();
                                       }
                                }
}

int Getkey()
{
   int X;                                                                                                                         
   X = 0;
   if( Set){ delay(1100);if( Set ){ X = 1; } }             //设置
   if( Exit ){ delay(1100); if( Exit ){ X = 2;} }               //退出
   if( Flash ){delay(1100); if( Flash){ X = 3;}}       //转接
   if( Save){ delay(1100); if(Save){ X = 4;}}                                //保存
   if( SetFlash ){delay(1100); if( SetFlash ){ X = 5;}}       //设置FLASH时间
   if( FlashIncre ){delay(1100);if( FlashIncre ){ X = 6;}}               //Flash加
   if( FlashDecre ){delay(1100); if( FlashDecre ){ X = 7;}}                               //Flash减
   if( Memory ){ delay(1100);if( Memory ){ X = 8;} }           //记忆
   if( Mute2 ){delay(1100); if( Mute2 ){ X = 9;}}                   //静音外部
   if( Mute1 ){delay(1100); if( Mute1 ){ X = 10;}}                   //静音内部
   if( Hook ){   delay(1100);if( Hook ){ while(!Hook );X = 11;}}                   //会议
   return X;
}
各位帮忙来点思路。
做产品的。一个会议电话

snoopyzz 发表于 2009-7-20 15:47:01

这可不算状态机哟~

你这不还是判断->延时->再判断,
正确的做法是数字滤波

snoopyzz 发表于 2009-7-20 15:50:39

#include "key.h"

KEY_T        Key = {0};

void KEY_DoEvent(void)
{
        //        读取键值,低电平表示有键按下,取反变成置位有效
        u8        key_value = (~KEY_PORT)&(K1|K2|K3|K4);
        if( key_value==Key.Value )
        {
                Key.Tick++;
                //        稳态检测时间:40ms
                if( Key.Tick>=MS(40) )
                {
                        Key.Tick = 0;
                        //        长按,40ms*25 = 1s
                        Key.IsLong = false;
                        Key.CountLong++;
                        if( Key.CountLong>=25 )
                        {
                                Key.CountLong = 0;
                                Key.IsLong = true;
                                //        K1允许长按触发
                                Key.Saved &= ~(K1);
                        }
                        //        重复,40ms*4 = 160ms
                        Key.CountRepeat++;
                        if( Key.CountRepeat>=Key.CountRepeatMax )
                        {
                                Key.CountRepeat = 0;
                                Key.CountRepeatMax = 4;
                                //        K3,K4允许连续触发
                                Key.Saved &= ~(K3|K4);
                        }
                }
                else
                {
                        return;
                }
        }
        else
        {
                Key.Tick = 0;       
                Key.Value = key_value;
                Key.CountLong = 0;
                Key.CountRepeat = 0;
                //        首次重复,40ms*12 = 480ms
                Key.CountRepeatMax = 12;
                return;
        }
        //
        //        按键处理:允许多个按键被按下时,新按下的按键被响应
        //
        key_value ^= Key.Saved;        // 异或:获取和上一次有效按键的不同键值
        key_value &= Key.Value; // 与:只获取新增按键值
        Key.Saved= Key.Value; // 保存这次有效键值
        //        K1:设定
        if( key_value&K1 )
        {
                if( Key.IsLong )
                {
                        Key_Setting();
                }
                else
                {
                        Key_Shift();
                }
        }
        //        K2:移位
        if( key_value&K2 )
        {
                Key_Shift();
        }
        //        K3:递增
        if( key_value&K3 )
        {
                Key_Inc();
        }
        //        K4:递减
        if( key_value&K4 )
        {
                Key_Dec();
        }
}

snoopyzz 发表于 2009-7-20 15:51:07

// key.h
#ifndef        _H_KEY
#define        _H_KEY

#include "main.h"

#define        Init_KEY        KEY_Init
extern        void KEY_Init(void);
extern        void KEY_DoEvent(void);

#define        K1        _BIT(KEY1)
#define        K2        _BIT(KEY2)
#define        K3        _BIT(KEY3)
#define        K4        _BIT(KEY4)

typedef        struct
{
        u8                Tick;
        u8                CountLong;
        u8                CountRepeat;
        u8                CountRepeatMax;
        u8                Value;
        u8                Saved;
        bool        IsLong;
}        KEY_T;
extern        KEY_T        Key;

extern        void Key_Setting(void);
extern        void Key_Shift(void);
extern        void Key_Inc(void);
extern        void Key_Dec(void);

enum
{
        SHIFT_HOUR,
        SHIFT_MIN,
        SHIFT_SEC,
        SHIFT_MS
};

#endif

snoopyzz 发表于 2009-7-20 15:53:02

保证KEY_DoEvent()在主循环中每若干个ms只执行一次...
(比如1ms,然后#define MS(ms) (ms)
如果是2ms,则是#define MS(ms) ((ms)+1)/2)
)

关键按键的端口定义如下

//        KEY
#define        KEY1        B,7
#define        KEY2        B,6
#define        KEY3        B,5
#define        KEY4        B,4
#define        KEY_PORT        PINB

snoopyzz 发表于 2009-7-20 15:57:43

以上程序支持按键数字滤波,一次响应,长按触发,连续触发,
某键被按下不影响其它按键的响应和数字滤波


简单的修改后还可以检测按键抬起和复合按键...

bnn1044 发表于 2009-7-21 00:57:21

谢谢各位的程序。程序我解决了。效果还可以。还有1楼。能不能给我说说状态机是怎么回事啊。不是很了解这个。谢谢。

tranquilly86 发表于 2012-10-26 09:24:29

snoopyzz 发表于 2009-7-20 15:50 static/image/common/back.gif
#include "key.h"

KEY_T        Key = {0};


程序方案很好啊!我还想问下,这里的MS是如何实现的,定时器中断吗?
可不可以不用中断的?.c文件不全啊?

jz701209李 发表于 2013-4-7 12:04:54

学习一下....

lunhuiliudao 发表于 2013-4-7 12:14:35

snoopyzz 发表于 2009-7-20 15:53 static/image/common/back.gif
保证KEY_DoEvent()在主循环中每若干个ms只执行一次...
(比如1ms,然后#define MS(ms) (ms)
如果是2ms,则是 ...

能发一下.c文件吗???
页: [1]
查看完整版本: 关于稳定按键问题。涉及消抖,和按键开关。用来做电话免提。