MicroHTR (Part 8)

Part 1, 2, 3, 4, 5, 6, 7, 8

From the code, one will find the large MenuDriver() function, which is the heart of the menu driver code. Unless you exactly know what you are doing, leave this function unchanged or some harm to your nerves may occur while trying to debug it. It is a pretty compact code because we want it to be executed fast. Would you like to wait seconds between clicks and scrolls ?

On the other hand, some customization is required for the next functions.

/* This routine is executed when menu is activated */  
void DoWhenMenuStarted(void)

/* This routine is executed when menu is released */ 
void DoWhenMenuStopped(void) 

/* Display the actual parameter value; menuIndex relates to the menu table as defined above */
void DisplayParameterValue(uint8_t menuIndex, uint16_t value)

/* Get the parameter value before attempting to change it; menuIndex relates to the menu table as defined above */
uint16_t GetParameter(uint8_t menuIndex) 

/* Set the parameter value after changes; menuIndex relates to the menu table as defined above */
void SetParameter(uint8_t menuIndex, uint16_t value).

Let’s take each function and describe their content. The name of the first function speaks for itself !

/* This routine is executed when menu is activated */  
void DoWhenMenuStarted(void)
{
	_requestResetStatistics = NO; /* Reset variable */
	_lastKp = _Kp;
	_lastKi = _Ki;
	_lastKd = _Kd;
	_lastSetpoint = _setpoint;
}

In this particular application, we collect the actual value of the parameters which may be changed during the menu navigation process. Then, the next possible event is:

/* menuIndex relates to the menu table as defined above */
uint16_t GetParameter(uint8_t menuIndex) 
{
	uint16_t value = 0;
	switch (menuIndex) {
	case 5: value = _setpoint;	break;
	case 6: value = _Kp; break;
	case 7: value = _Ki; break;
	case 8: value = _Kd; break;
	case 9: value = _intervals; break;
	case 11: value = (_minTemp * 10); break;
	case 12: value = (_maxTemp * 10); break;
	case 13: value = _requestResetStatistics; break;
	}
	return(value);
}

This function returns the actual value recorded in the menu table (see previous post). Note that only the menu type MNU_TYP_MOD_VALUE are read, thus the non consecutive case values. Note also that the menu driver only accepts signed integers, so that some formatting is required (e.g. temperature are expressed in tenth of degrees). Next step consists in displaying  this value using the PlainLCD functions:

/* menuIndex relates to the menu table as defined above */
void DisplayParameterValue(uint8_t menuIndex, uint16_t value)
{
	switch (menuIndex) {
	case 5: LCD.PrintFloat(float(value / 10.0), 1, 2); break;	
	case 6: LCD.PrintFloat(float(value / 100.0), 2, 2); break;	
	case 7: LCD.PrintFloat(float(value / 1000.0), 3, 2); break;	
	case 8: LCD.PrintFloat(float(value / 10.0), 1, 2); break;	
	case 9: LCD.PrintFloat(float(value / 10.0), 1, 2); break;	
	case 11: LCD.PrintFloat(float(value / 10.0), 1, 2); break;
	case 12: LCD.PrintFloat(float(value / 10.0), 1, 2); break;
	case 13: LCD.PrintString(vYesNo[value], 2); break;
	}	
}

This function is no more than a formatting function for the value of the current menuIndex. As the value of the parameter may change we want to keep the user updated with its current value, don’t we? Chronologically speaking, next function to be executed sets the value for the chosen parameter:

/* menuIndex relates to the menu table as defined above */
void SetParameter(uint8_t menuIndex, uint16_t value) 
{
	switch (menuIndex) {
	case 5:	_setpoint = value; break;	
	case 6: _Kp = value; break;				
	case 7: _Ki = value; break;				
	case 8: _Kd = value; break;				
	case 9: _intervals = value; break;				
	case 13: _requestResetStatistics = value; break;				
	}
}

Ultimately, the last step before leaving the menu consists in executing this last function:

/* This routine is executed when menu is released */ 
void DoWhenMenuStopped(void) 
{
	SaveParamters();
	if ((_lastKp != _Kp) || (_lastKi != _Ki) || (_lastKd != _Kd)) {
		PID.SetCoefficients((_Kp / 100.0), (_Ki / 1000.0), (_Kd / 10.0), _smoothingFactor);
	}
	if (_lastSetpoint != _setpoint) {
		PID.SetPoint(_setpoint / 10.0);
	}
	if (_requestResetStatistics) {
		ResetStatistics();
	}
	/* "Reset" display */
	LCD.PrintString(CAP_FIRMWARE, 1);
	LCD.PrintString("                ", 2);
}

In this particular application, we compare the current values with the ones which have been recorded while starting the navigation through the menu table (see the DoWhenMenuStarted() function). If these values have changed, various actions may be taken. Now that we completed the menu navigation, we have plenty of time to execute them. Ultimately, we may want to resume a default message to the display.

And this is it. From my own experience of this code, care should be taken while building the menu structure table, keeping in mind that we always count in base 0. Most flaws come then from mismatches between the menu indexes and the switches from the complementary functions explained in this post.

Want to give MicroHTR a try, pay a visit to the Code request page.

Good luck and enjoy !

Leave a Reply

You must be logged in to post a comment.