i typically use an array for parameters and use named indexes to refer to them
int settings [5][3];
#define minval 0
#define currentval 1
#define maxval 2
#define nothing 0
#define frequency 1
#define dutycycle 2
#define level 3
int parameter;
void rotaryhandler_up (current_parameter)
{
if (settings(currentparameter,currentval) < settings{currentparameter,maxval)) settings(currentparameter,currentval) = settings(currentparameter,currentval) +1;
event = evnt_rotary_up;
}
void rotaryhandler_down (current_parameter)
{
if (settings(currentparameter,currentval) < settings{currentparameter,maxval)) settings(currentparameter,currentval) = settings(currentparameter,currentval) -1;
event = evnt_rotary_down;
}
void rotary_handler_click (void)
{
current_parameter = 0;
event = evnt_rotary_click;
}
void eventhandler(event)
{
switch (event){
event_rotary_up:
event_rotary_down:
switch(parameter) {
frequency :
lcdprint (0,0,'Frequency = %i',settings(parameter,currentval);
break;
dutycycle :
lcdprint (0,0,'Dutycycle = %i',settings(parameter,currentval);
break;
level :
lcdprint (0,0,'Level = %i',settings(parameter,currentval);
break;
}
break;
event_rotary_click:
default:
}
event = 0;
}
something along those lines.
basically create an array that stores your settings. each ' setting has a minimum , maximum and current_value
the menuhandler sets an integer that determines which of the array entries is being manipulated. : current_parameter
the rotary encoder handler has 3 hardware events : up , down and click. it uses 'current_parameters to index the array and determines the new value of 'current_value' based on which direction and the minimum and maximum.
the 'click event' sets the index to zero. you can turn all you want : nothing increments or decrements. the zero index is a dummy.
There is a software event handler that is responsible for postprocessing. That one updates the display , sends the data into registers or peripherals and whatnot. The hardware handlers set a software_event so it can be post-processed.
upon post-processing the software_event is set to zero.
you can have multiple hardware rotary encoders. lets say you have an encoder for mulitple functions , and one dedicate to the output level.
the hardware handler for output level would simply 'force' the current_parameter to 'level' prior to changing the values. upon calling the softwareeventhandler , the correct parameter will be displayed as the current_parameter has changed.
the software eventhandler is not limited to rotary encoders. i can have pushbutton_events in there or other events
event output_overload : display ' overload '
event numberkey
number_key_0
number_key_1
number_key_2
....
numerical = numerical * 10 + numberkey;
event backspace
numerical = numerical \10
event enter
if numerical > settings ( current_parameter,minval) and numerical < settings ( current_parameter,manval) settings(current_parameter,current_value) = numerical;
I split things between hardware interrupts ( encoders, buttons , scanned events ). those hardware interrupts do minimal processing and critical processing and then fire a software event that deal with the rest.
critical events would be an overload : the hardware handler would switch off output , then fire the software event to notify the user.
scanned events are events triggered by a hardware timer. for example a loop that reads data over i2c or spi or io pins on a periodical sweep. those are for critical scans only.
i have a general purpose system_tick as well. that one can fire software scanned events.