在单片机项目中经常会设计一些与用户交互的程序,例如让用户通过液晶显示屏和几个按键来设置几项工作用参数.这样的程序如果组织不好会
导致浪费存储空间,添加/更改功能非常困难等问题.下面介绍一个小小的界面管理方案.希望这个程序能给您的设计带来一些启发,帮助您合理的完成设计任务.下面首先贴出界面的框架程序wnd.h和wnd.c
包含头文件wnd.h:
//wnd.h - http://www.chipart.cn
#ifndef WND_H
#define WND_H
//窗口结构
typedef struct tag_WND
{
struct tag_WND * pParentWnd; //上级窗口
uint8_t *Buf; //窗口专用全局空间
void (*Load)(struct tag_WND *pWnd); //装入事件处理函数
void (*UnLoad)(struct tag_WND *pWnd); //销毁事件处理函数
void (*KeyEvent) (struct tag_WND *pWnd,uint8_t key); //按键处理函数
void (*TimerEvent)(struct tag_WND *pWnd,uint8_t flag);//时钟处理函数
}WND,*PWND;
//接口函数
void CreateWnd(PWND pWnd,void (*kf)(PWND ,uint8_t) ,
PWND parWnd,
uint8_t buf_size);
void SetCallBackWnd(PWND pWnd,void (*Load)(PWND),void (*UnLoad)(PWND),void (*TimerEvent)(PWND,uint8_t));
void SetCurrentWnd(PWND pWnd);
void ExitCurrentWnd(void);
void CurrentKeyEvent(uint8_t key);
void CurrentTimerEvent(void);
#endif
程序文件:wnd.c
/********************************
一种简单的用户界面管理模块
文件名:wnd.c
编译:WinAVR-20070525 或 VC++6.0
芯艺设计室 2004-2007 版权所有
转载请保留本注释在内的全部内容
WEB: http://www.chipart.cn
Email: changfutong@sina.com
*******************************/
//在程序中调用CreateWnd时总共为窗口分配的缓冲区大小
#define MAX_WND_BUF_SIZE 20
static PWND g_pCurrentWnd=0; //当前窗口
static uint8_t g_WndBuffer[MAX_WND_BUF_SIZE];//分配给窗口用的缓冲区
static uint8_t *g_pWndBuf=g_WndBuffer;//缓冲分配当前位置
//初始化窗口函数,参数:窗口对象指针,按键处理函数,父窗口指针,为窗口分配缓冲区大小
//对于一个窗口此函数是必须被调用的
void CreateWnd(PWND pWnd, \
void (*kf)(PWND ,uint8_t) , \
PWND parWnd, \
uint8_t buf_size)
{
uint8_t i;
pWnd->KeyEvent=kf; //设置按键处理函数
pWnd->pParentWnd=(struct tag_WND *)parWnd; //设置父窗口
pWnd->Load=0;
pWnd->UnLoad=0;
pWnd->TimerEvent=0;
//分配窗口缓冲区
pWnd->Buf=g_pWndBuf;
g_pWndBuf+=buf_size;
//窗口缓冲区清零
for(i=0;i<buf_size;i++)
pWnd->Buf[i]=0;
}
//设置窗口回调函数 ,分别设置装入时调用的Load,销毁时调用的UnLoad和窗口定时触发事件函数
//如果没有相应的函数,则指定0,此函数是可选的
void SetCallBackWnd(PWND pWnd,\
void (*Load)(PWND),\
void (*UnLoad)(PWND),\
void (*TimerEvent)(PWND,uint8_t))
{
pWnd->Load=Load;
pWnd->UnLoad=UnLoad;
pWnd->TimerEvent=TimerEvent;
}
//设置当前显示窗口
void SetCurrentWnd(PWND pWnd)
{
//如果当前窗口有销毁函数就调用
if(g_pCurrentWnd)
{
if(g_pCurrentWnd->UnLoad != 0)
g_pCurrentWnd->UnLoad(g_pCurrentWnd);
}
g_pCurrentWnd = pWnd;
if(pWnd->Load != 0)
pWnd->Load(g_pCurrentWnd);
}
//退出当前显示窗口,如果没有父窗口就不起作用
void ExitCurrentWnd(void)
{
//如果当前窗口的父窗口有效才执行
if(g_pCurrentWnd->pParentWnd == 0)
return ;
//将父窗口设置为当前窗口
SetCurrentWnd(g_pCurrentWnd->pParentWnd);
}
//按键事件处理函数,主程序发现有按键时需调用此函数
void CurrentKeyEvent(uint8_t key)
{
if(g_pCurrentWnd->KeyEvent != 0)
g_pCurrentWnd->KeyEvent(g_pCurrentWnd,key);
}
//定时事件处理函数,主程序需要按一定的周期调用这个函数
void CurrentTimerEvent(void)
{
static uint8_t flag=0;
flag=!flag;
if(g_pCurrentWnd->TimerEvent != 0)
g_pCurrentWnd->TimerEvent(g_pCurrentWnd,flag);
}
我利用这个框架写了一个设置菜单程序,这个菜单程序包含6个可调数值的选项,它用5个按键实现对各选项的编辑。这个菜单程序是display.c和display.h,这里不贴源程序了,可从
下面的下载处找到它们。
我在三个不同的环境下实现了对这个菜单程序的调用,分别是:
1.VC++6.0
2.WinAVR + CA-M8X
3.WinAVR + AvrX + CA-M8X
下面是它们的运行结果:
|
界面程序在VC6.0环境下的模拟图 |
 |
|
在CA-M8X上的测试图 |
 |
界面模块及演示程序下载
Copyright http://www.chipart.cn
|