Pic 16f876-Ejercicios y Practicas 2003-2004

48
ESCUELA UNIVERSITARIA POLITÉCNICA MICROPROCESADORES EJERCICIOS Y PRÁCTICAS 2003 / 2004 Rubén Bartolomé Henares

description

Ejercicios y Practicas 2003-2004

Transcript of Pic 16f876-Ejercicios y Practicas 2003-2004

Page 1: Pic 16f876-Ejercicios y Practicas 2003-2004

ESCUELA UNIVERSITARIA POLITÉCNICA

MICROPROCESADORES

EJERCICIOS Y PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares

Page 2: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN I

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN I

2003 / 04

EJERCICIO 1: Código fuente

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

RESULTADO equ 0x20 ;Asigna la etiqueta "RESULTADO" a la dirección 0x20.

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio movlw d’7’ ;Carga 7 en el acumulador. addlw d’12’ ;Suma 12 al contenido del acumulador y lo guarda en él. movwf RESULTADO ;Deposita el contenido del acumulador en "RESULTADO". end ;Paro. También se puede emplear "sleep" o un bucle.

Page 3: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN I

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN I

2003 / 04

EJERCICIO 2: Código fuente ; Esta ALU solo sabe emplear como registro negativo el acumulador (W). De forma que para ; realizar la operación sumaremos primero A+B y lo guardaremos en una dirección de ; memoria "RESULTADO" para, posteriormente, cargar C en el acumulador y restárselo a ; RESULTADO mediante la instrucción "subwf": resta del registro F la cantidad contenida ; en W.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

DATOA equ 0x20 DATOB equ 0x21 DATOC equ 0x22 RESULTADO equ 0x23

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio movf DATOA,W ;Dato A al acumulador. addwf DATOB,W ;Sumo al acumulador el dato B. La suma A+B está en W. movwf RESULTADO ;Envío el contenido del acumulador a "RESULTADO". movf DATOC,W ;Envío el dato C al acumulador. subwf RESULTADO,F ;Resta del registro RESULTADO el contenido del

;acumulador y guárdalo en RESULTADO. end ; Si realizásemos el programa sin etiquetas: inicio movf 0x20,0 ;Dato A al acumulador addwf 0x21,0 ;Sumo al acumulador el dato B. La suma A+B está en W movwf 0x23 ;Envío el contenido del acumulador a "RESULTADO" movf 0x22,0 ;Envío el dato C al acumulador subwf 0x23,1 ;Resta del registro RESULTADO el contenido del

;acumulador y guárdalo en RESULTADO end ; Cuando ponemos en una instrucción W ó F en realidad lo que estamos escribiendo es el ; bit de dirección d, y habría que poner 0 (hacia el acumulador) ó 1 (hacia el registro) ; como se ha visto en teoría. El ensamblador no tendrá problemas en compilar el código ; gracias a las definiciones de registros internos. En "p16f876.inc" hay definidas unas ; etiquetas: w equ 0 y f equ 1 que facilitan al programador la escritura del código.

Page 4: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN I

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN I

2003 / 04

EJERCICIO 3: Código fuente ; Deberemos tener en cuenta que las palabras de 16 bits ocupan dos posiciones de memoria ; y deberemos tener en cuenta también si existe acarreo. Para ello cuestionaremos el bit ; "carry" del registro STATUS.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

A_H equ 0x20 A_L equ 0x21 B_H equ 0x22 B_L equ 0x23 SOL_H equ 0x24 SOL_L equ 0x25

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio movf A_L,W ;Sumo las partes bajas de los addwf B_L,W ;números A y B y guardo el movwf SOL_L ;resultado en SOL_L movf A_H,W ;Llevo la parte alta de A al acumulador btfsc STATUS,0 ;Cuestiono si se ha producido acarreo (carry=1)en la

addlw d’1’ ;suma anterior. Si carry=0 salta una instrucción y ;sigue con el resto de la suma, sino suma 1 (acarreo) ;a A_H

addwf B_H,W ;Sumo al acumulador la parte alta de B movwf SOL_H ;y lo guardo en SOL_H end ; Caso con acarreo: * Nota: Cuando escribimos "STATUS,0" o cualquier otro registro, nos estamos refiriendo al bit 0 de ese registro (en este caso el bit de carry).

A_H A_L

B_H B_L

SOL_H SOL_L

+ 1

1

0

1 C (acarreo)

Page 5: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN I

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN I

2003 / 04

EJERCICIO 4: Código fuente ; Básicamente el código es el mismo, pero deberemos recordar de teoría que el bit carry ; se interpreta como: 1 = se ha producido acarreo en el 8º bit ; 0 = no se ha producido acarreo ; Pero esto es para la suma. Si estamos restando, el bit carry se interpreta de forma ; inversa, es decir: 1 = no hay acarreo ; 0 = se ha producido acarreo en el 8º bit ; En este ejercicio deberemos emplear la instrucción "btfss" en vez de "btfsc". ; Deberemos tener cuidado al utilizar el bit C e interpretarlo convenientemente.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

A_H equ 0x20 A_L equ 0x21 B_H equ 0x22 B_L equ 0x23 SOL_H equ 0x24 SOL_L equ 0x25

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio movf B_L,W ;Resto las partes bajas de subwf A_L ;los registros A y B y guardo movwf SOL_L ;el resultado en SOL_L. movf B_H,W ;Llevo la parte baja de B al acumulador. btfss STATUS,0 ;Cuestiono si se ha producido acarreo. addlw d’1’ ;Si se ha producido sumo 1 al acumulador (a B_H). subwf A_H,W ;Resto la parte alta de A del acumulador movwf SOL_H ;y lo guardo en SOL_H. end

Page 6: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN I

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN I

2003 / 04

EJERCICIO 5: Código fuente ; Se puede realizar de dos formas diferentes: direccionamiento directo e indirecto. ; Con el direccionamiento directo cargaríamos el valor 0x33 en el acumulador y mediante ; la instrucción "movwf" lo llevaríamos a las 15 posiciones de memoria, pero el ; inconveniente es que deberíamos escribir la instrucción 15 veces. Esto no es muy ; económico. En estos casos se emplea el direccionamiento indirecto: ; Se emplearán los registros FSR e INDF. El registro FSR actúa como puntero, de forma ; que una instrucción que utilice el registro INDF accede al dato que se encuentra en ; la dirección a la que apunta FSR.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

CONT equ 0x70 ;Asignamos a CONT una dirección que no coincida con las

;que tenemos que escribir. Por ejemplo, 0x70.

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio movlw d’15’ ;Cargamos 15 en el acumulador. movwf CONT ;Asignamos el valor 15 a la variable CONT. movlw 0x20 ;Con esto conseguimos que el registro de movwf FSR ;direccionamiento indirecto apunte a la dirección 0x20. movlw 0x33 ;Cargamos en INDF el contenido 0x33, de forma que uno movwf INDF ;lo guardará en la dirección a la que apunte FSR. incf FSR,F ;Apunto a la siguiente dirección a escribir. decfsz CONT,F ;Decremento el contador y mientras no sea cero goto uno ;vuelvo a realizar la operación. end ;Si es cero, acabo el programa.

Page 7: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN I

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN I

2003 / 04

EJERCICIO 9: Código fuente ; Nos ayudaremos mediante una subrutina que llamará a una tabla donde se encontrarán ; contenidos los números en código gray.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

BIN equ 0x20 GRAY equ 0x21

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio movf BIN,W ;Llevo el valor en binario al acumulador call tabla ;Llamo a la subrutina de conversión movwf GRAY ;Aquí retorna la subrutina guardando el valor en código

;gray en el registro GRAY tabla addwf PCL,F ;Suma al PCL el contenido del acumulador ; Al ejecutar esta última instrucción el contador de programa en vez de apuntar a la ; dirección siguiente (+1) apunta a la dirección +(1 + contenido del W) retlw b’00000000’ ;retorna al programa principal con el número 0 en gray

;guardado en el acumulador retlw b’00000001’ ;número 1 en gray retlw b’00000011’ ;número 2 en gray retlw b’00000010’ ;número 3 en gray retlw b’00000110’ ;número 4 en gray retlw b’00000111’ ;número 5 en gray retlw b’00000101’ ;número 6 en gray retlw b’00000100’ ;número 7 en gray retlw b’00001100’ ;número 8 en gray retlw b’00001101’ ;número 9 en gray · · · · · · · · · · · · ;Como no nos especifican el tamaño de la tabla, la podemos hacer todo lo grande que ;queramos, pero con cuidado de no sobrepasar las 256 posiciones, ya que sino nos ;pasaríamos de página.

Page 8: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 1: Código fuente

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw b’00000110’ ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b’00000001’ ;Configurar en el puerto A movwf TRISA ;como entrada la patilla RA0. clrf TRISB ;Configurar puerto B como salida. Solo necesitamos RB0

;y RB1 como salidas. Como estén las demás es da igual, ;pero borrando todas nos ahorramos una instrucción.

bcf STATUS,RP0 ;Vuelvo al banco 0.

uno btfss PORTA,RA0 ;Cuestiono el valor de RA0. goto dos ;Si es cero voy a "dos", y bsf PORTB,RB0 ;si es uno enciendo el led de la patilla RB0 bcf PORTB,RB1 ;y apago el led de la patilla RB1 (valor negado). goto uno ;Vuelvo a cuestionar

dos bcf PORTB,RB0 ;Apago el led de la patilla RB0 y bsf PORTB,RB1 ;enciendo el led de RB1 (valor negado). goto uno ;Vuelvo a cuestionar el valor.

end

Page 9: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 2: Otro posible diagrama:

Borrar el puerto B

RA1=0?

Inicializar el puerto B como salida y el A como entrada

Leer dato del puerto A

RA0=0?

Escribir en el

puerto B ‘01010101’

SI

Escribir en el

puerto B ‘10101010’

SI NO RA0=0?

Escribir en el

puerto B ‘11110000’

Escribir en el

puerto B ‘00001111’

SI NO

NO

Ejercicio 2

00 01 10 11

Page 10: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 2: Código fuente

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw b’00000110’ ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b’00000011’ ;Configurar en el puerto A como movwf TRISA ;entradas las patillas RA1 y RA0.

clrf TRISB ;Configurar puerto B como salida (todas las patillas). bcf STATUS,RP0 ;Vuelvo al banco 0.

uno btfsc PORTA,RA1 ; goto tres ;Si RA1 es uno, voy a "tres". btfsc PORTA,RA0 ; goto dos ;Si RA0 es uno, voy a "dos". movlw b’10101010’ ;Si RA0 es cero envío el movwf PORTB ;valor al puerto B goto uno ;y vuelvo a "uno". dos movlw b’01010101’ ;Como RA0 es uno, envío el valor movwf PORTB ;correspondiente al puerto B. goto uno ;Vuelvo a "uno". tres btfsc PORTA,RA0 ; goto cuatro ;Si RA0 es uno voy a "cuatro". movlw b’00001111’ ;Si RA0 es cero envío el valor movwf PORTB ;correspondiente al puerto B. goto uno ;Vuelvo a "uno". cuatro movlw b’11110000’ ;Si RA0 es uno envío el valor movwf PORTB ;correspondiente al puerto B. goto uno ;Vuelvo a "uno". end

Page 11: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 3: Código fuente

;suponemos que RB0=1 ;saca el cilindro (avance) ;y RB0=0 lo mete (retroceso).

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw b’00000110’ ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b’00001111’ ;Configurar en el puerto A como entradas movwf TRISA ;las patillas RA3, RA2, RA1 y RA0.

clrf TRISB ;Configurar puerto B como salida (solo usamos RB2, RB1 ;y RB0). Borramos todas y ahorramos una instrucción

bcf STATUS,RP0 ;Vuelvo al banco 0.

uno btfss PORTA,RA0 ;Comprobar si se ha pulsado el pulsador de marcha. goto uno bcf PORTB,RB2 ;Zumbador está en off (apagado). bsf PORTB,RB0 ;El cilindro avanza e introduce la pieza. dos btfss PORTA,RA2 ;Comprobar si el sensor "b" está activado. goto dos bsf PORTB,RB1 ;Se activa el motor y comienza el torneado. tres btfss PORTA,RA3 ;Comprobar si la pieza ha llegado al final de carrera. goto tres bcf PORTB,RB0 ;El cilindro comienza el retroceso. cuatro btfss PORTA,RA2 ;Comprobar si la pieza pasa por el sensor

;de paro del motor. goto cuatro bcf PORTB,RB1 ;Se para el motor. cinco btfss PORTA,RA1 ;Comprobar si la pieza ha vuelto a su posición inicial. goto cinco bsf PORTB,RB2 ;Se activa la señal acústica (zumbador on). goto uno ;Comenzar de nuevo. end

Motor M

PIEZA

RA2

bRA1

aRA3

c

RB0

V

RB2

A

RA0 l

RB1

cuña

Page 12: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 4: Código fuente

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw b’00000110’ ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b’00000011’ ;Configurar en el puerto A como movwf TRISA ;entradas las patillas RA1 y RA0.

clrf TRISB ;Configurar puerto B como salida (todas las patillas) bcf STATUS,RP0 ;Vuelvo al banco 0.

leer0 btfss PORTA,RA0 ;Cuestiono el valor de RA0. goto cero ;Si es cero voy a "cero". Sino, movlw b’00000110’ ;envío la codificación en binario del número 1 al movwf PORTB ;puerto B para visualizarlo en el display. goto leer1 ;Paso a leer el bit RA1. cero movlw b’00111111’ ;Envío la codificación del número 0 movwf PORTB ;al display conectado en el puerto B. leer1 btfss PORTA,RA1 ;Cuestiono el valor de RA1. goto puntooff bsf PORTB, RB7 ;Enciendo el punto digital. goto leer0 ;Vuelvo a comenzar. puntooff bcf PORTB,RB7 ;Borro el punto digital del display. goto leer0 ;Comienzo de nuevo. end ; Se podría pensar que sería preciso desactivar las resistencias de pull-up del ; puerto B, pero esto no es necesario ya que éstas resistencias se desactivan ; automáticamente cuando las patillas del puerto B están configuradas como salida.

Page 13: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 5: Código fuente

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw b’00000110’ ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b’00001111’ ;Configurar en el puerto A como entradas movwf TRISA ;las patillas RA3, RA2, RA1 y RA0.

clrf TRISB ;Configurar puerto B como salida (todas las patillas) bcf STATUS,RP0 ;Vuelvo al banco 0.

uno movf PORTA,W ;Cargamos en el acumulador el valor del puerto A. andlw b’00001111’ ;Realizamos un enmascaramiento AND. ; Realizamos un enmascaramiento AND a las patillas RA3:RA0 de forma que, los bits no ; empleados valdrán cero, y los que utilizamos mantendrán su valor. Nos aseguramos así ; que, aunque halla algún valor en las patillas RA7:RA4 (no utilizadas), éste quedará ; "enmascarado" y valdrá cero ; ; PORTA RA7 RA6 RA5 RA4 RA3 RA2 RA1 RA0 ; -------------------------------- enmascaramiento AND ; 0 0 0 0 RA3 RA2 RA1 RA0 ; ; Me quedo con el valor de los últimos cuatro bits call tabla ;Llamo a la subrutina. movwf PORTB ;Llevo el valor codificado en 7 segmentos al display. goto uno tabla addwf PCL,F ;Sumo el contenido del acumulador al PC.

retlw b'00000110' ;número 1 en hexadecimal. retlw b'01011011' ;número 2 en hexadecimal. retlw b'01001111' ;número 3 en hexadecimal. retlw b'01100110' ;número 4 en hexadecimal. retlw b'01101101' ;número 5 en hexadecimal. retlw b'01111101' ;número 6 en hexadecimal. retlw b'00000111' ;número 7 en hexadecimal. retlw b'01111111' ;número 8 en hexadecimal. retlw b'01101111' ;número 9 en hexadecimal. retlw b'01110111' ;número A en hexadecimal. retlw b'01111100' ;número B en hexadecimal. retlw b'00111001' ;número C en hexadecimal. retlw b'01011110' ;número D en hexadecimal. retlw b'01111001' ;número E en hexadecimal. retlw b'01110001' ;número F en hexadecimal. end

Page 14: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 6: Código fuente ; Para realizar la temporización vamos a crear una subrutina que temporice 10 mseg y la ; repetiremos 50 veces con la ayuda de un contador.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

CONTADOR equ 0x20 ;Contador.

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción.

inicio bsf STATUS,RP0 ;Paso al banco 1 para modificar el registro ;OPTION_REG.

bcf OPTION_REG,T0CS ;Selecciono el TMR0 como temporizador. bcf OPTION_REG,PSA ;Asignamos el pre-divisor de frecuencias al

;módulo del temporizador TMR0.

;Comentario: ; ·Éstas dos instrucciones no se han realizado moviendo un literal ya que cuando se ; produce un reset el registro OPTION_REG posee todos sus bits a 1. Solo nos hará falta ; borrar aquellos bits que deban estar a cero. Se podría hacer moviendo un literal. bcf STATUS,RP0 ;Vuelvo al banco 0. movlw d’50’ ;Cargo el valor 50 para la repetición de la secuencia movwf CONTADOR ;en el registro "CONTADOR". uno bcf INTCON,T0IF ;Borrar el bit T0IF. ; ¡Importante!: Esta última operación se debe realizar siempre por programa aunque en ; teoría no haría falta, ya que al producirse un reset todos los bits de INTCON se ; ponen a cero. Es preferible incluirla siempre. ; Ahora hay que calcular el valor a cargar en el TMR0. Este calculo debe realizarse a ; mano. Sabemos que la ecuación que define la temporización para el TMR0 es: ; ; T = 4·Tosc·(256 - carga)·pre-escala ; ; Si despejamos la carga: ; T ; carga = 256 - ------------------- ; 4·Tosc·pre-escala ; ; La temporización que deseamos es T=10mseg. La pre-escala viene definida por el estado ; de los bits PS2, PS1 y PS0 del registro OPTION_REG. Los tres poseerán el valor 1 ya ; que, como se ha comentado, después de un reset todos los bits de OPTION_REG se ponen a ; uno. Se estará cargando, por tanto, y según el rango de funcionamiento del ; pre-divisor, el valor 256; luego pre-escala = 256 (Si se deseara otra pre-escala, ; bastaría con modificar los bits PS por programa). El periodo del oscilador será la ; inversa de la frecuencia, que en nuestro caso es de 20MHz. Por tanto, Tosc = 200nseg. ; Sustituyendo todos los datos en la ecuación se obtiene: ; ; carga = 60.6875 ; ; Debemos tomar un valor entero para cargarle en el TMR0. ¿Cuál es el correcto, 60 o 61? ; Calculamos a continuación cuál sería la temporización para ambos valores de la carga:

Page 15: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

; ; carga = 60 → T = 10.0352 mseg ; carga = 61 → T = 9.9840 mseg ; ; El segundo valor es el correcto, 61, ya que con el primero nos pasamos. Siempre será ; más sencillo ajustar la temporización deseada incluyendo en el programa instrucciones ; "nop". Continuamos con el programa. movlw d’61’ ;Realizamos la carga movwf TMR0 ;en el temporizador 0. ; Tardará dos ciclos en comenzar el proceso del temporizador. En el 3º se incrementa dos btfss INTCON,T0IF ;Compruebo si ha habido un desbordamiento (T0IF=1). goto dos ;Aquí, y hasta 256 ciclos después, TMR0 no se

;incrementa. decfsz CONTADOR,F ;Con este bucle realizo la goto uno ;temporización de 10mseg 50 veces. end

Page 16: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 9: Código fuente ; Como nos piden que cuente hasta 6, cargaremos en TMR0 un valor de forma que solo le ; falten 6 incrementos para desbordar, así desbordará después de 6 pulsos. Emplearé ; TMR0 para contar los 6 eventos y después lo emplearé como temporizador para ; temporizar el segundo de visualización del display. Esto no es incompatible, ya que ; las dos tareas no las realiza a la vez.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

CONT equ 0x20 ;Para el tiempo 1seg su valor será 100. W_TEMP equ 0x21 ; \ Para guardar los registros importantes STATUS_TEMP equ 0x22 ; > que vayan a ser modificados OPTION_REG_TEMP equ 0x23 ; / durante la interrupción

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x04 goto inter org 0x05

inicio clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw .6 ;Configurar puerto A movwf ADCON1 ;como E/S digitales (.6 es lo mismo que d’6’). bsf TRISA,RA4 ;Configurar en el puerto A como entrada la patilla RA4.

clrf TRISB ;Configurar puerto B como salida (todas las patillas).

movlw b’10101000’ ;Configuramos el registro OPTION_REG movwf OPTION_REG ;de acuerdo a nuestras necesidades.

;OPTION_REG = 10101000 ; bit 7 → RBPU =1 Da igual su estado. Las resistencias de pull-up se desconectan ; automáticamente al configurar el puerto B como salida. Las ; desactivamos por precaución. ; bit 6 → INTEDG=0 Interrupción activa con flanco descendente en RB0/INT. También lo

podríamos hacer con flanco ascendente, el enunciado no dice nada. ; bit 5 → T0CS=1 1 seleccionamos la entrada de pulsos por RA4, 0 para reloj interno. ; bit 4 → T0SE=0 El incremento de TMR0 se produce por flanco ascendente en RA4. ; bit 3 → PSA=1 Asigna el divisor de frecuencias al perro guardián(WDT). ; bits 2:0 → PS2:PS0=0 Da igual el valor, no estamos utilizando el reloj interno.

bcf STATUS,RP0 ;Vuelvo al banco 0. ; Debo cargar ahora el temporizador con el complemento a 1 de seis para que éste ; desborde tras seis eventos (en el séptimo, ya que 6 se decrementa hasta 0): ; ; TMR0 W Display ; F9 -----→ 6 -----→ 0 ; FA -----→ 5 -----→ 1 ; FB -----→ 4 -----→ 2 ; FC -----→ 3 -----→ 3 ; FD -----→ 2 -----→ 4 ; FE -----→ 1 -----→ 5 ; FF -----→ 0 -----→ 6 ; Interrupción 00

Page 17: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

movlw ~.6 ;Esto carga el complemento a 1 de 6 en el acumulador. movwf TMR0 ;Tengo el número de pulsos a contar para que desborde. ;Dos ciclos después se podrá incrementar el TMR0.

movlw b’00111111’ ;Esto para que nada más conectar el movwf PORTB ;display aparezca el número cero.

movlw b’10100000’ ;Configuro el registro movwf INTCON ;INTCON como necesite.

;INTCON = 10100000 ; bit 7 → GIE=1 Activamos el bit general de interrupciones. ; bit 5 → T0IE=1 Habilita la interrupción del TMR0. ; bit 2 → T0IF=0 Éste bit no se escribe. Yo leo de él cuando hay desbordamiento del ; temporizador TMR0. Deberá borrase por software (un cero). ; Todas las demás interrupciones deshabilitadas (ceros) uno comf TMR0 ;Complemento el valor de TMR0 y lo mando al acumulador andlw b’00001111’ ;Enmascaramiento AND. * ; * Ésta última instrucción es optativa ya que los valores que va a tomar el TMR0 serán ; del tipo Fx. Al complementar, F es 0. ej: F9=11111001 → 00000110 (ya hay ; enmascaramiento) call tabla ;Llamo a la subrutina tabla movwf PORTB ;Envío el número en código 7 segmentos al display goto uno ; El microprocesador estará en este bucle hasta que el bit T0IF sea uno, momento en el ; que se producirá una interrupción y el programa saltará a la subrutina de interrupción ; "inter" tabla addwf PCL,F ;Sumo el contenido del acumulador al PC retlw b'01111101' ;Retorno con el valor de 6 en 7 segmentos en W

retlw b'01101101' ;Retorno con el valor de 5 en 7 segmentos en W retlw b'01100110' ;Retorno con el valor de 4 en 7 segmentos en W retlw b'01001111' ;Retorno con el valor de 3 en 7 segmentos en W retlw b'01011011' ;Retorno con el valor de 2 en 7 segmentos en W retlw b'00000110' ;Retorno con el valor de 1 en 7 segmentos en W retlw b'00111111' ;Retorno con el valor de 0 en 7 segmentos en W

; Definimos la subrutina de interrupción que mostrará todos los segmentos del display ; iluminados durante 1 segundo. Para ello, como se ha comentado al principio, se ; empleará también el TMR0, ya que su primera función de contador ya ha terminado. ; Para temporizar 1 segundo, se empleará la temporización del ejercicio 6 que era de ; 10 mseg y la multiplicaremos por 100 (por eso definimos CONT) ; / *** interrupción *** / ;Lo primero es guardar todos los registros importantes para no perderlos inter movwf W_TEMP ;Guardar el W en un registro temporal. swapf STATUS,W ;Intercambia los nibbles de STATUS movwf STATUS_TEMP ;y lo guarda en un registro temporal. clrf STATUS ;Banco 0, sin importar el banco actual, borra

;los bits IRP,RP1,RP0. movf OPTION_REG,W ;Guarda el registro OPTION_REG movwf OPTION_REG_TEMP ;en un registro temporal. clrf OPTION_REG ;Borrar el registro. ;Los registros ya están guardados bsf STATUS,RP0 ;Banco 1. movlw b’10000111’ ;Configuramos el registro OPTION_REG para movwf OPTION_REG ;que el TMR0 funcione como temporizador.

Page 18: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

;OPTION_REG = 10000111 ; bit 7 → RBPU =1 Desactivamos las resistencias de pull-up por precaución. ; bit 6 → INTEDG=0 Con un 0, interrupción activa con flanco descendente en RB0/INT. ; bit 5 → T0CS=0 Con 0 seleccionamos los pulsos del reloj interno. ; bit 4 → T0SE=0 El incremento de TMR0 se produce por flanco ascendente del reloj. ; bit 3 → PSA=0 Asigna el divisor de frecuencias al módulo del TMR0. ; bits 2:0 → PS2:PS0=1 Selecciona el rango del divisor de frecuencia del TMR0 (256). bcf STATUS,RP0 ;Vuelvo al banco 0 bcf INTCON,T0IF ;Borrar T0IF. * ; * Hay que borrar el bit de señalización de desbordamiento T0IF, ya que si no lo borro ; cuando acabe la interrupción, el programa vuelve a entrar en ella (bucle infinito). movlw 0xFF ;El display se movwf PORTB ;enciende completamente. call retardo ;Subrutina para iluminar durante 1 segundo. clrf PORTB ;Borro el display. ;Recupero los registros guardados antes de finalizar la rutina de interrupción movf OPTION_REG_TEMP,W ;Recupero el valor de movwf OPTION_REG ;OPTION_REG a través de W. swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original. swapf W_TEMP,F ;Intercambia el contenido del reg. temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados stop goto stop ;Fin de subrutina de interrupción * ; * Todas las subrutinas deben acabar con un retorno, pero creo un bucle infinito porque ; el enunciado dice que para repetir el proceso será necesario pulsar RESET ; / *** subrutina de retardo *** / retardo movlw .100 ;Cargo el registro CONT movwf CONT ;con el valor 100 otravez bcf INTCON,T0IF ;Borrar el bit de señalización de interrupciones * movlw .61 ;Cargo con el valor 61 el TMR0. Ya se vió en el ej 6 movwf TMR0 ;que con este valor se temporizan 10 mseg dos btfss INTCON,T0IF ;Comprobar si hay desbordamiento goto dos decfsz CONT,F ;Si es así, decrementar CONT y comprobar si CONT=0 goto otravez ;Si CONT no es cero, realizar el proceso de nuevo return ;Si es cero, regresar. ; * Observar que en esta última subrutina se vuelve a borrar el bit de señalización de ; desbordamiento T0IF. En el programa, en la instrucción "goto otra vez", el bit T0IF ; posee el valor 1 (desbordamiento activado, no se ha borrado), por lo que, al saltar a ; "otravez", si no lo borro, el temporizador dejará de contar, ya que el microprocesador ; interpretará una interrupción. ;Empleo de "swapf" al guardar registros en la rutina de interrupción: ; Al guardar y recuperar STATUS y W se emplea la instrucción "swapf" en vez de "movwf" o ; "movf" ya que éstas dos últimas pueden afectar a los bits C, DC y Z y modificar así el ; STATUS con la consiguiente perturbación en el programa. "swapf" no afecta a ningún bit ; de estado.

Page 19: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

EJERCICIO 12: Código fuente ; Sabemos que el temporizador 1 puede trabajar con eventos externos a través de la ; patilla RC0/T1OSC/T1CKL. Mi objetivo es que cuente los pulsos de la señal cuadrada que ; voy a introducir por RC0, por lo que deberé configurar el TMR1 como contador. Los ; incrementos los realizará con los flancos ascendentes pero es preciso que primero ; detecte un flanco descendente antes de empezar a contar los impulsos. Es decir, antes ; de que interprete los flancos ascendentes y se incremente deberá haber detectado un ; flanco descendente. ; ; Cada N flancos ascendentes deberá desbordarse y producir una interrupción, como puede ; observarse en el cronograma. En la propia subrutina de interrupción deberé cambiar por ; programa el valor del TMR1 de FFFFh a 0000h y conmutar la señal en RB0. ; ; El número más grande al que puedo asignar N es 65535 (FFFFh), es decir, como mucho ; podré dividir la frecuencia F por 65535. ; Hacemos el programa, por ejemplo, para N=6. Para ello, en realidad, deberemos guardar ; el complemento a 2 de 6 para que después de contar 6 llegue a 0xFFFF y en el siguiente ; pulso se desborde y provoque la interrupción.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

N equ 0xFFF9 ;Cargamos el complemento a 2 del número 6 (0xFFF9). W_TEMP equ 0x21 ; \ Para guardar los registros STATUS_TEMP equ 0x22 ; / durante la interrupción

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x04 goto inter org 0x10 ;(Se puede poner 0x05 o cualquier otra dirección).

inicio clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1.

clrf TRISB ;Configurar puerto B como salida (todas las patillas). bsf TRISC,RC0 ;Patilla RC0 como entrada.

F

N=1

N=2

N=3

RB0

FFFF

0000

FFFF

0000

FFFF

0000

FFFF

0000

FFFF

0000

FFFF

0000

FFFF

0000

FFFE

0000

FFFE

0000

FFFE

FFFF

FFFE

FFFF

FFFF

0000

FFFD

0000

FFFD

FFFE

FFFD

FFFF

FFFE

FFFF

Page 20: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

; En realidad, esta última instrucción no es necesaria, ya que como los impulsos van a ; proceder de un oscilador externo (por RC0), deberemos activar el bit T1OSCEN del ; registro T1CON. Al activar este bit, las patillas RC0 y RC1 actúan como entradas, ; independientemente del registro TRISC.

bsf PIE1,TMR1IE ;Habilito las posibles interrupciones del TMR1.

bcf STAUS,RP0 ;Banco 0. movlw b’00000111’ ;Configuración del movwf T1CON ;registro T1CON. ;T1CON = 00000111 ; bits 7:6 → (no implementados) Preferiblemente se escribirán ceros. ; bits 5:4 → T1CKPS1:T1CKPS0=00 Rango del pre-divisor. No seleccionaremos pre-divisor, ; ya que el temporizador podría saltarse flancos. ; bit 3 → T1OSCEN=0 Deshabilitamos el oscilador externo. ; bit 2 → T1SYNC=1 No sincroniza la entrada del reloj externo con el interno. ; bit 1 → TMR1CS=1 Reloj externo procedente de la patilla RC0/T1OSO/T1CKL. ; bit 0 → TMR1ON=1 Habilitación del TMR1. clrf TMR1L ;Borro la parte baja del TMR1 para asegurar que no se

;desborda durante la operación de escritura. movlw low-N ;Envío la parte baja de N en complemento a 2, movwf TMR1L ;es decir, 0xF9 a la parte baja del TMR1. movlw high-N ;Envío la parte alta de N en complemento a 2, movwf TMR1H ;es decir, 0xFF a la parte alta del TMR1. ; Los comandos "low" y "high" se emplean para referirse a palabras que ocupan dos ; posiciones de memoria (16 bits). Si el valor de N solo ocupase 8 bits estos comando no ; harían falta. movlw b’11000000’ ;Activo los bits de habilitación global de movwf INTCON ;interrupciones y de los periféricos (GIE y PEIE). ;INTCON = 11000000 ; bit 7 → GIE=1 Activamos el bit general de interrupciones. ; bit 6 → PEIE=1 Habilita la interrupción de los periféricos. ; Todas las demás interrupciones deshabilitadas (ceros) uno sleep nop goto uno ; / *** interrupción *** / ;Guardamos los registros importantes: inter movwf W_TEMP ;Guardar el W en un registro temporal swapf STATUS,W ;Intercambia los nibbles de STATUS movwf STATUS_TEMP ;y lo guarda en un registro temporal clrf STATUS ;Banco 0, sin importar el banco actual, borra

;los bits IRP,RP1,RP0 ;Los registros ya están guardados ; Vuelvo a recargar el TMR1 con el complemento a 2 de 6: clrf TMR1L ;Borro la parte baja del TMR1 para asegurar que no se

;desborda durante la operación de escritura. movlw low-N ;Envío la parte baja de N en complemento a 2, movwf TMR1L ;es decir, 0xF9 a la parte baja del TMR1. movlw high-N ;Envío la parte alta de N en complemento a 2, movwf TMR1H ;es decir, 0xFF a la parte alta del TMR1.

Page 21: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN II

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN II

2003 / 04

bcf PIR1,TMR1IF ;Deshabilito la posible interrupción por desbordamiento

;del TMR1. movlw b’00000001’ ;Realiza la operación xorwf PORTB,F ;OR exclusiva entre W y PORTB. ; Con esta operación se consigue que el valor de la patilla RB0 cambie. Al colocar un 1 ; en el bit cero de W conseguimos que el bit cero del PORTB (RB0) cambie su valor ; actual. Las posiciones de W donde hay ceros no alteran el valor de los demás bits de ; PORTB. Lo vemos en la tabla de la verdad de la operación OR-exclusiva: ; ; W | RB0 | Nuevo valor ; -----|-----|------------- ; 0 | 0 | 0 ; 0 | 1 | 1 ; → 1 | 0 | 1 ; → 1 | 1 | 0 ; -----|-----|------------- ;Recuperamos ahora los registros guardados antes. swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original. swapf W_TEMP,F ;Intercambia el contenido del reg. temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados retfie ;Fin de la subrutina de interrupción. end ;Fin del programa.

Page 22: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

EJERCICIO 1: Código fuente ; La diferencia entre dos flancos ascendentes nos dará el periodo. La primera captura se ; almacenará en un registro temporal de 16 bit, ya que el módulo de captura solo ; memoriza la captura actual. También necesito establecer en que instante debo realizar ; la resta de valores. Definiré una variable llamada "N_FLANCO" de forma que cuando se ; produzca el primer flanco, N_FLANCO=0 y cuando se produzca el segundo N_FLANCO=1, ; momento en el que realizaré la resta. ; Como nos dice el enunciado, la velocidad de evolución del TMR1 oscila entre 1.6µseg y ; 100mseg, por lo que solo podré medir periodos que oscilen entre los 62KHz y los 10 Hz.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

PERIODO_H equ 0x20 PERIODO_L equ 0x21 CAP_TEMP_H equ 0x22 CAP_TEMP_L equ 0x23 N_FLANCO equ 0x24 W_TEMP equ 0x25 STATUS_TEMP equ 0x26

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x04 goto inter org 0x15 ;(Se puede poner 0x05 o cualquier otra dirección).

inicio clrf PERIODO_H ; \

clrf PERIODO_L ; | clrf CAP_TEMP_H ; > Borrar los registros de la memoria RAM. clrf CAP_TEMP_L ; | clrf N_FLANCO ; /

clrf PORTB ;Borro el valor de clrf PORTD ;los puertos B y D. bsf STATUS,RP0 ;Banco 1. clrf TRISB ;Puerto B configurado como salida. clrf TRISD ;Puerto D configurado como salida. bsf TRISC,RC2 ;Bit RC2 configurado como entrada. bsf PIE1,CCP1IE ;Habilito las posibles interrupciones del comparador 1. bcf STATUS,RP0 ;Vuelvo al banco 0.

Flanco 0 Flanco 1

1ª captura 2ª captura

Periodo

Page 23: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

clrf TMR1L ;Después de un reset el valor de estos registros es clrf TMR1H ;desconocido. Antes de poner en marcha el temporizador

;los borro para garantizar que comienzan a cero.

; Calculamos el rango del pre-divisor: ; ; 20MHz → 50ns = Tosc ; ; 1 ; -------- = 4·Tosc = 4·50ns = 200ns ; fosc/4 ; ; Debemos llegar al valor mínimo impuesto en el enunciado. Para ello emplearemos el ; pre-escaler: ; 1.6µs/200ns = 1600ns/200ns = 8 ; ; Con el pre-escaler x8 conseguimos este valor. El periodo máximo que conseguiremos ; será: ; (FFFF) ; 65535·1.6µs = 104587ms = 104.587µs = Tmáx ; ;T1CON = 00110001 ; bits 7:6 → (no implementados) Preferiblemente se escribirán ceros. ; bits 5:4 → T1CKPS1:T1CKPS0=11 Rango del pre-divisor, x8. ; bit 3 → T1OSCEN=0 Deshabilitamos el oscilador externo. ; bit 2 → T1SYNC=0 Sincroniza la entrada del reloj externo con el interno. ; bit 1 → TMR1CS=0 Reloj interno (fosc/4). ; bit 0 → TMR1ON=1 Habilitación del TMR1. movlw b’00110001’ ;Configuramos el registro T1CON en movwf T1CON ;función de nuestras necesidades ; Según el valor asignado al pre-escaler, después de 1600ns se producirá el primer ; flanco 200ns movlw b’11000000’ ;Habilito las interrupciones 400ns movwf INTCON ;globales y las de los periféricos ;INTCON = 11000000 ; bit 7 → GIE=1 Activamos el bit general de interrupciones. ; bit 6 → PEIE=1 Habilita la interrupción de los periféricos. ; Todas las demás interrupciones deshabilitadas (ceros). ; Ya estamos preparados para que se produzcan interrupciones cada vez que el módulo CCP ; detecte un flanco. Programamos ahora el módulo CCP. 600ns movlw b’00000101’ 800ns movwf CCP1CON ;CCP1CON = 00000101 ; bits 7:6 → (no implementados) Preferiblemente se escribirán ceros. ; bits 5:4 → CCP1X:CCP1Y=00 En modo captura, ceros.(Solo se emplean en modo PWM). ; bits 3:0 → CCP1M3:CCP1M0=0101 En cada flanco ascendente. loop 1000ns movf PERIODO_H,W ; 1200ns movwf PORTB ; La detección se producirá en este bucle. Cada vez que 1400ns movf PERIODO_L,W ; cuente 1600ns se detecta un flanco y se produce una 1600ns movwf PORTD ; interrupción. goto loop ;

Page 24: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

; *Nota: El que interrumpe al bucle anterior es el módulo CCP1 no el TMR1 (no lo he ; configurado así): ; ; (1) habilitado → CCP1IE ; Interrupción ; 1 con flanco ascendente en RC2 → CCP1IF (solo si los dos a 1) ; ; / *** interrupción *** / ;Lo primero es guardar todos los registros importantes para no perderlos inter movwf W_TEMP ;Guardar el W en un registro temporal. swapf STATUS,W ;Intercambia los nibbles de STATUS movwf STATUS_TEMP ;y lo guarda en un registro temporal. clrf STATUS ;Banco 0, sin importar el banco actual, borra

;los bits IRP,RP1,RP0. ;Los registros ya están guardados btfss PIR1,CCP1IF ;Detección de una posible falsa interrupción. retfie ; Con estas dos instrucciones conseguimos detectar posibles falsas interrupciones que no ; son debidas al módulo CCP1. Si CCP1IF=1 la interrupción es debida al módulo CCP1, ; saltará una instrucción y continuará con la subrutina de interrupción. Si este bit es ; cero significa que el programa ha entrado en la subrutina de interrupción pero no por ; que CCP1 halla detectado un flanco ascendente. En este caso cancelamos la interrupción

btfsc N_FLANCO,0 ;Si es cero es el primer flanco, con lo cual lo goto medir ;guardaré en los registros para restarlo después. Si es

;uno voy a "medir". movf CCPR1L,W ;Guardo la parte baja movwf CAP_TEMP_L ;del valor de CCPR1. movf CCPR1H,W ;Guardo la parte alta movwf CAP_TEMP_H ;del valor de CCPR1. incf N_FLANCO,F ;Incremento N_FLANCO para que la próxima vez valga uno

;y sea la segunda medida. ;Recupero los registros guardados antes de finalizar la rutina de interrupción swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original. swapf W_TEMP,F ;Intercambia el contenido del reg. temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados bcf PIR1,CCP1IF ;Borro el señalizador de interrupción del CCP1 antes de

;salir para que el programa no vuelva a la interrupción retfie medir movf CAP_TEMP_L,W ;Resto las partes bajas subwf CCPR1L,W ;de las dos medidas. movwf PERIODO_L ;Guardo la parte baja del resultado. btfss STATUS,C ;Compruebo si ha habido acarreo (resta: C=0 → acarreo)

incf CAP_TEMP_H ;y si es así sumo uno al sustraendo. movf CAP_TEMP_H,W ;Resto las partes altas subwf CCPR1H,W ;de las dos medidas movwf PERIODO_H ;y lo guardo en la parte alta del resultado. bcf PIR1,CCP1IF ;Borro el señalizador de interrupción del CCP1.

;Recupero los registros guardados antes de finalizar la rutina de interrupción swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original.

Page 25: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

swapf W_TEMP,F ;Intercambia el contenido del reg. temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados

retfie end ; Ejemplo: ; ; Si realizado el proceso, el valor que obtenemos es, por ejemplo: ; ; PERIODO_H | PERIODO_L_ ; 0 0 0 A ; ; Este resultado quiere decir que tenemos 10 eventos de la base de tiempos del TMR1, es ; decir: ; 10·1.6µs = 16µs ; ; *Nota: 16µs es el valor de nuestro periodo. Como se puede comprobar, los registros ; PERIODO_H y PERIODO_L no reflejan el valor real de nuestro periodo, reflejan el valor ; en función de la base de tiempos (dividido entre 1.6). Para que reflejasen el valor ; real haría falta codificar una subrutina de multiplicación para multiplicar el ; resultado por la base de tiempos.

Page 26: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

EJERCICIO 4: Código fuente ; *Nota: Como solo tengo 6 patillas en el puerto A solo emplearé 6 bits; no me harán ; falta los registros altos del TMR1 ni del CCP1.

list p=16F876,f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos.

W_TEMP equ 0x20 STATUS_TEMP equ 0x21

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x04 goto inter org 0x05 ;(Se puede poner 0x05 o cualquier otra dirección).

inicio clrf PORTB ;Borro el valor del puerto B. bsf STATUS,RP0 ;Banco 1. movlw .6 ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b’00111111’ ;Configurar todas las patillas movwf TRISA ;del puerto A como entradas.

bcf TRISB,RB0 ;Configurar la patilla RB0 como salida. bsf PIE1,CCP1IE ;Habilito las posibles interrupciones del comparador 1. bcf STATUS,RP0 ;Vuelvo al banco 0. movlw b’00000010’ ;Configuro el movwf T1CON ;temporizador 1. ;T1CON = 00000010 ; bits 7:6 → (no implementados) Preferiblemente se escribirán ceros. ; bits 5:4 → T1CKPS1:T1CKPS0=00 Rango del pre-divisor, 1:1 ; bit 3 → T1OSCEN=0 Deshabilitamos el oscilador externo. ; bit 2 → T1SYNC=0 Sincroniza la entrada del reloj externo con el interno. ; bit 1 → TMR1CS=1 Reloj externo procedente de la patilla RC0/T1OSO/T1CKL (flancos ; ascendentes). ; bit 0 → TMR1ON=0 Detiene el temporizador. (Lo habilitaré más tarde). movlw b’00001010’ ;Configuro el movwf CCP1CON ;módulo CCP1. ;CCP1CON = 00001010 ; bits 7:6 → (no implementados) Preferiblemente se escribirán ceros. ; bits 5:4 → CCP1X:CCP1Y=00 En modo captura, ceros.(Solo se emplean en modo PWM). ; bits 3:0 → CCP1M3:CCP1M0=1010 Modo comparador. Genera una interrupción por software ; activando CCP1IF. La patilla CCP1 no se ve afectada. clrf TMR1L ;Después de un reset no conocemos su valor. Antes de clrf TMR1H ;activar el TMR1 los borro para que comiencen a cero. clrf CCPR1H ;Como no lo voy a utilizar lo borro. bsf T1CON,TMR1ON ;Habilito el TMR1. Lo pongo en marcha ahora. movlw b’11000000’ ;Configuro las movwf INTCON ;interrupciones. ;INTCON = 11000000 ; bit 7 → GIE=1 Activamos el bit general de interrupciones. ; bit 6 → T0IE=1 Habilita la interrupción de los periféricos. ; Todas las demás interrupciones deshabilitadas (ceros).

Page 27: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

uno sleep ;Duermo al goto uno ;microprocesador. ; Entraré en la subrutina de interrupción cuando se active CCP1IF. Cuando coincidan la ; parte baja del comparador (no la he manipulado) y la del temporizador 1 (se irá ; aumentando en uno con cada flanco ascendente) se producirá la interrupción (se ; activará CCP1IF). ; / *** interrupción *** / ;Lo primero es guardar todos los registros importantes para no perderlos inter movwf W_TEMP ;Guardar el W en un registro temporal. swapf STATUS,W ;Intercambia los nibbles de STATUS movwf STATUS_TEMP ;y lo guarda en un registro temporal. clrf STATUS ;Banco 0, sin importar el banco actual, borra

;los bits IRP,RP1,RP0. ;Los registros ya están guardados btfss PIR1,CCP1IF ;Detección de una posible retfie ;falsa interrupción. bcf T1CON,TMR1ON ;Paro el temporizador. clrf TMR1L ;Borro el posible valor que clrf TMR1H ;puedan tener los registros. movlw b’00000001’ ;Con esto consigo cambiar el valor xorwf PORTB,F ;del bit RB0 del puerto B. clrf CCPR1H ;Lo borro por precaución ya que no lo voy a usar. ; Ahora hay que fijar cual será el número de flancos a contar, que vendrá dado por el ; valor de las patillas RA5:RA0. movf PORTA,W ;Enmascaramiento de andlw b’00111111’ ;bits no empleados.* movwf CCPR1L ;Mando el valor a contar al registro bajo del CCP1. ;(Como se ha comentado antes, el alto no se emplea). ; * En teoría esta operación no hace falta ya que el registro PORTA solo utiliza 6 bits ; (tantos como patillas tiene el puerto), pero si hay problemas con los buses o ; cualquier otro inconveniente se pueden modificar los bits 6 y 7. Los borro y ahorro ; posibles problemas. bsf T1CON,TMR1CON ;Reanudo el funcionamiento del temporizador. bcf PIR1,CCP1IF ;Borro el señalizador de interrupción del CCP1. ;Recupero los registros guardados antes de finalizar la rutina de interrupción. swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original. swapf W_TEMP,F ;Intercambia el contenido del reg. temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados retfie ; Problemas: ; ; · La parte baja del comparador presentará un valor desconocido (entre 00 y FF) si se ; produce un reset. ; · No se si exactamente voy a entrar al momento o después de 256 flancos.

Page 28: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

EJERCICIO 6: Código fuente ; Como vamos a tener que temporizar 1seg nos hará falta la subrutina de temporización de ; 10mseg que hemos venido empleando en algunos de los ejercicios. Además, nuestro ; formato de transmisión será de 8 bits, que es el tamaño de los caracteres del código ; ASCII extendido (el que emplean los PC’s).

list p=16F876,f=INHX8M ;Tipo de procesador include "P16F876.INC" ;Definiciones de registros internos

CONT equ 0x20 W_TEMP equ 0x21 STATUS_TEMP equ 0x22

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x04 goto inter org 0x05 ;(Se puede poner 0x05 o cualquier otra dirección).

inicio clrf PORTC ;Esto no haría falta. bsf STATUS,RP0 ;Banco 1. movlw b’10111111’ ;Configurar RC6/TX como salida (transmisor) movwf TRISC ;y RC7/RX como entrada (receptor). ; En realidad no haría falta configurar estas patillas como entrada y salida. El ; fabricante, Microchip, nos dice que para transmisión mediante la USART estos dos bits ; de TRISC deberían estar a 1. Éste es el estado que adquieren después de un reset, es ; decir, al iniciar el programa ya están a uno y no haría falta configurarlos. Pero en ; la práctica, asignando TX como salida y RX como entrada se obtiene el mismo resultado. ; La configuración escrita en el programa parece la más lógica y evita confusiones. movlw b’11000111’ ;Configuramos el movwf OPTION_REG ;temporizador 0. ;OPTION_REG = 11000111 ; bit 7 → RBPU =1 Da igual su estado. Las resistencias de pull-up se desconectan ; automáticamente al configurar el puerto B como salida. Activamos el ; bit por precaución. ; bit 6 → INTEDG=1 Interrupción externa activa con flanco ascendente en RB0/INT. ; bit 5 → T0CS=0 Pulsos del reloj interno de frecuencia igual al ciclo de instrucción ; bit 4 → T0SE=0 El incremento de TMR0 se produce por flanco ascendente del reloj. ; bit 3 → PSA=0 Asigna el divisor de frecuencias al módulo del TMR0 ; bits 2:0 → PS2:PS0=1 Selecciona el rango del divisor de frecuencia del TMR0 (256) ; El porqué de cargar este valor fue explicado en el primer ; ejercicio en el que se realizó la temporización de 10mseg. movlw b’00100100’ ;Configuro el registro de control movwf TXSTA ;y estado de transmisión TXSTA. ;TXSTA = 00100100 ; bit 7 → CSRC=0 Bit de selección de procedencia de la señal. En modo asíncrono no ; afecta (da igual su valor). ; bit 6 → TX9=0 Seleccionamos un formato de transmisión de 8 bits. ; bit 5 → TXEN=1 Transmisión activada. (a partir de ya se puede transmitir si la ; USART está activada) ; bit 4 → SYNC=0 Modo asíncrono. ; bit 3 → No implementado (se lee como cero). ; bit 2 → BRGH=1 Transmisión de alta velocidad. (en modo síncrono no afecta).

Page 29: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

; bit 1 → TRMT=0 Bit de estado del registro de desplazamiento de transmisión. Lo ; iniciamos como vacío (cero). ; bit 0 → TX9D=0 Bit de dato del 9º bit del formato de transmisión. Es un bit de ; salida, no de entrada. Nosotros no lo empleamos. ; Debemos cargar ahora el registro SPBRG adecuadamente para poder trabajar a la ; velocidad (en baudios) a la que vamos a transmitir. ; ; Sabemos que la ecuación que determina la velocidad en baudios viene definida por: ; ; fosc ; Velocidad = --------------- ; ( K·(X + 1) ) ; ; La velocidad son 9600 baudios, K=16 ya que hemos seleccionado modo de alta velocidad ; (BRGH=1), fosc es la que venimos empleando hasta ahora, 20MHz y X es el valor a cargar ; en el registro SPRG. Despejamos X: ; ; (fosc / velocidad) - K ; X = ------------------------ ; K ; ; Sustituyendo los valores obtenemos X=129,2. Cargando el valor 129 en el registro ; obtenemos una velocidad de aproximadamente 9615 baudios, muy acorde con la que ; necesitamos. movlw .129 movwf SPBRG ; Todo está preparado para que el programa comience a funcionar, solo falta habilitar la ; USART e inicializar el temporizador 0: bcf STATUS,RP0 ;Vuelvo al banco 0. bsf RCSTATUS,SPEN ;USART en ON. movlw ~.195 ;Para poder movwf TMR0 ;temporizar 10mseg. movlw .100 ;Para temporizar movwf CONT ;1 segundo. movlw b’10100000’ ;Habilitamos la interrupción movwf INTCON ;del temporizador 0. ;INTCON = 10100000 ; bit 7 → GIE=1 Activamos el bit general de interrupciones. ; bit 5 → T0IE=1 Habilita la interrupción del TMR0. ; Todas las demás interrupciones deshabilitadas (ceros). uno goto uno ;Colgamos al procesador. ; / *** interrupción *** / ;Lo primero es guardar todos los registros importantes para no perderlos inter movwf W_TEMP ;Guardar el W en un registro temporal swapf STATUS,W ;Intercambia los nibbles de STATUS movwf STATUS_TEMP ;y lo guarda en un registro temporal. clrf STATUS ;Banco 0, sin importar el banco actual, borra

;los bits IRP,RP1,RP0 ;Los registros ya están guardados

Page 30: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

bcf INTCON,T0IF ;Borramos el señalizador de desbordamiento del TMR0. movlw ~.195 ;Recargamos movwf TMR0 ;otros 10 mseg. decfsz CONT,F ;Decrementamos CONT. retfie ;Si no vale cero, todavía no pasado 1 segundo. Vuelvo ;a temporizar otros 10mseg hasta que llegue a 1 seg. movlw ‘A’ ;Si es cero, ya ha pasado 1seg. Cargo el dato call tx_dato ;y lo envío. movlw .100 ;Recargo el contador movwf CONT ;antes de regresar al bucle uno. ;Recupero los registros guardados antes de finalizar la rutina de interrupción swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original. swapf W_TEMP,F ;Intercambia el contenido del reg. temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados retfie ; / *** Subrutina de transmisión de dato *** / tx_dato movwf TXREG ;Transmito el dato que previamente tenía cargado en W. ; Ahora tendré que estar muestreando el bit de transmisión TRMT continuamente hasta que ; me indique que la transmisión ha finalizado: bsf STATUS,RP0 ;Voy al banco 1. dos btfss TXSTA,TRMT ;Cuando el bit sea uno, habrá finalizado la transmisión goto dos ;Mientras no sea así estará a cero, espero. return end ; *Nota: En el ensamblador MPLAB, no se pueden meter impulsos a TX y RX. No se puede ; simular la transmisión serie. Habría que poner manualmente a uno el bit TRMT para ; simular el fin de transmisión.

Page 31: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

EJERCICIO 7: Código fuente

list p=16F876,f=INHX8M ;Tipo de procesador include "P16F876.INC" ;Definiciones de registros internos

W_TEMP equ 0x20 STATUS_TEMP equ 0x21

org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x04 goto inter org 0x05 ;(Se puede poner 0x05 o cualquier otra dirección).

inicio clrf PORTC ;Esto no haría falta. Clrf PORTB ;Borramos el valor que pueda tener el puerto B. bsf STATUS,RP0 ;Banco 1. movlw b’10111111’ ;Configurar RC6/TX como salida (transmisor) movwf TRISC ;y RC7/RX como entrada (receptor). movlw b’00100100’ ;Configuro el registro de control movwf TXSTA ;y estado de transmisión TXSTA. ;TXSTA = 00100100 ; bit 7 → CSRC=0 Bit de selección de procedencia de la señal. En modo asíncrono no ; afecta (da igual su valor). ; bit 6 → TX9=0 Seleccionamos un formato de transmisión de 8 bits. ; bit 5 → TXEN=1 Transmisión activada. (a partir de ya se puede transmitir si la ; USART está activada). ; bit 4 → SYNC=0 Modo asíncrono. ; bit 3 → No implementado (se lee como cero). ; bit 2 → BRGH=1 Transmisión de alta velocidad. (en modo síncrono no afecta). ; bit 1 → TRMT=0 Bit de estado del registro de desplazamiento de transmisión. Lo ; iniciamos como vacío (cero). ; bit 0 → TX9D=0 bit de dato del 9º bit del formato de transmisión. Es un bit de ; salida, no de entrada. Nosotros no lo empleamos.

bsf PIE1,RCIE ;Habilitamos la recepción de la posible interrupción ;del USART.

bcf STATUS,RP0 ;Volvemos al banco 0. movlw b’10010000’ ;Configuramos el registro de control movwf RCSTA ;y estado de recepción RCSTA. ;RCSTA = 10010000 ; bit 7 → SPEN=1 Habilitación del puerto serie. Con un 1 se habilita el puerto serie ; (se configuran las patillas RC7 y RC6 como RX y TX). ; bit 6 → RX9=0 Recepción del 9º bit. Como hemos elegido un formato de 8 bits, ; lo deshabilitamos (cero). ; bit 5 → SREN=0 Recepción simple. En modo asíncrono no afecta (cero). ; bit 4 → CREN=1 Recepción continua (un bit detrás de otro). ; bit 3 → ADDEN=0 Detección de dirección. Solo si tenemos formato de 9 bits (cero). ; bit 2 → FERR=0 Error de trama (no hay). ; bit 1 → OERR=0 Error de sobrepaso (no hay). ; bit 0 → RX9D=0 Bit de dato del 9º bit del formato de recepción. No nos interesa. ; A partir de aquí funciona el USART, pero no produce interrupciones. Las habilitamos:

Page 32: Pic 16f876-Ejercicios y Practicas 2003-2004

EJERCICIOS DE PROGRAMACIÓN III

Rubén Bartolomé Henares EJERCICIOS DE PROGRAMACIÓN III

2003 / 04

bsf INTCON,PEIE ;Habilitamos las interrupciones de los periféricos. bsf INTCON,GIE ;(Es una buena técnica habilitar siempre en último

;lugar las interrupciones globales). uno goto uno ; / *** interrupción *** / ;Lo primero es guardar todos los registros importantes para no perderlos inter movwf W_TEMP ;Guardar el W en un registro temporal. swapf STATUS,W ;Intercambia los nibbles de STATUS movwf STATUS_TEMP ;y lo guarda en un registro temporal. clrf STATUS ;Banco 0, sin importar el banco actual, borra

;los bits IRP,RP1,RP0. ;Los registros ya están guardados btfss PIR1,RCIF ;Garantizamos que la interrupción retfie ;es producida por el USART. movf RCREG,W ;Reflejamos el dato recibido vía serie movwf PORTB ;asincrona en los leds del Puerto B. call tx_dato ;Transmito el dato. ;Recupero los registros guardados antes de finalizar la rutina de interrupción swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original. swapf W_TEMP,F ;Intercambia el contenido del reg. temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados retfie ; / *** Subrutina de transmisión de dato *** / tx_dato movwf TXREG ;Transmito el dato que previamente tenía cargado en W ;(lo último cargado en W era el dato recibido en RCREG) bsf STATUS,RP0 ;Voy al banco 1. dos btfss TXSTA,TRMT ;Cuando el bit sea uno, habrá finalizado la transmisión goto dos ;Mientras no sea así estará a cero, espero. return end ; Observaciones: ; · Los bits RCIF y TXIF, indicadores de interrupción, se borran automáticamente. No hay ; que borrarlos por software como ocurría por ejemplo con T0IF. ; · Mientras se transmite un dato (el programa está en tx_dato) puede estar recibiéndose ; otro dato en RC6. Es una configuración full-duplex.

Page 33: Pic 16f876-Ejercicios y Practicas 2003-2004

2

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 2 -

PRÁCTICA 2: Diagrama de flujo

Visualizar CONT

en el puerto B

Borrar

puerto B y N_FLANCOS

Inicializar

puerto B salida puerto A entrada

N_FLANCOS = 0 ?

(STOP)

SI

Retardo

Leer puerto A y

guardar en N_FLANCOS

RA4=0?

NO

SI

NO

SI

Retardo

RA4=1?

1

NO

Decrementar N_FLANCOS

Práctica 2

SI

N_FLANCOS = 0 ?

1

Incrementa

CONT

NO

Page 34: Pic 16f876-Ejercicios y Practicas 2003-2004

3

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 2 -

PRÁCTICA 2: Código fuente ; PRÁCTICA 2: ENTRADAS Y SALIDAS BÁSICAS (I) ; GRUPO: 2L ; MESA: 3 ; Alumnos: BARTOLOMÉ HENARES, RUBÉN ; REVILLA GUTIÉRREZ, JESÚS list p=16F876, f=INHX8M ;Tipo de procesador include "P16F876.INC" ;Definiciones de registros internos N_FLANCOS equ 0x51 ; \ CONT equ 0x52 ; | Asignar a las distintas variables DELAY1 equ 0x53 ; | sus registros correspondientes. DELAY2 equ 0x54 ; / org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción. inicio clrf N_FLANCOS ;Borra N_FLANCOS. clrf CONT ;Borra CONT. clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw b'00000110' ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b'00011111' ;Configurar las patillas RA4:RA0 movwf TRISA ;del puerto A como entrada. clrf TRISB ;Configurar puerto B como salida. bcf STATUS,RP0 ;Vuelvo al banco 0. leer_A movf PORTA,W ;Leer entradas RA3:RA0 y enviarlas al acumulador. andlw b'00001111' ;Enmascaramiento de los bits no utilizados. btfsc STATUS,Z ;Comprueba si RA3:RA0 valen cero (STOP) y si es así, goto leer_A ;vuelve a comprobarlos hasta que cambie su valor. ;Para cualquier otro valor comienza la ejecución. movwf N_FLANCOS ;Almacenamos el número de flancos a contar para

;incrementar CONT. loop0 btfsc PORTA,4 ;Detección de goto loop0 ;flanco de bajada. call retardo ;Llamada a subrutina para evitar rebotes mecánicos

;del interruptor. loop1 btfss PORTA,4 ;Detección de goto loop1 ;flanco de subida. call retardo decfsz N_FLANCOS,F ;Si N_FLANCOS no es cero goto loop0 ;vuelve a loop0. incf CONT,F ;Si N_FLANCOS es cero incrementa el contador. movf CONT,W ;Refleja el valor de CONT a movwf PORTB ;la salida del puerto B. goto leer_A ;Vuelve a realizar todo el proceso. ; / *** Subrutina de retardo para evitar rebotes mecánicos en el interruptor *** / retardo movlw d'66' movwf DELAY2

Page 35: Pic 16f876-Ejercicios y Practicas 2003-2004

4

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 2 -

uno movlw 0xFB movwf DELAY1 nop dos decfsz DELAY1,F goto dos decfsz DELAY2,F goto uno return end

Page 36: Pic 16f876-Ejercicios y Practicas 2003-2004

2

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 3 -

PRÁCTICA 3: Diagrama de flujo

Borrar

puerto B y N_FLANCOS

Inicializar

puerto B salida puerto A entrada

N_FLANCOS = 0 ?

(STOP)

SI

Retardo

Leer puerto A y

guardar en N_FLANCOS

RA4=0?

NO

SI

NO

SI

Retardo

SI

RA4=1?

N_FLANCOS = 0 ?

1

1

Incrementa

CONT

NO

NO

Decrementar N_FLANCOS

Tabla

Enviar el valor de CONT convertido al puerto B (display)

Tabla

Sumar

desplazamiento al PC (digito hex.)

Localizar valor en código 7 segmentos

Visualizar en el

puerto B (display)

CONT=20? (máximo)

NO

SI

Práctica 3

Fin

Retorna

Page 37: Pic 16f876-Ejercicios y Practicas 2003-2004

3

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 3 -

PRÁCTICA 3: Código fuente ; PRÁCTICA 3: ENTRADAS Y SALIDAS BÁSICAS (II) ; GRUPO: 2L ; MESA: 3 ; Alumnos: BARTOLOMÉ HENARES, RUBÉN ; REVILLA GUTIÉRREZ, JESÚS list p=16F876, f=INHX8M ;Tipo de procesador include "P16F876.INC" ;Definiciones de registros internos N_FLANCOS equ 0x51 ; \ CONT equ 0x52 ; | Asignar a las distintas variables DELAY1 equ 0x53 ; | sus registros correspondientes. DELAY2 equ 0x54 ; / org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción. inicio clrf N_FLANCOS ;Borra N_FLANCOS. clrf CONT ;Borra CONT clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw b'00000110' ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b'00011111' ;Configurar las patillas RA4:RA0 movwf TRISA ;del puerto A como entrada. clrf TRISB ;Configurar puerto B como salida. bcf STATUS,RP0 ;Vuelvo al banco 0. movlw b'00111111' ;Inicializo el display movwf PORTB ;con el número cero. leer_A movf PORTA,W ;Leer entradas RA3:RA0 y enviarlas al acumulador. andlw b'00001111' ;Enmascaramiento de los bits no utilizados. btfsc STATUS,Z ;Comprueba si RA3:RA0 valen cero (STOP) y si es así, goto leer_A ;vuelve a comprobarlos hasta que cambie su valor. ;Para cualquier otro valor comienza la ejecución. movwf N_FLANCOS ;Almacenamos el número de flancos a contar para

;incrementar CONT. loop0 btfsc PORTA,4 ;Detección de goto loop0 ;flanco de bajada. call retardo ;Llamada a subrutina para evitar rebotes mecánicos

;del interruptor. loop1 btfss PORTA,4 ;Detección de goto loop1 ;flanco de subida. call retardo decfsz N_FLANCOS,F ;Si N_FLANCOS no es cero goto loop0 ;vuelve a loop0. incf CONT,F ;Si N_FLANCOS es cero incrementa el contador. movlw d'20' ;Cargamos el valor máximo que queremos que cuente en W subwf CONT,W ;y se lo restamos a CONT, guardando el resultado en W. btfss STATUS,Z ;Si CONT aún no ha llegado a 19, la resta no goto visualizar ;será cero (Z=0) y pasa a visualizar el resultado. goto inicio ;Si se ha llegado al tope, CONT=20, la resta será cero ;(Z=1) y en este caso reiniciamos el programa.

Page 38: Pic 16f876-Ejercicios y Practicas 2003-2004

4

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 3 -

visualizar movf CONT,W ;Llevo CONT a W andlw b'00011111' ;Enmascaramiento de bits no utilizados. call tabla ;Llamo a la subrutina para visualizar en el display. movwf PORTB ;Enviar la codificación de los segmentos al puerto B clrf PCLATH ;Borro el PCLATH. goto leer_A ;Voy a por el siguiente número. ; / *** Subrutina de retardo para evitar los rebotes mecánicos del interruptor *** / retardo movlw d'66' movwf DELAY2 uno movlw 0xFB movwf DELAY1 nop dos decfsz DELAY1,F goto dos decfsz DELAY2,F goto uno return ; / *** Subrutina para visualizar en el display el valor de CONT *** / tabla addwf PCL,F nop ;Esta línea corresponde al 0, que ya está visualizado. ;segmentos .gfedcba retlw b'00000110' ; 1 retlw b'01011011' ; 2 retlw b'01001111' ; 3 retlw b'01100110' ; 4 retlw b'01101101' ; 5 retlw b'01111101' ; 6 retlw b'00000111' ; 7 retlw b'01111111' ; 8 retlw b'01101111' ; 9 retlw b'10111111' ;10 retlw b'10000110' ;11 retlw b'11011011' ;12 retlw b'11001111' ;13 retlw b'11100110' ;14 retlw b'11101101' ;15 retlw b'11111101' ;16 retlw b'10000111' ;17 retlw b'11111111' ;18 retlw b'11101111' ;19 end

Page 39: Pic 16f876-Ejercicios y Practicas 2003-2004

2

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 4 -

PRÁCTICA 4: Diagrama de flujo

Borrar puerto B

Inicializar

puerto B salida puerto A entrada

SI

temporizar

Encender el

led conectado a RB0

RA4=1?

NO

Apagar el

led conectado a RB0

temporizar

temporizar

CONT=50

Borrar T0IF y cargar el valor para temporizar 10mseg

TMR0=61

Práctica 4

T0IF=1? (desbordamiento)

NO

Decrementar el contador

CONT = CONT-1

CONT=0?

Fin

SI

NO

Retorna

SI

Page 40: Pic 16f876-Ejercicios y Practicas 2003-2004

3

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 4 -

PRÁCTICA 4: Código fuente ; PRÁCTICA 4: TEMPORIZADORES E INTERRUPCIONES ; GRUPO: 2L ; MESA: 3 ; Alumnos: BARTOLOMÉ HENARES, RUBÉN ; REVILLA GUTIÉRREZ, JESÚS list p=16F876, f=INHX8M ;Tipo de procesador include "P16F876.INC" ;Definiciones de registros internos CONT equ 0x50 ;Asignar a la variable su registro correspondiente. org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción. inicio clrf PORTB ;Borra los latch de salida. bsf STATUS,RP0 ;Selecciona el banco 1. movlw b'00000110' ;Configurar puerto A movwf ADCON1 ;como E/S digitales. bsf TRISA,0 ;Configurar RA0 de puerto A como entrada. bcf TRISB,0 ;Configurar RB0 de puerto B como salida. movlw b'10000111' ;Configuramos el registro OPTION_REG movwf OPTION_REG ;de acuerdo a nuestras necesidades. ;OPTION_REG = 10000111 ; bit 7 → RBPU =1 Da igual su estado. Las resistencias de pull-up se desconectan ; automáticamente al configurar el puerto B como salida. Activamos el ; bit por precaución. ; bit 6 → INTEDG=0 Selecciona el flanco en el que se activa la interrupción si entrase ; una señal por RB0/INT, peor como nosotros estamos empleando esta ; patilla como salida, el estado de este bit no influye. ; bit 5 → T0CS=0 Reloj interno, de frecuencia igual al ciclo de instrucción (CLKOUT) ; bit 4 → T0SE=0 Selecciona en que flanco, ascendente o descendente en RA4, se va a ; incrementar el TMR0. Aquí da igual, el TMR0 se va a incrementar ; con los flancos del reloj interno. Da igual el valor. ; bit 3 → PSA=0 Asigna el divisor de frecuencias al temporizador 0, TMR0 ; bits 2:0 → PS2:PS0=1 Selecciona el rango del divisor de frecuencias del TMR0 (256) bcf STATUS,RP0 ;Vuelvo al banco 0. uno btfss PORTA,0 ;Cuestiono el valor de RA0 goto uno ;hasta que valga uno, momento dos bsf PORTB,0 ;en el que pongo a uno RB0. call temporizar ;y lo mantengo 0.5 seg a uno. bcf PORTB,0 ;Después borro RB0, call temporizar ;y lo mantengo otros 0.5 seg borrado. goto uno ;Realiza el proceso de nuevo. ; / *** Subrutina de temporización de 0.5 segundos *** / temporizar movlw d'50' movwf CONT otravez bcf INTCON,2 ;Borro el bit T0IF de desbordamiento del TMR0 movlw d'61' movwf TMR0

Page 41: Pic 16f876-Ejercicios y Practicas 2003-2004

4

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 4 -

preguntar btfss INTCON,2 ;Cuestiono T0IF hasta que se produzca goto preguntar ;la interrupción, momento en el que decfsz CONT,F ;decrementará el contador y volverá a goto otravez ;realizar el proceso de nuevo, hasta que bcf INTCON,2 ;el CONT valga cero, momento en el que return ;habrá finalizado la temporización de 0.5seg. end ; Explicación del valor cargado en el TMR0: ; ; Este calculo lo debe realizar el propio programador. Sabemos que la ecuación que ; define la temporización para el TMR0 es: ; ; T = 4·Tosc·(256 - carga)·preescala ; ; Si despejamos la carga: ; T ; carga = 256 - ------------------ ; 4·Tosc·preescala ; ; La temporización que deseamos es T = 10mseg. La preescala viene definida por el ; estado de los bits PS2, PS1 y PS0 del registro OPTION_REG. Los tres poseerán el valor ; 1 ya que, como se ha comentado, después de un reset todos los bits de OPTION_REG se ; ponen a uno. Se estará cargando, por tanto, y según el rango de funcionamiento del ; predivisor, el valor 256; luego preescala = 256. (Si se deseara otra preescala, ; bastaría con modificar los bits PS por programa). El periodo del oscilador será la ; inversa de la frecuencia, que en nuestro caso es de 20MHz. Por tanto, Tosc = 200nseg. ; Sustituyendo todos los datos en la ecuación se obtiene: ; ; carga = 60.6875 ; ; Debemos tomar un valor entero para cargarle en el TMR0. ¿Cuál es el correcto, 60 o ; 61? Calculamos a continuación cuál sería la temporización para ambos valores de la ; carga: ; ; carga = 60 → T = 10.0352 mseg ; carga = 61 → T = 9.9840 mseg ; ; El segundo valor es el correcto, 61, ya que con el primero nos pasamos. Si queremos ; ajustar nuestro valor siempre será más sencillo ajustar la temporización deseada ; incluyendo en el programa instrucciones "nop".

Page 42: Pic 16f876-Ejercicios y Practicas 2003-2004

2

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 5 -

PRÁCTICA 5: Diagrama de flujo

RA5:RA0 del

puerto A como entradas

RC2/CCP1 como salida del modo

PWM

Cargar en PR2 el valor para obtener

2KHz de ciclo PWM

Asignar el valor en puerto A al ciclo de servicio del PWM

Práctica 5

Configurar el

módulo CCP1 en modo PWM

Configurar el TMR2 con el valor del

pre-escaler calculado

Page 43: Pic 16f876-Ejercicios y Practicas 2003-2004

3

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 5 -

PRÁCTICA 5: Código fuente ; PRÁCTICA 5: MÓDULO CAPTURA, COMPARACIÓN Y PWM. ; GRUPO: 2L ; MESA: 3 ; Alumnos: BARTOLOMÉ HENARES, RUBÉN ; REVILLA GUTIÉRREZ, JESÚS list p=16F876, f=INHX8M ;Tipo de procesador include "P16F876.INC" ;Definiciones de registros internos org 0x00 ;Vector de reset. Estas dos líneas sirven goto inicio ;para cargar el programa en el módulo. org 0x05 ;El programa comienza después del vector interrupción. inicio bsf STATUS,RP0 ;Selecciona el banco 1. movlw b'00000110' ;Configurar puerto A movwf ADCON1 ;como E/S digitales. movlw b'00111111' ;Configurar RA5:RA0 movwf TRISA ;como entradas. clrf TRISC ;Configurar la patilla RC2/CCP1 como salida

;del modo PWM. ; Calculamos el valor a cargar en el temporizador 2 para obtener 2KHz de periodo. La ; ecuación que determina el periodo es: ; ; Periodo_PWM = (PR2 + 1)·4·Tosc·Pre-divisor_TMR2 ; ; Despejamos PR2 que es el valor que deberemos cargar: ; ; Periodo_PWM ; PR2 = -------------------------- - 1 ; 4·Tosc·Pre-divisor_TMR2 ; ; El periodo son 1/2KHz = 0.5mseg, 4·Tosc son 200nseg y para el pre-divisor le daremos ; primeramente el valor 1. Con todo esto obtenemos: ; ; PR2 = 2499 ; ; Evidentemente, este valor no se puede cargar en un registro de 8 bits. Para reducir ; el valor a cargar asignaremos al pre-divisor el valor 16. Con este valor, el ; resultado es: ; PR2 = 155.25 ; ; El valor a cargar es, por tanto, PR2 = 156 movlw d'156' ;Cargamos en el registro PR2 el valor calculado movwf PR2 ;para el periodo de la señal del módulo PWM. bcf STATUS,RP0 ;Vuelvo al banco 0. clrf TMR2 ;Borramos el TMR2 antes de configurarlo ;para asegurarnos de que comienza en cero. movlw b'00001100' ;Configuramos el módulo CCP1 en modo PWM. Los 2 bits movwf CCP1CON ;menos significativos del PWM los iniciaremos como 0’s ;CCP1CON = 00001100 ; bits 7:6 → (no implementados) Preferiblemente se escribirán ceros. ; bits 5:4 → CCP1X:CCP1Y=00 Los iniciamos como ceros (no hay ajuste fino). ; bits 3:0 → CCP1M3:CCP1M0=11xx Modo PWM.

Page 44: Pic 16f876-Ejercicios y Practicas 2003-2004

4

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 5 -

movlw b'00000110' ;Configuramos el TMR2 acorde con nuestras necesidades. movwf T2CON ;(Ya habíamos calculado que el pre-escaler valdría 16

;para poder llegar al periodo deseado). ;T2CON = 00000110 ; bit 7 → (no implementados) Preferiblemente se escribirán ceros. ; bits 6:3 → TOUTPS3:TOUTPS0=0000 Rango del post-divisor, 1:1. ; bit 2 → TMR2ON=1 El TMR2 está en servicio. ; bits 1:0 → T2CKPS1:T2CKPS0=1x Rango del pre-divisor, 1:16. leer_ciclo movf PORTA,W ;Llevo el valor del ciclo de servicio introducido en andlw b'00111111' ;PORTA, realizando un enmascaramiento previo, movwf CCPR1L ;al registro CCPR1L. El ciclo ya está asignado. goto leer_ciclo end

Page 45: Pic 16f876-Ejercicios y Practicas 2003-2004

SIN COMPROBAR

2

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 6 -

PRÁCTICA 6: Diagrama de flujo

RC7/RX entrada RC6/TX salida

Configurar los

registros RCSTA y TXSTA

Configurar la

velocidad de trabajo del procesador

Práctica 6

Habilitar interrupciones de

recepción, periféricos y global

nop

interrupción

Borrar el flag de indicación de

interrupción por recepción RCIF

Guardar el dato

recibido

DATO<A ?

(en la codificación ASCII)

NO

SI

SI

Retorno

SI

Enviar el mensaje

“Error”

DATO>Z ?

(en la codificación ASCII)

Sumar 32 a DATO (letra minúscula) y

enviar

Fin de transmisión?

NO

NO

Fin de transmisión?

NO

SI

Page 46: Pic 16f876-Ejercicios y Practicas 2003-2004

SIN COMPROBAR

3

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 6 -

PRÁCTICA 6: Código fuente ; PRÁCTICA 6: EL MÓDULO USART ; GRUPO: 2L ; MESA: 3 ; Alumnos: BARTOLOMÉ HENARES, RUBÉN ; REVILLA GUTIÉRREZ, JESÚS list p=16F876, f=INHX8M ;Tipo de procesador. include "P16F876.INC" ;Definiciones de registros internos. DATO equ 0x20 ;Registro para almacenar el dato recibido. STATUS_TEMP equ 0x21 ;Registros para almacenar STATUS y W W_TEMP equ 0x22 ;durante la rutina de interrupción. org 0x00 goto inicio org 0x04 goto inter inicio clrf PORTC ;Esto no haría falta (es costumbre). bsf STATUS,RP0 ;Banco 1. movlw b'10111111' ;Configurar RC7/RX como entrada (receptor) movwf TRISC ;y RC6/TX como salida (transmisor). movlw b'00100100' ;Configurar el registro de control movwf TXSTA ;y estado de transmisión TXSTA. ;TXSTA = 00100100 ; bit 7 → CSRC=0 Bit de selección de procedencia de la señal. En modo asíncrono no ; afecta (da igual su valor). ; bit 6 → TX9=0 Seleccionamos un formato de transmisión de 8 bits. ; bit 5 → TXEN=1 Transmisión activada. (a partir de ya se puede transmitir si la ; USART está activada) ; bit 4 → SYNC=0 Modo asíncrono. ; bit 3 → No implementado (se lee como cero). ; bit 2 → BRGH=1 Transmisión de alta velocidad. (en modo síncrono no afecta). ; bit 1 → TRMT=0 Bit de estado del registro de desplazamiento de transmisión. Lo ; iniciamos como vacío (cero). ; bit 0 → TX9D=0 Bit de dato del 9º bit del formato de transmisión. Es un bit de ; salida, no de entrada. Nosotros no lo empleamos. ; Debemos cargar ahora el registro SPBRG adecuadamente para poder trabajar a la ; velocidad (en baudios) a la que vamos a transmitir. ; ; La velocidad son 9600 baudios, K=16 ya que hemos seleccionado modo de alta velocidad ; (BRGH=1), fosc son 20MHz y X es el valor a cargar en el registro SPRG, que vendrá ; determinado por: ; (fosc / velocidad) - K ; X = ------------------------ ; K ; ; Sustituyendo los valores obtenemos X=129,2. Cargando el valor 129 en el registro ; obtenemos una velocidad de aproximadamente 9615 baudios. movlw .129 ;La velocidad de transmisión movwf SPBRG ;será de 9600 baudios. bsf PIE1,RCIE ;Habilitar la recepción de interrupciones. bcf STATUS,RP0 ;Banco 0.

Page 47: Pic 16f876-Ejercicios y Practicas 2003-2004

SIN COMPROBAR

4

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 6 -

movlw b'10010000' ;Configurar el registro de control movwf RCSTA ;y estado de recepción RCSTA. ;RCSTA = 10010000 ; bit 7 → SPEN=1 Habilitación del puerto serie. Con un 1 se habilita el puerto serie ; (se configuran las patillas RC7 y RC6 como RX y TX). ; bit 6 → RX9=0 Recepción del 9º bit. Como hemos elegido un formato de 8 bits, ; lo deshabilitamos (cero). ; bit 5 → SREN=0 Recepción simple. En modo asíncrono no afecta (cero). ; bit 4 → CREN=1 Recepción continua (un bit detrás de otro). ; bit 3 → ADDEN=0 Detección de dirección. Solo si tenemos formato de 9 bits (cero). ; bit 2 → FERR=0 Error de trama (no hay). ; bit 1 → OERR=0 Error de sobrepaso (no hay). ; bit 0 → RX9D=0 Bit de dato del 9º bit del formato de recepción. No nos interesa. ; A partir de aquí funciona el USART, pero no produce interrupciones. Las habilitamos: bsf INTCON,PEIE ;Habilitación de interrupción de periféricos. bsf INTCON,GIE ;Habilitación global de interrupciones. uno goto uno ;Colgamos al procesador. ; / *** Rutina de interrupción *** / ;Lo primero es guardar todos los registros importantes para no perderlos inter movwf W_TEMP ;Guardar el W en un registro temporal. swapf STATUS,W ;Intercambia los nibbles de STATUS movwf STATUS_TEMP ;y lo guarda en un registro temporal. clrf STATUS ;Banco 0, sin importar el banco actual, borra

;los bits IRP,RP1,RP0. ;Los registros ya están guardados bcf INTCON,T0IF ;Comprobar si la interrupción ha btfss PIR1,RCIF ;sido provocada por el USART. retfie ;Si no es así, retorna. movf RCREG,W ;Guardar el valor recibido movwf DATO ;desde el PC a un registro. movfw 'A' ;Comprobar si el dato recibido está, en la subwf DATO,W ;codificación ASCII, por debajo de la letra "A". btfss STATUS,C ;Si es así, el bit carry valdrá cero goto error_ ;y se enviará el mensaje "Error". movlw 'Z' ;Sino, comprobamos ahora si el dato recibido subwf DATO,W ;está por debajo de la letra "Z" restando Z-DATO. btfsc STATUS,C ;Si el dato no es válido, carry valdrá goto error_ ;uno y enviaremos el mensaje de "Error". goto responder ;Si es válido, enviaremos la respuesta. error_ movlw 'E' movwf TXREG movlw 'r' movwf TXREG movlw 'r' movwf TXREG movlw 'o' movwf TXREG movlw 'r' movwf TXREG bsf STATUS,RP0 ;Banco 0 (Ya estoy en el banco 0, pero por si acaso).

Page 48: Pic 16f876-Ejercicios y Practicas 2003-2004

SIN COMPROBAR

5

PRÁCTICAS 2003 / 2004

Rubén Bartolomé Henares PRÁCTICA 6 -

dos btfss TXSTA,TRMT ;¿Ha terminado de enviar datos hacia el PC?. goto dos ;No. Vuelve a preguntar.

;Si. Recupera los registros y retorna.

;Recupero los registros guardados antes de finalizar la rutina de interrupción swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original. swapf W_TEMP,F ;Intercambia el contenido del reg temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados

retfie responder movlw .32 ;Sumar al DATO almacenado el valor 32 para obtener addwf DATO,W ;el equivalente en minúscula de la letra recibida movwf TXREG ;y enviarlo hacia el PC. bsf STATUS,RP0 ;Banco 0. tres btfss TXSTA,TRMT ;¿Ha terminado de enviar datos hacia el PC?. goto tres ;No. Vuelve a preguntar.

;Si. Recupera los registros y retorna.

;Recupero los registros guardados antes de finalizar la rutina de interrupción swapf STATUS_TEMP,W ;Vuelve a intercambiar STATUS_TEMP y lo movwf STATUS ;devuelve a STATUS en su estado original. swapf W_TEMP,F ;Intercambia el contenido del reg temporal de W swapf W_TEMP,W ;lo vuelve a intercambiar y lo transfiere al W. ;Los registros ya están recuperados

retfie end