xcodes 发表于 2009-12-19 10:06:45

一个占用内存极小的菜单系统在AVR上的移植

点击此处下载 ourdev_516483.pdf(文件大小:121K) (原文件名:一个占用内存极小的菜单系统在AVR上的移植.pdf)

感觉有用的要回复

155107149 发表于 2009-12-19 10:50:19

杜绝0回复。。。。。

wear778899 发表于 2009-12-19 10:53:54

杜绝1回复。。。。。

_yuming 发表于 2009-12-19 11:22:44

标题党,鉴定完毕!!

tony74 发表于 2009-12-25 18:47:55

正好用到,谢谢!
CVAVR要怎么修改??

xcodes 发表于 2009-12-25 19:32:13

没用过CVAVR
我用的是GCC

wjy6264 发表于 2009-12-27 16:43:15

学习下!

bkkman 发表于 2009-12-27 17:13:49

【3楼】 _yu-ming

标题党,鉴定完毕!!
******************************************************************

何以轻率下此结论?

LZ的工作值得赞许,是踏实的工作.
顺便把PDF内容贴出来.

******************************************************************

一个占用内存极小的菜单系统在 AVR AVR AVR AVR 上的移植
相信经典的 《 一个占用内存极小的菜单系统的实现》 这篇文章大家都看过了吧
我在做某工程的时候,也借鉴了作者的 的编程思想并在 atmega32 上做了自己的菜单系统
简单的说一下移植思路,本文假设读者详细阅读了 《一个占用内存很小的菜单系统》这篇
经典文章,并理解了原作者的编程思想,以及有一定的 AVR C 语言 编程经验。
本文以下代码基于 WINAVR20090313 WINAVR20090313 WINAVR20090313 WINAVR20090313
1. 1. 1. 1. 函数名列表 索引的移植
因为直接加 const 关键词定义表格是没有用的 表格的数据仍然是存放在 .data 区 (RAM) 的
还需要加 PROGMEM 关键字:
例子如下 :
例子如下 : : : :
const KbdTabStruct KeyTab[] PROGMEM ={
{0,1,2,3,4,(*MenuSleepInit)},
{1,0,0,0,0,(*MenuSleepUp)},
{2,0,0,0,0,(*MenuSleepDn)},
{3,0,0,0,0,(*MenuSleepEsc)},
{4,0,0,0,0,(*MenuSleepEtr)},
{5,6,7,8,9,(*MenuTopInit)},
{6,0,0,0,0,(*MenuTopUp)},
{7,0,0,0,0,(*MenuTopDn)},
{8,0,0,0,0,(*MenuTopEsc)},
{9,0,0,0,0,(*MenuTopEtr)},
……
}
这样 数组就被定义在 Flash 区了

bkkman 发表于 2009-12-27 17:14:38

这样 数组就被定义在 Flash 区了
2. 2. 2. 2. 如何读出菜单状态 ?
KeyFuncIndex=pgm_read_byte(&KeyTab.KeyUpState);
3. 3. 3. 3. 如何把函数指针从 Flash Flash Flash Flash 区取出来 并执行?
(*((void(*)(void))pgm_read_word(&KeyTab.CurrentOperate)))();
// 从 Flash 区 读出函数指针 (2 个字节 ) 并且强制转换为函数 执行
更简单的办法:
#define PgmFun(A) (*((void(*)(void))pgm_read_word(&A)))() // 定义一个可以执行
Flash 区函数指针的宏
然后一句
PgmFun(KeyTab.CurrentOperate);
就可以调用表格内的函数指针 .

bkkman 发表于 2009-12-27 17:16:15

就可以调用表格内的函数指针 .
4. 4. 4. 4. 菜单项的定义
const uchar MenuSetsEN_0[] PROGMEM="Set Time";
const uchar MenuSetsEN_1[] PROGMEM="Set Date";
const uchar * MenuSetsEN[] PROGMEM=
{
MenuSetsEN_0,
MenuSetsEN_1,
……
}
5. 5. 5. 5. 关于显示方面
一般情况下 printf(" formatstring "); 中的 formatstring 是在 .data 区的
我们还需要编写一个 Printf_P
下面是一个 LCD_Printf_P 函数
/*
函 数 名 : void LCD_Printf_P(unsigned char StartX,unsigned char AtLineY,const prog_char
*strfmt,...)
入口参数 : unsigned char StartX , unsigned char AtLineY 开始点
const prog_char *strfmt, 要显示的内容
%s 显示字符串 % d 显示一个无符号整数 0 ~ 65535 的
%% 显示一个 '%'
返回 : 无

bkkman 发表于 2009-12-27 17:18:09

返回 : : : : 无
调用函数 : : : :
LCD_SetPos(StartX,AtLineY); // 设置开始点的位置
LCD_PutC( char C); // 显示一个字符
LCD_PutStr(char *str); // 显示一个字符串
LCD_PutNum(unsigned int Num); // 显示一个无符号整数
例子 : : : : LCD_Printf_P(0,0,PSTR("hello,world!"));
Uint i=1234;
LCD_Printf_P(0,1,PSTR("%d"),i);
*/
void LCD_Printf_P(unsigned char StartX,unsigned char AtLineY,const prog_char *strfmt,...)
{
const char *str;
int Num;
char LCD_Buf;
char *fmt;
strcpy_P(LCD_Buf,strfmt);
fmt=LCD_Buf;
va_list arg_ptr;
LCD_SetPos(StartX,AtLineY);
va_start(arg_ptr,fmt);
while(*fmt)
{
if(*fmt!='%')
{
LCD_PutC(*fmt);
fmt++;
continue;
}
switch (*++fmt) // 先加
{
case 's':
str=va_arg(arg_ptr, char *);
LCD_PutStr(str);
break;
case 'd':
Num=va_arg(arg_ptr,int);
LCD_PutNum(Num);
break;
case '%':
LCD_PutC('%');
break;
default:
break;
}
fmt++;
}
va_end(arg_ptr);
}

bkkman 发表于 2009-12-27 17:18:59

6. 6. 6. 6. 如何使用 LCD_Printf_P LCD_Printf_P LCD_Printf_P LCD_Printf_P 函数显示菜单项 ? ? ? ?
LCD_Printf_P(0,0,(PGM_P)pgm_read_word(pMenu.Text+Item));
LCD_Printf_P(0,1,(PGM_P)pgm_read_word(pMenu.Text+Item+1));
7. 7. 7. 7. 语言选项方面
const Menu MenuSets[] PROGMEM=
{
MenuWhat(MenuSetsEN),
MenuWhat(MenuSetsCN),
};
把菜单指针指向语言项
pMenu=memcpy_P(pMenu,&MenuSets,sizeof(Menu));
-------------------------------------- 全文完 ------------------------------------------
以上是我所遇到的问题以及最终处理办法,语言表述有限,谢谢阅读。
李银超 20091218
QQ:422484931
liyinchao@gmail.com

astudent 发表于 2009-12-30 19:43:55

关注

zenboys 发表于 2010-3-18 14:51:22

很详细,感谢

eastcomm 发表于 2010-4-12 21:07:50

看来函数指针的运用很重要!

99stone 发表于 2010-4-18 13:12:53

用简洁的电路,简洁的程序,填充我的生活 ./emotion/em078.gif

chouxier 发表于 2010-5-25 18:10:07

正打算用GCC试着移植。

cyr_hongfeng 发表于 2010-5-25 19:06:40

一个占用内存极小的菜单系统的实现 我研究有一段时间了,这里先做个标记,做完毕设再过来

angle11 发表于 2010-7-12 10:23:13

我先下了才回复。。

wzxavr 发表于 2010-8-26 13:14:35

正要用到,非常感谢。

sunnyqdl 发表于 2010-8-28 13:54:23

标记一下先~~~~

lizardno1 发表于 2010-8-28 14:17:38

mark!

mydows 发表于 2010-9-7 13:04:53

自己已经移至完成了,就差keytab放到flash去了。感谢前人!

mydows 发表于 2010-9-7 13:27:36

请问大家是如何应对警告的:AVRstudio+GCC

警告1:../menu.c:569: warning: pointer targets in passing argument 1 of 'BarDisp' differ in signedness

源代码位置如下:
//-------------------
//既然Item Where均是未定的,那么我们使用从子菜单退出的方法来找到应该再Where=0位置显示的Item项
//----------------
//方法2
    if (Item >= Where) {Menu_j = Item -Where;} //未跨越零点
    else               {Menu_j = ItemNum- (Where - Item);}//跨越零点
    //此时Menu_J的值就是顶部(Where=0)显示的Item值
//----------------
    //显示全部的子菜单项
    for (Menu_i = 0; Menu_i < DispMin; Menu_i++) {
      if (Menu_j == Item)        {            BarDisp(*(DispItem+Item),0,Menu_i,1);}//反显第Item项,位置是Where********警告1位置
      else                                 {              BarDisp(*(DispItem+Menu_j),0,Menu_i,0);}//其它项 正常显示
      if (Menu_j == (ItemNum-1))        {Menu_j = 0;}//到了最后一项,回环到最开始的一项
      else                                                {Menu_j++;}//下一项
    }
    //Bar(Item,ItemNum,MenuBarPosX,MenuBarNumPosX);                  //维护滚动条
}


警告2:../menu.c:126: warning: braces around scalar initializer
       ../menu.c:126: warning: (near initialization for 'menutopCN')
警告3:../menu.c:127: warning: braces around scalar initializer
       ../menu.c:126: warning: (near initialization for 'menutopCN')



源代码位置如下:
const char * menutopCN[]=
{
        {"查空空询"},       *******警告2
        {"自空空检"},       *******警告3
        {"复空空位"},
        {"时钟设置"},
        {"地址设置"},
};

aliang2007 发表于 2010-9-14 23:16:02

学习学习 谢谢搂住

liaogang1314 发表于 2010-10-26 16:11:22

楼主以及各位高手:
    我一直在琢磨菜单结构,看大家用的大都是结构体,里面把数据和处理数据的函数放在一个结构体里面,我百看也不能理解是怎么实现的? 这个好像是面向对象的程序设计了吧!? 可是我没有学过C++, 对面向对象的程序设计方法不理解? 楼主以及各位高手能不能详细的指导指导我一下啊!?不胜感激!!!!!!!!!!!

zyw19987 发表于 2010-12-12 23:09:12

能创建级菜单吗?像手机一样,增加了一个文件或者文件夹。菜单改如何做呢???

peavey 发表于 2011-1-12 19:33:13

记号先

522yt 发表于 2011-3-20 17:47:03

看下。我那个菜单占内存太大了。才二级就没内存了。学习下。,

pei84 发表于 2011-4-15 15:12:53

顶你

ccxlslr 发表于 2011-4-15 17:22:15

太NB了啊!

bulinsheng 发表于 2011-4-15 17:36:10

强!!!

adszmc 发表于 2011-9-14 17:06:51

ljmdzyx 发表于 2011-9-16 23:36:05

牛,学习了。

bosw83 发表于 2012-5-10 21:42:52

应该很有用。MARK

hamipeter 发表于 2012-5-11 02:47:46

不错,很好

cumt_123456 发表于 2012-12-19 01:36:52

现在都别诱惑我做菜单,正做IAP

jz701209李 发表于 2013-4-10 14:52:32

学习一下....

hfjydq 发表于 2014-7-29 10:35:13

mydows 发表于 2010-9-7 13:04
自己已经移至完成了,就差keytab放到flash去了。感谢前人!

/*
FIXME!!!
如何修改BarMenuInit和如何处理Item Where的初始化来达到如此一个目的?
当前系统语言设定是英语,而英语这个项在第2项位置,因此如何能做到当菜单进入语言选择时,反显位置就在英语那里?
1。修改BarMenuInit代码,处理第一次进入时的处理方式,也许就可以仅仅使用从子菜单退出时的处理方法
*/
//Bar型菜单初始化公共部分
void BarMenuInit(void)
{
        U8 Menu_i;          //计数变量 在菜单函数中用到
        U8 Menu_j;          //计数变量
        //-------------------
        //比较"显示屏可以显示的项的数目(DispMax)"跟"需要显示的数目(ItemNum)"
        //找出小者,以小者为显示上限
        //例如显示屏可以显示3项,需要显示的项有2项,那么显示2项,有3项,显示3项,有4项的话,显示3项
        if (ItemNum > DispMax)
        {
          DispMin = DispMax;
        }
        else
        {
          DispMin = ItemNum;
        }
        //--------------------
        //    if (Flash) {//从父菜单进入 初始化
    if(Flash == FlashMode_AutoInit)//常规进入 做备份
    {
            PUSH();//在修改Item Where之前备份这些参数数据!!
      Item = 0;
      Where = 0;
    }
        else if (Flash == FlashMode_ManualInit)//非常规进入在之前已经备份了,这里做边界检查
        {   
      if(Where > DispMin-1)//检查是否出界
                {
              Where = DispMin-1;//A.最底部的显示位置
      }
      if(Item > ItemNum-1)//检查是否出界
                {
            //Item = ItemNum-1;//A.最后的一个项
            Item = 0;          //B.最开始的一个项
      }
    }
        //    }
        //-------------------
        //既然Item Where均是未定的,那么我们使用从子菜单退出的方法来找到应该再Where=0位置显示的Item项
        //----------------
        //方法2
    if (Item >= Where) //未跨越零点
        {
      Menu_j = Item -Where;
    }
        else //跨越零点
        {            
      Menu_j = ItemNum- (Where - Item);
    }
    //此时Menu_J的值就是顶部(Where=0)显示的Item值
        //----------------
    //显示全部的子菜单项
    for (Menu_i = 0; Menu_i < DispMin; Menu_i++)
        {
      if (Menu_j == Item)//反显第Item项,位置是Where
                {
            BarDisp(*(DispItem+Item),BarXOffset,Where*BarYSize+BarYOffset,1);
      }
                else //其它项 正常显示
                {            
            BarDisp(*(DispItem+Menu_j),BarXOffset,Menu_i*BarYSize+BarYOffset,0);
      }
      if (Menu_j == (ItemNum-1)) //到了最后一项,回环到最开始的一项
                {
            Menu_j = 0;
      }
                else //下一项
                {                  
            Menu_j++;
      }
    }
    Bar(Item,ItemNum,MenuBarPosX,MenuBarNumPosX);                  //维护滚动条
}






这个函数没看懂,没看明白他菜单条项如何上下翻的,也没看明白他子菜单返回如何处理的

rockyyangyang 发表于 2014-7-30 07:31:18

mark                     
页: [1]
查看完整版本: 一个占用内存极小的菜单系统在AVR上的移植