#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Definición de pines
#define BUTTON_C 15
#define BUTTON_F 4
#define BUTTON_K 16
#define BUTTON_MODE 17
#define BUTTON_SAVE 18
#define LED_ALARM 32
#define LED_FULL 33
#define POT_PIN 34
#define ONE_WIRE_BUS 5
// Configuración del display OLED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Configuración del sensor
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Estructura para rangos de temperatura
struct TempRange {
float min;
float max;
};
// Rangos predeterminados para cada unidad
TempRange tempRanges[] = {
{0, 100}, // Celsius
{32, 212}, // Fahrenheit
{273.15, 373.15} // Kelvin
};
// Variables globales
enum TempUnit { CELSIUS, FAHRENHEIT, KELVIN };
enum DisplayMode { MEDICION, HISTORIAL, REFERENCIA, RANGO_MIN, RANGO_MAX };
// Variables para el manejo de interrupciones
volatile TempUnit currentUnit = CELSIUS;
volatile DisplayMode currentMode = MEDICION;
volatile bool saveRequested = false;
volatile bool modeChangeRequested = false;
volatile bool unitChangeRequested = false;
volatile TempUnit requestedUnit = CELSIUS;
// Variables para control de debounce
volatile unsigned long lastModeInterruptTime = 0;
volatile unsigned long lastUnitInterruptTime = 0;
volatile unsigned long lastSaveInterruptTime = 0;
const unsigned long DEBOUNCE_TIME = 200; // 200ms de debounce
// Variables normales
float tempHistory[5] = {0.00, 0.00, 0.00, 0.00, 0.00};
float referenceTemp = 50.0;
float currentTemp = 0.0;
float userRangeMin = 0.0;
float userRangeMax = 100.0;
float tempRefSet = 50.0;
// Función para convertir temperatura entre unidades
float convertTemperature(float temp, TempUnit fromUnit, TempUnit toUnit) {
float tempC;
switch(fromUnit) {
case CELSIUS: tempC = temp; break;
case FAHRENHEIT: tempC = (temp - 32) * 5.0/9.0; break;
case KELVIN: tempC = temp - 273.15; break;
}
switch(toUnit) {
case CELSIUS: return tempC;
case FAHRENHEIT: return (tempC * 9.0/5.0) + 32;
case KELVIN: return tempC + 273.15;
default: return tempC;
}
}
String getUnitSymbol(TempUnit unit) {
switch(unit) {
case CELSIUS: return "C";
case FAHRENHEIT: return "F";
case KELVIN: return "K";
default: return "C";
}
}
void saveTemperature() {
if(currentMode == REFERENCIA && saveRequested) {
tempRefSet = referenceTemp;
}
else if(currentMode == RANGO_MIN && saveRequested) {
userRangeMin = referenceTemp;
}
else if(currentMode == RANGO_MAX && saveRequested) {
if(referenceTemp > userRangeMin) {
userRangeMax = referenceTemp;
}
}
else {
// Guardar en historial
for(int i = 4; i > 0; i--) {
tempHistory[i] = tempHistory[i-1];
}
tempHistory[0] = currentTemp;
}
}
// ISRs para todos los botones
void IRAM_ATTR buttonCISR() {
unsigned long currentTime = millis();
if (currentTime - lastUnitInterruptTime > DEBOUNCE_TIME) {
requestedUnit = CELSIUS;
unitChangeRequested = true;
lastUnitInterruptTime = currentTime;
}
}
void IRAM_ATTR buttonFISR() {
unsigned long currentTime = millis();
if (currentTime - lastUnitInterruptTime > DEBOUNCE_TIME) {
requestedUnit = FAHRENHEIT;
unitChangeRequested = true;
lastUnitInterruptTime = currentTime;
}
}
void IRAM_ATTR buttonKISR() {
unsigned long currentTime = millis();
if (currentTime - lastUnitInterruptTime > DEBOUNCE_TIME) {
requestedUnit = KELVIN;
unitChangeRequested = true;
lastUnitInterruptTime = currentTime;
}
}
void IRAM_ATTR buttonModeISR() {
unsigned long currentTime = millis();
if (currentTime - lastModeInterruptTime > DEBOUNCE_TIME) {
modeChangeRequested = true;
lastModeInterruptTime = currentTime;
}
}
void IRAM_ATTR saveButtonISR() {
unsigned long currentTime = millis();
if (currentTime - lastSaveInterruptTime > DEBOUNCE_TIME) {
saveRequested = true;
lastSaveInterruptTime = currentTime;
}
}
// Función para procesar los cambios solicitados por interrupciones
void processInterruptRequests() {
if (unitChangeRequested) {
currentUnit = requestedUnit;
unitChangeRequested = false;
}
if (modeChangeRequested) {
currentMode = static_cast<DisplayMode>((currentMode + 1) % 5);
modeChangeRequested = false;
}
if (saveRequested) {
saveTemperature();
saveRequested = false;
}
}
bool isOutOfRange(float temp) {
float convertedTemp = convertTemperature(temp, CELSIUS, currentUnit);
return (convertedTemp < userRangeMin || convertedTemp > userRangeMax);
}
bool isAbove80Percent() {
float currentRange = userRangeMax - userRangeMin;
float threshold = userRangeMin + (currentRange * 0.8);
float convertedTemp = convertTemperature(currentTemp, CELSIUS, currentUnit);
return convertedTemp > threshold;
}
float readStabilizedPot() {
const int numReadings = 10;
float total = 0;
for(int i = 0; i < numReadings; i++) {
total += analogRead(POT_PIN);
delay(1);
}
return total / numReadings;
}
float mapPotValueToTemp(float potValue, float minTemp, float maxTemp) {
return map(potValue, 0, 4095, minTemp * 100, maxTemp * 100) / 100.0;
}
// Funciones de display
void displayMedicion() {
display.setCursor(0, 0);
display.println("MEDICION");
display.setTextSize(2);
display.setCursor(4, 18);
float displayTemp = convertTemperature(currentTemp, CELSIUS, currentUnit);
display.print(displayTemp, 2);
display.print(" ");
display.print(getUnitSymbol(currentUnit));
if(isOutOfRange(currentTemp)) {
display.setTextSize(1);
display.setCursor(4, 45);
display.println("FUERA DE RANGO");
}
display.setTextSize(1);
display.setCursor(4, 55);
display.print("Ref: ");
display.print(convertTemperature(tempRefSet, CELSIUS, currentUnit), 1);
display.print(getUnitSymbol(currentUnit));
}
void displayHistorial() {
display.setCursor(0, 0);
display.setTextSize(1);
display.println("HISTORIAL");
for(int i = 0; i < 5; i++) {
display.setCursor(4, 12 + (i * 10));
float displayTemp = convertTemperature(tempHistory[i], CELSIUS, currentUnit);
display.print(displayTemp, 2);
display.print(" ");
display.print(getUnitSymbol(currentUnit));
}
}
void displayReferencia() {
display.setCursor(0, 0);
display.setTextSize(1);
display.println("REFERENCIA");
display.setTextSize(2);
display.setCursor(4, 18);
display.print(referenceTemp, 2);
display.print(" ");
display.print(getUnitSymbol(currentUnit));
display.setTextSize(1);
display.setCursor(4, 45);
display.print("SET: ");
display.print(convertTemperature(tempRefSet, CELSIUS, currentUnit), 1);
display.print(getUnitSymbol(currentUnit));
}
void displayRangoMin() {
display.setCursor(0, 0);
display.setTextSize(1);
display.println("RANGO MINIMO");
display.setTextSize(2);
display.setCursor(4, 18);
display.print(referenceTemp, 2);
display.print(" ");
display.print(getUnitSymbol(currentUnit));
display.setTextSize(1);
display.setCursor(4, 45);
display.print("SET: ");
display.print(convertTemperature(userRangeMin, CELSIUS, currentUnit), 1);
display.print(getUnitSymbol(currentUnit));
}
void displayRangoMax() {
display.setCursor(0, 0);
display.setTextSize(1);
display.println("RANGO MAXIMO");
display.setTextSize(2);
display.setCursor(4, 18);
display.print(referenceTemp, 2);
display.print(" ");
display.print(getUnitSymbol(currentUnit));
display.setTextSize(1);
display.setCursor(4, 45);
display.print("SET: ");
display.print(convertTemperature(userRangeMax, CELSIUS, currentUnit), 1);
display.print(getUnitSymbol(currentUnit));
}
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
switch(currentMode) {
case MEDICION: displayMedicion(); break;
case HISTORIAL: displayHistorial(); break;
case REFERENCIA: displayReferencia(); break;
case RANGO_MIN: displayRangoMin(); break;
case RANGO_MAX: displayRangoMax(); break;
}
display.display();
}
void setup() {
// Configuración de pines
pinMode(BUTTON_C, INPUT_PULLUP);
pinMode(BUTTON_F, INPUT_PULLUP);
pinMode(BUTTON_K, INPUT_PULLUP);
pinMode(BUTTON_MODE, INPUT_PULLUP);
pinMode(BUTTON_SAVE, INPUT_PULLUP);
pinMode(LED_ALARM, OUTPUT);
pinMode(LED_FULL, OUTPUT);
// Configuración de interrupciones
attachInterrupt(digitalPinToInterrupt(BUTTON_C), buttonCISR, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_F), buttonFISR, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_K), buttonKISR, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_MODE), buttonModeISR, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_SAVE), saveButtonISR, FALLING);
// Inicialización del display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.clearDisplay();
// Inicialización del sensor
sensors.begin();
Serial.begin(115200);
}
void loop() {
// Procesar las solicitudes de interrupciones
processInterruptRequests();
// Lectura de temperatura
sensors.requestTemperatures();
currentTemp = sensors.getTempCByIndex(0);
// Control del LED de alarma
digitalWrite(LED_ALARM, currentTemp >= tempRefSet ? HIGH : LOW);
// Lectura y mapeo del potenciómetro según el modo
float potValue = readStabilizedPot();
switch(currentMode) {
case REFERENCIA:
referenceTemp = mapPotValueToTemp(potValue, 0, 100);
break;
case RANGO_MIN:
referenceTemp = mapPotValueToTemp(potValue, -25, 0);
break;
case RANGO_MAX:
referenceTemp = mapPotValueToTemp(potValue, 0, 100);
break;
default:
break;
}
// Control del LED FULL
if (isAbove80Percent()) {
digitalWrite(LED_FULL, !digitalRead(LED_FULL));
} else {
digitalWrite(LED_FULL, LOW);
}
updateDisplay();
delay(100); // Delay para no sobrecargar el display
}Loading
ds18b20
ds18b20