YOUR CART
- No products in the cart.
Subtotal:
$0.00
BEST SELLING PRODUCTS
En RITSA Electrónica desarrollamos un proyecto innovador: un termómetro infrarrojo digital basado en el microcontrolador ESP32-C3 y el sensor MLX90614, ideal para medir la temperatura corporal o de objetos sin contacto.
Este dispositivo cuenta con:
📟 Pantalla OLED SSD1306 para mostrar la temperatura en °C y °F en tiempo real.
🌐 Conexión WiFi para visualizar gráficas en una página web futurista.
🔋 Batería recargable 18650 con módulo TP4056, diseñado para portabilidad.
🎮 Incluso incorpora un mini-juego tipo Dino de Chrome cuando no está midiendo.
Su diseño estilo pistola de temperatura se fabricó con impresión 3D en PLA, garantizando practicidad y bajo costo.
👉 Este proyecto combina electrónica, programación y diseño 3D, y es perfecto para aplicaciones educativas, makers o como base para desarrollos médicos y de IoT.
Este proyecto nació en un momento en el que medir la temperatura sin contacto se volvió parte de la vida diaria. Durante la pandemia, los termómetros infrarrojos se hicieron indispensables, pero la mayoría eran dispositivos costosos, cerrados y poco accesibles para quienes querían aprender o experimentar con ellos.
Con la pasión por la electrónica y el espíritu maker, decidimos crear nuestro propio medidor de temperatura infrarrojo, combinando la precisión del sensor MLX90614 con la versatilidad del microcontrolador ESP32-C3. Desde el inicio, la idea no fue solo tener un termómetro funcional, sino también un proyecto educativo y abierto, capaz de inspirar a estudiantes, aficionados y creadores.
El camino comenzó con pruebas sencillas en el monitor serial, hasta llegar a mostrar las lecturas en una pantalla OLED SSD1306. Luego vino la etapa más retadora: diseñar una interfaz web futurista, que permitiera ver gráficas en tiempo real desde cualquier dispositivo conectado al WiFi del termómetro. Finalmente, sumamos un detalle divertido: un minijuego estilo Dino de Chrome, que aparece cuando el dispositivo no está midiendo.
El resultado es un prototipo único: portátil, recargable y fabricado con impresión 3D en PLA en nuestra impresora Ender 3. Más que un simple termómetro, este proyecto es una mezcla de electrónica, programación, diseño 3D y creatividad.
Hoy lo compartimos como un aporte a la comunidad, porque creemos que la innovación debe ser accesible para todos. Y lo mejor es que este es solo el comienzo: queremos seguir evolucionando el diseño, añadir nuevas funciones, conectarlo a la nube e incluso convertirlo en un kit educativo para quienes sueñan con crear sus propios dispositivos inteligentes.
Arquitectura general (bloques):
ESP32-C3 SuperMini (MCU principal)
MLX90614 (termómetro IR, interfaz I²C)
OLED SSD1306 0.96″ (display I²C, 128×64)
TP4056 (cargador Li-ion 1S) + Batería 18650 (3.7 V nominal)
Botón momentáneo (entrada de usuario)
Interconexión principal (I²C compartido):
SDA = GPIO5 (ESP32-C3) → SDA (MLX90614 y OLED)
SCL = GPIO6 (ESP32-C3) → SCL (MLX90614 y OLED)
3V3 (ESP32-C3) → VDD (MLX90614) y VCC (OLED)
GND común entre todos los módulos
Nota de pull-ups I²C: la mayoría de módulos SSD1306 y/o MLX90614 traen resistencias pull-up de 4.7 k–10 k en SDA/SCL. Si ambos las traen, la resistencia equivalente disminuye (paralelo). Para buses cortos funciona bien; si observás ruido o clock stretching, dejá pull-ups solo en un módulo (típicamente el OLED).
Entrada de usuario (botón):
GPIO10 configurado con INPUT_PULLUP
Botón entre GPIO10 y GND (activo en bajo).
Se aplica antirrebote por software y detección de pulsación corta/larga.
Alimentación y gestión de energía:
TP4056
IN+ / IN-: 5 V (USB) / GND (para carga)
BAT+ / BAT-: a la batería 18650
Alimentación del ESP32-C3
Si tu placa SuperMini tiene regulador en VIN (5 V→3.3 V): conectá BAT+ a VIN (o a 5V según serigrafía), BAT- a GND.
Si tu placa NO tiene regulador en VIN (o querés minimizar pérdidas): conectá BAT+ a 3V3 solo si la placa lo admite (muchas SuperMini lo permiten), BAT- a GND. Tené en cuenta que el rango de la batería (≈4.2→3.2 V) debe permanecer dentro del rango operativo del regulador/LDO de tu módulo o del SoC; si no estás seguro, utilizá un step-up/step-down (ej. MP1584/TP5400 o buck-boost 3.3 V).
Decoupling: colocar 100 nF cerca de VDD de cada módulo + 10 µF en la línea de 3.3 V para absorber picos de corriente del Wi-Fi.
Retorno común: todas las tierras deben confluir a un GND común para evitar lazos de masa.
EMI / integridad de señal (recomendado):
Mantener SDA/SCL cortos (<20 cm) y enrutados juntos.
Si el bus supera 20–30 cm, usar 100 Ω en serie por línea y/o pull-ups más suaves (~10 k) para reducir overshoot.
Separar el lazo de carga (TP4056) del plano digital cuando sea posible.
Resumen funcional
Inicializa I²C en GPIO5 (SDA) y GPIO6 (SCL).
Lee temperatura de objeto y ambiente del MLX90614.
Aplica filtro media móvil para estabilidad de lecturas.
Muestra °C y °F en la OLED en tiempo real.
Botón en GPIO10 (pull-up interno)
pulsación corta: congela/descongela lectura (hold)
pulsación larga (>1.2 s): conmuta modo de refresco (rápido/lento)
Librerías requeridas (instalar desde Library Manager):
Adafruit MLX90614 Library
Adafruit SSD1306
+ Adafruit GFX Library
Selección de placa (Arduino IDE):
Board: ESP32C3 Dev Module (o la que corresponda a tu SuperMini)
Upload speed: 921600 (opcional)
Flash: por defecto de tu módulo
USB CDC On Boot: Enabled (en algunos cores)
Si tu OLED usa dirección distinta de
0x3C
, ajustala en el código. Si el bus I²C de tu módulo está mapeado diferente, mantené Wire.begin(5, 6) con tus pines reales.
/* Termómetro IR – ESP32-C3 + MLX90614 + OLED SSD1306 (I2C)
* RITSA Electrónica – Versión técnica para post
* Pines (ESP32-C3):
* SDA = GPIO5
* SCL = GPIO6
* BTN = GPIO10 (INPUT_PULLUP, activo en LOW)
*
* Librerías:
* Adafruit_MLX90614, Adafruit_SSD1306, Adafruit_GFX, Wire
*/
#include <Wire.h>
#include <Adafruit_MLX90614.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ———- Configuración de pines ———-
static constexpr int PIN_SDA = 5;
static constexpr int PIN_SCL = 6;
static constexpr int PIN_BTN = 10;
// ———- OLED ———-
#define OLED_ADDR 0x3C // Cambiar si tu módulo usa otra dirección
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, -1);
// ———- MLX90614 ———-
Adafruit_MLX90614 mlx = Adafruit_MLX90614(); // I2C
// ———- Control de muestreo / filtro ———-
static constexpr uint16_t LOOP_FAST_MS = 150; // modo rápido
static constexpr uint16_t LOOP_SLOW_MS = 500; // modo lento
bool fastMode = true;
static constexpr size_t AVG_WIN = 8; // ventana de media móvil
float bufObj[AVG_WIN] = {0};
float bufAmb[AVG_WIN] = {0};
size_t idx = 0;
bool bufFilled = false;
// ———- Botón (antirrebote) ———-
static constexpr uint32_t DEBOUNCE_MS = 30;
static constexpr uint32_t LONGPRESS_MS = 1200;
bool btnPrev = true;
uint32_t tLast = 0;
uint32_t tPress = 0;
bool holdFreeze = false;
// Utilidades
static inline float c_to_f(float c) { return c * 9.0f / 5.0f + 32.0f; }
float movingAvg(float *b, size_t n, bool filled) {
size_t count = filled ? n : idx;
if (count == 0) return 0;
float acc = 0;
for (size_t i = 0; i < count; ++i) acc += b[i];
return acc / (float)count;
}
void drawScreen(float objC, float ambC) {
display.clearDisplay();
// Header
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F(“RITSA – IR Thermometer”));
// Separador
display.drawLine(0, 10, 127, 10, SSD1306_WHITE);
// Temperaturas
display.setTextSize(2);
display.setCursor(0, 16);
display.print(F(“Obj: “));
display.print(objC, 1);
display.print(F(“C”));
display.setCursor(0, 36);
display.print(F(“Obj: “));
display.print(c_to_f(objC), 1);
display.print(F(“F”));
display.setTextSize(1);
display.setCursor(0, 56);
display.print(F(“Amb: “));
display.print(ambC, 1);
display.print(F(“C (“));
display.print(c_to_f(ambC), 1);
display.print(F(“F)”));
// Estado
if (holdFreeze) {
display.setCursor(92, 56);
display.print(F(“[HOLD]”));
} else {
display.setCursor(92, 56);
display.print(fastMode ? F(“[FAST]”) : F(“[SLOW]”));
}
display.display();
}
void setup() {
pinMode(PIN_BTN, INPUT_PULLUP);
// I2C en pines definidos
Wire.begin(PIN_SDA, PIN_SCL);
// OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
// Si falla, no bloqueamos; mostramos por Serial
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F(“Init I2C / OLED…”));
display.display();
// MLX90614
if (!mlx.begin()) {
display.clearDisplay();
display.setCursor(0, 0);
display.println(F(“MLX90614 not found”));
display.display();
delay(1500);
} else {
display.setCursor(0, 10);
display.println(F(“MLX90614 OK”));
display.display();
delay(600);
}
}
void loop() {
// — Gestión de botón con antirrebote —
bool btn = digitalRead(PIN_BTN); // true=HIGH (no pulsado), false=LOW (pulsado)
uint32_t now = millis();
if (btn != btnPrev) {
tLast = now; // cambió de estado: inicia ventana de debounce
btnPrev = btn;
}
// estable tras DEBOUNCE_MS
if (now – tLast >= DEBOUNCE_MS) {
static bool btnStable = true;
static bool btnStablePrev = true;
btnStable = btn; // estado estable
// flanco de bajada: inicio de pulsación
if (btnStable == LOW && btnStablePrev == HIGH) {
tPress = now;
}
// flanco de subida: fin de pulsación
if (btnStable == HIGH && btnStablePrev == LOW) {
uint32_t dur = now – tPress;
if (dur >= LONGPRESS_MS) {
// pulsación larga: conmutar velocidad
fastMode = !fastMode;
} else {
// pulsación corta: congela/retoma
holdFreeze = !holdFreeze;
}
}
btnStablePrev = btnStable;
}
static uint32_t tLoop = 0;
uint16_t loopMs = fastMode ? LOOP_FAST_MS : LOOP_SLOW_MS;
if (now – tLoop < loopMs) return;
tLoop = now;
// — Adquisición y filtrado —
static float objC = 0, ambC = 0;
if (!holdFreeze) {
float newObj = mlx.readObjectTempC();
float newAmb = mlx.readAmbientTempC();
// Sanitizar lecturas
if (!isnan(newObj) && newObj > -70 && newObj < 500) bufObj[idx] = newObj;
if (!isnan(newAmb) && newAmb > -70 && newAmb < 500) bufAmb[idx] = newAmb;
idx++;
if (idx >= AVG_WIN) { idx = 0; bufFilled = true; }
objC = movingAvg(bufObj, AVG_WIN, bufFilled);
ambC = movingAvg(bufAmb, AVG_WIN, bufFilled);
}
// — Render UI —
drawScreen(objC, ambC);
}
Puntos técnicos relevantes del firmware
I²C explícito: Wire.begin(5, 6) fija SDA/SCL en GPIO5/6 (por defecto del proyecto).
Filtro de media móvil (AVG_WIN = 8): mejora estabilidad visual y reduce jitter.
Antirrebote con ventana DEBOUNCE_MS=30 y detección de pulsación larga (LONGPRESS_MS=1200).
Rangos válidos para descartar valores anómalos: −70…500 °C (pueden ajustarse a tu caso).
Refresco dual: FAST (150 ms) para apuntado, SLOW (500 ms) para estabilidad / ahorro.
OLED: fuente conmutada interna SSD1306_SWITCHCAPVCC (la más común). Dirección por defecto 0x3C.
✅ Validaciones y pruebas recomendadas
Scan I²C: si no ves lecturas, corré un I²C scanner para verificar direcciones y continuidad de SDA/SCL.
Consumo: midí corriente con y sin Wi-Fi activo para dimensionar batería (picos del ESP32-C3 pueden superar 200–300 mA en Tx).
Térmica: el MLX90614 es sensible a corrientes de aire y temperatura del PCB; evitá montarlo cerca de reguladores calientes.
Calibración: para offsets leves, aplicá una corrección en firmware (p. ej., objC += kOffset;).