Display sensor reandings on submenu

Greetings, I'm having trouble with a menu I meed for a project I'm doing.
I have two sensors and thinking of adding one more(Already programed one of them which is a flow sensor, the other one is an oxigention sensor), and I need to be able to go in the menu and select which reading I want to see, for example I want to see the flow reading, select to see it for as long as I want and being able to go back to the main menu so I can scroll and look for another sensor.
I'm using an encoder and a Adruino uno.

I've been using this code but it's just working with leds. I dont know how to adapt it to just show the sensor reading instead of turning the leds on and off.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

//ENCODER
#define outputA 6
#define outputB 7
#define sw 4

int aState;
int aLastState;  

//LEDS
#define led1 8
#define led2 9
#define led3 10


int led_seleccionado = 0;

LiquidLine linea1(1, 0, "Flujo");
LiquidLine linea2(1, 1, "Sp02");
LiquidLine linea3(1, 0, "Ritmo");
LiquidLine linea4(1, 1, "Otros");
LiquidScreen pantalla1(linea1,linea2,linea3,linea4);

LiquidLine linea1_2(1, 0, "Encender");
LiquidLine linea2_2(1, 1, "Apagar");
LiquidLine linea3_2(1, 0, "Atras");
LiquidScreen pantalla2(linea1_2,linea2_2,linea3_2);

LiquidMenu menu(lcd,pantalla1,pantalla2);

void setup() {

  pinMode(led1,OUTPUT);
  pinMode(led2,OUTPUT);
  pinMode(led3,OUTPUT); 
  
  pinMode(sw,INPUT_PULLUP);
  
  lcd.init();
  lcd.backlight();
  

  menu.init();

  linea1.set_focusPosition(Position::LEFT); 
  linea2.set_focusPosition(Position::LEFT); 
  linea3.set_focusPosition(Position::LEFT); 
  linea4.set_focusPosition(Position::LEFT); 
   
  linea1.attach_function(1, fn_led1); 
  linea2.attach_function(1, fn_led2);
  linea3.attach_function(1, fn_led3);
  linea4.attach_function(1, fn_todos);
  
  menu.add_screen(pantalla1);
  

  
  linea1_2.set_focusPosition(Position::LEFT); 
  linea2_2.set_focusPosition(Position::LEFT); 
  linea3_2.set_focusPosition(Position::LEFT); 
  
  linea1_2.attach_function(1, fn_on); 
  linea2_2.attach_function(1, fn_off);
  linea3_2.attach_function(1, fn_atras);
   
  menu.add_screen(pantalla2);

  pantalla1.set_displayLineCount(2);
  pantalla2.set_displayLineCount(2);

  menu.set_focusedLine(0);

  menu.update();

}

void loop() {

  selectOption();

  aState = digitalRead(outputA); 
    if (aState != aLastState){     
      if (digitalRead(outputB) != aState) { 
        menu.switch_focus(false);
      } else {
        menu.switch_focus(true);
      }
      menu.update();
      aLastState = aState;
  }

}





//Funciones:::::
void selectOption(){
  if(digitalRead(sw) == LOW){
      menu.call_function(1);
      delay(500);
  }
}

void fn_led1(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
  led_seleccionado = 1;
}

void fn_led2(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
  led_seleccionado = 2;
}


void fn_led3(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
  led_seleccionado = 3;
}


void fn_todos(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
  led_seleccionado = 0;
}



void fn_on(){

  switch(led_seleccionado){
    case 1:
      digitalWrite(led1,HIGH);
      break;
    case 2:
      digitalWrite(led2,HIGH);
      break; 
    case 3:
      digitalWrite(led3,HIGH);
      break;
    case 0:
      digitalWrite(led1,HIGH);
      digitalWrite(led2,HIGH);
      digitalWrite(led3,HIGH);
      break;   
  }

}


void fn_off(){
  switch(led_seleccionado){
    case 1:
      digitalWrite(led1,LOW);
      break;
    case 2:
      digitalWrite(led2,LOW);
      break; 
    case 3:
      digitalWrite(led3,LOW);
      break;
    case 0:
      digitalWrite(led1,LOW);
      digitalWrite(led2,LOW);
      digitalWrite(led3,LOW);
      break;   
  }
}

void fn_atras(){
  menu.change_screen(1);
  menu.set_focusedLine(0);
}

And this is the code for the flow meter I am using

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,16,2);
const int ontime (200);
const int offtime (200);
const int buzzer= 11;
const int led = 12;
volatile int flow_frequency; // Measures flow sensor pulses
unsigned int l_mint; // Calculated litres/hour
unsigned char flowsensor = 2; // Sensor Input
unsigned long currentTime;
unsigned long cloopTime;
void flow () // Interrupt function
{
flow_frequency++;
}
void setup()
{
pinMode(buzzer, OUTPUT);
pinMode(led, OUTPUT);
pinMode(flowsensor, INPUT);
digitalWrite(flowsensor, HIGH); // Optional Internal Pull-Up
Serial.begin(9600);
attachInterrupt(0, flow, RISING); // Setup Interrupt
sei(); // Enable interrupts
currentTime = millis();
lcd.init();
lcd.backlight();
cloopTime = currentTime;
lcd.print(" Flow meter");
delay(2000);
lcd.clear();
}
void loop ()
{
currentTime = millis();
// Every second, calculate and print litres/mint
if(currentTime >= (cloopTime + 1000))
{
cloopTime = currentTime; // Updates cloopTime
// Pulse frequency (Hz) = 7.5Q, Q is flow rate in L/min.
l_mint = (flow_frequency * 60 / 98); // (Pulse frequency x 60 min) / 7.5Q = flowrate inL/mint
flow_frequency = 0; // Reset Counter
Serial.print(l_mint, DEC); // Print litres/hour
Serial.println(" L/mint");
lcd.setCursor(0,0);
lcd.print(" Flow Meter");
lcd.setCursor(0,1);
lcd.setCursor(2,1);
lcd.print(l_mint, DEC);
lcd.setCursor(5,1);
lcd.print("L/Min");
if(l_mint>=10)
{
  digitalWrite(led, HIGH);
  digitalWrite(buzzer, HIGH);
  delay(ontime);

}
if(l_mint<10){
  digitalWrite(led,LOW);
  digitalWrite(buzzer, LOW);
  delay(offtime);
}
}
}

Thanks in advance

This is ment to give you some ideas, not as a solution. I am writing similar code with nested menus. Rotation determines the direction in the menu (CW = up), then pressing the button selects an appropriate submenu. Scrolling through that I press the button to make my selection. I do this with a function that shows the click number (from 1 to the passed max), the direction, and if the button is pressed. From this I can select whatever selection I want. For example menu 3 selected temperature that gives me a submen of up or down then pressing the butty on will select. Holding the button takes it back to home or if inactive for a period of time it goes to the home menu.The key is the rotary function and the information it supplies. Because of all the messages they are stored in FRAM memory (3K x 8). Menu messages are fixed size 18 bytes and in a structure. The first Record has the number of messages in that structure and other infor. The number of messages tells the rotary function how many menu items are there. When it reaches the end it starts over with 1. Message 0 is for information not to be printed. Hopefully this helps.

And helpers have trouble, need to spend considerable time to understand Your code.
Somehow, some were, You got into typing characters at the keyboard making code. Why didn't You learn how to document the code? Using lots of words is not code documentation. One way is using Flow Charts that gives a very good overview of the flow of the code. That should be done before hitting the keyboard. Like making a road map of the oncoming travel before starting the travel.
I've penetrated several large, really large programs as professional but spending the time on amateur code from new members? No. There are better ways to use free time.

@Railroader I'm sorry if it made you upset it's a bad habit that I have to change. Here's a version with documentation

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <LiquidMenu.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

//ENCODER
#define outputA 6
#define outputB 7
#define sw 4

int aState;
int aLastState;  

//LEDS
#define led1 8 //Led 1 first option
#define led2 9 //Led 2 second option
#define led3 10//Led 3 third option


int led_seleccionado = 0; //selected led

LiquidLine linea1(1, 0, "Flujo"); //menu line 'option 1'
LiquidLine linea2(1, 1, "Sp02");//menu line 'option 2'
LiquidLine linea3(1, 0, "Ritmo");//menu line 'option 3'
LiquidLine linea4(1, 1, "Otros");//menu line 'option 4'
LiquidScreen pantalla1(linea1,linea2,linea3,linea4); //first menu lines

LiquidLine linea1_2(1, 0, "Encender"); //submenu options turn on led
LiquidLine linea2_2(1, 1, "Apagar"); //submenu options turn off led
LiquidLine linea3_2(1, 0, "Atras"); //submenu options go back to main menu
LiquidScreen pantalla2(linea1_2,linea2_2,linea3_2); //second menu lines

LiquidMenu menu(lcd,pantalla1,pantalla2);

void setup() {
//declaring leds as outputs
  pinMode(led1,OUTPUT); 
  pinMode(led2,OUTPUT);
  pinMode(led3,OUTPUT); 
  //declaring sw from encoder
  pinMode(sw,INPUT_PULLUP);
  //lcd begin
  lcd.init();
  lcd.backlight();
  
//menu begin
  menu.init();
//sets the postion for the focus line
  linea1.set_focusPosition(Position::LEFT); 
  linea2.set_focusPosition(Position::LEFT); 
  linea3.set_focusPosition(Position::LEFT); 
  linea4.set_focusPosition(Position::LEFT); 
//function for menu control
  linea1.attach_function(1, fn_led1); 
  linea2.attach_function(1, fn_led2);
  linea3.attach_function(1, fn_led3);
  linea4.attach_function(1, fn_todos);
  //adds first menu
  menu.add_screen(pantalla1);
  

//sets the postion for the focus line for second menu
  linea1_2.set_focusPosition(Position::LEFT); 
  linea2_2.set_focusPosition(Position::LEFT); 
  linea3_2.set_focusPosition(Position::LEFT); 
 //function for menu controls on second menu
  linea1_2.attach_function(1, fn_on); 
  linea2_2.attach_function(1, fn_off);
  linea3_2.attach_function(1, fn_atras);
   //adds second menu
  menu.add_screen(pantalla2);
//lines required for scrolling
  pantalla1.set_displayLineCount(2);
  pantalla2.set_displayLineCount(2);

  menu.set_focusedLine(0);
//Prints the updated menu
  menu.update();

}

void loop() {

  selectOption();
//for scrolling true the menu by output of encoder position
  aState = digitalRead(outputA); 
    if (aState != aLastState){     
      if (digitalRead(outputB) != aState) { 
        menu.switch_focus(false);
      } else {
        menu.switch_focus(true);
      }
      menu.update();
      aLastState = aState;
  }

}





//Funciones:::::
void selectOption(){
  //by pressing the sw will call for the function where the focus is located
  if(digitalRead(sw) == LOW){
      menu.call_function(1);
      delay(500);
  }
}
//to define cases for switch
void fn_led1(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
  led_seleccionado = 1; //to define cases for switch
}
//to define cases for switch
void fn_led2(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
  led_seleccionado = 2;
}

//to define cases for switch
void fn_led3(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
  led_seleccionado = 3;
}

//to define cases for switch
void fn_todos(){
  menu.change_screen(2);
  menu.set_focusedLine(0);
  led_seleccionado = 0;
}


//when to callback on function on second menu
void fn_on(){
//depends on the option selected in the first menu
  switch(led_seleccionado){ 
    case 1:
      digitalWrite(led1,HIGH);
      break;
    case 2:
      digitalWrite(led2,HIGH);
      break; 
    case 3:
      digitalWrite(led3,HIGH);
      break;
    case 0:
      digitalWrite(led1,HIGH);
      digitalWrite(led2,HIGH);
      digitalWrite(led3,HIGH);
      break;   
  }

}

//for call back off function on second menu
void fn_off(){
  switch(led_seleccionado){
    case 1:
      digitalWrite(led1,LOW);
      break;
    case 2:
      digitalWrite(led2,LOW);
      break; 
    case 3:
      digitalWrite(led3,LOW);
      break;
    case 0:
      digitalWrite(led1,LOW);
      digitalWrite(led2,LOW);
      digitalWrite(led3,LOW);
      break;   
  }
}
//function to go back
void fn_atras(){
  menu.change_screen(1);
  menu.set_focusedLine(0);
}```

@gilshultz Thank you for such a quick response!
Can you tell me how can it can go back by inactivity or by holding the sw?

That is determined by the direction the switch is rotating. My function returns that information and the current click stop. It detects if the switch is held down while rotating or not and sets a flag accordingly. I have no use for that but I tried it for the fun of it. When I work with a part especially the first time or it has been a while I write code and test it to be sure I understand how it is working. If it indicates the wrong direction swap the two wires to the rotary part, not the sw or common. Code for these can get very involved but they do a lot.

Thank you very much, I will now try it

1 Like

Let us know how you do!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.