一个占用内存极小的菜单系统在AVR上的移植
点击此处下载 ourdev_516483.pdf(文件大小:121K) (原文件名:一个占用内存极小的菜单系统在AVR上的移植.pdf)感觉有用的要回复 杜绝0回复。。。。。 杜绝1回复。。。。。 标题党,鉴定完毕!! 正好用到,谢谢!
CVAVR要怎么修改?? 没用过CVAVR
我用的是GCC 学习下! 【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 区了 这样 数组就被定义在 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);
就可以调用表格内的函数指针 . 就可以调用表格内的函数指针 .
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 的
%% 显示一个 '%'
返回 : 无 返回 : : : : 无
调用函数 : : : :
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);
} 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 关注 很详细,感谢 看来函数指针的运用很重要! 用简洁的电路,简洁的程序,填充我的生活 ./emotion/em078.gif 正打算用GCC试着移植。 一个占用内存极小的菜单系统的实现 我研究有一段时间了,这里先做个标记,做完毕设再过来 我先下了才回复。。 正要用到,非常感谢。 标记一下先~~~~ mark! 自己已经移至完成了,就差keytab放到flash去了。感谢前人! 请问大家是如何应对警告的: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
{"复空空位"},
{"时钟设置"},
{"地址设置"},
}; 学习学习 谢谢搂住 楼主以及各位高手:
我一直在琢磨菜单结构,看大家用的大都是结构体,里面把数据和处理数据的函数放在一个结构体里面,我百看也不能理解是怎么实现的? 这个好像是面向对象的程序设计了吧!? 可是我没有学过C++, 对面向对象的程序设计方法不理解? 楼主以及各位高手能不能详细的指导指导我一下啊!?不胜感激!!!!!!!!!!! 能创建级菜单吗?像手机一样,增加了一个文件或者文件夹。菜单改如何做呢??? 记号先 看下。我那个菜单占内存太大了。才二级就没内存了。学习下。, 顶你 太NB了啊! 强!!! 顶 牛,学习了。 应该很有用。MARK 不错,很好 现在都别诱惑我做菜单,正做IAP 学习一下.... 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); //维护滚动条
}
这个函数没看懂,没看明白他菜单条项如何上下翻的,也没看明白他子菜单返回如何处理的 mark
页:
[1]