Sensores de temperatura me enlentecen el programa

Pues estoy terminando un programa (para mí bastante largo, el mayor que he hecho hasta ahora) para control de una pantalla de leds para la iluminación de un acuario, con un pequeño display TFT de 2,5 pulgadas, imita los amaneceres, anocheceres, luz nocturna, control de dos alimentadores automáticos, y acabo de programar tres sensores de temperatura, temperatura ambiente, temperatura del agua (y para activar el calentador interno del acuario) y la temperatura de la pantalla de los leds de alta potencia para mantenerla por debajo de los 40 grados activando un grupo de ventiladores.

Todos los procesos están dentro de condicionales con millis para no detener el procesador, y hasta la implementación de los sensores de temperatura todo había llegado a funcionar bien.

Pero a partir del registro de temperaturas, el reloj digital que se dibuja en el display se ha "entorpecido" al mostrar los segundos, algunos se retrasan, otros se adelantan. No es problema del RTC, la hora y los minutos no se adelantan ni retrasan, además si comento simplemente la línea donde se llama al comando para obtener las temperaturas, el problema desaparece.
He comentado todas las salidas al puerto serie para ver si mejoraba el asunto, pero sigue igual.

Pongo básicamente el programa de registro de temperaturas:

void ControlTemperaturas()  //Temperatura del ambiente, apantalla de leds y del Agua
{ 
    unsigned long MillisPrevias;
    if (contador)                              //Para que lo registre una sola vez
      {
         MillisPrevias = millis(); 
         contador = false;
       }
    if ((millis() - MillisPrevias) >= 500)//Cada medio segundo (He probado diferentes tiempos)
     {
        MillisPrevias = millis();
        sensors.requestTemperatures();  //Comando para obtener las temperaturas ESTE ES EL QUE ENLENTECE
        float TAmbiente= sensors.getTempC(DirAmbiental);//Se obtiene la temperatura en °C del sensor ambiental
        float TPantalla= sensors.getTempC(DirPantalla);         //Se obtiene la temperatura en °C del sensor de la pantalla
        float TAgua    = sensors.getTempC(DirAgua);                   //Se obtiene la temperatura en °C del sensor del agua
        if (TPantalla > 59.00)                  
          {
             analogWrite(Buzzer, 255);
           }
        else if (TAgua > 29.99 || TAgua <15.00) 
          {
             analogWrite(Buzzer, 255);
           }
        else 
           {
              analogWrite(Buzzer, 0);
           }
        //Dibuja las temperaturas en el display TFT:        
        tft.setTextSize(2);
        if (TAmbiente > 29.99)  {tft.setTextColor(ROJO, NEGRO);} else {tft.setTextColor(VERDE, NEGRO);}  
        tft.setCursor(293,38);  tft.print(TAmbiente);
        if (TAgua > 26.99)      {tft.setTextColor(ROJO, NEGRO);} else {tft.setTextColor(VERDE, NEGRO);}
        tft.setCursor(293,67);  tft.print(TAgua);
        if (TPantalla > 49.99)  {tft.setTextColor(ROJO, NEGRO);} else {tft.setTextColor(VERDE, NEGRO);}
        tft.setCursor(293,96);  tft.print(TPantalla);
        tft.setTextColor(AMARILLO, NEGRO);  
        tft.setCursor(370,38);  tft.print("Grados");
        tft.setCursor(370,67);  tft.print("Grados");
        tft.setCursor(370,96);  tft.print("Grados");
    }
  } 
}

Repito, si solo comento el comando "sensors.requestTemperatures()" desaparece el problema.

¿Hay otras librerías, o comandos, o qué estoy haciendo mal?

cada DS18B20 demora 750mseg no hay forma de resolverlo.

surbyte:
cada DS18B20 demora 750mseg no hay forma de resolverlo.

Jo, ¿y no se te ocurre ningún truqillo para "engañar" al segundero?
Es que visualmente se pilla enseguida los "saltos" del segundero, y poner solo minutos y segundos no queda muy bien.

A ver qué te parece, creo que puede servir:

En la función que escribe la hora, los minutos y los segundos (con un condicional de if con millis), anular la escritura de los segundos, y cuando la sentencia que registra los segundos (RTC.second) sea cero, entrar en un if con millis que cada segundo aumente una variable local en uno y escriba el contenido de esa variable.

Creo que se verían probablemente 2 saltos, el primero entre ":00" y ":01" segundos y el segundo entre el segundo :59 y el siguiente, pero el resto serían exactos, o eso creo...

Estoy estudiando algo... simplemente cuando lo entienda te lo presentaré.

Hace tiempo inicié un programa para control de acuario, y creo que la estructura del programa, basada en objetos, estaba bastante bien conseguida. Me derrotó el maldito hardware, porque me interferían los dispositivos spi (SD y ethernet) y la pantalla lcd (también usé componentes clase bulk chinorri, lo que a buen seguro influyó bastante en el resultado, dado que fue algo meramente lúdico y no quise comprar más componentes). Uno de los problemas con los que lidié y solucioné, fue ese precisamente; además de los temporizados para amanecer/atardecer, etc. Si hay alguien interesado una colaboración que no sea tan patas con el hardware como yo, que me envíe un privado.
La solución a este problema, en todo caso, pasa por una máquina de estados. En un primer estado lanza la solicitud de lectura, en un segundo estado espera a que esté lista, y en un tercer estado se leen los sensores.

surbyte:
Estoy estudiando algo... simplemente cuando lo entienda te lo presentaré.

Ok, esperaré, mientras, voy a volver a currarme la máquina de estados como sugiere noter, que ya la estuve leyendo más de una vez y no he terminado de entenderla...

noter:
Hace tiempo inicié un programa para control de acuario, y creo que la estructura del programa, basada en objetos, estaba bastante bien conseguida. Me derrotó el maldito hardware, porque me interferían los dispositivos spi (SD y ethernet) y la pantalla lcd (también usé componentes clase bulk chinorri, lo que a buen seguro influyó bastante en el resultado, dado que fue algo meramente lúdico y no quise comprar más componentes).

Pues tengo el programa de control del acuario por ahora aparcado justamente porque sospecho que son demasiados componentes a controlar.

Por eso he decidido dividir en dos el proyecto, por un lado la pantalla de leds de alta potencia con el efecto amanecer anochecer (que con la ayuda de surbyte y de IgnoranteAbsoluto ha quedado pero que muy bien), regulación de 4 ventiladores de 12 voltios según temperatura de la pantalla de aluminio de los leds, control de 2 alimentadores automáticos (encendido programado automático y manual), registro de temperaturas del ambiente, del agua (con activación del cable calentador debajo del sustrato) y la temperatura de la pantalla para activar los ventiladores.

Utilizo un display TFT no táctil súper chinorrio, pero lleva un par de semanas encendido, por ahora sin problemas, donde muestro dos pantallas, una con todos los datos en un listado y la segunda un fondo negro con un reloj digital en el centro, y de allí el problema por el que consulto.

noter:
La solución a este problema, en todo caso, pasa por una máquina de estados. En un primer estado lanza la solicitud de lectura, en un segundo estado espera a que esté lista, y en un tercer estado se leen los sensores.

Pues como le decía más arriba a surbyte, aprovecharé la necesidad, a ver si de una vez por todas entiendo eso de la máquina de estados, jeje

Propuesta para una posible solución bastante sencilla haciendo algo semejante a lo que ha propuesto albertoG1.

Se necesita una variable de tipo byte con el "último segundo tratado", esta debería de ser estática en la función ControlTemperaturas(), para que mantenga su valor entre llamadas a la función. Con la que comparamos el segundo actual (RTC.second) y si difiere leemos las temperaturas, así estará sincronizado con el "segundero" del reloj.

Sólo habría que cambiar la función y quedaría así:

void ControlTemperaturas()  //Temperatura del ambiente, apantalla de leds y del Agua
{
    static byte segundoAnterior = 0; // Este es el último segundo "tratado", sólo se inicializa a cero una vez, el resto del tiempo mantendrá el último valor asignado, porque es "static"
    if (segundoAnterior <> RTC.second) // Verificamos si se ha cambiado de segundo con respecto al anterior
    {
        segundoAnterior = RTC.second; // Recordamos este segundo
        sensors.requestTemperatures();  //Comando para obtener las temperaturas ESTE ES EL QUE ENLENTECE
        float TAmbiente= sensors.getTempC(DirAmbiental);//Se obtiene la temperatura en °C del sensor ambiental
        float TPantalla= sensors.getTempC(DirPantalla);         //Se obtiene la temperatura en °C del sensor de la pantalla
        float TAgua    = sensors.getTempC(DirAgua);                   //Se obtiene la temperatura en °C del sensor del agua
        if (TPantalla > 59.00)
        {
             analogWrite(Buzzer, 255);
        }
        else if (TAgua > 29.99 || TAgua <15.00)
        {
             analogWrite(Buzzer, 255);
        }
        else
        {
              analogWrite(Buzzer, 0);
        }
        //Dibuja las temperaturas en el display TFT:
        tft.setTextSize(2);
        if (TAmbiente > 29.99)  {tft.setTextColor(ROJO, NEGRO);} else {tft.setTextColor(VERDE, NEGRO);} 
        tft.setCursor(293,38);  tft.print(TAmbiente);
        if (TAgua > 26.99)      {tft.setTextColor(ROJO, NEGRO);} else {tft.setTextColor(VERDE, NEGRO);}
        tft.setCursor(293,67);  tft.print(TAgua);
        if (TPantalla > 49.99)  {tft.setTextColor(ROJO, NEGRO);} else {tft.setTextColor(VERDE, NEGRO);}
        tft.setCursor(293,96);  tft.print(TPantalla);
        tft.setTextColor(AMARILLO, NEGRO); 
        tft.setCursor(370,38);  tft.print("Grados");
        tft.setCursor(370,67);  tft.print("Grados");
        tft.setCursor(370,96);  tft.print("Grados");
    }
}

Aconsejo que se llame primero a RTC.getTime() y acto seguido se pinte la hora con los segundos. Después, cuando se quiera, se llame a ControlTemperaturas() sin antes volver a llamar a RTC.getTime().

No he probado el código, ni tan siguiera sé si compila, pero espero que funcione sin problemas.

Una cosa más: no entiendo para qué el uso de la variable contador, Así que la he "eliminado" de la función.

Cuando digo que el foro es maravilloso no me equivoco. Si no hubieras tenido el problema no me habría preocupado en buscar una solución a esto, y te aseguro que lo consideré.
Bueno, leí por ahi que una alternativa es usar el DS18B20 en modo asincrónico... o sea, que se le pide que haga la lectura pero que en lugar de consumir 750mseg por cada sensor, una librería INTELIGENTE devuelve el control y AVISA cuando el sensor ha terminado y tiene nuevos datos.
Te presento tal librería, una librería ASINCRONICA que te permite no solo leer 1 sino varios sensores cuando éstos tienen nuevos datos permitiendo que tu código fluya, imagina que tuvieras milis() asi que manejalo como algo que es transparente para si.
Si hay datos, los presentas y si no, simplemente sigue con lo demas.

Librería DS18B20 Asincrónica

Ejemplos disponibles en la librería.

NOTA 1: moví mi respuesta porque no la leían.

NOTA 2: Cuando te dije y te inisití que pusiseras todo en un solo HILO mirá donde caes una y otra vez...
Porque no juntas todo y creas un hilo ACUARIO en Proyectos, explica la idea, y luego simplemente pones, links a cada consulta y de ahí sigues con todo junto asi será mas fácil para todos.
Se empieza a complicar porque justamente ahora las cosas tienen arrastre.

Bueno, ante todo gracias a IgnoranteAbsoluto, lo probaré y comento luego.

surbyte:
Te presento tal librería, una librería ASINCRONICA que te permite no solo leer 1 sino varios sensores cuando éstos tienen nuevos datos permitiendo que tu código fluya, imagina que tuvieras milis() asi que manejalo como algo que es transparente para si.
Si hay datos, los presentas y si no, simplemente sigue con lo demas.

Pues he buscado por internet librerías alternativas y no he encontrado nada, GRACIAS, la probaré, entiendo que puede ser la solución idónea.

surbyte:
NOTA 2: Cuando te dije y te inisití que pusiseras todo en un solo HILO mirá donde caes una y otra vez...
Porque no juntas todo y creas un hilo ACUARIO en Proyectos, explica la idea, y luego simplemente pones, links a cada consulta y de ahí sigues con todo junto asi será mas fácil para todos.
Se empieza a complicar porque justamente ahora las cosas tienen arrastre.

Creo que ya lo hemos discutido/comentado más de una vez, presentar un proyecto en su estado inicial, lleva a crear un post inmenso, donde página tras página se repiten conceptos que ya se plantearon en páginas anteriores, difícilmente alguien se lee un post de más de 3 páginas.
Mi idea, con todo respeto, es terminar el sketch (casi casi lo tengo) y luego comenzar un post en "proyectos", poner fotos del montaje del "invento", y poner el sketch, antes de armar todo de manera definitiva, para que algún valiente se anime a currarse las casi 600 líneas que lleva actualmente el sketch.
También es cierto que he separado las diferentes actividades del programa en funciones, lo cual de alguna manera simplifica la lectura, pero es un tostón.
Tal vez al poner todo el proyecto, se pueden separar en cuatro o cinco capítulos, con los comentarios de las dificultades y los links a los post que me insistes.

Entiendo que no estás de acuerdo en fragmentar el tema en varias partes, que es lo que he hecho, pero de esa manera he encontrado soluciones rápidas a problemas puntuales, así, encontrar el camino para seguir.

Finalmente, lo de que las cosas tienen arrastre, es cierto, pero en este post en concreto, hasta no llegar a la captura de datos para los sensores no habría surgido este tema.

De todas formas sabes que aunque soy medio rebelde en este tema, les respeto un montón, sin estas guías y comentarios sería imposible para gente como yo, tan lejos de la electrónica y con una edad que tendría que estar (mal)educando nietos, (que no tengo), JAJA.

surbyte:
Cuando digo que el foro es maravilloso no me equivoco. Si no hubieras tenido el problema no me habría preocupado en buscar una solución a esto, y te aseguro que lo consideré.
Bueno, leí por ahi que una alternativa es usar el DS18B20 en modo asincrónico... o sea, que se le pide que haga la lectura pero que en lugar de consumir 750mseg por cada sensor, una librería INTELIGENTE devuelve el control y AVISA cuando el sensor ha terminado y tiene nuevos datos.
Te presento tal librería, una librería ASINCRONICA que te permite no solo leer 1 sino varios sensores cuando éstos tienen nuevos datos permitiendo que tu código fluya, imagina que tuvieras milis() asi que manejalo como algo que es transparente para si.
Si hay datos, los presentas y si no, simplemente sigue con lo demas.

Librería DS18B20 Asincrónica

Ejemplos disponibles en la librería.

Pues ha funcionado perfectamente, es tan simple como la DallasTemperature o quizá más y no entorpece para nada el programa.
Supongo que merece que se abra un post en documentación o en la sección que corresponda para difundirla, pues creo que vale la pena.

Pienso que este post se puede poner como [SOLUCIONADO], por lo menos a mí me ha permitido llegar a la etapa final del sketch de mi proyecto de pantalla para acuario :smiley: :wink: 8)

Lo estoy preparando AlbertoG1, con lujo de detalles y comparación de tiempos.