Nota

Ciao, benvenuto nella Community Facebook degli appassionati di SunFounder Raspberry Pi & Arduino & ESP32! Approfondisci Raspberry Pi, Arduino ed ESP32 insieme ad altri appassionati.

Perché unirti?

  • Supporto esperto: Risolvi problemi post-vendita e sfide tecniche con l’aiuto della nostra community e del nostro team.

  • Impara e condividi: Scambia suggerimenti e tutorial per migliorare le tue competenze.

  • Anteprime esclusive: Accedi in anteprima ai nuovi annunci di prodotto e agli sneak peek.

  • Sconti speciali: Godi di sconti esclusivi sui nostri prodotti più recenti.

  • Promozioni e giveaway festivi: Partecipa a concorsi e promozioni festive.

👉 Pronto a esplorare e creare con noi? Clicca [Qui] e unisciti oggi stesso!

2.1.6 Joystick (MCP3008)

Nota

_images/mcp3008_and_adc0834.jpg

A seconda della versione del tuo kit, identifica se hai ADC0834 o MCP3008 e segui la sezione corrispondente.

Introduzione

In questo progetto impareremo come funziona un joystick. Muoviamo il joystick e visualizziamo i risultati sullo schermo.

Componenti necessari

In questo progetto utilizziamo i seguenti componenti.

_images/image317-copy.png

Principio

Joystick

Il concetto di base di un joystick è tradurre il movimento di una leva in informazioni elettroniche che un computer può elaborare.

Per comunicare l’intera gamma di movimenti al computer, un joystick deve misurare la posizione della leva su due assi: l’asse X (da sinistra a destra) e l’asse Y (dal basso verso l’alto). Come nella geometria di base, le coordinate X-Y individuano esattamente la posizione della leva.

Per determinare la posizione della leva, il sistema di controllo del joystick monitora semplicemente la posizione di ciascun asse. Il design convenzionale del joystick analogico lo fa utilizzando due potenziometri, o resistori variabili.

Il joystick ha anche un ingresso digitale che si attiva quando viene premuto verso il basso.

_images/image318.png

Schema elettrico

Quando si leggono i dati del joystick, ci sono alcune differenze tra gli assi: i dati degli assi X e Y sono analogici, quindi è necessario usare MCP3008 per convertirli in valori digitali. I dati dell’asse Z sono digitali, quindi puoi leggerli direttamente tramite GPIO o anche tramite ADC.

_images/schematic_2.1.9_joystick_mcp3008.png

Procedura sperimentale

Passo 1: Monta il circuito.

_images/july24_2.1.9_joystick_mcp3008.png

Per utenti C

Passo 2: Vai alla cartella del codice.

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

Passo 3: Compila il codice.

gcc 2.1.6_Joystick.c -o joystick -lwiringPi

Passo 4: Esegui il file eseguibile.

./joystick

Dopo aver eseguito il codice, muovi il joystick: i valori corrispondenti di x, y e Btn saranno visualizzati sullo schermo.

Nota

Se non funziona dopo l’esecuzione o compare l’errore «wiringPi.h: No such file or directory», fai riferimento a Installare e Verificare WiringPi.

Codice

#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

// Lettura dal canale MCP3008 (0–7)
int read_ADC(int channel) {
    if (channel < 0 || channel > 7) return -1;

    unsigned char buffer[3];
    buffer[0] = 1;                            // Bit di avvio
    buffer[1] = (8 + channel) << 4;           // Configurazione canale
    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("Inizializzazione WiringPi fallita!\n");
        return 1;
    }

    if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
        printf("Configurazione SPI fallita!\n");
        return 1;
    }

    pinMode(BtnPin, INPUT);
    pullUpDnControl(BtnPin, PUD_UP);

    while (1) {
        int x_val = read_ADC(0);     // VRX su CH0
        int y_val = read_ADC(1);     // VRY su CH1
        int btn_val = digitalRead(BtnPin);  // Pulsante SW

        printf("x = %d, y = %d, btn = %d\n", x_val, y_val, btn_val);
        delay(100);
    }

    return 0;
}

Spiegazione del codice

  1. Questa sezione inizializza le librerie necessarie per la comunicazione GPIO e 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. Definisce la funzione read_ADC() per leggere i dati analogici dal MCP3008. Comunica via SPI per richiedere dati da un canale (0–7) e interpreta la risposta per ottenere un valore ADC a 10 bit.

    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 funzione main inizializza WiringPi e SPI, configura il pin del pulsante del joystick e legge continuamente i valori, stampandoli sul terminale.

    int main(void) {
        if (wiringPiSetup() == -1) {
            printf("Inizializzazione WiringPi fallita!\n");
            return 1;
        }
    
        if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
            printf("Configurazione SPI fallita!\n");
            return 1;
        }
    
        pinMode(BtnPin, INPUT);
        pullUpDnControl(BtnPin, PUD_UP);
    
        while (1) {
            int x_val = read_ADC(0);     // VRX su CH0
            int y_val = read_ADC(1);     // VRY su CH1
            int btn_val = digitalRead(BtnPin);  // SW su GPIO22
    
            printf("x = %d, y = %d, btn = %d\n", x_val, y_val, btn_val);
            delay(100);
        }
    
        return 0;
    }
    

Per utenti Python

Passo 2: Configura l’interfaccia SPI e installa la libreria spidev (vedi Configurazione SPI per le istruzioni dettagliate). Se hai già completato questi passaggi, puoi saltarli.

Passo 3: Vai alla cartella del codice.

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

Passo 4: Esegui.

sudo python3 2.1.6-2_Joystick.py

Dopo aver eseguito il codice, muovi il joystick: i valori corrispondenti di x, y e Btn saranno visualizzati sullo schermo.

Avvertimento

Se compare l’errore RuntimeError: Cannot determine SOC peripheral base address, fai riferimento a Se gpiozero non funziona.

Codice

Nota

Puoi Modificare/Reimpostare/Copiare/Eseguire/Fermare il codice qui sotto. Prima di farlo, vai nella cartella del codice sorgente come davinci-kit-for-raspberry-pi/python. Dopo aver modificato il codice, puoi eseguirlo direttamente per vedere l’effetto.

#!/usr/bin/env python3

import RPi.GPIO as GPIO
import spidev
import time

# Pin GPIO per il pulsante del joystick (SW)
BTN_PIN = 22

# Configurazione GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # Pull-up interno

# Inizializzazione 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):
    """
    Legge il valore analogico dal canale MCP3008 specificato (0–7)
    :param channel: numero canale ADC (0–7)
    :return: valore intero a 10 bit (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:
    # Ciclo principale: legge e stampa i valori del joystick e lo stato del pulsante
    while True:
        x_val = read_adc(1)  # VRX collegato a CH1
        y_val = read_adc(2)  # VRY collegato a CH2

        Btn_val = GPIO.input(BTN_PIN)  # 0 = premuto, 1 = rilasciato

        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()

Spiegazione del codice

#!/usr/bin/env python3

import RPi.GPIO as GPIO
import spidev
import time

Questa sezione importa le librerie necessarie:

  • RPi.GPIO per gestire l’input GPIO (pulsante del joystick).

  • spidev per comunicare con il chip MCP3008 tramite SPI.

  • time per inserire ritardi tra le letture.

BTN_PIN = 22

GPIO.setmode(GPIO.BCM)
GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)

spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1000000

Questo blocco imposta la modalità GPIO su BCM, inizializza l’input del pulsante su GPIO22 con resistenza pull-up interna e configura l’interfaccia SPI con MCP3008 usando bus 0 e CE0 a 1 MHz.

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

Definisce la funzione read_adc() per leggere i dati analogici da un canale MCP3008 specifico, inviando tre byte via SPI e interpretando la risposta come valore a 10 bit.

try:
    while True:
        x_val = read_adc(0)
        y_val = read_adc(1)
        Btn_val = GPIO.input(BTN_PIN)
        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()

Il ciclo principale legge e stampa le posizioni X/Y e lo stato del pulsante ogni 200 ms. Se il programma viene interrotto (Ctrl+C), SPI e GPIO vengono chiusi correttamente.