单片机编程多动作(操作、事件)的设计方法心得(一)

    在写单片机程序的时候,一个程序有几个动作(操作,事件…),几个动作还有某种关系,或互斥,或按时间顺序等等。


    本文应该算作程序设计一类,还是比较简单的,权当为梳理记录,不图讲到什么高深道理。

   言归正传,设计程序的时候,一定要有分块的概念,大块包含小块,正如人类逻辑上的包含关系。比如一套广播体操分,几套动作,每一套动作分几Part简单的重复动作。那么我们应该认识到,这些简单的重复动作是不可再分割的,所以原则上,我们可以先把这些简单动作写成一个一个函数,至于后面的设计,可能需要合并这些函数,但是思维上把这些动作分割开是首要的。

【互斥动作】

比如机器的某个关节的几个动作是互斥的,下面以头部关节的转动为例,对互斥的动作进行设计:


#include 
#include 


bool HR_IF//头部转动动作执行或者不执行的开关标记


char HR_FLGS //bit7、6:表示头部转动的模式,参见Mode_HR成员;bit5~0表示头部转动次数


enum Mode_HR
{
    VERTI,
    HORI,
    ALLDIRE,
};




HR_VERTI(){}//头部水平转动函数
HR_HORI(){}//头部竖直转动函数
HR_ALLDIRE(){}//头部全方向转动函数


void HeadRotate(bool HR_if, Mode_HR mod , int times )//参数:开关,方式、次数(0为无限次)
{
    HR_IF = HR_if;
    HR_FLGS| = mod << 6;//Mode_HR有效位只有两位,把它左移到HR_FLGS的高2位
    HR_FLGS| = times & 0x3f;//HR_FLGSd bit5~0表示头部转动次数
}





int main()
{
    machine_init();
    while(1)
    {
        if(HR_if)
        {
            if(HR_FLGS&0xc0 == 0)//HR_FLGS的bit7、6:表示头部转动的模式,
                HR_VERTI();
            else if(HR_FLGS&0xc0 == 1)
                HR_HORI();
            else if(HR_FLGS&0xc0 == 1)
                HR_ALLDIRE();

            if(HR_FLGS&0x3f == 1)
                HR_if = 0;//计数次数完结,不再执行动作
            else(HR_FLGS&0x3f != 0)
                HR_FLGS--;
        }
    }
    return 0;
}


void interrupt()//按键中断函数
{
    HeadRotate(1,VERTI,9); //一旦按下按键,则让机器头部按水平方向转动。
}
>   可以看出,一个关节的动作其实是由几个小的动作组成的,几个小的动作是相互排斥的,这里用了几个if-else结果来表示这个互斥作用。
HR_VERTI(){}//头部水平转动函数
HR_HORI(){}//头部竖直转动函数
HR_ALLDIRE(){}//头部全方向转动函数

【独立动作】

那么两个独立的动作又怎么处理呢?独立的动作之间本身是没有关联性的,承接上例来说,头部关节的动作和躯干关节的动作本身是没有联系的,是独立的。

我依照上面的例子进行一些修改,加入一个机器的身体(BODY)动作:
#include 
#include 

char ACTION//!!!此处本来是头部动作开关的标记,现在改为几个动作的开关标记组

char HR_FLGS //bit7、6:表示头部转动的模式,参见Mode_HR成员;bit5~0表示头部转动次数

enum Mode_HR
{
    VERTI,
    HORI,
    ALLDIRE,
};


HR_VERTI(){}//头部水平转动函数
HR_HORI(){}//头部竖直转动函数
HR_ALLDIRE(){}//头部全方向转动函数

void HeadRotate(bool HR_if, Mode_HR mod , int times )//参数:开关,方式、次数(0为无限次)
{
    ACTION| = HR_if;//!ACTION的bit0表示头部动作
    HR_FLGS| = mod << 6;//Mode_HR有效位只有两位,把它左移到HR_FLGS的高2位
    HR_FLGS| = times & 0x3f;//HR_FLGSd bit5~0表示头部转动次数
}

//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//        新增body动作部分
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

char BD_FLGS //bit7、6:表示头部转动的模式,参见Mode_HR成员;bit5~0表示头部转动次数

enum Mode_BD
{
    BD_MODE0,
    BD_MODE1,
    BD_MODE2
};


BD_0(){}//头部水平转动函数
BD_1(){}//头部竖直转动函数
BD_2(){}//头部全方向转动函数

void HeadRotate(bool BD_if, Mode_HR mod , int times )//参数:开关,方式、次数(0为无限次)
{
    ACTION| = BD_if<<1;//!ACTION的bit1表示身体动作
    HR_FLGS| = mod << 6;
    HR_FLGS| = times & 0x3f;
}



//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\


int main()
{
    machine_init();
    while(1)
    {
        if(ACTION&0x01 == 1)//!如果头部动作可以执行
        {
            if(HR_FLGS&0xc0 == 0)//HR_FLGS的bit7、6:表示头部转动的模式,
                HR_VERTI();
            else if(HR_FLGS&0xc0 == 1)
                HR_HORI();
            else if(HR_FLGS&0xc0 == 1)
                HR_ALLDIRE();

            if(HR_FLGS&0x3f == 1)
                ACTION& = 0xfe;//计数次数完结,不再执行动作,清除bit0
            else(HR_FLGS&0x3f != 0)
                HR_FLGS--;
        }

        if(ACTION&0x02 == 1)//!如果身体动作可以执行
        {
            if(HR_FLGS&0xc0 == 0)
                HR_VERTI();
            else if(HR_FLGS&0xc0 == 1)
                HR_HORI();
            else if(HR_FLGS&0xc0 == 1)
                HR_ALLDIRE();

            if(HR_FLGS&0x3f == 1)
                ACTION& = 0xfd;//清除bit1
            else(HR_FLGS&0x3f != 0)
                HR_FLGS--;
        }

    }
    return 0;
}

void interrupt()//按键中断函数
{
    HeadRotate(1,VERTI,9); //一旦按下按键,则让机器头部按水平方向转动。
}
    > 由上面代码看出,BODY和HEAD的动作是分成两个独立部分的,它们在程序上有相似的结构(这不必须,不过作为程序的编写者,有必要让程序具有普适性),它们之间唯一的交集就是ACTION。虽然说两套动作的开关都在ACTION的某一bit里,但是本质上,这两个bit位的操作也是独立开来的,那为啥还要做在一个char里呢,这是为了方便综合控制,这个后面再说。


    >可以看出,上述两段代码都有一个基本的理念,就是把控制和实现分成两大部分。控制,利用标记和标记组,加上if或者switch判断来选择需要执行的具体函数这一过程,而具体实现则是几个细小得不可分割的函数。当然,像上面的代码,我们可以把mian函数里的if判断放在一个新的函数里以简化mian函数,形如:
void HEAD_ACTION(Mode_HR mod)
{
    if(mod == 0)//HR_FLGS的bit7、6:表示头部转动的模式,
        HR_VERTI();
    else if(mod  == 1)
        HR_HORI();
    else if(mod == 1)
        HR_ALLDIRE();

}
    几个关节的动作的开关合并作一个标记组ACTION,可以用于综合控制。围绕这个部分,还可以写一篇文章,关于复杂动作之间的关系,如何利用这个标记组表示和设计,所以此文就暂时到此为止。

你可能感兴趣的:(单片机编程多动作(操作、事件)的设计方法心得(一))