/* ============================================================================
MOCHILA INTELIGENTE - Verificacion de inventario (DEMO para Wokwi)
============================================================================
Componentes:
- Arduino Uno ............ el "cerebro"
- Boton VERIFICAR ........ enciende el sistema (en reposo todo apagado)
- RFID MFRC522 ........... Compartimiento 1 (insumo critico con identidad)
- Celda de carga + HX711 . Compartimiento 2 (insumo a granel, leido por BANDAS)
- OLED SSD1306 (I2C) ..... muestra la lista de faltantes
- 2 LEDs ................. verde = todo OK / rojo = falta algo
Flujo:
REPOSO -> pantalla y LEDs apagados
PULSAR -> se enciende ~5 s y hace el chequeo en vivo
* Tarjeta RFID sobre el lector -> Comp 1 PRESENTE (OK)
* Tarjeta retirada -> Comp 1 AUSENTE (FALTA)
* Slider del HX711 -> cambia la banda del Comp 2
5 s -> vuelve solo a reposo
Librerias (Wokwi -> "Library Manager"):
MFRC522, HX711 Arduino Library, Adafruit SSD1306, Adafruit GFX Library
============================================================================ */
#include <SPI.h>
#include <MFRC522.h>
#include "HX711.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// --------------------------- PINES ---------------------------
#define BTN_PIN 2 // Boton VERIFICAR (otro extremo a GND, INPUT_PULLUP)
#define SS_PIN 10 // RFID: SDA / SS
#define RST_PIN 9 // RFID: RST
#define HX_DT 6 // HX711: DT
#define HX_SCK 7 // HX711: SCK (reloj propio del HX711, NO el del SPI)
#define LED_VERDE 4
#define LED_ROJO 5
// (RFID tambien usa SCK=13, MOSI=11, MISO=12 ; OLED usa A4=SDA, A5=SCL)
// --------------------------- OLED ---------------------------
#define OLED_W 128
#define OLED_H 64
#define OLED_ADDR 0x3C
// ------------------ UMBRALES DE PESO (gramos, DEMO) ------------------
const float UMBRAL_LLENO = 150.0; // > 150 g -> LLENO
const float UMBRAL_POCO = 50.0; // 50-150 g -> POCO ; < 50 g -> FALTA
// ------------------ TIEMPO ENCENDIDO TRAS PULSAR ------------------
const unsigned long ACTIVO_MS = 5000; // 5 s
// ------------------ DEBOUNCE DE PRESENCIA RFID ------------------
// La tarjeta se declara AUSENTE solo tras N lecturas fallidas seguidas.
// Evita parpadeos cuando el lector pierde una lectura puntual.
const int FALLOS_PARA_AUSENTE = 3;
MFRC522 rfid(SS_PIN, RST_PIN);
HX711 scale;
Adafruit_SSD1306 display(OLED_W, OLED_H, &Wire, -1);
bool comp1Presente = false; // ¿el insumo del Comp 1 (RFID) esta presente?
int fallosRFID = 0; // lecturas fallidas seguidas del RFID
bool sistemaActivo = false; // ¿el sistema esta encendido ahora?
unsigned long tActivo = 0; // momento en que se pulso el boton
bool btnPrev = HIGH; // estado anterior del boton
/* ===========================================================================
MAPEO POR UID -- PENDIENTE (aun no tengo las tarjetas para registrar UID)
===========================================================================
Hoy la demo detecta "hay una tarjeta sobre el lector o no".
Cuando tengas las etiquetas, descomenta para distinguir QUE tarjeta es:
struct Tag { byte uid[4]; const char* nombre; };
Tag tagsConocidos[] = {
{ {0xDE, 0xAD, 0xBE, 0xEF}, "Comp 1" },
{ {0x12, 0x34, 0x56, 0x78}, "Comp 2" },
};
const char* identificarTag() {
for (Tag &t : tagsConocidos) {
bool igual = true;
for (byte i = 0; i < 4; i++) if (rfid.uid.uidByte[i] != t.uid[i]) igual = false;
if (igual) return t.nombre;
}
return nullptr;
}
// Registrar un UID nuevo: imprimir rfid.uid.uidByte[] por Serial al leer la tarjeta.
=========================================================================== */
void setup() {
Serial.begin(9600);
pinMode(BTN_PIN, INPUT_PULLUP);
pinMode(LED_VERDE, OUTPUT);
pinMode(LED_ROJO, OUTPUT);
SPI.begin();
rfid.PCD_Init();
scale.begin(HX_DT, HX_SCK);
scale.set_scale(0.42); // calibracion DEMO: unidades ~ gramos (Wokwi tipo 5kg)
scale.tare(); // pone el cero ("tara" al encender, con base vacia)
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println(F("OLED no encontrada"));
for (;;);
}
display.setTextColor(SSD1306_WHITE);
mostrarReposo();
}
// Devuelve true si HAY una tarjeta sobre el lector AHORA.
// IMPORTANTE: tras comunicarse con una tarjeta, el MFRC522 deja estos 3
// registros de modulacion en un estado que hace fallar la siguiente lectura
// (la tarjeta "desaparece" aunque siga puesta). Reescribirlos antes de cada
// sondeo restablece la deteccion continua. NO se hace HaltA: dejamos la
// tarjeta en IDLE para que REQA la siga detectando mientras este presente.
bool tarjetaPresente() {
rfid.PCD_WriteRegister(rfid.TxModeReg, 0x00);
rfid.PCD_WriteRegister(rfid.RxModeReg, 0x00);
rfid.PCD_WriteRegister(rfid.ModWidthReg, 0x26);
byte atqa[2];
byte size = sizeof(atqa);
MFRC522::StatusCode s = rfid.PICC_RequestA(atqa, &size);
return (s == MFRC522::STATUS_OK || s == MFRC522::STATUS_COLLISION);
}
String bandaGasas(float g) {
if (g >= UMBRAL_LLENO) return "LLENO";
if (g >= UMBRAL_POCO) return "POCO";
return "FALTA";
}
void mostrarReposo() {
digitalWrite(LED_VERDE, LOW);
digitalWrite(LED_ROJO, LOW);
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 20);
display.println(F(" ( En reposo )"));
display.println();
display.println(F("Pulsa para VERIFICAR"));
display.display();
}
void verificar() {
// Peso: get_units(5) toma 5 lecturas y las PROMEDIA (mas estable).
float gramos = scale.get_units(5);
if (gramos < 0) gramos = 0;
String banda = bandaGasas(gramos);
bool faltaAlgo = (!comp1Presente) || (banda == "FALTA");
digitalWrite(LED_VERDE, faltaAlgo ? LOW : HIGH);
digitalWrite(LED_ROJO, faltaAlgo ? HIGH : LOW);
display.clearDisplay();
display.setCursor(0, 0);
display.println(F("INSUMOS ACTUALES"));
display.println();
display.print(F("Comp 1: "));
display.println(comp1Presente ? F("OK") : F("FALTA"));
display.print(F("Comp 2: "));
display.print(banda);
display.print(F(" ("));
display.print((int)gramos);
display.println(F("g)"));
display.println();
display.println(faltaAlgo ? F(">> REVISAR <<") : F(">> TODO OK <<"));
display.display();
}
void loop() {
// (A) Detectar el "click" del boton (flanco HIGH -> LOW)
bool btn = digitalRead(BTN_PIN);
if (btnPrev == HIGH && btn == LOW) {
sistemaActivo = true;
tActivo = millis();
}
btnPrev = btn;
// (B) Solo si el sistema esta activo
if (sistemaActivo) {
// (B1) RFID: refleja si la tarjeta esta sobre el lector AHORA.
// Presente -> OK ; retirada -> FALTA (con debounce anti-parpadeo).
if (tarjetaPresente()) {
comp1Presente = true;
fallosRFID = 0;
} else if (++fallosRFID >= FALLOS_PARA_AUSENTE) {
comp1Presente = false;
}
// (B2) Verificar y mostrar
verificar();
// (B3) Pasados los 5 s, volver a reposo
if (millis() - tActivo > ACTIVO_MS) {
sistemaActivo = false;
fallosRFID = 0;
mostrarReposo();
}
}
delay(120);
}Loading
ssd1306
ssd1306
Loading
mfrc522
mfrc522