Atender pulsación de botón mientras delay

Buenas a todos, mi problema/duda es el siguiente:

Tengo un sensor de temperatura que cuando llega a un valor paro el motor [DELAY] durante X segundos. A la vez tengo dos botones (subir y bajar) para elegir la temperatura que deseamos. El problema que me encuentro es que los botones no son atendidos hasta que no ha pasado esos X segundos.

Puedo usar para este caso los millis?? Necesito conseguir que esos X segundos se respeten y que los valores de los botones se atiendan en el momento de pulsarlos.

Espero vuestra ayuda.
Saludos!

si claro, estan para eso concretamente, para interrupciones sin detener el programa

Yo no soy partidario de las interrupciones para programas hechos con delay() que deban atender botones.
Un buen programa usando millis() atiende todo y respeta los intervalos de tiempos que has indicado.
Ve a Documentacion => Indice de temas tutoriales => millis()

Aunque Mikms te ha dado dicho que uses interrupciones, no es la forma elegante de hacerlo.

Tenemos pocas fuentes de interrupción, en tu caso dices un boton subir y otro bajar, pero y si quieres añadir un tercero para otra función... teniendo en cuenta que en un UNO tenemos solo dos... tendríamos que pasarnos a poner un MEGA o un MICRO que tienen cuatro interrupciones.

Podrías usar una libreria que te permita manejar la interrupción asociada a cada pin, pero posiblemente acabarias liado mas del todo.

La solución "elegante" es usar millis. Para estás situaciones hice un par de tutoriales que están en la sección de DOCUMENTOS.

Te dejo el enlace al tutorial Como NO leer un botón y como SI debemos hacerlo.

Me he leído el enlace que has puesto e intentado hacerlo de esa manera pero no lo consigo. Indico mejor lo que pretendo por si acaso se piensan otra cosa distinta:

El el sistema consta de un sensor de presión, un motor y dos botones.

Con los botones selecciono la presión que quiero, si es más alta que la que hay, el motor hace una cosa y si es más baja hace otra. Ahora viene lo que no me sale:

cuando alcance la presión que busco, el motor se tiene que parar X tiempo (orden de minutos) pero mientras si yo pulso los botones para elegir otra presión, éstos tienen que responder mostrándome a tiempo real la presiónque voy eligiendo.

Actualmente tengo puestos tramos de Delays pero en esos delays los botones no son atendidos obviamente.

Muestro la parte de código que afecta a lo que busco:

   if (digitalRead(arriba) == 1){
      setpres ++; 
      }
    if (digitalRead (abajo) == 1){
      setpres --;
      }
    if ((setpres == 30)||(setpres ==29)){ 
      if (presion_1 <= 2.5){
        digitalWrite (motor_izq, 0); 
        digitalWrite (motor_der, 1); 
        delay (500);
        digitalWrite (motor_der, 0); 
        delay (500);
        }
      if ((presion_1 <= 2.8)&&(presion_1>2.5)){
        digitalWrite (motor_izq, 0); 
        digitalWrite (motor_der, 1); 
        delay (1000);
        digitalWrite (motor_der, 0); 
        }
      if ((presion_1 <= 3.1)&&(presion_1>=2.9)){
        delay (20000);
        }

Ahora se entiende mejor?

Gracias de antemano!

He intentado hacerlo con los millis() del siguiente modo pero no para ni motor ni hace las pausas que hacia con delay. Los botones sí responden en tiempo real pero…

  if (digitalRead (seleccion) == 0){
    if (digitalRead(arriba) == 1){
      setpres ++; 
      temporizador = 0;
      }
    if (digitalRead (abajo) == 1){
      setpres --;
      temporizador = 0;
      }
    if ((setpres == 30)||(setpres ==29)){ 
      if (presion_1 <= 2.5){
        digitalWrite (motor_izq, 0); 
        digitalWrite (motor_der, 1); 
        temporizador = millis();
        if (millis()-temporizador >peque){
        digitalWrite (motor_der, 0); 
        temporizador = 0;
          }
        }
      if ((presion_1 <= 2.8)&&(presion_1>2.5)){
        digitalWrite (motor_izq, 0); 
        digitalWrite (motor_der, 1); 
        temporizador = millis();
        if (millis()-temporizador >medio){
        digitalWrite (motor_der, 0); 
        temporizador = 0;
          }
        }
      if ((presion_1 <= 3.1)&&(presion_1>=2.9)){
        temporizador = millis();
        if (millis()-temporizador >grande){
        digitalWrite (motor_der, 0); 
        temporizador = 0;
          }
        }  
      if(presion_1 > 3.3){ 
        digitalWrite (motor_der, 0); 
        digitalWrite (motor_izq, 1); 
        temporizador = millis();
        if (millis()-temporizador >peque){
          digitalWrite (motor_izq, 0); 
          temporizador = 0;
          }
        }
      if ((presion_1 <= 3.2)&&(presion_1>=3.3)){
        digitalWrite (motor_izq, 0); 
        digitalWrite (motor_der, 1); 
        temporizador = millis();
        if (millis()-temporizador >medio){
          digitalWrite (motor_der, 0); 
          temporizador = 0;
          }
        }
      if ((presion_1 <= 3.1)&&(presion_1>=2.9)){
        temporizador = millis();
        if (millis()-temporizador >grande){
          digitalWrite (motor_izq, 0); 
          temporizador = 0;
          }
        }
    }

donde peque, medio y grande son 3 tiempos distintos

La verdad, cuesta entenderlo.

De tu código deduzco lo siguiente.

Presion Accion
0-2.4 Gira a derechas durante un t pequeño
2.5-2.8 Gira a derechas durante un t medio
2.9-3.1 El motor para durante un t grande
3.2-3.3 Gira a izquierdas durante un t medio
3.4 o mas Gira a izquierdas durante un t pequeño

Que habla de presión… Pero en tu último post:

… tengo un sensor de temperatura …

y en tus primeros posts:

… el sistema consta de un sensor de presión …

Si me fijo en tus especificaciones puedo desarrollar un poco de código, pero claro, intenta ser especifico, por que no nos aclaras nada y nos confundes…

Voy a definir tres funciones para controlar el motor y no escribir tanto código:

void giraDerecha() {
  digitalWrite(motor_izq,0);
  digitalWrite(motor_dch,1);
}

void giraIzquierda() {
  digitalWrite(motor_izq,1);
  digitalWrite(motor_dch,0);
}

void paraMotor() {
  digitalWrite(motor_izq,0);
  digitalWrite(motor_dch,0);
}

Definiremos una variable toperacion, que será el tiempo en el que estamos operando de la secuencia con lo que valdrá ‘pequeño’, ‘medio’, ‘grande’. Usaremos una variable t para el control del tiempo transcurrido.

// Los tiempos de trabajo.
const unsigned long PEQUENO  1000
const unsigned long MEDIO    5000
const unsigned long GRANDE   10000

// Las variables de tiempo.
unsigned long toperacion;
unsigned long t;

void setup() {
}

void loop() {
  // Leemos la presion y los botones.

  // Comparamos si el tiempo transcurrido es mayor que el tiempo
  // de operacion.
  if ( millis()-t >= toperacion ) {
    // Si ha trancurrido el tiempo entramos en esta parte de código donde debemos ver la
    // presion que hay y actuar en consecuencia segun la tabla que deduje en la parte
    // superior del post.
    if ( presion < 2.4 ) {
      giraDerechas();
      toperacion = PEQUENO;
    }
    else if ( presion >= 2.5 && presion <=2.8 ) {
      giraDerechas();
      toperacion = MEDIO;
    }
    else if ( presion >=2.9 && presion <=3.1 ) {
      paraMotor();
      toperacion = GRANDE;
    }
    else if ( presion >=3.2 && presion <=3.3 ) {
       giraIzquierdas();
       toperacion = MEDIO;
    } 
    else if ( presion >= 3.4 ) {
       giraIzquierdas();
       toperacion = PEQUENO;
    }
    // Finalmente guardamos el tiempo actual, para que vaya contando
    // el tiempo transcurrido.
    t = millis();
  }
}

Con eso estas trabajando simplemente con el motor. Habria que saber de verdad si es temperatura, presion, como se fijan los valores que tu quieres…

Buenas, gracias ante todo por el tiempo dedicado!

Al principio hablé de la Tª y luego la presión pero en realidad como no es una variable que interceda en mi problema creí que no importaba mucho, simplemente que tengo que tener en cuenta distintos rangos de valores, sea de presión o Tª da igual.

Gracias por el programa! lo he adaptado a una parte del mío pero no hace nada y creo que es por tema de tiempos.

La idea es que en cada tramo, la salida se active y se desactive con los intervalos de tiempo ‘pequeno’, ‘medio’ o ‘grande’.

El caso es que cuando lo cargo, no me da salida sea la presión que sea y por lo tanto pienso que puede ser que no cuenta bien.

Adjunto mi código por si hay un fallo y no lo veo vale??

#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>

OneWire ourWire1(16);                   //Se establece el pin 2  como bus OneWire
DallasTemperature sensors1(&ourWire1); //Se declara una variable u objeto para nuestro sensor Temperatura

// Los tiempos de trabajo.
const unsigned long PEQUENO = 100;
const unsigned long MEDIO = 500;
const unsigned long GRANDE = 1000;

// Las variables de tiempo.
unsigned long toperacion;
unsigned long t;

int motor_der = 53; // Giro motor derecha
int motor_izq = 51; // Giro motor izquierda
int Presion = A0;  //Sensor conectado en el pin A0
int ResRead;       //La Lectura de la Resistencia por División de Tensión...
float setpres = 0; // Comenzamos en 0
int arriba = 5;    // Pulsador para arriba es en pin 3
int abajo = 4;     // Pulsador para abajo es en el pin 4
int seleccion = 3; // Selecciona modo de funcionamiento pin 5
LiquidCrystal lcd (8, 9, 10, 11, 12, 13); //LCD es en 8, 9, 9, 10, 11, 12, 13

  void subir() {
    digitalWrite(motor_izq,0);
    digitalWrite(motor_der,1);
    }
  void bajar() {
    digitalWrite(motor_izq,1);
    digitalWrite(motor_der,0);
    }  
  void parar() {
    digitalWrite(motor_izq,0);
    digitalWrite(motor_der,0);
    }
    
void setup() {
  pinMode (motor_der, OUTPUT); 
  pinMode (motor_izq, OUTPUT); 
  Serial.begin (9600); //configurar al monitor serial velocidad de tx y rx
  sensors1.begin();   //Se inicia el sensor temperatura
  lcd.begin (16, 2); // configurar todos los "bloques" en la pantalla
  lcd.setCursor(0,0); //establecer el cursor a la fila de la columna 0 0
  lcd.clear(); //claro la pantalla lcd
  EEPROM.read (1); // realizar la dirección de memoria eeprom o atmega328 1
  EEPROM.read (2); // realizar la dirección de memoria eeprom o atmega328 1
}



void loop() {

  int ResRead = analogRead(Presion);         
  float presion_baja = ((ResRead * (5.0 / 1023.0) * 2.98) - 1.73);
  sensors1.requestTemperatures();   
  int temp1 = sensors1.getTempCByIndex(0); 
  lcd.setCursor (0,0); 
  lcd.print (temp1); 
  lcd.print ("\337C  /  ");
  lcd.print (presion_baja,1); 
  lcd.print ("bar");
  Serial.println (temp1);  
  setpres = EEPROM.read(2); /
  delay (5); 

  if (digitalRead (seleccion) == 0){
  // Leemos la presion y los botones.
    if (digitalRead(arriba) == 1){
      setpres ++; 
      }
    if (digitalRead (abajo) == 1){
      setpres --;
      }
    if ((setpres == 30)||(setpres ==29)){ 
        // Comparamos si el tiempo transcurrido es mayor que el tiempo
        // de operacion.
        if ( millis()-t >= toperacion ) {
          // Si ha trancurrido el tiempo entramos en esta parte de código donde debemos ver la
          // presion que hay y actuar en consecuencia segun la tabla que deduje en la parte
          // superior del post.

          if ( presion_baja < 2.4 ) {
            subir();
            toperacion = GRANDE;
            parar();
            toperacion = PEQUENO;
            }
          else if ( presion_baja >= 2.5 && presion_baja <=2.8 ) {
            subir();
            toperacion = MEDIO;
            parar();
            toperacion = PEQUENO;
            }
          else if ( presion_baja >=2.9 && presion_baja <=3.1 ) {
            parar();
            toperacion = GRANDE;
            }
          else if ( presion_baja >=3.2 && presion_baja <=3.3 ) {
            bajar();
            toperacion = MEDIO;
            parar();
            toperacion = PEQUENO;
            }
          else if ( presion_baja >= 3.4 ) {
            bajar();
            toperacion = GRANDE;
            parar();
            toperacion = PEQUENO;
            }
            // Finalmente guardamos el tiempo actual, para que vaya contando
            // el tiempo transcurrido.
            t = millis();
            }
      }
    lcd.setCursor (0,1); //establecer el cursor con precisión de 0,1
    lcd.print ("---> "); 
    lcd.print ((setpres/10),1);
    lcd.print ("bares");
    lcd.print (" <---"); 
    EEPROM.write (2, setpres);
    delay (5); 
}
}

Gracias nuevamente!

Te estas olvidando de esto

int temp1 = sensors1.getTempCByIndex(0);

Tal como esta definida la lectura del DS18B20 demoras 750mseg en tomar una lectura.
Esos tiempos son los que estan conspirando con tu código.

La solución es usar una librería que lee el DS18B20 y no bloquea el flujo del loop.

Acá tienes un código donde se ve compartivamente un código que bloquea y otro que no.

Encontré esta link mira los ejemplos que dicen Asincrónicos o WaitForConversion 1 y 2.

Buenos días!

He anulado la función del temp1 por si ese fuera el fallo y el resultado es negativo, continua sin hacer nada por lo que supongo que ese no es el problema.

Creo que el problema tiene que estar en que no inicializo bien los tiempos pequeno, grande o medio y que no los pongo a cero nuevamente cuando debería y por lo tanto el programa no se entera...

Claro que no hace nada, por ejemplo:

if ( presion_baja < 2.4 ) {
  subir();
  toperacion = GRANDE;
  parar();
  toperacion = PEQUENO;
}          }

Si en el mismo if pones que se ponga en marcha y luego que pare, ¿cómo se va a mover?.

A ver si consigo entender lo que pretendes hacer.

Tienes un sensor de presión que te da una presión P. Tu pretendes que esa P valga un valor setPres que vas a modificar con los botones. El problema está en que no quieres poner el motor que varia esa presión constantemente en marcha, sino que pretendes moverlo a intervalos:

  • Un tiempo pequeño si P está muy lejos de setPres.
  • Un tiempo medio si P está “relativamente cerca” de setPres.
  • Un tiempo grande si P está cerca de setPress.

Cosa que me parece tiene que ser al revés, pero es lo que deduzco de tu código.

Lo primero que tienes que hacer es contarnos como es ese “muy lejos”, “relativamente cerca” y “cerca” del valor setPress. No vale con poner un valor fijo, ya que tu pretendes alcanzar una presión P. Me explico, si setPress vale 4.7 (lo has elegido con los botones), ¿Cuales deberian ser los valores que tenemos que usar para que el motor actue de una manera u otra?

¿Entre cada intervalo de movimiento hay una pausa? ¿la pausa es fija o de tiempo también variable?

El funcionamiento y lo que pretendo conseguir es:

Yo quiero una determinada presión (por ejemplo 2.3), entonces la elijo con 'setPress=23'. Si la presión actual es 3.0 el motor tendrá que hacer intervalos de arranque 't1' y 't2' (del orden de los milisegundos o como mucho 1 segundo), cuando vaya por 2.6 entonces esos tiempos deberán ser 't3' y 't4' y cuando llegue a 2.3 el motor parará durante t5 (que será del orden de 1-10 minutos). Durante este último tiempo, el 't5', 'setPress' cambia de valor, hasta que no hasta trascurrido ese tiempo, el motor no andará. Una vez haya pasado ese 't5' entonces volverá a calibrarse a razón del nuevo valor.

Los valores una vez que pueda ajustarlos en la práctica serán fijos pero ahora les iré asignando distintos tiempos para ajustarlo correctamente.

Sigo sin aclararme, pero supongo que será cosa mia, porque llevo unos dias que para que contar...

Tenemos por un lado un sensor de presión que nos da la presión actual. Por otro lado nosotros tenemos una presión deseada. Y tendremos un umbral en el que se ha de cumplir lo siguiente:

  • Si la presion actual es mayor que el umbral tiene que hacer la secuencia un tiempo ON t1, y un tiempo OFF t2.
  • Si la presion actual es menor o igual que el umbral pero mayor que la presión deseada estará un tiempo t3 en ON y un t4 en OFF.
  • Cuando la presion actual es la presion deseada, se para el motor y se espera un tiempo t5. transcurrido este tiempo, se vuelve a realizar el proceso con la nuevo presiondeseada.

En el ejemplo que pones umbral es 2.6, si la presión es mayor que 2.6 hará intervalos de t1-t2 y cuando sea menor o igual t3-t4, parando t5 cuando la presion sea 2.3 que es la presión deseada.

Si la presión actual es 3.0 el motor tendrá que hacer intervalos de arranque 't1' y 't2' (del orden de los milisegundos o como mucho 1 segundo), cuando vaya por 2.6 entonces esos tiempos deberán ser 't3' y 't4'

Ahora me vienen dudas:

¿Cómo definimos el umbral? Me explico, si la presion deseada ya no es 2.3 si no 2.0, entonces el valor de 2.6 que fijamos antes sigue siendo valido, o pasaria a valer 2.3
¿Qué comportamiento va a tener si la presión es inferior a la deseada? Por ejemplo la presion es 1.9 y deseamos 2.3, (que vendría a ser una presion mayor de 3.0, pero por abajo), entonces hace la secuencia t1-t2 y cuando llegue a 2.0 hara la secuencia t3-t4...

Para resolver este ejercicio hay que usar una maquina de estados. El problema está en que hay que definir las transciones entre estados bien, y sin esos datos claros, no se puede hacer nada.