打印

单片机菜鸟求助:状态机、独立按键问题

[复制链接]
9339|34
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
初学-菜鸟|  楼主 | 2012-5-23 22:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 初学-菜鸟 于 2012-5-29 20:25 编辑

我仿照网上的程序,写了个状态机检测独立按键程序,4个按键,每个键按下并松开,对应的一个数码管显示数字加1。实际上,按了10多次,才会响应一两次,不知道问题出在哪里。
我用传统按键检测方法:检测到按键延时10ms确认键按下并while等待按键送开,返回键值,没有任何问题。
附代码:
//定时器1每10ms进入一次中断,调用该函数。
uchar Key_Scan(void)
{
    static uchar Key_State   = 0;           //按键状态
    static uchar Key_Prev    = 0;           //上次按键
    //static unsigned int Key_Delay   = 0;        
    uchar Key_Press  = KEY_NONE;            //按键值      
    uchar Key_Return = KEY_NONE;            //返回值
    Key_Press = Get_Key();
    switch (Key_State)
    {
    case 0:     //按键初始态
        if (Key_Press !=KEY_NONE)           //有键按下
        {
            Key_State = 1;
            Key_Prev  = Key_Press;
        }
        break;
    case 1:
        if ( Key_Press ==Key_Prev )         //确认和上次按键状态相同
        {                                   //等待释放
   Key_State = 2;                    
            //Key_Return = KEY_DOWN | Key_Prev;
        }
        else    //
        {
            Key_State = 0;
        }
        break;
    case 2:
       if(Key_Press == KEY_NONE)            //按键释放
       {
   Key_State = 0;                 
            Key_Return  = (KEY_UP | Key_Prev);  //返回     
       }
      
  break;                  
    default :   
        Key_State = 0;
        break;
    }
    return Key_Return;
}
附上keil2工程代码:

ttt.rar

27.5 KB

相关帖子

沙发
初学-菜鸟|  楼主 | 2012-5-23 22:47 | 只看该作者
传统按键检测方法,没有问题。代码如下:
uchar gKey_Scan(void)
{
   
    if(KEY_S1_STATUS == 0)
    {
        delay_ms(15);
        if(KEY_S1_STATUS == 0)
        {
            while(KEY_S1_STATUS == 0);
            return KEY_S1_RELEASE;
        }         
    }
    if(KEY_S2_STATUS == 0)
    {                                                                                                        
        delay_ms(15);
        if(KEY_S2_STATUS == 0)
        {
            while(KEY_S2_STATUS == 0);
            return KEY_S2_RELEASE;
        }         
    }
    if(KEY_S3_STATUS == 0)
    {
        delay_ms(15);
        if(KEY_S3_STATUS == 0)
        {
            while(KEY_S3_STATUS == 0);
            return KEY_S3_RELEASE;
        }         
    }
    if(KEY_S4_STATUS == 0)
    {
        delay_ms(15);
        if(KEY_S4_STATUS == 0)
        {
            while(KEY_S4_STATUS == 0);
            return KEY_S4_RELEASE;
        }         
    }
    return KEY_NONE;
}

使用特权

评论回复
板凳
Jordon138| | 2012-5-23 23:11 | 只看该作者
延时适当加长,看一下。

使用特权

评论回复
地板
joyme| | 2012-5-24 09:55 | 只看该作者
这段程序没有问题,估计是其他处理的问题

使用特权

评论回复
5
hwk612167| | 2012-5-25 20:38 | 只看该作者
看不出啥问题

使用特权

评论回复
6
初学-菜鸟|  楼主 | 2012-5-27 18:27 | 只看该作者
定时器换成15ms 20ms都不行,还是一样。。求教 3# Jordon138

使用特权

评论回复
7
初学-菜鸟|  楼主 | 2012-5-27 18:30 | 只看该作者
除了定时器每10ms调用一次读键处理,其它就数码管显示,没有别的了。只把中断中的读键函数屏蔽,在while主循环中用传统延时检测按键就是2L所贴代码,却没有任何问题。 4# joyme

使用特权

评论回复
8
初学-菜鸟|  楼主 | 2012-5-28 14:52 | 只看该作者
为什么没有人来回复,,,顶上去

使用特权

评论回复
9
joyme| | 2012-5-28 17:47 | 只看该作者
你干脆把整个程序贴个附件上来看看,状态机是个很成熟的东东,不会有什么问题呀

使用特权

评论回复
10
wukunshan| | 2012-5-29 00:02 | 只看该作者
问题就出在定时器每10ms才扫描一次。当你按下按键时,如果刚好碰到定时器到时,中断函数进来扫描按键,就能检测到按键被按下了;如果你按下按键时,定时器还在计时,还没中断,当然检测不到按键被按下。试想,你每次按下按键时都那么走运吗?

使用特权

评论回复
11
初学-菜鸟|  楼主 | 2012-5-29 09:19 | 只看该作者
一次按键按下怎么着也得持续个几十毫秒把,按你这个思路,用2L所贴代码同样存在你说的问题,怎么每次按键单片机检测都都没漏掉呢。

继续等,,, 10# wukunshan

使用特权

评论回复
12
阮天宇00| | 2012-5-29 09:56 | 只看该作者
本帖最后由 阮天宇00 于 2012-5-29 09:58 编辑

我也是新手,只能跟你说说我碰见这样的问题怎么处理的。
1。把其它的程序都/**/掉,你不是觉得你的按键程序是正常的么。
2.那你就只调用按键函数和一个LED灯,检测到按键,你就LED灯取反。先确定按键没问题。
3.你还有数码管显示程序。/**/掉按键函数,让后数码管显示,比如做显示0——9的循环。确保数码管显示没问题。
4.看两个函数调用正确不。
5.时序!!也就是CPU占用的时间,假如CPU正好被数码管程序占用,那个时候你检测按键,你就悲剧了。
好吧,我承认,时序让我很蛋疼,我也没搞明白。我现在碰到问题,最后都是时序把我搞糊涂。

使用特权

评论回复
13
阮天宇00| | 2012-5-29 09:59 | 只看该作者
另外说一下,最后搞个JTGA,比较好用。
PS:前提是你的单片机支持。

使用特权

评论回复
14
阮天宇00| | 2012-5-29 10:17 | 只看该作者
我仔细看了你的思路,用定时器进入键盘检测肯定不对!!这个想法有问题。

定时器1每10ms进入一次中断,调用该函数

你进入中断后,你可以看看你的键盘检测程序,在10ms内完成么?
假如没有完成检测,那么就会再来一次中断!然后上一次检测没完成……可不就是多数情况下检测不到么。

delay_ms(15);

这个……中断好多次了。

看来还是上面说的 “5.时序”问题啊!

使用特权

评论回复
15
joyme| | 2012-5-29 15:16 | 只看该作者
都说了这个函数没有问题,问题出在别的地方
中断函数没有初始化定时初值或看门狗打开没喂都会导致程序并没有按你说的10ms执行一次按键检测。调用时间间隔越长正确检测按键的可能性会越小

使用特权

评论回复
16
阮天宇00| | 2012-5-29 17:20 | 只看该作者
本帖最后由 阮天宇00 于 2012-5-29 17:24 编辑

可能是我没理解状态机吧……
我在网上找了状态机的东西看了看,也不太明白。

但是假如楼主说的状态机是软件实现的,调用的函数是一段在CPU里面跑的代码的话,那就肯定是我说的这个原因了!

你看CPU一个时间点只能干见事情,你第一次检测,OK!进入中断调用函数,可是你的程序还没有执行完,你的中断又来了,又调用一次函数,执行一半的又被覆盖了……所以应该是函数一直执行不了。

状态机?:dizzy:
是硬件么?


我又上网看了下状态机——那就是我说的问题了。

你的检测函数,在CPU里面永远不能运行完整一次。

使用特权

评论回复
17
初学-菜鸟|  楼主 | 2012-5-29 20:14 | 只看该作者
真不是你说的这样,数码管显示也是中断里的,每2.5ms切换一个数码管显示16# 阮天宇00

使用特权

评论回复
18
初学-菜鸟|  楼主 | 2012-5-29 20:14 | 只看该作者
源码已附在1楼主帖中,请指教! 16# 阮天宇00

使用特权

评论回复
19
初学-菜鸟|  楼主 | 2012-5-29 20:16 | 只看该作者
源码已附在1楼主帖中,请指教!
定时器中每500msLED状态改变一次,做指示灯用。 15# joyme

使用特权

评论回复
20
初学-菜鸟|  楼主 | 2012-5-29 20:17 | 只看该作者
源码已附在1楼主帖中,请指教!
10# wukunshan

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

18

帖子

0

粉丝