A l'Exemple RB tenim dos bucles de retard. Podríem definir aquest bucle com una funció i anar-hi des dels dos llocs on el necessitem. En realitat, passarem un paràmetre (a través de W) a la funció, així que es comportarà com una funció.
En el programa següent hem substituït els dos Bucles de retard per crides (call) a la funció i passem el nombre de cicles a través de l'acumulador.
#include <p16F690.inc> __config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
cblock 0x20 Polsador ; Una variable amb l'estat del polsador (1 = premut) Memoria ; El bit 0 és l'estat previ del polsador i el bit 1 és el sentit de gir Visualit ; Una variable on guardem el que mostraran els LED Compta ; Una variable per comptar iteracions Retard1 ; Variable per al bucle de retard Retard2 endc
org 0 Inici bsf STATUS,RP0 ; Tria el banc 1 movlw 0xFF ; Posa l'acumulador a FFh (tot uns) movwf TRISA ; Posa tots els bits del port A com a entrada clrf TRISC ; Posa tots els bits del port C com a sortida movlw b'00010000' movwf ADCON1 ; Posa el conversor a 1/8 de la freqüència bcf STATUS,RP0 bsf STATUS,RP1 ; Tria el banc 2 movlw b'00000001' movwf ANSEL ; Posa AN0 com entrada analògica bcf STATUS,RP0 bcf STATUS,RP1 ; Tria el banc 0 movlw b'00000001' ; activa el conversor A/D connectat a AN0 movwf ADCON0 ; amb el resultat justificat per l'esquerra movlw b'00001000' ; Activa el bit 3 movwf Visualit ; Ho copia sobre la variable Visualit clrf Memoria ; Inicialment, rotació a dreta i polsador és no premut Bucle movf Visualit,w ; Copia la variable Visualit a l'acumulador movwf PORTC ; Copia el resultat sobre els LED nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon, en total 5 bsf ADCON0,GO ; Inicia la conversió btfsc ADCON0,GO ; Quan el bit sigui 0 la conversió haurà acabat goto $-1 ; repetim la línia fins que deixi de ser 0 movf ADRESH,w ; Copia els bits superiors a l'acumulador addlw 1 ; Li suma 1 i tenim la durada variable del cicle call Retard movlw .13 ; El punt indica que es un valor decimal call Retard movlw b'00000001' ; Polsador activat movwf Polsador ; Activem polsador abans de comprovar btfsc PORTA,3 ; Mira si està desactivada l'entrada A3 ; Si desactivat (premut), no fa la instrucció següent clrf Polsador ; Si no està premut, desactiva polsador movf Memoria,w ; Copia Memoria a l'acumulador andlw b'00000001' ; Conserva només el bit 0 (Previ) xorwf Polsador,w ; Compara Previ amb Polsador, si són iguals s'activa Z btfsc STATUS,Z ; Si són iguals va a Final goto Rotar movf Memoria,w ; Copia Memoria a l'acumulador xorlw b'00000010' ; Inverteix el valor del bit 1 (Sentit) movwf Memoria ; I ho guarda a Sentit Rotar bcf STATUS,C ; posa a zero el bit d'arrossegament ; Això cal en qualsevol sentit btfsc Memoria,1 ; En quin sentit rodem? goto Esquerra ; 1 = Esquerra Dreta ; Gir a la dreta rrf Visualit,f ; Fa rodar els bits cap a la dreta ; el bit d'arrossegament entra per l'esquerra ; i el bit de la dreta passa a l'arrossegament btfsc STATUS,C ; Comprova si s'ha activat l'arrossegament ; Si no s'ha activat, salta una instrucció bsf Visualit,3 ; Si s'ha activat, torna a posar un 1 (0000 1000) goto Bucle ; Repetim-ho... Esquerra ; Gir a l'esquerra rlf Visualit,f ; Fa rodar els bits cap a l'esquerra btfss Visualit,4 ; Hem sortit fora dels 4 bits dels LED? goto Bucle ; No, repetim-ho... bcf Visualit,4 ; Sí, desactivem el 4 bsf Visualit,0 ; i tornem a activar el primer goto Bucle ; i repetim-ho...
; ; Bucle de retard ; Retard movwf Retard2 ; Ho copia a la variable Retard2 RetVar decfsz Retard1,f ; Decrementa la variable 1 ; si dona zero, no es fa la instrucció següent goto RetVar ; Salta, excepte si el resultat ha estat zero decfsz Retard2,f ; Decrementa la variable 2 goto RetVar ; Salta, excepte si el resultat ha estat zero return end
Les subfuncions (i altres parts del programa) poden estar en fitxers separats, de manera que estiguin ja preparats i comprovats i només calgui incloure'ls. Això permet reutilitzar fàcilment codi d'un programa a un altre.
Per exemple, la funció podria estar en el fitxer Retards.inc i llavors el nostre fitxer de programa podria ser:
#include <p16F690.inc> __config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
cblock 0x20 Polsador ; Una variable amb l'estat del polsador (1 = premut) Memoria ; El bit 0 és l'estat previ del polsador i el bit 1 és el sentit de gir Visualit ; Una variable on guardem el que mostraran els LED Compta ; Una variable per comptar iteracions Retard1 ; Variable per al bucle de retard Retard2 endc
org 0 Inici bsf STATUS,RP0 ; Tria el banc 1 movlw 0xFF ; Posa l'acumulador a FFh (tot uns) movwf TRISA ; Posa tots els bits del port A com a entrada clrf TRISC ; Posa tots els bits del port C com a sortida movlw b'00010000' movwf ADCON1 ; Posa el conversor a 1/8 de la freqüència bcf STATUS,RP0 bsf STATUS,RP1 ; Tria el banc 2 movlw b'00000001' movwf ANSEL ; Posa AN0 com entrada analògica bcf STATUS,RP0 bcf STATUS,RP1 ; Tria el banc 0 movlw b'00000001' ; activa el conversor A/D connectat a AN0 movwf ADCON0 ; amb el resultat justificat per l'esquerra movlw b'00001000' ; Activa el bit 3 movwf Visualit ; Ho copia sobre la variable Visualit clrf Memoria ; Inicialment, rotació a dreta i polsador és no premut Bucle movf Visualit,w ; Copia la variable Visualit a l'acumulador movwf PORTC ; Copia el resultat sobre els LED nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon nop ; espera un microsegon, en total 5 bsf ADCON0,GO ; Inicia la conversió btfsc ADCON0,GO ; Quan el bit sigui 0 la conversió haurà acabat goto $-1 ; repetim la línia fins que deixi de ser 0 movf ADRESH,w ; Copia els bits superiors a l'acumulador addlw 1 ; Li suma 1 i tenim la durada variable del cicle call Retard movlw .13 ; El punt indica que es un valor decimal call Retard movlw b'00000001' ; Polsador activat movwf Polsador ; Activem polsador abans de comprovar btfsc PORTA,3 ; Mira si està desactivada l'entrada A3 ; Si desactivat (premut), no fa la instrucció següent clrf Polsador ; Si no està premut, desactiva polsador movf Memoria,w ; Copia Memoria a l'acumulador andlw b'00000001' ; Conserva només el bit 0 (Previ) xorwf Polsador,w ; Compara Previ amb Polsador, si són iguals s'activa Z btfsc STATUS,Z ; Si són iguals va a Final goto Rotar movf Memoria,w ; Copia Memoria a l'acumulador xorlw b'00000010' ; Inverteix el valor del bit 1 (Sentit) movwf Memoria ; I ho guarda a Sentit Rotar bcf STATUS,C ; posa a zero el bit d'arrossegament ; Això cal en qualsevol sentit btfsc Memoria,1 ; En quin sentit rodem? goto Esquerra ; 1 = Esquerra Dreta ; Gir a la dreta rrf Visualit,f ; Fa rodar els bits cap a la dreta ; el bit d'arrossegament entra per l'esquerra ; i el bit de la dreta passa a l'arrossegament btfsc STATUS,C ; Comprova si s'ha activat l'arrossegament ; Si no s'ha activat, salta una instrucció bsf Visualit,3 ; Si s'ha activat, torna a posar un 1 (0000 1000) goto Bucle ; Repetim-ho... Esquerra ; Gir a l'esquerra rlf Visualit,f ; Fa rodar els bits cap a l'esquerra btfss Visualit,4 ; Hem sortit fora dels 4 bits dels LED? goto Bucle ; No, repetim-ho... bcf Visualit,4 ; Sí, desactivem el 4 bsf Visualit,0 ; i tornem a activar el primer goto Bucle ; i repetim-ho... #include <Retards.inc> end
I el fitxer Retards.inc seria:
; ; Bucle de retard ; Retard movwf Retard2 ; Ho copia a la variable Retard2 RetVar decfsz Retard1,f ; Decrementa la variable 1 ; si dona zero, no es fa la instrucció següent goto RetVar ; Salta, excepte si el resultat ha estat zero decfsz Retard2,f ; Decrementa la variable 2 goto RetVar ; Salta, excepte si el resultat ha estat zero return
Fixem-nos que en assemblador cal posar la directiva #include en el lloc exacte on volem carregar el fitxer. Si, per exemple, l'haguéssim posat al començament (entre org0 i Inici) el microcontrolador començaria executant la funció com si fos el programa principal.

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.