Programació en mpasm del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Estructura d'un programa

Un programa senzill tindrà normalment una estructura en tres parts.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
#define	Nivell		.21		; Valor de comparació per al nivell
	cblock 0x20
Valor					; Variable on guardem el que mostraran el valor
Comptador:2				; Variable de 16 bits
Llista:.16				; Bloc de 16 valors
	endc
	cblock 0xA0			; Zona de memòria de dades del banc 1
Taula:40				; Vector de 64 posicions (40h = 64)
	endc
	org 0
Inici
	bsf		STATUS,RP0	; Tria el banc 1
	...				; Inicialitzacions de registres del banc 1
	bcf		STATUS,RP0	
	bsf		STATUS,RP1	; Tria el banc 2
	...				; Inicialitzacions de registres del banc 2
	bcf		STATUS,RP1	; Tria el banc 0
	...				; Inicialitzacions de registres del banc 0
	movlw		b'00001000'	; Posa el valor al registre W
	movwf		Valor		; Copia el valor de W a la variable Valor
	...	
Bucle
	...				; Tros de programa que es repeteix cíclicament
	goto		Bucle		; Repetim-ho...
	end

A la primera part (que en aquest web s'indica amb fons de color daurat) hi ha la definició del microcontrolador que estem programant i la configuració base del microcontrolador (bits de configuració general). Aquesta configuració es defineix en el moment d'enviar un programa i no pot canviar-se mentre el programa està en execució. Aquestes dues línies són sempre idèntiques per a la majoria dels nostres programes. En aquesta part també s'hi poden definir símbols per definir valors. Els símbols no són variables i, per tant, no ocupen memòria (ni de programa ni de dades). En el moment d'enviar el programa, tots els símbols seran substituïts pels valors que els corresponen. L'ús de símbols permet tenir en un lloc fàcilment localitzable aquells valors que pot ser necessari modificar durant el desenvolupament i proves d'un programa.

A la segona part (que en aquest web s'indica amb fons de color blau fosc) hi ha la definició de les variables. La primera línia indica l'adreça on guardarem les variables i cada variable ocuparà una o més posicions a partir d'aquesta adreça. En principi, cada variable ocupa només una posició de memòria. Si una variable ha d'ocupar més d'una posició de memòria, això s'indica amb un valor després del símbol dels dos punts. Les variables de més d'una posició de memòria poden guardar números de 16 o més bits o bé llistes o vectors. Les llistes i els vectors normalment es gestionen amb adreçament indirecte. En alguns programes podem tenir diverses definicions de variables perquè fem servir més d'un banc de memòria.

A la tercera part (que en aquest web s'indica amb fons de color vermell fosc) correspon al programa pròpiament dit. Quasi tots els programes consten de dues parts, una part d'inicialització (que només s'executa un cop) i un bucle que es repeteix indefinidament. A la part d'inicialització es configura el microcontrolador, s'inicialitzen les variables i es fan aquelles altres tasques que només cal fer un cop. Sempre que sigui possible, es procura posar juntes totes les accions que corresponen a un banc per tal de no haver de canviar de banc més vegades que les mínimes necessàries. Normalment es fa abans la configuració que les inicialitzacions ja que algunes inicialitzacions poden requerir que el microcontrolador ja estigui convenientment configurat.

Un programa pot tenir funcions (també anomenades subfuncions). Les funcions (que en aquest web s'indica amb fons de color verd fosc) són trossos de programa separats als que s'accedeix amb la instrucció call i se'n retorna amb la instrucció return. Les funcions tenen l'avantatge que, quan acaben, retornen a la instrucció següent a aquella des d'on s'hi ha accedit. Això permet que es pugui accedir a la mateixa funció des de llocs diferents del programa ja que després es retorna al lloc correcte. També es fan servir les funcions quan tenim trossos de programa ja provats que ens interessa que no estiguin dins del programa principal per poder entendre millor el funcionament d'aquest. El cas més habitual és quan aquestes funcions s'aprofiten de programes anteriors.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
	...	
	endc
	org 0
Inici
	...	
Bucle
	...
	call		Retard
	...
	goto		Bucle		; 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

Atès que normalment cal modificar-les menys, és habitual posar les funcions al final, com en el cas de l'exemple anterior. Això, però, no és imprescindible. L'estructura de programa següent també funcionaria.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
	...	
	endc
	org 0
	goto		Inici
					;
					; 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
Inici
	...	
Bucle
	...
	call		Retard
	...
	goto		Bucle		; Repetim-ho...
	end

Convé posar totes les funcions juntes (a l'inici o al final) i no barrejar-les amb el programa per evitar confusions.

Quan un programa fa servir interrupcions l'estructura se'ns complica una mica. En aquest web les instruccions corresponents a les interrupcions s'indiquen amb fons de color lila. Resulta que el microcontrolador comença a executar el programa a partir de la instrucció que hi ha a la posició 0 i en cas d'interrupció executa a partir de la posició 4. Atès que entre les posicions 0 i 3 no hi cap pràcticament res, quan es treballa amb interrupcions se sol fer l'estructura següent.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
	...	
	endc
	org 0
	goto	Inici			; Saltem al lloc on hi ha el programa principal
	nop				; Zona de memòria de programa que no utilitzem
	nop
	nop
Interrup
	movwf	W_Copia			; Copiem l'acumulador a W_Copia
	swapf	STATUS,w		; Copiem STATUS a l'acumulador permutant els nibbles
	clrf	STATUS			; Posa a 0 i així segur que el banc és el 0
	movwf	ST_Copia		; Guarda STATUS permutat a ST_Copia
	...	
	swapf	ST_Copia,w		; Copia permutant ST_Copia a l'acumulador
	movwf	STATUS			; I ho passa a STATUS recuperant el valor d'abans
					; de la interrupció
	swapf	W_Copia,f		; Permuta els bits de W_Copia
	swapf	W_Copia,w		; Torna a permutar els bits de W_Copia
					; i els guarda a l'acumulador sense variar STATUS
	retfie				; Torna al programa principal, on s'havia quedat
Inici
	...	
Bucle
	...
	goto		Bucle		; Repetim-ho...
	...
	return
	end

El nostre programa pot contenir dades guardades a la memòria de programa o a la memòria EEPROM. En aquest web les dades que es defineixen a la memòria de programa o a la memòria EEPROM estan marcades amb un fons de color cian (blau verd).

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
	...	
	endc
	org 0
	goto	Inici			; Saltem al lloc on hi ha el programa principal
	nop				; Zona de memòria de programa que no utilitzem
	nop
	nop
Interrup
	...
	retfie				; Torna al programa principal, on s'havia quedat
Inici
	...	
Bucle
	...
	goto		Bucle		; Repetim-ho...
	...
	return
	org 0x700			; Lloc de la MEMPROG on guardem els valors
DadesMP	db		0,b'00000000',0,b'00000001',0,b'00000011',0,b'00000010',0,b'00000110',0,b'00000111'
	org 0x2100			; Inici de la memòria EEPROM
DadesEE	de		b'00000000',b'00000001',b'00000011',b'00000010',b'00000110',b'00000111',b'00000101'
	end

Quan tenim programes molt llargs, podem necessitar la segona pàgina de la memòria de programa. En aquest web el programa situat a la segona pàgina té el fons de color marró i les funcions que es troben en aquesta zona tenen el fons de color verd clar.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
	...	
	endc
	org 0
	goto	Inici			; Saltem al lloc on hi ha el programa principal
	nop				; Zona de memòria de programa que no utilitzem
	nop
	nop
Interrup
	...
	retfie				; Torna al programa principal, on s'havia quedat
Inici
	...	
Bucle
	...
	goto		Bucle		; Repetim-ho...
	...
	return
	org 0x800
IniciP2
	...				; Part del programa situada a la pàgina 2
	...				; Funcions situades a la pàgina 2
	return
	end

 

 

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