Sistema Inteligente de Control de Acceso Multipuerta
1. Objetivo del proyecto
El objetivo principal del proyecto es diseñar, desarrollar e implementar un sistema inteligente de control de acceso físico que permita gestionar la entrada a múltiples instalaciones o salas utilizando un único terminal de hardware centralizado.
Para alcanzar este propósito general, el proyecto se ha estructurado en torno a los siguientes objetivos específicos:
- Centralización y Escalabilidad: Eliminar la necesidad de instalar un lector de tarjetas independiente en cada puerta física, permitiendo al usuario seleccionar su destino desde un único punto de control interactivo (mediante un pulsador y un display de 7 segmentos).
- Integración IoT: Superar las limitaciones de memoria y procesamiento local del microcontrolador Arduino estableciendo una comunicación bidireccional en tiempo real con una interfaz web y un servidor mediante la Web Serial API.
- Trazabilidad y Gestión Dinámica: Desarrollar un panel de administración web que permita dar de alta, editar o eliminar usuarios, asignar permisos específicos por puerta y registrar un historial de accesos (logs) automático con fecha y hora.
- Experiencia de Usuario Multimodal: Proporcionar una respuesta inmediata y clara al usuario físico mediante múltiples canales sensoriales (pantalla LCD con mensajes personalizados, LEDs indicadores de estado y respuestas acústicas mediante zumbador).
- Eficiencia Económica: Demostrar la viabilidad de crear sistemas de seguridad complejos y de nivel empresarial utilizando componentes de bajo coste y aprovechando al máximo los recursos disponibles en el laboratorio.
2. Descripción del proyecto
El sistema consiste en una solución que funciona como un control de acceso centralizado. En lugar de tener una cerradura inteligente en cada puerta de un edificio, el sistema utiliza un único terminal principal desde el cual el usuario puede intentar acceder a 5 puertas o salas diferentes.
Para lograr esto, el sistema se compone de dos grandes bloques que se comunican entre sí en tiempo real:
1. El Módulo Físico: Es la parte física que interactúa con las personas, construida sobre una placa Arduino Uno. Consiste en:
- Selector de Puerta: Un pulsador físico que, al presionarlo, cambia la puerta a la que se desea acceder.
- Indicador de Puerta: Un display de 7 segmentos que muestra visualmente el número de la puerta seleccionada (del 1 al 5).
- Lector de Identificación: Un módulo RFID PN532 que escanea el UID de las tarjetas o llaveros de los usuarios.
- Sistema de Feedback (Avisos): Una pantalla LCD 16×2 que muestra mensajes de texto («Pase tarjeta», «Acceso Concedido», etc.), apoyada por un LED verde (éxito), un LED rojo (denegado) y un zumbador que emite distintos tonos sonoros.
2. El Módulo de Gestión (Servidor Web) Es el «cerebro» lógico del sistema, alojado en un ordenador y desarrollado con PHP y JavaScript. Consiste en:
- Panel de Administración: Una página web interactiva conectada al Arduino mediante un cable USB (usando la tecnología Web Serial API).
- Base de Datos (JSON): Archivos locales que almacenan qué usuarios existen, qué número de tarjeta tienen y una «matriz de permisos» que indica a qué puertas exactas puede entrar cada uno.
- Historial Automático: Un registro sobre tarjeta se ha pasado, en qué puerta, a qué hora exacta y si se le dejó entrar o no, también en ficheros .json.
3. Componentes del sistema
Para el desarrollo del prototipo, se ha integrado una combinación de hardware electrónico y tecnologías de software. La selección de materiales se realizó bajo un criterio de eficiencia, aprovechando los recursos proporcionados por el equipo docente y adquiriendo únicamente los módulos necesarios para escalar las capacidades del sistema.
3.1. Hardware aportado por la universidad:
Estos componentes forman la base electrónica del proyecto y la interfaz física básica:
- Placa Arduino Uno: Actúa como el microcontrolador central (el «cerebro» local). Se encarga de leer los sensores, accionar los dispositivos de salida y mantener la comunicación serie por USB con el ordenador.
- Display de 7 segmentos: Utilizado como indicador visual numérico. Su función exclusiva es mostrar al usuario qué puerta (del 1 al 5) está seleccionada en ese momento.
- Pulsador: Botón físico que permite al usuario navegar cíclicamente por las distintas puertas disponibles. Cuenta con un sistema de software anti-rebote para garantizar transiciones limpias.
- LEDs indicadores (Rojo y Verde): Actuadores lumínicos básicos. El LED verde se enciende cuando el servidor autoriza el acceso, y el LED rojo se activa cuando se deniega.
- Zumbador: Actuador acústico que emite diferentes frecuencias (tonos agudos para bienvenida, graves para error), proporcionando feedback sonoro al instante.
- Protoboard y Cableado Jumper: Placa de pruebas y cables (macho-macho, macho-hembra) utilizados para realizar todas las conexiones eléctricas sin necesidad de soldadura.
3.2. Hardware adquirido por el equipo:
Para dotar al sistema de sus características de lectura e información detallada, hemos invertido en los siguientes componentes:
- Módulo Lector RFID (PN532) y Tarjetas: Es el sensor principal del proyecto. Utiliza comunicación por radiofrecuencia para escanear el Identificador Único (UID) de las tarjetas o llaveros de los usuarios que intentan acceder.
- Pantalla LCD 16×2 con adaptador I2C: Una pantalla de cristal líquido capaz de mostrar dos líneas de texto de 16 caracteres. Gracias al adaptador I2C, se conecta al Arduino usando solo dos pines de datos (SDA y SCL), liberando espacio para el resto de componentes. Su función es saludar al usuario por su nombre o mostrar el estado del sistema («SISTEMA LISTO», «NO AUTORIZADO»).
3.3. Software y Tecnologías utilizadas
El proyecto no funcionaría sin la capa lógica que conecta el hardware físico con el entorno web:
- C++ (Arduino IDE): Lenguaje utilizado para programar el firmware del Arduino, controlando las interrupciones de hardware, los buses de datos (I2C) y la captura de señales del lector.
- JavaScript (Web Serial API): Tecnología de navegador de última generación utilizada en el frontend de la página web. Actúa como un «puente», permitiendo que la web lea directamente lo que el Arduino manda por el cable USB y viceversa.
- PHP: Lenguaje de backend que se ejecuta en el servidor. Es el encargado de recibir los datos, procesar la lógica de seguridad y devolver una respuesta de autorización o bloqueo.
- JSON (JavaScript Object Notation): Formato de archivo de texto estructurado utilizado como Base de Datos ligera. El proyecto usa dos archivos JSON: uno para almacenar los usuarios y sus matrices de permisos (
users.json), y otro para guardar el historial inmutable de accesos (logs.json).
4. Funcionamiento general del sistema
El funcionamiento del sistema es el siguiente:
PASO 1: Encendido
La pantalla LCD muestra «SISTEMA ACTIVO», el sistema se ha encendido.
En este momento, el sistema está esperando la conexión con el equipo a través del panel web.

PASO 2: Reposo
La pantalla LCD muestra «LISTO», el número de puerta en el que se encuentra y «Pase tarjeta…». El sistema espera instrucciones.

PASO 3: Selección de Puerta
El usuario pulsa el botón físico “Cambio de puerta”. El display de 7 segmentos avanza indicando la puerta seleccionada (del 1 al 5).

PASO 4: Identificación. El usuario acerca su tarjeta RFID al lector RC522
El usuario acerca la tarjeta. El módulo PN532 lee el UID y emite un pitido de validación.

PASO 5: Feedback Inmediato
Si tiene permiso: Se enciende el LED Verde y el LCD muestra “Hola» Seguido del nombre del usuario.
Si NO tiene permiso: Se enciende el LED Rojo con un pitido y el LCD muestra «Acceso Denegado»
Si no se reconoce la tarjeta: Se entiende como que el usuario es desconocido, luego también se deniega el acceso y se muestra «Acceso Denegado» en el LCD, además del pitido.


5. Implementación
Hardware utilizado:
- Módulo lector RFID (PN532)
- Pantalla LCD 16×2 (I2C) para mensajes de estado del sistema.
- Display de 7 segmentos para indicar la puerta seleccionada.
- Pulsador para la navegación/selección de puertas.
- LEDs (Verde y Rojo) como indicadores de acceso concedido o denegado.
Software:
- Local (Arduino/C++): Lectura del UID de la tarjeta y actualización de los displays físicos.
- Comunicación: Enlace directo bidireccional vía puerto Serie (Web Serial API).
- Servidor (PHP + JSON): El panel web procesa los permisos, valida la base de datos de usuarios y registra un historial de accesos.

6. Código
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_PN532.h>
// Configuración de Pines (Alineado con tu montaje físico)
#define SDA_PIN A4
#define SCL_PIN A5
#define LED_VERDE 3 // Cable verde en pin 3 (Acceso concedido)
#define LED_ROJO 4 // Cable rojo en pin 4 (Acceso denegado)
#define BUZZER_PIN 5 // Cable azul en pin 5 (Zumbador)
// Configuración Botón y Display
#define BOTON_PIN 2
const int pinesSegmentos[7] = {6, 7, 8, 9, 10, 11, 12}; // Segmentos: A, B, C, D, E, F, G
// Mapa de segmentos para los números del 1 al 9 (Display Cátodo Común)
const byte numeros[10][7] = {
{1,1,1,1,1,1,0}, // 0
{0,1,1,0,0,0,0}, // 1
{1,1,0,1,1,0,1}, // 2
{1,1,1,1,0,0,1}, // 3
{0,1,1,0,0,1,1}, // 4
{1,0,1,1,0,1,1}, // 5
{1,0,1,1,1,1,1}, // 6
{1,1,1,0,0,0,0}, // 7
{1,1,1,1,1,1,1}, // 8
{1,1,1,1,0,1,1} // 9
};
// Instancias
LiquidCrystal_I2C lcd(0x27, 16, 2);
Adafruit_PN532 nfc(SDA_PIN, SCL_PIN);
// Variables de estado
bool webConectada = false;
volatile int puertaActual = 1;
volatile bool puertaCambiada = false;
// Variables para evitar lectura múltiple rápida
uint8_t lastUid[] = {0, 0, 0, 0, 0, 0, 0};
uint8_t lastUidLength = 0;
unsigned long lastReadTime = 0;
void mostrarNumero(int num) {
for(int i = 0; i < 7; i++) {
digitalWrite(pinesSegmentos[i], numeros[num][i]);
}
}
void isrBoton() {
static unsigned long tiempoUltimoReboteISR = 0;
if (millis() – tiempoUltimoReboteISR > 250) {
puertaActual++;
if (puertaActual > 5) puertaActual = 1;
puertaCambiada = true;
tiempoUltimoReboteISR = millis();
}
}
void setup() {
Serial.begin(9600);
pinMode(LED_ROJO, OUTPUT);
pinMode(LED_VERDE, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BOTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BOTON_PIN), isrBoton, FALLING);
for(int i = 0; i < 7; i++) {
pinMode(pinesSegmentos[i], OUTPUT);
}
mostrarNumero(puertaActual);
lcd.init();
lcd.backlight();
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (!versiondata) {
lcd.print(«Error PN532»);
while (1);
}
nfc.SAMConfig();
// Sonido breve de arranque
tone(BUZZER_PIN, 1500, 100);
delay(150);
tone(BUZZER_PIN, 2000, 150);
lcd.print(«SISTEMA ACTIVO»);
delay(1000);
actualizarPantallaNormal();
}
void loop() {
// 0. Revisar si la interrupción cambió la puerta
if (puertaCambiada) {
mostrarNumero(puertaActual);
actualizarPantallaNormal();
puertaCambiada = false;
}
// 1. Escuchar órdenes de la WEB (Autorización Remota)
if (Serial.available() > 0) {
String comando = Serial.readStringUntil(‘\n’);
comando.trim();
if (comando == «WEB_OK») {
if (!webConectada) {
// Pitido de conexión web exitosa (agudo y rápido)
tone(BUZZER_PIN, 2500, 100);
delay(150);
tone(BUZZER_PIN, 3000, 150);
}
webConectada = true;
actualizarPantallaNormal();
}
else if (comando.startsWith(«ACCESS_OK:»)) {
String nombre = comando.substring(10);
ejecutarAccesoConcedido(nombre);
}
else if (comando == «ACCESS_DENIED») {
ejecutarAccesoDenegado();
}
}
// 2. Lectura de tarjeta y envío a la WEB
uint8_t success;
uint8_t uid[] = {0, 0, 0, 0, 0, 0, 0};
uint8_t uidLength;
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 50);
if (success) {
if (millis() – lastReadTime < 3000 && compararUID(uid, uidLength, lastUid, lastUidLength)) {
return;
}
for (uint8_t i = 0; i < uidLength; i++) { lastUid[i] = uid[i]; }
lastUidLength = uidLength;
lastReadTime = millis();
// Notificar a la web
Serial.print(«CARD_READ:»);
for (uint8_t i = 0; i < uidLength; i++) {
if (uid[i] < 0x10) Serial.print(«0»);
Serial.print(uid[i], HEX);
if (i < uidLength – 1) Serial.print(«-«);
}
Serial.print(«|DOOR:»);
Serial.println(puertaActual);
lcd.clear();
lcd.print(«VALIDANDO…»);
}
}
void ejecutarAccesoConcedido(String nombre) {
lcd.clear();
lcd.print(«HOLA,»);
lcd.setCursor(0, 1);
lcd.print(nombre);
digitalWrite(LED_VERDE, HIGH);
tone(BUZZER_PIN, 1800, 200); delay(250); tone(BUZZER_PIN, 2300, 400);
delay(2000);
digitalWrite(LED_VERDE, LOW);
actualizarPantallaNormal();
}
void ejecutarAccesoDenegado() {
lcd.clear();
lcd.print(«ACCESO DENEGADO»);
lcd.setCursor(0, 1);
lcd.print(«NO AUTORIZADO»);
digitalWrite(LED_ROJO, HIGH);
tone(BUZZER_PIN, 300, 600);
delay(2000);
digitalWrite(LED_ROJO, LOW);
actualizarPantallaNormal();
}
bool compararUID(uint8_t *u1, uint8_t l1, uint8_t *u2, uint8_t l2) {
if (l1 != l2) return false;
for (uint8_t i = 0; i < l1; i++) {
if (u1[i] != u2[i]) return false;
}
return true;
}
void actualizarPantallaNormal() {
lcd.clear();
if (webConectada) {
lcd.print(«ONLINE P:»);
} else {
lcd.print(«LISTO P:»);
}
lcd.print(puertaActual);
lcd.setCursor(0, 1);
lcd.print(«Pase tarjeta…»);
}
7. Funcionamiento
En el siguiente vídeo, se refleja el funcionamiento del sistema completo.
8. Reparto de tareas
Para maximizar la eficiencia y cumplir con los plazos de entrega, el proyecto se dividió en módulos. Todos los miembros participaron en el diseño conceptual, pero la carga técnica se distribuyó equitativamente según las fortalezas del grupo:
| Miembro del Equipo | Tareas Asignadas |
| Víctor | Desarrollo del código en C++ (Arduino). Integración de las librerías y control del display de 7 segmentos. Configuración de la comunicación Serial. |
| Diego | Diseño de la interfaz gráfica del panel de administración (Access). Implementación de la Web Serial API en JavaScript. |
| Marcos | Programación de los scripts en PHP (crear, editar, borrar usuarios y permisos). Estructuración de la base de datos en formato JSON. |
| Javier | Montaje del circuito físico en protoboard. Diseño del esquema de conexiones, cableado de actuadores (LCD, LEDs, Buzzer) y gestión de energía. |
9. Presupuesto y coste de materiales
El proyecto se ha desarrollado bajo una estricta optimización de recursos, aprovechando el material didáctico existente para reducir la inversión económica, demostrando viabilidad para prototipado rápido de bajo coste:
| Componente | Proveedor / Origen | Coste (€) |
| Placa Arduino Uno + Cable USB | Laboratorio (Centro) | 5,59 € |
| Electrónica base (LEDs, Zumbador, Pulsador) | Laboratorio (Centro) | 6,51 € |
| Display 7 Segmentos + Resistencias | Laboratorio (Centro) | 1,17 € |
| Protoboard y Cables Jumper (M-M, M-H) | Laboratorio (Centro) | 3,87 € |
| Módulo Lector RFID PN532 + Tarjetas | Adquisición del Grupo | 3,19 € |
| Pantalla LCD 16×2 con adaptador I2C | Adquisición del Grupo | 2,46 € |
| TOTAL INVERSIÓN | 22,79 € |
10. Problemas encontrados y soluciones
Durante la fase de desarrollo e integración, el equipo se enfrentó a varios retos técnicos que requirieron rediseños en el código:
•Saturación del puerto Serie: Solo se puede interactuar con el dispositivo Arduino a través de un puerto a la vez.
•Varios de los lectores no funcionaron: Los componentes RDM6300 y MFRC-522 que intentamos utilizar en el proyecto resultaron incompatibles o su configuración no resultó apropiada para el desarrollo de este prototipo, por lo que procedimos a usar el PN532 como lector RFID.
•La pantalla original no era I2C: Se trató de conectar aun así, pero al no incorporar el módulo I2C, no disponíamos de pines suficientes junto con el resto de componentes para la maqueta.
•El sistema es inestable debido a enlaces entre cables (Botón RESET): Ya que hemos tratado de reutilizar la mayor parte de nuestro material de trabajo, no hemos realizado soldaduras ni utilizado cables diferentes a los jumpers incluidos o aportados por el equipo, lo que deriva en algunos casos en errores mínimos que se evitarían en caso de realizar estas soldaduras. Es por ello que se incluye el botón de reset, encargado de restablecer el sistema en este tipo de eventos.
11. Casos de uso
La arquitectura escalable de este proyecto permite su implantación directa en diversos sectores comerciales, entre ellos los siguientes:
- Sector Hotelero: Gestión centralizada desde recepción de las tarjetas de los huéspedes, habilitando el acceso a sus habitaciones o zonas comunes (piscina, gimnasio) y anulándolas automáticamente al hacer el check-out sin necesidad de manipular las cerraduras.
- Centros Deportivos: Torno único que permite al sistema derivar al usuario a diferentes instalaciones según la cuota que esté pagando (acceso general, spa, pistas de pádel).
- Entornos Corporativos y Laboratorios: Sistema de acceso «Fail-Secure» que restringe el paso a zonas de servidores o material peligroso, manteniendo un registro horario detallado de las entradas y salidas de cada empleado para auditorías.