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
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.
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.
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.
Procedimiento experimental
Paso 1: Construir el circuito.
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
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
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; }
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.GPIOse usa para manejar la entrada GPIO (botón del joystick).spidevse usa para comunicarse con el chip ADC MCP3008 vía SPI.timese 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.