Programmazione di MPLAB Xpress Board: quarto esempio: ADC e Potenziometro

Con questo quarto articolo vediamo ancora che si può imparare a programmare facilmente un microcontrollore Microchip, il PIC16F18855 contenuto all'interno della MPLAB Xpress Evaluation Board della Microchip (DM164140)

Leggere questo articolo dopo il primo.

Si deve far riferimento alla seconda pagina dello schema elettrico.

Lo scopo di questo quarto esempio è di testare il modulo ADCC integrato, ossia il modulo del convertitore analogico digitale e il potenziometro presente nello schema elettrico ed indicato come resistenza R15 e collegato al microcontrollore al PIN RA4/ANA4.

A seconda del valore della tensione letto dal potenziometro, essendo un ADC a 10 bit il valore convertito è compreso tra 0 e 1023.

Se il valore convertito è inferiore a 256 vogliamo far lampeggiare D2 collegato a RA0; se il valore è compreso tra 256 e 512 deve rimanere acceso D2 e deve lampeggiare D3 collegato a RA1; se il valore è compreso tra 512 e 768 devono rimanere accesi D2 e D3 e deve lampeggiare D4 collegato a RA2; infine se il valore convertito è maggiore di 768 deve lampreggiare D4 collegato a RA3 e rimanere accesi gli altri tre Led.

 

Non si vuole usare MCC Code Configurator. Non si ha nulla in contrario ad usarlo, anzi il codice che esso produce viene preso come "punto di partenza" per creare un codice più snello e semplificato.

 

Si usa MPLAB Xpress IDE in cloud, creando un nuovo progetto.

New Project --> Microchip Embedded ---> Standalone Project

Family: Mid Range 8-bit MCUs (PIC 10/12/16)

Device: PIC16F18855

eppoi si sceglie il nome significativo al progetto: PIC16F18855_Adc_Potentiometer

Si comincia inserendo il programma principale main.c:

Ecco il codice:

/*
 * File:   main.c
 * Author: mariani.fausto
 *
 * Created on 11/6/2017 1:26:08 PM UTC
 * "Created in MPLAB Xpress"
 */


#include "config.h"  // custom edited config file.
#include <xc.h>
#include "adcc.h"  //

#define _XTAL_FREQ 32000000

adcc_channel_t AN_Channel;
adc_result_t convertedValue;

void main(void) {
    SYSTEM_Initialize();
    TRISA = 0b00010000; // we set RA0, RA1, RA2, RA3 as Output, RA4 as Input
    ADCC_Initialize();
    ANSELAbits.ANSA4 = 1; // ANA4 as analog Input
    
//    ADCON0bits.CHS = 0b00100; // we select channel ANA4

    while(1) {
        AN_Channel = 0b00100; // we select channel ANA4
        ADCC_StartConversion(AN_Channel);
    
        while(!ADCC_IsConversionDone());
        convertedValue = ADCC_GetConversionResult();
        if (convertedValue < 256) 
        {   LATAbits.LATA3 = 0;
            LATAbits.LATA1 = 0;
            LATAbits.LATA2 = 0;
            LATAbits.LATA0 = 1;
            __delay_ms(500);
            LATAbits.LATA0 = 0;
            __delay_ms(500);            
        } 
        else if (convertedValue < 512) 
        {
            LATAbits.LATA0 = 1;
            LATAbits.LATA1 = 1;
            __delay_ms(500);
            LATAbits.LATA1 = 0;
            __delay_ms(500);            
        }  
        else if (convertedValue < 768) 
        {
            LATAbits.LATA0 = 1;
            LATAbits.LATA1 = 1;
            LATAbits.LATA2 = 1;
            __delay_ms(500);
            LATAbits.LATA2 = 0;
            __delay_ms(500);            
        } 
        else
        {
            LATAbits.LATA0 = 1;
            LATAbits.LATA1 = 1;
            LATAbits.LATA2 = 1;
            LATAbits.LATA3 = 1;
            __delay_ms(500);
            LATAbits.LATA3 = 0;
            __delay_ms(500); 
            
        }
    }
    return;
}

Non si riporta anche il codice di configurazione config.h che conviene prendere da uno dei tanti esempi preesistenti, oppure si può prendere quello del primo articolo.

Inoltre nel progetto è conveniente che ci siano altri due file adcc.h e adcc.c, il primo nella parte Header files e il secondo nella parte Sources files.

Ecco adcc.h

/* 
 * File:   adcc.h
 * Author: mariani.fausto
 *
 * Created on 11/6/2017 1:40:31 PM UTC
 * "Created in MPLAB Xpress"
 */

#ifndef ADCC_H
#define	ADCC_H
#include <stdint.h>
#include <stdbool.h>

typedef uint16_t adc_result_t;
typedef enum
{
    channel_ANA4 =  0x4,
    channel_VSS =  0x3C,
    channel_Temp =  0x3D,
    channel_DAC1 =  0x3E,
    channel_FVR =  0x3F
} adcc_channel_t;

/**
  @Summary
    Initializes the ADCC
  @Description
    This routine initializes the Initializes the ADCC.
    This routine must be called before any other ADCC routine is called.
    This routine should only be called once during system initialization.
 */
void ADCC_Initialize(void);

void ADCC_StartConversion(adcc_channel_t channel);
/**
  @Summary
    Returns true when the conversion is completed otherwise false.

  @Description
    This routine is used to determine if conversion is completed.
    When conversion is complete routine returns true. It returns false otherwise.

  @Preconditions
    ADCC_Initialize() and ADCC_StartConversion(adcc_channel_t channel)
    function should have been called before calling this function.

  @Returns
    true  - If conversion is complete
    false - If conversion is not completed

  @Param
    None

  @Example
    <code>
    uint16_t convertedValue;

    ADCC_Initialize();
    ADCC_StartConversion(AN1_Channel);

    while(!ADCC_IsConversionDone());
    convertedValue = ADCC_GetConversionResult();

 */
bool ADCC_IsConversionDone();

adc_result_t ADCC_GetConversionResult(void);


#endif	/* ADCC_H */

Ecco adcc.c

/*
 * File:   adcc.c
 * Author: mariani.fausto
 *
 * Created on 11/6/2017 1:41:15 PM UTC
 * "Created in MPLAB Xpress"
 */

#include <xc.h>
#include "adcc.h"

void ADCC_Initialize(void)
{
    // set the ADCC to the options selected in the User Interface
    // ADDSEN disabled; ADGPOL digital_low; ADIPEN disabled; ADPPOL VSS; 
    ADCON1 = 0x00;
    // ADCRS 0; ADMD Basic_mode; ADACLR disabled; ADPSIS ADFLTR; 
    ADCON2 = 0x00;
    // ADCALC First derivative of Single measurement; ADTMD disabled; ADSOI ADGO not cleared; 
    ADCON3 = 0x00;
    // ADACT disabled; 
    ADACT = 0x00;
    // ADAOV ACC or ADERR not Overflowed; 
    ADSTAT = 0x00;
    // ADCCS FOSC/94; 
    ADCLK = 0x2E;
    // ADNREF VSS; ADPREF VDD; 
    ADREF = 0x00;
    // ADCAP 0; 
    ADCAP = 0x00;
    // ADPRE 0; 
    ADPRE = 0x00;
    // ADACQ 32; 
    ADACQ = 0x20;
    // ADPCH ANA0; 
    ADPCH = 0x00;
    // ADRPT 0; 
    ADRPT = 0x00;
    // ADLTHL 0; 
    ADLTHL = 0x00;
    // ADLTHH 0; 
    ADLTHH = 0x00;
    // ADUTHL 0; 
    ADUTHL = 0x00;
    // ADUTHH 0; 
    ADUTHH = 0x00;
    // ADSTPTL 0; 
    ADSTPTL = 0x00;
    // ADSTPTH 0; 
    ADSTPTH = 0x00;
    
    // ADGO stop; ADFM right; ADON enabled; ADCONT disabled; ADCS FOSC/ADCLK; 
    ADCON0 = 0x84;
    

}
void ADCC_StartConversion(adcc_channel_t channel)
{
    // select the A/D channel
    ADPCH = channel;  
  
    // Turn on the ADC module
    ADCON0bits.ADON = 1;      

    // Start the conversion
    ADCON0bits.ADGO = 1;
}

adc_result_t ADCC_GetConversionResult(void)
{
    // Return the result
    return ((adc_result_t)((ADRESH << 8) + ADRESL));
}

bool ADCC_IsConversionDone()
{
    // Start the conversion
    return (!ADCON0bits.ADGO);
}

 

Chiaramente per comprendere nei dettagli il funzionamento è conveniente consultare il datasheet.

 

La struttura del progetto è

Progetto MPLAB Xpress

 

Ecco alcune foto del funzionamento:

Potenziometro in "prima posizione"
Potenziometro in "prima posizione"

 

Potenziometro in "seconda posizione"
Potenziometro in "seconda posizione"

 

Potenziometro in "terza posizione"
Potenziometro in "terza posizione"

 

Potenziometro in "quarta posizione"
Potenziometro in "quarta posizione"