Esercitazioni ASM - PIC18

 


ESERCITAZIONE # 5


Il Clock Interno - INTIO1 / INTIO2

 

La velocità di esecuzione di una istruzione dipende dal clock del processore.

In queste esercitazioni stiamo utilizzando il generatore interno di clock, che è una rete RC di precisione.

Attraverso il CONFIG iniziale è possibile impostare due modi base, INTIO1 e INTIO2.
La differenza tra i due consiste esclusivamente nel fatto che RA6 diventa una uscita del clock / 4 e nel secondo, invece, è un GPIO.
Il primo modo è essenzialmente previsto per avere una sorgente di clock per altri componenti eterni, ma, in debug, è utilizzabile anche come monitor del clock con un frequenzimetro o un oscilloscopio.
Il secondo rende disponibili due pin addizionali di I/O digitale.

Maggiori informazioni sulle caratteristiche dell' oscillatore integrato qui.

Il processore, per default al POR stabilisce una configurazione dell' oscillatore interno tale da generare una frequenza di 1 MHz, ma questo valore può essere facilmente modificato attraverso il programma. Infatti va notato che, se la scelta della sorgente del clock è una impostazione nel CONFIG, quella della frequenza, invece, va fatta attraverso le istruzioni del programma, che, se necessario, andrà a modificare il registro relativo.

Quindi, per ricapitolare:

  • la scelta della sorgente del clock è obbligatoria attraverso il CONFIG
  • la scelta della frequenza del clock interno va fatta attraverso istruzioni del programma

Ciò vuol dire che la frequenza del clock principale nei modi INTIO1/INTIO2 può essere cambiata "in corso d' opera", ovvero durante il funzionamento del processore. E il foglio dati riporta le temporizzazioni di questo scambio, di cui fa parte anche un bit nel registro  che consente di verificare il momento in cui l' oscillatore si è stabilizzato.

In questa Esercitazione vogliamo apprendere come maneggiare questo scambio della frequenza.

Per evitare l' impiego obbligato di uno strumento costoso come un oscilloscopio o un frequenzimetro, la visualizzazione dell' avvenuta commutazione del clock viene demandata al lampeggio di un paio di LED. Comunque, utilizzando il modo INTIO1, chi ha ha disposizione questi strumenti potrà collegarli al pin  RA6 e verificare il valore esatto del clock dopo ogni commutazione. 

I PIC della famiglia 18F2321 hanno il controllo di queste funzioni in un registro OSCON, che, nei bit 6-4 consente di scegliere 8 diverse frequenze:

OSCON bit 6-4   IRCF2:0 Selezione della frequenza dell' oscillatore interno INTOSC
                        111 =  8MHz
                        110 = 4 MHz
                        101 = 2 MHz
                        100 = 1 MHz  (valore di default al RESET)
                        011 = 500 kHz
                        010 = 250 kHz
                        001 = 125 kHz
                        000 = 31 kHz

Sempre nello stesso registro, il bit 2 indica lo stato dell' oscillatore:

OSCCON bit 2      IOFS :  INTOSC Frequency stable
                      1 =  la frequenza prodotta da INTOSC è stabile
                      0 =  la frequenza prodotta da INTOSC non è stabile

Realizziamo, allora, un programma, decisamente più complesso dei precedenti, che ha lo scopo di far lampeggiare due LED ad una velocità determinata dal clock, utilizzando il metodo già visto. Il programma commuta da un clock a 1MHz (default al POR) a 2, 4 , 8 MHz.
Vedremo così variare la velocità di lampeggio da un ciclo molto lento con il clock a 1 MHz ad uno rapidissimo con il clock a 8 MHz.

Il disegno di un flow chart diventa, in questo caso, un obbligo.

Dopo aver inizializzato il processore e gli I/O necessari, facciamo lampeggiare i LED per un certo numero di volte, utilizzando come base tempo il ciclo delle istruzioni, ovvero la frequenza del clock.
Questa, dopo l' avvio del processore, sarà per default fissata a 1 MHz.

Successivamente commutiamo il clock su un valore maggiore e ripetiamo il lampeggio dei LED. Dato che il clock varia raddoppiando, per mantenere costante il tempo di lampeggio dei LED, ne aumentiamo le ripetizioni della stessa quantità.

Il loop prosegue commutando a passi successivi il clock e facendo lampeggiare di conseguenza i LED.

Arrivati alla frequenza massima prevista dai modi INTIO, ovvero 8 MHz, il clock viene commutato di nuovo a 1 MHz e il ciclo riprende.

Nulla vieta, volendo, di ampliare il ciclo sfruttando anche le frequenze inferiori.

 

Possiamo notare che l' operazione di lampeggio è sempre la stessa, ripetuta più volte. Questa situazione si presta ottimamente per essere implementata come subroutine.

Il numero di lampeggi da effettuare viene passato alla subroutine attraverso il registro WREG; in questo modo è possibile la scrittura di un solo algoritmo per un numero di lampeggi variabile tra 1 e 256 (dato che WREG è a 8 bit).

Il valore passato attraverso WREG viene salvato una locazione RAM che servirà per contare il numero dei lampeggi.

Il lampeggio dei LED è del tutto analogo a quanto già visto in esercizi precedenti e si basa su una routine di attesa waste time, la quale, dipendendo dal clock per la sua esecuzione, è la componente che determina la frequenza del lampeggio.

Eseguito un lampeggio, il contatore viene decrementato di una unità; se il suo contenuto è maggiore di zero, sono ancora da eseguire lampeggi, per cui il ciclo prosegue.

Se il contatore è azzerato, tutti i lampeggi sono stati eseguiti e il ciclo è esaurito: spegniamo tutti LED e ritorniamo al programma principale con l' istruzione Return.

Come detto, essendo il loop determinato dalla frequenza del clock, il suo tempo di esecuzione dimezzerà per ogni raddoppio del clock e viceversa. Se, nel contempo, passiamo alla routine un numero adeguato di ripetizioni, avremo una ciclo per ogni valore di clock di durata praticamente uguale.

Lo scambio di clock che avviene tra un ciclo di lampeggio e l' altro darà origine ad un effetto luminoso interessante.

Come per gli altri esempi, onde evitare per ora calcoli sui tempi di ciclo delle istruzioni, utilizziamo il calcolatore disponibile in rete per la creazione di ritardi di tempo, il noto Delay Generator di Nicolai Golovchenko.

Viene definito un tempo base di 500 ms per un clock di 1 MHz, che si ridurrà come segue:

Clock
[MHz]
Ciclo
[us]
Loop
Attesa
Lampeggi
al s
1 4 500 ms 2
2 2 250 ms 4
4 1 125 ms 8
8 0.5 62,5 ms 16

Il nostro esercizio prevede di collegare un LED al bit 0 di PORTC ed uno al bit 1 di PORTC, che lampeggeranno come indicato in tabella in cicli successivi.

Per quanto riguarda la commutazione del clock, anche in questo caso non è opportuno basarsi su istruzioni da ripetere più volte, ma diventa sensato scrivere una piccola libreria che contenga dei macro comandi.
Questa soluzione ha molti vantaggi:

  • in primo luogo, rende del tutto auto descrittivo il sorgente
  • inoltre costituisce un oggetto che potrà essere ri utilizzato in altre occasioni senza la necessità di riscrivere codice
  • per ultimo, data la sua struttura auto esplicativa, non richiede la continua consultazione del foglio dati: una volta determinati i bit da programmare e/o verificare durante la scrittura della libreria, il foglio dati non sarà più necessario

Una descrizione dettagliata della libreria in questione la trovate qui.

Per l' esecuzione pratica si dovranno semplicemente collegare i pin PC0 e PC1 a due LED della UniBoard (o del proprio hardware).

Il Pickit è inserito direttamente nella spina ICSP/ICD e permette un debug passo passo delle istruzioni.


Per chi non avesse chiare le connessioni, qui trova di seguito 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)
  • due cavetti jumper da 14-15 cm

Il listato sorgente è una estensione di quello già visto negli altri esercizi e che fa da base per tutti i seguenti, aggiungendo gli elementi necessari al nuovo lavoro.


Vediamo il listato nei dettagli.

Come inizio, è sempre presente una testata di descrizione del programma e delle sue funzioni e la già descritta definizione del processore usato, a cui segue la sezione di configurazione.

Dovendo utilizzare una libreria esterna, la dobbiamo includere. Trattandosi di MACRO, vanno definite PRIMA di essere utilizzate.

;----------------------------------------------------------------------
; Include libreria per gestione clock interno


   #include  "C:\PIC\LIBRARY\18F\18FIntClock.asm"

 


Assegniamo un paio di locazioni in RAM con la direttiva CBLOCK/ENDC.
Nel caso di questo programma, saranno necessari tre registri come supporto alle routines di attesa, ai quali si aggiunge il registro del contatore di lampeggi.

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


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

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

Possiamo anche cerare due macro per il comando dei LED, con la finalità di rendere più leggibile il listato.

;----------------------------------------------------------------------
; Equates 
;
; Numero lampeggi a 1 MHz
nlamp  equ  .10

; assegnazioni per i LED
#define  LED0  LATC,0 ; LED collegato a RC0
#define  LED1  LATC,1 ; LED collegato a RC1

;----------------------------------------------------------------------
; Macros
;
Led1On   MACRO
     
bsf   LATC,0
       
ENDM
Led1Off
  MACRO
     
bcf   LATC,0
       
ENDM     

Led2On   MACRO
     
bsf   LATC,1
       
ENDM
Led2Off
  MACRO
     
bcf   LATC,1
       
ENDM  

LedOff  MACRO
     
bcf   LATC,0
     
bcf   LATC,1
       
ENDM  

 


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

Da notare che sono utilizzate due macro dalla libreria 18FIntClock.asm:

m18SetIntClock   seleziona in OSCON il clock specificato dal parametro x
m18IntOscStable    attende la stabilizzazione dell' oscillatore prima di proseguire

;=====================================================================
; Inizio programma

   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 PORTC
; questo serve per avere subito a livello 0 i pin che saranno programmati come uscite
; non ha effetto sui pin programmati come ingressi.

       clrf   LATC

; inizializza PC0 e PC1 come output
; agendo sul registro di direzione
       bcf    TRISC,0 
       bcf    TRISC,1

; Ciclo primario
mainloop
       movlw  nlamp        ; numero lampeggi
       call   ciclo        ; lampeggio

       m18SetIntClock 2    ; clock 2 MHz
      
m18IntOscStable     ; attendi stabilizzazione oscillatore
       movlw  nlamp        ; numero lampeggi
       call   ciclo        ; lampeggio

       m18SetIntClock 4    ; clock 4 MHz
      
m18IntOscStable     ; attendi stabilizzazione oscillatore
       movlw 
 nlamp        ; numero lampeggi
       call   ciclo        ; lampeggio

       m18SetIntClock 8    ; clock 8 MHz
      
m18IntOscStable     ; attendi stabilizzazione oscillatore
       movlw 
nlamp        ; numero lampeggi
       call   ciclo        ; lampeggio
     
       m18SetIntClock 1    ; clock 1 MHz
      
m18IntOscStable     ; attendi stabilizzazione oscillatore

       bra    mainloop     ; ripeti indefinitamemte

Dato che utilizziamo la stessa sequenza di  ciclo di lampeggio più volte diventa sensato formularla come una subroutine e richiamarla con l' istruzione call o rcall.
L' uso delle Macro pre definite consente di avere un listato molto semplice e leggibile con facilità.

;=====================================================================
; Subroutines

; Ciclo di lampeggio alternato dei due LED
; Il numero dei lampeggi arriva attraverso WREG

ciclo  movwf  counter   ; salva W in counter

ciclo1 Led1Off          ; LED1 spento
       Led0On
           ; LED0 acceso
      
call   Attesa    ; attesa
      
Led0Off          ; scambia LED
      
Led1On  
      
call   Attesa
   
      
decfsz counter, f ; decrementa e testa il contatore
       
bra   ciclo1     ; non 0 - altro ciclo
; contatore azzerato - fine ciclo di lampeggio       
      
LedOff            ; spegne i LED
      
return            ; e ritorna

Analogamente per la routine di attesa, settata per 500 ms a 1 MHZ di clock, secondo l' algoritmo di Nicolai Golovchenko.

; Attesa 0.5 s @ 1 MHz di clock
; Procedura ricavata dal Delay Generator di Golovchenko
; Sorgente modificato per l' uso con il set di istruzioni enhanced
; Delay = 0.5 seconds
; Clock frequency = 1 MHz
; Actual delay = 0.5 seconds = 125000 cycles
; Error = 0 %

Attesa               ;124993 cycles
      movlw 0xA6
      movwf d1
      movlw 0x62
      movwf d2
Delay_0
      decfszd1, f
      goto   $+6
      decfszd2, f
       goto Delay_0
                    ;3 cycles
      goto$+4
      nop
                    ;4 cycles (including call)
      return

;********************************************************************
; 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, non termina, dato che permane nel loop che fa lampeggiare i LED


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.