Esercitazioni ASM - PIC18

 


ESERCITAZIONE # 2


USO dei PORT come uscite digitali

 

Uno dei più comuni impieghi dei pin di un embedded è il comando di un carico in uscita (LED, relay, ecc). Questo richiede che il programma provveda, per prima cosa, a configurare quel pin come uscita.

Questo richiede una azione sul registro di direzione del port (TRIS) a cui il pin appartiene, in modo da dirigerlo come uscita.

Sfortunatamente, anche un banale uso dei PORT di I/O per accendere un LED negli embedded richiede una certa struttura, che, a prima vista vista, sembra molto ampia.
Questo è dovuto semplicemente al fatto che ogni pin può svolgere numerose funzioni, tutte programmabili. E non è detto che quella di uscita digitale sia quella stabilita dal default all' accensione.

In effetti, la politica del costruttore è quella di portare il chip, dopo un reset, in una condizione "neutra" in cui si da la preferenza ad una situazione di consumo minimo. E questo privilegia, ad esempio, la configurazione dei port come analogici piuttosto che digitali.

Quindi, volendo utilizzare uno o più pin con funzione di I/O digitali può essere necessario modificare i default con un certo numero di istruzioni.
Non tutti i port possono assumere funzioni analogiche; nella famiglia 18 di solito questo compito è assegnato ai PORTA, B ed E, mentre il PORTC e D ne sono esclusi. Quindi, la programmazione addizionale riguarderà essenzialmente le prime.
In ogni caso, essendo tutti port configurati come ingressi dal default del reset, per tutti i pin che si desidera utilizzare come uscita occorre modificare il registro di direzione relativo (TRISx).

Il nostro esercizio prevede di collegare un LED al bit 0 di ogni port (RA0, RB0, RC0). I LED sono posti tra il pin e il gnd (Vss, massa) con la rispettiva resistenza in serie e quindi saranno accesi quando il pin, configurato come uscita, sarà portato a livello 1.

L' esercizio ha lo scopo di verificare in pratica il modo di assegnazione di una funzione GPIO di uscita ad un pin di ogni port.

Ovviamente, dovendo visualizzare il risultato, il progetto imposta Pickit3 come debugger e viene utilizzata la Uniboard, direttamente alimentata a 5V dal Pickit.

Si dovranno semplicemente collegare i pin PA0, PB0 e PC0 ognuno ad un dei LED della scheda.
Il Pickit è inserito direttamente nella spina ICSP/ICD e permette un debug passo passo delle istruzioni.

Ovviamente sarà possibile utilizzare Pickit2 senza variazioni se non la diversa impostazione nell' ambiente MPLAB; oppure anche REAL ICE o ICD, sempre con il semplice cambio nel setup di MPLAB, tenendo presente che non tutti i tools sono in  grado di alimentare l' hardaware.
Inoltre è sempre possibile utilizzare SIM senza alcun hardware o debugger collegato.

Una descrizione particolareggiata delle funzioni dei PORT è consultabile qui.


Per chi non avesse chiare le connessioni, qui trova una pagina dedicata.

L' esercizio richiede le seguenti risorse:

  • MPLAB IDE installato
  • Pickit3 (o Pickit2)
  • 28-40pin UniBoard con PIC18F2321 0 4321 (o 2221 o 4221 o altro hardware similare)
  • tre cavetti jumper da 14-15 cm

Il listato sorgente è una estensione di quello già visto nell' Esercizo 1, di cui conserva la struttura del template, aggiungendo gli elementi necessari al nuovo lavoro.

Da un punto di vista strutturale il programma agisce in questo modo:

  1. Azzeramento dei latch dei port. Questa operazione preliminare serve per pre determinare il livello che i pin assumeranno  nel momento in cui saranno configurati come uscite.
  2. Disabilitazione delle funzioni analogiche da tutti i PORT A e B agendo sul registro ADCON1.
  3. Disabilitazione dei comparatori analogici presenti sui PORTA agendo sul registro COMCON.
  4. Imposizione della direzione uscita per i bit 0 dei PORT A, B, C agendo sui rispettivi registri TRIS.
  5. Attivazione dei led portando a livello 1 i relativi bit. L' azione viene effettuata sui registri LAT, dato che i PIC18 consentono un accesso separato a questi SFR.
  6. Stop del micro bloccandolo in un loop infinito. 

Il punto 6 è necessario in quanto il programma non è un loop chiuso, ma, una volta accesi i LED, ha terminato la sua funzione. Però non è possibile bloccare il processore se non in due modi:
- mettendolo in condizione di SLEEP, ovvero bloccando il clock principale
- impegnandolo in un loop infinito

La funzione SLEEP e le sue possibilità saranno oggetto di altre esercitazioni dedicate a questo.

Ora ci limitiamo alla seconda soluzione, ovvero chiudiamo il programma costringendo il processore a circolare su una istruzione che si richiude su se stessa.
Questa soluzione, apparentemente strana, è dovuta al fatto che, altrimenti, terminate quelle che sono per noi le operazioni richieste al processore, il Program Counter continuerebbe comunque a scandire locazioni di memoria programma, mentre la logica di decodifica cercherebbe di eseguire come istruzioni i codici casuali in esse. Però, essendo queste  celle della Flash non inizializzata, potrebbero verificarsi situazioni imprevedibili.
Dunque, "stoppiamo" il processore costringendolo a fare come il cane che corre in circolo dietro alla sua coda, soluzione poco elegante, ma efficace.


Vediamo il listato nei dettagli.

Come inizio, è sempre presente una testata di descrizione del programma e delle sue funzioni.


;*****************************************************************
; Esercitazioni PIC18 - Esercitazione # 2
;*****************************************************************
; Esempio di uso dei PORT
; Author  : afg
; Version : E18_2_00
; Date    : 09/10/2010
;-----------------------------------------------------------------
; Descrizione: Il sorgente imposta alcuni pin dei PORTA,B,C,D
; come uscite e accende i relativi LED collegati.
;-----------------------------------------------------------------
; Note : Processore PIC18F2321
; Oscillatore interno a 1 MHz (clock interno 250 us)
; senza la necessità di componenti esterni
; Debug con MPLAB IDE e PickKit3
; Previsto per funzionare con tutti gli enhanced
;*****************************************************************

Inizia ora il vero e proprio sorgente, con gli elementi di definizione del processore.

         LIST P=18F2321 ; Utilizziamo il PIC18F2321
         radix dec      ; con base decimale per le operazioni
                        ; matematiche


         #include "P18F2321.INC" ; Include l' header file

; questo header è fornito dallo stesso Assembler e non richiede 
; alcun file addizionale

 


Segue quindi la configurazione del processore.

Qui è utilizzata una configurazione minima. I commenti chiariscono le funzioni configurate.

;---------------------------------------------------------------------
; Configurazione minima dei debug del processore
;
; Background debugger enabled su RB6 e RB7 per il debug con il 

; Pickit o altro, attraverso ICSP/ICD
  CONFIG DEBUG = ON 
; Single-Supply ICSP disabled 
  CONFIG LVP = OFF 
; Uso dell' oscillatore interno, port su RA7 e FOSC/4 su RA6

  CONFIG OSC = INTIO1 
; PWRT disabled per il debug 
  CONFIG PWRT = OFF
; Brown-out in hardware only 
  CONFIG BOR = ON 
; Soglia BOR 4.2V 
  CONFIG BORV = 1
; Funzione del pin MCLR abilitata 
  CONFIG MCLRE = ON
; WDT disabilitato 
  CONFIG WDT = OFF 



Assegniamo un paio di locazioni in RAM con la direttiva CBLOCK/ENDC.
Nel caso di questo programma, non hanno alcuna funzione. Serviranno nelle esercitazioni successive.

;----------------------------------------------------------------------
;Assegna registri di memoria RAM


 CBLOCK 0x00 ; blocco di RAM a partire da 0x00
   d1        ; riserva 2 bytes per un contatore
   d2
 ENDC       
; fine blocco RAM

Nell' area degli Equates inseriamo alcune definizioni che ci serviranno durante il programma.

Inizialmente definiamo una maschera che, applicata al registro di direzione TRISx programmerà il bit 0 come uscita.

Poi, è pratico assegnare delle label ai LED in modo tale da richiamarle successivamente ed avre una immediata indicazione di cosa fa il programma in quel dato punto.
Da notare che utilizziamo il registro LATx al posto di POPRTx

;----------------------------------------------------------------------
; Equates 
;

; Maschera per impostare il registro di direzione del pin 0 di un port
; come uscita

port0_out
equ b
'11111110'

; assegnazioni per i LED
#define LEDA LATA,0 ; LED collegato a RA0
#define LEDB LATB,0 ; LED collegato a RB0
#define LEDC LATC,0 ; LED collegato a RC0

 


Ecco il "programma" vero e proprio, con ampi commenti che descrivono le funzioni svolte da ogni riga:

;=====================================================================
; Inizio programma
; Il programma:
; - imposta i pin RA0, RB0, RC0 come uscite
; - porta questi pin a livello alto
; se ad essi c'è collegato un LED verso massa, esso verrà acceso



   ORG 0x00         ; Programma inizia a 0x00 - vettore del reset

Start  nop          ; dummy - linea utile solo ai fini del debug

; inizializza a 0 i latch di uscita dei PORT
; questo serve per avere subito a livello 0 i pin che saranno programmati come uscite
; non ha effetto sui pin programmati come ingressi.

       clrf  LATA
       clrf  LATB
       clrf  LATC

; inizializza PORTA
; La prima operazione è quella di disabilitare la funzione di input
; analogico che i pin assumono dopo il reset

       movlw 0x0F   ; disabilita tutti gli ingressi analogici
       movwf ADCON1
; poi, disabilitiamo i compratori
       movlw 0x07   ; disabilita i comparatori
       movwf CMCON  ; dal PORTA
; ora possiamo applicare la maschera predefinita che obbliga 
; PORTA0 = out e tutti gli altri in

       movlw port0_out
       movwf TRISA

; inizializza PORTB
; le precedenti linee movlw 0x0F e
movwf ADCON1 hanno escluso le funzioni
; analogiche anche da PORTB

       movwf TRISB

; inizializza PORTC, che non richiede particolare attenzione

       movwf TRISC

; accende i LED
       bsf  LEDA
       bsf  LEDB
       bsf  LEDC

; il programma ha eseguito il suo compito - blocchiamo il processore
; in un loop infinito

lock   goto lock    ; loop di blocco


;=====================================================================
; Subroutines
; area vuota
;********************************************************************
; Direttiva di fine sorgente

   END

La fine del sorgente è determinata come al solito dalla direttiva END

Da notare che il programma vero e proprio, invece, termina impegnando la CPU in un loop infinito. Questo è necessario altrimenti il processore proseguirebbe ad eseguire i codici casuali contenuti nella memoria programma, con la possibilità di creare situazioni imprevedibili.


Avviando lo step-by-step  potremo seguire il flusso delle istruzioni ed osservare l' accensione di LED dopo le relative istruzioni.

Se si incontrano errori nella compilazione è opportuno verificarli con la lista di descrizione degli errori e correggere dove si è sbagliato.


Il file compresso di questa esercitazione è scaricabile dall'  area di download.

 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 04/04/11.