PROYECTO_04
Control de Acceso Físico
Control de acceso para una escuela, con placa hecha en casa: quién entra lo decide el backend, no el lector.
- TIPO
- Hardware · Full Stack
- ESTADO
- EN PRODUCCIÓN
- DIAGRAMAS
- 4
- CAPTURAS
- 13
01 Qué es
Control de acceso para una escuela, de punta a punta: una PCB propia con Arduino Nano que gobierna dos lectores Wiegand y dos chapas, un lector de tarjetas MIFARE ZKTeco PROID10BM en cada puerta, un backend en Spring Boot que decide quién entra y un panel web para dar de alta, dar de baja y bloquear alumnos, hospedado en el servidor de la propia escuela.
- Placa
pcb_controlRev A: 170 × 115 mm, 61 componentes THT, 42 redes, ERC y DRC en cero. - Dos lectores Wiegand 26/34 independientes, dos relés de puerta como contacto seco y dos botones de salida.
- La placa no decide nada: lee la tarjeta, manda el ID por el puerto serie y abre solo cuando el backend le da la señal.
- Backend en Spring Boot que valida si el alumno está activo o bloqueado, y panel web con alumnos, tarjetas, historial de accesos y estado.
02 La placa · Rev A
Diseñada en KiCad. Todo es de agujero pasante a propósito: nada de SMD, para que la placa entera se suelde con la misma técnica y el mismo cautín. Cuatro tornillos M3 en agujeros de 3.2 mm.
| Bloque | Componentes | Para qué |
|---|---|---|
| Cerebro | Arduino Nano v3 (A1) | Lee los dos lectores por interrupción y maneja relés, botones, LED y buzzer |
| Alimentación | PTC F1 1.1 A · Schottky SB340 D7 · buck MP1584 U1 · C1 100 µF · C2 10 µF | 12 V protegidos; 5 V para el Nano y los pull-ups |
| Entrada Wiegand ×2 | TVS P6KE6.8CA D1–D4 · C4–C7 1 nF · R3, R4, R7, R8 220 Ω · pull-ups R1, R2, R5, R6 2.2 kΩ | Protege el AVR y compra distancia de cable |
| Relés ×2 | SRD-12VDC-SL-C K1, K2 · BC337 Q1, Q2 · 1N4148 D5, D6 · snubber R17, R18 100 Ω + C10, C11 100 nF/250 V | Contacto seco COM/NC/NO hacia la chapa |
| Avisos del lector | ULN2003A U2 · pull-ups R22–R25 4.7 kΩ sin poblar | LED y buzzer de ambos lectores con un solo integrado |
| Indicadores | LED verde LED1 (PWR) · LED rojo LED2, LED3 (relé 1 y 2) | Ninguno gasta un pin del Nano |
| Borneras | MX126/DG126 paso 5.00 mm: J2, J3 7 vías · J4, J5 3 vías · J1, J6, J7 2 vías | Lectores, puertas, entrada 12 V y botones de salida |
03 Cómo funciona
Alimentación
Los 12 V entran por J1, pasan por el PTC F1 (rearmable: al quitar la falla vuelve solo) y por el Schottky D7, que bloquea la polaridad invertida. Ese riel alimenta directo las bobinas de los relés, los dos lectores y la entrada del buck U1, que baja a 5 V para el Nano y los pull-ups: unos 40 mA en total.
La lectura Wiegand
Las líneas D0 y D1 del lector son colector abierto: en reposo ambas están en 5 V por los pull-ups de 2.2 kΩ. Para mandar un bit, el lector tira una a masa durante ~50 µs; pulso en D0 = bit 0, pulso en D1 = bit 1. Una tarjeta de 26 bits son 26 pulsos repartidos entre las dos líneas.
Cada línea recorre TVS → filtro de 1 nF → resistencia serie de 220 Ω → pin del Nano. Esa cadena es lo que compra la distancia: Wiegand no es diferencial y por eso es sensible al ruido.
La apertura y la salida
Cuando el backend autoriza, el Nano pone D6 en alto, R9 mete ~4.3 mA a la base de Q1, el transistor satura y conecta el negativo de la bobina a masa. R10 (10 kΩ) mantiene la base a masa mientras el Nano arranca: sin ella el pin flota y el relé podría dispararse solo al encender. D5 absorbe el pico inverso de la bobina.
J4 y J5 entregan COM/NC/NO como contacto seco: el relé es solo un interruptor y la corriente de la cerradura no pasa por la placa. El snubber RC (R17 + C10) puentea COM–NO para que el arco no pegue los contactos; se eligió RC y no diodo porque no tiene polaridad y funciona igual con carga DC o AC.
LEDs de la placa, LED y buzzer del lector
Tres LEDs y ninguno gasta un pin del Nano. LED1 (verde, PWR) cuelga del riel de 5 V: si enciende, el buck funciona. LED2 y LED3 (rojos) van del +12 V a la bobina del relé por R20 y R21: encienden justo cuando el transistor satura, así que indican el accionamiento real y no lo que el firmware cree. Si el LED de relé enciende y la puerta no abre, el problema está del relé para afuera; si no enciende, del transistor para adentro. Parte el diagnóstico en dos.
El LED y el buzzer del lector son colector abierto: hay que tirarlos a masa. En vez de cuatro transistores con sus resistencias va un ULN2003A (U2), que trae siete drivers con las resistencias de base y los diodos de clamp ya dentro; se usan cuatro canales. Los controla el Nano por A0–A3 y no por D10–D13 por una razón concreta: D13 lleva el LED de la placa Nano y el bootloader lo parpadea en cada arranque, así que el lector pitaría en cada reset.
04 Borneras
Familia MX126 / DG126, paso 5.00 mm, taladro 1.3 mm y pad de Ø2.8 mm. J2 y J3 están giradas 180° para que la boca del cable mire al borde, así que el pin 1 queda a la derecha: la serigrafía está rotulada pad por pad y se lee MALLA · BUZZ · LED · D1 · D0 · GND · 12V de izquierda a derecha. Hazle caso a la serigrafía, no al número de pin.
| Bornera | Uso | Pines |
|---|---|---|
J2 / J3 | Lector 1 y 2 · 7 vías | 12V · GND · D0 · D1 · LED · BUZZ · MALLA |
J4 / J5 | Puerta 1 y 2 · contacto seco · 3 vías | COM · NC · NO |
J1 | Entrada 12 V · 2 vías | +12V · GND |
J6 / J7 | Botón de salida 1 y 2 · 2 vías | BTN · GND |
05 Pinout del Nano
El Nano solo tiene dos interrupciones por hardware y aquí hacen falta cuatro líneas Wiegand. El lector 1 se queda con INT0/INT1; el lector 2 va por pin-change interrupt. Por eso el firmware no puede ser el ejemplo básico de dos líneas.
| Pin | Función | Red | Nota |
|---|---|---|---|
D2 · D3 | Lector 1 · D0 / D1 | W1_D0 · W1_D1 | INT0 / INT1, hardware |
D4 · D5 | Lector 2 · D0 / D1 | W2_D0 · W2_D1 | PCINT20 / PCINT21 |
D6 · D7 | Relé 1 / 2 | REL1_CTRL · REL2_CTRL | alto = abre |
D8 · D9 | Botón de salida 1 / 2 | BTN1 · BTN2 | bajo = pulsado |
A0 · A1 | LED / buzzer lector 1 | RDR1_LED_C · RDR1_BEEP_C | → ULN2003A I1 / I2 |
A2 · A3 | LED / buzzer lector 2 | RDR2_LED_C · RDR2_BEEP_C | → ULN2003A I3 / I4 |
+5V | Entrada de 5 V | +5V | desde el buck; el USB del Nano va al servidor y su Schottky evita que se retroalimente |
VIN | Sin conectar | — | a propósito: se alimenta por el pin de 5 V |
Quedan libres D10–D13 y A4–A7: sitio para sensores de puerta, un RTC o almacenar tarjetas por I²C.
06 Firmware
control_acceso.ino compila para arduino:avr:nano sin avisos: 6.5 KB de flash (21 %) y 324 B de RAM. Lee ambos lectores por interrupción y arma la trama bit a bit; cierra la lectura tras 25 ms de silencio; acepta 26 y 34 bits y valida las dos paridades antes de mandar nada. No guarda tarjetas: el ID sale por el USB del Nano, como puerto serie a 115200, hacia el servidor de la escuela, y es el backend quien decide.
- Manda
CARDcon el número de lector y el ID; si el backend respondeOPEN, abre el relé 3 s sin bloquear el bucle, con un pitido largo y LED verde; si respondeDENYo la trama viene mal, tres pitidos cortos. - Botones de salida con antirrebote de 30 ms.
- El ID es
(facility << 16) | número, igual para Wiegand 26 y 34: los dos formatos se aplastan al mismo ID de 32 bits, que es el que se guarda en el servidor al dar de alta al alumno. - El backend registra cada lectura, autorizada o no, en el historial de accesos.
- El vector
PCINT2cubre todo el puerto D, así que la rutina compara con el estado anterior para quedarse solo con los flancos de bajada dePD4yPD5.
> CARD 1 00A1B2C3 # Nano → backend: lector 1 leyó este ID
> OPEN 1 # backend → Nano: alumno activo, abre el relé 1 tres segundos
> DENY 1 # backend → Nano: bloqueado o desconocido, tres pitidos
> BTN 2 # Nano → backend: botón de salida 2, solo para el historial07 Resiliencia
Un control de acceso vive dentro de una caja, sin nadie mirándolo, y tiene que seguir funcionando. Estas son las decisiones tomadas con eso en mente, no por elegancia.
| Si… | Entonces |
|---|---|
| el firmware se cuelga | Un watchdog de 2 s reinicia el Nano, y lo primero que hace setup() es apagar los dos relés: si el reset ocurrió con una puerta abierta, no se queda abierta |
| el lector no es de 26 bits | Se aceptan Wiegand 26 y 34 con sus paridades; el registro de bits es de 64 bits porque una trama de 34 no cabe en 32 |
| hay ruido en el cable | Una trama que no tenga exactamente 26 o 34 bits se descarta sola; el contador sigue subiendo pasado el límite para que una ráfaga quede con un n imposible en vez de parecerse a una tarjeta |
| el backend no contesta o el USB se desconecta | La placa sigue alimentada por el buck, no por el USB. La puerta no abre: sin OPEN no hay apertura y el intento queda con tres pitidos. Los botones de salida siguen funcionando porque son locales a la placa |
| hay que dar de alta o bloquear un alumno | Se hace en el panel, sin tocar la placa: el ID de la tarjeta se captura pasándola por el lector y el cambio aplica en la siguiente lectura |
| la placa lleva 49 días encendida | millis() desborda; todas las esperas usan resta sin signo, que sobrevive al desbordamiento, y no hay un solo delay(): relés, LEDs y pitidos son máquinas de estado |
08 Verificación y riesgos
Lo comprobado y lo no comprobado, separado a propósito. Que el ERC pase no significa que el circuito funcione: durante el diseño, un error grave (base y colector del BC337 invertidos) sobrevivió a un ERC perfectamente limpio. Solo apareció al leer la netlist red por red y preguntarle a KiCad el orden real de las patas del transistor.
| Verificado | Cómo |
|---|---|
| ERC: 0 errores, 0 avisos | Reglas eléctricas del esquemático con --severity-all |
| Netlist: 42 redes | Exportada y leída red por red: base en Q1.2, colector en Q1.1, bobina en K1.2, común en K1.1 |
| Huellas: 61 de 61 | Cada huella contrastada contra su .kicad_mod real, pin a pad |
| DRC: 0 violaciones | Reglas de diseño de la placa |
| Polaridad de LED y buzzer del lector | Contra la documentación de HID, referencia del sector: se activan a masa, 0–12 V / 100 mA, dentro de spec del ULN2003A |