Esempi ed esercizi

Esercizi

Questa pagina contiene alcuni esempi ed alcuni esercizi utili per familiarizzare con le istruzioni assembly del PIC18. Tutto può essere eseguito utilizzando il simulatore.

Somma di numeri positivi

Esempio 1

Memorizzare in due variabili a 8 bit ADD1 e ADD2 i due numeri decimali 12 e 34; sommare le due variabili ADD1 e ADD2 e salvare il risultato in una terza variabile SOMMA. Si supponga che il risultato sia minore di 255. Utilizzare l'Access Bank.

Una possibile soluzione è mostrata di seguito.

Somma di due numeri ad otto bit

Metodologia generale di analisi:

  1. Leggere con attenzione il quesito (!)
  2. Leggere tutto il programma, in particolare i commenti. Non è necessario comprendere tutto subito, serve solo per farsi un'idea del contenuto
  3. Scrivere o copiare il codice all'interno di MPLABX ed assemblare per verificare l'assenza di errori di sintassi. In particolare osservare nella finestra di Output righe con Errors oppure Warnings (evidenziati in blu o rosso)
  4. Leggere sui fogli tecnici la funzione delle singole istruzioni e delle singole direttive non ancora conosciute
  5. Eseguire il programma passo-passo, osservando il contento delle variabili con la finestra Debug → New Watch; è possibile impostare la base numerica ed altri parametri di visualizzazione. Come alternativa, è possibile usare il mouse direttamente sul codice sorgente in corrispondenza del nome della variabile oppure osservare la finestra File Registers.

In particolare analizziamo l'istruzione addwf:

esercizi.addwf

L'istruzione ha tre argomenti, solo il primo obbligatorio. Essa somma WREG ad un generico registro:

Esercizio 1a

Modificare il codice del primo esempio ponendo le tre variabili in un generico banco invece che nell'Access Bank

Esercizio 1b

Scrivere il programma che somma tre variabili, memorizzando il risultato in una quarta. Tutte le variabili sono nell'Access Bank

Esercizio 1c

Scrivere il programma che somma due variabili poste in due diversi banchi. Il risultato deve essere memorizzato in una variabile posta nell'Access Bank

Esempio 2a

Memorizzare nelle due variabili a 16 bit (2 byte) ADD1 e ADD2 i due numeri 0x1234 e 0x5678; sommare le due variabili ADD1 e ADD2 e salvare il risultato in una terza variabile SOMMA. Si supponga che il risultato sia minore di 65 535.

Qualche osservazione preliminare:

Nell'esaminare il codice, prestare particolare attenzione alle differenza tra le istruzioni ADDWF e ADDWFC e al flag C (Carry)

Somma a 16 bit 

Esempio 2b

Sommare due numeri di otto bit tenendo conto del riporto (carry). Per esempio: 0xFF + 0x10 = 0x10F (2 byte)

Somma con riporto

Esercizio 2c

Modificare l'esempio 2a usando una codifica big endian (nota 2)

Esercizio 2d (lungo)

Sommare due numeri a 32 bit, con rappresentazione little endian

Esercizio 2e

Riscrivere uno dei programmi precedenti ponendo i due addendi in un banco e la somma in un altro banco

Esercizio 2f

Riscrivere uno dei programmi precedenti ponendo i due addendi in un banco e la somma nell'Access Bank

Buffer

Buffer è un temine che ha molti significati... In questo contesto si intende un blocco di memoria, in genere utilizzato attraverso l'indirizzamento indiretto.

Esempio 3a

Riempire un buffer di memoria di dimensioni 8 byte con il numero 0x55

Una soluzione semplice, ma poco flessibile e scomoda da usare se il buffer ha dimensioni ampie.

  UDATA_ACS
buffer res 8

 CODE 0
 movlw 0x55
 movwf buffer
 movwf buffer+1
 movwf buffer+2
 movwf buffer+3
 movwf buffer+4
 movwf buffer+5
 movwf buffer+6
 movwf buffer+7
 END

Commentare il codice precedente

Esempio 3b

Una soluzione più generale di quanto richiesto con l'esempio 3a:

Cancellazione di un buffer

Questo codice potrebbe essere paragonato all'analogo C/Java:

int buffer[8];
int contatore;
int i;        // Implicito nell'uso di POSTINC
int WREG;     // Sottointeso...

WREG=0x55;
i = 0;

for (contatore=8; contatore!=0; contatore--) {
 buffer[i] = WREG; i++;
}

Per osservare l'evoluzione del programma durante l'esecuzione passo-passo è possibile usare sia la finestra di Watch (impostare la vista del buffer usando il tasto destro) che attraverso la finestra File Registers. Nella finestra di Watch è visualizzato anche lo SFR FSR0

Esercizio 3c

Riempire il buffer dell'esempio 3 cominciando dall'ultima cella invece che dalla prima

Esercizio 3d

Riempire il buffer di numeri da 1 a 8

Esercizio 3e

Dopo aver creato il buffer del precedente esercizio, sommare i numeri in esso contenuto e salvare il risultato in una variabile a otto bit

Esercizio 3f

Riempire il buffer con le lettere dell'alfabeto da A a H (ricordando che il codice ASCII di una lettera è un numero...)

Cicli di ritardo

In alcune occasioni è necessario rallentare l'esecuzione di un codice "troppo veloce". Per esempio se decidiamo di far lampeggiare un LED potrebbe essere necessario rendere questa operazione più o meno veloce per essere percepita da un umano, che in genere fatica a vedere cose che durano meno di molte decine di millisecondi

Esempio 4a

Il seguente codice introduce un ritardo di poco più di 3 ms. contatore è una generica variabile di 8 bit, inizialmente azzerata e quindi decrementata nuovamente fino a zero: 0 → 255 → 254 → ... → 3 → 2 →1 → 0, per complessive 256 volte.

Ritardo di 3 ms

Alcuni quesiti:

Esercizio 4b

Scrivere il codice che introduce un ritardo di 1 ms circa; non è necessario calcolare esattamente la durata, basta osservare che il tempo di esecuzione deve essere circa tre volte minore di quanto mostrato nell'esempio 4a.

Esempio 4c

Il seguente codice introduce un ritardo di quasi un secondo. contatore è una variabile di 16 bit, inizialmente impostata a 0xFFFF (65 535) e quindi decrementata fino a zero

Ritardo lungo

Esercizio 4d

Modificare il codice dell'esempio 4c per ottenere un ritardo di 78 ms (o altro intervallo minore di 785 ms)

Esercizio 4e

Scrivere il codice che, per ottenere un ritardo, incrementa la variabile contatore anziché decrementarla

Ancora operazioni aritmetiche

Esempio 5a

Scrivere il codice che moltiplica le due variabili moltiplicando1 e moltiplicando2 attraverso somme successive. Si supponga che il risultato sia minore di 255 e che entrambi i moltiplicandi siano diversi da zero.

Moltiplicazione

Esercizio 5b

Commentare il codice dell'esempio 5a

Esercizio 5c

Scrivere il codice che moltiplica le due variabili moltiplicando1 e moltiplicando2 attraverso somme successive. Il risultato può anche essere maggiore di 255

Esercizio 5d

Scrivere il codice che moltiplica le due variabili moltiplicando1 e moltiplicando2 usando l'istruzione mulwf.

Esempio 5e

Scrivere il codice che implementa la divisione intera tra due variabili attraverso successive sottrazioni. Nell'esempio il risultato della divisione 100 : 20 = 5 è ottenuto come 100 - 20 - 20 - 20 - 20 - 20. L'esempio ignora la condizione in cui il divisore è nullo (division by zero).

Divisione intera 

Esempio 5f

Commentare il codice dell'esempio 5e

Esercizio 5g

Aggiungere un controllo prima della divisione per gestire il caso in cui il divisore è nullo

Esercizio 5h

Scrivere il codice che implementa la divisione intera tra una variabile di due byte ed una variabile di 1 byte attraverso successive sottrazioni. Ignorare la condizione in cui il divisore è nullo (division by zero)

Esercizio 5i (avanzato)

Quando mostrato nell'esempio 5e è lontano dall'essere efficiente... Scrivere il codice che implementa la divisione in colonna appresa nelle scuole elementari

Stringhe e caratteri

Esempio 6a

Memorizzare nella variabile maiuscola il codice ASCII di un qualunque carattere maiuscolo ('A' nell'esempio). Copiare in una seconda variabile minuscola il corrispondente carattere minuscolo. Se verifichi la tabella ASCII con il contenuto della memoria. Utile visualizzare le variabili nella finestra Watch come carattere e non come numero.

Si noti che non è effettuato alcun controllo sul fatto che maiuscola contenga davvero un codice ASCII compreso tra 65 e 90 ('A' → 'Z')

Esempio 6: maiuscole/minuscole

Esempio 6 - watch

Esercizio 6b

Scrivere il codice che trasforma un carattere un carattere maiuscolo nel corrispondente minuscolo, lasciandolo nella stessa cella di memoria

Esercizio 6c

Riscrivere l'esempio 6a per trasformare un carattere minuscolo in uno maiuscolo

Esercizio 6d

Riscrivere l'esercizio 6c per trasformare un carattere minuscolo in uno maiuscolo

Esempio 6e

Gli esempio ed esercizi precedenti non verificano se il carattere è davvero maiuscolo o minuscolo. Inserire questa verifica: il codice deve essere eseguito solo se la variabile contiene un valore corretto. Per esempio lo spezzone di codice seguente esegue la riga 16 solo se il carattere è effettivamente un carattere minuscolo

esempi - test

Esercizio 6f

Completare, eseguire e commentare il codice dell'esempio 6e

Esercizio 6g

Aggiungere all'esempio 6a un controllo per verificare che in maiuscola ci sia davvero un carattere maiuscolo

Conversione da binario a codice ASCII

Esempio 7

L'esempio BinToASCII.asm converte un numero intero positivo a 8 bit (compreso quindi tra 0 e 255) in tre byte contenenti il codice ASCII corrispondente. Per esempio il numero 0x7B (123 in decimale) viene convertito nella corrispondente stringa di caratteri ASCII "123" (0x31 0x32 0x33).

L'idea:

Leggere il codice, approfondendo in particolare:

Esempio 7a

L'esempio BinToASCII_a.asm affronta lo stesso problema con un'idea brillante, basato sull'osservazione che lo scorrimento verso sinistra di un numero binario coincide con la sua moltiplicazione per due; in decimale la moltiplicazione per due di un numero coincide invece con la somma con se stesso.

Quindi:

Esempio 7b

L'esempio Bin16ToASCII.asm usa gli stessi concetti dell'esempio 7a per convertire un numero a 16 bit in cinque caratteri ASCII. Il commento del codice è lasciato come esercizio

 

Note

  1. Lo Stopwatch è utilizzabile solo usando il simulatore
  2. I processori ad 8 bit puri non predeterminano l'endianness, a differenza di quelli a 16 o 32 bit. Ciononostante, MPLABX preferisce il little endian

 

Data di creazione di questa pagina: gennaio 2017
Ultima modifica: 3 novembre 2017


Licenza Creative Commons Attribuzione 4.0 Internazionale


Pagina principaleAccessibilitàNote legaliPosta elettronicaXHTML 1.0 StrictCSS 3

Vai in cima