Programació en mpasm del PIC 16F690

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

Exemple TI - Comunicació per infraroig

En aquest exemple volem comunicar dos microcontroladors per infrarojos.

Ens basarem en l'exemple EA. A l'emissor hi tindrem el programa d'aquest exemple però, addicionalment, enviarem per infrarojos el mateix valor que enviem als LED. En el receptor, rebrem el valor i el mostrarem als LED. Així doncs, els LED de les dues plaques tindran la mateixa combinació que podrem variar amb el potenciòmetre de la targeta emissora.

Per estalviar energia, esperarem 0,6 s entre una lectura i la següent. L'emissor estarà connectat a RB4 i el receptor a RB6. Fem servir potes diferents perquè en cas de voler implementar un enllaç bidireccional tindríem emissor i receptor en el mateix microcontrolador.

Emissor

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock	0x20
Port			; Variable per al contingut del port B
			; que permet modificar els bits individualment
Comp_bits		; Variable per comptar bits
Comp_bytes		; Variable per comptar bytes
Control			; Variable per calcular el byte de control
Retard			; Comptador per al retard
Byte			; Variable de treball per enviar un byte
Bytes			; Número de bytes que voldrem enviar
			; Un paquet tindrà aquests i el byte de control
Ret:3			; Tres variables per a bucles de retard
Vector			; Lloc on es guardaran els bytes a enviar
			; Després d'aquesta ja no es poden declarar més variables
			; ja que el vector tindrà tantes posicions com hi digui a Bytes
			; més una per al byte de control
	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		TRISB		; Posa tots els bits del port B com a sortida
	clrf		TRISC		; Posa tots els bits del port C com a sortida
	movlw		b'00010000'	; Posa el conversor a 1/8 de la freqüència
	movwf		ADCON1		; Copia W a la configuració del conversor A/D
	bcf		STATUS,RP0
	bsf		STATUS,RP1	; Tria el banc 2
	movlw		0xFF		; Posa l'acumulador a FFh (tot uns)
	movwf		ANSEL		; Configura AN0-AN7 com entrades analògiques
	bcf		STATUS,RP0
	bcf		STATUS,RP1	; Tria el banc 0
	movlw		0		; Inicialment totes les sortides desactivades
	movwf		Port		; Ho guardem a Port
	movwf		PORTB		; I ho copiem al port B
	movlw		.2		; Número de bytes que volem enviar
	movwf		Bytes		; Ho guardem a Bytes
	movlw		0x93		; Codi d'identificació
	movwf		Vector		; El guarda sobre el primer byte de dades que enviarem
	movlw		b'00000001'	; activa el conversor A/D connectat a AN0
	movwf		ADCON0		; amb el resultat justificat per l'esquerra
Bucle
	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 1
	swapf		ADRESH,w	; Permuta els nibbles dels bits superiors
	movwf		PORTC		; Copia el resultat sobre els LED
	movwf		Vector+1	; i sobre el segon byte de dades que enviarem
	call		Envia		; Envia la dada
	movlw		.3		; Bucle de retard de 3 * 0,2 = 0,6 s
	movwf		Ret+2
Bucles
	decfsz		Ret,f		
	goto		Bucles		
	decfsz		Ret+1,f		
	goto		Bucles		
	decfsz		Ret+2,f	
	goto		Bucles
	goto		Bucle
					;
					; Funció per enviar un paquet
					;
Envia					
					; Comencem calculant el byte de control
					; Hem de sumar (sense portar-ne) tots els bytes
	clrf		Control		; El posem a zero
	movf		Bytes,w		; Llegim el número de bytes que volem enviar
	movwf		Comp_bytes	; Ho guardem al comptador de bytes
	movlw		Vector		; Llegim l'adreça de Vector
	movwf		FSR		; Ho posem al punter d'adreçament indirecte
	movlw		0		; L'acumulador contindrà la suma, comencem a 0
	addwf		INDF,w		; Hi sumem un dels bytes
	incf		FSR,f		; Desplaça el punter
	decfsz		Comp_bytes,f	; Byte següent
	goto		$-3		; Si no és el darrer, seguim
					; Ja tenim la suma, ara ho restem (sense portar-ne) de Control (= 0)
	subwf		Control,w	; W = Control - suma
	movwf		INDF		; Ho guarda al final del Vector
					; Comencem a enviar
					; Primer cal enviar la capçalera
	movlw		.15		; Primer 15 bits a 1
	movwf		Comp_bits	; Ho guarda al comptador de bits
	call		Envia_1		; Envia un 1
	decfsz		Comp_bits,f	; Decrementa els bits pendents
	goto		$-2		; Repeteix fins que s'acabi
	call		Envia_0		; Finalment un bit a 0
					; Després cal enviar els bytes
	movf		Bytes,w		; Llegim el número de bytes que volem enviar
	movwf		Comp_bytes	; Ho guardem al comptador de bytes
	incf		Comp_bytes,f	; Incrementa el comptador de bytes per afegir el byte de control
	movlw		Vector		; Llegim l'adreça de Vector
	movwf		FSR		; Ho posem al punter d'adreçament indirecte
TI	movf		INDF,w		; Agafa un dels bytes
	movwf		Byte		; Ho guarda a la variable de treball
	movlw		.8		; Un byte són 8 bits
	movwf		Comp_bits	; Ho guarda al comptador de bits
TR	rlf		Byte,f		; El bit de més a l'esquerra passa a C
	btfss		STATUS,C	; Mira sí és 0
	goto		T0		; Sí, envia un 0
	call		Envia_1		; No, envia un 1
	goto		TF
T0	call		Envia_0		; Envia un 0
TF	decfsz		Comp_bits,f	; Següent bit
	goto		TR
					; Al final de cada byte s'envia un 1 i un 0
	call		Envia_1		; Envia un 1
	call		Envia_0		; Envia un 0	
	incf		FSR,f		; Desplaça el punter
	decfsz		Comp_bytes,f	; Byte següent
	goto		TI
	bcf		Port,4		; Desactiva l'emissor
	movf		Port,w		; Ho canviem a Port
	movwf		PORTB		; I ho copiem al port B
	return
Envia_0					; Funció per enviar un 0
	bsf		Port,4		; Un bit 0 comença amb 1
	movf		Port,w		; Ho canviem a Port
	movwf		PORTB		; I ho copiem al port B
	movlw		.166		; Cada dec són 1 us i cada goto són 2 us
	movwf		Retard		; 165 * 3 (a la darrera no hi ha goto) dona 495
	decfsz		Retard,f	; que amb els 4 dels mov i 1 del dec
	goto		$-1		; fem 500 us
	bcf		Port,4		; I canvia a 0 a mig bit
	movf		Port,w		; Ho canviem a Port
	movwf		PORTB		; I ho copiem al port B
	movlw		.166		; Cada dec són 1 us i cada goto són 2 us
	movwf		Retard		; 165 * 3 (a la darrera no hi ha goto) dona 495
	decfsz		Retard,f	; que amb els 4 dels mov i 1 del dec
	goto		$-1		; fem 500 us
	return				; 0 enviat
Envia_1					; Funció per enviar un 1
	bcf		Port,4		; Un bit 1 comença amb 0
	movf		Port,w		; Ho canviem a Port
	movwf		PORTB		; I ho copiem al port B
	movlw		.166		; Cada dec són 1 us i cada goto són 2 us
	movwf		Retard		; 165 * 3 (a la darrera no hi ha goto) dona 495
	decfsz		Retard,f	; que amb els 4 dels mov i 1 del dec
	goto		$-1		; fem 500 us
	bsf		Port,4		; I canvia a 1 a mig bit
	movf		Port,w		; Ho canviem a Port
	movwf		PORTB		; I ho copiem al port B
	movlw		.166		; Cada dec són 1 us i cada goto són 2 us
	movwf		Retard		; 165 * 3 (a la darrera no hi ha goto) dona 495
	decfsz		Retard,f	; que amb els 4 dels mov i 1 del dec
	goto		$-1		; fem 500 us
	return				; 1 enviat
	end

Receptor

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock	0x20
Estat			; Variable per memoritzar estats
Comp_bits		; Variable per comptar bits
Comp_bytes		; Variable per comptar bytes
Byte			; Variable temporal per construir un byte
Bytes			; Número de bytes que rebrem
Temps			; Variable per comptar el temps
minS			; Valor mínim per a la durada d'un semiperíode
maxS			; Valor màxim per a la durada d'un semiperíode
minP			; Valor mínim per a la durada d'un període
maxP			; Valor màxim per a la durada d'un període
Vector			; Lloc on es guardaran els bytes rebuts
			; Després d'aquesta ja no es poden declarar més variables
			; ja que el vector tindrà tantes posicions com hi digui a Bytes
			; més una per al byte de control
	endc
	org 0
Inici					; Comencem amb la inicialització
	bsf		STATUS,RP0	; Tria el banc 1
	movlw		b'01000000'	; RB6 és entrada, la resta del port B és sortida
	movwf		TRISB
	clrf		TRISC		; Posa tots els bits del port C com a sortida
	movlw		b'10000010'	; Configuració de Timer0
					; Com a temporitzador basat en rellotge
					; 010 - Factor d'escala de 8
					; TMR0 s'incrementarà cada 8 us
					; I resistències de pull-up desactivades (valor per defecte)
	movwf		OPTION_REG	; Ho guarda al registre de configuració del Timer0
	bcf		STATUS,RP0	; Tria el banc 0
					; Inicialització de variables
	clrf		Estat		; De moment, desactiva tots els bits d'estat
	movlw		.3		; Número de bytes que rebrem
	movwf		Bytes		; Ho guardem a Bytes
					; Semiperíode de 500 us
					; Marge d'error: 30 % 	500 * 0,3 = 150
	movlw		.43		; (500 - 150)/8
	movwf		minS		; Valor mínim per a la durada d'un semiperíode
	movlw		.82		; (500 + 150)/8
	movwf		maxS		; Valor màxim per a la durada d'un semiperíode
	movlw		.87		; 2 * (500 - 150)/8
	movwf		minP		; Valor mínim per a la durada d'un període
	movlw		.163		; 2 * (500 + 150)/8
	movwf		maxP		; Valor màxim per a la durada d'un període
	clrf		PORTC		; Comencem amb els LED apagats
Bucle
	call		Rebre		; Espera que arribi un paquet
	andlw		0xFF		; Anem a veure si W és zero
	btfss		STATUS,Z	; Si és zero, and donarà zero
	goto		Bucle		; No és zero, esperem un altre paquet
	movlw		0x93		; Sí és zero, anem a veure el Codi d'identificació
	xorwf		Vector,w	; Compara amb el codi d'identificació 
	btfss		STATUS,Z	; Si Z = 1 es que són iguals
	goto		Bucle		; Z = 0, esperem un altre paquet
	movf		Vector+1,w	; Agafem el byte de dades
	movwf		PORTC		; i el copia sobre els LED
	goto		Bucle		; Acabat, esperem un altre paquet
					;
					; Funció per rebre un paquet
					;
Rebre				
					; Comencem inicialitzant variables
	movlw		Vector		; Carreguem l'adreça del lloc on es guardaran els bytes rebuts
	movwf		FSR		; Punter per a l'adreçament indirecte
	clrf		Comp_bits	; Posem a zero la variable que compta els bits rebuts
	movf		Bytes,w		; Número de bytes que rebrem
	movwf		Comp_bytes	; Variable de comptatge
	bsf		Estat,5		; Cap = 1
					; Ara esperem la primera activació (primer 1)
	btfsc		PORTB,6		; S'ha activat el LED? O sigui, s'ha desactivat l'entrada?
	goto		$-1		; No, doncs esperem
	clrf		TMR0		; Sí, comencem a comptar el temps
Espera					; Esperem a que es desactivi l'entrada
	btfsc		PORTB,6		; S'ha desactivat el LED? O sigui, s'ha activat l'entrada?
	goto		PrimerBit	; Sí, doncs el primer bit ja està
	movf		TMR0,w		; No, agafa el valor actual del temps
	movwf		Temps		; i el guarda
	movf		maxS,w		; Mirem que no passem de maxS
	subwf		Temps,w		; W = Temps - W
	btfss		STATUS,C	; C = 1 si Temps >= maxS
	goto		Espera		; És més petit, seguim esperant
	retlw		.129		; És més gran: Error 129 - Bit d'inici massa llarg
PrimerBit				; El primer bit ja està
	movf		TMR0,w		; Agafa el valor actual del temps
	movwf		Temps		; i el guarda
	clrf		TMR0		; Comencem a comptar el temps
	movf		minS,w		; Mirem que no sigui menor que minS
	subwf		Temps,w		; W = Temps - W
	btfss		STATUS,C	; C = 1 si Temps >= minS
	retlw		.130		; És més petit: Error 130 - Bit d'inici massa curt
	incf		Comp_bits,f	; Ja tenim un bit
	bsf		Estat,6		; Pre = 1
	bcf		Estat,7		; Rebut = 0
SegTran					; Esperem al següent canvi a l'entrada
	btfsc		Estat,7		; Quin és el darrer valor de l'entrada?
	goto		Espera0		; 1, doncs hem de rebre un 0
	goto		Espera1		; 0, doncs hem de rebre un 1
Espera0					; Esperem que es desactivi l'entrada
	btfsc		PORTB,6		; S'ha desactivat el LED? O sigui, s'ha activat l'entrada?
	goto		Canvi		; Sí	
	movf		TMR0,w		; No, agafa el valor actual del temps
	movwf		Temps		; i el guarda
	movf		maxP,w		; Mirem que no passem de maxP
	subwf		Temps,w		; W = Temps - W
	btfss		STATUS,C	; C = 1 si Temps >= maxP
	goto		Espera0		; És més petit, seguim esperant
	retlw		.17		; És més gran: Error 17 - Període massa llarg
Espera1					; Esperem que s'activi l'entrada
	btfss		PORTB,6		; S'ha activat el LED? O sigui, s'ha desactivat l'entrada?
	goto		Canvi		; Sí	
	movf		TMR0,w		; No, agafa el valor actual del temps
	movwf		Temps		; i el guarda
	movf		maxP,w		; Mirem que no passem de maxP
	subwf		Temps,w		; W = Temps - W
	btfss		STATUS,C	; C = 1 si Temps >= maxP
	goto		Espera1		; És més petit, seguim esperant
	retlw		.17		; És més gran: Error 17 - Període massa llarg
Canvi					; L'entrada ja ha canviat
	movf		TMR0,w		; Agafa el valor actual del temps
	movwf		Temps		; i el guarda
	clrf		TMR0		; Comencem a comptar el temps
	movf		minS,w		; Mirem que no sigui menor que minS
	subwf		Temps,w		; W = Temps - W
	btfss		STATUS,C	; C = 1 si Temps >= minS
	retlw		.18		; És més petit: Error 18 - Semiperíode massa curt
	movlw		b'10000000'	; Invertim bit 7
	xorwf		Estat,f		; o sigui, invertim Rebut
	movf		maxS,w		; Mirem si és més gran que maxS
	subwf		Temps,w		; W = Temps - W
	btfss		STATUS,C	; C = 1 si Temps >= maxS
	goto		Curt		; És més petit, és un pols curt
	movf		minP,w		; També mirem si és més gran que minP
	subwf		Temps,w		; W = Temps - W
	btfsc		STATUS,C	; C = 1 si Temps >= minP
	goto		Llarg		; És més gran, és un pols llarg
	retlw		.19		; Ni curt ni llarg
					; Error 19 - Semiperíode massa llarg o període massa curt
Llarg					; És un pols llarg
	btfsc		Estat,6		; Pre = 1?
	retlw		.9		; Sí: Error 9 - No hi ha canvi a mig període
	goto		CanviFinal	; No, esperem canvi al final de període
Curt					; És un pols curt
	movlw		b'01000000'	; Invertim Pre ara
	xorwf		Estat,f		; per no haver-ho de fer dos cops
	btfsc		Estat,6		; Pre = 1?
	goto		SegTran		; No, esperem canvi a mig període
CanviFinal				; Sí, esperem canvi al final de període
	btfss		Estat,5		; Cap = 1?
	goto		NoCap		; No, ja no estem rebent capçalera
	btfss		Estat,7		; Rebut = 1?
	goto		Cap0		; No, hem rebut un zero a la capçalera
	incf		Comp_bits,f	; Tenim un altre 1 de capçalera
	movlw		.16		; Hem arribat al final de la capçalera?
	xorwf		Comp_bits,w	; Comp_bits = 16?
	btfsc		STATUS,Z	; Z = 1 si Comp_bits = 16
	retlw		.66		; Sí: Error 66 - Massa 1 a la capçalera
	goto		SegTran		; No, esperem el següent
Cap0					; Hem rebut un zero a la capçalera
	movlw		.15		; Hem arribat al final de la capçalera?
	xorwf		Comp_bits,w	; Comp_bits = 15?
	btfss		STATUS,Z	; Z = 1 si Comp_bits = 15
	retlw		.65		; Sí: Error 65 - Pocs 1 a la capçalera
	bcf		Estat,5		; Cap = 0 - Capçalera ja acabada, ara rebrem el missatge
	movlw		.10		; Cada byte són 10 bits
	movwf		Comp_bits	; 8 de dades i dos d'aturada
	clrf		Byte		; De moment, no hem rebut cap bit de Byte
	goto		SegTran		; Anem a esperar el primer bit
NoCap					; Ja no estem rebent capçalera
	decfsz		Comp_bits,f	; Decrementem, és 0?
	goto		NoEs0		; No, cal saber si és 1 o més gran
	btfsc		Estat,7		; Sí, darrer bit d'aturada - Rebut = 1?
	retlw		.34		; Sí: Error 34 - No hi ha 0 als bits d'aturada
	movf		Byte,w		; Agafa el byte rebut
	movwf		INDF		; I el guarda a Vector
	incf		FSR,f		; Incrementa el punter
	decfsz		Comp_bytes,f	; Decrementem, és 0?
	goto		NoFi		; No, cal rebre un altre byte
					; Ja hem acabat, anem a fer la suma de control
	movlw		Vector		; Carreguem l'adreça del lloc on es guardaran els bytes rebuts
	movwf		FSR		; Punter per a l'adreçament indirecte
	movf		Bytes,w		; Número de bytes que hem rebut
	movwf		Comp_bytes	; Variable de comptatge
	movlw		0		; Comencem amb zero per anar sumant
SumaControl				; i anem a fer el bucle de suma
	addwf		INDF,w		; Suma el valor de Vector
	incf		FSR,f		; Incrementa el punter
	decfsz		Comp_bytes,f	; Decrementa, és 0?
	goto		SumaControl	; No, sumem un altre
	andlw		0xFF		; Sí, anem a veure si surt zero
	btfss		STATUS,Z	; Si és zero, and donarà zero
	retlw		.5		; No és zero: Error 5 - La suma de control no dona 0
	retlw		0		; Sí és zero: Error 0 - Recepció correcta
NoFi					; Cal rebre un altre byte
	movlw		.10		; Cada byte són 10 bits
	movwf		Comp_bits	; 8 de dades i dos d'aturada
	clrf		Byte		; De moment, no hem rebut cap bit de Byte
	goto		SegTran		; Anem a esperar el primer bit
NoEs0					; Cal saber si és 1 o més gran
	decfsz		Comp_bits,w	; Decrementem provisionalment, és 0?
	goto		Dades		; No, doncs encara és un bit de dades
	btfss		Estat,7		; Sí, és un bit d'aturada - Rebut = 1?
	retlw		.33		; No: Error 33 - No hi ha 1 als bits d'aturada
	goto		SegTran		; Sí, esperem el següent bit d'aturada
Dades					; És un bit de dades
	rlf		Estat,w		; Passa Rebut a C
	rlf		Byte,f		; I el col·loca a la dreta de Byte desplaçant els que ja hi són
	goto		SegTran		; Esperem el següent bit
	end

 

 

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