Corso programmazione PICMicro in C – Lezione 3 – Il primo programma in C: scrivere un semplice programma in C per PICMicro, impostare MPLAB e flashare il PICMicro con il PICKit2. Facciamo lampeggiare un LED!

Aggiornamento Ottobre 2017
La Microchip ha rilasciato nuovi tool per lo sviluppo: MPLAB X IDE e i compilatori XC. Per far fronte alle novità e per non riscrivere tutti gli articoli daccapo, ho scritto delle lezioni integrative per consentire il passaggio dai vecchi strumenti a quelli nuovi. Le nozioni teoriche riportate negli articoli “vecchi” sono ancora valide. Per quanto concerne la scrittura del codice, l’utilizzo dell’IDE, i codici di esempio ecc, fate riferimento alle nuove lezioni che si trovano nella categoria PICmicro nuovo corso.

Finalmente dopo le precedenti due lezioni, per lo più introduttive, eccoci alla parte pratica! In questa lezione scriveremo il nostro primo programma in C, lo compileremo e lo caricheremo sul PICMicro per vederlo in azione.

Ovviamente il primo programma è sempre qualcosa di molto molto semplice: faremo lampeggiare un diodo led. Certo non è un qualcosa di molto entusiasmante, ma bisogna partire a piccoli passi per comprendere a fondo tutto quello che c’è dietro ai programmi più complessi.

Ricordate lo schema elettrico del circuito di base presentato nella seconda lezione? Bene, andremo a collegare sul pin n° 19 (che rappresenta la porta RD0, ovvero la prima delle porte D) un diodo led, con in serie una resistenza da 330Ω (che ha la funzione di limitare la corrente che circola nel LED, in maniera tale da non farlo bruciare). Realizzeremo  quindi il seguente schema:

primo_programma_picmicro_in_c_mplab_schema_thumb

Quando andrete a montare il LED, tenete conto che il terminale più corto dei due è quello che va verso massa. Se lo montate al contrario non si accenderà. Fate una prova alimentandolo con 5 volt e con la resistenza da 330Ω: vedrete che in un senso si accenderà e dall’altro no. Anche se emette luce, si tratta pur sempre di un diodo ed è quindi capace di far circolare la corrente in un verso soltanto.

La porta RD0 è stata scelta a caso, avremmo potuto collegare il LED su qualsiasi altra porta indifferentemente: ci serve difatti unicamente la funzione di I/O digitale, che come abbiamo visto nelle lezioni precedenti, è a disposizione di qualsiasi porta.

Se state utilizzando per questi esperimenti la scheda Freedom di Mauro Laurenti, per poter utilizzare le varie porte per gli esperimenti, potete crearvi una piattina che da un lato si innesta nella scheda di sviluppo e dall’altro invece presenta uno strip da 10 contatti in linea che possiamo utilizzare facilmente per la connessione con una breadboard:

primo_programma_picmicro_in_c_adattatore_freedom_breadboard

Parte 1 – Scriviamo il programma

EDIT: questo articolo è stato aggiornato, lo lascio qui per ragioni storiche, con i nuovi sistemi il codice si scrive diversamente: qui c’è il nuovo articolo

Dopo aver montato tutto il circuito, possiamo procedere alla scrittura del nostro primo programma. Personalmente per scrivere il programma in C, utilizzo Notepad++ (mi piace perchè è freeware, evidenzia le parole chiave con colori diversi, ha il supporto della sintassi per molti linguaggi, la numerazione delle righe ecc). Voi ovviamente potete utilizzare ciò che più vi piace, anche il blocco note di windows (anche se non lo consiglio affatto, è buono avere un editor tipo Notepad++ che evidenzia la sintassi).

ATTENZIONE!
Dato che il 90% degli italiani non ha assolutamente la sana abitudine di leggere i commenti, nè tantomeno cercare una risposta, scrivo qui una cosa che continuo a ripetere all’infinito e di cui mi sono stufato: dal momento che l’Hitech-C è stato aggiornato, alcuni nomi mnemonici non combaciano più con quelli delle vecchie versioni, per cui finito di leggere l’articolo, prima di compilare il programma VI PREGO, VI SCONGIURO di andarvi a leggere questo articolo: https://www.settorezero.com/wordpress/hitec-c-compiler-i-nuovi-nomi-mnemonici-che-causano-errori-nei-vecchi-programmi/

Questo è il primo programma che andremo a scrivere (sarà comunque possibile scaricarlo in fondo all’articolo per gli utenti iscritti: è gratis!), creiamo un file di testo vuoto, diamogli il nome “main.c” e incolliamoci all’interno il seguente codice:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//*************************************************
// CORSO PROGRAMMAZIONE PICMICRO
// www.settorezero.com
//
// modulo: main.c
// autore: Bernardo Giovanni
// data: 18/08/09
// descrizione: lampeggia un led su RD0
// picmicro: PIC16F877A
// clock: 20MHz
//
//*************************************************
 
#define  XTAL_FREQ 20MHZ // questo è utilizzato dalle routine di ritardo contenute in Delay.C
#include <pic.h> // contiene i nomi mnemonici di registri e porte
 
// Fuses di configurazione
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
 
#include "delay.c" // routine per ritardi
#define&nbsp;&nbsp; &nbsp;LED&nbsp;&nbsp; &nbsp;RD0 // invece di scrivere RD0, scriverò LED, così mi è più facile ricordare
 
// funzione principale, eseguita all'avvio del picmicro
void main(void)
 {
 
 // imposto i registri tristato in maniera tale che tutte le porte siano configurate come pin di uscita
 TRISA=0b00000000;
 TRISB=0b00000000;
 TRISC=0b00000000;
 TRISD=0b00000000;
 TRISE=0b00000000;
 
 while(1) // eseguo un ciclo finito
 {
 LED=LED^1;
 DelayMs(250);
 }// Fine ciclo continuo
 
 } // Fine main

Analizziamo quindi il programma. Quello che si trova dietro il doppio backslash (//) sono semplici annotazioni, verranno ignorate dal compilatore, servono soltanto al programmatore a “ricordarsi” cosa succede. E’ sempre buona norma mettere all’inizio del programma un’intestazione con le date ecc, e che specifica autore, scopo del programma e quant’altro vogliamo, se non altro ci aiuterà tra qualche anno quando dovremmo rimettere mano a un codice per modificarlo o migliorarlo.

14
#define&nbsp; XTAL_FREQ 20MHZ

Le righe che iniziano con il cancelletto (#) sono direttive inviate al compilatore, ovvero non si tratta di vere e proprie istruzioni di programma, ma di istruzioni inviate al compilatore e che non occuperanno spazio in memoria programma. In questa riga in particolare, l’istruzione define dice al compilatore che quando all’interno del programma troverà la scritta “XTAL_FREQ”, la dovrà sostituire con il valore “20MHz”. Non si tratta affatto dell’assegnazione del valore ad una variabile, stiamo soltanto definendo un nome alternativo per un valore, il che ci aiuta molto a ricordare. Questa riga in particolare è utilizzata da una routine (che vedremo in seguito) che serve a generare ritardi.

15
#include <pic.h>

è un’altra direttiva (vedete? c’è il cancelletto): stiamo dicendo al compilatore di includere in quel punto, il file “pic.h”.  In pratica tale direttiva leggerà il contenuto di quel file e lo inserirà in quel punto. Questo è un buon modo per scrivere codice “portabile”: una volta scritta una porzione di codice riutilizzabile, non ci sarà bisogno di riscriverla sempre nei nostri programmi, basterà “includerla”. Quando tale direttiva include un file contenuto nella cartella “include” dell’installazione del compilatore, tale file va scritto tra < e >, quando invece il file da includere si trova in un altro percorso, allora va incluso tra virgolette ” ” (in particolare se tra virgolette indichiamo unicamente il nome del file, il compilatore assume che tale file da includere si trovi nello stesso percorso del file principale, ovvero main.c).

Il file pic.h in particolare, che già si trova nella cartella “include” di installazione dell’Hitec-C, contiene tutte le definizioni dei nomi delle porte e dei registri dei vari picmicro. In pratica non dovremo ricordarci tutti gli indirizzi di memoria (che sono numerici!) del nostro PICMicro: basterà ricordarsi i nomi “mnemonici”, molto più facili da ricordare perchè i loro nomi rispecchiano in un certo qual modo le funzioni dei registri. Impareremo man mano a utilizzare i nomi mnemonici quando ne avremo bisogno. In particolare il file pic.h includerà a sua volta un altro o più file con estensione .h a seconda del PICMicro che sceglieremo durante la compilazione del programma.

Quando programmerete in C, incontrerete essenzialmente due tipi di file di testo, con estensione .c (che  contengono funzioni, programmi principali) e con estensione .h. h sta per Header, ovvero “intestazione”, si tratta in genere di files ausiliari che contengono settaggi, prototipi di funzioni ecc, necessari per il funzionamento delle funzioni principali, si tratta in pratica di una convenzione e buona pratica di programmazione. Ovviamente noi potremmo scrivere tutto il nostro codice in un unico file, ma avere il file principale, soprattutto se si tratta di programmi complessi, suddiviso in più files c e h ci aiuterà molto a concentrarci su una parte di programma e ci permetterà di rendere il nostro programma, o le nostre funzioni, riutilizzabili in altri ambiti anche totalmente differenti da quelli per cui sono stati progettati.

Date una sbirciatina nella cartella “include” del compilatore (C:\Programmi\HI-TECH Software\PICC\PRO\9.65) : vedete? Ci sono un sacco di files .h, ognuno che contiene vari #define a seconda del picmicro che andremo a scegliere. Il file pic.h è quello generico, che si accorgerà di quale pic abbiamo scelto (durante l’operazione di compilazione che vedremo dopo) e che provvederà a includere il file .h adatto: in particolare per il PIC16F877 sarà incluso il file pic1687x.h.

Andiamo avanti con la spiegazione del programma:

18
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);

Questa parte qui è un po’ più complicata… Si tratta in pratica di una funzione (chiamata appunto “__CONFIG” definita nel file pic.h) che serve a settare i FUSES (o fusibili) di configurazione del picmicro e di cui abbiamo già accennato qualcosina nelle precedenti lezioni. Ogni picmicro ha un suo registro di configurazione con i propri valori (vedete pag. 144 del datasheet del PIC16F877A) e che serve per impostare le modalità di funzionamento. I valori che si trovano tra parentesi (ovvero gli argomenti della funzione) sono nomi mnemonici (ogni parola, tipo HS è in realtà un valore numerico, definito da vari #define contenuti nei file h del picmicro scelto), che vengono combinati tramite AND logici per ottenere la word di configurazione adatta. In particolare questo settaggio dice:

HS (High Speed) = intendiamo utilizzare un oscillatore al quarzo ad alta frequenza.

WDTDIS (Watch Dog Timer DISabled) = disabilitiamo il Watch Dog Timer: si tratta di un timer che ha la funzione di resettare il pic se il programma si blocca e quindi far ripartire il programma daccapo, noi per ora (e forse mai) non utilizzeremo questo timer, dobbiamo programmare bene per fare in modo che il programma non si blocchi!! In realtà tale funzione a volte è utile, ma noi probabilmente non la useremo.

PWRTEN (PoWeRup Timer ENabled) = il pic aspetta alcuni microsecondi all’accensione prima di avviare il programma, in maniera tale da far stabilizzare la tensione e l’oscillatore.

BORDIS (Brown Out Reset DISabled) = il brown out è una funzione che permette di resettare il pic se la tensione di alimentazione scende al di sotto di un dato valore, tale funzione non ci serve, quindi la disattiviamo.

LVPDIS (LowVoltage Programming DISabled) = disabilitiamo la programmazione a bassa tensione (abbiamo visto nelle lezioni precedenti di cosa si tratta).

DUNPROT (Data UNPROTected) = la memoria dati non sarà protetta

WRTEN (WRite ENabled) = scrittura memoria flash abilitata

DEBUGDIS (DEBUG DISabled) = funzioni di debugging disabilitate, il debug non è disponibile con il pickit2

UNPROTECT = non protegge la memoria programma

Questi sono i settaggi ideali per gli esperimenti: proteggere la memoria dati, programma, eeprom, disattivare la scrittura, potrebbe difatti renderci impossibile riprogrammare il PIC una seconda volta, quindi se sbagliamo, il pic sarà da buttare! Quindi non proteggiamo assolutamente nulla!

20
#include "delay.c"

Stiamo includendo il file delay.c (scaricabile insieme a tutto il progetto in fondo all’articolo, per gli utenti iscritti) che si trova nello stesso percorso del file principale. Tale file include delle routine per creare ritardi (delay). Includendo questo file avremo a disposizione nel nostro programma due funzioni: DelayMs(n) che ci permetterà di eseguire ritardi di n millisecondi (con n da 0 a 255) e DelayUs(n) che ci permetterà di eseguire ritardi di n microsecondi. I ritardi sono funzioni molto importanti nei programmi.

21
#define&nbsp;&nbsp; &nbsp;LED&nbsp;&nbsp; &nbsp;RD0

Ancora un’altra direttiva! Stiamo dicendo al compilatore che quando leggerà la parola “LED” all’interno del programma, gli dovrà sostituire il valore RD0 (ricordate lo schema? Abbiamo collegato il led alla porta RD0, è più facile ricordarsi LED, sapendo che li cè collegato un led, piuttosto che RD0, vi pare?). La parola (o forse meglio il SIMBOLO) RD0 è a sua volta definito in uno di quei file h che abbiamo incluso all’inizio e contiene l’indirizzo di memoria che “mappa” la porta RD0, non ci dovremo preoccupare a quale indirizzo si trova la porta RD0, tanto abbiamo già tutti i nomi mnemonici già definiti per il nostro pic (definiti da pic.h, incluso all’inizio). Quindi come c’è RD0, ci sarà anche RA1, RB3 ecc ecc, comodo no?

Finalmente inizia il programma vero e proprio:

24
25
void main(void)
 {

Chiariamo innanzitutto una cosa, qui stiamo scrivendo una funzione, questa funzione si chiama “main” (scritto minuscolo!, ricordate che il C è case-sensitive! Ovvero fa distinzione tra maiuscole e minuscole!). La funzione chiamata main è quella che viene eseguita all’accensione del picmicro, per cui tutti i nostri programmi avranno sempre una funzione chiamata così.

Il “void” scritto all’inizio indica che tale funzione non restituisce valori (void=vuoto), il void scritto tra parentesi dopo main, indica che tale funzione non accetta valori in ingresso. La funzione main difatti non può nè deve accettare/restituire valori. Ci saranno altre funzioni che potranno accettare valori per eseguirci su dei calcoli e quindi restituire un valore, altre che restituiranno un valore ma non accetteranno niente in ingresso, altre ancora che accetteranno valori in ingresso ma non restituiranno niente.

Una cosa del genere ad esempio:

int somma(int a, int b)

definisce una funzione chiamata “somma”, che restituisce un numero intero (int), e accetta in ingresso due variabili (a e b) interi anch’essi. L’int messo davanti (al posto del void) specifica appunto un intero, int è uno specificatore del tipo di dato. Fate riferimento alla pagina 83 del file “manual.pdf” contenuto nella cartella docs del compilatore (C:\Programmi\HI-TECH Software\PICC\PRO\9.65\docs) per vedere quali sono i tipi di dato disponibili in C. Qui vi riporto un estratto:

tipi_di_dato_hitec_c

Ricordate inoltre: tutto ciò che deve essere eseguito dalla funzione, deve trovarsi tra parentesi graffe! Per cui: ricordiamoci di chiudere le parentesi dopo che le abbiamo aperte. E’ sempre buona norma mettere sempre prima entrambe le parentesi (aperta e chiusa) e quindi successivamente scriverci tutto all’interno.

Ovviamente qui qualcuno andrà nel pallone non trovando le parentesi graffe sulla tastiera. Le parentesi graffe si inseriscono tenendo premuto ALT (quello a sinistra, NO ALT GR) e quindi digitando in sequenza 1-2-3 sul tastierino numerico (ho detto sul tastierino! Non funziona con i numeri sopra alle lettere!) e quindi rilasciando il tasto ALT per la parentesi aperta, stessa cosa ma digitando 1-2-5 per la parentesi chiusa, e così anche per tutti gli altri caratteri che non trovano posto sulla tastiera.

Proseguiamo nella lettura del programma con qualcosa di più interessante:

28
29
30
31
32
TRISA=0b00000000;
TRISB=0b00000000;
TRISC=0b00000000;
TRISD=0b00000000;
TRISE=0b00000000;

I registri TRIS (regisatri tristato, ve ne ho accennato nella lezione 2) ci sono per ogni gruppo di porte (TRISA è il registro tristato delle porte A, e… TRISB ?). Notate innanzitutto che dopo l’uguale abbiamo uno 0b, questo zero-bi indica al compilatore che il numero che segue è in formato binario, se avessimo messo 0x (zero-ics) voleva dire che il numero che seguiva era scritto in esadecimale, invece senza notazione alcuna sarebbe stato scritto in decimale). Vi rimando ad un mio precedente articolo sulla numerazione binaria ed esadecimale, imparare queste cose non fa mai male. Sempre a pagina 83 del manuale dell’Hitec-C troviamo un’altra tabella con i prefissi da usare per specificare la base con cui scriviamo i numeri:

tipi_di_formato_numerico_hitec_c

Scrivendo

TRISA=0b00000000;

Stiamo dicendo che tutti i bit del registro tristato delle porte A, devono essere impostati su ZERO. Cosa significa? Impostare nel registro tristato un bit a zero equivale a impostare quella porta (quel pin) come USCITA (Output, per aiutarvi a memorizzarlo ricordate la somiglianza tra lo zero e la lettera O di Output…), impostare un bit a 1 equivale rendere quella porta (quel pin) un ingresso (Input, 1 somiglia alla lettera I, giusto? ;) ). In particolare il bit più significativo (ovvero l’ottavo bit) è quello più a sinistra: quello più vicino alla lettera b, andando verso destra troviamo il bit 7, 6 ecc fino ad arrivare al bit1 che viene detto bit meno significativo. Il bit1 mappa la porta 0, il bit2 mappa la porta 1 e così via. In pratica se noi scriviamo:

TRISA=0b00000010;

Diremo al PICMicro che la porta RA1 dovrà essere una porta di ingresso (abbiamo messo l’uno sul secondo bit, che mappa la seconda porta, ovvero la RA1) mentre tutte le restanti porte dovranno essere pin di uscita. Abbastanza semplice non trovate? Per questo motivo il settaggio delle porte lo scrivo in binario, così visivamente mi accorgo di quale porta sto impostando come ingresso e quale come uscita, ovviamente nulla mi vietava di scrivere 0x2 (notazione esadecimale) oppure 2 (notazione decimale) al posto di 0b00000010 … (usate la calcolatrice di windows in modalità scientifica per capire che ho detto se non ci siete arrivati…).

Ovviamente alcuni banchi di porte non disporranno di tutti e 8 i bit: ricordate l’immagine del datasheet del PIC16F877? Osservate: Le porte A sono soltanto 6 (da RA0 a RA5), quando vorremo settare questa porta, è buona norma per noi mettere comunque tutti e 8 i bit, ovviamente i bit 7 e 8 li metteremo a zero, tanto pure se li mettiamo a 1 non avranno effetto perchè le porte RA6 e RA7 su questo PIC non esistono… (per non parlare delle porte E che sono soltanto 3… Qui avremo a disposizione soltanto i bit 1, 2 e 3, gli altri bit da 4 a 8 li metteremo sempre a zero perchè tali porte non esistono).

Bene, abbiamo quindi settato tutte quante le porte del nostro PIC16F877 come uscita!

Quando nel nostro circuito rimarranno pin non utilizzati, è sempre bene impostare tali porte come uscite, perchè se le impostiamo come ingressi e non vengono utilizzate, potrebbero captare disturbi di natura elettromagnetica che dobbiamo sempre evitare come la peste.

Proseguiamo:

34
35
while(1) // eseguo un ciclo finito
 {

Qui abbiamo un ciclo while (vi rimando all’ottima lettura TrickyC presente nell’area risorse del sito, pagina 79, per capire come funzionano i 3 tipi di cicli disponibili in C) che verrà eseguito all’infinito perchè vi abbiamo messo 1 come condizione, che è sempre vera. All’interno di questo ciclo troviamo la parte interessante:

36
37
LED=LED^1;
DelayMs(250);

Qui stiamo accendendo e spegnendo il led!! Ma come? Iniziamo col dire che DelayMs(250) esegue una pausa di 250 millisecondi (ricordate le funzioni DelayMs incluse nel file delay.c di cui abbiamo parlato più in alto?), in pratica il led rimarrà acceso 250 ms e spento altri 250ms per poi ricominciare daccapo. L’accensione e lo spegnimento del led vengono eseguiti dall’istruzione LED=LED^1. Chiariamo innanzitutto che il simbolo ^ in C non è l’elevamento a potenza ma rappresenta la funzione di XOR, in pratica quando su un bit viene eseguito l’XOR con 1, viene invertito lo stato del bit: diventerà 1 se era 0 e viceversa.

Fate riferimento a questo nostro articolo per conoscere come si effettuano le operazioni di algebra booleana.

Scrivere LED=1 significa “dare tensione” a quel pin (ricordate? LED=RD0), quindi se scrivo LED=1 la porta RD0 si porterà in condizione di livello logico alto, ovvero da quel pin usciranno 5volt, per cui il led si accenderà, scrivere LED=0 porterà la porta RD0 in stato logico basso, per cui da quel pin usciranno zero volt (massa) e il led si spegnerà, scrivere LED=LED^1 significa semplicemente invertirne lo stato… Dal momento che dopo viene una pausa, si avrà l’effetto di vedere il led accendersi e spegnersi ogni 250ms (se avete la fortuna di avere un oscilloscopio, vedrete su tale pin un’onda quadra con la frequenza di 2Hz).

Difatti per portare un’uscita a livello logico alto (far uscire 5 volt), basta impostare tale porta a 1, per renderla bassa, si imposta a zero. Non dovrebbe risultare complicato.

Ci tengo a far notare che tutte le istruzioni devono terminare con un punto e virgola, altrimenti si verificheranno errori strani e incomprensibili durante la compilazione, e spesso gli errori vengono segnalati in una parte di programma che non c’entra nulla quando mancano il punto e virgola o non viene chiusa una funzione.

Abbiamo infine la chiusura del ciclo while e quindi della funzione main:

38
39
40
}// Fine ciclo continuo
 
} // Fine main

Ok… Abbiamo scritto il nostro primo programma (ok l’abbiamo copiato oppure scaricato!), abbiamo capito (si spera) come funziona… Non ci resta che compilarlo, caricarlo sul PICMicro e vedere come funziona!

Parte 2 – Compiliamo il programma

Abbiamo questa situazione: in una cartella ci sono i files: main.c, delay.c e delay.h scaricati in fondo all’articolo. Avviamo MPLAB IDE, Selezioniamo Project -> Project Wizard

primo_programma_picmicro_in_c_mplab_01

Comparirà la finestra del wizard (ovvero la procedura guidata) :

primo_programma_picmicro_in_c_mplab_02

Clicchiamo su Avanti, ci verrà chiesto di selezionare il dispositivo (il PICMicro) che intendiamo utilizzare per questo progetto:

primo_programma_picmicro_in_c_mplab_03

Scorriamo la lista e troviamo PIC16F877A, premiamo quindi Avanti. Ci verrà mostrata la finestra nella quale dobbiamo scegliere quale suite di linguaggio intendiamo utilizzare:

primo_programma_picmicro_in_c_mplab_04

Dal menù Active Toolsuite selezioniamo HI-TECH Universal ToolSuite come nella figura (l’abbiamo installato nella lezione 2, ricordate?), premiamo quindi Avanti, dovremo dare un nome al nostro progetto:

primo_programma_picmicro_in_c_mplab_05

Premiamo sul tasto Browse e andiamo a trovare la cartella in cui abbiamo salvato main.c e tutto il resto, nella casella nome file mettiamo un nome facile da ricordare: lampeggia_led, come in figura:

primo_programma_picmicro_in_c_mplab_06

Premiamo quindi salva, ritorneremo nella finestra precedente:

primo_programma_picmicro_in_c_mplab_07

Clicchiamo su Avanti, ci verrà chiesto di aggiungere dei files al progetto:

primo_programma_picmicro_in_c_mplab_08

Selezioniamo soltanto main.c e premiamo sul tasto Add>> per aggiungerlo al progetto, premiamo quindi Avanti. Sarà mostrata una finestra di riepilogo:

primo_programma_picmicro_in_c_mplab_09

Possiamo quindi premere Fine, verremo riportati alla finestra principale di MPLab:

primo_programma_picmicro_in_c_mplab_10

Vedete sulla sinistra c’è una finestra più piccola in cui è evidenziato il nostro codice sorgente main.c, anche se non abbiamo incluso gli altri file nel progetto durante il wizard, funzionerà tutto lo stesso perchè saranno inclusi dal compilatore grazie alle direttive #include che abbiamo scritto nel programma. Possiamo passare a compilare il programma. Vedete nella barra degli strumenti ci sono due tasti: uno nero e uno rosso:

primo_programma_picmicro_in_c_mplab_11

Quello nero è per compilare la prima volta, quello rosso è per RI-compilare nel caso avessimo già compilato e modificato qualcosa (verranno cancellati dei file “di appoggio” e ricompilato tutto daccapo). Premiamo il tasto nero. La compilazione prenderà generalmente meno di un minuto (dipende da tanti fattori) e se tutto è andato per il meglio, sarà presentata una finestra di riepilogo con le operazioni di compilazione e una scritta BUILD SUCCESSFUL alla fine:

primo_programma_picmicro_in_c_mplab_12

Vedete in questa finestra ci sono molte informazioni: quanta memoria programma abbiamo utilizzato (lo 0.9%, ma ricordate che stiamo utilizzando la versione LITE che non ci permette di utilizzare tutta la memoria programma disponibile ma ha un limite di 2000h words, con una versione PRO lo spazio a disposizione è molto di più, inoltre con la versione pro viene abilitata una funzione, chiamata Omniscient Code Generation, che permette di risparmiare ulteriore spazio, fino al 52% in meno, dal momento che ottimizza ancor più il codice compilato).

Quando qualcosa andrà storto, ci sarà invece scritto BUILD FAILED, con l’elenco dei numeri di riga che hanno dato l’errore, in questo caso dovremo individuare l’errore, correggerlo e ricompilare (premendo il tasto rosso anzichè quello nero). Errori tipici dei principianti sono:

  • dimenticanza del punto e virgola alla fine di una riga che lo prevede
  • dimenticanza della chiusura di una o più parentesi graffe
  • dimenticanza che il C è case sensitive, per cui se abbiamo dichiarato una “VarIABILE” e la richiamiamo come “variabilE”, non sarà riconosciuta, stessa cosa per le funzioni e per tutto il resto: rispettate maiuscole e minuscole!

Andiamo a controllare la cartella dove avevamo messo main.c, vedete, ci sono un sacco di altri file, a noi ne interessa in particolar modo uno soltanto: lampeggia_led.hex, quello con estensione HEX! E’ questo qui che dobbiamo caricare nel PICMicro? Come?

Parte 3 – Carichiamo il programma compilato nel PICMicro

Colleghiamo il PICKit2 alla porta USB del computer e innestiamolo nel connettore ICSP del circuito (ricordatevi di non tenere alimentato il circuito, anzi staccategli proprio i fili dell’alimentazione quando lo programmate).

Per sapere come va collegato il PICKit2 ai vari tipi di PICmicro (e anche alle memorie EEPROM), può esservi utile questo nostro articolo: Adattatore multizoccolo per PICKit2.

Avviamo il programma PICKit2:

primo_programma_picmicro_in_c_flashare_con_pikcit2_01

Dovrà essere presente il messaggio “PICkit2 found and connected” come in figura, dal menù “Device”, dove c’è scritto “-Select Part-“, scorriamo fino a scegliere PIC16F877A

Se PIC16F877A non è presente nell’elenco potrebbe essere necessario andare sul menù “Device Family” e selezionare Midrange -> Standard

primo_programma_picmicro_in_c_flashare_con_pikcit2_02

Come vedete cambia il valore di Configuration (che è il valore che sarà assegnato al registro di configurazione, non curiamoci di quello che esce scritto in questa fase, dal momento che il programma non l’abbiamo ancora caricato) e il valore di Checksum. Il Checksum in particolare è un valore che in un certo qualmodo identifica il programma che abbiamo caricato, quando faremo piccole o grandi modifiche a uno stesso programma, vedremo che tale valore cambierà, quindi due programmi perfettamente uguali avranno lo stesso checksum, è un buon modo per identificare un programma.

Andiamo avanti, dobbiamo caricare il nostro programma in memoria. Dal menù File selezioniamo “Import Hex”:

primo_programma_picmicro_in_c_flashare_con_pikcit2_03

Cerchiamo la cartella con il programma e selezioniamo “lampeggia_led.hex”:

primo_programma_picmicro_in_c_flashare_con_pikcit2_04

Premiamo quindi Apri, il file Hex sarà importato in memoria e cambieranno tutti i valori nell’interfaccia:

primo_programma_picmicro_in_c_flashare_con_pikcit2_05

In particolare cambierà il valore di configuration, che per i nostri esperimenti sarà sempre 2F02. Vedete che il campo program memory adesso contiene tanti valori, quei valori rappresentano appunto il nostro programma compilato: ovvero convertito da codice sorgente (comprensibile per gli esseri umani) a linguaggio macchina (comprensibile per il dispositivo).

Avete collegato il PICKit2 al circuito vero? Bene… Premiamo il tasto Write:

primo_programma_picmicro_in_c_flashare_con_pikcit2_06

Attendiamo un po’ che il nostro fido programmatore carichi nella memoria del PIC tutto il necessario: configurazione e programma. Dopodichè, se tutto va per il meglio, deve apparire la magica scritta:

primo_programma_picmicro_in_c_flashare_con_pikcit2_07

Ovviamente c’è un certo senso di soddisfazione: adesso il programma che abbiamo scritto è memorizzato all’interno del microcontrollore! Non ci resta che staccare il programmatore, e dare alimentazione al circuito. Il risultato che otterremo è questo:

Certo non è molto entusiasmante, ma avete visto quanto mi ci è voluto per insegnarvelo? Spero che abbiate capito tutto. Lasciate commenti e se potete, supportate il sito e chi ci lavora per passione. Nella prossima puntata cercheremo di fare di meglio ;)

Downloads

Nota: i programmi di esempio sono stati sviluppati con una versione precedente dell’Hitec-C Compiler, per cui compilati con la nuova versione, restituiscono errori. Fate riferimento a questo articolo per maggiori informazioni su come adattare i vecchi programmi. Consiglio spassionato se volete davvero imparare a programmare: non utilizzate l’include legacy headers, ma imparate a cambiare i nomi mnemonici.

[download#42]

Il codice aggiornato per il nuovo Corso di Programmazione PICmicro in C con MPLAB X e compilatore XC8 si trova in quest’altro articolo.

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