Problema con LCD, KeyPad y LM35 [2]

Hola a tod @ s, soy un estudiante de secundaria que está teniendo problemas con un proyecto de una bomba de agua, en el trabajo estoy usando un ATMEGA328P, un LCD 20x4, un KeyPad 4x3, un sensor de temperatura LM35 y un relé (bomba de agua). El circuito lo tengo armado en Proteus 8.
Funcionamiento:

  1. Al presionar dos teclas seteo una temperatura de 25 ° C.
  2. Esa temperatura quiero que tenga un margen, por ejemplo, que suba o baje dos grados centigrados, a 27 ° C o 23 ° C según el caso.
  3. Con el LM35, voy a basarme en la temperatura que muestre para que ande el relé, osea, si el LM35 está en 18 ° C el relé estará apagado y si está en 25 ° C estará prendido (funcionando con el margen de + -2 ° C).
  4. En caso de que suba o baje más de 2 ° C el relé se apagará.
  5. Habrá una constante que show si el relé está prendido o apagado.

Problema: La parte de mostrar la temperatura del LM35 la tengo hecha, también lo de setear la T ° con el KeyPad y lo de mostrar si el relé está prendido o apagado.
Lo que sucede es que no entiendo como seleccionar un margen, hice un while (T_set = 25) y abajo un if con las condiciones de que si es mayor o igual a 23 esté encendido el relé, y si es menor o igual a 27 que ande, pero se traba la T ° del LM35 en una y no puedo bajarla ni subirla y la constante de la bomba primero muestra que está OFF y luego ON, y no sucede más nada, ya que el LM35 está trabado.
Lo único que sigue andando es lo de setear la T ° con el KeyPad.
Les agradecería si me ayudan :slight_smile:

//librerias
#include <Keypad.h>
#include <TimerOne.h>
#include <LiquidCrystal.h>

//definir nombre de pines
#define BOMBA 8

//hago una variable int llamada T_Set
int T_Set = 0;

//configuración del teclado
const byte ROWS = 4;
const byte COLS = 3;

char hexaKeys[ROWS][COLS] = {
    {'1', '2', '3'},
    {'4', '5', '6'},
    {'7', '8', '9'},
    {'*', '0', '#'}
};

byte rowPins[ROWS] = {9, 10, 11, 12};
byte colPins[COLS] = {13, A1, A2};

Keypad myKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

//configuración para el lcd
const int rs = 7, en = 2, d4 = 3, d5 = 4, d6 = 5, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//configuración para el sensor de temperatura
float aref = 5.0;
volatile float TEMP;

void setup() 
{
  //iniciar lcd
  lcd.begin(20, 4);
  analogReference(EXTERNAL);
  //imprimo constantes
  lcd.setCursor(0, 0);
  lcd.print("Temp Sensor=");
  lcd.setCursor(0, 1);
  lcd.print("Temp Set=");
  lcd.setCursor(0, 2);
  lcd.print("Bomba=");
  //configuro E y S
  pinMode(A0, INPUT);
  pinMode(BOMBA, OUTPUT);
  //interrupcion
  Timer1.initialize(1000000);
  Timer1.attachInterrupt(MargenT);
}

void loop()
{
  //leer temp
  int lectura = analogRead(A0);
  TEMP = (lectura * (aref / 1024)) * 10;
  //TEMP = lectura;
  lcd.setCursor(13, 0);
  lcd.print(TEMP );
  delay(100);
  //teclado
  Teclado();
}

void MargenT()
{
    while(T_Set = 25)
    {
    if(TEMP >= 23.00 <= 27.00)
    {
      lcd.setCursor(7, 2); //Estado de la bomba
      lcd.print("ON ");
      digitalWrite(BOMBA, HIGH);
    }
    else if(TEMP < 23.00 > 27.00)
    {
      lcd.setCursor(7, 2); //Estado de la bomba
      lcd.print("OFF");
      digitalWrite(BOMBA, HIGH);
    }
    }
}

void Teclado()
{
  String T_Set = "";
  while(T_Set.length() < 2) //longitud del string = 2
  {
    char key = '\0'; //no hay ninguna tecla presionada
    do 
    {
      key = myKeypad.getKey(); //leo la tleca
    } 
    while (key == NO_KEY); //si no se presiona una tecla, el while espera 
    if (isDigit(key)) //verifica si la tecla presionada es un digito (del 0 al 9)
    {
      T_Set = T_Set + key; //guardo la tecla presionada en el string T_Set si llega a 2 digitos, vuelve al primer lugar 
      lcd.setCursor(10, 1);
      lcd.print(T_Set);
    }
  }
  MargenT();
}

Captura de pantalla (163).png

Creo que ésto es lo que quieres (si entendí bien)

if(TEMP > T_Set.toFloat() - 2.0 && TEMP < T_Set.toFloat() + 2.0) {
// enciende ventilador y demas cosas por hacer
} else {
// apaga ventilador y otras cosas por hacer
}

T_Set es lo que seteaste pero está en una cadena, hay que pasarla a float (para eso es toFloat())

Revisa porque hay muchos errores de sintaxis en tu código.

Además no tiene sentido definir TEMP como volatile en la forma que la estás usando

volatile float TEMP;

Que quede así

float TEMP;

Gracias por solucionarme la parte del if, pero lo que no entiendo es porque no está bien la parte donde declare volatile float si tengo una interrupción.

Porque TEMP no se altera durante la interrupción, por eso te dije que no tiene sentido en la forma que la usas, si lo prefieres dejala, no le afecta, a lo sumo perderá algún ciclo de reloj.

Te dejo un link donde lo explican mejor.

Bueno gracias, voy a tener en cuenta lo que me dijiste

Hola, estuve implementando lo anterior y me apareció este error

C:\Users\lucia\OneDrive\Escritorio\BombaDeAgua\BombaDeAgua.ino: In function 'void MargenT()':

BombaDeAgua:71:20: error: request for member 'toFloat' in 'TSet', which is of non-class type 'int'

     if(TEMP > TSet.toFloat - 2.00 && TEMP < TSet.toFloat + 2.00)

                    ^~~~~~~

BombaDeAgua:71:50: error: request for member 'toFloat' in 'TSet', which is of non-class type 'int'

     if(TEMP > TSet.toFloat - 2.00 && TEMP < TSet.toFloat + 2.00)

                                                  ^~~~~~~

Utilizando biblioteca Keypad en carpeta: C:\Users\lucia\OneDrive\Documentos\Arduino\libraries\Keypad (legacy)
Usando librería TimerOne-master con versión 1.1 en la carpeta: C:\Users\lucia\OneDrive\Documentos\Arduino\libraries\TimerOne-master
Usando librería LiquidCrystal con versión 1.0.7 en la carpeta: C:\Program Files (x86)\Arduino\libraries\LiquidCrystal 
exit status 1
request for member 'toFloat' in 'TSet', which is of non-class type 'int'
//librerias
#include <Keypad.h>
#include <TimerOne.h>
#include <LiquidCrystal.h>

//definir nombre de pines
#define BOMBA 8

//hago una variable int llamada T_Set
int TSet = 0;

//configuración del teclado
const byte ROWS = 4;
const byte COLS = 3;

char hexaKeys[ROWS][COLS] = {
    {'1', '2', '3'},
    {'4', '5', '6'},
    {'7', '8', '9'},
    {'*', '0', '#'}
};

byte rowPins[ROWS] = {9, 10, 11, 12};
byte colPins[COLS] = {13, A1, A2};

Keypad myKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

//configuración para el lcd
const int rs = 7, en = 2, d4 = 3, d5 = 4, d6 = 5, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//configuración para el sensor de temperatura
float aref = 5.0;
float TEMP;

void setup() 
{
  //iniciar lcd
  lcd.begin(20, 4);
  analogReference(EXTERNAL);
  //imprimo constantes
  lcd.setCursor(0, 0);
  lcd.print("Temp Sensor=");
  lcd.setCursor(0, 1);
  lcd.print("Temp Set=");
  lcd.setCursor(0, 2);
  lcd.print("Bomba=");
  //configuro E y S
  pinMode(A0, INPUT);
  pinMode(BOMBA, OUTPUT);
  //interrupcion
  Timer1.initialize(1000000);
  Timer1.attachInterrupt(MargenT);
}

void loop()
{
  //leer temp
  int lectura = analogRead(A0);
  TEMP = (lectura * (aref / 1024)) * 10;
  //TEMP = lectura;
  lcd.setCursor(13, 0);
  lcd.print(TEMP );
  delay(100);
  //teclado
  Teclado();  
}

void MargenT()
{
    if(TEMP > TSet.toFloat - 2.00 && TEMP < TSet.toFloat + 2.00)
    {
      lcd.setCursor(7, 2); //Estado de la bomba
      lcd.print("ON ");
      digitalWrite(BOMBA, HIGH);
    }
    else
    {
      lcd.setCursor(7, 2); //Estado de la bomba
      lcd.print("OFF");
      digitalWrite(BOMBA, HIGH);
    }
}

void Teclado()
{
  String TSet = "";
  while(TSet.length() < 2) //longitud del string = 2
  {
    char key = '\0'; //no hay ninguna tecla presionada
    do 
    {
      key = myKeypad.getKey(); //leo la tleca
    } 
    while (key == NO_KEY); //si no se presiona una tecla, el while espera 
    if (isDigit(key)) //verifica si la tecla presionada es un digito (del 0 al 9)
    {
      TSet = TSet + key; //guardo la tecla presionada en el string T_Set si llega a 2 digitos, vuelve al primer lugar 
      lcd.setCursor(10, 1);
      lcd.print(TSet);
    }
  }
  MargenT();
}

La función es toFloat()

TSet.toFloat()

Ahh si, me olvidé de poner los parentesis, pero me sigue apareciendo el mismo error

Claro te sale el mismo error porque definiste una TSet global como entero y una TSet local como String. Define directamente la global como string, y en Teclado() quítale el string de delante

Si, ya funciona todo perfectamente, gracias gatul :)

Adjunto el código por si alguien lo quiere

//librerias
#include <Keypad.h>
#include <TimerOne.h>
#include <LiquidCrystal.h>

//definir nombre de pines
#define BOMBA 8

//hago un string llamado TSet
String TSet;

//configuración del teclado
const byte ROWS = 4;
const byte COLS = 3;

char hexaKeys[ROWS][COLS] = {
    {'1', '2', '3'},
    {'4', '5', '6'},
    {'7', '8', '9'},
    {'*', '0', '#'}
};

byte rowPins[ROWS] = {9, 10, 11, 12};
byte colPins[COLS] = {13, A1, A2};

Keypad myKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

//configuración para el lcd
const int rs = 7, en = 2, d4 = 3, d5 = 4, d6 = 5, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//configuración para el sensor de temperatura
float aref = 5.0;
float TEMP;

void setup() 
{
  //iniciar lcd
  lcd.begin(20, 4);
  analogReference(EXTERNAL);
  //imprimo constantes
  lcd.setCursor(0, 0);
  lcd.print("Temp Sensor=");
  lcd.setCursor(0, 1);
  lcd.print("Temp Set=");
  lcd.setCursor(0, 2);
  lcd.print("Bomba=");
  //configuro E y S
  pinMode(A0, INPUT);
  pinMode(BOMBA, OUTPUT);
  //interrupcion
  Timer1.initialize(1000000);
  Timer1.attachInterrupt(MargenT);
}

void loop()
{
  //leer temp
  int lectura = analogRead(A0);
  TEMP = (lectura * (aref / 1024)) * 10;
  //TEMP = lectura;
  lcd.setCursor(13, 0);
  lcd.print(TEMP );
  delay(100);
  //teclado
  Teclado();  
}

void MargenT()
{
    if(TEMP > TSet.toFloat() - 2.00 && TEMP < TSet.toFloat() + 2.00)
    {
      lcd.setCursor(7, 2); //Estado de la bomba
      lcd.print("ON ");
      digitalWrite(BOMBA, HIGH);
    }
    else
    {
      lcd.setCursor(7, 2); //Estado de la bomba
      lcd.print("OFF");
      digitalWrite(BOMBA, LOW);
    }
}

void Teclado()
{
  while(TSet.length() < 2) //longitud del string = 2
  {
    char key = '\0'; //no hay ninguna tecla presionada
    do 
    {
      key = myKeypad.getKey(); //leo la tleca
    } 
    while (key == NO_KEY); //si no se presiona una tecla, el while espera 
    if (isDigit(key)) //verifica si la tecla presionada es un digito (del 0 al 9)
    {
      TSet = TSet + key; //guardo la tecla presionada en el string TSet si llega a 2 digitos, vuelve al primer lugar 
      lcd.setCursor(10, 1);
      lcd.print(TSet);
    }
  }
  MargenT();
}

De nada!

Edito: si tienes problemas al ingresar la temperatura por segunda vez, agrega

TSet = "";

al inicio de teclado() para quitar los caracteres que ya tecleaste en el anterior ingreso (por eso te dije que sacaras el tipo (string) de delante de la asignación de la variable, no toda la asignación)

[color=#222222]Hola a tod@s, sigo con el proyecto de la bomba de agua, en el trabajo estoy usando un ATMEGA328P, un LCD 20x4, un KeyPad 4x3, un sensor de temperatura LM35 y un relé (bomba de agua). El circuito está hecho en Proteus 8.[/color]
[color=#222222]Funcionamiento: [/color]
[color=#222222]1) Al presionar dos teclas seteo una temperatura de 25 ° C. [/color]
[color=#222222]2) Esa temperatura quiero que tenga un margen, por ejemplo, que suba dos grados centigrados, a 27 ° C.[/color]
[color=#222222]3) Con el LM35, voy a basarme en la temperatura que muestre para que ande el relé, osea, si el LM35 está en 18 ° C el relé estará prendido y si está en 25 ° C también, pero si está a más o a igual T° que 27°C se apagará (funcionando con un margen de +2 ° C). [/color]
[color=#222222]4) Habrá una constante que muestre si el relé está prendido o apagado.[/color]

–Hasta ahí tengo hecho–
5) El LM35 quiero que ande igual subiendo o bajando la T ° sin prender nada solo cambiando la temp, porque como es un sensor no depende del la temperatura seteada, pero cuando yo setee la temperatura de 25°C ahí si que prenda el relé, si en ese momento se encuentra en el margen.
6) Quiero que tenga un botón de encendido/apagado, si apago el sistema que borre la temp seteada, apagué la bomba y muestre en el LCD que está en off, pero que siga mostrando la T ° del sensor, y cuando lo encienda funcione normalmente, permitiendo ingresar la temp seteada, que cambie a ON el estado de la bomba (si la temp del sensor está en el margen), y que siga mostrando la T° del LM35 sin ningún cambio.

Problema: La parte de mostrar la temperatura del LM35 la tengo hecha, también lo de setear la T ° con el KeyPad y que tenga un margen lo hice, y lo mismo con lo de mostrar si el relé está prendido o apagado.
Ahora lo que no entiendo, es como hago para que suba y baje la temp del sensor sin prender nada y que no tenga que setear la temperatura para que yo pueda hacer que funcione, estuve pensando en hacerla una función global a void loop para que ande o llamar a MargenT (); antes que Teclado(); para que no haya ningún incoveniente pero no me anduvo ninguno.
Lo mismo me pasa con el botón porque quería hacer una función llamada OnOff () y el lcd me mostraba todo en blanco.
Les agradecería si me ayudan :)

//librerias
#include <Keypad.h>
#include <TimerOne.h>
#include <LiquidCrystal.h>

//definir nombre de pines
#define BOMBA 8

//hago un string llamado TSet
String TSet;

//configuración del teclado
const byte ROWS = 4;
const byte COLS = 3;

char hexaKeys[ROWS][COLS] = {
    {'1', '2', '3'},
    {'4', '5', '6'},
    {'7', '8', '9'},
    {'*', '0', '#'}
};

byte rowPins[ROWS] = {9, 10, 11, 12};
byte colPins[COLS] = {13, A1, A2};

Keypad myKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

//configuración para el lcd
const int rs = 7, en = 2, d4 = 3, d5 = 4, d6 = 5, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//configuración para el sensor de temperatura
float aref = 5.0;
volatile float TEMP;

void setup() 
{
  //iniciar lcd
  lcd.begin(20, 4);
  analogReference(EXTERNAL);
  //imprimo constantes
  lcd.setCursor(0, 0);
  lcd.print("Temp Sensor=");
  lcd.setCursor(0, 1);
  lcd.print("Temp Set=");
  lcd.setCursor(0, 2);
  lcd.print("Bomba=");
  //configuro E y S
  pinMode(A0, INPUT);
  pinMode(BOMBA, OUTPUT);
  //interrupcion
  Timer1.initialize(1000000);
  Timer1.attachInterrupt(MargenT);
}

void loop()
{
  //leer temp
  int lectura = analogRead(A0);
  TEMP = (lectura * (aref / 1024)) * 10;
  //TEMP = lectura;
  lcd.setCursor(13, 0);
  lcd.print(TEMP );
  delay(100);
  //teclado
  Teclado();  
}

void Teclado()
{       
  while(TSet.length() < 2) //longitud del string = 2
  {
    char key = '\0';       //borra la variable
    do 
    {
      key = myKeypad.getKey(); //leo la tecla
    } 
    while (key == NO_KEY); //si no se presiona una tecla, el while espera 
    if (isDigit(key)) //verifica si la tecla presionada es un digito (del 0 al 9)
    {
      TSet = TSet + key; //guardo la tecla presionada en el string TSet si llega a 2 digitos, salta a MargenT 
      lcd.setCursor(10, 1);
      lcd.print(TSet);
    }
  }
  MargenT();
}

void MargenT()
{
   if(TEMP <= TSet.toFloat() + 2.00)            //si TEMP es menor o igual que TSet + 2.00, también la encenderá
   {                                                 
     lcd.setCursor(7, 2); //Estado de la bomba
     lcd.print("ON ");
     digitalWrite(BOMBA, HIGH);
   }
   else
   {
     lcd.setCursor(7, 2); //Estado de la bomba
     lcd.print("OFF");
     digitalWrite(BOMBA, LOW);
   }
}

Captura de pantalla (163).png

Para que arranque aunque no fijes una temperatura con el teclado tenes que definirle un valor a TSet sino no tiene con qué comparar. Por ej. en lugar de

String TSet;

Poné

String TSet = "25";

Asi cuando lo encendes si la temperatura es menor a 27C va a arrancar el ventilador aunque no ingreses nada por el teclado (yo puse "25" como ejemplo pero vos poné el.valor que quieras).

Al margen, tendrías que haber seguido con el hilo donde ya tratabamos esto, no abrir uno nuevo. Editabas de nuevo el titulo (borrabas el "Solucionado" y listo.) ;)

Si tenés razón, pero ya lo cerraron

Y volviendo al código, no hay ninguna manera de que yo empiece con el LM35 normalmente, sin compararlo con nada, y que suba y baje la T° como lo haría en un código aparte y que después si selecciono una temp con el teclado, automáticamente entré a un void donde encienda y apague el relé

No estoy muy de acuerdo con tu código pero hay un par de cosas que te van a traer problemas.
Una ya te la dije en el otro hilo, tenes que resetear TSet porque para hacer la lectura de teclado el length de TSet tiene que ser menor que 2, hasta ahí bien. Ingresas la temperatura y el length de TSet es 2. Pero cuando vuelva a querer leer el teclado como el length de TSet ya es 2 nunca mas hace la lectura de las teclas.
Vas a tener que hacer algo así

//librerias
#include <Keypad.h>
#include <TimerOne.h>
#include <LiquidCrystal.h>

//definir nombre de pines
#define BOMBA 8

//hago un string llamado TSet
String TSet;
float tseteada = 25; // *** para fijar una T de arranque de 25C

//configuración del teclado
const byte ROWS = 4;
const byte COLS = 3;

char hexaKeys[ROWS][COLS] = {
    {'1', '2', '3'},
    {'4', '5', '6'},
    {'7', '8', '9'},
    {'*', '0', '#'}
};

byte rowPins[ROWS] = {9, 10, 11, 12};
byte colPins[COLS] = {13, A1, A2};

Keypad myKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

//configuración para el lcd
const int rs = 7, en = 2, d4 = 3, d5 = 4, d6 = 5, d7 = 6;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//configuración para el sensor de temperatura
float aref = 5.0;
volatile float TEMP;

void setup() 
{
  //iniciar lcd
  lcd.begin(20, 4);
  analogReference(EXTERNAL);
  //imprimo constantes
  lcd.setCursor(0, 0);
  lcd.print("Temp Sensor=");
  lcd.setCursor(0, 1);
  lcd.print("Temp Set=");
  lcd.setCursor(0, 2);
  lcd.print("Bomba=");
  //configuro E y S
  pinMode(A0, INPUT);
  pinMode(BOMBA, OUTPUT);
  //interrupcion
  Timer1.initialize(1000000);
  Timer1.attachInterrupt(MargenT);
}

void loop()
{
  //leer temp
  int lectura = analogRead(A0);
  TEMP = (lectura * (aref / 1024)) * 10;
  //TEMP = lectura;
  lcd.setCursor(13, 0);
  lcd.print(TEMP );
  delay(100);
  //teclado
  Teclado();  
}

void Teclado()
{ 
  TSet = ""; // *** agregado
  while(TSet.length() < 2) //longitud del string = 2
  {
    char key = '\0';       //borra la variable
    do 
    {
      key = myKeypad.getKey(); //leo la tecla
    } 
    while (key == NO_KEY); //si no se presiona una tecla, el while espera 
    if (isDigit(key)) //verifica si la tecla presionada es un digito (del 0 al 9)
    {
      TSet = TSet + key; //guardo la tecla presionada en el string TSet si llega a 2 digitos, salta a MargenT 
      lcd.setCursor(10, 1);
      lcd.print(TSet);
    }
  }
  tseteada = TSet.toFloat(); // *** agregado
  MargenT();
}

void MargenT()
{
   if(TEMP <= tseteada + 2.00) // *** cambiado           //si TEMP es menor o igual que TSet + 2.00, también la encenderá
   {                                                 
     lcd.setCursor(7, 2); //Estado de la bomba
     lcd.print("ON ");
     digitalWrite(BOMBA, HIGH);
   }
   else
   {
     lcd.setCursor(7, 2); //Estado de la bomba
     lcd.print("OFF");
     digitalWrite(BOMBA, LOW);
   }
}

Ya lo modifiqué para que arranque con una temperatura prefijada

Y decime en que parte no estás de acuerdo, total estoy para aprender. También quise hacer la parte de TSet="" pero se borraba la variable y no quedaba guardada

Ah, entonces lo que querés es al reves de lo que dijiste antes, que no arranque hasta que ingreses una temperatura.

Ahí sale el primer problema por el que no estoy de acuerdo con tu código, tu rutina de interrupción cada 1 seg. hace comparación de lo seteado con lo que te mide el LM, siempre está comparando, entonces algún valor le tenes que dar a tseteada (o TSet según el código anterior).

Otra cosa es que se complica modificarlo porque siempre tenes que estar atento a que la interrupción necesita sus datos disponibles.

Y lo que menos me gusta es que después de pulsar una tecla el código se quede esperando que pulses la 2da. indefinidamente (por eso necesitas la interrupción sino quedaría "muerto")

Eso trae otro problema, y es otra razón por lo que agregué "tseteada", cuando pulsas la primer tecla TSet es menor a 10 porque tiene un solo dígito. ¿Y si antes que pulses la 2da. hay una interrupción? Compararía con un valor menor que 10 y te apaga todo lo que estuviera encendido. ¡Chan!

Volviendo a que no haga nada hasta que ingreses una temperatura, fácil

float tseteada = -100.00;

y listo, como nunca vas a leer -100C entonces de arranque no hace nada

luciano_sch: También quise hacer la parte de TSet="" pero se borraba la variable y no quedaba guardada

Fijate el ultimo código que puse en #4, te modifique 3 o 4 lineas (y te puse comentarios de lo hice en el código) para que no pase eso.