marker 发表于 2008-3-29 10:59:29

节省RAM在Flash空间实现的菜单方法

这个是AVR单片机实现的菜单方法,尽量使用Flash空间,少使用RAM。
本来这个程序在两年前就做了,但是由于某种协议的关系只能在今天才能透出一点,虽然协议到期但由于这是个商业产品,我也不想惹出事端,删除了一此细节的东西,并做了大量的更改,改变了本来的面目(有点面目全非:)),现在列出来的程序也比较隐晦,希望大家见谅。我只是提出了一种方法,如果大家要做菜单时再看这个程序应该就不难了。

欢迎大家讨论这个方法。

近段时间把C++也学习完了:),现在是用VC++还是用BCB不能确定,从实际情况来看用BCB要好些(我的程序较简单,界面多些),但实示我也要考虑口袋的银子问题。
写程序我是被逼的,我喜欢做电路设计,也是我学的专业,实际上我的电路设计比程序设计要好,而且要多些:)
说明:
fo为函数的标记头。

这个菜单是在LCD1602显示屏上实现的

#ifndef __MENU_LAYOUT_H__
#define __MENU_LAYOUT_H__

struct menu
{
    const structmenu * parent;            // 父指针
    const structmenu * child;               // 子指针
    unsigned char pos;                        // 位置
    unsigned char MenuLenght;               // 本菜单中的子菜单长度
    void          (*CurrentOperate)(void);    // 调用函数用,以fo为头
    unsigned char str_len;                  // 显示文字长度
    unsigned char name;                   // point to display name of menu item
};

#define NULL (struct menu const *)0

void NullSubs(void)
{
}

#pragma data:code
extern const struct menu main_menu;
extern const struct menu sub_setting;   //设置
extern const struct menu sub_view;      //查看
extern const struct menu sub_info;      //信息
extern const struct menu sub_set;             
extern const struct menu sub_view;         
/*****************顶层菜单*********************/
const struct menu main_menu=      
{
        {NULL, &sub_setting, 0, 3, NullSubs,7,"Setting"},
        {NULL, &sub_view,    1, 3, NullSubs,4,"View"},
        {NULL, &sub_info,    2, 3, NullSubs,4,"Help"},
};
/******************第二层**********************/
const struct menu sub_setting =      
{
        {&main_menu, NULL,         0, 4, foSetting0, 8, "Setting0"},                
        {&main_menu, NULL,         1, 4, foSetting1, 8, "Setting1"},
        {&main_menu, &sub_set,    2, 4, foSetting2, 8,"Setting2"},
        {&main_menu, NULL,         3, 4, fosetting3, 8, "Setting3"},
};
const struct menu sub_view =   
{
        {&main_menu, &sub_view, 0, 3, foView0,5, "View0"},
        {&main_menu, NULL,          1, 3, foView1, 5, "View1"},
        {&main_menu, NULL,          2, 3, foView2, 5,"View2"},
};
const struct menu sub_info=   
{
        {&main_menu, NULL,         0, 2, foInfo0,    5,"Help0"},
        {&main_menu, NULL,         1, 2, foInfo1,   5, "Help1"},
};
/*******************第三层**********************/
const struct menu sub_set =
{
        {&sub_setting, NULL, 0,2, foSubSetting0,   15, "SubSetting0"},
        {&sub_setting, NULL, 1,2, foSubSetting1,   13, "SubSetting1"},
};
const struct menu sub_view =
{
        {&sub_view, NULL,0, 4, foSubView0, 8, "SubView0"},
        {&sub_view, NULL,1, 4, foSubView1, 8, "SubView1"},
        {&sub_view, NULL,2, 4, foSubView2, 8, "SubView2"},
        {&sub_view, NULL,3, 4, foSubView3, 8, "SubView3"},
};
#pragma data:data
#endif

/**********************************/
/*   菜单操作函数               */
/**********************************/
unsigned char menu_exe(void)       //函数调用,如果返回值为0xFF则中止
{
        const struct menu   * mp;
        const unsigned char * str;
        unsigned char menu_len, position;
        unsigned char len;
        unsigned char key_val;
        void (*KeyFuncPtr)(void);
       
        mp = main_menu;
        position = 0;
       
        while(1)
        {
                WDR();
                menu_len = mp->MenuLenght;
                str = mp->name;
                len = mp->str_len;
                delay_ms(300);   
                LCD_clr();                   //清屏
                delay_ms(3);               //保证按键人性化
                LCD_write_string_P(0,0,4,str_menu);
                if(menu_len < 10)
                {
                        LCD_write_data(12,0,menu_len+0x30);
                }
                else
                {
                        LCD_write_data(11,0,0x31);
                        LCD_write_data(12,0,menu_len+0x26);
                }
                LCD_write_data(13,0,'-');
                if( position < 9)
                {
                        LCD_write_data(14,0,position+0x31);
                }
                else
                {
                        LCD_write_data(14,0,0x31);
                        LCD_write_data(15,0,position+0x27);
                }
                do
                {
                        FlashStr(str,0x20,0,1);
                        delay_ms(2);
                        key_val = GetKey();
                        if(lighttimer < 8000)
                        {
                                return 0xFF;                                 //超时退出
                        }
                }
                while(!key_val);                                     //wait the key press
                switch (key_val)
                {
                        case DOWN_KEY:
                                if (position == (menu_len - 1))
                                {
                                        position = 0;
                                        mp -= menu_len -1;
                                }
                                else
                                {
                                        mp++;
                                        position++;
                                }
                                break;
                        case UP_KEY:
                                if (position == 0)
                                {
                                        position = menu_len - 1;
                                        mp += menu_len - 1;
                                }
                                else
                                {
                                        mp--;
                                        position--;
                                }
                                break;
                        case ENTER_KEY:
                                if(mp->child == NULL)
                                {
                                        LCD_clr();                              //清屏
                                        delay_ms(10);                           //保证按键人性化
                                        KeyFuncPtr = mp->CurrentOperate;
                                        (*KeyFuncPtr)();       
                                        //mp = mp->parent;
                                }
                                else
                                {
                                        mp = mp->child;
                                        position = 0;
                                }
                                break;
                        case ESC_KEY:
                                if(mp->parent == NULL)
                                return 0xFF;
                                mp = mp->parent;
                                position = mp->pos;
                                break;
                }
        }
        return 0;
}

marker 发表于 2008-3-29 11:05:46

本来我一直用的是GCC,但是GCC好象对flash存储器,flash指针支持不是很好,要通过API来实现,而且我没找到存储在flash内指向flash的指针在GCC AVR是怎样实现的;(,只能用ICC来实现了。

cai_mouse 发表于 2008-5-18 22:44:37

在编写菜单程序时,我也由于GCC对flash存储器操作不太好而改用其他C语言来替代GCC.

sjzd 发表于 2008-5-19 00:38:02

顶下    自己还菜   标记下

ATmega32 发表于 2008-5-19 08:10:15

存储在flash内指向flash的指针在GCC AVR是怎样实现的.

实际上就是存储在FLASH里面的指针,至于指针是指向RAM,还是FLASH,由程序控制.

perfect_co 发表于 2008-5-19 10:53:43

发觉怎么很多人写出的菜单结构都是这种...可以思考下其他的方法,这种方法在深度深时恐怕比较麻烦,结构化程度还不是很高...当然我没仔细看,也许说的不对

lonely88 发表于 2008-8-1 18:21:11

menu   mark

382383706 发表于 2010-3-24 21:30:08

mark

xuejianhua1986 发表于 2010-3-24 22:27:12

mark

zxc2769 发表于 2013-12-31 08:58:54

。。。。。。。。。。。。

yayagepei 发表于 2013-12-31 18:17:00

看看,很实用的样子

whatcanitbe 发表于 2013-12-31 20:37:12

这种模式适合菜单固定的,而且转向确定的场合,比如这种就相对难实现

菜单A    可以跳转到   菜单C
菜单B   也可以跳转到 菜单C

当在菜单C处理完后分别退回到 菜单A   菜单B

wsm80828 发表于 2014-1-1 20:13:39

谢谢分享
页: [1]
查看完整版本: 节省RAM在Flash空间实现的菜单方法