打印
[AVR单片机]

请教一个关于程序结构的问题

[复制链接]
2750|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
七月飞雪|  楼主 | 2007-1-16 09:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
要用mega16写一个程序,用于人机界面,控制液晶和键盘。主菜单下可能包含几级子菜单。我的思路是每个子菜单用一个函数来实现,在进入某个菜单后程序一直在该函数里循环,直到有外部事件触发(比如键盘)才退回上级或进入下级菜单。键盘的询检也是放在各个子函数里的。
可是我的同事和我的意见相左。他把键盘询检和液晶显示的程序都放在主函数里,当检查到某个按键按下时要根据系统当前的状态来判断下面系统应该进入哪种状态。其实就是针对每个子菜单起码要设一个状态码。我觉得这样的话写程序时可能会把逻辑搞乱了,而且别人读程序的话可能也比较费劲。
我自己的方法也有问题就是程序里的嵌套和循环比较多,如果菜单级数越多那我的嵌套也就越多了。
请问大家是怎么想的?谢谢!

相关帖子

沙发
zhaoruixbj| | 2007-1-16 17:13 | 只看该作者

还是听你同事的吧.

   把键盘询检和液晶显示的程序都放在主函数里,当检查到某个按键按下时要根据系统当前的状态来判断下面系统应该进入哪种状态。其实就是针对每个子菜单起码要设一个状态码
   这就跟FPGA里面似的,做成状态机,一个主循环,根据判断状态码转移.
   比较好扩展和维护

使用特权

评论回复
板凳
七月飞雪|  楼主 | 2007-1-16 17:38 | 只看该作者

扩展和维护么?

我知道PCI协议的状态机,可是那个状态比较少啊
我们这个,比如说我按下一个enter键或者数字键,程序得判断当前是哪个菜单下的第几个条目,因为我同级菜单下可能还要翻屏的,这样的话状态太多了,很容易搞错了的呀
而且可读性应该不怎么样,因为我读过他之前的一个程序,只有4个按键,没有液晶,读起来比较吃力,因为一个按键按下之后还要判断之前的按键是什么,开始都不明白是什么意思,看不懂他程序的流程。
按我自己的方式我可以很容易知道这是第几级菜单,它的上一级或下一级是什么。我觉得要扩展的话应该也蛮容易的呀。
不知道是不是我自己一叶障目,欢迎大家提意见,谢谢!

使用特权

评论回复
地板
su_mj000| | 2007-1-17 01:37 | 只看该作者

我倒是觉得LZ的想法更好一点

液晶显示和键盘扫描应该是公用函数/程序,独立于
各菜单(同一个按键在不同的菜单里可有不同的定义)。
令外,每个菜单进入和返回可用链式堆栈保护/恢复
上一级菜单。

这样做的好处是容易扩展,模块之间牵连少。坏处可
能是耗费内存多些。

使用特权

评论回复
5
七月飞雪|  楼主 | 2007-1-17 17:37 | 只看该作者

谢谢回复

一开始被要求按照别人的想法重写程序时心里的抵触情绪很强
现在冷静下来觉得两种方法各有各的优缺点,他的程序结构干净,我的呢,可读性要好一些
但是我还是觉得同事的方法适合写简单的程序,复杂一些的应该写起来比较累吧

使用特权

评论回复
6
robin_ee| | 2007-1-17 17:46 | 只看该作者

呵呵

建议采用你的方式,但也不完全和你的一样。就是阻塞在每个调用函数里面,这样问题比较容易处理,特别是没有os的系统。


对应菜单这里有一个我自己写的,可以参考

void SuperMenu(unsigned char ucMenuItemNum,                            // menu total num
               unsigned char ucStartLineNo,                            // first menu item row pos        1
               unsigned char ucEndLineNo,                            // last menu item row pos         3
               unsigned long ulWaitKeyTimeOut,                        // wait key timeout
               unsigned char ucKeySoundOpen,                        // key beep switch
               unsigned char ucDectectCard,                            // return from menu if card present
               char *pMenuTitle,                                    // menu main title
               char *MenuText[],                                    // menu item content
               void (*function[])(void))                            // menu item function 
{
    unsigned char ucItemNumPerScr;                                    // menu item num per screen
    unsigned char i,j,ucRnt,                                        //
        ucLastScrLineNum,                                            // menu item num in last screen
        ucScrNum,                                                    // menu screen num
        ucCurScr,                                                    // current screen
        ucCurLine;                                                    // current row
    unsigned long ulDelay;
    unsigned char ucShowMargin;

    ucItemNumPerScr = ucEndLineNo - ucStartLineNo + 1;

    UpdateFace();

    lcd_disp(0, 0, "", LCD_CLS);
    
    ucCurLine = 0;
    ucCurScr = 0;
    ulDelay = ulWaitKeyTimeOut;
    ucShowMargin = 1;
    ucScrNum = ucMenuItemNum / ucItemNumPerScr;
    ucLastScrLineNum = ucMenuItemNum % ucItemNumPerScr;
    if(ucLastScrLineNum)
        ucScrNum ++;
    else
        ucLastScrLineNum = ucItemNumPerScr;                            // 
    
    while(1)
    {
        if(ucShowMargin) {
            lcd_disp(0, 0, (char *)pMenuTitle, NULL);
            ucShowMargin = 0;
        }
        // disp a screen info
        for(i=0; i<ucItemNumPerScr; i++) {
            j = ucCurScr*ucItemNumPerScr+i;
            if( j>(ucMenuItemNum-1) ) {
                lcd_disp((ucStartLineNo+i) * 2 , 0, "                ", NULL);
                continue;
            }
            if(i == ucCurLine)
                lcd_disp((ucStartLineNo+i)*2, 0, MenuText[j], LCD_REVERT);
            else
                lcd_disp((ucStartLineNo+i)*2, 0, MenuText[j], 0);
        }
        
        // wait for menu select
        while(1) {
            ucRnt = get_key(TRUE);
            if(ucRnt != NULL)
                break;
            ulDelay --;
            if(ulDelay == 0)
                return;
#if 0
            if(ucDectectCard) { 
                if(profile(0) != ST_ERROR)
                    return;
            }
#endif
            OSTimeDlyHMSM(0, 0, 0, 40);
        }
#if 0
        if(ucKeySoundOpen)
            Beep(1, 100, 50);
#endif
        ulDelay = ulWaitKeyTimeOut;
        //按键处理
        switch(ucRnt) {
        case KEY_DOWN:
            if(ucCurScr == (ucScrNum-1)) {
                if(ucCurLine == (ucLastScrLineNum-1)) {
                    ucCurLine = 0;
                    ucCurScr = 0;
                    break;
                }
            }
            ucCurLine ++;
            if(ucCurLine < ucItemNumPerScr)
                break;
            ucCurLine = 0;
            ucCurScr ++;
            if(ucCurScr < ucScrNum)
                break;
            ucCurScr = 0;
            break;
            
        case KEY_UP:
            if(ucCurLine == 0) {
                if(ucCurScr == 0) {
                    ucCurScr = ucScrNum-1;
                    if(ucCurScr == 0)
                        ucCurLine = ucLastScrLineNum-1;
                } else
                    ucCurScr --;
            }
            else
                ucCurLine --;
            break;
            
        case KEY_CANCEL:
            return;
            
        case KEY_ENTER:
            lcd_disp(0, 0, "", LCD_CLS);
            function[ucCurScr*ucItemNumPerScr + ucCurLine] ();
            ucShowMargin = 1;
            break;
            
        default:
            break;
        }
    }
}    




使用特权

评论回复
7
robin_ee| | 2007-1-17 17:48 | 只看该作者

呵呵

建议你参考我的菜单函数参数设置,他可以嵌套调用,调用方便,而且条理清楚。给足够的灵活性。
void SuperMenu(unsigned char ucMenuItemNum,                            // menu total num
               unsigned char ucStartLineNo,                            // first menu item row pos        1
               unsigned char ucEndLineNo,                            // last menu item row pos         3
               unsigned long ulWaitKeyTimeOut,                        // wait key timeout
               unsigned char ucKeySoundOpen,                        // key beep switch
               unsigned char ucDectectCard,                            // return from menu if card present
               char *pMenuTitle,                                    // menu main title
               char *MenuText[],                                    // menu item content
               void (*function[])(void));                            // menu item function 


使用特权

评论回复
8
robin_ee| | 2007-1-17 17:49 | 只看该作者

呵呵

// some system config entrance
void SystemMenu(void)
{
    unsigned char sMenuTitle[]=  " --Sys Config-- ";
    char *menu[]={                {"① System Ver   "},
                                {"② Device ID    "},
                                {"③ Set Clock    "},
                                {"④ Debug Menu   "},
                                };
    void (*function[])(void) = {
                                    ShowSysVer, 
                                    SetDeviceID,
                                    SetClock,
                                    DebugMenu,
                                };

    SuperMenu( 4,                                                    // menu num
               1,                                                    // first row pos 1
               3,                                                    // last row pos  3
               0x8ffffL,                                            // timeout
               TRUE,                                                // key beep opern
               TRUE,
               sMenuTitle, 
               menu, 
               function);
    return;
}

使用特权

评论回复
9
Bitfu| | 2007-1-17 22:47 | 只看该作者

将问题拆分成容易理解的小部分后编码

有助于维护和阅读!

使用特权

评论回复
10
robin_ee| | 2007-1-18 09:20 | 只看该作者

呵呵

你如果不是用一个GUI系统(包括自己写的小的GUI),而把所有窗口,界面的输入输出操作都放在一个地方来统一处理,如果没有好的组织方式,很难看清楚,看起代码来很麻烦.
mfc的那些什么OnClick..() 之类的事件响应函数就是一些组织方式,让你只需要填充简单的宏,来安装你的响应事件的响应函数,至于这个函数怎么和事件对应起来,怎么被调用,这部分代码是不需要看到的,这个包装工作也是巧妙的.

使用特权

评论回复
11
七月飞雪|  楼主 | 2007-1-18 10:21 | 只看该作者

谢谢大家

谢谢robin_ee的热心回复
不过因为这是我用C写的第一个程序,对于GUI,MFC等等还不是很熟悉(新手上路:))
要学习的东西太多了。。。

使用特权

评论回复
12
robin_ee| | 2007-1-18 11:03 | 只看该作者

呵呵

如果你要了解GUI,特别是嵌入式的GUI,可以先到windows上面去熏陶,windows的GUI是很成熟的,去感化一点点就不错了.建议安装一个vc6.0,写基于win32 API的程序,里面会展示最简单的win32程序,消息系统.

使用特权

评论回复
13
wenlw| | 2007-1-20 17:10 | 只看该作者

robin_ee 的写法是参照UC/OS的写法,这样较好!

robin_ee 的写法是参照UC/OS的写法,这样较好!且实时性较强.

使用特权

评论回复
14
七月飞雪|  楼主 | 2007-1-22 11:33 | 只看该作者

我现在还是按照原来的思路在写,已经可以在线编辑了,可以进行各种参数的设置和修改
robin_ee的写法我会好好学习的:)

使用特权

评论回复
15
ayb_ice| | 2007-3-7 11:14 | 只看该作者

随便说说

你的思路要好一些,不用管理复杂的状态编码,更重要的是修改方便,我也是这样做的,只是把扫键显示等程序放在定时中断中处理更好.

使用特权

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

本版积分规则

4

主题

14

帖子

1

粉丝