|
这个是AVR单片机实现的菜单方法,尽量使用Flash空间,少使用RAM。
本来这个程序在两年前就做了,但是由于某种协议的关系只能在今天才能透出一点,虽然协议到期但由于这是个商业产品,我也不想惹出事端,删除了一此细节的东西,并做了大量的更改,改变了本来的面目(有点面目全非:)),现在列出来的程序也比较隐晦,希望大家见谅。我只是提出了一种方法,如果大家要做菜单时再看这个程序应该就不难了。
欢迎大家讨论这个方法。
近段时间把C++也学习完了:),现在是用VC++还是用BCB不能确定,从实际情况来看用BCB要好些(我的程序较简单,界面多些),但实示我也要考虑口袋的银子问题。
写程序我是被逼的,我喜欢做电路设计,也是我学的专业,实际上我的电路设计比程序设计要好,而且要多些:)
说明:
fo为函数的标记头。
这个菜单是在LCD1602显示屏上实现的
#ifndef __MENU_LAYOUT_H__
#define __MENU_LAYOUT_H__
struct menu
{
const struct menu * parent; // 父指针
const struct menu * child; // 子指针
unsigned char pos; // 位置
unsigned char MenuLenght; // 本菜单中的子菜单长度
void (*CurrentOperate)(void); // 调用函数用,以fo为头
unsigned char str_len; // 显示文字长度
unsigned char name[16]; // 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[3];
extern const struct menu sub_setting[4]; //设置
extern const struct menu sub_view[3]; //查看
extern const struct menu sub_info[2]; //信息
extern const struct menu sub_set[2];
extern const struct menu sub_view[4];
/*****************顶层菜单*********************/
const struct menu main_menu[3] =
{
{NULL, &sub_setting[0], 0, 3, NullSubs, 7, "Setting"},
{NULL, &sub_view[0], 1, 3, NullSubs, 4, "View"},
{NULL, &sub_info[0], 2, 3, NullSubs, 4, "Help"},
};
/******************第二层**********************/
const struct menu sub_setting[4] =
{
{&main_menu[0], NULL, 0, 4, foSetting0, 8, "Setting0"},
{&main_menu[0], NULL, 1, 4, foSetting1, 8, "Setting1"},
{&main_menu[0], &sub_set[0], 2, 4, foSetting2, 8,"Setting2"},
{&main_menu[0], NULL, 3, 4, fosetting3, 8, "Setting3"},
};
const struct menu sub_view[3] =
{
{&main_menu[1], &sub_view[0], 0, 3, foView0, 5, "View0"},
{&main_menu[1], NULL, 1, 3, foView1, 5, "View1"},
{&main_menu[1], NULL, 2, 3, foView2, 5, "View2"},
};
const struct menu sub_info[2] =
{
{&main_menu[2], NULL, 0, 2, foInfo0, 5, "Help0"},
{&main_menu[2], NULL, 1, 2, foInfo1, 5, "Help1"},
};
/*******************第三层**********************/
const struct menu sub_set[2] =
{
{&sub_setting[2], NULL, 0, 2, foSubSetting0, 15, "SubSetting0"},
{&sub_setting[2], NULL, 1, 2, foSubSetting1, 13, "SubSetting1"},
};
const struct menu sub_view[4] =
{
{&sub_view[0], NULL, 0, 4, foSubView0, 8, "SubView0"},
{&sub_view[0], NULL, 1, 4, foSubView1, 8, "SubView1"},
{&sub_view[0], NULL, 2, 4, foSubView2, 8, "SubView2"},
{&sub_view[0], 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;
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|