Al powerup, l'8051 scrive il valore 0000h nel PC. Da quel momento l'8051 inizia ad eseguire le istruzioni sequenzialmente in memoria a meno che un' istruzione del programma non alteri il PC. Ci sono diverse istruzioni che possono modificare il valore del PC tra le quali: le istruzioni di branching condizionali, i salti diretti e le chiamate e i ritorni a/da subroutine. In piu' gli interrupt, quando abilitati, possono causare la deviazione del flusso di programma dal suo schema sequenziale.
L'8051 dispone di una serie di istruzioni che, come gruppo, sono denominate istruzioni di "branching (ramificazione) condizionale". Queste istruzioni forzano l'esecuzione del programma ad abbandonare la loro natura sequenziale se alcune condizioni risultano vere.
Prendiamo, per esempio, l'istruzione JB. Questa istruzione significa "Salta da una parte del programma se il Bit e' ad uno (Set)". Un esempio di questa istruzione potrebbe essere:
JB 45h,HELLO | |
NOP | |
HELLO: | .... |
Il branching condizionale e' realisticamente il blocco fondamentale della logica di programmazzione. Infatti ogni decisione nel flusso del codice coinvolge un branching condizionale. Esso puo' essere considerato come la struttura "IF...THEN" del linguaggio assembler dell'8051.
Una cosa importante vale la pena sottolineare circa il branching condizionale
e riguarda il fatto che il programma puo' saltare ad una locazione di memoria
collocata 128 byte prima o 127 byte dopo l'indirizzo dal quale inizia l'istruzione
di branch condizionale. Cio' significa che, nell'esempio precedente, la
label HELLO deve trovarsi nel range +/- 128 byte dal punto in cui risiede
l'istruzione di branching condizionale.
Anche se il branching condizionale e' estremamente importante, spesso e' necessario saltare direttamente ad una locazione di memoria senza necessariamente prendere alcuna decisione logica. Cio' equivale al "Goto" del BASIC. In questo caso volete che il programma continui a girare da un determinato indirizzo senza condizioni.
Cio' e' ottenuto nell'8051 usando le istruzioni "Direct Jump e Call". Come appena illustrato, la suite di istruzioni forza il flusso del programma a cambiare in maniera incondizionata.
Consideriamo il seguente esempio:
LJMP NEW_ADDRESS | |
. | |
. | |
. | |
NEW_ADDRESS: | .... |
L' ovvia differenza tra le istruzioni precedenti e il branching condizionale e' che nel primo caso il programma e' sempre costretto a saltare mentre nel secondo esso salta solo se la condizione richiesta risulta vera.
C'e' da ricordare che oltre a LJMP, ci sono altre due istruzioni che causano il salto diretto del programma e sono: SJMP e AJMP. Funzionalmente queste due istruzioni si comportano alla stessa maniera di LJMP ma differiscono come segue:
Ultimamente, ho scritto un programma di 2100 byte totali ma disponevo di una memoria di soli 2k (2048 byte). Sostituendo tutte le istruzioni LJMP con AJMP il programma si e' accorciato fino a diventare di 1950 byte. A questo punto, senza cambiare la logica nel mio programma, risparmiando 150 byte e' stato possibile far entrare il programma nei 2048 byte previsti.
NOTA: Alcuni assembler di qualita' effettuano la conversione automaticamente. Essi sostituiscono, cioe' le istruzioni LJMP con le SJMP laddove e' possibile.Questa e' una capacita' molto elegante e potente che vorreste vedere in un assembler se pensate di sviluppare molti progetti che hanno consistenti restrizioni di memoria.
Un'altra operazione che sara' familiare ai programmatori esperti e' l'istruzione LCALL. Essa e' simile al comando "Gosub" in BASIC.
Quando l'8051 esegue l'istruzione LCALL, pone immediatamente il contenuto
del Program Counter nello stack (operazione di push) e continua l'esecuzione
del codice all'indirizzo contenuto nell'istruzione LCALL.
Un'altra istruzione che puo' causare il cambio sul flusso di programma e' l'istruzione di "Ritorno da Subroutine", conosciuta come RET nel linguaggio assembler dell'8051.
L'istruzione RET, quando eseguita, fa tornare il programma all'indirizzo
che seguiva l'istruzione che aveva effettuato la chiamata a subroutine.
Piu' in dettaglio, esso ritorna all'indirizzo caricato nello stack.
L'istruzione RET e' diretta nel senso che cambia sempre il flusso del
programma senza condizioni, ma e' variabile poiche' dipende da quale subroutine
era stata chiamata originariamente.
Un interrupt e' una caratteristica speciale che permette all'8051 di fornire l'illusione del "multi-tasking" anche se esso esegue una sola istruzione alla volta. La parola "interrupt" puo' essere spesso sostituita con la parola "evento".
Un interrupt viene attivato quando il corrispondente evento si presenta. In questo caso, l'8051 congela momentaneamente la normale esecuzione del programma ed esegue una speciale sezione di codice denominata "interrupt handler". Questo spezzone di codice sbriga le funzioni richieste dall'evento e restituisce il controllo all'8051 dal punto in cui era stato fermato, in maniera tale che l'esecuzione del programma possa proseguire come se non fosse mai stato interrotto.
L'argomento degli interrupt e' qualcosa di complicato e molto importante.
Per questa ragione un intero capitolo sara' dedicato a questo tema. Per
ora, e' sufficiente dire che gli interrupt possono causare un cambio al
flusso del programma.