Aunque parezca obvio, no es lo mismo:
PREV_MILLIS = CURRENT_MILLIS;
... que:
PREV_MILLIS += 1000;
¿Pero, a efectos prácticos, cuál es la diferencia?
La diferencia es que en el primer caso nos aseguramos que siempre transcurre al menos el tiempo deseado (1000 milisegundos en este caso) entre la asignación de PREV_MILLIS y el que se cumpla la condición de tiempo transcurrido, ya que "el contador de tiempo parte desde el instante actual (CURRENT_MILLIS)", sin importar cuánto tiempo había pasado desde el instante anterior. Con ello nos aseguramos que al menos han pasado los 1000 milisegundos. Eso significa que podría haber sido más de 1000 milisegundos (y seguramente habrán sido más de 1000) con lo que poco a poco tendremos "perdidas de tiempo" y el contador de segundos se retrasará. Que es lo que te estaba pasando porque el delay() hace que el tiempo entre comparación y comparación sea algo superior a 1000 milisegundos (las instrucciones, aunque poco, tardan su tiempo en realizarse).
Esta forma de controlar los millis() viene bien cuando nos queremos asegurar de que el "evento" no se realiza antes del tiempo estipulado y es preferible que se realice más tarde. Por ejemplo, en tu caso podría ser el leer la temperatura. No queremos que entre lectura y lectura de temperatura pase menos de, por ejemplo, 500 milisegundos (podría ser tu caso, pero no lo es porque los millis() los estas usando para otra cosa, y estás usando el delay() para la temperatura).
En el segundo caso puede que transcurra más o menos tiempo del deseado (1000 milisegundos en este caso) entre la "actualización" de PREV_MILLIS y el que se cumpla la condición de tiempo transcurrido. No importa si transcurre menos de 1000 milisegundos o más de 1000 milisegundos, lo que nos importa es controlar que "salte" una vez por cada 1000 milisegundos que hayan pasado. Porque lo que queremos es contar de 1000 en 1000 los milisegundos transcurridos para saber lo más exactamente posible el "tiempo total" transcurrido. Esto es lo que se busca en este caso.
Tu caso sería un ejemplo práctico para usar ambos. Ya que por un lado se desea asegurar que siempre transcurra un tiempo mínimo entre consulta y consulta de la temperatura porque si se hacen dos demasiado rápidas falla la lectura. Y por otro lado se desea contar lo más exactamente posible el tiempo total transcurrido. Así que vamos a aprovechar lo que tienes para ejemplificar los dos casos. El que controla el tiempo transcurrido lo dejamos con los dos cambios que señaló noter y añadamos otro PREV_MILLIS_TEMPERATURA para quitarnos el delay() y controlar con millis() que el tiempo transcurrido entre lectura y lectura de temperatura es, como mínimo, de 500 milisegundos.
En programa llamaba a ktc.readCelsius() para mostrarse la temperatura y "casi al instante" vuelvía a llamar a ktc.readCelsius() dentro de la función control_actuador(). Así que para evitarlo he modificado la función y ahora recibe la temperatura, que leo una vez y se usa también para mostrar su valor.
#define ST_TEMP A0
#define ST_TIME A1
#define START A2
#define STOP A3
#define LED_SET A4
#define KTC_SO 2
#define KTC_CS 3
#define KTC_CLK 4
#define LED_PRO 5
#define BUZZER 6
#define LCD_RS 7
#define LCD_EN 8
#define LCD_D4 9
#define LCD_D5 10
#define LCD_D6 11
#define LCD_D7 12
#define SSR 13
byte termo[8] = {
B00100,
B01010,
B01010,
B01110,
B01110,
B11111,
B11111,
B01110
};
byte reloj[8] = {
0b00000,
0b10101,
0b01110,
0b10001,
0b10101,
0b10001,
0b01110,
0b00000
};
byte arrowr[] = {
B00000,
B01000,
B00100,
B11110,
B00100,
B01000,
B00000,
B00000
};
unsigned int setpoint_temp;
unsigned int tiempo, cont = 0;
unsigned int display_time = 0;
unsigned long PREV_MILLIS = 0;
unsigned long PREV_MILLIS_TEMPERATURA = 0; // <-- para controlar el tiempo de lectura de temperatura
const int FALSE = 0;
const int TRUE = 1;
short FLAG_STOP = 0;
char buffer[16];
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
MAX6675 ktc(KTC_CLK, KTC_CS, KTC_SO);
void setup() {
digitalWrite(START, HIGH); // Habilita Pullup Interna
digitalWrite(STOP, HIGH); // Habilita Pullup Interna
digitalWrite(A5, HIGH); // Habilita Pullup Interna
digitalWrite(A6, HIGH); // Habilita Pullup Interna
digitalWrite(A7, HIGH); // Habilita Pullup Interna
digitalWrite(KTC_SO, HIGH); // Habilita Pullup Interna
pinMode(BUZZER, OUTPUT);
pinMode(LED_PRO, OUTPUT);
pinMode(SSR, OUTPUT);
pinMode(LED_SET, OUTPUT);
lcd.begin(16, 2);
mensaje_bienvenida();
lcd.clear();
lcd.createChar(0, arrowr);
lcd.createChar (1, termo);
lcd.createChar (2, reloj);
while (digitalRead(START) || tiempo == 0)
{
setpoint_temp = analogRead(ST_TEMP) * 0.1956;
display_temp(setpoint_temp);
display_temp_act();
tiempo = analogRead(ST_TIME) * 0.176;
display_tiempo();
display_tiempo_act();
}
lcd.clear();
digitalWrite(LED_PRO, HIGH); // APAGA INDICADOR MODO SET POINT
}
void mensaje_bienvenida() {
lcd.clear();
lcd.setCursor(1, 0); // 1-0
lcd.print("...");
lcd.setCursor(5, 1);
lcd.print("...");
delay(2000);
lcd.clear();
}
void loop()
{
CURRENT_MILLIS_TEMPERATURA = millis() - 500; // <-- Lo ponemos 500 milisegundos en el "pasado" para forzar la lectura de la temperatura
PREV_MILLIS = millis(); // <-- Inicializamos la "cuenta total" de tiempo
while (FLAG_STOP == FALSE)
{
unsigned long CURRENT_MILLIS = millis();
if (CURRENT_MILLIS - PREV_MILLIS_TEMPERATURA >= 500)
{
unsigned int temperatura = ktc.readCelsius();
PREV_MILLIS_TEMPERATURA = CURRENT_MILLIS; // <-- Nos queremos asegurar que transcurran al menos 500 milisegundos
display_temp(temperatura);
display_tiempo();
control_actuador(temperatura);
}
if (CURRENT_MILLIS - PREV_MILLIS >= 1000)
{
tiempo--;
PREV_MILLIS += 1000; // <-- Queremos que decremente tiempo por cada 1000 milisegundos transcurridos
}
if (!digitalRead(STOP) || (tiempo == 0))
{
FLAG_STOP = TRUE;
}
}
while (FLAG_STOP)
{
digitalWrite(SSR, LOW); // APAGA EL SSR
digitalWrite(LED_PRO, LOW); // APAGA INDICADOR PROCESO
final_proceso();
lcd.clear();
while (digitalRead(START) || tiempo == 0)
{
setpoint_temp = analogRead(ST_TEMP) * 0.1956;
display_temp(setpoint_temp);
display_temp_act();
tiempo = analogRead(ST_TIME) * 0.176;
display_tiempo();
display_tiempo_act();
}
lcd.clear();
digitalWrite(LED_PRO, HIGH); // ACTIVA INDICADOR MODO PROCESO
FLAG_STOP = FALSE;
// delay(100); // ADD
}
}
void display_temp(int cache_temp) {
lcd.setCursor(0, 0);
lcd.print("SENSOR");
lcd.setCursor(12, 0);
sprintf(buffer, "%u%c ", cache_temp, 0xDF);
lcd.print(buffer);
lcd.setCursor(10, 0); // ADD arrowr
lcd.write((byte)0);// ADD arrowr
}
void display_temp_loop(int cache_temp_set, int cache_temp_actual) {
lcd.setCursor(0, 0);
sprintf(buffer, "S:%d%cC ACT:%u%c ", cache_temp_set, 0xDF, cache_temp_actual, 0xDF);
lcd.print(buffer);
}
void display_tiempo() {
unsigned int minuto, segundo;
lcd.setCursor(0, 1);
minuto = tiempo / 60;
segundo = tiempo % 60;
lcd.print("TIEMPO");
lcd.setCursor(12, 1);
sprintf(buffer, "%u:%0.2u ", minuto, segundo);
lcd.print(buffer);
lcd.setCursor(10, 1); // ADD arrowr
lcd.write((byte)0); // ADD arrowr
}
void final_proceso() {
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("PROCESO");
lcd.setCursor(3, 1);
lcd.print("FINALIZADO");
digitalWrite(LED_PRO, LOW);
digitalWrite(LED_SET, LOW);
digitalWrite(SSR, LOW);
digitalWrite(BUZZER, HIGH);
delay(1000);
digitalWrite(BUZZER, LOW);
}
void display_temp_act()
{
lcd.setCursor(0, 0);
lcd.print("SP TEMP");
lcd.setCursor(10, 0);
lcd.write((byte)1);// termo ADD
}
void display_tiempo_act()
{
lcd.setCursor(0, 1);
lcd.print("ST TIEMPO");
lcd.setCursor(10, 1);
lcd.write((byte)2); // reloj ADD
}
void control_actuador(unsigned int temperatura)
{
if (temperatura >= setpoint_temp)
{
digitalWrite(SSR, LOW);
digitalWrite(LED_SET, LOW);
}
else
{
digitalWrite(SSR, HIGH);
digitalWrite(LED_SET, HIGH);
}
}
No lo he probado, así que no descarto fallos. Espero que sirva para ilustrar lo que he querido explicar.
Nota: he quitado líneas que habían comentadas porque el post era demasiado grande.
Nota2: he corregido el código, que accidentalmente lo puse sin cambios.