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