Funzione di lettura analogica per microcontrollori ST (STM32xxxxxx)

Gran parte delle applicazioni delle schede di sviluppo a microcontrollore, come Arduino e la Nucleo ST, richiedono l'acquisizione di grandezze esterne tramite sensori analogici. Si pensi, ad esempio, alla temperatura o all'intensità luminosa. E' quindi necessario convertire la grandezza analogica ottenuta dai sensori in una grandezza digitale.


Se per Arduino questo procedimento è relativamente semplice, poiché esiste già una funzione atta alla lettura (analogRead(...) per intenderci), per i microcontrollori ST e per le relative schede Nucleo la lettura e conseguente conversione da analogica a digitale richiedono diversi passaggi.

Ho deciso quindi di creare una funzione analoga alla primitiva analogRead(...) di Arduino, che riesca a leggere e convertire una grandezza proveniente da un ingresso analogico.

    1. Si apre l'IDE di sviluppo STM32CubeIDE e si crea un nuovo progetto di firmware corrispondente alla scheda di sviluppo/microcontrollore in possesso (nel mio caso F401RE); IMPORTANTE: nella sezione Project Manager  entrare in Code Generator e attivare la spunta su "Generate Peripheral initializations as...
Figura 1: Generazione di file .c/.h per le periferiche

    2.si apre la schermata di configurazione Pinout & Configuration. Dopo aver configurato adeguatamente il clock nella sezione system core -> RCC -> HSE -> Crystal/Ceramic resonator (figura 2), si procede alla configurazione delle frequenze nella schermata Clock Configuration. Nel particolare, selezionare PLL Source Mux ->HSE e System Clock Mux -> PLLCLK. (figura 3)*
Figura 2: configurazione del clock (1)
Figura 3. configurazione del clock (2)
*Il punto numero 2 è fortemente consigliato per la configurazione del clock nelle schede di sviluppo Nucleo. In caso di progetti personali (es. PCB con microcontrollori) attenersi sempre alla frequenza dell'oscillatore al quarzo installato esternamente (se presente). In caso contrario, lasciare HSE e LSE (in System Core -> RCC) su "Disabled".

    3.nella schermata Pinout & Configuration, entrare nella sezione Analog -> ADC1. Attivare tutti i canali dell'ADC necessari (figura 4);
Figura 4: Inizializzazione dell'ADC.

    4. Nella stessa schermata, entrare nella sezione Parameter settings, settare Clock Prescaler -> PCLK2 divided by 4 e Resolution -> 10 bits. La risoluzione dell'ADC può essere anche lasciata a 12 bit (figura 5): su 10 bit, il valore ottenuto sarà compreso tra 0 e 1023, su 12 bit sarà ottenuto un valore tra 0 e 4095;
Figura 5: parametri dell'ADC

    5. Generare il programma tramite l'icona ingranaggio giallo sulla barra strumenti;
Figura 6: Generazione del programma
    6. nella sezione Project explorer, aprire la directory Core -> Inc e cliccare due volte sul file adc.h. Dichiarare all'interno del suddetto file, nella sezione /* USER CODE BEGIN Prototypes */, una funzione uint32_t ADC_Read(uint32_t channel).
Figura 7: dichiarazione della funzione nel file adc.h

    7. Recarsi sul file adc.c accessibile nella directory Core -> Src. Nella funzione MX_ADC_Init()eliminare le dichiarazioni mostrate in figura 8:
Figura 8: sezioni da eliminare nel file adc.c

Nella sezione /* USER CODE BEGIN 1 */ dichiarare la medesima funzione seguita dalla scrittura del seguente codice:
uint32_t ADC_Read(uint32_t channel){
    uint32_t val = 0;
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = channel;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
    if(HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){
        Error_Handler();
    }
    if(HAL_ADC_Start(&hadc1) != HAL_OK){
        Error_Handler();
    }
    HAL_ADC_PollForConversion(&hadc1, 100);

    val = HAL_ADC_GetValue(&hadc1);

    HAL_ADC_Stop(&hadc1);

    return val;

}

Figura 9: dichiarazione della funzione ADC_Read nel file adc.c


La funzione potrà ora essere impiegata nel programma principale per la lettura rapida del valore ottenuto dal convertitore AD, passando come argomento il canale (ingresso) da cui leggere.
Ad esempio, se si vuole leggere un valore dal canale 1 dell'ADC, sarà necessario scrivere nel while eterno:
while(1){
    int x = (int)(ADC_Read(ADC_CHANNEL_1));
    //proseguo del programma...
}
Alcuni canali fondamentali dell'ADC sono l'ADC_CHANNEL_VBAT (tensione sulla batteria collegata al pin VBAT) e ADC_CHANNEL_TEMPSENSOR (Temperatura ottenuta dal sensore interno al microcontrollore).

Commenti

Post popolari in questo blog

Conversione analogico - digitale (ADC) e digitale - analogico (DAC) con amplificatori operazionali

Tempo di propagazione nella logica pass-transistor - legge di Elmore (39)

Modello di Ebers & Moll delle correnti nel BJT - Guadagni di corrente (15)