.. note:: ¡Hola, bienvenido a la Comunidad de Entusiastas de SunFounder Raspberry Pi & Arduino & ESP32 en Facebook! Profundiza en Raspberry Pi, Arduino y ESP32 con otros entusiastas. **¿Por qué unirte?** - **Soporte experto**: Resuelve problemas postventa y desafíos técnicos con la ayuda de nuestra comunidad y equipo. - **Aprende y comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades. - **Avances exclusivos**: Obtén acceso anticipado a anuncios de nuevos productos y vistas previas. - **Descuentos especiales**: Disfruta de descuentos exclusivos en nuestros productos más nuevos. - **Promociones y sorteos festivos**: Participa en sorteos y promociones especiales en fechas señaladas. 👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y ¡únete hoy! .. _2.1.6_c_mcp3008: 2.1.6 Joystick (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 continúa con la sección correspondiente. Introducción -------------- En este proyecto vamos a aprender cómo funciona un joystick. Manipularemos el joystick y mostraremos los resultados en la pantalla. Componentes requeridos ------------------------------- En este proyecto necesitaremos los siguientes componentes. .. image:: img/image317-copy.png Principio --------- **Joystick** La idea básica de un joystick es traducir el movimiento de una palanca en información electrónica que un ordenador pueda procesar. Para comunicar un rango completo de movimiento al ordenador, un joystick necesita medir la posición de la palanca en dos ejes: el eje X (izquierda a derecha) y el eje Y (arriba y abajo). Tal como en geometría básica, las coordenadas X-Y determinan la posición exacta de la palanca. Para determinar la ubicación de la palanca, el sistema de control del joystick simplemente monitorea la posición de cada eje. El diseño convencional de un joystick analógico hace esto con dos potenciómetros o resistencias variables. El joystick también tiene una entrada digital que se activa cuando se presiona hacia abajo. .. image:: img/image318.png Diagrama esquemático -------------------- Cuando se leen los datos del joystick, hay diferencias entre los ejes: los datos de los ejes X e Y son analógicos, por lo que es necesario usar un MCP3008 para convertir el valor analógico a digital. Los datos del eje Z son digitales, por lo que puedes leerlos directamente desde un GPIO, o también usando el ADC. .. .. image:: img/image319.png * - Nombre en la T-Board - Físico - WiringPi - BCM * - SPICE0 - pin24 - 10 - 8 * - SPIMOSI - pin19 - 12 - 10 * - SPIMISO - pin21 - 13 - 9 * - SPISCLK - pin23 - 14 - 11 * - GPIO22 - pin15 - 3 - 22 .. image:: img/schematic_2.1.9_joystick_mcp3008.png Procedimiento experimental -------------------------- **Paso 1:** Construir el circuito. .. image:: img/july24_2.1.9_joystick_mcp3008.png Para usuarios de lenguaje C ^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Paso 2:** Ve a la carpeta del código. .. raw:: html .. code-block:: cd ~/davinci-kit-for-raspberry-pi/c/2.1.6-2/ **Paso 3:** Compila el código. .. raw:: html .. code-block:: gcc 2.1.6_Joystick.c -o joystick -lwiringPi **Paso 4:** Ejecuta el archivo compilado. .. raw:: html .. code-block:: ./joystick Después de ejecutar el código, mueve el joystick y se mostrarán en pantalla los valores correspondientes de x, y y Btn. .. note:: Si no funciona después de ejecutarlo, o aparece el mensaje de error: "wiringPi.h: No such file or directory", consulta :ref:`install_wiringpi`. **Código** .. code-block:: c #include #include #include #define SPI_CHANNEL 0 #define SPI_SPEED 1000000 // 1 MHz #define BtnPin 3 // WiringPi 3 = BCM GPIO22 // Leer desde el canal del MCP3008 (0–7) int read_ADC(int channel) { if (channel < 0 || channel > 7) return -1; unsigned char buffer[3]; buffer[0] = 1; // Bit de inicio buffer[1] = (8 + channel) << 4; // Configuración de canal buffer[2] = 0; wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3); int result = ((buffer[1] & 0x03) << 8) | buffer[2]; return result; } int main(void) { if (wiringPiSetup() == -1) { printf("¡Error en la inicialización de WiringPi!\n"); return 1; } if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) { printf("¡Error en la configuración de SPI!\n"); return 1; } pinMode(BtnPin, INPUT); pullUpDnControl(BtnPin, PUD_UP); while (1) { int x_val = read_ADC(0); // VRX en CH0 int y_val = read_ADC(1); // VRY en CH1 int btn_val = digitalRead(BtnPin); // Botón SW printf("x = %d, y = %d, btn = %d\n", x_val, y_val, btn_val); delay(100); } return 0; } **Explicación del código** #. Esta sección inicializa las librerías necesarias para GPIO y comunicación SPI. .. code-block:: c #include #include #include #define SPI_CHANNEL 0 #define SPI_SPEED 1000000 // 1 MHz #define BtnPin 3 // WiringPi 3 = BCM GPIO22 #. Define la función ``read_ADC()`` para leer datos analógicos desde el MCP3008. Se comunica por SPI solicitando datos de un canal dado (0–7) y procesa la respuesta para obtener un valor ADC de 10 bits. .. code-block:: c int read_ADC(int channel) { if (channel < 0 || channel > 7) return -1; unsigned char buffer[3]; buffer[0] = 1; buffer[1] = (8 + channel) << 4; buffer[2] = 0; wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3); int result = ((buffer[1] & 0x03) << 8) | buffer[2]; return result; } #. La función principal inicializa WiringPi y SPI, configura el pin del botón del joystick, y lee continuamente los valores del joystick para mostrarlos por consola. .. code-block:: c int main(void) { if (wiringPiSetup() == -1) { printf("¡Error en la inicialización de WiringPi!\n"); return 1; } if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) { printf("¡Error en la configuración de SPI!\n"); return 1; } pinMode(BtnPin, INPUT); pullUpDnControl(BtnPin, PUD_UP); while (1) { int x_val = read_ADC(0); // VRX a CH0 int y_val = read_ADC(1); // VRY a CH1 int btn_val = digitalRead(BtnPin); // SW a GPIO22 printf("x = %d, y = %d, btn = %d\n", x_val, y_val, btn_val); delay(100); } return 0; } Para usuarios de lenguaje Python ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Paso 2:** Configura la interfaz SPI e instala la librería ``spidev`` (consulta :ref:`spi_configuration` para instrucciones detalladas). Si ya completaste estos pasos, puedes omitirlos. **Paso 3:** Ve a la carpeta del código. .. raw:: html .. code-block:: cd ~/davinci-kit-for-raspberry-pi/python **Paso 4:** Ejecuta. .. raw:: html .. code-block:: sudo python3 2.1.6-2_Joystick.py Después de ejecutar el código, mueve el joystick y se mostrarán en pantalla los valores correspondientes de X, Y y Btn. .. warning:: Si aparece el error ``RuntimeError: Cannot determine SOC peripheral base address``, consulta :ref:`faq_soc`. **Código** .. note:: Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Pero antes de eso, debes ir a la ruta del código fuente, como ``davinci-kit-for-raspberry-pi/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 # Definir pin GPIO para el botón del joystick (pin SW) BTN_PIN = 22 # Configurar el modo de numeración GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Usar resistencia pull-up interna # Inicializar comunicación SPI con MCP3008 spi = spidev.SpiDev() spi.open(0, 0) # Bus SPI 0, CE0 spi.max_speed_hz = 1000000 # 1 MHz def read_adc(channel): """ Lee el valor analógico del canal especificado del MCP3008 (0–7) :param channel: número de canal del ADC (0–7) :return: valor entero de 10 bits (0–1023) """ 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 try: # Bucle principal para leer e imprimir los valores del joystick y el estado del botón while True: # Leer valores X e Y desde los canales 1 y 2 del MCP3008 x_val = read_adc(1) # VRX del joystick conectado a CH1 y_val = read_adc(2) # VRY del joystick conectado a CH2 # Leer estado del botón del joystick (SW) Btn_val = GPIO.input(BTN_PIN) # 0 = presionado, 1 = liberado # Imprimir los valores leídos print('X: %d Y: %d Btn: %d' % (x_val, y_val, Btn_val)) time.sleep(0.2) except KeyboardInterrupt: pass finally: spi.close() GPIO.cleanup() **Explicación del código** .. code-block:: python #!/usr/bin/env python3 import RPi.GPIO as GPIO import spidev import time Esta sección importa las librerías necesarias: - ``RPi.GPIO`` se usa para manejar la entrada GPIO (botón del joystick). - ``spidev`` se usa para comunicarse con el chip ADC MCP3008 vía SPI. - ``time`` se usa para introducir pausas entre lecturas. .. code-block:: python # Definir pin GPIO para el botón del joystick (pin SW) BTN_PIN = 22 # Configurar el modo de numeración GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Inicializar comunicación SPI con MCP3008 spi = spidev.SpiDev() spi.open(0, 0) # Bus SPI 0, CE0 spi.max_speed_hz = 1000000 Este bloque configura el modo GPIO como ``BCM``, inicializa la entrada para el botón del joystick en el GPIO22 con resistencia pull-up, y configura la interfaz SPI con el MCP3008 usando bus 0 y chip enable 0 (CE0) a 1 MHz. .. code-block:: python def read_adc(channel): """ Lee el valor analógico del canal especificado del MCP3008 (0–7) :param channel: número de canal del ADC (0–7) :return: valor entero de 10 bits (0–1023) """ 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 Define la función ``read_adc()`` para leer datos analógicos desde un canal específico del MCP3008. Envía tres bytes por SPI e interpreta la respuesta para devolver un valor de 10 bits entre 0 y 1023. .. code-block:: python try: # Bucle principal para leer e imprimir los valores del joystick y el estado del botón while True: # Leer valores X e Y desde los canales 0 y 1 del MCP3008 x_val = read_adc(0) # VRX del joystick conectado a CH0 y_val = read_adc(1) # VRY del joystick conectado a CH1 # Leer estado del botón del joystick (SW) Btn_val = GPIO.input(BTN_PIN) # 0 = presionado, 1 = liberado # Imprimir los valores leídos print('X: %d Y: %d Btn: %d' % (x_val, y_val, Btn_val)) time.sleep(0.2) except KeyboardInterrupt: pass finally: spi.close() GPIO.cleanup() Este bucle principal lee y muestra en pantalla las posiciones X/Y analógicas del joystick y el estado de su botón cada 200 ms. Si se interrumpe el script con el teclado (Ctrl+C), se cierran correctamente las conexiones SPI y GPIO.