.. note:: ¡Hola, bienvenido a la Comunidad de Entusiastas de SunFounder Raspberry Pi & Arduino & ESP32 en Facebook! Sumérgete en el mundo de Raspberry Pi, Arduino y ESP32 junto a otros entusiastas. **¿Por qué unirse?** - **Soporte experto**: Resuelve problemas postventa y desafíos técnicos con la ayuda de nuestra comunidad y equipo. - **Aprender y compartir**: Intercambia consejos y tutoriales para mejorar tus habilidades. - **Preestrenos exclusivos**: Obtén acceso anticipado a nuevos anuncios de productos y adelantos. - **Descuentos especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes. - **Promociones y sorteos festivos**: Participa en sorteos y promociones especiales de temporada. 👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy mismo. .. _4.1.10_py_mcp3008: 4.1.10 Ventilador Inteligente (MCP3008) ======================================= .. note:: .. image:: ../img/mcp3008_and_adc0834.jpg :width: 25% :align: left Dependiendo de la versión de tu kit, identifica si tienes **ADC0834** o **MCP3008** y procede con la sección correspondiente. Introducción ------------ En este proyecto, utilizaremos motores, botones y termistores para hacer un ventilador inteligente manual + automático cuya velocidad de viento es ajustable. Componentes requeridos ---------------------- En este proyecto, necesitamos los siguientes componentes. .. image:: ../img/list2_Smart_Fan.png :width: 800 :align: center Es definitivamente conveniente comprar un kit completo, aquí tienes el enlace: .. list-table:: :widths: 20 20 20 :header-rows: 1 * - Nombre - ELEMENTOS EN ESTE KIT - ENLACE * - Kit Raphael - 337 - |link_Raphael_kit| También puedes comprarlos por separado en los siguientes enlaces. .. list-table:: :widths: 30 20 :header-rows: 1 * - INTRODUCCIÓN DEL COMPONENTE - ENLACE DE COMPRA * - :ref:`cpn_gpio_board` - |link_gpio_board_buy| * - :ref:`cpn_breadboard` - |link_breadboard_buy| * - :ref:`cpn_wires` - |link_wires_buy| * - :ref:`cpn_resistor` - |link_resistor_buy| * - :ref:`cpn_power_module` - \- * - :ref:`cpn_thermistor` - |link_thermistor_buy| * - :ref:`cpn_l293d` - \- * - :ref:`cpn_mcp3008` - \- * - :ref:`cpn_button` - |link_button_buy| * - :ref:`cpn_motor` - |link_motor_buy| Diagrama esquemático -------------------- .. list-table:: :header-rows: 1 * - Nombre - T-Board - WiringPi - BCM * - SPICE0 - Pin 24 - 10 - 8 * - SPIMOSI - Pin 19 - 12 - 10 * - SPIMISO - Pin 21 - 13 - 9 * - SPISCLK - Pin 23 - 14 - 11 * - GPIO22 - Pin 15 - 3 - 22 * - GPIO5 - Pin 29 - 21 - 5 * - GPIO6 - Pin 31 - 22 - 6 * - GPIO13 - Pin 33 - 23 - 13 .. image:: ../img/schematic_3.1.4_smart_fan_mcp3008.png :align: center Procedimientos experimentales ----------------------------- **Paso 1:** Construir el circuito. .. image:: ../img/july24_3.1.4_smart_fan_mcp3008.png .. note:: El módulo de alimentación puede usar una batería de 9V con el conector de batería de 9V incluido en el kit. Inserta el jumper del módulo de alimentación en las líneas de bus de 5V de la protoboard. .. image:: ../img/image118.jpeg :align: center **Paso 2:** Configura la interfaz SPI e instala la librería ``spidev`` (consulta :ref:`spi_configuration` para instrucciones detalladas). Si ya has completado estos pasos, puedes omitirlos. **Paso 3:** Entra a la carpeta del código. .. raw:: html .. code-block:: cd ~/raphael-kit/python **Paso 4:** Ejecuta. .. raw:: html .. code-block:: sudo python3 4.1.10-2_SmartFan.py Al ejecutar el código, inicia el ventilador presionando el botón. Cada vez que lo presiones, se ajustará la velocidad en un nivel arriba o abajo. Hay **5** niveles de velocidad: **0~4**. Cuando se ajusta al **4°** nivel y presionas de nuevo el botón, el ventilador se detiene con velocidad **0**. Una vez que la temperatura suba o baje más de 2℃, la velocidad automáticamente aumenta o disminuye un nivel. Código ------ .. note:: Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código siguiente. Pero antes de eso, necesitas ir a la ruta del código fuente como ``raphael-kit/python``. Después de modificar el código, puedes ejecutarlo directamente para ver el efecto. .. raw:: html .. code-block:: python #!/usr/bin/env python3 import RPi.GPIO as GPIO import spidev import time import math # Configuración de pines BTN_PIN = 22 # Botón GPIO (pin físico 15) MOTOR_IN1 = 5 # Motor hacia adelante MOTOR_IN2 = 6 # Motor hacia atrás MOTOR_EN = 13 # Pin de habilitación PWM # Configuración GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(MOTOR_IN1, GPIO.OUT) GPIO.setup(MOTOR_IN2, GPIO.OUT) GPIO.setup(MOTOR_EN, GPIO.OUT) # Configuración PWM para control de velocidad del motor pwm = GPIO.PWM(MOTOR_EN, 1000) # Frecuencia 1kHz pwm.start(0) # Inicializar SPI para MCP3008 spi = spidev.SpiDev() spi.open(0, 0) # Bus 0, CE0 spi.max_speed_hz = 1000000 # 1 MHz # Variables globales level = 0 currentTemp = 0 markTemp = 0 def read_adc(channel): if channel < 0 or channel > 7: return -1 adc = spi.xfer2([1, (8 + channel) << 4, 0]) value = ((adc[1] & 0x03) << 8) | adc[2] return value def temperature(): analogVal = read_adc(0) Vr = 3.3 * analogVal / 1023.0 Rt = 10000.0 * Vr / (3.3 - Vr) tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0))) Cel = tempK - 273.15 return Cel def motor_run(level): if level == 0: GPIO.output(MOTOR_IN1, GPIO.LOW) GPIO.output(MOTOR_IN2, GPIO.LOW) pwm.ChangeDutyCycle(0) return 0 if level >= 4: level = 4 GPIO.output(MOTOR_IN1, GPIO.HIGH) GPIO.output(MOTOR_IN2, GPIO.LOW) pwm.ChangeDutyCycle(level * 25) # Mapea nivel (1–4) a 25%–100% return level def changeLevel(channel): global level, currentTemp, markTemp print("Botón presionado") level = (level + 1) % 5 markTemp = currentTemp # Detección de evento para pulsación del botón GPIO.add_event_detect(BTN_PIN, GPIO.FALLING, callback=changeLevel, bouncetime=300) def main(): global level, currentTemp, markTemp markTemp = temperature() while True: currentTemp = temperature() if level != 0: if currentTemp - markTemp <= -2: level -= 1 markTemp = currentTemp elif currentTemp - markTemp >= 2: if level < 4: level += 1 markTemp = currentTemp level = motor_run(level) time.sleep(0.2) try: main() except KeyboardInterrupt: pass finally: pwm.stop() GPIO.cleanup() spi.close() Explicación del código ---------------------- #. Importar los módulos requeridos: - ``RPi.GPIO`` para control de GPIO (botón y motor), - ``spidev`` para comunicación con el MCP3008, - ``time`` para retardos, - ``math`` para el cálculo de temperatura usando funciones logarítmicas. .. code-block:: python #!/usr/bin/env python3 import RPi.GPIO as GPIO import spidev import time import math #. Configurar pines GPIO: - Botón en GPIO22 (con resistencia pull-up interna), - Control de motor usando GPIO5 (adelante), GPIO6 (atrás) y GPIO13 (habilitación PWM). .. code-block:: python BTN_PIN = 22 MOTOR_IN1 = 5 MOTOR_IN2 = 6 MOTOR_EN = 13 GPIO.setmode(GPIO.BCM) GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(MOTOR_IN1, GPIO.OUT) GPIO.setup(MOTOR_IN2, GPIO.OUT) GPIO.setup(MOTOR_EN, GPIO.OUT) pwm = GPIO.PWM(MOTOR_EN, 1000) pwm.start(0) #. Inicializar comunicación SPI con MCP3008 (Bus 0, Chip Enable 0) a 1 MHz. .. code-block:: python spi = spidev.SpiDev() spi.open(0, 0) spi.max_speed_hz = 1000000 #. Definir función ``read_adc()`` para leer un valor analógico de 10 bits (0–1023) del canal MCP3008 especificado (0–7). .. code-block:: python def read_adc(channel): if channel < 0 or channel > 7: return -1 adc = spi.xfer2([1, (8 + channel) << 4, 0]) value = ((adc[1] & 0x03) << 8) | adc[2] return value #. Definir función ``temperature()`` para: - Convertir voltaje analógico a resistencia, - Aplicar la ecuación Steinhart–Hart simplificada para calcular temperatura en Celsius. .. code-block:: python def temperature(): analogVal = read_adc(0) Vr = 3.3 * analogVal / 1023.0 Rt = 10000.0 * Vr / (3.3 - Vr) tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0))) Cel = tempK - 273.15 return Cel #. Definir ``motor_run()`` para: - Detener el motor en nivel 0, - Ejecutar el motor hacia adelante con mayor velocidad según nivel 1–4, con ciclo de trabajo PWM de 25% a 100%. .. code-block:: python def motor_run(level): if level == 0: GPIO.output(MOTOR_IN1, GPIO.LOW) GPIO.output(MOTOR_IN2, GPIO.LOW) pwm.ChangeDutyCycle(0) return 0 if level >= 4: level = 4 GPIO.output(MOTOR_IN1, GPIO.HIGH) GPIO.output(MOTOR_IN2, GPIO.LOW) pwm.ChangeDutyCycle(level * 25) return level #. Definir función de callback ``changeLevel()`` para el botón: - Aumentar el nivel del motor cíclicamente (0 a 4), - Registrar la temperatura actual como nueva referencia. .. code-block:: python def changeLevel(channel): global level, currentTemp, markTemp print("Botón presionado") level = (level + 1) % 5 markTemp = currentTemp GPIO.add_event_detect(BTN_PIN, GPIO.FALLING, callback=changeLevel, bouncetime=300) #. Definir bucle ``main()`` para: - Monitorear cambios de temperatura respecto a la temperatura de referencia, - Disminuir el nivel si la temperatura baja 2°C o más, - Aumentar el nivel si la temperatura sube 2°C o más, - Ajustar la velocidad del motor cada 0,2 segundos. .. code-block:: python def main(): global level, currentTemp, markTemp markTemp = temperature() while True: currentTemp = temperature() if level != 0: if currentTemp - markTemp <= -2: level -= 1 markTemp = currentTemp elif currentTemp - markTemp >= 2: if level < 4: level += 1 markTemp = currentTemp level = motor_run(level) time.sleep(0.2) #. Ejecutar la función principal y asegurar limpieza al presionar Ctrl+C (detener motor, limpiar GPIO, cerrar SPI). .. code-block:: python try: main() except KeyboardInterrupt: pass finally: pwm.stop() GPIO.cleanup() spi.close()