ELEMANIA
PIC16F690 - Un semplice programma
Creazione del progetto

Al termine dell'installazione, il compilatore può essere utilizzato facilmente all'interno dell'ambiente di sviluppo MPLAB-IDE. Per fare questo bisogna creare un nuovo progetto con Project Wizard e al passo due (Step Two) scegliere Hi-TECH Universal ToolSuite e HI-TECH ANSI C Compiler come mostrato in figura:

Selezionare il compilatore ANSI C HI-TECH

Infine bisogna creare un nuovo file con File/New, salvarlo con estensione .c ed aggiungerlo al progetto (per i dettagli della creazione di un progetto vedi la lezione su MPLAB-IDE).

ATTENZIONE: il linguaggio usato dal compilatore è il C standard e non il C++. Perciò non è possibile usare classi e oggetti e le funzioni di input e output devono essere realizzate con printf e scanf invece che con cin e cout.

 

Un semplice programma di esempio: far lampeggiare i LED

Vediamo subito un semplice esempio di programma scritto in HI-TECH C per la Low Pin Count Demo Board del PIC16F690. Il programma fa lampeggiare i quattro led della scheda quando viene premuto il pulsante collegato con RA3:

/*
Semplice programma di esempio per far lampeggiare i LED del PIC
Periodo di lampeggiamento un secondo
*/

#include <htc.h>

// questa costante serve alla routine __delay_ms per sapere qual è la freq del clock
#define _XTAL_FREQ 125000

__CONFIG(  CP_OFF & // Program memory code protection is disabled
                CPD_OFF & // Data memory code protection is disabled
                BOREN_OFF & // BOR disabled
                PWRTE_ON & // PWRT enabled
                WDTE_OFF & // WDT disabled
                FOSC_INTRCIO & // INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin
                MCLRE_OFF & // MCLR pin function is digital input
                FCMEN_OFF & // Fail-Safe Clock Monitor is disabled
                IESO_OFF); // Internal External Switchover mode is disabled

void main()
{
OSCCON = 0b00010000; // setta la frequenza del clock a 125000 Hz

ANSEL = 0;        // azzera ANSEL e ANSELH per settare tutte le porte in digitale
ANSELH = 0,

PORTC=0X00; // azzera tutti i bit di PORTC (LED spenti inizialmente)

TRISC=0X00; // programma PORTC tutta in output

while(1)        // ciclo infinito
    {

       while (RA3); // ciclo di attesa della pressione del pulsante su RA3

PORTC=0XFF; // tutti i bit di PORTC a 1 (LED tutti accesi)
__delay_ms(500);    // ritardo di 500ms

PORTC=0X00; // tutti i bit di PORTC a 0 (LED tutti spenti)
__delay_ms(500);    // ritardo di 500ms

}

}

Per far compilare il programma, una volta creato correttamente il project come spiegato nella precedente lezione, è sufficiente scegliere Project/Build. La simulazione può essere effettuata come già visto trattando della simulazione in assembly.

Per vedere il listato in assembly corrispondente al codice C basta scegliere View/Disassembly Listing:

Esaminiamo adesso brevemente le diverse parti di cui si compone il programma. Per una descrizione più dettagliata rimandiamo il lettore alle sezioni specifiche nel seguito. Per le spiegazioni riguardanti la sintassi del linguaggio C, i link nel testo rimandano alle pagine del sito Programmiamo. Invece per il funzionamento dei componenti hardware del PIC, i link rimandano alle altre sezioni di questo sito dove tali componenti sono già stati trattati parlando di programmazione in assembly del PIC.

Maiuscole e minuscole

A differenza dell'assembly, che non distingue le maiuscole dalle minuscole, il C è un linguaggio case-sensitive: cioè le istruzioni vanno scritte esattamente come nell'esempio sopra, rispettando le maiuscole e le minuscole utilizzate.

Commenti, istruzioni e direttive

I commenti seguono la sintassi standard del C. Si usa il doppio slash // se il commento occupa una sola riga:

// questa costante serve alla routine __delay_ms per sapere qual è la freq del clock

Si usa invece /* ... */ se il commento occupa più righe di testo:

/*
Semplice programma di esempio per far lampeggiare i LED del PIC
Periodo di lampeggiamento un secondo
*/

Tutte le istruzioni del C sono terminate da un punto e virgola finale. Questa è un'importante differenza rispetto al linguaggio assembly, dove invece il punto e virgola serve per indicare un commento.

Le direttive del preprocessore (es. #include e #define) non sono istruzioni (non producono codice eseguibile) e non sono terminate da punto e virgola.

 

L'include iniziale

Ogni programma inizia con la direttiva del preprocessore:

#include <htc.h>

Questa direttiva serve per includere nel programma la definizione di tutte le costanti specifiche del PIC utilizzato. Il tipo di PIC viene settato al momento della costruzione del Project, quando bisogna specificare il modello di PIC.

Il file htc.h fa a sua volta riferimento ad altri file include, in particolare pic.h e, nel nostro caso, pic16f690.h (il file specifico del nostro PIC). Non è però necessario includere esplicitamente tali file all'inizio del programma, poiché l'inclusione viene fatta automaticamente attraverso il file htc.h.

La macro __CONFIG

La istruzione __CONFIG iniziale (in realtà si tratta più propriamente di una macro) serve per settare i valori della Configuration Word. I diversi valori vengono indicati per mezzo di una serie di costanti letterali concatenate dall'operatore &.

Si noti in particolare la costante MCLRE_OFF indispensabile per poter usare RA3 come input (altrimenti verrebbe usato come master clear reset) e FOSC_INTRCIO che specifica l'uso dell'oscillatore interno al PIC.

L'elenco delle costanti predefinite per l'istruzione __CONFIG si trova nel file include pic16f690.h.

Uso dei registri SFR

Il programma contiene alcune assegnazioni a registri SFR (Special Function Register) del PIC. Per esempio:

ANSEL = 0;
ANSELH = 0,

servono per azzerare i registri ANSEL e ANSELH. In questo caso ANSEL e ANSELH sono variabili speciali predefinite del HI-TECH C che fanno riferimento direttamente ai corrispondenti registri del PIC.

Osserviamo che è possibile accedere anche ai singoli bit di un registro SFR mediante il loro nome come in:

while (RA3);

dove viene testato ripetutamente il bit 3 di PORTA (finché non diventa zero ed esce dal ciclo - per la sintassi del while vedi qui).

Poiché alcuni bit hanno lo stesso nome in porte diverse esiste anche la seguente sintassi alternativa per fare riferimento a un bit di un registro:

while (PORTAbits.RA3);

Osserviamo che non è necessario selezionare esplicitamente il banco di memoria di appartenenza dei registri: tale selezione viene fatta automaticamente dal compilatore C. Per i dettagli sul funzionamento e lo scopo dei registri SFR del PIC si rimanda il lettore alle relative lezioni in linguaggio assembly.

L'elenco dei nomi dei registri e dei bit predefiniti si trova nel file include pic16f690.h. Per i dettagli sulla programmazione delle porte del PIC rimandiamo alle lezioni sullo stesso argomento in linguaggio assembly.

Costanti numeriche

Vi sono diversi modi per indicare i valori numerici costanti, come mostrato in tabella:

Tipo
Sintassi
Esempio
Binario
0b seguito dal numero binario
0b00111001
Decimale
il numero stesso
25
Esadecimale
0x seguito dal numero binario
0x9F

Se non si indica nulla, i valori vengono considerati come decimali, come in:

__delay_ms(500);

Per specificare un valore binario bisogna anteporre 0b alla sequenza di bit come in:

OSCCON = 0b00010000;

Per i valori esadecimali il numero deve essere preceduto da 0x come in:

PORTC=0XFF;

La funzione _delay_ms

Per fare lampeggiare i LED collegati con PORTC è necessario introdurre un ritardo fra l'accensione e lo spegnimento. Ciò viene realizzato con la funzione __delay_ms (notare il doppio undescore all'inizio).

Questa funzione, come suggerisce il nome, genera un ritardo pari al numero di millisecondi indicati (nel nostro caso 500ms, cioè 0,5 secondi). Per poter funzionare correttamente questa funzione necessita della costante _XTAL_FREQ, definita all'inizio del programma:

#define _XTAL_FREQ 125000

Questa costante specifica la frequenza del  clock interno del PIC (nel nostro esempio 125000 Hz). Si presti attenzione al fatto che il valore indicato nella definizione di _XTAL_FREQ non setta la frequenza del clock del PIC. Questa operazione viene infatti eseguita da:

OSCCON = 0b00010000;

che setta i bit del registro OSCCON per avere una frequenza di clock di 125KHz. Lo stesso risultato si poteva ottenere settando direttamente i bit IRCF0, IRCF1 e IRCF2 di OSCCON nel seguente modo:

IRCF0 = 1;
IRCF1 = 0;
IRCF2 = 0;

Si presti attenzione al fatto che, perché tutto funzioni correttamente, la frequenza specificata con _XTAL_FREQ deve essere la stessa settata con OSCCON.

Un'altra precisazione importante a proposito di _delay_ms è che il tempo di ritardo in millisecondi indicato non può in nessun caso superare un valore massimo che dipende dal clock usato. Tale valore massimo è pari a circa 200.000.000 volte il periodo del clock. In pratica, usando un clock con frequenza 125kHz e periodo 1/125 kHz = 8 µs, il massimo ritardo che sarà possibile usare con la funzione _delay_ms è dato da:

200.106 x 8.10-6 = 1600 secondi = 1.600.000 ms

Superando tale valore massimo si otterrà, al momento della compilazione, un messaggio di errore del tipo "delay exceeds maximum limit of 50462464 cycles" (si noti che nel messaggio il limite massimo viene espresso in cicli di istruzione (instruction cycle), essendo un ciclo di istruzione pari a 4 periodi del clock).

 

Un ciclo infinito nascosto

Una caratteristica poco documentata del compilatore HI-TECH C è il fatto che il codice prodotto contiene un ciclo infinito implicito o nascosto. In pratica il programma compilato viene eseguito ripetutamente all'infinito sul PIC, anche in assenza di cicli infiniti dichiarati esplicitamente nel codice C.

Infatti (come già discusso) il PIC non possiede un'istruzione di tipo HALT in grado di interrompere l'esecuzione del programma. Pertanto in realtà un programma per il PIC non può terminare per definizione, in quanto il PIC non smette mai di eseguire istruzioni. Questo fatto viene affrontato al momento della scrittura di un programma in due possibili modi:

Evidentemente i programmatori di HI-TECH hanno optato per la prima soluzione. Il risultato è che ogni programma compilato in questo modo viene eseguito ripetutamente sempre daccapo. Non sempre questo comportamento è desiderabile. Quando non si desidera che venga ripetuto, occorre terminare il programma (dopo l'ultima istruzione) con un ciclo infinito di blocco, tipo:

while(1);

In questo modo arrivato in fondo all'esecuzione, il PIC rimane intrappolato nel precedente ciclo e non ripete tutto quanto dall'inizio.

 

 

precedente - successiva

Sito realizzato in base al template offerto da

http://www.graphixmania.it