# TECNOLOGIA APLICADA IOT - SECCIÓN 50
# EVALUACION 3
# INTEGRANTE: LEONARDO PAYAUNA
# APLICACIÓN: CONTEO DE PERSONAS Y AFORO
from machine import Pin, I2C
import utime
# ================== CONFIGURACION HARDWARE ==================
# --- Pines sensor ENTRADA ---
TRIG_ENTRADA_PIN = 3
ECHO_ENTRADA_PIN = 2
LED_ENTRADA_PIN = 6
# --- Pines sensor SALIDA ---
TRIG_SALIDA_PIN = 18
ECHO_SALIDA_PIN = 19
LED_SALIDA_PIN = 27
# --- Distancia de detección (cm) ---
UMBRAL_CM = 100.0 # 100 cm
# --- I2C para LCD (ajusta si usas otros pines) ---
I2C_SDA_PIN = 0
I2C_SCL_PIN = 1
I2C_FREQ = 400000 # Hz
LCD_I2C_ADDR = 0x27 # Dirección típica de los módulos PCF8574
# ================== CLASE PARA LCD I2C 16x2 ==================
class I2cLcd:
# Comandos básicos del HD44780
LCD_CLR = 0x01
LCD_HOME = 0x02
LCD_ENTRY_MODE = 0x06
LCD_DISPLAY_ON = 0x0C
LCD_FUNCTION_SET = 0x28 # 4 bits, 2 líneas, 5x8 font
def __init__(self, i2c, addr, cols, rows):
self.i2c = i2c
self.addr = addr
self.cols = cols
self.rows = rows
self.backlight = 0x08 # backlight ON
utime.sleep_ms(20)
self._write_init_nibble(0x03)
utime.sleep_ms(5)
self._write_init_nibble(0x03)
utime.sleep_ms(5)
self._write_init_nibble(0x03)
utime.sleep_ms(5)
self._write_init_nibble(0x02) # 4-bit mode
self._command(self.LCD_FUNCTION_SET)
self._command(self.LCD_DISPLAY_ON)
self._command(self.LCD_CLR)
self._command(self.LCD_ENTRY_MODE)
utime.sleep_ms(2)
def _write_init_nibble(self, nibble):
self._write4(nibble << 4)
def _write4(self, data):
# Enable = 0b00000100
self.i2c.writeto(self.addr, bytes([data | self.backlight | 0x04]))
self.i2c.writeto(self.addr, bytes([data | self.backlight & ~0x04]))
def _send(self, value, mode):
# mode = 0 para comando, 1 para datos
high = value & 0xF0
low = (value << 4) & 0xF0
self._write4(high | mode)
self._write4(low | mode)
def _command(self, cmd):
self._send(cmd, 0)
def clear(self):
self._command(self.LCD_CLR)
utime.sleep_ms(2)
def home(self):
self._command(self.LCD_HOME)
utime.sleep_ms(2)
def move_to(self, col, row):
# Direcciones base de cada línea
row_offsets = [0x00, 0x40, 0x14, 0x54]
addr = 0x80 | (col + row_offsets[row])
self._command(addr)
def putchar(self, char):
self._send(ord(char), 1)
def putstr(self, string):
for c in string:
self.putchar(c)
# ================== FUNCIONES ULTRASONICO ==================
def leer_distancia_cm(trig: Pin, echo: Pin) -> float:
"""
Devuelve la distancia en cm usando un HC-SR04.
Si está fuera de rango, devuelve 9999.
"""
# Asegurar pulso limpio
trig.value(0)
utime.sleep_us(2)
trig.value(1)
utime.sleep_us(10)
trig.value(0)
# Medir pulso HIGH en ECHO (timeout 30 ms)
start = utime.ticks_us()
while echo.value() == 0:
if utime.ticks_diff(utime.ticks_us(), start) > 30000:
return 9999
start = utime.ticks_us()
while echo.value() == 1:
if utime.ticks_diff(utime.ticks_us(), start) > 30000:
return 9999
duration = utime.ticks_diff(utime.ticks_us(), start)
distancia = (duration * 0.0343) / 2.0 # cm
if distancia <= 0 or distancia > 400:
return 9999
return distancia
# ================== CONFIGURACION INICIAL ==================
# Pines sensores ENTRADA
trig_entrada = Pin(TRIG_ENTRADA_PIN, Pin.OUT)
echo_entrada = Pin(ECHO_ENTRADA_PIN, Pin.IN)
led_entrada = Pin(LED_ENTRADA_PIN, Pin.OUT)
# Pines sensores SALIDA
trig_salida = Pin(TRIG_SALIDA_PIN, Pin.OUT)
echo_salida = Pin(ECHO_SALIDA_PIN, Pin.IN)
led_salida = Pin(LED_SALIDA_PIN, Pin.OUT)
# LCD I2C
i2c = I2C(0, sda=Pin(I2C_SDA_PIN), scl=Pin(I2C_SCL_PIN), freq=I2C_FREQ)
lcd = I2cLcd(i2c, LCD_I2C_ADDR, 16, 2)
# Mensaje de inicio
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("PEOPLE COUNTING")
lcd.move_to(0, 1)
lcd.putstr("ENT/SAL & AFORO")
utime.sleep(2)
lcd.clear()
# Contadores
contador_entrada = 0
contador_salida = 0
# Estados anteriores (detección o no detección)
entrada_presente_antes = False
salida_presente_antes = False
# ================== BUCLE PRINCIPAL ==================
while True:
# ----- SENSOR ENTRADA -----
dist_entrada = leer_distancia_cm(trig_entrada, echo_entrada)
entrada_presente = dist_entrada < UMBRAL_CM
if entrada_presente and not entrada_presente_antes:
# Recién detectado
contador_entrada += 1
led_entrada.value(1)
print("ENTRADA detectada | Dist:", dist_entrada, "cm")
elif not entrada_presente and entrada_presente_antes:
# Objeto/persona se fue
led_entrada.value(0)
entrada_presente_antes = entrada_presente
# ----- SENSOR SALIDA -----
dist_salida = leer_distancia_cm(trig_salida, echo_salida)
salida_presente = dist_salida < UMBRAL_CM
if salida_presente and not salida_presente_antes:
contador_salida += 1
led_salida.value(1)
print("SALIDA detectada | Dist:", dist_salida, "cm")
elif not salida_presente and salida_presente_antes:
led_salida.value(0)
salida_presente_antes = salida_presente
# ----- AFORO ACTUAL -----
aforo_actual = contador_entrada - contador_salida
if aforo_actual < 0:
aforo_actual = 0 # por seguridad
# ----- MOSTRAR EN LCD -----
lcd.clear()
# Línea 1: Entradas y salidas
lcd.move_to(0, 0)
linea1 = "Ent:{:3d} Sal:{:3d}".format(
int(contador_entrada),
int(contador_salida)
)
lcd.putstr(linea1[:16])
# Línea 2: Aforo
lcd.move_to(0, 1)
linea2 = "Aforo: {:5d}".format(int(aforo_actual))
lcd.putstr(linea2[:16])
# (Opcional) mensaje por consola
print("Entradas:", contador_entrada,
"Salidas:", contador_salida,
"Aforo:", aforo_actual)
utime.sleep(0.3) # pequeña pausa para evitar rebotes locos