Another Analog key Issue (while loop)

Hi everybody.

This is my issue. I was using a guide for making an aruino that checks temperture and humidity (http://www.instructables.com/id/Arduino-Automatic-Temperature-Humidity-Controller-/?ALLSTEPS)

Now, I have added a ground moisture sensor that works perfectly fine, the only problem is that i dont have enough space in my (robot lcd keypad shield) screen for all the values.

What I tried to do was making (at first an IF loop but then) a WHILE loop that will continue monitoring and showing some of the data -> and when a key id pressed (up and down for this case) the program will go to another While loop, showing the rest of the information.

I have to admit the i got a bit confused, but dont blame me, just a newbie :smiley:
The issue with my program, is that the program have to run in a loop until a key is pressed, and not wait for the user to press the key (becouse then the monitorind, and the real time info will get stuck)

This is where i got so far (not working):

#include <LiquidCrystal.h>
#include <DFR_Key.h>
#include "DHT.h"
#define temHighTrigger 29  //Setting the trigger value for the temperture, once the temperture lower than this trigger value, the heater band will start heating
#define humLowTrigger 45 //Setting the trigger value for the humidity, once the humidity lower than this value, start humidification
#define DHTPIN 15     // what pin we're connected to

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11 
#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)


// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

const int relay1 =  18;      // the number of the relay 1 pin
const int relay2 =  19;      // the number of the relay 2 pin
const int DFRKEY = 0;
const int CYTRON = 1;


DHT dht(DHTPIN, DHTTYPE);


//Pin assignments for DFRobot LCD Keypad Shield
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 
//---------------------------------------------

DFR_Key keypad;

// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;

#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

int sensorPin = A2;    // select the input pin for the potentiometer
int sensorValue = 0;  // variable to store the value coming from the moist sensor
int read_LCD_buttons(){               // read the buttons
    adc_key_in = analogRead(0);       // read the value from the sensor 

    // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
    // we add approx 50 to those values and check to see if we are close
    // We make this the 1st option for speed reasons since it will be the most likely result

    if (adc_key_in > 1000) return btnNONE; 

    // For V1.1 us this threshold
    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;  

   // For V1.0 comment the other threshold and use the one below:
   /*
     if (adc_key_in < 50)   return btnRIGHT;  
     if (adc_key_in < 195)  return btnUP; 
     if (adc_key_in < 380)  return btnDOWN; 
     if (adc_key_in < 555)  return btnLEFT; 
     if (adc_key_in < 790)  return btnSELECT;   
   */

    return btnNONE;                // when all others fail, return this.
}

void setup() 
{ 
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("initializing...");
  lcd.setCursor(0, 1);
  delay(1000);
  
  Serial.begin(9600);
  dht.begin();
  delay(1000);
  lcd.clear();
  
  /*
  OPTIONAL
  keypad.setRate(x);
  Sets the sample rate at once every x milliseconds.
  Default: 10ms
  */
  keypad.setRate(10);
  
  digitalWrite(relay1, HIGH);
  digitalWrite(relay2, HIGH);

}

void loop() 
{ 
      float h = dht.readHumidity();
      float t = dht.readTemperature();
      float sensorValue = analogRead(sensorPin); 
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)

while (read_LCD_buttons() > 1000) {};
while (read_LCD_buttons() < 250) {

      // check if returns are valid, if they are NaN (not a number) then something went wrong!
      if (isnan(t) || isnan(h)) {
          Serial.println("Failed to read from DHT");
          } else { 
           
      lcd.setCursor(0, 0);
      lcd.print("Hum: ");
      lcd.print(h);
      lcd.print(" %");
    
      lcd.setCursor(0, 1);
      lcd.print("Tem: ");
      lcd.print(t);
      lcd.print(" *C");
      }
      
    if(h < humLowTrigger) //if the humidity lower than the trigger value
      digitalWrite(relay1, LOW); //start humidification
    else
      digitalWrite(relay1, HIGH);
      
     if(t < temHighTrigger)
      digitalWrite(relay2, HIGH);//if temperture higher start cooling
    else
      digitalWrite(relay2, LOW);
       }     
      
      while (read_LCD_buttons() > 250 and read_LCD_buttons() < 450) {

      // check if returns are valid, if they are NaN (not a number) then something went wrong!
      if (isnan(t) || isnan(h)) {
          Serial.println("Failed to read from DHT");
          } else { 
      lcd.setCursor(0, 1);
      lcd.print("Moist: ");
      lcd.print(sensorValue);
      lcd.print(" %");
      }
      
    if(h < humLowTrigger) //if the humidity lower than the trigger value
      digitalWrite(relay1, LOW); //start humidification
    else
      digitalWrite(relay1, HIGH);
      
     if(t < temHighTrigger)
      digitalWrite(relay2, HIGH);//if temperture higher start cooling
    else
      digitalWrite(relay2, LOW);
       }      
}

What I tried to do was making (at first an IF loop but then)

An if loop? What the hell is that? There is an if STATEMENT...

while (read_LCD_buttons() > 1000) {};

The function returns a value between 0 and 5. How many times is this while statement going to iterate?

while (read_LCD_buttons() < 250) {

That will be pretty much always. Rather pointless, eh?

   while (read_LCD_buttons() > 250 and read_LCD_buttons() < 450) {

This might as well say "while never..."

Hi thank you very much! instead of just trying to make a laugh of new guys failed try's, you actually helped me with...... hmmm... nothing i guess.

sry i called it for loop and not statement? now can you help a guy? after all technical speaking issues have been solved?

My while loop is just trying to read the analog key from the lcd shield, since all five of them are connected throw one analog pin (atleast that what they said at wiki)

Here is the tab that i thougtholds the right info
Im beging to think that a for statment will go much better here, am i right? can anybody help me with that?

    // For V1.1 us this threshold
    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;

Please edit your post, select the code, and put it between [code] ... [/code] tags.

You can do that by hitting the "Code" icon above the posting area. It is the first icon, with the symbol: </>

Don't ignore what PaulS is saying. Your function read_LCD_buttons returns a number in the range 0 to 5. Why you are testing for > 250 and < 450 is a complete mystery to both of us.

Read your own code and reflect on what you are doing.

Im beging to think that a for statment will go much better here, am i right? can anybody help me with that?

You've lost me there. Help you do what?

First of all my apologies for not explaining my self correctly, everything here is very new and im trying to keep up.
Thanks you Nick and paul, very much for trying to understand my gibrish :slight_smile:

I think i was misinformed that because the button on the lcd shield are analog, i will have to call them by a different method.

My only wish is to have multiple screens wich i can go back and forward between them by pressing up_key or down_key. and the screens have to keep refreshing.

if i understand you correctly, read_LCD_buttons function uses 0-5 which are the numbers for the button?
If so, the statement should be

while (read_LCD_buttons(1)) { }
while (read_LCD_buttons(2)) { }
while (read_LCD_buttons(3)) { }

and so on..?

and another question. will the program keep running without waiting for the button to be pressed? because i need the info on screen constantly refreshing.

It won't keep running if you do this sort of thing:

while (read_LCD_buttons() > 1000) {};
while (read_LCD_buttons() < 250) {

The program does what you tell it. If you tell it to loop, waiting for a certain button, that's what it's gonna do!

while (read_LCD_buttons(1)) { }
while (read_LCD_buttons(2)) { }
while (read_LCD_buttons(3)) { }

Think about what you are writing there. That's like saying "while the fridge light is on, do nothing".

because i need the info on screen constantly refreshing.

Not while the fridge light is on, eh?

please, nick! give me somthing to work with i compoletly confused.

what i ment by

while (read_LCD_buttons(1)) { }
while (read_LCD_buttons(2)) { }
while (read_LCD_buttons(3)) { }

was instead of the 250, 450 etc... (i wouldnt live it empty ofcourse!) full content should look like this?

void loop() 
{ 
      float h = dht.readHumidity();
      float t = dht.readTemperature();
      float sensorValue = analogRead(sensorPin); 
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)

while (read_LCD_buttons() == 1) {

      // check if returns are valid, if they are NaN (not a number) then something went wrong!
      if (isnan(t) || isnan(h)) {
          Serial.println("Failed to read from DHT");
          } else { 
           
      lcd.setCursor(0, 0);
      lcd.print("Hum: ");
      lcd.print(h);
      lcd.print(" %");
    
      lcd.setCursor(0, 1);
      lcd.print("Tem: ");
      lcd.print(t);
      lcd.print(" *C");
      }
      
    if(h < humLowTrigger) //if the humidity lower than the trigger value
      digitalWrite(relay1, LOW); //start humidification
    else
      digitalWrite(relay1, HIGH);
      
     if(t < temHighTrigger)
      digitalWrite(relay2, HIGH);//if temperture higher start cooling
    else
      digitalWrite(relay2, LOW);
       }     
      
      while (read_LCD_buttons() == 2) {

      // check if returns are valid, if they are NaN (not a number) then something went wrong!
      if (isnan(t) || isnan(h)) {
          Serial.println("Failed to read from DHT");
          } else { 
      lcd.setCursor(0, 1);
      lcd.print("Moist: ");
      lcd.print(sensorValue);
      lcd.print(" %");
      }
      
    if(h < humLowTrigger) //if the humidity lower than the trigger value
      digitalWrite(relay1, LOW); //start humidification
    else
      digitalWrite(relay1, HIGH);
      
     if(t < temHighTrigger)
      digitalWrite(relay2, HIGH);//if temperture higher start cooling
    else
      digitalWrite(relay2, LOW);
       }      
}

Alright Nick, So after your help it kind of work! i change the read_LCD_buttons() to a digital number (1 and 2) and not it changes screen.

the only issue i have now is that the loop is waiting for a button to be pressed before it refreshes the data, any way to make the loop continue until a button is pressed?

Have a look at planning and implementing a program - especially the way the code is organized into small functions.

Then write two functions - one causes one lot of data to display. The other causes the other set of data to display.

Then write some code to select which function gets called depending on your button press.

Putting the code into small single-purpose functions makes it easy to separate the action from the logic.

...R

Thanks Robin. I'm beginning to understand the idea.

one question tho, wouldn't the program will get stuck (waiting for a button to be pressed) even if ill insert each screen to a function? because of the command 'read_LCD_buttons()'?

lysrgic:
wouldn't the program will get stuck (waiting for a button to be pressed) even if ill insert each screen to a function? because of the command 'read_LCD_buttons()'?

That would only happen if the function read_LCD_buttons() blocks. If it is properly written it won't.

There should be a variable whose value selects the function for the display. That variable will always have a value that selects displayA() or displayB(). The readButtons() function will change that variable. But if the variable is not changed nothing bad will happen.

...R

The ideal structure for a sketch is that the only(*) loop is the one called the
function loop().

Inside loop() you test for all the conditions that you have to respond to, and respond
to them by promptly changing state and updating outputs and setting time-out
variables.

This is a somewhat contorted framework in which to program, but its forced by
the lack of multi-tasking in a severely resource-starved microcontroller (2K of RAM).

(*) The only loop that takes any length of time - you're allowed to loop really, just
not to hang waiting for some condition or event. Then every input get sampled
repeatedly in the loop () function which should be called frequently all the time.

The readButtons() function will change that variable. But if the variable is not changed nothing bad will happen.

ok, I see where your going with that. so i need a triger like 'if key pressed' right? becouse the readButtons() function starts with the adc_key_in = analogRead(0); (adc_key_in is the veriable that changes inside the functione) wich means that the programwill wait for a key press.
the only option i see is to make an if statment inside the function that will check if the user has pressed a button?

is that makes any sence? and please, I do appritiate your help alot, could you direct me to the right command? right now i changed my script alittle bit and im using currentButton = keypad.getKey(); but i read that this function is not very stable or somthing like that, am i right?

wich means that the programwill wait for a key press.

NO! It does NOT mean that. When you call the readButtons() function, it tells you which key IS BEING PRESSED. That most of the time will be no key is being pressed. You MUST account for that fact.

You should also account for the fact that it might me the same key as last time you asked, in which case it is not a unique key press.

To build on what @PaulS has said ...

You need to read the value of the pin the button is connected to.
If it shows that the button is pressed you need to set the appropriate variable that records that
This assumes you have one button to display screenA and a different button to display screenB

If you are using a single button to toggle between screens (first press shows screenA, 2nd press screenB, 3rd press screenA again etc) then you need to check to ensure the button was released. You also need to allow a little time between checks (say 50 millisecs) to exclude the possibilty of mechanical bouncing in the switch.

The code in several things at a time includes a simple system for dealing with switch bounce.

...R

lysrgic:
This is my issue. I was using a guide for making an aruino that checks temperture and humidity (http://www.instructables.com/id/Arduino-Automatic-Temperature-Humidity-Controller-/?ALLSTEPS)

Now, I have added a ground moisture sensor that works perfectly fine, the only problem is that i dont have enough space in my (robot lcd keypad shield) screen for all the values.

If I need to display more information than fits on the two lines of a 16x2 LCD display, I typically create a timed switching display.

Here is some demonstration code that shows 4 different "screens", and each of them is displayed for 5 seconds:

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 

void lcdOut(byte line, char* text)
{
  lcd.setCursor(0,line); 
  lcd.print(text);
  for (int i=strlen(text);i<16;i++) 
    lcd.print(' '); // clear to end of line
}

void screen0()
{
  lcdOut(0,"Temp: 20.0 C");
  lcdOut(1,"Humidity: 56%");
}


void screen1()
{
  lcdOut(0,"Date: 17.05.2015");
  lcdOut(1,"Time: 14:25:31");
}

void screen2()
{
  char buf[17];
  snprintf(buf,sizeof(buf),"Seconds: %06ld", millis()/1000);
  lcdOut(0,buf);
  lcdOut(1,"Since last reset");
}

void screen3()
{
  lcdOut(0,"Hello World!");
  lcdOut(1,"");
}



void setup()
{
  lcd.begin(16,2);
}

void loop()
{
  // How to create timed display with 4 screens, updated once per second
  static long lastSeconds;
  long seconds=millis()/1000;
  if (seconds!=lastSeconds)
  {
    lastSeconds=seconds;
    byte screen= (seconds/5)%4; // 4 screens, each shows up 5 seconds
    if (screen==0) screen0();
    else if (screen==1) screen1();
    else if (screen==2) screen2();
    else if (screen==3) screen3();
  }
}

For demonstration purposes most screens show fixed text only.
But in the screen2() function you can see how to format a text buffer with current value before displaying it.

That way you don't need any button or button logic, but the displayed contents will switch by time automatically.

4 screens of 2 lines of 16 characters.
Of course, any amount of screens would be possible.

Timed toggling of display contents is an easy way to show more information than fits on the display at once.