CAFace Micro User Interface Management Module

Introduction:

When single-chip computer develops a simple human-machine interface, if the program is not well organized, it can easily lead to bloated code, difficult to read, or even change the error situation of the side running. CAFace is the organization specification of such an interface program, or the user interface management software module. It takes up less space and is ideal for simple user interface on 8-bit or low-end 32-bit computers. It enables programmers to concentrate on the implementation of functions without spending more time on the structure of the program, and makes it easier to add or subtract product functions in the future and easier to maintain.

CAFace version and description:

CAFace V0.8 reduced version
It is simple in structure and flexible in use. It is suitable for small applications, such as digital tube or segment LCD user interface, and SCM with less resources.

CAFace V1.0 Classic Edition
For smaller applications, for more cumbersome interfaces, relatively rich resources system applications (such as MEGA128, ARM7, CORTEX-M3, etc.).

CAFace V1.3 Enhanced Edition
For relatively complex user interface implementations, such as occupied LCD screen, color industrial serial screen, etc., for OS-based applications (such as STM32+FreeRTOS), and for messaging applications.

Application examples

wnd.h

//wnd.h
#ifndef WND_H
#define WND_H

//Window Structure
typedef struct tag_WND
{
 struct tag_WND * pParentWnd; //Upper window
 uint8_t *Buf; //Window Private Global Space

 void (*Load)(struct tag_WND *pWnd); //Load event handler
 void (*UnLoad)(struct tag_WND *pWnd); //Destroy event handler
 void (*KeyEvent) (struct tag_WND *pWnd,uint8_t key); //Key Processing Function
 void (*TimerEvent)(struct tag_WND *pWnd,uint8_t flag);//Clock Processing Function
}WND,*PWND;

//Application program interface
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

//Total buffer size allocated for windows when CreateWnd is called in the program
#define MAX_WND_BUF_SIZE 20

static PWND g_pCurrentWnd=0; //current window
static uint8_t g_WndBuffer[MAX_WND_BUF_SIZE];//Buffers allocated to windows
static uint8_t *g_pWndBuf=g_WndBuffer;//Buffer allocation current position

//Initialize window functions, parameters: window object pointer, key processing function, parent window pointer, allocate buffer size to window
//This function must be called for a window
void CreateWnd(PWND pWnd, \
void (*kf)(PWND ,uint8_t) , \
PWND parWnd, \
uint8_t buf_size)
{
 uint8_t i;

 pWnd->KeyEvent=kf; //Set key handling functions
 pWnd->pParentWnd=(struct tag_WND *)parWnd; //Set Parent Window
 pWnd->Load=0;
 pWnd->UnLoad=0;
 pWnd->TimerEvent=0;

 //Allocate window buffers
 pWnd->Buf=g_pWndBuf;
 g_pWndBuf+=buf_size;
 //Window Buffer Zeroing
 for(i=0;i<buf_size;i++)
  pWnd->Buf[i]=0;
}

//Set the window callback function to set Load called on load, UnLoad called on destroy, and window timer trigger event function, respectively
//If there is no corresponding function, specify 0, which is optional
void SetCallBackWnd(PWND pWnd,\
void (*Load)(PWND),\
void (*UnLoad)(PWND),\
void (*TimerEvent)(PWND,uint8_t))
{
 pWnd->Load=Load;
 pWnd->UnLoad=UnLoad;
 pWnd->TimerEvent=TimerEvent;
}

//Set the current display window
void SetCurrentWnd(PWND pWnd)
{
 //Called if the current window has a destroy function
 if(g_pCurrentWnd)
 {
  if(g_pCurrentWnd->UnLoad != 0)
   g_pCurrentWnd->UnLoad(g_pCurrentWnd);
 }
 g_pCurrentWnd = pWnd;
 if(pWnd->Load != 0)
  pWnd->Load(g_pCurrentWnd);
}

//Exit the current display window and will not work without a parent window
void ExitCurrentWnd(void)
{
 //Execute if the parent window of the current window is valid
 if(g_pCurrentWnd->pParentWnd == 0)
  return ;

 //Set parent window as current window
 SetCurrentWnd(g_pCurrentWnd->pParentWnd);
}

//Key event handler, which is called when the main program finds a key
void CurrentKeyEvent(uint8_t key)
{
 if(g_pCurrentWnd->KeyEvent != 0)
  g_pCurrentWnd->KeyEvent(g_pCurrentWnd,key);
}

//Timed event handler, the main program needs to call this function periodically
void CurrentTimerEvent(void)
{
 static uint8_t flag=0;

 flag=!flag;

 if(g_pCurrentWnd->TimerEvent != 0)
  g_pCurrentWnd->TimerEvent(g_pCurrentWnd,flag);
}

Using this framework, a setup menu program is written, which contains six adjustable numeric options and uses five keys to edit each option. The procedure is as follows:

/********************************
	CAFace Implemented 1602 Menu Demonstrator
	Filename: display.c
	Compile: WinAVR-20070525 or VC++6.0
	
	Function: This program implements a menu system on LCM1602
	It responds to five keys: add, subtract, switch, confirm and cancel.
	Six parameters can be set or adjusted.
	Operation method:
	1.Enter the Home Interface Welcome to www.chipart after power-on. Cn
	Press the Confirm key to enter the menu selection interface at this time
	2.In the menu selection interface, you can press the "plus", "minus" key to select menu items
	After selecting a menu item, press the Confirm key to enter the current item and adjust its value.
	3.Press "minus" and "key" to adjust parameters, then press "confirm" to save to EEPROM
	Then exit to the upper interface, if you press Cancel, you will not save the exit to the upper interface.
	4.The third item in the menu is the adjustment of clock format data, and the adjustment of hour and minute values uses the Switch key.
	To switch to each other.
*******************************/

WND g_MainWnd;//Main Interface Window Object
WND g_MenuWnd;//Menu Window Object
WND g_OptionWnd[6];//Menu Options Window Object

uint8_t eep_Par[7] EEMEM={10,20,12,40,40,50,60}; //EEPROM data, storage parameters

//General Numeric Adjustment Key Processing Function
//Key:key buf:numeric address to edit max:maximum min:minimum
void  GeneralEditVal(uint8_t key,uint8_t *buf,uint8_t max,uint8_t min)
{
	switch(key)
	{
		case KEY_INC:
			if((*buf) < max)
				(*buf)++;
			break;
		case KEY_DEC:
			if((*buf)>min)
				(*buf)--;
			break;
		case KEY_CANCEL:
			ExitCurrentWnd();		
			break;
		default:
			break;
	}

}
//Universal Clock Adjustment Function
void GeneralEditTime(uint8_t key,uint8_t *buf)
{
	uint8_t max;
	uint8_t *p;
	if(buf[2]==0)
	{
		max=23;
		p=buf;
	}
	else
	{
		max=59;
		p=buf+1;
	}
	switch(key)
	{
		case KEY_INC:
			if(*p<max)
				(*p)++;
			break;
		case KEY_DEC:
			if(*p>0)
				(*p)--;
			break;
		case KEY_TAB:
			if(buf[2]==0)
				buf[2]=1;
			else
				buf[2]=0;
			break;
		case KEY_CANCEL:
			ExitCurrentWnd();

			break;
		default :
			break;
	}
}


///Home Interface
void MainLoad(PWND pWnd)
{
	lcd_clear();
	lcd_display_string(3,0,"Welcome to");
	lcd_display_string(1,1,"www.chipart.cn");	
}
void MainKey(PWND pWnd,uint8_t key)
{
	if(key==KEY_OK)
		SetCurrentWnd(&g_MenuWnd);
}
///menu interface
void MenuLoad(PWND pWnd)
{
	lcd_clear();
	lcd_display_string(5,0,"Menu");
	lcd_display_number(9,0,pWnd->Buf[0]);
	lcd_display_string(0,1,"ok");
	lcd_display_string(10,1,"cancel");
}
void MenuKey(PWND pWnd,uint8_t key)
{
	if(key==KEY_CANCEL)
	{
		ExitCurrentWnd();
		return ;
	}
	else if (key==KEY_OK)
	{
		SetCurrentWnd(&g_OptionWnd[pWnd->Buf[0]]);
		return ;
	}
	else if(key== KEY_INC)
	{
		if(pWnd->Buf[0] < 5)
			++(pWnd->Buf[0]);
		lcd_display_number(9,0,pWnd->Buf[0]);
	}
	else if(key == KEY_DEC)
	{
		if(pWnd->Buf[0] >0)
			--(pWnd->Buf[0]);
		lcd_display_number(9,0,pWnd->Buf[0]);
	}
}
///Option 1 Edit a 5-15 data
void Option1Load(PWND pWnd)
{
	lcd_clear();
	lcd_display_string(0,0,"Parameter1:");

	pWnd->Buf[0]=eeprom_read_byte(eep_Par);
}
void Option1Key(PWND pWnd,uint8_t key)
{
	if(key==KEY_OK)
	{
		eeprom_write_byte(eep_Par,pWnd->Buf[0]);
		ExitCurrentWnd();	
	}
	else
		GeneralEditVal(key,pWnd->Buf,15,5);

}
void Option1Timer(PWND pWnd,uint8_t flag)
{
	if(flag)
		lcd_display_number(7,1,pWnd->Buf[0]);
	else
		lcd_display_string(7,1,"  ");
}
///Option 2 Edit a data range of 15-25
void Option2Load(PWND pWnd)
{
	lcd_clear();
	lcd_display_string(0,0,"Parameter2:");

	pWnd->Buf[0]=eeprom_read_byte(eep_Par+1);
}
void Option2Key(PWND pWnd,uint8_t key)
{
	if(key==KEY_OK)
	{
		eeprom_write_byte(eep_Par+1,pWnd->Buf[0]);
		ExitCurrentWnd();	
	}
	else
		GeneralEditVal(key,pWnd->Buf,25,15);

}
///Option 3 Edit a clock data
void Option3Load(PWND pWnd)
{
	lcd_clear();
	lcd_display_string(0,0,"Parameter3:");
	lcd_display_char(7,1,':');

	pWnd->Buf[0]=eeprom_read_byte(eep_Par+2); 
	pWnd->Buf[1]=eeprom_read_byte(eep_Par+3);
}
void Option3Key(PWND pWnd,uint8_t key)
{
	if(key==KEY_OK)
	{
		eeprom_write_byte(eep_Par+2,pWnd->Buf[0]);
		eeprom_write_byte(eep_Par+3,pWnd->Buf[1]);
		ExitCurrentWnd();	
	}
	else
		GeneralEditTime(key,pWnd->Buf);

}
void Option3Timer(PWND pWnd,uint8_t flag)
{
	if(flag)
	{
		lcd_display_number(5,1,pWnd->Buf[0]);
		lcd_display_number(8,1,pWnd->Buf[1]);
	}
	else
	{
		if(pWnd->Buf[2]==0)
		{
			lcd_display_string(5,1,"  ");
			lcd_display_number(8,1,pWnd->Buf[1]);
		}
		else
		{
			lcd_display_string(8,1,"  ");
			lcd_display_number(5,1,pWnd->Buf[0]);
		}
	}
}
///Option 4 Edit a 35-45 data set
void Option4Load(PWND pWnd)
{
	lcd_clear();
	lcd_display_string(0,0,"Parameter4:");

	pWnd->Buf[0]=eeprom_read_byte(eep_Par+4); 
}
void Option4Key(PWND pWnd,uint8_t key)
{
	if(key==KEY_OK)
	{
		eeprom_write_byte(eep_Par+4,pWnd->Buf[0]);  
		ExitCurrentWnd();	
	}
	else
		GeneralEditVal(key,pWnd->Buf,45,35);
}
///Option 5 Edit a 45-55 data set
void Option5Load(PWND pWnd)
{
	lcd_clear();
	lcd_display_string(0,0,"Parameter5:");

	pWnd->Buf[0]=eeprom_read_byte(eep_Par+5); 
}
void Option5Key(PWND pWnd,uint8_t key)
{
	if(key==KEY_OK)
	{
		eeprom_write_byte(eep_Par+5,pWnd->Buf[0]);  
		ExitCurrentWnd();	
	}
	else
		GeneralEditVal(key,pWnd->Buf,55,45);
}
///Option 6 Edit a data range of 55-65
void Option6Load(PWND pWnd)
{
	lcd_clear();
	lcd_display_string(0,0,"Parameter6:");

	pWnd->Buf[0]=eeprom_read_byte(eep_Par+6); 
}
void Option6Key(PWND pWnd,uint8_t key)
{
	if(key==KEY_OK)
	{
		eeprom_write_byte(eep_Par+6,pWnd->Buf[0]);  
		ExitCurrentWnd();	
	}
	else
	{
		GeneralEditVal(key,pWnd->Buf,65,55);
	}
}

//This is the only interface function out of this file. No other functions need to be called explicitly in the main program.
void DisplayInit(void)
{
	uint8_t i,x;
	
	//Parameter legalization process, initialize EEPROM if there is an illegal value in the parameter
	if(eeprom_read_byte(eep_Par)==0xff)
	{
		for(i=0;i<7;i++)
		{
			if(i==2)
				x=12;
			else
				x=(i+1)*10;
			eeprom_busy_wait();
			eeprom_write_byte(eep_Par + i,x);
		}
	}
	
	//Main window initialization
	CreateWnd(&g_MainWnd,MainKey,0,0);
	SetCallBackWnd(&g_MainWnd,MainLoad,0,0);
	
	//Menu Window
	CreateWnd(&g_MenuWnd,MenuKey,&g_MainWnd,1);
	SetCallBackWnd(&g_MenuWnd,MenuLoad,0,0);

	//First Options Window
	CreateWnd(&g_OptionWnd[0],Option1Key,&g_MenuWnd,1);
	SetCallBackWnd(&g_OptionWnd[0],Option1Load,0,Option1Timer);

	//Second Options Window
	CreateWnd(&g_OptionWnd[1],Option2Key,&g_MenuWnd,1);
	SetCallBackWnd(&g_OptionWnd[1],Option2Load,0,Option1Timer);

	//Third Options Window
	CreateWnd(&g_OptionWnd[2],Option3Key,&g_MenuWnd,3);
	SetCallBackWnd(&g_OptionWnd[2],Option3Load,0,Option3Timer);
	
	//Fourth Options Window
	CreateWnd(&g_OptionWnd[3],Option4Key,&g_MenuWnd,1);
	SetCallBackWnd(&g_OptionWnd[3],Option4Load,0,Option1Timer);
	
	//Fifth Options Window
	CreateWnd(&g_OptionWnd[4],Option5Key,&g_MenuWnd,1);
	SetCallBackWnd(&g_OptionWnd[4],Option5Load,0,Option1Timer);
	
	//Sixth Option Window
	CreateWnd(&g_OptionWnd[5],Option6Key,&g_MenuWnd,1);
	SetCallBackWnd(&g_OptionWnd[5],Option6Load,0,Option1Timer);
						
	SetCurrentWnd(&g_MainWnd);//Show Main Interface
}

Here are their results:

application area

1. Operation management of digital tube instruments
2. Operational management of segment LCD
3. Display system consisting of LCD1602
4. dot matrix LCD module display system

Available CAFace Home Page Download the source code.

Tags: Single-Chip Microcomputer GUI

Posted by ctsiow on Sat, 07 May 2022 19:40:30 +0300