PID, CALDERA a LEÑA, Arduino UNO y XY-LWM

Hola, buen día.

En primer lugar, destacar la amplia generosidad de toda la gente que participa en este foro. Debo decir que mis conocimientos en programación son muy escasos.

Estoy buscando ayuda para escribir un código PID que sea capaz de mantener una temperatura de (450 a 550ºC) dentro del hogar de una caldera a leña.

El lazo de control esta compuesto por : sensor de temperatura MAX 6675 y la variable a controlar es el aire de combustión suministrado por un forzador BFB1012 de 4 cables cuyo Duty Cycle lo controla un modulo xy-LPWM seteado a 25 kHz.

He construido un circuito de conexiones que adjuntare a continuación.

Agradeceria cualquier ayuda

Hay mucha información sobre el uso de la libreria PID

Este es un buen comienzo, Luis Llamas siempre explica excelentemente las cosas

Pero busca temas similares en Youtube y vuelve si tienes dudas.

Hola @elmogote

Aquí te copio un video que puede ser de tu interés:

Gracias EGRAL, un gusto

Estoy basicamente intentando leer temperatura con el siguiente codigo para implementarlo en el PID. pero no logro que lea correctamente.
Este codigo pertenece a ELECTRONOOBS

Algo tengo mal en el codigo o en la conexieon

/* Max6675 Module ==> Arduino
  • CS ==> D10
    
  • SO ==> D12
    
  • SCK ==> D13
    
  • Vcc ==> Vcc (5v)
    
  • Gnd ==> Gnd */
    
//LCD config
#include <Wire.h>#include <LiquidCrystal_I2C.h> //If you don't have the LiquidCrystal_I2C library, download it and install itLiquidCrystal_I2C lcd(0x27,20,4); //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.
/* i2c LCD Module ==> Arduino
  • SCL ==> A5
    
  • SDA ==> A4
    
  • Vcc ==> Vcc (5v)
    
  • Gnd ==> Gnd */
    
#include <SPI.h>
#define MAX6675_CS 10#define MAX6675_SO 12#define MAX6675_SCK 13
void setup() {lcd.init();lcd.backlight();
// Serial.begin (9600);}
void loop() {float temperature_read = readThermocouple();lcd.setCursor(0,0);lcd.print("TEMPERATURE");lcd.setCursor(7,1);lcd.print(temperature_read,1);delay(1000);
//Serial.print(temperature_read);// Serial.println("ºC");}
double readThermocouple() {
uint16_t v;pinMode(MAX6675_CS, OUTPUT);pinMode(MAX6675_SO, INPUT);pinMode(MAX6675_SCK, OUTPUT);
digitalWrite(MAX6675_CS, LOW);delay(1);
// Serial.print(v);// Serial.println("ºC");
// Read in 16 bits,// 15 = 0 always// 14..2 = 0.25 degree counts MSB First// 2 = 1 if thermocouple is open circuit// 1..0 = uninteresting status
v >>= 3;v |= shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
digitalWrite(MAX6675_CS, HIGH);if (v & 0x4)
{// Bit 2 indicates if the thermocouple is disconnectedreturn NAN;}
// The lower three bits (0,1,2) are discarded status bitsv >>= 3;
// The remaining bits are the number of 0.25 degree (C) countsreturn v*0.25;}

Saludos

En martes, 2 de septiembre de 2025, 14:55:16 GMT-3, ENGRAL via Arduino Forum notifications@arduino.discoursemail.com escribió:

| ENGRALSeptember 2 |

  • | - |

Hola @elmogote

Aquí te copio un video que puede ser de tu interés:

Registro de temperatura con termopar K, MAX6675, OLED y ESP32 (Micropython)

Moderador:
Por favor, lee las Normas del foro y publica/edita tu código/error usando etiquetas de código.
Ve a edición, luego selecciona todo el código que has publicado/editado, lo cortas y click en (<CODE/>)

Gracias, moderador, mil disculpas,

Saludos

Hola @elmogote

No se de donde has copiado este código, pero te sugiero (aparte de lo que te digan fuentes mas autorizadas) que lo revises a fondo.

Además, deberías copiarlo (normativamente) bien en el Foro. Tiene continuas interrupciones.

Un saludo !!:cocktail_glass::cocktail_glass:

Mil disculpas nuevamente, y agradecer el tiempo que me dedicas

El objetivo de este proyecto, tal como lo plantee desde un principio es lograr un control PID para una caldera pirolitica.

Los pasos que pretendo seguir son los siguientes:

1.- Poder leer los valores de temperatura con una zonda tipo K. a través del modulo MAX 6675. Estos valores necesito tenerlos disponibles, quizas en el puerto serie de la ID de arduino.

2.- Poder estudiar la curva de reacción en el hogar de mi caldera, induciendo un salto escalón en el caudal de aire que suministra el forzador. a fin de poder obtener los valores de Kp Ki y Kd.

3.- Poder hacer un código PID con los valores obtenidos.

4.- Enviar la señal de control al ventilador para corregir el error a través del modulo ZY-LPWM que trabaja con 12 Voltios de alimentación y PWM 25 KHz.

Bueno, este es mi plan de trabajo, por ahora estoy solo intentando estudiar y lograr el primer objetivo.

Saludos

El código está mal adjuntado, casi imposible de leer.

Desconfía de un código que incluye una librería que luego no usa, en este caso "SPI". Demuestra que el autor no prestó mucha atención a lo que hizo.

Como para arrancar te sugiero que uses la librería MAX6675 de Adafruit (la instalas desde el administrador de librerías) y pruebes un código de ejemplo de la misma para comprobar el funcionamiento de la sonda.

Hola MaximoEsfuerzo, Solo quiero saber si eta bien adjuntado. Gracias

Te dejo el enlace desde donde saque el código. https://www.youtube.com/watch?v=NVwsOzVxZAk

Decirte también que con la librería del MAX6675, si puedo leer perfectamente la zonda K. Pero desearía saber donde esta el error en el código siguiente y espero que este bien adjuntado.

Un saludo y gracias

[code]
/*    Max6675 Module  ==>   Arduino
 *    CS              ==>     D10
 *    SO              ==>     D12
 *    SCK             ==>     D13
 *    Vcc             ==>     Vcc (5v)
 *    Gnd             ==>     Gnd      */

//LCD config
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>    //If you don't have the LiquidCrystal_I2C library, download it and install it
LiquidCrystal_I2C lcd(0x3f,20,4);  //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.

/*    i2c LCD Module  ==>   Arduino
 *    SCL             ==>     A5
 *    SDA             ==>     A4
 *    Vcc             ==>     Vcc (5v)
 *    Gnd             ==>     Gnd      */

#include <SPI.h>

#define MAX6675_CS   10
#define MAX6675_SO   12
#define MAX6675_SCK  13

void setup() {
  lcd.init();
  lcd.backlight();
}

void loop() {
  float temperature_read = readThermocouple(); 
  lcd.setCursor(0,0);
  lcd.print("TEMPERATURE");
  lcd.setCursor(7,1);  
  lcd.print(temperature_read,1);    
  delay(300);
}


double readThermocouple() {

  uint16_t v;
  pinMode(MAX6675_CS, OUTPUT);
  pinMode(MAX6675_SO, INPUT);
  pinMode(MAX6675_SCK, OUTPUT);
  
  digitalWrite(MAX6675_CS, LOW);
  delay(1);

  // Read in 16 bits,
  //  15    = 0 always
  //  14..2 = 0.25 degree counts MSB First
  //  2     = 1 if thermocouple is open circuit  
  //  1..0  = uninteresting status
  
  v = shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
  v <<= 8;
  v |= shiftIn(MAX6675_SO, MAX6675_SCK, MSBFIRST);
  
  digitalWrite(MAX6675_CS, HIGH);
  if (v & 0x4) 
  {    
    // Bit 2 indicates if the thermocouple is disconnected
    return NAN;     
  }

  // The lower three bits (0,1,2) are discarded status bits
  v >>= 3;

  // The remaining bits are the number of 0.25 degree (C) counts
  return v*0.25;
}
[/code]

El código original ya lo había visto, de ahí mi comentario.

Básicamente el código de lectura es como el de la librería salvo que aquí usa shiftin() para leer los datos, Tal vez ese sea el error.

Yo no me rompería la cabeza y usaría la librería que ya está hiper probada y apenas ocupa unos pocos bytes más que esta implementación.

Voy a intentar corregir. Espero poder hacerlo por que me cuesta muchísimo escribir códigos. Dado mis escasos recursos en lenguajes de programación. Debo decir que antes de molestar al foro estuve siguiendo cursos online de programación en Arduino. Esto me ayudo mucho, pero veo que no es suficiente. Seguiré intentando, un abrazo

Probá este código (lo modifiqué para que trabaje con la librería)

/*    Max6675 Module  ==>   Arduino
 *    CS              ==>     D10
 *    SO              ==>     D12
 *    SCK             ==>     D13
 *    Vcc             ==>     Vcc (5v)
 *    Gnd             ==>     Gnd      */

//LCD config
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>    //If you don't have the LiquidCrystal_I2C library, download it and install it
LiquidCrystal_I2C lcd(0x3f,20,4);  //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.

/*    i2c LCD Module  ==>   Arduino
 *    SCL             ==>     A5
 *    SDA             ==>     A4
 *    Vcc             ==>     Vcc (5v)
 *    Gnd             ==>     Gnd      */

#include <max6675.h>

#define MAX6675_CS   10
#define MAX6675_SO   12
#define MAX6675_SCK  13


MAX6675 thermocouple(MAX6675_SCK, MAX6675_CS, MAX6675_SO);

void setup() {
  lcd.init();
  lcd.backlight();
}

void loop() {
  float temperature_read = thermocouple.readCelsius(); 
  lcd.setCursor(0,0);
  lcd.print("TEMPERATURE");
  lcd.setCursor(7,1);  
  lcd.print(temperature_read,1);    
  delay(300);
}

Asegurate de instalar la librería de Adafruit, creo que figura como max6675_library en el administrador, no lo puedo verificar porque me cortaron la luz :face_with_symbols_on_mouth: y estoy respondiendo desde el móvil.

Hola Máximo, Espero que tengas luz,:sun_with_face:

Funciona muy bien. Salvo que en la linea de código

LiquidCrystal_I2C lcd(0x3f,20,4);

en vez de (0x3f,20,4) va de la siguiente manera

LiquidCrystal_I2C lcd(0x27,20,4);

Ahora ya tengo el sensor funcionando. Intentare hacer el PID y te comento como me va

Saludos, gracias por tu aporte muy valioso

Editado por Moderador.
Aunque sea una línea de código debe ir con etiquetas.

Así está en el código que adjuntaste en #10. :wink:

Gracias, perdón no lo sabia

Saludos