Programació en mpasm del PIC 16F690

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

Exemple NT - Fem sonar notes musicals amb interrupcions

En aquest exemple farem servir interrupcions creades pel timer 2 per fer sonar unes notes musicals en un brunzidor piezoelèctric o un altaveu.

El següent programa toca la seqüència do - re - mi. Després de la darrera nota, fa una pausa de 0,2 s i torna a començar el bucle.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock	0x20
valPre			; Valor que posarem com a prescala (0 a 3)
valPos			; Valor que posarem com a postescala (0 a 15)
valPR2			; Valor que carregarem a PR2
numbuc			; Nombre de cicles per fer 0,2 s
bucles			; Comptador de cicles
numsil			; Nombre de cicles per al silenci
temp			; Variable temporal de la funció TocaNota
control			; Variable de control de la funció TocaNota
			; Si és 0 nota, si és 1 silenci
port			; Variable per gestionar el port C
	endc
	cblock 0x70	; Zona de memòria de dades que no depèn del banc triat
W_Copia			; Guardarà el contingut de W durant la interrupció
ST_Copia		; Guardarà STATUS durant la interrupció
	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
	btfss	PIR1,TMR2IF	; Mira si Timer2 ha arribat a zero
				; Si hi ha arribat, no fa la instrucció següent
	goto	FiInt		; Si la interrupció no és del Timer0 no fem res
Timer2				; Programa corresponent a Timer2
	bcf	PIR1,TMR2IF	; Si ha arribat, desactivem el bit
	movf	control,f	; Mirem si estem fent sonar la nota
	btfss	STATUS,Z
	goto	TN1		; Si és 1 no invertim la sortida
	movlw	b'00100000'	; RC5 correspon al brunzidor
	xorwf	port,f		; Inverteix el bit
	movf	port,w		; Agafa port
	movwf	PORTC		; i ho copia al port C
TN1
	decfsz	bucles,f	; Comptador per a la durada de la nota
	goto	FiInt		; Si no ha arribat a zero, ja hem acabat la interrupció
	movf	control,f	; Mirem si estem fent sonar la nota
	btfss	STATUS,Z
	goto	TN2		; Si estem en silenci vol dir que ja hem acabat
	bcf	port,5		; A l'acabar, deixa la sortida desactivada
	movf	port,w
	movwf	PORTC		; i ho copia al port C
	movf	numsil,w	; Agafem la durada del silenci
	btfsc	STATUS,Z
	goto	TN2		; Si el valor és zero no hi haurà silenci
	movwf	bucles		; Nova durada del cicle
	movlw	.1		; Estem en silenci
	movwf	control
	goto	FiInt		; Comença el silenci
TN2
	bcf	T2CON,TMR2ON	; Desactivem el Timer2
	bsf	STATUS,RP0	; Tria el banc 1
	bcf	PIE1,TMR2IE	; Desactivem les interrupcions per Timer2
	bcf	STATUS,RP0	; Tria el banc 0
FiInt
	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
	bsf	STATUS,RP0	; Tria el banc 1
	clrf	TRISC		; Tot el port C és de sortida
	bcf	STATUS,RP0	; Tria el banc 0
	clrf	port
	clrf	PORTC		; Desactiva les sortides del port C
	movlw	b'11000000'	; Activa GIE i PEIE
	movwf	INTCON		; Activa les interrupcions a nivell general i les de PIE1
Bucle
	movlw	.0		; Valors que correspon aproximadament a do3
	movwf	valPre		; Prescalador
	movlw	.7
	movwf	valPos		; Postescalador
	movlw	.239
	movwf	valPR2		; Valor per a PR2
	movlw	.105
	movwf	numbuc		; Nombre de cicles per fer 0,2 s
	clrf	numsil		; Les notes van seguides
	call	TocaNota	; Toca la nota configurada
	movlw	.0		; Valors que correspon aproximadament a re3
	movwf	valPre		; Prescalador
	movlw	.6
	movwf	valPos		; Postescalador
	movlw	.213
	movwf	valPR2		; Valor per a PR2
	movlw	.117
	movwf	numbuc		; Nombre de cicles per fer 0,2 s
	clrf	numsil		; Les notes van seguides
	call	TocaNota	; Toca la nota configurada
	movlw	.0		; Valors que correspon aproximadament a mi3
	movwf	valPre		; Prescalador
	movlw	.5
	movwf	valPos		; Postescalador
	movlw	.190
	movwf	valPR2		; Valor per a PR2
	movlw	.132
	movwf	numbuc		; Nombre de cicles per fer 0,2 s
	movwf	numsil		; Silenci de 0,2 s
	call	TocaNota	; Toca la nota configurada
	goto	Bucle
				;
				; Funció per tocar una nota
				; valPre	Valor que posarem com a prescala (0 o 1)
				; valPos	Valor que posarem com a postescala (0 a 15)
				; valPR2	Valor que carregarem a PR2
				; numbuc	Nombre de cicles per fer 0,2 s
				; Aquestes variables no es modifiquen si estan dins el rang
TocaNota
	btfsc	T2CON,TMR2ON	; Mira si està activat el Timer2
	goto	TocaNota	; Mentre sona una nota no podem tocar una altra
	movlw	b'00001111'
	andwf	valPos,f	; Per precaució, posem a zero els altres bits
	movf	valPos,w	; Agafa el valor del postescalat
	movwf	temp		; El guarda a la variable temporal
	rlf	temp		; Posicionem el postescalat al seu lloc
	rlf	temp
	rlf	temp
	movlw	b'00000011'
	andwf	valPre,f	; Per precaució, posem a zero els altres bits
	movf	valPre,w	; Agafa el valor del prescalat
	iorwf	temp,w		; El combina amb el postescalador
	movwf	T2CON		; Ho posa a la configuració del Timer2
	movf	valPR2,w	; Agafa la preselecció de PR2
	bsf	STATUS,RP0	; Tria el banc 1
	movwf	PR2		; I la posa al seu lloc
	bcf	STATUS,RP0	; Tria el banc 0
	movf	numbuc,w	; Agafa el nombre de cicles
	movwf	bucles		; I el posa al seu lloc
	clrf	control		; Comencem tocant la nota
	bsf	STATUS,RP0	; Tria el banc 1
	bsf	PIE1,TMR2IE	; Activem les interrupcions per Timer2
	bcf	STATUS,RP0	; Tria el banc 0
	bsf	T2CON,TMR2ON	; Activem el Timer2
	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.