/****************************************************************
Ejercicio 3.
La actuación tiene dos señales:
- Indicador de modo: 0 = frío, 1 = calor.
- Señal PWM que regula la cantidad de frío o calor
- Panel de control con dos pulsadores, que permiten elevar ó disminuir
la temperatura de referencia. Por defecto en el arranque es de 26ºC.
- La temperatura se lee usando la función float readTemp() que está en
la librería "sensortemperatura.h"
- Realizar un controlador PID para controlar la temperatura teniendo
en cuenta la temperatura de referencia.
- Parámetros del PID: Kp=3, Kd=0.2 y Ki=0.01
****************************************************************/
#include <Ticker.h>
//#include <sensortemperatura.h>
// Defino la funcion para no generar errores
float readTemp(void) {
return 24.0;
}
Ticker blinker; //Usado para programar el periodo de control en tiempo real
// Definicion de salidas y entradas digitales
// Salidas
#define pinPWM 25
#define pinModo 26
// Entradas
#define botonSubirRef 35
#define botonBajarRef 32
// Configuración PWM
#define PWMChannel 1
#define frequency 1000
#define resolution 10 // Se podría poner 8, pero hay que ser consecuente después
// Variables del controlador
const float Kp = 3; //Proporcional
const float Ki = 0.01; //Integral
const float Kd = 0.2; //Derivativo
// Variables para realizar el control
volatile float sn; //Acumulador
volatile float en; //Error
volatile float enOld; //Error en el instante anterior
volatile float mn; //Variable de actuacion
volatile float ref; //Referencia
//Funcion que implementa el algoritmo de control
void PIDControl() {
sn = sn + en; // Actualizo el error acumulado
mn = (Kp * en) + (Ki * sn) + (Kd * (en - enOld)); // Calculo la actuacion
enOld = en; // Actualizo la variable error anterior
}
// Funcion que genera la salida PWM y sentido
// Está realizada teniendo 10 bits de precisión (0-1023)
void Actuador() {
// Saturo la salida para la precisión seleccionada
if ((mn > 1023) || (mn < -1023)) {
ledcWrite(PWMChannel, 1023);
} else {
ledcWrite(PWMChannel, (unsigned int)abs(mn)); // Se realiza un cast a entero sin signo
}
// Determino el modo frío (0) ó calor (1)
// Si la actuación es (+), debo aumentar temperatura: modo calor (1)
// Si la actuación es (-), debo reducir temperatura: modo frío (0)
if (mn >= 0) {
digitalWrite(pinModo, HIGH);
} else {
digitalWrite(pinModo, LOW);
}
}
//Manejadores de interrupción
void onTimerISR() {
en = ref - readTemp(); // Actualizo el error actual
PIDControl(); // Realizo el control PID
Actuador(); // Actuo sobre la planta
}
// Lectura de los botones encargados de cambiar la referencia
void IRAM_ATTR ISR_bSubirRef(void) {
ref = ref + 0.5;
}
void IRAM_ATTR ISR_bBajarRef(void) {
ref = ref - 0.5;
}
// Funcion setup que se ejecuta una sola vez cuando arranca el microcontrolador
void setup() {
// Inicialización del puerto serie
Serial.begin(9600);
//Inicializacion del Timer
blinker.attach(10, onTimerISR); // Se realiza el bucle de control cada 10 segundos
// Configuración de las entradas digitales
pinMode(botonSubirRef, INPUT_PULLUP);
pinMode(botonBajarRef, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(botonSubirRef), &ISR_bSubirRef, RISING);
attachInterrupt(digitalPinToInterrupt(botonBajarRef), &ISR_bBajarRef, RISING);
// Inicialización de las salidas digitales
pinMode(pinModo, OUTPUT);
ledcSetup(PWMChannel, frequency, resolution); // Configura el canal a la frecuencia y resolución indicados
ledcAttachPin(pinPWM, PWMChannel); // Enlaza la salida digital con el canal configurado previamente
//Inicializacion de la referencia
ref = 26;
//Inicializacion variables controlador
sn = 0;
en = 0;
enOld = 0;
mn = 0;
}
// Bucle loop que se ejecutará de manera infinita
void loop() {
Serial.print("Referencia: ");
Serial.print(String(ref));
Serial.print(" Error: ");
Serial.print(String(en));
Serial.print(" Actuacion: ");
Serial.print(String(mn));
Serial.print(" Temperatura: ");
Serial.println(String(readTemp()));
delay(5000);
}