打印

状态机在单片机中的应用

[复制链接]
838|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lium|  楼主 | 2019-3-13 15:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

状态机在单片机中的应用
请大家说说,或者给点资料,谢谢了!
沙发
wangzsa| | 2019-3-13 15:59 | 只看该作者

我记得我有点,稍等啊

使用特权

评论回复
板凳
lium|  楼主 | 2019-3-13 16:02 | 只看该作者


能举个例子吗

使用特权

评论回复
地板
wangpe| | 2019-3-13 16:06 | 只看该作者

比如某些芯片的AD采样 你就可以用状态机写

使用特权

评论回复
5
zhuww| | 2019-3-13 16:09 | 只看该作者

嗯, 这样结构就很清晰

使用特权

评论回复
6
lium|  楼主 | 2019-3-13 16:12 | 只看该作者

也是,我等2楼兄弟了,给我发站内信就行

使用特权

评论回复
7
hanwe| | 2019-3-13 16:16 | 只看该作者
好的

使用特权

评论回复
8
yufe| | 2019-3-13 16:19 | 只看该作者
功能:按键去抖;

描述:按钮按下时RES1返回1,如果持续按下的时间超过delay_key_on,则置按键状态status_res1为1,不超过则保持status_res1原值;

同样,按钮释放时RES1返回0,如果持续释放的时间超过delay_key_off,则置按键状态status_res1为0,不超过则保持status_res1原值;



step_res1:当前处理状态,按下/释放;

add_res1:用于累计状态持续时间

======================

switch(step_res1) //处理输入信号

{

       case 0:

           if(RES1) //如果按钮被按下

{

                add_res1++;

                if(add_res1>delay_key_on){//如果持续按下的时间足够

                    status_res1=1;//置当前状态为闭合

                    add_res1=0;//清计数器

                    step_res1=1;//进入第二步

                }

           }

           else{

                add_res1=0;//如果按钮被释放,则重新累计

           }

           break;

       case 1:

           if(!RES1) //如果按钮被释放

                     {

                add_res1++;

                if(add_res1>delay_key_off){//如果持续释放的时间足够

                    status_res1=0;//置当前状态为释放

                    add_res1=0;//清计数器

                    step_res1=0;//回到第一步

                }

           }

           else{

                add_res1=0;//如果按钮仍然闭合,则重新累计

           }

            break;

       default:

           add_res1=0;//若为其他状态,则初始化

           step_res1=0;

           break;

}

使用特权

评论回复
9
llia| | 2019-3-13 16:22 | 只看该作者

1-头文件:KeyBoard.h

#ifndef_Key_Board_h_

    #define _Key_Board_h_



    #define   Key_Up        0x3E    //上箭头

    #define   Key_Down    0x3D    //下箭头

    #define   Key_Add        0x3B    //加

    #define   Key_Sub        0x37    //减

    #define   Key_Enter    0x2F   //回车

    #define   Key_Return    0x1F   //返回

    #define Key_LR        0x33   //左右组合键

    //可以在此定义其它组合键……

   

    #define Key_NULL    0xFF   //无任何按键



    //声明几个需要在外部调用的函数

    extern void Key_Board_Init(void);//键盘接口初始化

    extern u8 Read_Key(void);    //读键函数,返回键盘缓冲区中的键值

    extern void Key_In(void);//处理按键输入函数,在定时器中断里调用



    extern void Key_Board_Test(void);    //键盘接口测试函数(仅在调试阶段使用)



#endif



2-源文件:KeyBoard.c

//#include"includes.h"    //公共头文件

#include"Key_Board.h"



//键盘缓冲区相关常量定义

#defineKeyBuffLen 8    //定义键值环形缓冲区长度为8(缓冲区大小可自由定义,只要大于0即可)



//定义一个键盘缓冲区结构体

structStruct_KeyBoardBuff

{

    u8 buff[KeyBuffLen];//键值环形缓冲区

    u8 in;    //写键值指示(定时器中断写)

    u8 out;   //读键值指示(用户读)

}Key;





/*************************************************************************

函数原型:void Key_Board_Init(void)

函数功能:对键盘接口进行初始化,即把键值缓冲区清零

传入参数:无

返回参数:无

全局变量:直接操作键盘缓冲区结构体

设    计:莫汉伟 amo73@126.com

修改日期:2007-9-5

备    注:仅在上电初始化的时候被调用一次

**************************************************************************/

voidKey_Board_Init(void)

{

    memset(&Key,0,sizeof(Key));

}



/*************************************************************************

函数原型:u8 Read_Key(void)

函数功能:从键值缓冲区读取一个键值

传入参数:无

返回参数:u8型按键值,如果缓冲区为空,则返回-1

设    计:莫汉伟 amo73@126.com

修改日期:2007-9-5

备    注:供用户程序调用;用户不用关心键盘底层硬件。

**************************************************************************/

u8Read_Key(void)

{

    u8 Value;

    if(Key.out != Key.in)

    {

        Value=Key.buff[Key.out++];//"读"还没有追上"写",缓冲区有键值,读之

        if(Key.out >= KeyBuffLen) //如果"读"跑到了队列尾部,则重新跳回原点

        {

            Key.out=0;

        }

    }

    else

    {

        Value=Key_NULL;//"读"追上了"写",缓冲区没有键值,返回空键值

    }

    return(Value);

}



//判断一个键值的键数(在本硬件里1bit对应一个按键,0表示按键按下)

u8 JudgeKey(u8key)

{

    u8 i,count=0;

    for(i=0;i<6;i++)

    {

        if((key & 0x01)==0)

            count++;

        key >>= 1;

    }

    return(count);

}

/*************************************************************************

函数原型:void Key_In(void)

函数功能:在定时器中断里每10ms调用1次,处理按键输入,并将按键值放入键值缓冲区中。

          支持单键、双键组合键

传入参数:无

返回参数:无

设    计:莫汉伟 amo73@126.com

修改日期:2007-10-12

备    注:详细功能和处理算法请参照本文件相关的流程图和文档

**************************************************************************/

enumKeyFSM_Enum //按键状态有限状态机

{

    _Key_Idle=0,    //空闲

    _Key1_down,    //单键按下消抖

    _Key1_press,    //单键按下

    _Key1_up,   //单键抬起消抖

    _Key2_down,    //双键按下消抖

    _Key2_press,    //双键按下

    _Key2_up,   //双键抬起消抖

    _Key_confirm,    //按键确认成功

};



//处理扫描按键、判断按键、保存键值等。在定时器中断里(周期为10ms以上即可)调用本函数。

voidKey_In(void)

{

    static u8 Key_Input=0;

    //在此添加获取键值代码(参照硬件电路图)

    static u8 volatile step=0;//步骤

    u8 NewKey = uPSD.DATAIN_A & 0x3F;//读取按键

    //获取键值代码结束

    u8 num=JudgeKey(NewKey);//判断当前有几个按键按下

    switch(step)//状态机

    {

        case _Key_Idle://空闲

        {

            switch(num)

            {

                case 1://单键

                {

                    Key_Input = NewKey;//保存键值

                    step = _Key1_down;//单键按下消抖

                   SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间

                    break;

                }

                case 2://双键

                {

                    Key_Input = NewKey;//保存键值

                    step = _Key2_down;//双键按下消抖

                   SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间

                    break;

                }

                default://其它

                {

                    break;

                }

            }

            break;

        }

        case _Key1_down://单键按下消抖

        {

            switch(num)

            {

                case 1://单键

                {

                    if(NewKey == Key_Input)//键值不变

                        step = _Key1_press;//单键按下

                    else

                        step = _Key_Idle;//空闲

                    break;

                }

                case 2://双键

                {

                    Key_Input = NewKey;//保存键值

                    step = _Key2_down;//双键按下消抖

                    break;

                }

                default://其它

                {

                    step = _Key_Idle;//空闲

                    break;

                }

            }

            break;

        }

        case _Key1_press://单键按下

        {

            switch(num)

            {

                case 1://单键

                {

                    if(NewKey != Key_Input)//键值改变

                        step = _Key1_up;//单键抬起消抖

                    break;

                }

                case 2://双键

                {

                    Key_Input = NewKey;//保存键值

                    step = _Key2_down;//双键按下消抖

                    break;

                }

                default://其它

                {

                    step = _Key1_up;//单键抬起消抖

                    break;

                }

            }

            break;

        }

        case _Key1_up://单键抬起消抖

        {

            switch(num)

            {

                case 1://单键

                {

                    if(NewKey == Key_Input)//键值不变

                        step = _Key1_press;//单键按下

                    else

                        step = _Key_confirm;//按键确认成功

                    break;

                }

                case 2://双键

                {

                    Key_Input = NewKey;//保存键值

                    step = _Key2_down;//双键按下消抖

                    break;

                }

                default://其它

                {

                    step = _Key_confirm;//按键确认成功

                    break;

                }

            }

            break;

        }

        case _Key2_down://双键按下消抖

        {

            if(NewKey == Key_Input)//键值不变

                step = _Key2_press;//双键按下

            else

                step = _Key_Idle;//空闲

            break;

        }

        case _Key2_press://双键按下

        {

            if(num==0)//无键

                step = _Key2_up;//双键抬起消抖

            break;

        }

        case _Key2_up://双键抬起消抖

        {

            if(num==0)//无键

                step = _Key_confirm;//按键确认成功

            break;

        }

        default://出现异常,流程复位

        {

            step = _Key_Idle;//空闲

            break;

        }

    }



    if(step == _Key_confirm)//按键确认成功

    {

        step = _Key_Idle;//空闲



    //   SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间

        //放入键值缓冲区中

        if(Key_Input != 0)//如果键值有效,则放入缓冲区中

        {

        //   SoundLight_ms(_TypeBeep,30);//蜂鸣器发声30ms

        //   menu_auto_return_s = 60;//60秒后菜单自动返回

            Key.buff[Key.in++] = Key_Input;

            if(Key.in >= KeyBuffLen)//如果"写"跑到了队列尾部,则重新跳回原点

            {

                Key.in=0;

            }

        }

    }



    //"写"只管在前面跑,不用管"读"在后面怎么追;如果"写"跑了一圈又超过了"读"

    //就算是自动将缓冲区清空了,这样的算法具有天生的容错性,只会丢掉前面的键值,

    //而不会崩溃。

}

使用特权

评论回复
10
wangzsa| | 2019-3-13 16:28 | 只看该作者

测试程序:
/*************************************************************************
本文件所有模块的公用测试函数。您可以把本函数放在main()函数的开头里,然后在
本函数内添加您编写的各个模块函数的测试函数,这样你就可以单独测试自己的函数,
而不会影响别的组员的工作(因为main函数一开始就执行了您的测试函数,没有执行
别人的函数!)
**************************************************************************/
/*
void Key_Board_Test(void)//
{
     //如果您想测试函数My_Fun(),那么您就编写相应的My_Fun_Test(),然后把它
     //放到这里来执行。测试完成以后,根据实际情况决定是否保留该测试函数。
     //在本函数前应已初始化串口、定时器0中断!
     u8 key;
     Key_Board_Init();//初始化键盘缓冲区
     while(1)
     {
         key=Read_Key();//从缓冲区读取键值
         if(key == -1)
         {
             continue;
         }
         SoundLight_ms(_TypeBeep,30);//蜂鸣器发声30ms
         switch(key)
         {
             case Key_Up://上箭头
             {
                 printf("您按下了“上箭头”按键。\n\n");
                 break;
             }
             case Key_Down://下箭头
             {
                 printf("您按下了“下箭头”按键。\n\n");
                 break;
             }
             case Key_Add: //加
             {
                 printf("您按下了“加”按键。\n\n");
                 break;
             }
             case Key_Sub://减
             {
                 printf("您按下了“减”按键。\n\n");
                 break;
             }
             case Key_Enter://回车
             {
                 printf("您按下了“回车”按键。\n\n");
                 break;
             }
             case Key_Return://返回
             {
                 printf("您按下了“返回”按键。\n\n");
                 break;
             }
             case Key_LR://左右组合键
             {
                 printf("您同时按下了“左、右”按键。\n\n");
                 break;
             }
             default://未定义按键
             {
                 printf("不知道您按下了什么按键...\n\n");
                 break;
             }
         }
     }
}*/

使用特权

评论回复
11
lium|  楼主 | 2019-3-13 16:31 | 只看该作者

多谢楼上了,太详细了,我慢慢看看

使用特权

评论回复
12
zhangbo1985| | 2019-3-23 23:09 | 只看该作者
这个得是CAN总线的开发的

使用特权

评论回复
13
smilingangel| | 2019-3-23 23:11 | 只看该作者
这个具体是什么上面要用到状态机的?

使用特权

评论回复
14
smilingangel| | 2019-3-23 23:12 | 只看该作者
还有这个状态机的是否就是一个类似任务缓存处理的机制的?

使用特权

评论回复
15
smilingangel| | 2019-3-23 23:12 | 只看该作者
不是特别明白的,欢迎拍砖的

使用特权

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

本版积分规则

915

主题

9578

帖子

3

粉丝