Help with output to 1602 LCD.

Hi,

I have posted this issue in the Project Guidance forum as part of the greater project of building a spa pool controller but have had no replies and i really need some help.

I am working on building a new spa pool controller, as part of this project I am trying to get elements of the overall code working, the final project will pull what I have learned together. I have encountered a problem that I can't solve. While the code is not finialised in any sense for the project as a whole I'm hoping someone can help me with this specific problem.

The code started with simply trying to set a desired comfort temperature of the spa that is set by a keypad. I used the 1602 shield with integrated buttons for ease but the final project probably will use a different LCD.

The code is prominently about setting and using the buttons which move the "ComfTemp" up and down. As part of the code I added in a "Current Temperature" which is run off a LM35 connected to A5.

If I run the code with the up and down section commented out so it only shows the current temperature it works fine and shows 21 deg (room temp here).

If I run the code that has the comfort temp only, the up and down works fine.

If I run both parts in the same loop the up and down works fine but the current temp shows 40 deg + .

Can anyone see in my code why the current temp would be inflated, I apologise in advance if it is a bit messy as I have been hacking it around to make it work?

Cheers
Al

#include <LiquidCrystal.h> // Library for 1602 LCD

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // set the pins for the dispay, if using shield these are standard

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

int ButtonsPin = A0;
int comfTemp = 40; // default spa temp
boolean lcdNeedsUpdate = true;

int tempPin = A5;   // the output pin of LM35
int curTemp = 0; // defines current spa temp
long lastread = 0; // to allow reading of spa temp once per minute

int read_LCD_buttons() // returns a value from 0-6 using the define list matching the button to corrosponding value
{
  int returnValue;
  // read ADC value of pressed button
  int adc_key_in =  analogRead (ButtonsPin); // reads the value from A0 to determin button
  int adc_key_in1 =  analogRead (ButtonsPin); // reads the value again, used to check the value is constant
  // read again and check for stable ADC reading (software debouncing for analog input)
  if (abs(adc_key_in1 - adc_key_in) > 1) return btnNONE; // if ADC reading is not stable, return btnNONE
  // below values for the buttons coneected to A0 may vary depending on the sheild used, these need to be worked out prior
  if (adc_key_in < 50) returnValue = btnRIGHT;
  else if ( (adc_key_in > 95) && (adc_key_in < 110) ) returnValue = btnUP;
  else if ( (adc_key_in > 250) && (adc_key_in < 350) ) returnValue = btnDOWN;
  else  if ( (adc_key_in > 400) && (adc_key_in < 450) ) returnValue = btnLEFT;
  else if ( (adc_key_in > 630) && (adc_key_in < 700) ) returnValue = btnSELECT;
  else returnValue = btnNONE;
  // simple "blocking" code: "Busy waiting" until button is released by user
  while (adc_key_in < 999) adc_key_in = analogRead(ButtonsPin);
  return returnValue;
}

int readTemp() // get the temperature and convert it to celsius
{
  curTemp = analogRead(tempPin);
  return curTemp * 0.48828125;
}

void setup()
{
  Serial.begin(9600); // begin serial monitor so you can view the output of selected temp
  lcd.begin(16, 2); // initialise the display
  lcd.clear(); // clear the display
  lcd.print ("Current Temp:"); // will display current temp of spa
  lcd.setCursor (0, 1);
  lcd.print ("Comfort Temp:"); // will display desired temp

  pinMode(tempPin, INPUT); // defines temp pin as input from LM35
}


void loop()
{
  if (millis() >= lastread + 10000) { // check if last temp reading was greater than 10 sec
    curTemp = readTemp();     // get the temperature
    lcd.setCursor(14, 0); // adds the current temp to the end of the first line
    lcd.print(curTemp); // should print onto line one at end
    lastread = millis(); // set the lastread of sensor
  }


  int key = read_LCD_buttons();
  if (key != btnNONE) lcdNeedsUpdate = true;

  switch (key)
  {
    case btnUP:
      if (comfTemp < 42) comfTemp++;
      break;
    case btnDOWN:
      if (comfTemp > 36) comfTemp--;
      break;
    case btnSELECT:
      Serial.print("Saved value: ");
      Serial.println(comfTemp);
      Serial.println(curTemp);
      break;
  }

  if (lcdNeedsUpdate)
  {
    lcd.setCursor(14, 1); // should print onto line 2 
    lcd.print(comfTemp);
    lcdNeedsUpdate = false;
  }
 
}

You can reset the key variable so that you don't repeat the action.

key = btnNONE;

If I run both parts in the same loop the up and down works fine but the current temp shows 40 deg +

it's not clear to me what you mean by both parts.

If I run the code with the up and down section commented out so it only shows the current temperature it works fine and shows 21 deg (room temp here).

why is it 21 deg and not 40 which is what comfTemp is initialized to.

and the commented out code is simply the two cases: btnUP and btnDOWN in loop()?

I would just put a print statement in the readtemp routine and see what you are getting print out the raw counts then another print out after you multipy by 0.488.

That is the place where it's read so you want to make sure it's being read correctly.

noweare:
I would just put a print statement in the readtemp routine and see what you are getting print out the raw counts then another print out after you multipy by 0.488.

That is the place where it's read so you want to make sure it's being read correctly.

Yes that is correct, that is how I established the value originally without the rest of the code for the buttons, I have used the LM35 for a number of heat detecting projects and analogRead(TempPin) * 0.488 returns the correct temperature.

If I comment out the button section of the code from int key = read_LCD_buttons(); as per below and add in Serial.println(analogRead(A5)); the serial monitor shows 46-47 which is about 22deg.

If i add the button section back in, everything from int key = read_LCD_buttons(); down then the serial monitor shows 74-75 which is 36 deg.

Now this is where it gets really wired.
If I move the line Serial.println(analogRead(A5)); to the first item in void loop()
then the serial monitor outputs 86-87.

if I add in a line
analogRead(A5); as the first item in void loop() above Serial.println(analogRead(A5)); then the serial monitor outputs 46-47 which is correct.

So it seems it is something to do with with the code reading A5 and maybe A0 at the same time and getting some form of induced voltage to the analog pins. Well beyond my understanding.

Code below has the the section already commented out and the analogRead and Serial.Println added but commented out.

#include <LiquidCrystal.h> // Library for 1602 LCD

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // set the pins for the dispay, if using shield these are standard

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

int ButtonsPin = A0;
int comfTemp = 40; // default spa temp
boolean lcdNeedsUpdate = true;

int tempPin = A5;   // the output pin of LM35
int curTemp = 0; // defines current spa temp
long lastread = 0; // to allow reading of spa temp once per minute

int read_LCD_buttons() // returns a value from 0-6 using the define list matching the button to corrosponding value
{
  int returnValue;
  // read ADC value of pressed button
  int adc_key_in =  analogRead (ButtonsPin); // reads the value from A0 to determin button
  int adc_key_in1 =  analogRead (ButtonsPin); // reads the value again, used to check the value is constant
  // read again and check for stable ADC reading (software debouncing for analog input)
  if (abs(adc_key_in1 - adc_key_in) > 1) return btnNONE; // if ADC reading is not stable, return btnNONE
  // below values for the buttons coneected to A0 may vary depending on the sheild used, these need to be worked out prior
  if (adc_key_in < 50) returnValue = btnRIGHT;
  else if ( (adc_key_in > 95) && (adc_key_in < 110) ) returnValue = btnUP;
  else if ( (adc_key_in > 250) && (adc_key_in < 350) ) returnValue = btnDOWN;
  else  if ( (adc_key_in > 400) && (adc_key_in < 450) ) returnValue = btnLEFT;
  else if ( (adc_key_in > 630) && (adc_key_in < 700) ) returnValue = btnSELECT;
  else returnValue = btnNONE;
  // simple "blocking" code: "Busy waiting" until button is released by user
  while (adc_key_in < 999) adc_key_in = analogRead(ButtonsPin);
  return returnValue;
}

int readTemp() // get the temperature and convert it to celsius
{
  curTemp = analogRead(tempPin);
  return curTemp * 0.48828125;
}

void setup()
{
  Serial.begin(9600); // begin serial monitor so you can view the output of selected temp
  lcd.begin(16, 2); // initialise the display
  lcd.clear(); // clear the display
  lcd.print ("Current Temp:"); // will display current temp of spa
  lcd.setCursor (0, 1);
  lcd.print ("Comfort Temp:"); // will display desired temp

  pinMode(tempPin, INPUT); // defines temp pin as input from LM35
}


void loop()
{

//analogRead(A5);
//Serial.println(analogRead(A5));
   
  if (millis() >= lastread + 10000) { // check if last temp reading was greater than 10 sec
    curTemp = readTemp();     // get the temperature
    lcd.setCursor(14, 0); // adds the current temp to the end of the first line
    lcd.print(curTemp); // should print onto line one at end
    lastread = millis(); // set the lastread of sensor
  }
  Serial.println(analogRead(A5));

/*
  int key = read_LCD_buttons();
  
  if (key != btnNONE) lcdNeedsUpdate = true;

  switch (key)
  {
    case btnUP:
      if (comfTemp < 42) comfTemp++;
      break;
    case btnDOWN:
      if (comfTemp > 36) comfTemp--;
      break;
    case btnSELECT:
      Serial.print("Saved value: ");
      Serial.println(comfTemp);
      Serial.println(curTemp);
      break;
  }

  if (lcdNeedsUpdate)
  {
    lcd.setCursor(14, 1); // should print onto line 2 
    lcd.print(comfTemp);
    lcdNeedsUpdate = false;
    key = btnNONE;
  }
*/
}

rtek1000:
You can reset the key variable so that you don't repeat the action.

key = btnNONE;

Sorry rtek1000 I'm not sure where you are suggesting I insert that line. I added into the last If statement that resets the lcdNeedsUpdate so it resets key as well but it made no difference.

I dont know if this is wrong but I know if you are using the
analog inputs as analog inputs you do not need this:

pinMode(tempPin, INPUT); // defines temp pin as input from LM35

I don't see any cross contamination. This is interesting.
You could try to just connect the buttons to their own digital inputs and see if that
works, but I would like to know whats going on here.

I try to simplify things when things when they are not working right.

Instead of:
Serial.println(analogRead(tempPin);

use:
some_variable = analogRead(tempPin);
Serial.println(some_variable);

Try the usual trick and read the ADC more than once when you read temperature. There is only one and previous uses can impact subsequent reads.

Better yet, get a waterproof DS18B20 :wink:

Thanks Noweare

I removed the line pinMode(tempPin, INPUT); I realize now that they are for the digital pins. (still new to this)

Removing it made no difference to the program.

I take your point regarding some_variable, the Serial.Print was thrown in to see what was going on in my frustration.

So here is what happens

  1. With no analogRead(tempPin); and Serial.println(analogRead(A5)); below the first if statement in the void loop(). the serial monitor is (notice the odd 38 in the list) mostly 83-85 and the LCD prints 42 deg which is incorrect
38
83
83
86
82
84
85
67
84
  1. With no analogRead(tempPin); and Serial.println(analogRead(A5)); above the first if statement in the void loop() the serial monitor is is mostly 87-89 and the LCD prints 23 deg which is correct but I don't see any 47 in the list (47 * .488 = 23 deg)
89
89
90
87
89
89
89
89
88
89
89
89
57
88
89
90
88
88
88
88
88
88
88
88
88
88
88
88
56
87
89
89
90
87
87
87
89
89
  1. Add analogRead(tempPin); above the if statement and Serial.println(analogRead(A5)); either above or below the first if statement in the void loop() the serial monitor is is mostly 47-48 and the LCD prints 23 deg which is correct.
48
48
48
48
48
48
47
48
48
48
48
48
47
48
48
48
48
48
48
48
47
48
48
48
47

I don't get it, it seems that the code needs to read the A5 pin "tempPin" at the beginning of the loop to stabilize the reading before moving on to reading A0 for the buttons from the shield.

wildbill:
Try the usual trick and read the ADC more than once when you read temperature. There is only one and previous uses can impact subsequent reads.

Can you point me to an example of the usual trick? I'm still learning basics (sit, come, stay) and haven't moved onto tricks yet

wildbill:
Better yet, get a waterproof DS18B20 :wink:

Thanks for that I almost certainly will get one of those (and almost certainly not use this 1602 non waterproof keypad)

Read the ADC to get the temperature. Then repeat that line of code so you read it again. The idea is to read & throw away and then read again to reduce the impact of what you were reading on the same ADC to detect button presses.

Thanks Wildbill

So i added

int readTemp() // get the temperature and convert it to celsius
{
  curTemp = analogRead(tempPin);
  curTemp = analogRead(tempPin);
  return curTemp * 0.48828125;
}

and it now works without the analogRead(tempPin); in the loop.

Thanks everyone,

So it looks like you are using default as a reference which is VCC .
What is the voltage coming from your temperature sensor ?

You lose resolution in your measurement if the temp sensor output is much lower than your reference.

Move the temp. sensor away from the display if it is close.

Wild Bills idea may work or at least help.

I will have to remember this, thanks wildbill !

wildbill:
Read the ADC to get the temperature. Then repeat that line of code so you read it again. The idea is to read & throw away and then read again to reduce the impact of what you were reading on the same ADC to detect button presses.

If that solves, isn't the sampling time wrong?

ref.: In the ADC why is the sample-and-hold capacitor connected to Vcc/2? - General Electronics - Arduino Forum