Questa pagina contiene alcuni esempi ed alcuni esercizi utili per familiarizzare con le istruzioni assembly del PIC18. Tutto può essere eseguito utilizzando il simulatore.
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.
Metodologia generale di analisi:
In particolare analizziamo l'istruzione addwf:
L'istruzione ha tre argomenti, solo il primo obbligatorio. Essa somma WREG ad un generico registro:
Modificare il codice del primo esempio ponendo le tre variabili in un generico banco invece che nell'Access Bank
Scrivere il programma che somma tre variabili, memorizzando il risultato in una quarta. Tutte le variabili sono nell'Access Bank
Scrivere il programma che somma due variabili poste in due diversi banchi. Il risultato deve essere memorizzato in una variabile posta nell'Access Bank
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)
Sommare due numeri di otto bit tenendo conto del riporto (carry). Per esempio: 0xFF + 0x10 = 0x10F (2 byte)
Modificare l'esempio 2a usando una codifica big endian (nota 2)
Sommare due numeri a 32 bit, con rappresentazione little endian
Riscrivere uno dei programmi precedenti ponendo i due addendi in un banco e la somma in un altro banco
Riscrivere uno dei programmi precedenti ponendo i due addendi in un banco e la somma nell'Access Bank
Buffer è un temine che ha molti significati... In questo contesto si intende un blocco di memoria, in genere utilizzato attraverso l'indirizzamento indiretto.
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
Una soluzione più generale di quanto richiesto con l'esempio 3a:
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
Riempire il buffer dell'esempio 3 cominciando dall'ultima cella invece che dalla prima
Riempire il buffer di numeri da 1 a 8
Dopo aver creato il buffer del precedente esercizio, sommare i numeri in esso contenuto e salvare il risultato in una variabile a otto bit
Riempire il buffer con le lettere dell'alfabeto da A a H (ricordando che il codice ASCII di una lettera è un numero...)
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
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.
Alcuni quesiti:
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.
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
Modificare il codice dell'esempio 4c per ottenere un ritardo di 78 ms (o altro intervallo minore di 785 ms)
Scrivere il codice che, per ottenere un ritardo, incrementa la variabile contatore anziché decrementarla
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.
Commentare il codice dell'esempio 5a
Scrivere il codice che moltiplica le due variabili moltiplicando1 e moltiplicando2 attraverso somme successive. Il risultato può anche essere maggiore di 255
Scrivere il codice che moltiplica le due variabili moltiplicando1 e moltiplicando2 usando l'istruzione mulwf.
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).
Commentare il codice dell'esempio 5e
Aggiungere un controllo prima della divisione per gestire il caso in cui il divisore è nullo
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)
Quando mostrato nell'esempio 5e è lontano dall'essere efficiente... Scrivere il codice che implementa la divisione in colonna appresa nelle scuole elementari
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')
Scrivere il codice che trasforma un carattere un carattere maiuscolo nel corrispondente minuscolo, lasciandolo nella stessa cella di memoria
Riscrivere l'esempio 6a per trasformare un carattere minuscolo in uno maiuscolo
Riscrivere l'esercizio 6c per trasformare un carattere minuscolo in uno maiuscolo
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
Completare, eseguire e commentare il codice dell'esempio 6e
Aggiungere all'esempio 6a un controllo per verificare che in maiuscola ci sia davvero un carattere maiuscolo
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:
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:
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
Data di creazione di questa pagina: gennaio 2017
Ultima modifica: 3 novembre 2017
Assembly PIC18 - Versione 0.5 - aprile 2018
Copyright 2016-2018, Vincenzo Villa (https://www.vincenzov.net)
Assembly PIC18 di Vincenzo Villa è distribuito con Licenza Creative Commons Attribuzione 4.0 Internazionale