Diseño del Sistema de Control
Este documento describe la implementación de un sistema de regulación de temperatura empleando un controlador PID sobre la plataforma STM32. La solución integra la adquisición de datos, el cálculo del algoritmo de control y la visualización del estado del sistema.
Configuración del Hardware
La selección de componentes es crucial para el desempeño del sistema. A continuación se detallan los elementos principales:
| Módulo | Componente | Especificaciones Clave |
|---|---|---|
| Sensor térmico | DS18B20 | Protocolo 1-Wire, precisión ±0.5°C |
| Interfaz gráfica | LCD 128x64 (SPI) | 128x64 píxeles, controlador ST7920 |
| Procesador principal | STM32G431CB | Núcleo Cortex-M4 a 170 MHz, 1 MB Flash |
| Actuador térmico | Resistencia calefactora 500W | 24V DC, impedancia de 15Ω |
Esquema de Conexión
Circuito de medición:
DS18B20 ---[DQ]--- Resistencia 4.7kΩ --- Alimentación 3.3V
| |
+--------------------------------+--- GND
STM32 (PB6) --- Conexión al bus 1-Wire
Circuito de potencia:
STM32 (TIM2_CH1) --- Circuito driver MOSFET --- Carga térmica (resistencia)
|
+--- Diodo de protección
Conexión del display:
STM32 (SPI1) --- LCD (Señales CS, DC, RST)
Implementación del Algoritmo de Control PID
El algoritmo se estructura en una entidad que almacena los parámetros y estados necesarios para el cálculo.
typedef struct {
float ganancia_proporcional;
float ganancia_integral;
float ganancia_derivativa;
float valor_consigna;
float acumulador_integral;
float error_anterior;
float senal_control;
} ControladorPID;
void InicializarControlador(ControladorPID *ctrl) {
ctrl->ganancia_proporcional = 3.0f;
ctrl->ganancia_integral = 0.05f;
ctrl->ganancia_derivativa = 0.2f;
ctrl->acumulador_integral = 0.0f;
ctrl->error_anterior = 0.0f;
ctrl->senal_control = 0.0f;
}
float CalcularSenalPID(ControladorPID *ctrl, float medicion_actual) {
float error_actual = ctrl->valor_consigna - medicion_actual;
// Manejo de saturación del término integral
if (fabs(error_actual) > 20.0f) {
ctrl->acumulador_integral = 0.0f;
} else {
ctrl->acumulador_integral += error_actual;
}
float variacion_error = error_actual - ctrl->error_anterior;
// Ecuación del PID incremental
float resultado = ctrl->ganancia_proporcional * variacion_error +
ctrl->ganancia_integral * ctrl->acumulador_integral +
ctrl->ganancia_derivativa * variacion_error;
ctrl->error_anterior = error_actual;
// Límites de la señal de salida (PWM)
if (resultado > 100.0f) resultado = 100.0f;
if (resultado < 0.0f) resultado = 0.0f;
return resultado;
}
Obtención de Datos del Sensor DS18B20
#define PIN_DATOS GPIO_PIN_6
#define PUERTO_DATOS GPIOB
float LeerTemperaturaSensor() {
uint8_t registro_datos[9];
IniciarComunicacion1Wire(PUERTO_DATOS, PIN_DATOS);
EscribirByte1Wire(PUERTO_DATOS, PIN_DATOS, 0xCC); // Skip ROM
EscribirByte1Wire(PUERTO_DATOS, PIN_DATOS, 0x44); // Iniciar conversión
while (!LeerBit1Wire(PUERTO_DATOS, PIN_DATOS)); // Esperar fin de conversión
IniciarComunicacion1Wire(PUERTO_DATOS, PIN_DATOS);
EscribirByte1Wire(PUERTO_DATOS, PIN_DATOS, 0xCC);
EscribirByte1Wire(PUERTO_DATOS, PIN_DATOS, 0xBE); // Leer registro
for (int i = 0; i < 9; i++) {
registro_datos[i] = LeerByte1Wire(PUERTO_DATOS, PIN_DATOS);
}
int16_t lectura_cruda = (registro_datos[1] << 8) | registro_datos[0];
return lectura_cruda * 0.0625f; // Conversión a grados Celsius
}
Control de la Pantalla LCD
void ConfigurarDisplay() {
InicializarSPI();
EnviarComandoLCD(0x38); // Modo 8 bits
EnviarComandoLCD(0x0C); // Encender display
EnviarComandoLCD(0x06); // Incremento automático
BorrarPantallaLCD();
}
void MostrarEstado(float temperatura, float salida_pid) {
char linea1[20];
char linea2[20];
sprintf(linea1, "Temperatura: %.1fC", temperatura);
sprintf(linea2, "Calefactor: %.1f%%", salida_pid);
EscribirCadenaLCD(0, 0, linea1);
EscribirCadenaLCD(1, 0, linea2);
}
Rutina Principal
int main(void) {
// Inicialización de periféricos
ConfigurarRelojDelSistema();
ConfigurarGPIO();
InicializarSPI1();
ConfigurarTimerPWM();
ControladorPID mi_controlador;
InicializarControlador(&mi_controlador);
// Activar generación de PWM
IniciarPWM(&htim2, CANAL_1);
while (1) {
float temperatura_leida = LeerTemperaturaSensor();
float accion_control = CalcularSenalPID(&mi_controlador, temperatura_leida);
AjustarCicloTrabajoPWM(&htim2, CANAL_1, accion_control);
MostrarEstado(temperatura_leida, accion_control);
EsperarMilisegundos(1000); // Período de muestreo
}
}
Técnicas de Mejora del Sistema
Filtrado digital de señales:
#define TAMANO_VENTANA 5
static float historial_mediciones[TAMANO_VENTANA] = {0};
float AplicarFiltroPromedio(float nueva_muestra) {
for (int i = 1; i < TAMANO_VENTANA; i++) {
historial_mediciones[i-1] = historial_mediciones[i];
}
historial_mediciones[TAMANO_VENTANA-1] = nueva_muestra;
float suma = 0;
for (int i = 0; i < TAMANO_VENTANA; i++) {
suma += historial_mediciones[i];
}
return suma / TAMANO_VENTANA;
}
Ajuste adaptativo de parámetros:
void ActualizarParametrosAdaptativos(ControladorPID *ctrl, float error_promedio) {
static uint32_t contador_ciclos = 0;
if (++contador_ciclos >= 1000) {
contador_ciclos = 0;
if (error_promedio > 5.0f) {
ctrl->ganancia_proporcional += 0.2f;
}
if (error_promedio < 1.0f) {
ctrl->ganancia_integral += 0.01f;
}
}
}
Consideraciones de Diseño Electrónico
- Planos de alimentación: Utilizar PCB de 4 capas (Señal, GND, Poder, GND) para estabilidad.
- Filtrado de alimentación: Colocar red LC (10µH + 100nF) en la línea del sensor.
- Integridad de señales: Enrutar la línea de datos del DS18B20 con un plano de tierra contiguo.
- Disipación térmica: Incorporar isla térmica y vias de disipación bajo el MOSFET.
Procedimiento de Puesta a Punto
La sintonización del controlador se realiza siguiendo estos pasos:
- Establecer ganancias Ki y Kd en cero. Incrementar Kp hasta observar oscilaciones sostenidas.
- Aumentar Kd para amortiguar las oscilaciones.
- Ajustar Ki para eliminar el error en régimen permanente.
| Parámetro de Rendimiento | Valor Obtenido | Especificación Requerida |
|---|---|---|
| Error en estado estable | ±0.4°C | ±1°C máximo |
| Sobreimpulso | 4% | Menor al 10% |
| Tiempo de establecimiento | 28 segundos | Menor a 60 segundos |
| Consumo energético | 4.5 W | Menor a 8 W |
Funcionalidades Adicionales
Monitoreo multicanal:
#define CANTIDAD_MAXIMA_SENSORES 4
typedef struct {
float lecturas[CANTIDAD_MAXIMA_SENSORES];
uint8_t cantidad_conectados;
} RedSensores;
Interfaz de comunicación serie:
void ProcesarComandoSerie(uint8_t byte_recibido) {
if (byte_recibido == 'A') { // Comando para ajustar temperatura
float nueva_consigna = RecibirFlotantePorUART();
ActualizarConsigna(nueva_consigna);
}
}