Programació en mpasm del PIC 16F690

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

Sensor de so

En realitat es tracta d'un micròfon i un petit amplificador muntat en una placa, com aquest que permet ajustar l'amplificació del senyal.

Sensor de so  [AF]

El sensor es connecta amb tres fils: els d'alimentació (positiu, VCC, i negatiu, GND) i el de senyal que connectarem a una entrada analògica.

El sensor ens dona una lectura proporcional al senyal de so, que és una ona. Atès que les entrades analògiques només admeten tensions positives, el sensor suma la meitat de la tensió d'alimentació al senyal de sortida. Això vol dir que en silenci llegirem un valor de 511 i quan hi ha so tindrem valors que oscil·laran al voltant d'aquest nombre. En el nostre cas connectarem el sensor a l'entrada AN8 (pota RC6). En la figura, tenim un exemple d'una ona de so que té la mitjana al voltant de 511 (com és esperable), un valor màxim de l'ordre de 780 i un valor mínim de l'ordre de 230.

Exemples de valors llegits

Farem un programa de prova que ens permeti llegir 32 valors del sensor durant un temps de 20 ms. Els valors llegits els mostrarem a una pantalla LCD. Si dividim els 20 ms en 32 parts ens surt que cal llegir un valor cada 625 μs. Per comptar el temps farem servir el Timer 0. Ens interessa posar-li un factor de configuració que tingui el màxim nombre d'iteracions possible (per tenir la màxima precisió) però que sigui inferior a 256. La presselecció que candrà posar-hi serà la diferència entre 256 i el nombre d'iteracions. Veiem algun cas:

Bits Escala Període Iteracions Preselecció
111 1/256 256 μs 2 254
... ... ... ... ...
010 1/8 8 μs 78 178
001 1/4 4 μs 156 100
000 1/2 2 μs 313 ---

Ens quedem amb el penúltim valor. El temporitzador partirà d'un valor de 100 i s'anirà incrementant cada 4 μs. Quan arribi a zero hauran passat 624 μs. Cada cop que el temporitzador acabi de comptar el reiniciarem, llegirem l'entrada analògica i guardarem el resultat a la memòria. Llegirem 32 valors de dos bytes cada un; en total 64 bytes. Quan l'usuari premi el polsador, escriurem els 32 valors llegits a la pantalla. Inicialment els quatre primers a la primera línia (quatre caràcters per valor) i els quatre següents a la segona; amb això en tindrem 8. Quan premem el polsador n'escriurem 8 més i així fins que al quart cop ja els haurem escrit tots.

El programa principal i les subfuncions BCD5 i Separa fan servir adreçament indirecte sobre adreces diferents. Per evitar conflictes cal guardar els contingut de FSR a una variable (Indir) a l'entrar a la funció i recuperar-lo al moment de sortir.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
Lectura:.64		; Lectures 
Comptador		; Comptador d'iteracions programa principal
Compta			; Comptador d'iteracions funció Linia
Compt			; Comptador d'iteracions subfuncions BCD5 i Separa
Temp			; Variable temporal
Indir			; Variable temporal per guardar FSR
Valor:2			; Valor d'entrada (16 bits)
Resul:5			; Valor de sortida 
Caracter		; Caràcter o codi a enviar
Retard1			; Variables per als cicles de retard
Retard2
	endc
	org 0
Inici
	bsf		STATUS,RP0	; Tria el banc 1
	movlw		b'10000001'	; Configuració de Timer0
					; Com a temporitzador basat en rellotge
					; 001 - Factor d'escala de 4
					; I resistències de pull-up desactivades (valor per defecte)
	movwf		OPTION_REG	; Ho guarda al registre de configuració del Timer0
	movlw		0xFF		; Posa l'acumulador a FFh (tot uns)
	movwf		TRISA		; Posa tots els bits del port A com a entrada
	clrf		TRISB		; Tot el port B és de sortida
	movlw		b'01000000'	; Posa RC6 (AN8) com a entrada
	movwf		TRISC		; La resta del port C és de 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
	bsf		TXSTA,BRGH	; Configuració de velocitat
	bcf		BAUDCTL,BRG16	; Paràmetre de velocitat de 8 bits
	movlw		.25		; Velocitat de 9600 baud
	movwf		SPBRG		; Paràmetre de velocitat
	bcf		TXSTA,SYNC 	; Comunicació asíncrona
	bcf		TXSTA,TX9 	; Comunicació de 8 bits
	bcf		STATUS,RP0	; Tria el banc 0
	bsf		RCSTA,SPEN	; Activa comunicació sèrie
	bsf		STATUS,RP0	; Tria el banc 1
	bsf		TXSTA,TXEN 	; Activa comunicació
	bcf		STATUS,RP0	; Tria el banc 0
	bsf		STATUS,RP1	; Tria el banc 2
	movlw		b'00000001'
	movwf		ANSEL		; Configura port AN0 com entrada analògica
	movlw		b'00000001'
	movwf		ANSELH		; Configura port AN8 com entrada analògica
	bcf		STATUS,RP1	; Tria el banc 0
	clrf		PORTB		; Desactiva les sortides del port B
	clrf		PORTC		; Desactiva les sortides del port C
	movlw		'P'		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'r'		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'e'		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'm'		; Lletra
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		b'10100001'	; activa el conversor A/D connectat a AN8
	movwf		ADCON0		; amb el resultat justificat per la dreta
	clrw				; Dos bucles de 0,2 s
	call		Retard		; Crida a la funció Retard, el paràmetre està a W
	call		Retard		; Per assegurar la desconnexió del programador
	movlw		.100		; Presselecció de 100, que són 156 iteracions
					; (amb un factor 4 dona 624)
	movwf		TMR0		; Ho posa com a preselecció del temporitzador
	bcf		INTCON,T0IF	; Desactivem el bit de final de temporització
	movlw		.32		; Volem 32 iteracions (32 lectures)
	movwf		Comptador	; Comptador d'iteracions
	movlw		Lectura		; Agafa l'adreça de la memòria de lectures
	movwf		FSR		; Adreçament indirecte
Bucle
	movlw		.100		; Presselecció de 100, que són 156 iteracions
					; (amb un factor 4 dona 624)
	btfss		INTCON,T0IF	; Mira si Timer0 ha arribat a zero
					; Si hi ha arribat, no fa la instrucció següent
	goto		$-1		; Si no hi ha arribat, repeteix la instrucció
	movwf		TMR0		; Posa el 100 com a preselecció del temporitzador
	bcf		INTCON,T0IF	; Si ha arribat, desactivem el bit
	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
	bsf		STATUS,RP0	; Tria el banc 1
	movf		ADRESL,w	; Llegim byte inferior del resultat
	bcf		STATUS,RP0	; Tria el banc 0
	movwf		INDF		; El guardem
	incf		FSR,f		; Incrementem punter
	movf		ADRESH,w	; Llegim byte superior del resultat
	movwf		INDF		; El guardem
	incf		FSR,f		; Incrementem punter
	decfsz		Comptador,f	; Decrementem el comptador	
	goto		Bucle		; Repetim-ho...
					; Acabada la lectura, anem a mostrar els resultats
	movlw		.4		; A cada pantalla hi caben 1/4 dels resultats
	movwf		Comptador	; Comptador d'iteracions (quatre pantalles de 8 valors)
	movlw		Lectura		; Agafa l'adreça de la memòria de lectures
	movwf		FSR		; Adreçament indirecte
Bucle4
	btfsc		PORTA,3		; Mira el polsador
	goto		$-1		; Espera a que estigui premut
	clrw				; Bucle de 0,2 s
	call		Retard		; Crida a la funció Retard, el paràmetre està a W
	btfss		PORTA,3		; Mira el polsador
	goto		$-1		; Espera a que no estigui premut
	clrw				; Bucle de 0,2 s
	call		Retard		; Crida a la funció Retard, el paràmetre està a W
	movlw		.254		; Control de la posició del cursor
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		.1		; Esborra la pantalla
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	call		Linia		; Escriu els de la primera línia (4 valors)
	movlw		.254		; Control de la posició del cursor
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		.64		; Filera 2 columna 1
	iorlw		b'10000000'	; Posa el bit de posicionat a 1
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	call		Linia		; Escriu els de la segona línia (4 valors més)
	decfsz		Comptador,f	; Decrementem el comptador	
	goto		Bucle4		; Repetim-ho...
	goto		$	
					;	
					; funcions d'escriptura a la pantalla
					;	
Linia					; Escriu una línia de la pantalla (la primera adreça a W)
	movlw		.4		; Volem 4 iteracions (4 lectures)
	movwf		Compta		; Comptador d'iteracions
BucleLin
	movf		INDF,w		; Byte inferior
	movwf		Valor		; Variable per a convertir a BCD
	incf		FSR,f		; Incrementem punter
	movf		INDF,w		; Byte superior
	movwf		Valor+1		; Variable per a convertir a BCD
	incf		FSR,f		; Incrementem punter
	call		BCD5		; Ho convertim a BCD
	call		Separa		; Ho separem en 5 bytes
	movf		Resul+3,w	; Llegeix el caràcter
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf		Resul+2,w	; Llegeix el caràcter
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf		Resul+1,w	; Llegeix el caràcter
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf		Resul,w		; Llegeix el caràcter
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	decfsz		Compta,f	; Decrementa el comptador
	goto		BucleLin	; Si no és zero, seguim
	return
					;
					; Enviem caràcters a visualitzar
					;
EnviaL	
	movf		Caracter,f	; Agafa el caràcter
	movwf		TXREG		; L'envia
	nop			
	nop				; Espera 2 us
	btfss		PIR1,TXIF	; El registre TXREG ha quedat lliure?
	goto		$-1		; No, doncs esperem
	return				; Tornem al lloc des d'on hem vingut
					;	
					; Bucles de retard
					;	
Retard					; Funció Retard, W conté
					; el nombre de cicles de 771 us que cal fer
	movwf		Retard2		; Ho copia a la variable Retard2
BucRet	
	decfsz		Retard1,f	; Decrementa la variable 1
					; si dona zero, no es fa la instrucció següent
	goto		BucRet		; Salta, excepte si el resultat ha estat zero
	decfsz		Retard2,f	; Decrementa la variable 2
	goto		BucRet		; Salta, excepte si el resultat ha estat zero
	return				; Tornem al lloc des d'on hem vingut
					;	
					; funcions de conversió a BCD
					;	
BCD5					; Converteix a BCD
	movf		FSR,w		; Llegim el valor de FSR
	movwf		Indir		; I el guardem
	bcf		STATUS,C	; Posa a zero C per entrar zeros a les rotacions
	movlw		.16		; Nombre d'iteracions
	movwf		Compt		; Comptador d'iteracions
	clrf		Resul+2		; Desenes de miler 
	clrf		Resul+1		; Unitats de miler i centenes
	clrf		Resul		; Desenes i unitats
BucleBCD
	rlf		Valor,f		; Girem bits a l'esquerra a valor
	rlf		Valor+1,f	; Cap a valor+1
	rlf		Resul,f		; I cap als resultats
	rlf		Resul+1,f
	rlf		Resul+2,f
	decfsz		Compt,f		; Decrementa Compt
	goto		ajust		; Si no és zero, ajustem el resultat
	movf		Indir,w		; Recuperem el valor de FSR
	movwf		FSR		; I el guardem al seu lloc
	retlw		0		; Si és zero ja estem; tornem un 0 a W
ajust					; funció d'ajust dels resultats
	movlw		Resul		; Agafem l'adreça del byte de menys pes
	movwf		FSR		; La posa a l'adreçament indirecte
	call		ajustBCD	; Ajusta el byte de més a la dreta
	movlw		Resul+1		; Agafem l'adreça del byte del mig
	movwf		FSR		; La posa a l'adreçament indirecte
	call		ajustBCD	; Ajusta el byte del mig
	movlw		Resul+2		; Agafem l'adreça del byte de més pes
	movwf		FSR		; La posa a l'adreçament indirecte
	call		ajustBCD	; Ajusta el byte de més a l'esquerra
	goto		BucleBCD	; Torna a repetir el bucle (fins a 16 cops)
ajustBCD				; funció d'ajust d'un byte, primer el nibble
				; de la dreta, després l'altre
	movlw		0x03		; Agafa el valor 03h
	addwf		INDF,w		; El suma al byte que ajustem
	movwf		Temp		; Ho guarda a Temp
	btfsc		Temp,3		; És més gran que 07h (s'ha activat el bit 3)?
	movwf		INDF		; Si és cert, sobreposa el resultat
	movlw		0x30		; Agafa el valor 30h
	addwf		INDF,w		; El suma al byte que ajustem
	movwf		Temp		; Ho guarda a Temp
	btfsc		Temp,7		; És més gran que 70h (s'ha activat el bit 7)?
	movwf		INDF		; Si és cert, sobreposa el resultat
	retlw		0		; Retorna amb un zero a W
					;	
					; funcions de conversió a ASCII
					;	
Separa					; Separa els digits i els converteix a ASCII
	movf		FSR,w		; Llegim el valor de FSR
	movwf		Indir		; I el guardem
	movf		Resul+2,w	; Agafa les desenes de miler
	movwf		Resul+4		; Les posa al seu lloc
	swapf		Resul+1,w	; Llegeix les unitats de miler i les centenes i les
					; guarda, permutades, a w
	andlw		0x0F		; Es queda amb les unitats de miler
	movwf		Resul+3		; Les posa al seu lloc
	movf		Resul+1,w	; Llegeix les unitats de miler i les centenes i
					; les guarda a w
	andlw		0x0F		; Es queda amb les centenes
	movwf		Resul+2		; Les posa al seu lloc
	swapf		Resul,w		; Llegeix les desenes i les unitats i les
					; guarda, permutades, a w
	andlw		0x0F		; Es queda amb les desenes
	movwf		Resul+1		; Les posa al seu lloc
	movf		Resul,w		; Llegeix les desenes i les unitats i les guarda a w
	andlw		0x0F		; Es queda amb les unitats
	movwf		Resul		; Les posa al seu lloc
	movlw		.5		; Cal fer-ho 5 cops
	movwf		Compt		; Ho posem al comptador
	movlw		Resul+4		; Adreça de la darrera xifra
	movwf		FSR		; Adreçament indirecte
	movlw		'0'		; Carrega el codi ASCII del número 0
					; Sumant-li la xifra tindrem el codi ASCII
Bucle1
	addwf		INDF,f		; Ho afegeix al dígit
	decf		FSR,f		; Decrementa FSR
	decfsz		Compt,f		; Decrementa el comptador
	goto		Bucle1		; Si no és zero, repetim
	movlw		.4		; Cal fer-ho 4 cops
	movwf		Compt		; Ho posem al comptador
	movlw		Resul+4		; Adreça de la darrera xifra
	movwf		FSR		; Adreçament indirecte
Bucle2
	movf		INDF,w		; Llegeix el dígit
	xorlw		'0'		; Compara amb 0
	btfss		STATUS,Z	; Si Z està activat eren iguals
	goto		Final		; Si no eren iguals, ja estem
	movlw		' '		; Carrega un espai en blanc
	movwf		INDF		; Substitueix el 0 per l'espai
	decf		FSR,f		; Decrementa FSR
	decfsz		Compt,f		; Decrementa el comptador
	goto		Bucle2		; Si no és zero, repetim
Final
	movf		Indir,w		; Recuperem el valor de FSR
	movwf		FSR		; I el guardem al seu lloc
	retlw		0		; Retorna amb un 0 a W
	end

 

 

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