.. nota::

    Ciao, benvenuto nella community di SunFounder Raspberry Pi & Arduino & ESP32 su Facebook! Approfondisci le tue conoscenze su Raspberry Pi, Arduino ed ESP32 insieme ad altri appassionati.

    **Perché unirti a noi?**

    - **Supporto Esperto**: Risolvi i problemi post-vendita e le sfide tecniche con l'aiuto della nostra comunità e del nostro team.
    - **Impara e Condividi**: Scambia suggerimenti e tutorial per migliorare le tue competenze.
    - **Anteprime Esclusive**: Ottieni accesso anticipato ai nuovi annunci di prodotti e alle anteprime.
    - **Sconti Speciali**: Approfitta di sconti esclusivi sui nostri prodotti più recenti.
    - **Promozioni Festive e Giveaway**: Partecipa a concorsi e promozioni festive.

    👉 Pronto a esplorare e creare con noi? Clicca su [|link_sf_facebook|] e unisciti subito!

.. _2.1.7_c:

2.1.7 Potenziometro
===========================

Introduzione
---------------

La funzione ADC può essere utilizzata per convertire segnali analogici in segnali 
digitali, e in questo esperimento viene utilizzato ADC0834 per ottenere tale funzione. 
Qui, implementiamo questo processo utilizzando un potenziometro. Il potenziometro 
cambia la quantità fisica, cioè la tensione, che viene convertita dalla funzione ADC.

Componenti Necessari
------------------------------

In questo progetto, abbiamo bisogno dei seguenti componenti.

.. image:: ../img/list_2.1.4_potentiometer.png

È sicuramente conveniente acquistare un kit completo, ecco il link:

.. list-table::
    :widths: 20 20 20
    :header-rows: 1

    *   - Nome	
        - COMPONENTI IN QUESTO KIT
        - LINK
    *   - Raphael Kit
        - 337
        - |link_Raphael_kit|

Puoi anche acquistarli separatamente dai link seguenti.

.. list-table::
    :widths: 30 20
    :header-rows: 1

    *   - INTRODUZIONE AI COMPONENTI
        - LINK PER L'ACQUISTO

    *   - :ref:`cpn_gpio_extension_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_led`
        - |link_led_buy|
    *   - :ref:`cpn_potentiometer`
        - |link_potentiometer_buy|
    *   - :ref:`cpn_adc0834`
        - \-

Schema Elettrico
--------------------

.. image:: ../img/image311.png


.. image:: ../img/image312.png


Procedure Sperimentali
--------------------------

**Passo 1:** Costruisci il circuito.

.. image:: ../img/image180.png


.. note::
    Posiziona il chip facendo riferimento alla posizione corrispondente
    raffigurata nell'immagine. Nota che le scanalature sul chip dovrebbero
    essere a sinistra quando viene posizionato.

**Passo 2:** Apri il file del codice.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/c/2.1.7/

**Passo 3:** Compila il codice.

.. raw:: html

   <run></run>

.. code-block::

    gcc 2.1.7_Potentiometer.c -lwiringPi

**Passo 4:** Esegui.

.. raw:: html

   <run></run>

.. code-block::

    sudo ./a.out

Dopo l'esecuzione del codice, ruota la manopola del potenziometro e l'intensità
dell'LED cambierà di conseguenza.

.. note::

    Se non funziona dopo l'esecuzione o appare un errore come: \"wiringPi.h: No such file or directory\", fai riferimento a :ref:`install_wiringpi`.

**Codice**

.. code-block:: c

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

    typedef unsigned char uchar;
    typedef unsigned int uint;

    #define     ADC_CS    0
    #define     ADC_CLK   1
    #define     ADC_DIO   2
    #define     LedPin    3

    uchar get_ADC_Result(uint channel)
    {
        uchar i;
        uchar dat1=0, dat2=0;
        int sel = channel > 1 & 1;
        int odd = channel & 1;

        digitalWrite(ADC_CLK, 1);
        delayMicroseconds(2);
        digitalWrite(ADC_CLK, 0);
        delayMicroseconds(2);

        pinMode(ADC_DIO, OUTPUT);
        digitalWrite(ADC_CS, 0);
        // Start bit
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
        digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
        // Single End mode
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
        digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
        // ODD
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,odd);  delayMicroseconds(2);
        digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
        // Select
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,sel);    delayMicroseconds(2);
        digitalWrite(ADC_CLK,1);

        digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,1);    delayMicroseconds(2);

        for(i=0;i<8;i++)
        {
            digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
            digitalWrite(ADC_CLK,0);    delayMicroseconds(2);

            pinMode(ADC_DIO, INPUT);
            dat1=dat1<<1 | digitalRead(ADC_DIO);
        }

        for(i=0;i<8;i++)
        {
            dat2 = dat2 | ((uchar)(digitalRead(ADC_DIO))<<i);
            digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
            digitalWrite(ADC_CLK,0);    delayMicroseconds(2);
        }

        digitalWrite(ADC_CS,1);
        pinMode(ADC_DIO, OUTPUT);
        return(dat1==dat2) ? dat1 : 0;
    }

    int main(void)
    {
        uchar analogVal;
        if(wiringPiSetup() == -1){ //quando l'inizializzazione wiring fallisce, stampa messaggio a schermo
            printf("setup wiringPi failed !");
            return 1;
        }
        softPwmCreate(LedPin,  0, 100);
        pinMode(ADC_CS,  OUTPUT);
        pinMode(ADC_CLK, OUTPUT);

        while(1){
            analogVal = get_ADC_Result(0);
            printf("Current analogVal : %d\n", analogVal);
            softPwmWrite(LedPin, analogVal);
            delay(100);
        }
        return 0;
    }

**Spiegazione del Codice**

.. code-block:: c

    #define     ADC_CS    0
    #define     ADC_CLK   1
    #define     ADC_DIO   2
    #define     LedPin    3

Definisci CS, CLK, DIO di ADC0834 e collegali rispettivamente a GPIO0, GPIO1 e
GPIO2. Quindi collega il LED a GPIO3.

.. code-block:: c

    uchar get_ADC_Result(uint channel)
    {
        uchar i;
        uchar dat1=0, dat2=0;
        int sel = channel > 1 & 1;
        int odd = channel & 1;

        pinMode(ADC_DIO, OUTPUT);
        digitalWrite(ADC_CS, 0);
        // Start bit
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
        digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
        // Single End mode
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
        digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
        // ODD
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,odd);  delayMicroseconds(2);
        digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
        // Select
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,sel);    delayMicroseconds(2);
        digitalWrite(ADC_CLK,1);

        digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
        digitalWrite(ADC_CLK,0);
        digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
        for(i=0;i<8;i++)
        {
            digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
            digitalWrite(ADC_CLK,0);    delayMicroseconds(2);

            pinMode(ADC_DIO, INPUT);
            dat1=dat1<<1 | digitalRead(ADC_DIO);
        }

        for(i=0;i<8;i++)
        {
            dat2 = dat2 | ((uchar)(digitalRead(ADC_DIO))<<i);
            digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
            digitalWrite(ADC_CLK,0);    delayMicroseconds(2);
        }

        digitalWrite(ADC_CS,1);
        pinMode(ADC_DIO, OUTPUT);
        return(dat1==dat2) ? dat1 : 0;
    }

Esiste una funzione di ADC0834 per ottenere la conversione da analogico a digitale. Il flusso di lavoro specifico è il seguente:

.. code-block:: c

    digitalWrite(ADC_CS, 0);

Imposta CS a livello basso e inizia ad abilitare la conversione AD.

.. code-block:: c

    // Start bit
    digitalWrite(ADC_CLK,0);
    digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
    digitalWrite(ADC_CLK,1);    delayMicroseconds(2);

Quando si verifica la transizione da basso ad alto dell'input del clock 
per la prima volta, imposta DIO a 1 come bit di avvio. Nei tre passaggi 
successivi, ci sono 3 parole di assegnazione.

.. code-block:: c

    // Single End mode
    digitalWrite(ADC_CLK,0);
    digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
    digitalWrite(ADC_CLK,1);    delayMicroseconds(2);

Non appena si verifica la transizione da basso ad alto dell'input del clock per la seconda volta, imposta DIO a 1 e scegli la modalità SGL.

.. code-block:: c

    // ODD
    digitalWrite(ADC_CLK,0);
    digitalWrite(ADC_DIO,odd);  delayMicroseconds(2);
    digitalWrite(ADC_CLK,1);    delayMicroseconds(2);

Una volta che si verifica per la terza volta, il valore di DIO è controllato dalla variabile **odd**.

.. code-block:: c

    // Select
    digitalWrite(ADC_CLK,0);
    digitalWrite(ADC_DIO,sel);    delayMicroseconds(2);
    digitalWrite(ADC_CLK,1);

Il quarto impulso di CLK convertito da livello basso a livello alto, il valore di 
DIO è controllato dalla variabile **sel**.

Nella condizione in cui channel=0, sel=0, odd=0, le formule operative riguardanti
 **sel** e **odd** sono le seguenti:

.. code-block:: c

    int sel = channel > 1 & 1;
    int odd = channel & 1;

Quando la condizione channel=1, sel=0, odd=1 è soddisfatta, fai riferimento alla 
seguente tabella di logica del controllo degli indirizzi. Qui viene scelto CH1, 
e il bit di avvio viene spostato nella posizione iniziale del registro multiplexer 
e la conversione inizia.

.. image:: ../img/image313.png


.. code-block:: c

    digitalWrite(ADC_DIO,1);    delayMicroseconds(2);
    digitalWrite(ADC_CLK,0);
    digitalWrite(ADC_DIO,1);    delayMicroseconds(2);

Qui, imposta due volte DIO a 1, ignoralo.

.. code-block:: c

    for(i=0;i<8;i++)
        {
            digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
            digitalWrite(ADC_CLK,0);    delayMicroseconds(2);

            pinMode(ADC_DIO, INPUT);
            dat1=dat1<<1 | digitalRead(ADC_DIO);
        }

Nel primo ciclo for(), non appena il quinto impulso di CLK viene convertito 
da alto a basso livello, imposta DIO in modalità di input. Quindi la conversione 
inizia e il valore convertito viene memorizzato nella variabile dat1. Dopo otto 
periodi di clock, la conversione è completata.

.. code-block:: c

    for(i=0;i<8;i++)
        {
            dat2 = dat2 | ((uchar)(digitalRead(ADC_DIO))<<i);
            digitalWrite(ADC_CLK,1);    delayMicroseconds(2);
            digitalWrite(ADC_CLK,0);    delayMicroseconds(2);
        }

Nel secondo ciclo for(), i valori convertiti vengono emessi tramite DO dopo altri 
otto periodi di clock e memorizzati nella variabile dat2.

.. code-block:: c

    digitalWrite(ADC_CS,1);
    pinMode(ADC_DIO, OUTPUT);
    return(dat1==dat2) ? dat1 : 0;

return(dat1==dat2) ? dat1 : 0 viene utilizzato per confrontare il valore ottenuto 
durante la conversione e il valore in uscita. Se sono uguali tra loro, emette il 
valore convertito dat1; altrimenti emette 0. Qui, il flusso di lavoro di ADC0834 
è completato.

.. code-block:: c

    softPwmCreate(LedPin,  0, 100);

La funzione è quella di utilizzare il software per creare un pin PWM, LedPin, quindi 
la larghezza dell'impulso iniziale è impostata a 0, e il periodo del PWM è 100 x 100us.

.. code-block:: c

    while(1){
            analogVal = get_ADC_Result(0);
            printf("Current analogVal : %d\n", analogVal);
            softPwmWrite(LedPin, analogVal);
            delay(100);
        }

Nel programma principale, leggi il valore del channel 0 che è stato collegato a 
un potenziometro. Memorizza il valore nella variabile analogVal e quindi scrivilo 
in LedPin. Ora puoi vedere la luminosità dell'LED cambiare con il valore del 
potenziometro.

Immagine del Fenomeno
------------------------------

.. image:: ../img/image181.jpeg


