PROYECTO #06 Nivel Medio ⏱ 60 min

Abanico
Inteligente

La velocidad del ventilador cambia automaticamente segun la luz del ambiente. Aprende PWM (modulacion de ancho de pulso) y control proporcional — la base de casi toda la electronica de control moderna: motores, dimers de LED, cargadores de movil.

Sensor de Luz (LDR) Ventilador DC Pantalla OLED micro:bit Placa expansion
★ Materiales

Que necesitas

El ventilador requiere la placa de expansion para funcionar correctamente — el micro:bit solo no puede dar suficiente corriente. Si ya hiciste el Proyecto 05, la OLED ya deberia tener instalada su extension en MakeCode.

🤖
micro:bit v2
x1 unidad
Ver guia →
🔌
Placa de expansion
x1 unidad
Ver guia →
Sensor de Luz (LDR)
x1 unidad
Ver guia →
🐜
Ventilador DC
x1 unidad
Ver guia →
📺
Pantalla OLED
x1 unidad (128x64)
Ver guia →
Cables dupont
x9 cables
Ver guia →
⚡ Conexion

Como conectar los componentes

Tres componentes, tres grupos de conexiones. El sensor de luz y el ventilador usan pines normales. La OLED usa I2C. Conecta de uno en uno y prueba cada componente antes de pasar al siguiente.

💡 Que es PWM?
PWM (Pulse Width Modulation) es una tecnica para simular voltajes variables usando pulsos digitales rapidos. En vez de dar 1.5V al motor (lo cual no es posible con salidas digitales), el micro:bit enciende y apaga la salida miles de veces por segundo. Si esta encendido el 50% del tiempo, el motor "siente" la mitad de la potencia. Usamos pins.analogWritePin con valores de 0 (apagado) a 1023 (maximo) para controlar la velocidad.
Componente Pin del componente Pin micro:bit Color recomendado
Sensor Luz (LDR) Signal (analog) P0 🟡 Amarillo
Sensor Luz (LDR) V (VCC) 3.3V 🔴 Rojo
Sensor Luz (LDR) G (GND) GND ⚫ Negro
Ventilador DC Signal (PWM) P1 (PWM) 🟠 Naranja
Ventilador DC V (VCC) 3.3V 🔴 Rojo
Ventilador DC G (GND) GND ⚫ Negro
Pantalla OLED CLK (SCL) SCL / P19 🔵 Azul
Pantalla OLED DA (SDA) SDA / P20 🔳 Verde
Pantalla OLED V (VCC) 3.3V 🔴 Rojo
Pantalla OLED G (GND) GND ⚫ Negro
1
Inserta el micro:bit en la placa de expansion. Comprueba que todos los pines entran bien.
2
Conecta el sensor de luz: pin analogico (Signal) a P0, VCC a 3.3V, GND a GND. El sensor LDR es analogico — mide un rango de 0 a 1023, no solo 0 o 1.
3
Conecta el ventilador: pin Signal a P1, VCC a 3.3V, GND a GND. El pin P1 es compatible con PWM — esto es lo que permite controlar la velocidad de forma proporcional.
4
Conecta la OLED: CLK/SCL al pin SCL de la placa, DA/SDA al pin SDA, VCC a 3.3V, GND a GND. Si ya hiciste el Proyecto 05, el proceso es identico.
5
Recuerda la extension OLED: ve a MakeCode → Extensiones → busca "oled" e instalala si no lo has hecho en el proyecto anterior.
</> Programacion

El codigo del proyecto

El codigo lee la luz cada 500ms, convierte el valor al rango de velocidad del motor con Math.map, aplica PWM al ventilador y muestra el estado en la OLED. Los botones A y B permiten control manual de emergencia.

Como funciona el control proporcional en este proyecto
Luz: 100
Vel: 10%
Luz: 300
Vel: 30%
Luz: 500
Vel: 50%
Luz: 700
Vel: 70%
Luz: 950
Vel: 93%
A mas luz detectada por el sensor, mayor velocidad del ventilador. Math.map hace la conversion matematica entre el rango del sensor (0-1023) y el rango PWM del motor (0-1023) de forma proporcional.
💡
Extension OLED requerida: En MakeCode ve a Extensiones y busca "oled". Instala la de Kitronik. Si ya lo hiciste en el Proyecto 05, no hace falta repetirlo — la extension se guarda por proyecto.
JavaScript — MakeCode (requiere extension OLED)
// Abanico inteligente con control PWM
// La velocidad del ventilador varía según la luz

let nivelLuz = 0
let velocidadMotor = 0

// Inicializar OLED (128x64 pixels)
OLED.init(128, 64)

basic.forever(function () {
    // Leer sensor de luz (0-1023)
    nivelLuz = pins.analogReadPin(AnalogPin.P0)

    // Convertir luz a velocidad del motor (proporcional, mismo rango)
    velocidadMotor = Math.map(nivelLuz, 0, 1023, 0, 1023)

    // Controlar ventilador con PWM
    pins.analogWritePin(AnalogPin.P1, velocidadMotor)

    // Mostrar estado en OLED
    OLED.clear()
    OLED.writeString("=== ABANICO ===")
    OLED.writeString("Luz: " + nivelLuz)
    OLED.writeString("Velocidad: " + Math.round(velocidadMotor / 10) + "%")

    if (velocidadMotor < 300) {
        OLED.writeString("ESTADO: Parado")
        basic.showIcon(IconNames.SmallSquare)
    } else if (velocidadMotor < 700) {
        OLED.writeString("ESTADO: Medio")
        basic.showIcon(IconNames.Square)
    } else {
        OLED.writeString("ESTADO: Maximo")
        basic.showIcon(IconNames.Yes)
    }

    basic.pause(500)
})

// Botón A: forzar ventilador apagado (modo manual OFF)
input.onButtonPressed(Button.A, function () {
    pins.analogWritePin(AnalogPin.P1, 0)
    OLED.clear()
    OLED.writeString("MODO MANUAL")
    OLED.writeString("Ventilador: OFF")
    basic.pause(2000)
})

// Botón B: forzar ventilador a tope (modo manual MAX)
input.onButtonPressed(Button.B, function () {
    pins.analogWritePin(AnalogPin.P1, 1023)
    OLED.clear()
    OLED.writeString("MODO MANUAL")
    OLED.writeString("Ventilador: MAX")
    basic.pause(2000)
})
MicroPython (requiere libreria ssd1306)
from microbit import *
import ssd1306

oled = ssd1306.SSD1306_I2C(128, 64, i2c)

# Función para mapear un valor de un rango a otro
def mapear(valor, min_ent, max_ent, min_sal, max_sal):
    return int((valor - min_ent) * (max_sal - min_sal) / (max_ent - min_ent) + min_sal)

while True:
    # Leer sensor de luz (0-1023)
    nivel_luz = pin0.read_analog()

    # Calcular velocidad proporcional a la luz
    velocidad = mapear(nivel_luz, 0, 1023, 0, 1023)

    # Control PWM del ventilador
    pin1.write_analog(velocidad)

    # Mostrar en OLED
    oled.fill(0)
    oled.text("ABANICO INTEL.", 0, 0)
    oled.text("Luz: " + str(nivel_luz), 0, 16)
    porcentaje = int(velocidad / 10.23)
    oled.text("Vel: " + str(porcentaje) + "%", 0, 32)

    if velocidad < 300:
        oled.text("Parado", 0, 48)
        display.show(Image.SQUARE_SMALL)
    elif velocidad < 700:
        oled.text("Velocidad media", 0, 48)
    else:
        oled.text("Velocidad max!", 0, 48)

    oled.show()

    # Control manual con botones
    if button_a.was_pressed():
        pin1.write_analog(0)
        sleep(2000)
    if button_b.was_pressed():
        pin1.write_analog(1023)
        sleep(2000)

    sleep(500)
✓ Pruebalo

Que deberia pasar

Comprueba cada paso. Tapa el sensor con la mano para ver el efecto — la diferencia entre mucha y poca luz debe notarse claramente en la velocidad del ventilador.

Al encender: la OLED muestra "ABANICO", el valor de luz actual y el porcentaje de velocidad. El ventilador puede estar girando o parado segun la luz del ambiente.
Apuntando una linterna al sensor: el valor de luz sube (por encima de 700), el porcentaje de velocidad aumenta y el ventilador gira a mayor velocidad. La OLED muestra "ESTADO: Maximo".
Tapando el sensor con la mano: el valor de luz baja, la velocidad disminuye progresivamente. El ventilador puede llegar a pararse si tapas completamente el sensor.
Pulsando el boton A: el ventilador se para inmediatamente y la OLED muestra "MODO MANUAL / Ventilador: OFF" durante 2 segundos. Luego el sistema vuelve al modo automatico.
Pulsando el boton B: el ventilador va a maxima velocidad y la OLED muestra "MODO MANUAL / Ventilador: MAX" durante 2 segundos. Despues vuelve al automatico.
Transiciones suaves: al mover gradualmente una fuente de luz, el ventilador deberia cambiar de velocidad de forma progresiva, no de golpe. Esto es el control proporcional en accion.
🎯 Actividades

Amplia el proyecto

El Desafio 1 mejora la estabilidad del sistema. Los demas exploran conceptos avanzados de control: umbrales, logica inversa y memoria de maximo.

🎯 Desafio 1 — Basico
Umbral minimo de arranque
Anade un umbral minimo: el ventilador no gira si la luz es menor de 200 (evita que gire por ruido del sensor). Usa un if antes de llamar a analogWritePin: si nivelLuz < 200, escribe 0 directamente sin hacer el mapeo.
🎯 Desafio 2 — Medio
Tres velocidades fijas
En vez de control proporcional continuo, implementa 3 velocidades fijas: parado (luz < 300 → motor = 0), media (300-700 → motor = 512), maxima (luz > 700 → motor = 1023). Compara como se siente respecto al control proporcional: ¿cual prefieres y por que?
🎯 Desafio 3 — Avanzado
Logica invertida
Invierte la logica: a menos luz, mas velocidad del ventilador (simula un "abanico nocturno" o un sistema de refrigeracion que trabaja mas cuando se apagan las luces de una habitacion). Cambia el mapeo: Math.map(nivelLuz, 0, 1023, 1023, 0).
🎯 Desafio 4 — Experto
Historial de maximo
Anade una variable maxLuz que guarda el valor mas alto de luz que ha visto el sensor desde que arranco. Mostrala en la cuarta linea de la OLED como "Max: XXX". Para resetearla usa el boton A+B a la vez (en MakeCode: input.onButtonPressed(Button.AB, ...)).
⚠ Problemas frecuentes

Algo no funciona?

Los problemas mas comunes con el ventilador son de conexion o de rango del sensor. Lee el sintoma que reconoces.

"El ventilador no gira con ninguna cantidad de luz"
Primero prueba con el boton B — deberia ir a tope. Si no gira ni con el boton B, el problema es la conexion: revisa que el cable Signal del ventilador esta en P1 y que VCC y GND estan bien conectados. Si gira con B pero no en automatico, el problema esta en el sensor de luz — prueba a iluminarlo directamente con una linterna.
"El ventilador siempre va a maxima velocidad, no cambia"
El sensor de luz esta recibiendo mucha luz del entorno (luz solar directa, lampara cerca). Tapa el sensor con la mano y observa si el valor en la OLED baja. Si baja, el sensor funciona — solo necesitas ajustar el entorno. Si el valor no baja aunque tapes el sensor, comprueba que esta conectado a P0 y no a otro pin.
"La velocidad cambia muy bruscamente — da saltos en vez de ser suave"
El sensor LDR puede ser sensible a pequenas fluctuaciones de luz. Para suavizarlo, calcula la media de varias lecturas: antes de usar nivelLuz, lee el sensor 3 veces y haz la media: (pin0.readAnalog() + pin0.readAnalog() + pin0.readAnalog()) / 3. Esto reduce el ruido del sensor.
"Math.map da error o no existe en MakeCode"
Asegurate de estar en modo JavaScript en MakeCode (no en Bloques). Math.map es una funcion especifica de MakeCode que no existe en JavaScript estandar — funciona perfectamente en el editor de MakeCode. Si ves un subrayado rojo, prueba a hacer clic en "Descargar" igualmente; a veces el editor marca falsos errores que no impiden la compilacion.
🚀 Mas alla

Ideas para seguir explorando

El control proporcional (PWM) es uno de los conceptos mas importantes en electronica. Ahora que lo entiendes, lo veras en todas partes.

🔌
Reguladores de luz (dimmers) Los interruptores de intensidad regulable de las luces de casa usan PWM exactamente igual que tu proyecto. La diferencia es que usan voltaje de 220V en lugar de 3.3V — pero el principio matematico es identico.
🚗
Control de motores en coches Los coches electricos controlan la velocidad de sus motores con PWM. Cuando el conductor pisa el acelerador a medias, el controlador aplica un ciclo de trabajo proporcional — exactamente lo que hace tu Math.map.
Cargadores de bateria Los cargadores rapidos de movil ajustan el voltaje y la corriente dinamicamente usando control proporcional. El chip del cargador lee la bateria (el sensor) y ajusta la potencia (el actuador) — igual que tu sensor y ventilador.
🕐
PID: el siguiente nivel El control proporcional de este proyecto es el "P" de PID (Proporcional-Integral-Derivativo). Los sistemas de control avanzados (impresoras 3D, drones, coches autonomos) usan PID completo para mayor precision y estabilidad.