交互界面设计(草稿)

方案一:简单按键扫描

  硬件:独立按键,液晶;

  软件架构:

全局变量;
外设(如DA)输出初始化;
液晶初始化显示;
while(1)
{
按键扫描();
}

  液晶需要显示的内容数值和外设的数值放在全局变量里面。在按键扫描程序中检测独立按键是否拉低,若拉低进行去抖动延时再检测,根据相应的按键值改变全局变量并更新液晶显示和外设输出。

方案二:菜单

LCD12864_Menu.c代码如下。提示:代码中包含扫描式矩阵按键头文件和LCD12864显示头文件。本想将数据和函数分离开,写成.c加.h形式,但因此代码数据和函数混在一起,故写在一个.c文件中。

基本概念:1、菜单分层次。主菜单是第1层,为最顶层。子菜单若无子节点,则为最底层菜单。主菜单无父节点。

       2、每一层次菜单菜单项称作数据节点。下列代码中每个数据节点包含信息有:当前层菜单节点总数、节点标题,节点函数,子节点(下一层菜单指针),父节点(上一层菜单指针)。

     3、程序运行中,菜单更新函数依照按键值执行相应功能。若节点函数存在,则执行函数,等待按键返回菜单显示界面;若节点函数不存在则更新菜单显示。

//=================================版本信息==================================//
//Ver:2011082601
//Author:XZQ
//===========================================================================//
//=================================头文件=============================//
#include "msp430f5438.h"
#include "MCU_Init.h"
#include "LCD12864_Driver.h"
#include "ArrayKey_Driver.h"

#define Null 0
/********************** 
* 菜单结构体定义 * 
**********************/ 
struct MenuItem
{ 
	unsigned char MenuCount;  //当前层节点数
	unsigned char *DisplayString; //节点标题
	void (*Subs)();  //节点函数
	struct MenuItem *ChildrenMenus; //子节点
	struct MenuItem *ParentMenus; //父节点
}; 
//=================================菜单变量定义=============================//
/*********************** 
* 全局变量声明区 * 
***********************/ 
unsigned char DisplayStart = 0; //显示时的第一个菜单项
unsigned char UserChoose = 0;  //用户所选菜单项
unsigned char DisplayPoint = 0;//显示指针
unsigned MaxItems;  //同层所有节点数
unsigned char ShowCount=4; //单屏显示最多节点数
unsigned char Menu_key=0;//菜单函数中存放按键值变量
void DispVoid(void)
{
  DispOneChar(0,0,0x30);
}
void NullSubs(void) //空操作函数
{ 
}
//菜单变量声明
struct MenuItem Vol_Menu[3];
struct MenuItem FFT_Menu[3];
struct MenuItem Fre_Set_Menu[3];
struct MenuItem Fre_Test_Menu[4];
struct MenuItem MainMenu[6];
struct MenuItem (*MenuPoint) = MainMenu; //结构体指针,初始化时指向主菜单
//********************第2层菜单变量******************************//
struct MenuItem FFT_Menu[3]=
{ //MenuCount  DisplayString  Subs  ChildrenMenus ParentMenus
{3,  "  【频谱显示】" , NullSubs,  Null,  MainMenu},
{3,  "1.频率测量    ",  DispVoid,  Null,  MainMenu},
{3,  "2.返回",  NullSubs,  MainMenu,  MainMenu}, 
};

struct MenuItem Vol_Menu[3]=
{ //MenuCount  DisplayString  Subs  ChildrenMenus ParentMenus
{3,  "  【幅值测量】 " , NullSubs,  Null,  MainMenu},
{3,  "1.频率测量    ",  NullSubs,  Null,  MainMenu},
 {3, "2.返回",  NullSubs,  MainMenu,  MainMenu},
};

struct MenuItem Fre_Set_Menu[3]=
{ //MenuCount  DisplayString  Subs  ChildrenMenus ParentMenus
{3,  "  【频率设置】 " , NullSubs,  Null,  MainMenu},
{3,  "1.频率设置    ", Clear_GDRAM ,  Null,  MainMenu},
{3,  "2.Back",  NullSubs,  MainMenu,  MainMenu}, 
};

struct MenuItem Fre_Test_Menu[4]=
{ //MenuCount  DisplayString  Subs  ChildrenMenus ParentMenus
{4,  "  【测频、测相】" , NullSubs,  Null,  MainMenu},
{4,  "1.频率测量    ",  NullSubs,  Null,  MainMenu},
{4,  "2.相位测量    ",  NullSubs,  Null,  MainMenu},
{4,  "3.返回",  NullSubs,  MainMenu,  MainMenu},	 
};
//********************第1层菜单变量:主菜单******************************//
struct MenuItem MainMenu[6]=
{//MenuCount DisplayString Subs     ChildrenMenus ParentMenus
{6,  "  【主菜单】   " , NullSubs,  Null,         Null},
{6,  "1.测频、测相  "  , NullSubs,  Fre_Test_Menu,Null},
{6,  "2.频率设置"      , NullSubs,  Fre_Set_Menu, Null},
{6,  "3.幅值测量"      , NullSubs,  Vol_Menu,     Null},
{6,  "4.频谱显示"      , NullSubs,  FFT_Menu,     Null},
{6,  "5.返回"          , NullSubs,  MainMenu,     MainMenu},
}; 
//=================================菜单函数定义=============================//
//菜单界面初始化显示
void ShowMenu(void) 
{
	unsigned char n;
	MaxItems = MenuPoint[0].MenuCount;//得到主层菜单节点个数
	DisplayPoint = DisplayStart;//指向该层菜单第一个节点
	for(n=0;(DisplayPoint<MaxItems)&&(n<ShowCount);n++) 
	{	 	 			   
		DispStr(0,n,MenuPoint[DisplayPoint++].DisplayString);
	}	
}
//菜单界面显示更新
void Menu_Change(uchar KeyValue)
{
    switch(KeyValue) //根据按键值选择相应操作
    {  
		case UP: 
				UserChoose --; 
				if (UserChoose ==255)
				{ 
					UserChoose = 0;//上翻截至,如果要回滚赋值MaxItems-1
				} 
				break; 
                case Down: 
				UserChoose ++; 
				if (UserChoose == MaxItems ) 
				{ 
					UserChoose = MaxItems-2;//下翻截至,如要回滚赋值为0 
				} 
				break; 
		case Esc: 
				if (MenuPoint[UserChoose].ParentMenus != Null) 
				{ 
					MenuPoint = MenuPoint[UserChoose].ParentMenus; 
					UserChoose = 0; 
					DisplayStart = 0; 
				} 
				break; 
		case Enter: 
				if (MenuPoint[UserChoose].Subs != NullSubs) //如果函数不为空,说明是底层菜单,执行函数
				{ 
					Clear_DDRAM(); 
	  	                        (*MenuPoint[UserChoose].Subs)(); 
                                        Menu_key=KeyDefault;//改变Menu_key,确保一次按键只执行一次代码
					while(Menu_key!=Esc)
                                          Menu_key=KeyScan();
				} 
				else if (MenuPoint[UserChoose].ChildrenMenus != Null)//函数为空,子层不为空,不是底层菜单,设置下一菜单显示数据 
				{ 
					MenuPoint = MenuPoint[UserChoose].ChildrenMenus; 
					UserChoose = 0; 
					DisplayStart = 0; 
				} 
				break; 
		
		default:break;
	}
		//KEY_FLAG = 0;
	 	Clear_DDRAM(); 
	  	//delay_ms(10);  //液晶为慢速器件
		
		
		if ((UserChoose%ShowCount==0) && (KeyValue == Down))  //一屏只能显示ShowCount行
		{	
			DisplayStart = UserChoose;	  // UserChoose = 4; 
		}
		if (((UserChoose)%(ShowCount-1)==0) && (KeyValue == UP))  //一屏只能显示ShowCount行
		{	
			DisplayStart = 0;
		}
 
		ShowMenu();//显示更新后的菜单
		if(UserChoose == 0)
			UserChoose = 1 ;
		//if(UserChoose != 0)
			DispStr(14,UserChoose%ShowCount,"←");	
} 
原文地址:https://www.cnblogs.com/yuesheng/p/2147160.html