Nota

¡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 [Aquí] y ¡únete hoy!

2.1.6 Joystick (MCP3008)

Nota

_images/mcp3008_and_adc0834.jpg

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.

_images/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.

_images/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.

_images/schematic_2.1.9_joystick_mcp3008.png

Procedimiento experimental

Paso 1: Construir el circuito.

_images/july24_2.1.9_joystick_mcp3008.png

Para usuarios de lenguaje C

Paso 2: Ve a la carpeta del código.

cd ~/davinci-kit-for-raspberry-pi/c/2.1.6-2/

Paso 3: Compila el código.

gcc 2.1.6_Joystick.c -o joystick -lwiringPi

Paso 4: Ejecuta el archivo compilado.

./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.

Nota

Si no funciona después de ejecutarlo, o aparece el mensaje de error: «wiringPi.h: No such file or directory», consulta Instalar y Comprobar WiringPi.

Código

#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <stdio.h>

#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

  1. Esta sección inicializa las librerías necesarias para GPIO y comunicación SPI.

    #include <wiringPi.h>
    #include <wiringPiSPI.h>
    #include <stdio.h>
    
    #define SPI_CHANNEL 0
    #define SPI_SPEED   1000000  // 1 MHz
    #define BtnPin      3        // WiringPi 3 = BCM GPIO22
    
  2. 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.

    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;
    }
    
  3. 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.

    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 Configuración de SPI para instrucciones detalladas). Si ya completaste estos pasos, puedes omitirlos.

Paso 3: Ve a la carpeta del código.

cd ~/davinci-kit-for-raspberry-pi/python

Paso 4: Ejecuta.

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.

Advertencia

Si aparece el error RuntimeError: Cannot determine SOC peripheral base address, consulta Si gpiozero no funciona..

Código

Nota

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.

#!/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

#!/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.

# 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.

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.

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.