User Interface (Part 5)

Part 1234, 5

I brought several improvements since the introduction of the early design of a simplified however yet powerful human interface. Among them the possibility to display variables that the user can change and variables or constants that the user cannot change. Thus the introduction of a new set of menu types:

/* Menu types */
const uint8_t MNU_TYP_HEADER = 0x00;
const uint8_t MNU_TYP_MOD_VALUE = 0x01;
const uint8_t MNU_TYP_FXD_VALUE = 0x02;
const uint8_t MNU_TYP_FLD_BACK = 0x03;

These new data types are the MNU_TYP_MOD_VALUE type  and the MNU_TYP_FXD_VALUE type.

The way the menuItem structure has been changed too in order to ease the readability of the whole menu structure. The new structure format looks like:

struct mnuItem { 
	uint8_t menuType; /* One of MNU_TYP_x */
	int16_t minValue; /* min value */
	int16_t maxValue; /* max value */
	uint8_t nextMenuIndex; /* Next menu item */
	uint8_t lastMenuIndex; /* Must be set to 0 as default */
	const char *ptrCap;  /* Pointer to menu ptrCap */
}; 

where:

/* 
menuType: 	one of MNU_TYP_xxx,
minValue: 	min value (Base0), 
maxValue: 	max value (Base0),
nextMenuIndex: 	next sub menu index (Base0),
lastMenuIndex:	last menu index, for returning to previous level (Base0),
ptrCap: 	pointer to caption 
*/

But the most significant change applies to the storage of arrays of characters (so as to say, strings). These memory consuming data are stored in the program memory instead of a storage in the SRAM. As their content keeps constant along the firmware usage, they are eligible to program memory storage. For your records, the SRAM memory is 2k wide in the UNO boards (featuring ATMEGA 328P micro-controllers) while the program memory is 32k wide, which is x16 times larger !

Storing and reading constant data in the program memory requires that the following steps are completed:

Declare pgmspace in the header section of the main code

#include <avr/pgmspace.h> /* Progmem */

Declare the arrays of characters in the header section: these are extracted from the unreleased MicroHTR application (heating element controller)

const char CAP_P_FIRMWARE[] PROGMEM =		"**  MicroHTR  **";
const char CAP_P_VERSION[] PROGMEM =		"    rev. 1a";
/* Application related constants */
const char CAP_P_SP[] PROGMEM = 		"SET POINT";
const char CAP_P_KP[] PROGMEM = 		"KP";
const char CAP_P_KI[] PROGMEM = 		"KI";
const char CAP_P_KD[] PROGMEM = 		"KD";
const char CAP_P_INT[] PROGMEM = 		"INTERVALS";
const char CAP_P_STATISTICS[] PROGMEM = 	"STATISTICS";
const char CAP_P_MISCELLANEOUS[] PROGMEM =	"MISCELLANEOUS";
const char CAP_P_TEMPERATURE[] PROGMEM = 	"TEMPERATURE";
const char CAP_P_MAX_TEMP[] PROGMEM = 		"TEMP. MAX.";
const char CAP_P_MIN_TEMP[] PROGMEM = 		"TEMP. MIN.";
const char CAP_P_RESET[] PROGMEM = 		"RESET";
const char CAP_P_SETTINGS[] PROGMEM = 		"SETTINGS";
const char CAP_P_PRN_DATA[] PROGMEM = 		"PRINT DATA";
/* Captions, reserved words for menu driven interface (do not change) */
const char CAP_P_PARAM[] PROGMEM = 		"PARAMETERS";
const char CAP_P_EXIT[] PROGMEM = 		"EXIT";
const char CAP_P_RETURN[] PROGMEM = 		"RETURN";

 

and here is the structure for the menu:

struct mnuItem vMnuItems[] =	
{ 
/* 	{type, 				min, 		max,		next,	last, 	caption}*/
	{MNU_TYP_HEADER,	X, 			X, 			X,		X,		CAP_P_FIRMWARE}, 				
	{MNU_TYP_HEADER,	0, 			3, 			2, 		X,		CAP_P_PARAM},
	{MNU_TYP_HEADER,	0, 			5, 			6, 		X, 		CAP_P_SETTINGS}, /* Main menu */
	{MNU_TYP_HEADER,	0, 			3, 			12,		X, 		CAP_P_STATISTICS},
	{MNU_TYP_HEADER,	0, 			1, 			16,		X, 		CAP_P_MISCELLANEOUS},
	{MNU_TYP_FLD_BACK, 	X, 			X, 			0,		X, 		CAP_P_EXIT},
	{MNU_TYP_MOD_VALUE,	MIN_SP,		MAX_SP,		2,		X, 		CAP_P_SP}, /* Settings */
	{MNU_TYP_MOD_VALUE,	MIN_KP,		MAX_KP,		2,		X, 		CAP_P_KP}, 
	{MNU_TYP_MOD_VALUE,	MIN_KI,		MAX_KI,		2,		X, 		CAP_P_KI}, 
	{MNU_TYP_MOD_VALUE,	MIN_KD,		MAX_KD,		2,		X, 		CAP_P_KD}, 
	{MNU_TYP_MOD_VALUE,	MIN_INT, 	MAX_INT,	2, 		X, 		CAP_P_INT}, 
	{MNU_TYP_FLD_BACK,	X, 			X, 			1, 		X, 		CAP_P_RETURN},
	{MNU_TYP_FXD_VALUE, MAX_TEMP, 	MIN_TEMP, 	3,		X, 		CAP_P_MIN_TEMP}, /* Statistics */
	{MNU_TYP_FXD_VALUE, MAX_TEMP, 	MIN_TEMP, 	3, 		X, 		CAP_P_MAX_TEMP},
	{MNU_TYP_MOD_VALUE, NO, 		YES, 		3,		X, 		CAP_P_RESET},
	{MNU_TYP_FLD_BACK,	X, 			X, 			1, 		X, 		CAP_P_RETURN},	
	{MNU_TYP_MOD_VALUE, NO, 		YES,		4,		X, 		CAP_P_PRN_DATA}, /* Miscellaneous */	
	{MNU_TYP_FLD_BACK,	X, 			X, 			1, 		X, 		CAP_P_RETURN}	
};

Within the menu handler routine, the lines

LCD.PrintArrayOfChar(vMnuItems[menuIndex].ptrCap, 1); /* Display menu ptrCap on first line */

LCD.PrintArrayOfChar(vMnuItems[vMnuItems[menuIndex].nextMenuIndex + counts].ptrCap, 2); /* Display menu caption */

become

LCD.PrintArrayOfChar(P(vMnuItems[menuIndex].ptrCap), 1); /* Display menu ptrCap on first line */

LCD.PrintArrayOfChar(P(vMnuItems[vMnuItems[menuIndex].nextMenuIndex + counts].ptrCap), 2); /* Display menu caption */

thanks to this little function:

char* P(const char* ptr) 
{	
	strcpy_P(vCapBuffer, ptr);
	return(vCapBuffer);
}

In this way, you will be able to save hundreds of bytes from the SRAM which is good news to the Arduino’s developers.

Leave a Reply

You must be logged in to post a comment.