【原创分享】单片机菜单功能的设计(节点)----2009.07

来源:互联网 发布:java教程中创建数据包 编辑:程序博客网 时间:2024/06/05 22:37

恩,上次由于总经理有说要做一个彩屏的LCD遥控器,呵呵,用ARM或者AVR32,真高级。还好 我都曾经弄过。

由于屏幕还在挑选中 (NAKIA的那几款手机的不错 资料也多),自己有个 给个休假的同事拿走了 哎。所以先做了个简单的菜单。

恩 首先要把参考资料告诉大家 《基于节点编号的通用树状菜单设计方法与实现》这个PDF给了我很大的提示,基本思路还是与上相同 但是 其方法中的 子项的处理感觉模糊。

所以 用了自己的方法写了个完整的 建立在 TS-12664-3的字库型液晶上。换屏只是换LCD部分程序,影响不大 这里主要是菜单的实现。

基于节点编号的通用树状菜单设计方法与实现一文对节点的方法解析得是很清楚的,而我的有点偏差,ID定义还是一样方法,只是一个菜单的项的子菜单定义有别

ID:1

遥控器--->子项为11

收音机--->子项为12

电视机--->子项为13

还是看看完整的程序吧。

#include "avr/io.h"#include "lcd/lcd.h"#include "delay/delay.h"//#include "data.h"#define NULL 0#define MENUNO 10 //菜单数目#define PRONO 4 //程序数目#define uchar unsigned char#define uint unsigned int#define KEYPORT PORTD#define KEYPIN PINDtypedef struct menu{uint ID; //菜单IDchar *name[10]; //菜单项描叙uchar total,cur,line; //总项,当前选择项,以及屏幕当前停留在哪行(1-4行);struct menu *esc;}MENU;//我的菜单项的结构定义MENU menus[MENUNO]={{1,{"遥控器","收音机","学习机","电视机","VCD","音响"},6,0,0,NULL},{11,{"三星","LG","康佳"},3,0,0,NULL},{12,{"建设中"},1,0,0,NULL},{13,{"建设中"},1,0,0,NULL},{14,{"建设中"},1,0,0,NULL},{15,{"建设中"},1,0,0,NULL},{16,{"建设中"},1,0,0,NULL},{111,{"TM79","TM85","TM86","TM87"},4,0,0,NULL},{112,{"建设中"},1,0,0,NULL},{113,{"建设中"},1,0,0,NULL},};volatile uchar i,j,temp,data,lin,keyflag,key;volatile MENU *pmenu,*ptemp;volatile uint menuid[MENUNO]={1,11,12,13,14,15,16,111,112,113};volatile char *se="<--";void tm79pro(void);void tm85pro(void);typedef struct menup{uint ID;void (*mp)();}MP;volatile MP menupro[PRONO]={{1111,tm79pro},{1112,tm85pro}};//-----------------------------------------------////---------------程序区--------------------------////-----------------------------------------------//void tm79pro(void){uchar j;char *p="你选择的是TM79";clr_screen();lcd_pos(1,0);for(j=0;j<16;j++){lcd_wdat(*(p+j));}}void tm85pro(void){uchar j;char *p="你选择的是TM85";clr_screen();lcd_pos(1,0);for(j=0;j<16;j++){lcd_wdat(*(p+j));}}uchar menuidcheck(uint id){uchar i;for(i=0;i<MENUNO-1;i++){if(id==menuid[i]) return 1;}return 0;}MENU *getmenu(uint id){uchar i;for(i=0;i<MENUNO-1;i++){if(id==menuid[i]) return &menus[i];}return NULL;}//当前只定义ESC键各个地址void menuinit(void){for(i=0;i<MENUNO-1;i++){//menus[i].enter=getmenu(menus[i].ID*10+menus[i].cur+1); //获取下个子项菜单地址 如果没有//没有下层菜单 则为空if(menus[i].ID/10==0)menus[i].esc=&menus[0];elsemenus[i].esc=getmenu(menus[i].ID/10);}}//显示当前菜单的内容void display(void){uchar i,j,num,curr,start;char *name;num=pmenu->total;curr=pmenu->cur;lin=pmenu->line;if(num>4) num=4;start=curr-lin;clr_screen();for(i=0;i<num;i++){name=pmenu->name[start];lcd_pos(i+1,0);for(j=0;j<16;j++){if((*(name+j))==('\0')) break;lcd_wdat(*(name+j));}if(i==lin){for(j=0;j<16;j++){if((*(se+j))==('\0')) break;lcd_wdat(*(se+j));}}start++;}// changeb(lin);}uchar keyscan(void){uchar i;if((KEYPIN|0xe4)==0xff){keyflag=0;return 0;}delay1ms(100);if((KEYPIN|0xe4)==0xff) return 0;for(i=0;i<7;i++){if((KEYPIN&(1<<i))==0){if(i!=2)return (i+1);}}return 0;}void runpro(void){uint tempID;uchar i;tempID=(pmenu->ID)*10+(pmenu->cur)+1;for(i=0;i<PRONO;i++){if(tempID==menupro[i].ID){menupro[i].mp();}}}int main(void){pmenu=menus;keyflag=0;DDRB=0XFF;PORTB=0X00;DDRA=0XFF;PORTA=0X00;DDRD=0X00;PORTD=0XFF;menuinit();lcd_init();display();while(1){key=keyscan();if(key!=0){if(keyflag==0){keyflag=1;if(key==1) //UP{if((pmenu->cur)!=0){pmenu->cur-=1;if((pmenu->line)!=0)pmenu->line-=1;display();}}else if(key==2) //DOWN{if((pmenu->cur)!=((pmenu->total)-1)){pmenu->cur+=1;if((pmenu->line)!=3)pmenu->line+=1;display();}}else if(key==4) //ENTER{ptemp=getmenu((pmenu->ID)*10+(pmenu->cur)+1);if(ptemp!=NULL){pmenu=ptemp;display();}elserunpro();}else if(key==5) //ESC{pmenu->cur=0;pmenu->line=0;pmenu=pmenu->esc;display();}}}}}


算是一个很简单的程序了,由于TS-12864-3的反白存在很大问题绘图模式来实现会扰屏,放弃,用了‘<---'来标示。

ENTER时进入下级菜单,ESC时返回上级菜单,UP,DOWN选择菜单项

不知道大家有注意到 这样的方法的缺陷没有,其实有两个致命的缺陷

1.菜单项不能多余10个

2.深度不能过多

第一个问题 由于是放大10倍 所以 菜单项的数目就不能多于10个 否则菜单项的ID与 子菜单重复了

第二个问题 由于用16为整数时 就是65536 也就是5层深度,如果高于5层 就要用长整形 很明显不划算

所以此方法 仅仅是实现一个菜单的设计,同时仅适用于简单的菜单设计 如果还是有兴趣的朋友 可以一起探讨下用什么样的方法能处理的更好

呵呵 我也是在追索。

最后附图几张破手机拍的不够清晰 还是能看 O(∩_∩)O~








原创粉丝点击