ITIS OMAR NOVARA
Programmazione microcontroller
Il software dei microcontroller della famiglia 8051
Note, suggerimenti, esempi, mappe e locazioni sulla programmazione e simulazione
Assegnazioni
pag. 2
Routines
3
Interruzioni
3
Pilotaggio del display a cristalli liquidi (LCD)
4
Conversione binario-BCD
5
Label (etichette)
6
Loop infinito
6
Interfacciamento di una tastiera esadecimale
6
Acquisizione dati tramite A/D converter
6
Fine programma
8
Note
8
--------------------------------------------------------------------------------------------------------------------------------Modi di indirizzamento
9
Istruzioni di trasferimento dati
10
Istruzioni artimetiche
11
Istruzioni di manipolazione di bit
11
Istruzioni logiche
12
Istruzioni di rotazione
12
Istruzioni di controllo
13
Nomi assembler e relativi indirizzi in RAM
14
Codice delle istruzioni
15
Tabella delle locazioni
16
----------------------------------------------------------------------------------------------------------------------------------Esempi di uso dei timer
17
precisione delle formule per il calcolo dei tempi
17
Routines di temporizzazione
17
temporizzazioni molto brevi (fino a 256 cicli macchina)
17
la temporizzazione viene richiesta una sola volta
17
la temporizzazione prosegue indefinitamente, a intervalli regolari
18
temporizzazioni fino a 65 mila cicli macchina
18
temporizzazioni per tempi fino a circa 13 secondi
19
temporizzazioni per tempi lunghi
20
----------------------------------------------------------------------------------------------------------------------------------Note sull’istruzione CJNE
21
----------------------------------------------------------------------------------------------------------------------------------Software di simulazione
22
Assemblatore CYS8051
23
direttive
25
Simulatore SIM8051
25
Modifiche dei dati durante l’esecuzione del programma
26
Finestra del codice
26
Finestra della memoria
26
Finestra del flusso
28
Formattazione del flusso
28
Simulazione degli interrupt esterni
29
G. Renolfi – P. Vittor
pag. 1
ITIS OMAR NOVARA
Programmazione microcontroller
Note e suggerimenti per la stesura del programma per il microcontroller 8751- 8951
Il programma può essere scritto con un comune editor di testo e deve essere salvato in formato DOS
ASCII, ovvero senza alcuna formattazione.
Assegnazioni
E’ consigliabile effettuare tutte le necessarie assegnazioni iniziali, utili sia per chi legge il
programma, sia per facilitare il lavoro degli stessi programmatori nel modificare il programma in un
secondo tempo.
Ad esempio, se leggo: “setb P2.3" per sapere quale funzione svolge tale pin e dove è collegato
devo andare a vedere lo schema elettrico ogni volta che incontro tale indicazione. Se invece assegno
a tale pin un’etichetta che ne indica la funzione o la destinazione, risparmio sicuramente tempo. Ad
esempio, l’etichetta “rs_lcd” mi ricorda la funzione svolta dal pin Register Select del display a cristalli
liquidi, oppure “eoc_adc” mi ricorda che si tratta del pin di End Of Conversion dell’A/D converter, e
così via.
Queste assegnazioni possono essere fatte con il comando bit dell’assemblatore; ad esempio:
rs_lcd
bit
P1.2
relè_motore bit
P2.7
flag_1
bit
00 (primo bit dell’indirizzo 20H - area indirizzabile a bit)
Sempre allo scopo di facilitare la memorizzazione della funzione svolta da particolari locazioni di
memoria, dei Port oppure di determinati valori si può usare il comando equ (o anche =):
parametri_iniz
equ 24H (oppure: = 24H)
costante_1
equ 55
(oppure: = 55)
lcd_port
equ P0
(oppure: = P0)
tasto_1
equ 00001010b (oppure = 00001010b)
valore_1
=
low(7D0H)
valore_2
=
high(7D0H)
increm_1
=
valore_1 + 1
somma_1
=
valore_1 + valore_2 + 30
diff_1
=
256 - valore_2
Altre assegnazioni possono essere fatte tramite valori; ad esempio:
variabile_1 byte 10H
Si consiglia di inserire (fra le righe di programma oppure in coda alle istruzioni) opportuni commenti,
che chiariscano (anche allo stesso programmatore!) la funzione di ciò che si sta facendo; tali
commenti debbono essere preceduti da un punto e virgola. Esempio:
;routine di pilotaggio del motore
mov
P0, A
setb
P1.2
;accendo il LED di segnalazione
Fatte le assegnazioni iniziali, il programma va iniziato con:
;%S ;(ovvero Start) il compilatore inizia ad assemblare da questo punto
G. Renolfi – P. Vittor
pag. 2
ITIS OMAR NOVARA
Programmazione microcontroller
Routines
E’ consigliabile inserire le varie routines all’inizio del programma vero e proprio, e ciò sia per
ritrovarle rapidamente, sia per evitare l’errore di eseguirle comunque, anche se non richieste.
Altrimenti bisognerebbe ricordarsi di far eseguire del salti prima di ciascuna di esse.
E’ ovvio che, se si scrivono all’inizio, il listato deve iniziare con un salto al programma principale.
La struttura generale del programma diviene quindi la seguente:
(assegnazioni iniziali)
;%S
sjmp inizio
label: (titolo delle varie routines)
[routines varie]
inizio: (programma principale)
;%E
End
Interruzioni
Poiché al sopraggiungere di un’interruzione il micro salta alla relativa locazione di risposta ed
esegue le istruzioni che vi ci trova, è necessario scrivere in questi indirizzi le istruzioni desiderate.
Come già detto per le routines, proprio allo scopo di non eseguire comunque queste istruzioni di
risposta all’interrupt durante la normale lettura del programma, è necessario scriverle all’inizio del
listato, dopo un salto al programma principale.
La routine di risposta all’interrupt deve essere preceduta dall’indicazione della relativa locazione, con il
comando ORG (Origin); ad esempio, per il primo interrupt (INT0):
org
03H
seguita dalle relative istruzioni (per un massimo di 8 byte, altrimenti si richiamano altre routine) e
conclusa da:
reti ;ritorno dall’interruzione
La struttura del programma diviene quindi la seguente:
(assegnazioni iniziali)
;%S
sjmp inizio
org 03H
(routine di risposta INT0)
reti
label: (routines di servizio)
inizio:
(programma principale)
Se la risposta all’interrupt richiede operazioni più complesse, occorre richiamare altre routines o
effettuare salti ad altre parti del programma, ricordandosi di concluderli con RETI (e bypassarli con dei
salti!).
G. Renolfi – P. Vittor
pag. 3
ITIS OMAR NOVARA
Programmazione microcontroller
Pilotaggio del display a cristalli liquidi (LCD)
Prima di inviare i caratteri al display, occorre inviare innanzitutto le necessarie istruzioni, utili al
fine di impostare le varie modalità operative dell’LCD. Per inviare le istruzioni all’LCD occorre
mandare a 0 il pin RS (Register Select), e quindi inviare il byte di configurazione. Ricordarsi che l’LCD
leggere il byte ricevuto solo in corrispondenza di una transizione 1 -> 0 del pin di Enable.
Per prima cosa occorre indicare all’LCD che inviamo istruzioni e dati su 8 bit, per cui la prima
istruzione sarà necessariamente quella denominata Function Set (vedi foglio tecnico dell’LCD). Come
avvisa il data-sheet, è consigliabile inviare due volte la stringa suddetta. In secondo luogo è
necessario inviare all’LCD il comando Display On/Off, seguito poi da Clear e Home, rispettando i
dovuti ritardi.
Per scrivere un singolo carattere sull’LCD si può fare così:
setb rs_lcd
;(solo per il primo carattere inviato)
setb en_lcd
mov p0,#01000001b
;carattere da visualizzare (es. lettera A)
(può anche essere scritta: mov p0,#’A’)
clr en_lcd
;lettura del dato da parte dell’LCD
lcall rit_40
;ritardo di 40 µsec (tempo di esecuzione dell’LCD)
Per scrivere invece una serie di caratteri è possibile operare in due modi: il primo è quello di
inviare i dati carattere per carattere, uno alla volta; il secondo modo (molto più sbrigativo e compatto)
è invece quello di definire l’intera stringa e poi di leggerne il contenuto con un ciclo che utilizza
l’istruzione MOVC per l’indirizzamento delle tabelle nell’area programmi.
La sequenza di comandi può essere strutturata così:
mess_1:
.....
scrittura:
ripeti:
fine:
display:
db ‘stringa 1', 00H
mov dptr,#mess_1
clr A
movc A,@A+dptr
jz fine
lcall display
inc dptr
sjmp ripeti
ret
setb rs_lcd
setb en_lcd
mov P0,A
clr en_lcd
lcall rit_40
ret
;”stringa 1" è il contenuto del messaggio da visualizzare
;”db” per il compilatore significa Define Byte
;lo “00" finale serve per indicare la fine della stringa
;copia in A il contenuto della memoria programmi con
;indirizzo A+DPTR
;esce da questa routine quando trova lo “0" di fine stringa
;routine di invio del singolo carattere all’LCD (vedi sotto)
;legge il carattere successivo della stringa
;modalità dati per l’LCD
;invio i dati dall’accumulatore al display
Tutte la sequenza di istruzioni ora vista può essere messa nella sezione routines, mentre nel
programma principale è sufficiente avviare la scrittura dei singoli messaggi; ad esempio:
scrivi_1:
mov dptr,#mess_1
lcall ripeti
;routine di scansione di DPTR e poi di invio dati all’LCD
ricordarsi di pulire il display prima di inviare una nuova scritta, altrimenti verrà scritta in coda alla
precedente (il controller dell’LCD incrementa automaticamente la locazione di scrittura).
Per scrivere un certo messaggio o un certo valore in una posizione diversa dalla coda della
scritta precedente o dal primo carattere dell’LCD (nel caso di utilizzo dell’istruzione di Clear Display) è
necessario utilizzare l’istruzione 1AAAAAAA, dove al posto delle A va scritta la locazione (ovvero
l’indirizzo) della posizione desiderata sul display, che va da 00 a 27H per la prima riga (40 caratteri) e
G. Renolfi – P. Vittor
pag. 4
ITIS OMAR NOVARA
Programmazione microcontroller
da 40H a 67H (da 64 a 104 decimali) per la seconda riga. Il valore binario corrispondente alla
posizione desiderata va scritto al posto delle A.
Esempio: se si vuole scrivere un certo valore numerico nella quinta posizione della seconda riga
(locazione 45H), è necessario utilizzare l’istruzione 11000100, dove i bit che seguono il primo 1 sono
l’equivalente binario di 45H ovvero di 68 decimale.
Conversione binario-BCD
Poiché ad ogni display si deve inviare solo una cifra alla volta, si pone il problema di rappresentare
valori numerici a più di una cifra, per i quali occorre quindi convertire innanzitutto i valori numerici da
binario a BCD, al fine di ricavare le singole cifre da visualizzare (centinaia, decine, unità, decimi, ecc.).
L’esempio indicato dalla routine seguente presuppone che il dato da convertire si trovi
nell’accumulatore:
assegnazioni:
cent:
dec:
uni:
bin_bcd:
mov B, #100
div AB
mov cent,A
mov a,#10
xch A,B
div AB
mov dec,A
mov A,B
mov uni,A
ret
ds 01 ;il comando Define Storage è dell’assemblatore
ds 01
ds 01
;il registro B viene usato come appoggio per l’acc.
Per convertire i valori numerici binari nei corrispondenti ASCII è possibile usare la seguente routine,
che presuppone che il dato da convertire sia presente nella parte bassa dell’accumulatore. Il
corrispondente valore ASCII viene restituito nell’accumulatore stesso.
hexascii:
numero:
ambo:
end:
anl A,#00001111b ;maschera i primi 4 bit
cjne A,#09,ambo
orl A,#00110000b ;add A,#30h, ovvero converte in ASCII
sjmp end
jc numero
add A,#37h
ret
Label
A proposito di label (etichette), ricordarsi che il compilatore segnala errore se le label iniziano con un
numero, oppure se hanno spazi o utilizzano segni quali * . + - ecc.
Ricordarsi di usare una label una volta sola.
G. Renolfi – P. Vittor
pag. 5
ITIS OMAR NOVARA
Programmazione microcontroller
Loop infinito
Per bloccare l’esecuzione del programma in un determinato punto (utile ad esempio per avere la
possibilità di verificare con il tester la combinazione dei livelli logici sui pin di un Port), è possibile
scrivere ad esempio:
loop:
sjmp
loop
Interfacciamento di una tastiera esadecimale
La tastiera è connessa al micro tramite 4 linee (mezzo Port) più una linea di Data Available gestita ad
esempio come interruzione da INT0. Occorre abilitare INT0 con SETB EA e SETB EX0, dopodiché
occorre effettuare il riconoscimento dei tasti:
org 03H
lcall tastiera
reti
;locazione di recupero dell’INT0
;routine di risposta
key_tab:
tastiera:
db ‘1234567890ABCDEF’
mov A,P2
anl A,#00001111b
mov dptr,#key_tab
movc A,@A+dptr
cjne A,#’1’,tasto_2
ljmp esegui_1
;creo la tabella dei tasti
;leggo il dato inviato dal decoder di tastiera
;maschero i bit che non arrivano dalla tastiera
;carico nel DPTR i 16 valori della tabella key_tab
;muovo in A il valore relativo al tasto premuto
;confronto i codici ricevuti
;routine di risposta al tasto “1”
tasto_2:
cjne A,#’2’, tasto_3
ljmp esegui_2
;routine di risposta al tasto “2”
...
...dopo tutta la scansione dei tasti ...
ret
;se nella routine posta in “org 03h” si usa un
;”ljmp tastiera” è (ovviamente!) necessario
;sostituire questo ”ret” con “reti”
Acquisizione dati tramite A/D converter
fatte le necessarie assegnazioni, conviene indicare sull’LCD il significato di ciò che poi verrà scritto;
ad esempio, se stiamo per indicare la temperatura, possiamo scrivere: “Temp =”, sapendo che i dati
che invieremo successivamente verranno automaticamente scritti di seguito.
ritardo:
polling:
setb soc
clr soc
mov port_adc,#0FFH
.....
jnb eoc,polling
mov A,port_adc
mov B,#51
div AB
mov 21h,A
mov A,#5
xch A,B
div AB
mov 22h,A
mov A,#2
G. Renolfi – P. Vittor
;avvio conversione
;predispone per la successiva conversione
;predispone il port dell’8951 in lettura
;ritardo per attendere il resettaggio di EOC
;polling per vedere se l’ADC ha finito
;si presuppone oe_adc sempre attivo
;leggo il dato convertito e lo pongo in A
;il fondo scala letto (FFH) va rapportato a 50°C,
;ovvero: 256:51 = 50°C (arrotondato)
;divido per 51 il valore ottenuto
;salvo le decine di °C nella locazione di Ram 21H
;le unità vengono rapportate a 5°C
;porto il resto (unità di gradi) da B ad A
;divido per 5 le unità di gradi
;salvo le unità di °C nella locazione 22H
;i decimi di °C vengono rapportati a 0.5 (=*2)
pag. 6
ITIS OMAR NOVARA
xch A,B
mul AB
mov 23h,A
mov A,21h
anl A,#00001111b
add A,#30h
lcall display
mov A,22h
anl A,#00001111b
add A,#30H
lcall display
lcall punto_dec
mov A,23h
anl A,#00001111b
add A,#30H
lcall display
Programmazione microcontroller
;porto il resto (decimi di °C) da B ad A
;moltiplico per 2 il resto per ottenere i decimi
;salvo i decimi di °C in 23H
;sposto le decine di °C nell’accumulatore
;maschero i primi 4 bit dell’acc.
;sommo 30H per convertire in ASCII
;analogo a scrivere -> ORL A,#00110000B
;chiamo la routine di invio delle decine all’LCD
;sposto le unità di °C nell’acc.
;maschero i primi 4 bit
;converto in ASCII (oppure -> orl A,#00110000b)
;invio dati all’LCD
;sposto i decimi di °C nell’acc.
;maschero i primi 4 bit
;converto in ASCII per l’LCD
;invio dati all’LCD
punto_dec: mov p2,#00101110b
;routine che scrive il punto decimale sull’LCD
setb en_lcd
;la riga precedente si può anche scrivere mov a,#’.’
clr en_lcd
lcall rit_40
Per non doversi ricordare che le locazioni di Ram 21h, 22h e 23h contengono rispettivamente le
decine, le unità e i decimi di grado, è possibile utilizzare una particolare istruzione dell’assembler,
ovvero DS (Define Storage) che riserva (a partire da una posizione specificata) il numero di byte
desiderati per l’impiego scelto; ad esempio:
adc_decine:
adc_unità:
adc_decimi:
org 0008
ds 01
ds 01
ds 01
;a partire dalla locazione di Ram 08
;1 byte riservato per le decine convertite
;1 byte per le unità convertite
;1 byte per i decimi
successivamente, i salvataggi possono essere scritti in maniera più comprensibile:
mov adc_decine,A
anziché
mov 21h,A
oppure:
mov A,adc_unità
anziché
mov A,21h
Tabelle di ricerca
E’ possibile sfruttare la modalità di indirizzamento indicizzato tramite l’istruzione MOVC al fine di
gestire delle tabelle all’interno della memoria programmi. Vediamo due esempi:
MOVC A,@A+DPTR
MOVC A,@A+PC
copia in A il dato puntato da (A+DPTR)
copia in Ail dato puntato da (A+PC)
I registri DPTR oppure PC fungono da puntatori alla “base” (inizio) della tabella nell’area programmi,
mentre l’accumulatore funge da puntatore all’interno della tabella, che può quindi accogliere fino ad un
massimo di 256 elementi (dati). Gli elementi contenuti nella tabella vengono così numerati da 1 a
255, mentre il numero 0 non può essere utilizzato poiché coincide con la posizione occupata
dall’istruzione RET (indirizzo contenuto nel PC durante l’esecuzione di MOVC) e quindi il valore
restituito dalla lettura della tabella sarebbe nient’altro che il codice operativo dell’istruzione RET. Un
esempio di utilizzo di questa tecnica è fornito dal sottoprogramma riportato a proposito della gestione
del display LCD.
G. Renolfi – P. Vittor
pag. 7
ITIS OMAR NOVARA
Programmazione microcontroller
Fine programma
Il programma va terminato con:
;%E
end
;fine della compilazione
;fine programma
Note
Si ricordi sempre che:
P2.0 è l’LSB (bit meno significativo), e P2.7 è l’MSB (bit più significativo)
G. Renolfi – P. Vittor
pag. 8
ITIS OMAR NOVARA
Programmazione microcontroller
Modi di indirizzamento
Indirizzamento IMMEDIATO: in alcune istruzioni il byte che segue il codice operativo rappresenta
direttamente il valore di una costante numerica, per cui il dato è contenuto nel codice operativo
stesso.
Esempio: MOV A,#30H (carica nell’accumulatore il valore esadecimale 30).
oppure: ADD A,#30H (il valore 30 esadecimale viene sommato all’accumulatore).
Indirizzamento DIRETTO: l’operando viene fornito mediante l’indirizzo di una locazione di memoria.
Questa modalità consente una maggior flessibilità rispetto alla precedente, in quanto il valore da
caricare è contenuto in un indirizzo di Ram e quindi può essere facilmente modificato sia via software
sia da una periferica esterna. Possono essere indirizzati direttamente solo i primi 128 byte della RAM
e i registri SFR.
Esempio: MOV A,30H (il contenuto della locazione 30H viene copiato nell’accumulatore)
oppure: ADD A,30H (il contenuto della locazione 30H viene sommato all’accumulatore).
Indirizzamento INDIRETTO: nell’istruzione viene specificato un registro che contiene l’indirizzo
dell’operando (registro puntatore). Tutta la RAM dati (esterna o interna, anche i 128 byte superiori il
cui indirizzo è sovrapposto all’area SFR) può essere indirizzata in questa modalità. I registri puntatori
possono essere R0 o R1 oppure lo Stack Pointer (per indirizzi a 8 bit), mentre per gli indirizzi a 16 bit
bisogna ricorrere al registro DPTR. La locazione puntata con questa modalità può essere relativa
esclusivamente all’area di Ram dati, e mai ad un registro SFR.
Esempio: MOV A,@R0 (copia nell’accumulatore il dato che si trova nell’indirizzo di RAM specificato
nel registro R0).
Indirizzamento a registro: alcune istruzioni possono accedere ai banchi di registri disponibili nella
parte bassa della RAM. Questo metodo permette di eliminare il byte del campo indirizzo.
Esempio: ADD A,R7 (il contenuto dell’accumulatore viene sommato al contenuto del registro R7).
Indirizzamento INDICIZZATO: tramite un registro a 16 bit (DPTR o il Program Counter) si punta
all’inizio di una tabella, e l’accumulatore viene usato come indice all’interno della tabella. L’indirizzo
effettivo viene ottenuto sommando al DPTR o al PC il contenuto dell’accumulatore. E’ possibile usare
questo metodo solo nella memoria programmi. Un altro tipo di indirizzamento indicizzato è
rappresentato dal “salto con selezione multipla”, dove l’indirizzo di salto viene calcolato sommando
alla base il contenuto dell’accumulatore.
Esempio: MOVC A, A + DPTR (mette in A il contenuto della locazione di memoria di programma
ricavata dalla somma di A + il contenuto del DPTR).
Indirizzamento implicito: alcune istruzioni sono specifiche di alcuni registri per cui nel codice
operativo è implicitamente specificato di quale registro si tratta.
G. Renolfi – P. Vittor
pag. 9
ITIS OMAR NOVARA
Programmazione microcontroller
Istruzioni di trasferimento dati
Codice mnemonico
n°byte
descrizione
cicli
MOV A,Rn
MOV A,direct
MOV A,@Ri
MOV A,#dato
MOV Rn,A
MOV Rn,direct
MOV Rn,#dato
MOV direct,A
MOV direct,Rn
MOV direct,@Ri
MOV direct,#dato
MOV DPTR,#dat16
MOV C,bit
MOV bit,C
MOV sorg,dest
MOV @Ri,A
MOV @Ri,direct
MOV @Ri,#dato
MOVC A,@A+DPTR
MOVC A,@A+PC
MOVX A,@Ri
MOVX A,@DPTR
MOVX @Ri,A
MOVX @DPTR,A
1
2
1
2
1
2
2
2
2
2
3
3
2
2
3
1
2
2
1
1
1
1
1
1
1
1
1
1
1
2
1
1
2
2
2
2
1
1
2
1
2
1
2
2
2
2
2
2
PUSH direct
POP direct
2
2
XCH A,direct
XCH A,Rn
XCH A,@Ri
XCHD A,@Ri
2
1
1
1
Copia in A il contenuto. del registro Rn
Copia in A il contenuto. della locazione direct
Copia in A il contenuto della locazione puntata da Ri
Copia in A il dato
Copia nel registro Rn il contenuto di A
Copia nel registro Rn il contenuto della locaz. direct
Copia nel registro Rn il dato
Copia nella locazione direct il contenuto di A
Copia nella locaz. direct il contenuto del registro Rn
Copia nella locazione direct il contenuto. della locazione puntata da Ri
Copia nella locazione direct il dato
Copia in DPTR un dato a 16 bit
Copia nel carry il bit di indirizzo bit
Copia il carry nell'indirizzo bit
Copia nella locaz. dest il contenuto della locaz. sorg
Copia nella locazione puntata da Ri il contenuto di A
Copia nella locazione puntata da Ri il contenuto. della locazione direct
Copia nella locazione puntata da Ri il dato
Copia in A il contenuto. della memoria programma di indirizzo DPTR + A
Copia in A il contenuto. della memoria programma di indirizzo PC + A +1
Copia in A il contenuto. della memoria dati esterna puntata da Ri
Copia in A il contenuto. della memoria dati esterna puntata da DPTR
Copia nella locazione di memoria dati esterna puntata da Ri il contenuto. di A
Copia nella locaz. di memoria dati esterna puntata da DPTR il contenuto. di A
e aumentalo Stack di una unità
Copia nella locazione puntata da SP il contenuto. della locazione direct
Copia nella locazione direct il contenuto della locazione puntata da SP e
diminuisce lo Stack di una unità
Scambia il conten. di A con quello della locaz. direct
Scambia il contenuto di A con quello del reg. Rn
Scambia il contenuto. di A con quello della locazione puntata da Ri
Scambia il nibble meno signif. di A con il più signif. della locaz. puntata da Ri
osservazione:
simboli usati:
Rn
Ri
direct
dato
dat16
indirizzo11
indirizzo16
rel
bit
G. Renolfi – P. Vittor
2
2
1
1
1
1
l’istruzione MOV Rn,Rm viene accettata dall’assembler come se fosse MOV
Rn,direct con direct=m, per cui l’istruzione apparentemente funziona se si lavora
nel banco 0, mentre indirizza in modo errato se si lavora negli altri banchi.
uno dei registri di uso generale, da R0 a R7
uno dei registri indice, R0 o R1
un byte di indirizzo della memoria dati interna
un dato di un byte
un dato di due byte
un indirizzo di 11 bit (viene indicato con un’etichetta)
un indirizzo di 16 bit (viene indicato con un’etichetta)
un byte che codifica un numero con segno in complemento a 2, quindi compreso
fra –128 e +127
un byte che indica un indirizzo dei bit indirizzabili individualmente
pag. 10
ITIS OMAR NOVARA
Programmazione microcontroller
Istruzioni aritmetiche
Codice mnemonico
ADD A,Rn
ADD A,direct
ADD A,@Ri
ADD A,#dato
ADDC A,Rn
ADDC A,direct
ADDC A,@Ri
ADDC A,#dato
SUBB A,Rn
SUBB A,direct
SUBB A,@Ri
SUBB A,#dato
INC A
INC Rn
INC direct
INC @Ri
INC DPTR
DEC A
DEC Rn
DEC direct
DEC @Ri
MUL AB
byte
1
2
1
2
1
2
1
2
1
2
1
2
1
1
2
1
1
1
1
2
1
1
Descrizione
Somma ad A il contenuto del registro Rn
Somma ad A il contenuto della locazione direct
Somma ad A il contenuto della locazione puntata da Ri
Somma ad A il dato (A <- A + dato)
Somma ad A il contenuto del registro Rn e il CY
Somma ad A il contenuto della locazione direct e il CY
Somma ad A il contenuto della locazione puntata da Ri e il CY
Somma ad A il dato e il CY (A <- A + dato + C)
Sottrae da A il contenuto del registro Rn e il CY
Sottrae da A il contenuto della locazione direct e il CY
Sottrae da A il contenuto della locazione puntata da Ri e il CY
Sottrae da A il dato e il CY
Aumenta di 1 il contenuto di A
Aumenta di 1 il contenuto del registro Rn
Aumenta di 1 il contenuto della locazione direct
Aumenta di 1 il contenuto della locaz. puntata da Ri
Aumenta di 1 il contenuto del registro DPTR
Diminuisce di 1 il contenuto di A
Diminuisce di 1 il contenuto del registro Rn
Diminuisce dI 1 il contenuto della locazione direct
Diminuisce di 1 il contenuto della locaz. puntata da Ri
Moltiplica il contenuto di A per quello di B; la parte bassa del risultato va
in A e la parte alta va in B
1 Divide il contenuto di A per B; il quoziente va in A e il resto in B
1 Realizza l'aggiustamento decimale del contenuto di A. Utilizzando la
rappresentazione in BCD le istruzioni ADD e ADDC debbono essere
seguite da DA: ciò assicura che il risultato sia ancora in BCD
DIV AB
DA A
cicli AC CY OV
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
b
b
b
1
1
1
1
1
1
1
1
1
4
0
b
4
1
-
0
0
0
0
Istruzioni di manipolazione di bit
Codice mnemonico
CLR C
CLR bit
SETB C
SETB bit
CPL C
CPL bit
ANL C,bit
ANL C,/bit
ORL C,bit
ORL C,/bit
byte
1
2
1
2
1
2
2
2
2
2
G. Renolfi – P. Vittor
Descrizione
azzera il flag CY
azzera il bit dell’indirizzo [bit]
pone a 1 il flag CY
pone a 1 il bit dell’indirizzo [bit]
inverte il flag CY
inverte il bit dell’indirizzo [bit]
AND logico fra CY e il bit dell’indirizzo [bit]
AND logico fra CY e la negazione del bit dell’indirizzo [bit]
OR logico fra CY e il bit dell’indirizzo [bit]
OR logico fra CY e la negazione del bit dell’indirizzo [bit]
cicli AC CY OV
1
0
1
1
1
1
1
b
1
2
b
2
b
2
b
2
b
pag. 11
ITIS OMAR NOVARA
Programmazione microcontroller
Istruzioni di logiche
Codice mnemonico
ANL A,Rn
ANL A,direct
ANL A,@Ri
ANL A,#dato
ANL direct,A
byte
1
2
1
2
2
ANL direct,#dato
3
ORL A,Rn
ORL A,direct
ORL A,@Ri
ORL A,#dato
ORL direct,A
1
2
1
2
2
ORL direct,#dato
3
XRL A,Rn
XRL A,direct
XRL A,@Ri
XRL A,#dato
XRL direct,A
1
2
1
2
2
XRL direct,#dato
3
CLR A
CPL A
1
1
Descrizione
cicli AC CY OV
AND logico tra A e il contenuto del registro Rn
1
AND logico tra A e il contenuto della locazione direct
1
AND logico tra A e il contenuto della locazione puntata da Ri
1
AND logico tra A e il dato
1
AND logico tra il contenuto della locazione direct e dell'ACC; il risultato 2
rimane nella locazione direct
AND logico tra il contenuto della locazione direct ed il dato; il risultato
1
rimane nella locazione direct
OR logico tra A e il contenuto del registro Rn
1
OR logico tra A e il contenuto della locazione direct
1
OR logico tra A e il contenuto della locazione puntata da Ri
1
OR logico tra A e il dato
1
OR logico tra il contenuto della locazione direct e dell'ACC; il risultato
1
rimane nella locazione direct
OR logico tra il contenuto della locazione direct ed il dato; il risultato
2
rimane nella locazione direct
EX-OR logico tra A e il contenuto del registro Rn
1
EX-OR logico tra A e il contenuto della locazione direct
1
EX-OR logico tra A e il contenuto della locazione puntata da Ri
1
EX-OR logico tra A e il dato
1
EX-OR logico tra il contenuto della locazione direct e A, il risultato
1
rimane nella locazione direct
EX-OR logico tra il contenuto della locazione direct e il dato, il risultato 2
rimane nella locazione direct
Azzera tutti i bit di A
1
Complementa a 1 (ovvero inverte) tutti i bit di A
1
Istruzioni di rotazione
Codice mnemonico
RL A
byte
Descrizione
1 ruota di un posto verso sinistra i bit di A
cicli
1
RLC A
1
ruota di un posto verso sinistra i bit di A con riporto al CY
1
RR A
1
Ruota di un posto verso destra i bit di A
1
RRC A
1
Ruota di un posto verso destra i bit di A con riporto al CY
1
SWAP A
1
scambia i due nibble dell’accumulatore
1
G. Renolfi – P. Vittor
pag. 12
ITIS OMAR NOVARA
Programmazione microcontroller
Istruzioni di controllo
Codice mnemonico
ACALL indirizzo11
LCALL indirizzo16
RET
RETI
AJMP indirizzo11
LJMP indirizzo16
SJMP rel
JMP @A+DPTR
JZ rel
JNZ rel
JC rel
JNC rel
JB bit,rel
JNB bit,rel
JBC bit,rel
CJNE A,direct,rel
byte
2
3
1
1
2
3
2
1
2
2
2
2
3
3
3
3
CJNE A,#dato,rel
3
CJNE Rn,#dato,rel
3
CJNE @Ri,#dato,rel
3
DJNZ Rn,rel
DJNZ direct,rel
2
3
NOP
1
Descrizione
cicli
manda in esecuzione una routine entro un segmento da 2K (solo in avanti)
2
manda in esecuzione una routine (anche fuori segmento, fino a ±32K)
2
termina l’esecuzione di una routine
2
termina l’esecuzione della routine di risposta ad un’interruzione
2
salta all’indirizzo specificato entro un segmento da 2K (solo in avanti)
2
salta all’indirizzo specificato (anche fuori segmento, fino a ±32K)
2
salta a [rel] posizioni successive del Program Counter (entro –128 e +127)
2
salta alla locazione di PC puntata da A + il contenuto del DPTR
2
salta alla locazione [rel] se il contenuto di A è uguale a zero
2
salta alla locazione [rel] se il contenuto di A è diverso da zero
2
salta alla locazione [rel] se il bit di CY vale 1
2
salta alla locazione [rel] se il bit di CY vale 0
2
salta alla locazione [rel] se il bit contenuto nell’indirizzo [bit] vale 1
2
salta alla locazione [rel] se il bit contenuto nell’indirizzo [bit] vale 0
2
salta alla locaz. [rel] se il bit contenuto nell’indirizzo [bit] vale 1, e poi lo azzera
2
salta alla locaz. [rel] se il contenuto di A è diverso da quello di [direct]; se A è
2
minore di [direct] pone CY=1, altrimenti CY=0
salta alla locaz. [rel] se il contenuto di A è diverso da quello di #dato; se A è
2
minore di #dato pone CY=1, altrimenti CY=0
salta alla locaz. [rel] se il contenuto di A è diverso da quello di Rn; se A è minore
2
di Rn pone CY=1, altrimenti CY=0
salta alla locaz. [rel] se il contenuto di A è diverso da quello della locazione
2
puntata da Ri; se A è minore della locaz. pone CY=1, altrimenti CY=0
Diminuisce di 1 il contenuto di Rn; se Rn non diventa 0, salta a [rel]
2
Diminuisce di 1 il contenuto della locazione [direct]; se il contenuto non diventa 0, 2
salta a [rel]
Nessuna operazione (ritardo di un ciclo macchina)
1
osservazioni:
1-
Le istruzioni ACALL e AJMP possono causare errori se sono scritte in una delle locazioni 0111
1111 1110 oppure 0111 1111 1111 (valori binari) poiché in tal caso durante la fase di fetch il bit
più significativo diventa 1 e l’indirizzo a 11 bit viene aggiunto ad un bit errato.
2-
Se il salto richiesto dal valore [rel] supera 127 locazioni in avanti o 128 indietro, l’assembler
genera un messaggio di errore; infatti REL viene tradotto con un numero di un solo byte. Se
sono richiesti salti più ampi occorre spezzarli in più salti o trovare un criterio alternativo.
3–
A proposito dell’istruzione CJNE primo,secondo,rel si osservi che:
se primo = secondo non viene effettuato il salto, e CY viene posto a 0
se primo > secondo il salto viene effettuato, e CY viene posto a 0
se primo < secondo il salto viene effettuato, e CY viene posto a 1
G. Renolfi – P. Vittor
pag. 13
ITIS OMAR NOVARA
Programmazione microcontroller
Nomi assembler e relativi indirizzi in RAM
BYTE
B I T
B
F0
ACC
E0
PSW
D0
IP
B8
P3
B0
IE
A8
P2
A0
SBUF
SCON
99
98
P1
90
TH1
TH0
TL1
TL0
TMOD
TCON
8D
8C
8B
8A
89
88
PCON
DPTH
DPTL
SP
P0
87
83
82
81
80
7F-00
2F-20
RAM
1F-18
UTENTE 17-10
0F-08
07-00
B.7
B.6
B.5
B.4
F7
F6
F5
F4
ACC.7 ACC.6 ACC.5 ACC.4
E7
E6
E5
E4
C
AC
F0
RS1
D7
D6
D5
D4
_
_
_
PS
BC
P3.7 P3.6 P3.5 P3.4
RD
WR
T1
T0
B7
B6
B5
B4
EA
_
_
ES
AF
AC
P2.7 P2.6 P2.5 P2.4
A7
A6
A5
A4
B.3
F3
ACC.3
E3
RS0
D3
PT1
BB
P3.3
INT1
B3
ET1
AB
P2.3
A3
B.2
B.1
B.0
F2
F1
F0
ACC.2 ACC.1 ACC.0
E2
E1
E0
OV
_
P
D2
D0
PX1
PT0
PX0
BA
B9
B8
P3.2 P3.1 P3.0
INT0
TXD
RXD
B2
B1
B0
EX1
ET0
EX0
AA
A9
A8
P2.2 P2.1 P2.0
A2
A1
A0
Indirizzabile solo in blocco
SM0
9F
P1.7
97
SM1
9E
P1.6
96
REN
9C
P1.4
94
Indirizzabile
Indirizzabile
Indirizzabile
Indirizzabile
M1
M0
GATE
TF1
8F
SMOD
SM2
9D
P1.5
95
TR1
8E
_
TF0
8D
_
TR0
8C
_
TB8
9B
P1.3
93
solo in
solo in
solo in
solo in
GATE
IE1
8B
GF1
RB8
9A
P1.2
92
TI
99
P1.1
91
RI
98
P1.0
90
M1
M0
IE0
89
PD
IT0
88
IDL
P0.1
81
P0.0
80
blocco
blocco
blocco
blocco
IT1
8A
GF0
Indirizzabile solo in blocco
Indirizzabile solo in blocco
Indirizzabile solo in blocco
P0.7
87
P0.6
86
P0.5
85
P0.4
84
P0.3
83
P0.2
82
Indirizzabile comunque a livello di byte
Indirizzabile anche a livello di bit (indirizzi da 127 a 0)
Registri di uso generale, da R7 a R0 (banco 3)
Registri di uso generale, da R7 a R0 (banco 2)
Registri di uso generale, da R7 a R0 (banco 1)
Registri di uso generale, da R7 a R0 (banco 0)
solo le scritte in grassetto sono riferite a nomi assembler; gli indirizzi sono in esadecimale
G. Renolfi – P. Vittor
pag. 14
ITIS OMAR NOVARA
codice
oggetto
00
01 11
02 AD 16
03
04
05 56
06
07
08
09
0A
0B
0C
0D
0E
0F
10 1B 15
11 11
12AD 16
13
14
15 56
16
17
18
19
1A
1B
1C
1D
1E
1F
20 1B 1B
21 11
22
23
24 41
25 56
26
27
28
29
2A
2B
2C
2D
2E
2F
30 1B 18
31 11
32
codice
mnemonico
NOP
AJMP 0011H
LJMP addr16
RR A
INC A
INC direct
INC @R0
INC @R1
INC R0
INC R1
INC R2
INC R3
INC R4
INC R5
INC R6
INC R7
JBC bit,rel
ACALL 0011H
LCALL addr16
RRC A
DEC A
DEC direct
DEC @R0
DEC @R1
DEC R0
DEC R1
DEC R2
DEC R3
DEC R4
DEC R5
DEC R6
DEC R7
JB bit,rel
AJMP 0111H
RET
RL A
ADD A,#dato
ADD A,direct
ADD A,@R0
ADD A,@R1
ADD A,R0
ADD A,R1
ADD A,R2
ADD A,R3
ADD A,R4
ADD A,R5
ADD A,R6
ADD A,R7
JNB bit,rel
ACALL 0111H
RETI
codice
oggetto
33
34 41
36
37
38
39
3A
3B
3C
3D
3E
3F
40 20
41 11
42 56
43 56 41
44 41
45 56
46
47
48
49
4A
4B
4C
4D
4E
4F
50 1E
51 11
52 56
53 56 41
54 41
55 56
56
57
58
59
5A
5B
5C
5D
5E
5F
60 24
61 11
62 56
63 56 41
64 41
65 56
66
Programmazione microcontroller
codice
mnemonico
RLC A
ADDC A,#dato
ADDC A,@R0
ADDC A,@R1
ADDC A,R0
ADDC A,R1
ADDC A,R2
ADDC A,R3
ADDC A,R4
ADDC A,R5
ADDC A,R6
ADDC A,R7
JC rel
AJMP 0211H
ORL direct,A
ORL direct,#dato
ORL A,#dato
ORL A,direct
ORL A,@R0
ORL A,@R1
ORL A,R0
ORL A,R1
ORL A,R2
ORL A,R3
ORL A,R4
ORL A,R5
ORL A,R6
ORL A,R7
JNC rel
ACALL 0211H
ANL direct,A
ANL direct,#dato
ANL A,#dato
ANL A,direct
ANL A,@R0
ANL A,@R1
ANL A,R0
ANL A,R1
ANL A,R2
ANL A,R3
ANL A,R4
ANL A,R5
ANL A,R6
ANL A,R7
JZ rel
AJMP 0311H
XRL direct,A
XRL direct,#dato
XRL A,#dato
XRL A,direct
XRL A,@R0
codice
oggetto
67
68
69
6A
6B
6C
6D
6E
6F
70 22
71 11
72 1B
73
74 41
75 56 41
76 41
77 41
78 41
79 41
7A 41
7B 41
7C 41
7D 41
7E 41
7F 41
80 27
81 11
82 1B
83
84
85 2E 50
86 56
87 56
88 56
89 56
8A 56
8B 56
8C 56
8D 56
8E 56
8F 56
90 42 41
91 11
92 71
93
94 41
95 56
96
97
98
99
codice mnemonico
codice
oggetto
XRL A,@R1
9A
XRL A,R0
9B
XRL A,R1
9C
XRL A,R2
9D
XRL A,R3
9E
XRL A,R4
9F
XRL A,R5
A0 1B
XRL A,R6
A1 11
XRL A,R7
A2 71
JNZ rel
A3
ACALL 0311H
A4
ORL C,bit
A6 56
JMP @A+DPTR
A7 56
MOV A,#dato
A8 56
MOV direct,#dato
A9 56
MOV @R0,#dato
AA 56
MOV @R1,#dato
AB 56
MOV R0,#dato
AC 56
MOV R1,#dato
AD 56
MOV R2,#dato
AE 56
MOV R3,#dato
AF 56
MOV R4,#dato
B0 1B
MOV R5,#dato
B1 11
MOV R6,#dato
B2 1B
MOV R7,#dato
B3
SJMP rel
B4 41 0F
AJMP 0411H
B5 56 12
ANL C,bit
B6 41 EE
MOVC A,@A+PC B6 41 F1
DIV AB
B8 41 03
MOV 50H,2EH
B8 41 0C
MOV direct,@R0
B9 41 09
MOV direct,@R1
BA 41 06
MOV direct,R0
BB 41 00
MOV direct,R1
BC 41 FD
MOV direct,R2
BD 41 FA
MOV direct,R3
BE 41 F7
MOV direct,R4
BF 41 F4
MOV direct,R5
C0 56
MOV direct,R6
C1 11
MOV direct,R7
C2 1B
MOV DPTR,#dato16 C3
ACALL 0411H
C4
MOV 71H,C
C5 56
MOVC A,@A+DPTR C6
SUBB A,#dato
C7
SUBB A,direct
C8
SUBB A,@R0
C9
SUBB A,@R1
CA
SUBB A,R0
CB
SUBB A,R1
CC
codice mnemonico
SUBB A,R2
SUBB A,R3
SUBB A,R4
SUBB A,R5
SUBB A,R6
SUBB A,R7
ORL C,/bit
AJMP 0511H
MOV C,71H
INC DPTR
MUL AB
MOV @R0,direct
MOV @R1,direct
MOV R0,direct
MOV R1,direct
MOV R2,direct
MOV R3,direct
MOV R4,direct
MOV R5,direct
MOV R6,direct
MOV R7,direct
ANL C,/bit
ACALL 0511H
CPL bit
CPL C
CJNE A,#dato,rel
CJNE A,direct,rel
CJNE @R0,#dato,rel
CJNE @R0,#dato,rel
CJNE R0,#dato,rel
CJNE R0,#dato,rel
CJNE R1,#dato,rel
CJNE R2,#dato,rel
CJNE R3,#dato,rel
CJNE R4,#dato,rel
CJNE R5,#dato,rel
CJNE R6,#dato,rel
CJNE R7,#dato,rel
PUSH direct
AJMP 0611H
CLR bit
CLR C
SWAP A
XCH A,direct
XCH A,@R0
XCH A,@R1
XCH A,R0
XCH A,R1
XCH A,R2
XCH A,R3
XCH A,R4
codice
oggetto
CD
CE
CF
D0 56
D1 11
D2 1B
D3
D4
D5 56 DB
D6
D7
D8 EC
D9 EA
DA E8
DB E6
DC E4
DD E2
DE E0
DF DE
E0
E1 11
E2
E3
E4
E5 56
E6
E7
E8
E9
EA
EB
EC
ED
EE
EF
F0
F1 11
F2
F3
F4
F5 56
F6
F7
F8
F9
FA
FB
FC
FD
FE
FF
codice mnemonico
XCH A,R5
XCH A,R6
XCH A,R7
POP direct
ACALL 0611H
SETB bit
SETB C
DA A
DJNZ direct,rel
XCHD A,@R0
XCHD A,@R1
DJNZ R0,rel
DJNZ R1,rel
DJNZ R2,rel
DJNZ R3,rel
DJNZ R4,rel
DJNZ R5,rel
DJNZ R6,rel
DJNZ R7,rel
MOVX A,@DPTR
AJMP 0711H
MOVX A,@R0
MOVX A,@R1
CLR A
MOV A,direct
MOV A,@R0
MOV A,@R1
MOV A,R0
MOV A,R1
MOV A,R2
MOV A,R3
MOV A,R4
MOV A,R5
MOV A,R6
MOV A,R7
MOVX @DPTR,A
ACALL 0711H
MOVX @R0,A
MOVX @R1,A
CPL A
MOV direct,A
MOV @R0,A
MOV @R1,A
MOV R0,A
MOV R1,A
MOV R2,A
MOV R3,A
MOV R4,A
MOV R5,A
MOV R6,A
MOV R7,A
rel può essere qualsiasi byte da 00H a FFH; viene interpretato come numero con segno da –128 a +127
G. Renolfi – P. Vittor
pag. 15
ITIS OMAR NOVARA
Programmazione microcontroller
Tabella delle locazioni dell’8751
indiri
zzi
R0
R1
R2
R3
R4
R5
R6
R7
20H
21H
22H
23H
24H
25H
26H
27H
28H
29H
2AH
2BH
2CH
2DH
2EH
2FH
BANCHI DEI REGISTRI
Banco 0
00H
01H
02H
03H
04H
05H
06H
07H
00H
08H
10H
18H
20H
28H
30H
38H
40H
48H
50H
58H
60H
68H
70H
78H
30H
31H
32H
33H
34H
35H
36H
37H
38H
39H
3AH
3BH
3CH
3DH
3EH
3FH
G. Renolfi – P. Vittor
Banco 1
08H
09H
0AH
0BH
0CH
0DH
0EH
0FH
Banco 2
10H
11H
12H
13H
14H
15H
16H
17H
01H
09H
11H
19H
21H
29H
31H
39H
41H
49H
51H
59H
61H
69H
71H
79H
AREA INDIRIZZABILE A BIT
02H
03H
04H
05H
0AH
0BH
0CH
0DH
12H
13H
14H
15H
1AH
1BH
1CH
1DH
22H
23H
24H
25H
2AH
2BH
2CH
2DH
32H
33H
34H
35H
3AH
3BH
3CH
3DH
42H
43H
44H
45H
4AH
4BH
4CH
4DH
52H
53H
54H
55H
5AH
5BH
5CH
5DH
62H
63H
64H
65H
6AH
6BH
6CH
6DH
72H
73H
74H
75H
7AH
7BH
7CH
7DH
40H
41H
42H
43H
44H
45H
46H
47H
48H
49H
4AH
4BH
4CH
4DH
4EH
4FH
AREA INDIRIZZABILE A BYTES
50H
60H
51H
61H
52H
62H
53H
63H
54H
64H
55H
65H
56H
66H
57H
67H
58H
68H
59H
69H
5AH
6AH
5BH
6BH
5CH
6CH
5DH
6DH
5EH
6EH
5FH
6FH
Banco 3
18H
19H
1AH
1BH
1CH
1DH
1EH
1FH
06H
0EH
16H
1EH
26H
2EH
36H
3EH
46H
4EH
56H
5EH
66H
6EH
76H
7EH
07H
0FH
17H
1FH
27H
2FH
37H
3FH
47H
4FH
57H
5FH
67H
6FH
77H
7FH
70H
71H
72H
73H
74H
75H
76H
77H
78H
79H
7AH
7BH
7CH
7DH
7EH
7FH
pag. 16
ITIS OMAR NOVARA
Programmazione microcontroller
ESEMPI DI USO DEI TIMER DELL’8751
Occorre tenere presente che i Timer sono incrementati ogni ciclo macchina e pertanto,
supponendo frequenza di clock = 12 MHz, la cadenza di conteggio risulta essere 1 µsec.
Se servono tempi piuttosto lunghi, è possibile ottenerli in due modi diversi:
I.
Via software, conteggiando in un registro le interruzioni richieste, e confrontando il valore
memorizzato nel registro con il valore desiderato
II.
Via hardware, usando il timer come contatore di impulsi esterni, e collegando il piedino Tx con
una sorgente di clock con una frequenza più bassa.
Gli esempi che seguono azionano una specie di sveglia, che dopo un intervallo di tempo prestabilito
interrompe temporaneamente un programma che la CPU sta eseguendo, forza la CPU ad effettuare
altre operazioni e poi torna al programma interrotto.
In questi esempi sono previste due possibilità:
1) La temporizzazione viene richiesta una volta sola
2) La temporizzazione prosegue indefinitamente, ad intervalli regolari
Bisogna poi distinguere il caso delle temporizzazioni molto brevi (fino a 256 µsec con clock di
12 MHz), per le quali conviene usare il modo 2 (conteggio a 8 bit con possibilità di ricaricamento
automatico), da quelle più lunghe, per le quali può essere più conveniente il modo 1 con conteggio a
16 bit.
Precisione delle formule per il calcolo dei tempi
La risposta alla richiesta di interrupt proveniente dal timer parte con tre cicli-macchina di ritardo
rispetto al tempo in cui avviene l’overflow dei timer. Infatti TFx è testato il ciclo successivo a quello in
cui viene settato; il salto alla locazione di risposta, con salvataggio nello stack della locazione di
ritorno e aggiornamento dello stack pointer, richiede altri due cicli.
Nel modo 2 il ricaricamento automatico di TLx, tuttavia, avviene nello stesso ciclo in cui avviene il
traboccamento, per cui il nuovo conteggio riparte già prima che parta la routine di risposta, e l’errore di
tre cicli è limitato alla prima chiamata dopo il settaggio di TRx.
Nel modo 1, invece, la routine di risposta parte quando il timer segna già 0003, ed occorrono altri due
cicli per ricaricare thx e due per TLx, per cui il conteggio partirà da
quando sono già
trascorsi 7 cicli dal settaggio di TRx.
Inoltre la risposta all’interrupt non parte prima di aver completato l’istruzione in corso, e quindi vi è un
altro tempo di ritardo se la richiesta è pronta per essere accolta nel primo ciclo di un’istruzione che ne
impiega due (peggio ancora nel caso di MUL e DIV che durano 4 cicli-macchina).
Ultima considerazione: le correzioni precedenti in genere riguardano errori che possono essere
inferiori a quelli dovuti ai limiti di precisione della frequenza del clock, e quindi possono essere
superflue.
Routines di temporizzazione
Temporizzazioni molto brevi (fino a 256 cicli-macchina)
1) La temporizzazione viene richiesta una volta sola
In questo esempio, Numero è definito con la pseudoistruzione EQU ed è calcolato con la formula
Numero = 259 – (td · fclk) / 12
Dove td è il tempo di ritardo desiderato e fclk è la frequenza di clock del sistema.
;%s
sjmp inizia
org 0BH
G. Renolfi – P. Vittor
; routine di risposta all'overflow di Timer0
pag. 17
ITIS OMAR NOVARA
clr TR0
.............
reti
inizia:
mov TMOD,#2
mov TL0,#Numero
setb EA
setb ET0
main:
.............
setb TR0
.............
;%e
end
Programmazione microcontroller
; blocca la “sveglia”
; esegue le operazioni richieste dopo la temporizzazione
; inizializzazione e partenza del timer
; Timer0 in modo 2
; "carica la sveglia" per il tempo voluto
; TH0 non viene usato
; abilitazione generale delle interruzioni
; abilitazione dell'interrupt chiesto da Timer0
; programma principale
; prima parte del programma principale
; parte la "sveglia"
; proseguimento del programma principale
2) La temporizzazione prosegue indefinitamente, ad intervalli regolari
In questo esempio, Numero è calcolato con la formula:
Numero = 256 – (td · fclk) / 12
Dove td è il tempo di ritardo desiderato ed fclk è la frequenza di clock del sistema
Si noti che la prima routine di risposta partirà con un ritardo di 3 cicli-macchina rispetto al valore di td
;%s
sjmp inizia
org 0BH
.............
reti
inizia:
mov TMOD,#2
mov TL0,#Numero
mov TH0,#Numero
setb EA
setb ET0
setb TR0
; posizione della routine di risposta all'overflow di Timer0
; esegue le operazioni richieste dopo la temporizzazione
; inizializzazione e partenza del timer
; Timer0 in modo 2
; "carica la sveglia" per il tempo voluto
; TH0 ricaricherà automaticamente TL0
; abilitazione generale delle interruzioni
; abilitazione dell'interrupt chiesto da Timer0
; parte la "sveglia"
MAIN:
.............
.............
;%e
end
; esegue il programma principale
Temporizzazioni fino a 65536 cicli-macchina
Negli esempi seguenti, NH e NL sono definiti dalla formula:
t = 65543 – (256 · NH + NL) cicli-macchina
in cui NH ed NL si calcolano nel modo seguente:
Posto:
N = 65543 – (td · fclk) / 12
Dove td è il tempo di ritardo desiderato ed fclk è la frequenza di clock del sistema
NH = N / 256
NL = resto della divisione presedente
Con il clock di 12 MHz, con la routine seguente si può arrivare fino a circa 65 msec (Tale valore può
essere aumentato usando con un quarzo di frequenza più bassa). In questo modello la
temporizzazione prosegue indefinitamente, ad intervalli regolari
G. Renolfi – P. Vittor
pag. 18
ITIS OMAR NOVARA
;%s
sjmp Inizia
org 0BH
mov TL0,#NL
mov TH0,#NH
.............
reti
Programmazione microcontroller
; routine di risposta all'overflow di Timer0
; "ricarica la sveglia"
; esegue le operazioni richieste dopo la temporizzazione
inizia:
mov TMOD,#1
mov TL0,#NL
mov TH0,#NH
setb EA
setb ET0
setb TR0
; Inizializzazione e partenza del timer
; Timer0 in modo 1
; "carica la sveglia" per il tempo voluto
; abilitazione generale delle interruzioni
; abilitazione dell'interrupt chiesto da Timer0
; parte la "sveglia"
MAIN:
.............
;%e
end
; esegue il programma principale
Temporizzazioni per tempi fino a circa 13 sec.
Negli esempi seguenti, NR, NH e NL sono definiti dalle formule seguenti:
t = NR · [65543 – (256 · NH + NL)] cicli macchina
N.B.
Con:
NR = 0 si comporta come se fosse NR = 256
NH = 60 ed NL = 183 si ottiene t = NR · 50 msec con frequenza di clock di 12 MHz
Calcolando comunque NH ed NL in modo da ottenere, con le formule della routine precedente: td =
50 msec abbiamo, con t espresso in secondi: NR = 20 · t
In questo modello la temporizzazione prosegue indefinitamente, ad intervalli regolari
;%s
sjmp Inizia
org 0BH
mov TL0,#NL
mov TH0,#NH
djnz R7, Torna
.............
mov R7,#NR
TORNA:
inizia:
; routine di risposta all'overflow di Timer0
; "ricarica la sveglia"
; le operazioni di risposta sono effettuate solo se
; sono già trascorsi NR volte
; (65536 - 256 x NH - NL) cicli-macchina
; esegue le operazioni richieste dopo la temporizzazione
; R7 è usato per contare quante volte viene eseguito il ciclo
; temporizzato dal registro a 16 bit TH0 -TL0
reti
mov TMOD,#1
mov TL0,#NL
mov TH0,#NH
mov R7,#NR
setb EA
setb ET0
setb TR0
; inizializzazione e partenza del timer
; Timer0 in modo 1
; "carica la sveglia" per il tempo voluto
; abilitazione generale delle interruzioni
; abilitazione dell'interrupt chiesto da Timer0
; parte la "sveglia"
MAIN:
.............
;%e
end
G. Renolfi – P. Vittor
; esegue il programma principale
pag. 19
ITIS OMAR NOVARA
Programmazione microcontroller
Temporizzazioni per tempi lunghi.
NR, NH e NL sono definiti dalla formula:
t = NR1 · NR2 · [65536 – (256 · NH + NL)] cicli-macchina
N.B. NR1 = 0, NR2 = 0 si comportano come se fossero: NR1 = 256, NR2 = 256
Calcolando comunque NH ed NL in modo da ottenere, con le formule della routine precedente: td =
50 msec abbiamo, con t espresso in secondi: NR = 20 · t
Si possono ottenere tempi fino a più di un’ora. Con:
NR1 = 20
NR2 = 60
NR1 = 200
NR2 = 60
NR1 = 200
NR2 = 180
Calcolando NH ed NR per td = 60 msec, con NR1 = 234, NR2 = 96
t = 1 minuto
t = 10 minuti
t = 30 minuti
t = 1 ora
In questo modello la temporizzazione prosegue indefinitamente, ad intervalli regolari
;%s
sjmp Inizia
org 0BH
mov TL0,#NL
mov TH0,#NH
djnz R7, Torna
mov R7,#NR1
djnz R6, Torna
.............
torna:
inizia:
; routine di risposta all'overflow di Timer0
; "ricarica la sveglia"
; esegue le operazioni richieste dopo la
; temporizzazione
mov R7,#NR1
mov R6,#NR2
reti
mov TMOD,#1
mov TL0,#NL
mov TH0,#NH
mov R7,#NR1
mov R6,#NR2
setb EA
setb ET0
setb TR0
; inizializzazione e partenza del timer
; Timer0 in modo 1
; "carica la sveglia" per il tempo voluto
; abilitazione generale delle interruzioni
; abilitazione dell'interrupt chiesto da Timer0
; parte la "sveglia"
MAIN:
.............
;%e
end
G. Renolfi – P. Vittor
; esegue il programma principale
pag. 20
ITIS OMAR NOVARA
Programmazione microcontroller
Note sull’istruzione CJNE
Nella famiglia 8051, CJNE è l’unica istruzione che permette di effettuare il confronto fra due valori.
CJNE significa “Compare and Jump if Not Equal” cioè “confronta e salta se non è uguale”.
Generalmente, nei microprocessori “confrontare” due termini significa eseguire la loro sottrazione, ma
non mostrarne il risultato. L’unico effetto rimane l’azione sui flag, che vengono modificati in accordo
con le conseguenze che sarebbero scaturite dalla sottrazione vera e propria.
Sotto questo aspetto, l’8051 con CJNE si comporta in modo parzialmente anomalo. Il flag di Carry
viene resettato se il primo termine del confronto è maggiore o uguale al secondo, settato se è minore,
indicando così che la sottrazione è stata effettuata prendendo un “prestito”. Invece non esiste un flag
di “zero”, per cui i due termini vengono confrontati direttamente.
La sintassi è: CJNE primo_termine, secondo_termine, label
Il microprocessore confronta direttamente i due
termini, bit per bit e, se non sono uguali, somma
al Program Counter un numero di 1 byte. Ne
risulta che il massimo salto che può essere
eseguito è di 127 locazioni in avanti e 128
indietro.
Vediamo nella figura a fianco il diagramma di
flusso delle operazioni eseguite; per compattare
il disegno, primo_termine è stato indicato con
P, secondo_termine con S. P può essere il
contenuto dell’accumulatore, ed allora S può
essere qualsiasi byte od il contenuto di qualsiasi
locazione della RAM interna. P può anche
essere il contenuto di uno degli otto registri o di
una locazione puntata da uno dei due registri
indice, ed allora il confronto è possibile solo con
un dato numerico del tipo #byte.
L’istruzione genera comunque un salto se i due
termini di confronto sono diversi. Se interessa invece che il salto venga eseguito quando uno dei due
termini è maggiore o minore dell’altro, occorre ricorrere anche ad un ulteriore salto condizionato dal
Carry, usando l’istruzione JC oppure JNC. Vediamo un elenco dei casi possibili:
1) Salta se il primo termine P è diverso dal
secondo termine S. Si tratta del caso più banale,
e si traduce in una sola riga:
CJNE P,S,label
Prosegui (istruzione seguente)
2) Salta se P è uguale a S. Il codice può
essere:
CJNE P,S,avanti
SJMP label
avanti:
Prosegui (istruzione seguente)
G. Renolfi – P. Vittor
pag. 21
ITIS OMAR NOVARA
Programmazione microcontroller
3) Salta se P è maggiore di S
CJNE P,S,etich
SJMP avanti
etich:
JNC label
avanti:
Prosegui (istruzione seguente)
4) Salta se P è minore di S
CJNE P,S,etich
etich:
JC label
Prosegui (istruzione seguente)
5) Salta se P è minore o uguale a S
CJNE P,S,etich
SJMP label
etich:
JC label
Prosegui (istruzione seguente)
6) Salta se P è maggiore o uguale a S
CJNE P,S,etich
etich: JNC label
Prosegui (istruzione seguente)
SOFTWARE DI SIMULAZIONE
1) l’assemblatore CYS8051 è un software che gira su sistemi MS DOS e permette di sviluppare ed
assemblare programmi per la famiglia 8051 partendo da un file nomefile.ASM scritto in linguaggio
assembly e memorizzato in codice ASCII puro (testo non formattato).
2) il simulatore SIM8051 è un software che gira su sistemi MS DOS e permette di utilizzare i
corrispondenti file nomefile.HEX e nomefile.LST creati dal CYS8051.
Il file nomefile.HEX viene utilizzato per simulare l'esecuzione di un programma in codicemacchina dell'8051. Il relativo file nomefile.LST viene utilizzato per visualizzare le istruzioni durante la
loro esecuzione e l'eventuale diagramma di flusso. Poiché la rappresentazione è combinata in
un'unica visualizzazione con tre finestre, si ottiene un potente sistema di debug, senza dover uscire ed
utilizzare un circuito di emulazione.
G. Renolfi – P. Vittor
pag. 22
ITIS OMAR NOVARA
Programmazione microcontroller
Elenco dei registri
visualizzati:
SP
Stack pointer
BS Banco di registri
selezionato
R0..R7
Registri del
banco selezionato
P0....P3 Porte di I/O
CC Contatore di cicli
C0..C2
Contatori/temporizzatori
PC Program counter
PD Puntatore di dati
AC Accumulatore
PS Registro della parola di
stato
ASSEMBLATORE CYS8051
Se si vuole assemblare un proprio file nomefile.ASM, questo deve essere già scritto e salvato
prima di lanciare il programma assemblatore. Il file sorgente deve essere in codice ASCII puro; per
scriverlo si può usare il Blocco Note di Windows o l’editor del DOS. Se si usa invece un word
processor, occorre salvare il file in formato ASCII, altrimenti verrebbero aggiunti codici di controllo
particolari che l'assemblatore non è in grado di riconoscere.
Subito dopo il lancio appare una schermata con l'elenco dei comandi. Tale schermata è la
stessa che si ottiene col comando HELP. Il prompt del programma è rappresentato dal simbolo > in
fondo allo schermo. Quando questo è presente vuol dire che il programma è pronto ad accettare un
comando. Il comando per assemblare è ASM51 nomefile.
L'assemblatore genera altri due file: nomefile.HEX e nomefile.LST.
nomefile.HEX è il vero e proprio codice-oggetto INTEL, in formato esadecimale; e viene usato dal
SIM8051 per effettuare la simulazione. Può anche essere stampato e soprattutto utilizzato per
programmare il microcontroller.
nomefile.LST è un listato del sorgente unito ai codici macchina esadecimali, che mostra tutte le
locazioni ed i valori delle etichette. Può essere stampato ed usato come documentazione. Viene
utilizzato dal simulatore SIM8051 per visualizzare, durante l'esecuzione, i codici sorgente ed il
diagramma di flusso.
Per uscire dal programma e tornare al DOS, usare il comando EXIT.
Formato del file sorgente (nomefile.ASM)
Ciascuna linea del file sorgente sarà considerata un comando, e l'assemblatore tenterà di
tradurla. Oltre alle linee di codice di istruzioni 8051, possono esistere linee vuote di soli commenti, di
direttive (comandi) per l'assemblatore, che non producono però codice-oggetto.
Il formato generale di ciascuna linea, divisa in quattro campi, è il seguente:
Etichetta
Comando
Argomenti ;Commenti
Ad esempio:
Label: MOV R5,P1 ;Copia nel registro R5 il dato proveniente dalla porta P1
Alcuni dei quattro campi sopra indicati (o anche tutti) possono mancare, per cui vi possono
essere righe bianche (o di solo commento o di solo codice) senza etichetta e senza commento.
Ciascuna linea deve terminare con un codice di "ritorno-carrello (invio)" seguito da uno di "una linea in
G. Renolfi – P. Vittor
pag. 23
ITIS OMAR NOVARA
Programmazione microcontroller
basso", cosa che producono automaticamente i vari editor di testo quando si preme il tasto di “invio”.
Il numero di spazi (o di tabulazioni) fra i campi è libero, per cui si può incolonnare o indentare come si
preferisce. La massima lunghezza della linea è di 80 caratteri.
Primo campo (etichetta):
Il valore numerico che sarà assegnato all'etichetta è l'indirizzo del codice della stessa linea.
Le etichette possono essere lunghe quanto si vuole, ma non devono contenere caratteri di spazio o
altri usati come delimitatori od operatori aritmetici; devono iniziare con un carattere alfabetico e
terminare con ":" (due punti).
Quando sono utilizzate nel campo Argomenti, i "due punti" non devono essere scritti.
Secondo campo (codici delle istruzioni):
Vi sono i codici mnemonici delle istruzioni dell'8051, come ad esempio MOV o INC.
In alternativa, vi possono essere direttive per l'assemblatore; esse non producono codice-macchina,
ma dicono solo all'assemblatore come deve lavorare, o definiscono simboli (valori numerici) che
verranno usati in seguito come argomenti.
Le righe che contengono direttive non devono contenere nulla nel campo Etichetta.
Terzo campo (argomenti):
Gli argomenti devono essere scritti in questo campo, se sono richiesti dal comando. Se sono
più di uno devono essere separati da virgole.
La direttiva EQU fa eccezione, perché l'argomento destinazione appare prima del comando EQU.
Gli argomenti sono espressi con le convenzioni INTEL, per cui i valori forniti con indirizzamento
immediato sono preceduti da # ed i registri R0 ed R1, se usati per indirizzare indirettamente sono
preceduti da @.
Ad esempio:
MOV
R1,#25 scrive il numero 25 (19 in esadecimale) nel registro R1
MOV
@R1,#25 scrive lo stesso numero nella locazione puntata da R1
Possono essere argomenti:
1 - Le parole riservate tipo i nomi dei registri di uso generale o speciale (A, B, R5, TCON, ecc.) o delle
porte (P1, ecc.) o dei loro bit (P3.2, ecc.).
2 - Etichette che simboleggiano un indirizzo o simboli definiti con la direttiva EQU come costanti
numeriche.
3 - Valori numerici espressi in:
- base 10, usando le cifre dallo zero al 9, senza alcun suffisso;
- base 16, usando le cifre e/o le lettere da A ad F, seguite dal suffisso H. Nel caso che il
numero esadecimale inizi con un valore da A ad F, deve essere preceduto da uno 0 (zero),
per evitare che sia confuso con un'etichetta;
- base 2, usando solo le cifre 0 ed 1, seguite dal suffisso B.
4 - Stringhe di caratteri scritte fra apici (Esempio 'Stringa di esempio') ma non possono contenere
un apice come carattere.
Quarto campo (commenti):
Qualunque scritta preceduta da un punto e virgola è considerata un commento, fino alla fine
della linea. Una linea può contenere anche il solo campo Commenti.
Il simulatore SIM8051 usa particolari commenti per generare il diagramma di flusso e per eseguire il
programma.
Informazioni sul file nomefile.LST
Il listato vero e proprio ha la seguente forma:
Il primo carattere è di norma bianco; se invece è una "I" indica un file incluso nell'assemblaggio; se è
un "+" indica una macro.
I successivi 4 caratteri sono l'indirizzo del program counter per l'istruzione contenuta nella linea; per
le direttive tipo EQU indicano il valore generato dalla direttiva; per la direttiva END indica l'indirizzo di
inizio del programma assemblato. Dopo un singolo spazio segue un'area di 10 caratteri, coi codici
esadecimali dei programma oggetto. Se la riga contiene una direttiva, tale spazio è vuoto, salvo che
per quelle tipo EQU, dove c'è un segno di "=".
G. Renolfi – P. Vittor
pag. 24
ITIS OMAR NOVARA
Programmazione microcontroller
Dopo i primi 16 caratteri, segue la riga del file sorgente nella sua forma originaria. Pertanto se il
totale della linea supera gli 80 caratteri, la stampa richiede una stampante da 132 colonne, o con
caratteri più stretti. Altrimenti conviene prevedere di non creare linee lunghe più di 64 caratteri
scrivendo il file sorgente, dividendo eventualmente i commenti su più righe.
DIRETTIVE
Direttiva ORG
Assegna il valore del program counter per l'istruzione che segue la direttiva.
Possono essere usati più ORG nello stesso programma; l'assemblatore non riempirà le locazioni
intermedie che rimarranno inutilizzate. Esempi di sintassi:
ORG 123H
ORG $ + 15 ; salta 15 locazioni in avanti
In mancanza di indicazione iniziale, alla prima istruzione sarà assegnata la locazione ZERO.
Direttiva END
Indica la fine del file sorgente, e può avere un argomento, che può essere un valore od
un'espressione, che indica l'indirizzo di inizio del programma. Tale valore viene scritto in uno
speciale record del file.HEX. Se non esiste argomento, tale record non viene incluso nel file.HEX,
permettendo così di poter combinare fra loro più file .HEX, senza che entrino in conflitto le locazioni di
inizio.
Direttiva EQU
Permette di definire una costante. La sintassi è del tipo:
Simbolo EQU Espressione
oppure:
Esempio:
PIPPO = 2AH
Simbolo = Espressione
Possono essere usate anche operazioni aritmetiche, ad esempio:
PIPPO = 2AH + 12H
Direttiva BYTE
Permette di definire una costante, come la precedente, lunga un solo byte.
La sintassi è del tipo:
Simbolo BYTE Espressione
La differenza sta nel fatto che il simulatore la visualizzerà durante le operazioni di scansione della
memoria.
Direttiva BIT
La sintassi è del tipo:
Simbolo BIT Espressione
Il valore dell'espressione rappresenta l'indirizzo di una delle locazioni indirizzabili bit per bit.
Direttiva ALTNAME
Esempio di sintassi:
; definisce col simbolo conta il registro R3
ALTNAME R3,conta
Questa direttiva permette di definire con un nome significativo un elemento che l'assemblatore già
definisce con una parola riservata. Tuttavia quest'ultima può ancora essere usata.
SIMULATORE
SIM8051
Prima di avviare il simulatore, il programma CYS8051 deve avere già creato, partendo da un file
sorgente nomefile.ASM (ile in linguaggio assembly) i file nomefile.HEX (file esadecimale, che è il vero
programma in linguaggio macchina) e il nomefile.LST, ovvero il listato che può essere stampato e
viene usato per la visualizzazione nelle finestre.
Appare una schermata con l'elenco dei comandi, e sotto la scritta: "Enter HEX file name:"
Occorre rispondere col nome del file, con o senza l’estensione .HEX.
Appare una schermata come quella riportata in figura, con l'elenco dei registri e i valori dei medesimi
G. Renolfi – P. Vittor
pag. 25
ITIS OMAR NOVARA
Programmazione microcontroller
all'atto del Reset, e tre finestre di dialogo inizialmente vuote.
Elenco dei registri visualizzati:
SP
Stack pointer
BS
Banco di registri selezionato
R0....R7
Registri del banco selezionato
P0....P3Porte di ingresso/uscita
CC
Contatore di cicli
C0....C2
Contatori/temporizzatori
PC
Program counter
PD
Puntatore di dati
AC
Accumulatore
PS
Registro della parola di stato
Per eseguire il programma passo-passo: premere la barra spaziatrice, una volta per ogni passo.
Per l'esecuzione automatica del programma: premere <Invio>.
In alternativa il comando Ctrl-Q fa partire e ferma l'esecuzione automatica.
L'esecuzione automatica può essere rallentata con Ctrl-D oppure accelerata con Ctrl-F.
Il comando di RESET si simula digitando Ctrl-I
Per uscire dal programma digitare semplicemente Q e confermare con Y (yes).
Modifiche dei dati durante l’esecuzione del programma.
È sempre possibile, durante l’esecuzione, modificare il contenuto dei registri o della memoria.
Per modificare il contenuto dei registri visualizzati esternamente alle finestre, basta digitare il nome del
registro seguito dal simbolo = (uguale) e dal nuovo valore, esadecimale.
Esempio: R5 = A3
Durante la digitazione, l’eco sullo schermo appare in basso a sinistra, nell’ultima riga (riga dei
comandi). In caso di comandi impropri, compare il messaggio “Try one of {......}”; fra le parentesi
graffe vi è l’elenco dei caratteri che il simulatore è in grado di comprendere.
Per modificare i valori dei registri speciali e della memoria, oppure dei bit indirizzabili individualmente,
occorre entrare nella finestra della memoria, come è dettagliato nel paragrafo ad essa dedicata.
Occorre precisare che tali modifiche sono del tutto indipendenti dai valori derivanti dalle istruzioni
precedenti la loro immissione, ma influenzano tutta la prosecuzione successiva. Esse rappresentano
quindi un potente strumento di debug.
Digitando: PC = xxxx si possono forzare salti in avanti o indietro non previsti dal programma.
Digitando: PC = 0 si fa ripartire il programma dall’inizio, ma occorre tenere presente che questo non
equivale ad un RESET, perché registri e memoria mantengono inalterati i valori che avevano al
momento del ritorno forzato.
Finestra del codice
Contiene gli indirizzi della memoria programmi affiancati dalle istruzioni in codice mnemonico. Un
asterisco indica l'istruzione che sarà eseguita alla successiva pressione della barra spaziatrice:
codice già eseguito
ultima istruzione eseguita
*
prossima istruzione
codice successivo
La visualizzazione del codice va interpretata cosi:
L'ordine delle istruzioni SOTTO l'asterisco è sempre quello del programma sorgente, mentre SOPRA
le istruzioni sono nell'ordine reale col quale sono state eseguite.
Ovviamente, quest'ultimo può differire dal precedente se vi sono istruzioni di salto.
Finestra della memoria
Vi si accede col tasto (freccia in su) oppure (freccia in giù) e ci si sposta nell’interno usando le quattro
frecce: Può visualizzare dei byte oppure dei bit: segue una descrizione delle opzioni disponibili,
muovendosi con le frecce.
G. Renolfi – P. Vittor
pag. 26
ITIS OMAR NOVARA
Programmazione microcontroller
Opzioni disponibili:
Bit: 00 = 0
1 and 0 Set/Reset Bit
Scan Bits by using Left/Right Cursor
In questa situazione si possono leggere e modificare sia i bit delle locazioni accessibili a bit individuali,
sia quelli dei registri speciali. La selezione si effettua con le frecce, per la modifica basta premere 1 o
0; l’effetto si vede immediatamente nella finestra.
Se ci si porta nella visualizzazione Portx.y = 1, si può modificare il valore in uscita del bit y della
porta x, cioè si simula un valore nel latch connesso al pin Px.y.
DS: 0000 = 00 00 00 00 00 00 00 00
0xx write xx TROUGH selected pointer
DS sta per Data Segment. Permette di visualizzare 8 byte di memoria dati, a partire dalla locazione
scritta prima del segno di =. Nella seconda riga della finestra c’è la traduzione interpretando i byte in
codice ASCII. I codici non traducibili in caratteri (codici di controllo) ed i codici dell’ASCII esteso
vengono resi con un puntino.
La selezione si effettua con le frecce, per la modifica occorre digitare uno 0 (ZERO) seguito dal byte
che si vuole scrivere nella locazione selezionata, confermando con la pressione di <Invio>. L’eco
sullo schermo appare nella riga sotto il messaggio.
Lo stesso modo di selezione, modifica e lo stesso messaggio (.0xx write xx TROUGH selected
pointer) valgono anche per le seguenti altre opzioni:
ds: R0 = 00 00 00 00 00 00 00 00
ds sta per Data Segment. .Permette di visualizzare 8 byte di memoria dati, a partire dalla locazione
scritta nel registro R0. Con le frecce si ottiene una finestra del seguente tipo:
ds: R0+0001 = 00 00 00 00 00 00 00 00
Funziona in modo del tutto identico l’opzione con R1 al posto di R0 come registro puntatore.
ds: R1+0001 = 00 00 00 00 00 00 00 00
PD: 0000 = 00 00 00 00 00 00 00 00
PD sta per Pointed Data. Permette di visualizzare 8 byte di memoria dati esterni, a partire dalla
locazione scritta nel registro DPTR (PD nel simulatore).
CS: 0000 = 74 87 7A DC 2A FF 40 04
t
z
*
@
CS sta per Code Segment. Permette di visualizzare 8 byte di memoria programma, a partire dalla
locazione scritta prima del segno di =. Nella seconda riga della finestra c’è la traduzione
interpretando i byte in codice ASCII, come già visto per DS.
G. Renolfi – P. Vittor
pag. 27
ITIS OMAR NOVARA
Programmazione microcontroller
La stessa selezione si ottiene con la seguente opzione:
cs: PC = 74 87 7A DC 2A FF 40 04
0000 MOV A,#87
La differenza sta nel fatto che, in questo modo, anziché la traduzione in caratteri, nella seconda riga
della finestra viene disassemblata la prima istruzione
L’ultima opzione, che in realtà è la prima a comparire, permette di visualizzare e modificare il
contenuto di tutti i registri SFR. Riportiamo sotto un esempio:
Stkpt = 07
Stack pointer
0xx write xx INTO selected register
Il modo di selezione e modifica è identico a quello già visto per i puntatori
Se si selezionano i registri delle porte, la finestra appare del tipo:
P0 wr = FF
P0 rd = FF
* Port 0 output
Port 0 input
L’asterisco sta a indicare che con 0xx si modificano i latch della porta, cioè il valore inviato all’uscita.
Se si vuole simulare un byte inviato dall’esterno all’ingresso della porta, occorre digitare: P0 = byte.
N.B.
Poiché i valori ZERO sui latch dei singoli pin di uscita cortocircuitano il pin medesimo, i valori
di ingresso sugli stessi pin vengono automaticamente azzerati, ed il tentativo di rimetterli a 1 viene
rifiutato dal simulatore. Questo accade anche nella realtà, con l’aggravante che il corto circuito
potrebbe danneggiare la sorgente del valore 5 V corrispondente al valore logico “1”.
L’esempio visto per la porta P0 vale, ovviamente, anche per le altre porte.
Finestra del flusso
In questa finestra appaiono le etichette con cui i vari segmenti di programma sono stati individuati nel
file sorgente (nomefile.ASM); appaiono anche i messaggi di Reset all’inizio, di chiamata di subroutine
e di richiesta di interrupt accolta.
I diagrammi di flusso di norma si compongono di etichette e punti di diramazione. Le istruzioni
individuali sono mostrate nella finestra di codice ma non in quella di flusso.
Il comando T (TRACE) fa disassemblare e visualizzare il codice nella finestra di flusso.
In risposta il sistema richiede il numero di passi da visualizzare.
Si può rispondere in due modi: digitare il numero di linee da tracciare, e poi <Invio>, oppure premere
<Invio> subito. Nel secondo caso il sistema mostrerà ogni istruzione nella finestra di flusso.
Il diagramma di flusso può essere disattivato e riattivato premendo Ctrl-G.
Il comando Ctrl-C cancella tutte le finestre del simulatore.
Col comando Ctrl-P è possibile inviare il contenuto della finestra di flusso alla stampante. La
stampante stamperà anche commenti, preceduti dal punto e virgola, introdotti al momento.
I comandi ;%S e ;%E delimitano la sezione di programma che sarà "visibile" durante la simulazione.
In genere si desidera che tutto il programma sia visibile. Se vi sono subroutines che disturbano la
visualizzazione, è tuttavia possibile escluderle, scrivendole dopo ;%E.
In tal caso, durante l'esecuzione passo-passo, le subroutines escluse saranno eseguite in un solo
passo, e verrà visualizzata solo l'istruzione CALL.
La visualizzazione e l'esecuzione passo-passo possono essere abilitate col comando "V". Lo
stesso comando può essere usato per disabilitarle nuovamente.
Se si vogliono visualizzare i punti di diramazione, in corrispondenza ai comandi di salto condizionato,
occorre usare il simbolo ;? con le regole illustrate nel paragrafo seguente, dedicato alla formattazione
dei diagrammi di flusso.
G. Renolfi – P. Vittor
pag. 28
ITIS OMAR NOVARA
Programmazione microcontroller
Formattazione del flusso
Etichette: Sono tutte visualizzate nel diagramma di flusso. Un uso ben studiato permetterà ai
diagrammi di flusso di essere più rappresentativi.
Indicatori di inizio e fine: devono essere le uniche istruzioni scritte nella linea. Qualunque cosa le
segua, sarà ignorato dal simulatore.
Indicatori della tavola dei simboli: ;%T e ;%Z delimitano la tavola dei simboli, e sono scritte
automaticamente dalla versione 3.00 dell'assemblatore.
Indicatore di diramazione: ;? Deve essere scritto SOLO dopo una istruzione di salto
condizionato, e deve essere nella stessa linea del salto.
Indicatore di etichetta: ;: deve seguire SOLO un'etichetta, e deve essere nella stessa linea. I
codici seguenti l'etichetta vanno scritti nella linea successiva. In tal caso il messaggio scritto dopo ;:
viene visualizzato in un riquadro, dopo il nome dell’etichetta.
Simulazione degli interrupt esterni
Gli interrupt esterni dell'8751 sono basati sui pin 12 e 13 e provocano un salto alle locazioni di
codice rispettivamente 3 e 13H, e sono attivi bassi.
Per usare la linea di interrupt INT0 (corrispondente al piedino P3.2) selezionare lo spazio dei bit
individuali tramite i tasti <freccia in su> o <freccia in giù> e poi usare la freccia destra fino a
portarsi su "Port3.2". Premere 0 per attivare la linea.
Premendo la <barra spazio> (se gli interrupt sono stati attivati) vedremo effettuare il salto nella
locazione 3, e proseguire fino ad incontrare l'istruzione RETI, che riporta al programma interrotto.
Se proseguiamo, l'interruzione si verificherà nuovamente; ciò perché il pin P3.2 è ancora a livello
basso. Se non vogliamo altre interruzioni, dobbiamo riportare a "1" il pin P3.2 prima di eseguire la
prima istruzione dopo RETI. Analogo discorso vale per INT1, che provoca un salto nella locazione
13H.
Osservazione: in questo caso, il simulatore funziona in modo un po’ improprio. Infatti, ponendo
P3.2 = 0, si azzera il corrispondente latch, e questo forza a zero la tensione sul piedino. Nella realtà, il
valore zero arriva dall’esterno, ed il latch rimane a “1”. Si potrebbe simulare più adeguatamente la
situazione reale scrivendo nella riga di comando P3=byte, con byte calcolato in modo che il bit 2 sia
nullo. In questo modo il valore di P3 in uscita rimane invariato, e varia solo il valore in ingresso.
Tale maniera di procedere è però più macchinosa, specie nel caso che si utilizzino più ingressi della
porta P3. Se non si utilizzano altri ingressi, ci si può regolare con la seguente tabella:
P3 = FB
simula INT0 richiesto e INT1 non richiesto;
P3 = F7simula INT1 richiesto e INT0 non richiesto;
P3 = F3simula INT0 ed INT1 richiesti;
P3 = FF
simula INT0 ed INT1 non richiesti.
Interrupt forzati col comando I
SIM8051 genera un interrupt anche col comando I, digitato direttamente sulla linea dei comandi. Per
scegliere quale interrupt simulare, vedere la tabella seguente
I0 Interrupt esterno IT0
I1 Interrupt del Counter/Timer 0
I2 Interrupt esterno IT1
I3 Interrupt del Counter/Timer 1
I4 Interrupt seriale
L'interrupt forzato non tiene basso il pin che dovrebbe generare la richiesta, per cui l'interruzione
si verifica una volta sola. E' un meccanismo progettato strettamente per facilità e
convenienza dell'utente, e serve solo a provare il funzionamento delle routines di risposta, senza
controllare se vengono chiamate correttamente. Con questo comando, il salto alle routines di risposta
viene effettuato anche se gli interrupt non sono abilitati.
G. Renolfi – P. Vittor
pag. 29