Hi, brunialti. With reference to your request in post #302 here is an example of addUsrNav. You are free to use this if you find it beneficial.
MENWIZ is controlled via addUsrNav call to function navMenu. This function check the value of "virtualButton". Values of virtualButton is set in one of two ISR functions. The reason to use ISR is that both pid calculation and temperature sensor communication is time consuming, and I was worried that button presses would be missed.
One ISR is handling the rotary encoder (up/down) and the other ISR two push buttons (confirm/escape).
Please ask if anything is unclear.
(only fragment of code is pasted due to 9500 char limit... Se full .ino below.)
ISR(PCINT0_vect) // handle pin change interrupt for PCINT0 to PCINT7 here, pin D53-D50 and D10-D13
{
static uint8_t btn = _BV(PB5) | _BV(PB6);
uint8_t t = PINB; // read port status
// check if buttons are pushed
t &= _BV(PB6) | _BV(PB5); // D11 D12
if (t != btn) { // activity on pins, we're only interested in high to low transitions
if((long)(micros() - last_micros) >= debouncing_time * 1000) {
push[0] |= !(t & _BV(PB5));
push[1] |= !(t & _BV(PB6));
btn = t;
last_micros = micros(); // start/restart bounce guard timer (covers make and break)
}
}
}
ISR(PCINT2_vect) // handle pin change interrupt for PCINT 16 to PCINT23 here, pin D62-D69/A8-A15
{
static uint8_t AB = 0x03; //lookup table index
static long encval = 0; //encoder value
static const int8_t enc_states[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
uint8_t t = PINK; // read port status
// check for rotary2 state change on pin D5 D6
AB <<= 2; // save previous state
AB |= (t >> 5) & 0x03; // add current state
encval += enc_states[AB & 0x0f];
if( encval > 1 ) { // step forward
virtualButton = 2; encval = 0;
}
else if( encval < -1 ) { // step backwards
virtualButton = 1; encval = 0;
}
}
int navMenu() // called from menu.draw
{
switch (virtualButton)
{
case 5: // Escape
virtualButton = 0;
return MW_BTE;
break;
case 6: // Confirm
virtualButton = 0;
return MW_BTC;
break;
case 1: // Up
virtualButton = 0;
return MW_BTU;
break;
case 2: // Down
virtualButton = 0;
return MW_BTD;
break;
case 0: // no button
return MW_BTNULL;
break;
}
}
void setup() {
Serial.begin(9600);
_menu *r,*s1,*s2;
menu.begin(&lcd,20,4);
menu.addUsrNav(navMenu,4);
r=menu.addMenu(MW_ROOT,NULL,F("BC Main menu"));
s1=menu.addMenu(MW_VAR,r, F("Set BC On/Off"));
s1->addVar(MW_BOOLEAN,&running);
s1=menu.addMenu(MW_VAR,r, F("Set pump On/Off"));
s1->addVar(MW_BOOLEAN,&mashPump);
s1=menu.addMenu(MW_SUBMENU,r, F("Select state"));
s2=menu.addMenu(MW_VAR,s1, F("Prep1"));
s2->addVar(MW_ACTION,selStatePrep1);
s2=menu.addMenu(MW_VAR,s1, F("Prep2"));
s2->addVar(MW_ACTION,selStatePrep2);
s2=menu.addMenu(MW_VAR,s1, F("Mash"));
s2->addVar(MW_ACTION,selStateMash);
s2=menu.addMenu(MW_VAR,s1, F("Boil"));
s2->addVar(MW_ACTION,selStateBoil);
s2=menu.addMenu(MW_VAR,s1, F("Cool"));
s2->addVar(MW_ACTION,selStateCool);
s1=menu.addMenu(MW_SUBMENU,r, F("Change T SetP"));
s2=menu.addMenu(MW_VAR,s1, F("HLT SetP"));
s2->addVar(MW_AUTO_INT,&selectHltSetp,25,98,1);
s2=menu.addMenu(MW_VAR,s1, F("Boil SetP"));
s2->addVar(MW_AUTO_INT,&selectBoilSetp,25,102,1);
s2=menu.addMenu(MW_VAR,s1,F("back"));
s2->addVar(MW_ACTION,escapeFunct);
s2->setBehaviour(MW_ACTION_CONFIRM,false); // MW_ACTION_IMMEDIATE described in MENWIZ_0-6-0_QUICK TOUR.pdf
s1=menu.addMenu(MW_VAR,r, F("View details"));
s1->addVar(MW_LIST,&selectView);
s1->addItem(MW_LIST, F("(no detail)"));
s1->addItem(MW_LIST, F("HLT"));
s1->addItem(MW_LIST, F("Boiler"));
menu.addUsrScreen(lcdUpdate,3000); // Default screen function shown after msecs since last button push
}
//==========================================================================================
// Arduino Loop
//==========================================================================================
void loop() {
menu.draw(); // NAVIGATION MANAGEMENT & DRAWING ON LCD. NOT BLOCKING has to be the first in the void loop
if (running) {
hltPID.SetMode(AUTOMATIC); //turn the PID on
boilPID.SetMode(AUTOMATIC); //turn the PID on
} else {
hltPID.SetMode(MANUAL); //turn the PID off
boilPID.SetMode(MANUAL); //turn the PID off
Timer3.setPwmDuty(pin_PWM_a, 0); // set the pwm with the output of the pid output to control the SSR:
Timer3.setPwmDuty(pin_PWM_b, 0); // set the pwm with the output of the pid output to control the SSR:
}
if ( hltSet != selectHltSetp ) { hltSet = selectHltSetp; }
if ( boilSet != selectBoilSetp ) { boilSet = selectBoilSetp; }
switch(selectView) {
case 0: viewActive = viewNormal; break;
case 1: viewActive = viewHltD; break;
case 2: viewActive = viewBoilD; break;
}
if ( push [0] > 0 ) { // confirm
virtualButton = 6;
push[0] = 0;
}
if ( push [1] > 0 ) { // escape
virtualButton = 5;
push[1] = 0;
}
// do brew process activity
brewProcess();
// do data logging if it is time for it
if(millis() - logTime>LOG_DELAY) {
logTime += LOG_DELAY;
Serial.print("brewController loop, do dataLogger");
dataLogger();
}
}
I have included two pictures, showing wall mounted controller and a look inside the box.
BrewCtrl_09_06.ino (27.4 KB)