Autor Tema: PIC16F877A en lenguaje ensamblador  (Leído 5926 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Nary

  • PIC10
  • *
  • Mensajes: 7
PIC16F877A en lenguaje ensamblador
« en: 18 de Octubre de 2017, 03:41:35 »
Estoy realizando un programa en el cual el pin CCP2 se pondra a 1 al haber igualdad con el registro TMR1, utilizando interrupción  en modo comparación. Me gustaria saber como realizar la comparación y habilitar las interrupciones  :oops:

LIST p=PIC16F877A
INCLUDE <P16F877A.INC>



      ORG    00h       ;Reset
      GOTO    INICIO       ;Etiqueta de inicio
      ORG      05h       ;Inicio del programa



   INICIO:
      BANKSEL   TRISC   ;Se accede al banco
      clrf   TRISC   ;Se limpia el contenido de TRISC y se configura como salida
      BANKSEL PORTC     ;Se limpia el contenido
      clrf   PORTC   ;
      bsf      PORTC,0 ;Se coloca en 1 el pic y se activa la salida 0
                  ;Habilitar interrucciones 

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:PIC16F877A en lenguaje ensamblador
« Respuesta #1 en: 18 de Octubre de 2017, 15:32:32 »
Primero que nada vamos a ver el datasheet:
http://ww1.microchip.com/downloads/en/DeviceDoc/39582b.pdf

Si programas en ASM, es tu biblia el datasheet o reference manual.

Citar
Me gustaria saber como realizar la comparación y habilitar las interrupciones

Primero vamos a tratar las interrupciones.
Los PIC16F tiene 2 vectores ( posicion de memoria a la cual va el micro ante un determinado evento), uno de reset en 0x00 y el de interrupcion en 0x04.

A partir de aca tenes que entender como es que funciona el micro cuando sucede una interrupcion. El micro va a estar felizmente ejecutando el codigo el cual le sigue a la configuracion de los modulos etc y va a ser un loop infinito. Cuando sucede una interrupcion el micro guarda la posicion de memoria que estaba ejecutando y se va a 0x04 a ejecutar la interrupcion, terminada la interrupcion saca esa direccion guardada y sigue desde alli, entonces podes pensar que la inetrrupcion y el programa principal son 2 programas apartes uno de otro. El mayor problema de esto es que los registros que se usan para operar se modifican en la interrupcion y cuando vuelvas deberia ser los mismos que cuando se fueron, por eso uno debe tener un codigo extra en la interrupcion. El codigo hasta ahora quedaria asi:

Código: ASM
  1. ORG     0x00
  2.         GOTO    CONFIG
  3.         ORG     0x04
  4.         GOTO    INTERRUPCION
  5.  
  6. CONFIG:
  7.  
  8.         ;Aca configuro todos los modulos
  9.  
  10.         ;Aca habilito las interrupciones, esto es lo ULTIMO a hacer.
  11.  
  12. LOOP:
  13.         ; Aca mi LOOP principa e infinito, de aca nunca sale
  14.  
  15.         GOTO    LOOP
  16.  
  17.  
  18. INTERRUPCION:
  19.  
  20.         ; Codigo de entrada que guarda los valores W y STATUS sin modificarlos
  21.  
  22.         ; Aca el codigo de la interrupcion en si
  23.  
  24.         ; Codigo de salida que reestablece los valores de W y STATUS para dejarlos como estaban
  25.  
  26.         RETFIE

Observaras que nunca hay nada que haga saltar el codigo hacia la interrupcion, eso lo hace el propio micro.

¿Como habilito las interrupciones?

Primero debo saber cual quiero habilitar, y el porque se produce la interrupcion, ejemplo la interrupcion del TMR se produce cuando ocurre un overflow, si es de 8bits es cuando pasa de 0xFF a 0x00, y si es de 16bits cuando pasa de 0xFFFF a 0x0000.

En ese micro existen varios registros dedicados unicamente a la interrupciones. Estos son:

INTCON : El principal el cual permite habilitar todas las interrupciones y algunas principales
PIEx : Este registro posee la habilitacion de las interrupciones de los perifericos
PIRx : Este registro posee el estado de las banderas de las interrupciones ( si sucedio o no )

Por ejemplo el CCP1 posee en el PIE1 el bit: CCP1IE - CCP1 Interrupt Enable bit -, el cual si lo activamos vamos a permitir que se le avise al nucleo cuando suceda y de esa forma salte al vector de interrupcion. En PIR1 tenemos el bit CCP1IF el cual nos indica si sucedio o no.
Pero ese no es el unico bit para habilitar, los demas los tenes en el INTCON y que son 2 bits mas:

PEIE: Peripheral Interrupt Enable bit, este bit permite que cualquiera de los bits de PIEx sean tomados en cuenta. Y
GIE: Global Interrupt Enable bit, el que finalmente habilita por fin todas las interrupciones

Entonces si quisiera habilitar la interrupcion del CCP1 deberia:

- Poner a 0 el CCP1IF, borro el flag por si estaba activo
- Poner a 1 el CCP1IE, habilito la interrupcion de ese modulo
- Poner a 1 el PEIE, habilito las interrupcion de los perifericos
- Poner a 1 el GIE, este me habilita todas las interrupciones habilitadas.

En la interrupcion vas a tener que limpiar el CCP1IF

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Ahora vamos con el modulo CCP o Capture-Compare-PWM

Como su nombre lo indica puede hacer 3 cosas el mismo modulo.

El Capture, (mira pagina 65 del datasheet, el dibujito) hace que cuando suceda un evento ( flanco ascendente, o descendente en el pin del CCP1 ) agarre el valor que posea el TMR1 y lo guarde en los registros CCP1Rx
Te podria servir por ejemplo para saber el periodo de una señal, lo activas en flanco ascendente, esperas el primer valor, lo guardas, y luego cuando llega el segundo valor, lo restas y es el tiempo que paso.

Este obviamente no te sirve.

El Compare, (Pagina 66 del datasheet) hace lo que buscamos, y es comparar el valor del TMR1, y cuando es igual podemos configurarlo para varias cosas.
Cuando es igual podemos hacer que el pin de salida pase a 1, o que el TMR1 se ponga a 0. Esto lo definis con el valor de los registros.

Y el PWM que para este caso escapa lo que queremos hacer y por lo tanto no lo vamos a ver.


Ahora ¿como configuro el CCP?

Como leccion para CUALQUIER modulo, es ir al datasheet, revisar cuales son los registros/bits que utiliza y configurarlos, siempre al final de la explicacion del modulo tiene cuales son ( pag 68 para el TMR1 ).

Entonces vemos que tenemos los siguientes registros:

Los INTCON y los PIE, PIR, observaras que solo algunos estan en blancos, esos son los de la interrupcion del CCP1 y CCP2, vamos a usar el 1.
Luego tenes el TRISC, en caso de que uses la salida del CCP como eveto especial cuando coincidan en valores.
Tambien tenemos TMR1x y T1CON, como se compara con el TMR1, tenemos que si o si configurar el TMR1 y darle o no un valor inicial.

Y por fin los registros de nuestro modulo que son los CCP1Rx (H y L ) los cuales vamos a poner el valor en el cual debe coincidir, y el CCP1CON el cual va a decidir si el modulo CCP se comporta como Capture, Compare o PWM, y en caso de Compare que hacer cuando se produzca la igualdad.

Buscando el registros CCP1CON encontramos lo siguiente:

Citar
CCPxM3:CCPxM0: CCPx Mode Select bits
0000 = Capture/Compare/PWM disabled (resets CCPx module)
0100 = Capture mode, every falling edge
0101 = Capture mode, every rising edge
0110 = Capture mode, every 4th rising edge
0111 = Capture mode, every 16th rising edge
1000 = Compare mode, set output on match (CCPxIF bit is set)
1001 = Compare mode, clear output on match (CCPxIF bit is set)
1010 = Compare mode, generate software interrupt on match (CCPxIF bit is set, CCPx pin is unaffected)
1011 = Compare mode, trigger special event (CCPxIF bit is set, CCPx pin is unaffected); CCP1 resets TMR1; CCP2 resets TMR1 and starts an A/D conversion (if A/D module is enabled)
11xx = PWM mode

Tenemos 4 posibilidades del Compare,
- La primer opciones usa la salida, y pone a 1 la salida en caso que el TMR1 sea igual a CCP1Rx, tambien activa la interrupcion
- La segunda opcion de igual forma que la anterior actua sobre la salida, pero esta ves lo pone a 0. Y activa la interrupcion
- La tercera opcion, solo genera una interrupcion, no usa el pin, por lo cual te permite que en la interrupcion puedas activar cualquier pin que te guste.
- La cuarta opcion, genera un evento especial ademas de la interrupcion.
Si usas el CCP1, el evento especial hace que el TMR1 se vuelva a 0
Si usas el CCP2, el evento especial hace que el TMR1 se vuelva a 0 y ademas inicia una conversion del ADC si es que esta habilitado el modulo.


Entonces Supongamos que el TMR1 esta corriendo continuamente a tal velocidad que cuando cuenta 1000 paso 1 segundo. Y yo quiero que cada ese segundo quiero cambiar el estado de una salida. Puedo hacerlo de 2 formas.

La primera es usar un Timer cargar el valor 65536 - 1000 ( el complemento a 2 de 1000, ay que recorda que la interrupcion es por overflow ), Y cuando se genere la interrupcion en la misma poner de vuelta el valor ese asi cuenta otros 1000 mas. Es una solucion simple, pero ocurre que el tiempo perdido entre que ocurrio la interrupcion hasta que se logro cargar los valores nuevos al TMR1 es un error de tiempo y que se va a ir acumulando, exagerando pensemos que eso tarda 100ms, si yo queria medir 30 segundos, me voy a dar cuenta que al momento de que el micro cree que pasaron 30 segundos en realiadad fueron ( 1s + 100ms ) * 30 = 33 segundos, es decir un error.

Para eso esta el CCP y ese evento especial. Lo que voy a hacer con el CCP, lo vo ya configurar en modo Compare, y que me resete el TMR1.
Cargo los valores 1000 en los registros CCP1Rx ( valor a comparar ) y activo el TMR1, al momento de llegar a 1000 y producirse la igualdad, el mismo CCP1 pone a 0 el TMR1 asi comienza a contar de vuelta, y vos podes tardar en la interrupcion sin ningun problema, entonces ese error que teniamos antes se reduce drasticamente.

Y aca va la pregunta para vos.
El TMR1 que finalidad va a tener ? Contar pulsos externos ? Una ves que se produzca la igualdad, ademas de poner en 1 el pin  de salida, que vas a hacer con el valor del TMR1? lo reseteas? o tenes otro boton para eso?. Si lo resteas, cuanto tiempo debe estar la salida en 1, o apenas resetees el TMR queres que pase a 0 la salida?

Espero haber sido de ayuda , y que las preguntas te expandan las ideas para tener todo el control necesario de que debe realizar tu programa.

PD: El codigo que va al inicio de la interrupcion y a la salida, lo podes encontrar en el datasheet, busca por W_TEMP o STATUS_TEMP, que son lso nombres que usa Microchip para ese cometido ( Pag. 154). Es copiar y pegar nada mas

Ahora crea tu programa y si tenes problemas acudis nuevamente,
« Última modificación: 18 de Octubre de 2017, 15:34:49 por KILLERJC »

Desconectado Nary

  • PIC10
  • *
  • Mensajes: 7
Re:PIC16F877A en lenguaje ensamblador
« Respuesta #2 en: 18 de Octubre de 2017, 18:05:35 »
Al hacer la comparacion y existir una igualdad en CCP2 y Timer1 habra una interrupción donde se encendera un led por un segundo luego se apagara y se repetira el proceso

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:PIC16F877A en lenguaje ensamblador
« Respuesta #3 en: 18 de Octubre de 2017, 19:13:56 »
Bien pero el TMR1 que lo va a hacer aumentar? un pulso externo? el mismo oscilador?
A que velocidad va a aumentar si es que usa el oscilador? Que frecuencia pensas usar ?

Eso y muchas mas preguntas te faltan para terminar tu programa. De ahora en adelante queda en vos hacer el programa y traerlo aca.
« Última modificación: 18 de Octubre de 2017, 19:20:10 por KILLERJC »