Corso programmazione microcontrollori PIC® in C (aggiornamento MPLAB X) – Generiamo il nostro primo progetto con MPLAB X IDE – Led Lampeggiante con Delay

Eccoci qui alla seconda puntata relativa agli aggiornamenti del mio storico corso di programmazione microcontrollori PIC® in C. Dato che si tratta di aggiornamenti non mi soffermerò a spiegare tutto daccapo ma mi limiterò ad illustrare le differenze tra la programmazione con il nuovo MPLAB X IDE e il vecchio MPLAB IDE 8, anche se, in realtà, gli aggiornamenti sono perfettamente fruibili anche dai newbies dato che comunque fornirò istruzioni passo passo.

Solo per i nuovi utenti: vi invito a leggere le prime lezioni escludendo la parte descrittiva IDE/compilatore:

e per gli utenti vecchi che vogliono passare al nuovo (ma anche per i nuovi dato che alcune cose le ho scritte qui e non voglio ripeterle):

In questo nuovo articolo illustreremo il classico programma per far lampeggiare un led con un PIC® utilizzando i delays.

Circuito

Per questi nuovi esempi, dato che il vecchio PIC16F877A è uscito fuori produzione, utilizzerò il primo sostituto: PIC16F887 che è molto simile. In realtà anche il PIC16F887 andrà fuori produzione perchè c’è già un nuovo modello: PIC16F18877 che è un vero mostro (ha addirittura ingressi analogici/resistenze di pullup/ingressi open drain su tutti i pin nonchè numerose nuove periferiche). Il problema è che non ho ancora disponibile questo nuovo modello (dovrebbe arrivarmi prossimamente), per cui per ora procedo con l’887.

Se abbiamo la scheda Freedom II (per la Freedom III non posso esprimermi perchè non ce l’ho) possiamo tranquillamente sostituire il 16F887 al 16F877A, in realtà per questo primo tutorial il circuito è molto semplice e potremmo anche realizzarlo su una millefori (sconsiglio la breadboard perchè potreste avere problemi con il clock).

Metto qui lo schema originale del circuito: tanto è lo stesso, cambia soltanto la sigla del PICmicro:

Elenco componenti:

  • R1: 10KΩ
  • R2: 330Ω
  • D1: 1N4148 o 1N4007
  • Q1: Quarzo 20MHz
  • C1: 100nF poliestere
  • C2: 18 ÷ 22pF ceramico
  • C3: 18 ÷ 22pF ceramico 
  • IC1: PIC16F887-I/P (40pin formato PDIP, usabile su millefori)
  • ICSP: strip maschio 6 pin, passo 2,54mm

 

Creazione dei files nel progetto

Nell’articolo precedente abbiamo visto come creare un progetto in MPLAB X IDE (File->New Project … leggete l’articolo precedente se non lo ricordate).

Nell’immagine sottostante ci troviamo all’ultimo passaggio della creazione del progetto: la scelta del nome e della cartella. Chiamiamo il progetto semplicemente “Led_lampeggiante”:

Sulla cartella “Source Files” premere il tasto destro del mouse e selezionare New -> main.c

In realtà per creare un file con estensione C (che dicevamo nell’articolo principale: contiene le funzioni principali e verrà compilato), nel menù New sono presenti 3 scelte:

  • C Source File
  • C Main File
  • main.c

La differenza sta unicamente in quello che MPLAB X IDE scrive di default nel nuovo file creato. Se scegliamo C Source File, il file creato sarà completamente vuoto. Se scegliamo C Main File, il file creato conterrà l’inclusione di <stdio.h> e <stdlib.h> che sono due librerie standard utilizzate generalmente in C ma a noi non sempre servono. Se scegliamo main.c il file conterrà l’inclusione di <xc.h>, per questo motivo scegliamo main.c dal menù, giusto per risparmiarci la digitazione di #include <xc.h>.

Si presenta quindi la finestra in cui dobbiamo specificare il nome del file. Di default esce scritto “newmain”:

Cambiamo il nome e scriviamo semplicemente main -senza estensione- perchè ci piace di più (in realtà il nome non è importante, il modulo main è sempre quello che contiene la funzione main, indipendentemente da come si chiama il file):

Premiamo quindi il pulsante Finish. Ci ritroviamo il nostro nuovo main che contiene già qualcosa come detto prima:

Come detto nell’articolo precedente, l’inclusione di <xc.h> è necessaria perchè carica tutti i nomi mnemonici dei registri e pin del PICmicro selezionato più qualche altra utile funzione, tra cui i delays e svolge le funzioni del vecchio htc.h.

Adesso aggiungiamo anche un file header nel quale andremo a scrivere la configurazione (sia chiaro: la possiamo scrivere anche nel main.c, poi voi farete come volete, questo è solo un esercizio). Clicchiamo sulla cartella Header files con il tasto destro e selezioniamo New -> C Header file:

Si presenta la finestra in cui ci viene chiesto quale nome dare al file, scriviamo semplicemente config -senza estensione- e premiamo finish. Viene creato un file H generico:

Tutto quello che c’è dentro lo possiamo anche cancellare. Adesso generiamo la Config Word. Come vi dicevo, il nuovo MPLAB X IDE ha una funzione apposta per generare la Config Word del PICmicro che abbiamo scelto per il progetto. Dal menù Window selezioniamo PIC Memory Views -> Configuration Bits

Compare una finestra in basso con l’elenco dei registri di configurazione e tutti i fuses. Nel caso del PICmicro che ho scelto ci sono soltanto due config word e le impostazioni sono poche. Impostiamo i fuses come da immagine:

La cosa buona è che, a parte la descrizione dei bit, cambiando le impostazioni compare una descrizione nell’ultima colonna che ci aiuta a capire cosa stiamo facendo (ma ad ogni modo non può mai sostituire il datasheet). Abbiamo già imparato dalle vecchie lezioni a cosa servono molti di questi parametri ma il datasheet vi è sempre amico dato che molti PICmicro hanno altre impostazioni sebbene quelle illustrate su questo PICmicro e abbiano un po’ tutti. In particolare ho selezionato:

  • FOSC: HS – questo mi permette di utilizzare un quarzo esterno ad alta velocità. In realtà per la maggior parte delle applicazioni (a meno che non abbiamo bisogno di clock stabili e molto precisi) può andare bene il clock interno che ormai tutti i nuovi PICmicro offrono. Ho fatto questa scelta per ragioni storiche e per utilizzare schede che già ho in cui è già montato il quarzo con i due condensatori. Ma sappiate che l’utilizzo dell’oscillatore interno ci fa risparmiare, oltre ai componenti esterni, anche altri due pin che possiamo utilizzare come normali IO (RA6 e RA7). Se scegliamo l’oscillatore interno, poi dovremo settare anche il registro OSCCON.
  • WDTE: OFF – ho disabilitato il Watchdog Timer. Ricordo che questo è un timer indipendente che, se attivo, ogni tanto deve essere resettato nel nostro programma altrimenti se termina il suo conteggio esegue il reset del programma. E’ una funzione di sicurezza nel caso in cui i programmi si blocchino.
  • PWRTE: ON – Il programma non entra in funzione fino a che la tensione di alimentazione non è stabile.
  • MCLRE: ON – Il pin di Master Clear (MCLR) verrà utilizzato come reset ovvero deve essere tenuto a livello alto con una resistenza di pull-up ed è possibile portarlo a livello basso (GND) mediante un pulsante per eseguire il reset. Sappiate che su molti PICmicro vecchi questo fuse non c’è. Qui c’è perchè il pin di MCLR volendo si può utilizzare come normale Input (ma NON output) impostando questo fuse a OFF (liberiamo RE3).
  • CP: OFF – Protezione area codice disattivata
  • CPD: OFF – Protezione area dati disattivata
  • BOREN: OFF – Brown Out disabilitato. Il Brown Out è una funzione che resetta il microcontrollore nel caso in cui ci siano abbassamenti di tensione, è utile in alcune applicazioni per evitare corruzione dei dati o altri problemi.
  • IESO: OFF – IESO sta per Internal/External SwitchOver. Serve per abilitare la funzionalità “Two Speed Start-up”: in pratica il PICmicro parte con il clock interno a bassa frequenza per permettere al clock esterno di stabilizzarsi, dopodichè passa al clock esterno. E’ una funzione utile per risparmiare energia durante le modalità sleep.
  • FCMEN: OFF – Funzione di monitoraggio malfunzionamento Clock esterno disabilitata. Questa funzione permette di controllare costantemente il clock esterno: se ci sono problemi (il clock viene interrotto), il PICmicro continua a funzionare utilizzando il clock interno. Al verificarsi di questa condizione è anche possibile catturare un interrupt.
  • LVP: OFF – Programmazione a bassa tensione disattivata. Ricorderete che questo serve per programmare il PICmicro senza fornire l’alta tensione sul pin MCLR (basta la 5V), ma in compenso bisogna utilizzare un altro pin (RB3/PGM).
  • BOR4V: BOR21V – è il livello di tensione di riferimento per la funzione di Brown Out: il reset avviene quando si scende sotto al livello selezionato, ammesso che BOREN sia impostato su ON.
  • WRT: OFF – Protezione da auto-scrittura memoria flash disattivata

In realtà da datasheet i PICmicro hanno un altro bit di configurazione che viene nascosto da questo tool: DEBUG che messo a zero consente di utilizzare RB6/RB7 per funzioni di debug. Anche se lo resettiamo manualmente scrivendo #pragma config DEBUG=ON il debug verrà comunque sempre disattivato in fase di compilazione e MPLAB X ci avviserà di questa situazione con un Warning in rosso (Warning: The hex file has the debug bit set. The debug bit has been cleared during load to memory. The original hex file has not been modified.). Questo accade perchè molti utenti lasciavano spesso il debug attivo anche nel programma finale, il che causava malfunzionamenti dato che RB6/RB7 venivano usati per altri scopi. Se serve il debug, difatti, è il programmatore che lo imposta indipendentemente da quello che scriviamo noi nella config word.

Ulteriori dettagli sulla word di configurazione e sulle opzioni di Clock sui nuovi PICmicro sono disponibili in questo articolo.

Bene, ora che abbiamo capito (più o meno) cosa fanno questi fuse di configurazione, siamo pronti a premere il pulsante Generate Source Code to Output: vengono generate tutte le direttive #pragma per la configurazione in una finestra che si apre sempre in questa zona:

Con MPLAB IDE 8 utilizzavamo la macro __CONFIG che a me non è mai piaciuta: questo sistema è più comodo ed è lo stesso che si utilizzava con i compilatori non Hi-Tech (come il vecchio MPLAB C18).

Leggiamo un po’ il codice generato: vediamo che in fondo c’è scritto:

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>

Dice che le direttive #pragma devono precedere le direttive #include (e difatti mette #include <xc.h> dopo). Copiamo tutto saltando queste ultime 3 righe (saltiamo l’include di xc.h) e incolliamo nel nostro file config.h dal quale avevamo cancellato tutto il contenuto:

Altra soluzione molto comoda offerta da MPLAB X IDE è quella di posizionare il cursore nel file in cui vogliamo copiare la configurazione, quindi premere col tasto destro in un punto qualsiasi della finestra di configurazione e selezionare Insert Source Code in Editor:

Come vedete nel config.h ho messo esclusivamente le direttive #pragma. Adesso nel main.c dobbiamo includere la configurazione, prima di #include <xc.h>:

Da notare che config.h l’ho messo tra virgolette per dire al compilatore di cercarlo nello stesso percorso del main. Le librerie di sistema invece vogliono i segni di minore e maggiore.

Dobbiamo far lampeggiare un led utilizzando le routine di ritardo. Come dicevo nell’articolo precedente, ci sono delle routine di Delay integrate e per utilizzarle dobbiamo definire _XTAL_FREQ con la frequenza, in Hertz, dell’oscillatore utilizzato (qualunque esso sia: interno o esterno). Dato che sto usando un quarzo da 20MHz, scriverò:

#define _XTAL_FREQ 20000000

Questo define va messo prima dell’include di xc.h dato che serve alle routine di delay incluse in quel modulo e quindi va dichiarato prima che le routine vengano caricate.

Le vecchie routine di ritardo risiedevano in un modulo a parte (delay C) e richiedevano anch’esse un define, scritto senza l’underscore che precede.

Definiamo quindi un nome mnemonico per il led associandolo alla porta su cui è collegato:

#define LED PORTDbits.RD0

Facciamo questo perchè è più facile ricordarsi di “LED” piuttosto che di PORTDbits.RD0. Ricordo che i #define vanno fuori dalle funzioni, in cima al sorgente.

Come detto nell’articolo precedente: prima scrivevamo soltanto RD0, adesso dobbiamo specificare tutto il banco di porte puntando al singolo bit

Un errore molto comune è quello di utilizzare, per funzioni di IO digitale, pin multiplexati con il convertitore Analogico/Digitale dimenticandosi di disattivare la funzionalità analogica, che di default prevale su quella digitale. Questo PICmicro in particolare ha due registri ANSEL e ANSELH nei quali si imposta quali porte devono essere usate come analogiche o digitali. Dopo aver impostato le porte come digitali, spegniamo anche il modulo A/D. Questo lo possiamo fare nel main prima del ciclo infinito oppure in una funzione di configurazione a parte (una funzione di setup):

ANSEL=0; // pins A/D (0-7) con funzioni di I/O digitale
ANSELH=0; // pins A/D (8-13) con funzioni di I/O digitale
ADCON0bits.ADON=0; // modulo A/D spento

Nel caso di PICmicro più evoluti, come il PIC16F18877 che dicevo prima, che hanno gli ingressi analogici su tutti i pin, ci sono registri analogici separati per ogni banco di porte, quindi avremo ANSELA (per il banco A), ANSELB ecc. Sempre il 18877 ha anche la possibilità di specificare ogni pin come a collettore aperto il che vuol dire che un pin, utilizzato come uscita digitale, è in grado soltanto di tirare corrente (fornire il GND) ma non di fornirla, per cui è necessaria una resistenza di pull-up. In questo caso ci sono anche i registri Open Drain Control che vanno posti a zero se non si desidera questa funzione ODCONA, ODCONB ecc. Altri PICmicro vecchi potrebbero avere RA4 a collettore aperto (non settabile), altri ancora (sempre vecchi) potrebbero avere il solo comparatore che anche va disabilitato. Ulteriori informazioni in questo vecchio articolo e commenti.

Adesso impostiamo RD0 come uscita, tutti i pin non utilizzati li impostiamo come ingressi per evitare corto-circuiti accidentali:

TRISA=0xFF;
TRISB=0xFF;
TRISC=0xFF;
TRISD=0b11111110; // solo RD0 come uscita: qui è collegato il led
// potevo anche scrivere: TRISDbits.TRISD0=0;
TRISE=0xFF;

Possiamo quindi inserire il ciclo infinito nel quale facciamo lampeggiare il led sfruttando un or esclusivo come già detto nelle vecchie lezioni:

while(1)
{
// inverto lo stato della porta a cui è collegato il LED
LED^=1; // LED = LED XOR 1
 
// la seguente funzione di ritardo è inclusa nel compilatore XC
// e accetta unicamente costanti, non utilizzarla con variabili!
__delay_ms(500); //500mS di attesa
}

Importare un progetto

Dato che il progetto di esempio che ho illustrato qui potete scaricarlo più in basso, sappiate che lo potete anche importare direttamente in MPLAB X IDE. Basta cliccare con il tasto destro in una zona vuota del riquadro Projects e selezionare “Open Project”:

Selezionate quindi la cartella con estensione X che avete scaricato. E’ possibile che dobbiate fare degli aggiustamenti al progetto per poterlo adattare ai vostri strumenti. In particolare potrebbe essere necessario cambiare il programmatore o la versione del compilatore: questo potete farlo dalle proprietà del progetto.

Compilare il progetto

Per compilare soltanto il progetto (senza caricarlo sulla scheda tramite il programmatore) si preme il pulsante con il martello o quello con martello+scopa (io premo sempre quest’ultimo, che cancella ogni volta anche i file intermedi).

In questo caso l’HEX lo potete trovare in:

[percorso alla cartella dove avete il progetto]\[nome del progetto].X\dist\default\production

Se avete connesso il programmatore e la scheda, potete anche compilare il progetto e caricare l’HEX in un solo colpo premendo il tasto con la freccia verde verso il basso con il circuito integrato:

Se avete problemi durante la programmazione, vi rimando al precedente articolo.

Downloads

Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)