TODOPIC

Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: GRUTTIS en 12 de Agosto de 2009, 21:21:45

Título: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 12 de Agosto de 2009, 21:21:45
Hola a todos, estoy metido en el desarrollo del control de una máquina que ejecuta diferentes funciones, por diferentes motivos, elegí el PIC16F877. Iba todo en orden hasta que decidí, por motivos de necesidad del sistema, aumentar algunas líneas en el programa, esto provocó que este no se ejecute correctamente, llega hasta un punto, se “resetea” y vuelve al principio.
Gracias al simulador del MPLAB, descubrí que lo que está ocurriendo es que el contador de programa ó de página, no tengo muy en claro el tema, se rebalsa y esto provoca la falla mencionada. Por motivos de espacio no puedo publicar todo el programa, pero les dejo resumido, a modo de ejemplo la falla en cuestión, básicamente se van ejecutando instrucciones y al momento de llamar una subrutina, en este caso de retardo, durante la ejecución de este se produce el reseteo.
Espero que alguien me pueda orientar, estaría muy agradecido, chau Darío.         



;**************************** CONFIGURACIÓN DE PUERTOS Y REGISTROS ****************************           
 
           ORG    0x00           ; El programa comienza en la dirección 0 y
           goto   INICIO         ; salta a la dirección 5 para sobrepasar el
           ORG    0x05           ; vector de interrupción


INICIO movlw  0x81           ;SE SELECCIONA RA0 COMO ENTRADA ANALÓGICA, RELOG
           movwf  ADCON0     ;DERIVADO DE LA FRECUENCIA DEL OSCILADOR/32     
             

           bsf    STATUS,5      ;SE SELECCIONA DEL BANCO 1
                   
           movlw  0xFF           ;SE CONFIGURA EL PUERTO A COMO ENTRADA
           movwf  PORTA       

           movlw  0x00          ;SE CONFIGURA EL PUERTO B COMO SALIDA     
           movwf  PORTB

           movlw  0xBF          ;SE CONFIGURAN RC0, RC1, RC2, RC3, RC4, RC5 Y RC7 COMO
           movwf  PORTC       ;ENTRADA, RC6 COMO SALIDA
 
           movlw  0x00          ;SE CONFIGURA EL PUERTO D COMO SALIDA
           movwf  PORTD       
   
           movlw  0x07          ;SE CONFIGURA EL PUERTO E COMO ENTRADA, PUERTO D COMO 
           movwf  PORTE       ;PUERTO DE PROPOSITO GENERAL 

           movlw  0x04          ;SE CONFIGURAN RA0, RA1 Y RA3 COMO ENTRADAS   
           movwf  ADCON1    ;ANALÓGICAS  RA2, RA5, RE1, RE2 Y RE3 COMO ENTRADAS DIGITALES
                 
           movlw  0x24          ;SE CONFIGURAN 8 BITS DE TRANSMISIÓN, TRANSMISIÓN HABILITADA 
           movwf  TXSTA       ;MODO DE COMUNICACIÓN ASÍNCRONO, ALTA VELOCIDAD PARA EL MODO
                                       ;ASÍNCRONO
 
           movlw  0x0A         ;SE AJUSTA LA VELOCIDAD DE COMUNICACIÓN A 56.818 BIT/SEG       
           movwf  SPBRG 

           movlw  0x05         ;SE MUEVE EL VALOR 0x05 A SSPADD, DE ESTA FORMA SE CONFIGURA   
           movwf  SSPADD    ;LA FRECUENCIA DE TRABAJO DEL PUERTO I2C A 400KHz, PARA UNA
                                       ;FRECUENCIA DE RELOJ DE 10MHz
 
           movlw  0x00          ;SE PONE A 0 AL REGISTRO SSPSTAT
           movwf  SSPSTAT

           movlw  0x80          ;SE LE ASIGNA LA DIVISION AL TMR0
           movwf  TMR0_OPT
           
           bcf    STATUS,5      ;SELECCION DEL BANCO 0

;**********************************************************************************************

 
;****************************** INICIO DEL PROGRAMA PRINCIPAL *********************************

           clrf   PORTA         ;SE LIMPIAN LOS POSIBLES VALORES ERRÓNEOS DE LOS PUERTOS
           clrf   PORTB 
           clrf   PORTC 
           clrf   PORTD
           clrf   PORTE     
           
           clrf   PIR1            ;SE PONE A 0 A PIR1 Y RCREG A 0
           clrf   RCREG           


          Acá se produce la falla, no se “vuelve” de la subrutina de retardo

           call  RET_1_SEG   ;COMO PRECAUCIÓN SE GENERA UN RETARDO DE 1 SEGUNDO  [/size]





Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 13 de Agosto de 2009, 01:57:13
El 99% de los casos en que un programa se resetea al agregarle unas líneas, está relacionado con las tablas, computed goto's o funciones que cruzan las páginas del uC.

Tenés alguna tabla más adelante en el código?
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: tapi8 en 13 de Agosto de 2009, 12:15:30
Citar
[   movlw  0x80          ;SE LE ASIGNA LA DIVISION AL TMR0
           movwf  TMR0_OPT
/quote]

No estara aqui el fallo?

INTEDG: Interrupt Edge Select bit
1 = Interrupt on rising edge of RB0/INT pin
0 = Interrupt on falling edge of RB0/INT pin

no eatas activando esto?

tapi8
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: tapi8 en 13 de Agosto de 2009, 14:21:13
Lo de citar no es lo mio y el hex parece que tampoco, es esto lo que deshabilita

         .-
RBPU: PORTB Pull-up Enable bit
1 = PORTB pull-ups are disabled
0 = PORTB pull-ups are enabled by individual port latch values

Pero no veo que lo habilites en INTCON, o esta mal el comentario y solo deshabitas las PULL-UPS.

Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 14 de Agosto de 2009, 00:14:41
El 99% de los casos en que un programa se resetea al agregarle unas líneas, está relacionado con las tablas, computed goto's o funciones que cruzan las páginas del uC.

Tenés alguna tabla más adelante en el código?


Hola Bruno, gracias por contestar an rápido y disculpa por mi ignorancia, ¿pero a que le llaman tabla ustedes?, saludos!!
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 14 de Agosto de 2009, 00:32:45
Lo de citar no es lo mio y el hex parece que tampoco, es esto lo que deshabilita

         .-
RBPU: PORTB Pull-up Enable bit
1 = PORTB pull-ups are disabled
0 = PORTB pull-ups are enabled by individual port latch values

Pero no veo que lo habilites en INTCON, o esta mal el comentario y solo deshabitas las PULL-UPS.


Hola Tapi8, gracias por interesarte en mi problema, te comento que las Pull-up del puerto B no están siendo habilitadas, faltó aclararlo en el texto, con el valor que asigné a TMR0_OPT (0x80) las deshabilito y le doy el valor de división que necesito para las subrutinas de retardo que estoy usando.
En cuanto al registro INTCON solo exploro el bit 2, que según entiendo, es el que me indica cuando el TMR0 se rebalsó ¿puede ser que el problema este relacionado con esto?, saludos!!! 
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 14 de Agosto de 2009, 04:44:41
Adjunta el codigo entero y puede que logremos ayudarte..
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 14 de Agosto de 2009, 09:52:26
Adjunta el codigo entero y puede que logremos ayudarte..

Hola de nuevo, el programa completo ocupa casi 4750 líneas, lo cual me causa un poco de verguenza jajaj, ya que seguramente se podría hacer mejor, pero bueno, me salió así ¿o publico por acá nomas?
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 14 de Agosto de 2009, 14:10:44
Comprimilo y publicalo como archivo adjunto a tu mensaje
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 14 de Agosto de 2009, 17:20:46
Comprimilo y publicalo como archivo adjunto a tu mensaje

Bueno, entendí, entonces adjunto a este mnsaje envío el archivo "asm"
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: todopic en 16 de Agosto de 2009, 13:27:47
Hola Grutis, a simple vista, veo que al final, hay unas subrutinas, que estan "despues" del END...  el end es lo ultimo que tienes que colocar ok?

Suerte!
Norberto
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 16 de Agosto de 2009, 18:38:02
Hola Grutis, a simple vista, veo que al final, hay unas subrutinas, que estan "despues" del END...  el end es lo ultimo que tienes que colocar ok?

Suerte!
Norberto

Hola Norberto, esa subrutina la coloqué allí a modo de "borrador", pensé que no influiría en el programa. De todos modos las eliminé, pero el problema continúa, olvide aclarar que al compilar el programa en el mplab, este me da una advertencia: "Message[306] D:\T.I\MPLAB\T.I-02\MODELO BASE\T.I-02A\TI-02A.ASM 4655 : Crossing page boundary -- ensure page bits are set", saludos y gracias, por ayudarme.
 
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 16 de Agosto de 2009, 23:20:17
Hola.

Si, esa advertencia es la que indica el problema.

Como estas usando más de 2KWords de la memoria FLASH del uC, tenes que tener ciertos recuados antes de llamar a una subrutina que no se encuentra en la misma pagina del uC.

para hacerlo debes hacer, por ejemplo:


     pagesel Rutina_Pag1
     call Rutina_Pag1
     pagesel $

    el pagesel es una MACRO que viene incorporada en un conjunto que trae el MPASM y es la que va a generar las 2 instrucciones necesarias para realizar el cambio de pagina.
    el pagesel $ es necesario para volver a la pagina actual cada vez que se retorna de una subrutina que estaba en otro banco...

Quise hacer una MACRO que generara(o no) automaticamente el codigo, pero la verdad que el MPLAB deja bastante que desear en eso, y solo obtengo errores asi que te va a tocar agregarlas una por una.

Saludos.


Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 17 de Agosto de 2009, 17:52:51
Hola.

Si, esa advertencia es la que indica el problema.

Como estas usando más de 2KWords de la memoria FLASH del uC, tenes que tener ciertos recuados antes de llamar a una subrutina que no se encuentra en la misma pagina del uC.

para hacerlo debes hacer, por ejemplo:


     pagesel Rutina_Pag1
     call Rutina_Pag1
     pagesel $

    el pagesel es una MACRO que viene incorporada en un conjunto que trae el MPASM y es la que va a generar las 2 instrucciones necesarias para realizar el cambio de pagina.
    el pagesel $ es necesario para volver a la pagina actual cada vez que se retorna de una subrutina que estaba en otro banco...

Quise hacer una MACRO que generara(o no) automaticamente el codigo, pero la verdad que el MPLAB deja bastante que desear en eso, y solo obtengo errores asi que te va a tocar agregarlas una por una.

Saludos.


Hola de nuevo BrunoF, nuevamente gracias por contestar, me has aclarado un poco más el tema, veo que no estoy al tanto de todos los secretos de este mundo de los µC y sus programaciones y nuevamente pido disculpas por mi ignorancia.
Puedo entender que lo que está ocurriendo, es similar a cuando se usan registros que no están en el Bank 0 y están en los otros bancos, por ejemplo, si quisiera usar el conversor A/D del PIC16F877 tengo el registro “ADRESH”, que esta en el Bank 0 y el “ADRESL” que esta en el Bank 1 para pasar de bancos es necesario utilizar los bits 5 y 6 del registro “STATUS” ¿es acertada la comparación?, de todos modos sigo sin entender bien lo que pusiste después (lo de generar una MACRO y lo de arreglarlas una por una) nuevamente perdón por la ignorancia, realmente me da mucha vergüenza. De todos modos el ejemplito me sirvió para hacer esto:


pagesel  RET_1_SEG

call        RET_1_SEG     ;COMO PRECAUCIÓN SE GENERA UN RETARDO DE 1 SEGUNDO   

pagesel $ ¿acá debería indicar a donde debe apuntar pcl?       
       
bsf         PORTD,7       ;SE CONMUTA LA LLAVE ELECTRÓNICA PARA PODER COMUNICAR LA
                                 ;CENTRAL CON EL MÓDULO DE CONTROL DEL DISPLAY



Espero no molestarlos con tantas preguntas básicas, quizás para ustedes que dominan el tema tan bien, saludos!!!




Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 17 de Agosto de 2009, 18:52:39
Si. Es una comparacion bastante bien aproximada...

Y a lo segundo también. Cada vez que llames a una subrutina que no esté en la misma página que desde donde la estás llamando, necesitás configurar la página antes de llamarla, y volver a configurar la página actual después de haberlo hecho.

No necesitás hacer ninguna macro. Era solo para que no tengas que hacer la tediosa tarea de agregar las macros antes y después de cada llamada a subrutinas de otras páginas.

Te comento el motivo del por qué es necesario el pagesel $ después de cada llamada a subrutinas de otras páginas.(He hablado sobre este tema en el foro extensamente, aunque no recuerdo bien en qué tema...tal vez si haces una busqueda en el foro logres encontrar algo).

La MACRO pagesel setea los bits necesarios del registro PCLATH. Estos bits se utilizan a la hora de ejecutar una instrucción call. Cuando por ejemplo haces:

       pagesel subrutina_pag1
       call       subrutina_pag1
      
la primer linea(pagesel) setea los bits para la pagina donde se encuentre la subrutina "subrutina_pag1"(que supuestamente esta en la pagina 1). Luego se realiza el call correctamente. Al volver de la subrutina, los bits del PCLATH siguen cargados con la página 1, entonces acá surgen los problemas si intentás llamara normalmente a otra subrutina,ya que deberías volver a la página actual antes de hacerlo.

Por ello, es necesario la instrucción pagesel $, que hará que los bits del PCLATH vuelvan a configurarse para la página actual.


Vamos con un ejemplo más real:

Código: ASM
  1. org 0x000
  2.  
  3.         clrf PCLATH
  4.  
  5.         pagesel pag1
  6.         call pag1
  7.      
  8.         call pag0
  9.  
  10.         goto $
  11.  
  12. pag0    nop
  13.         nop
  14.         retlw 0x00
  15.  
  16.         org 0x800                 ;vector de pagina 1
  17.         pag1 nop
  18.  
  19.         retlw 0xAA

Este codigo no se va a comportar bien...Veamos en profundidad el por qué.

Primero vamos a anotar dónde se guarda cada línea en la memoria FLASH:

LINEA:DIRECCION FLASH
org 0x000-
clrf PCLATH0x000
pagesel pag10x001
0x002
call pag10x003
call pag00x004
goto $0x005
pag0 nop0x006
retlw 0x000x007
org 0x800-
pag1 nop0x800
retlw 0xAA0x801

Ahora vamos a empezar a ensamblar de a poquito las líneas tal cual lo haría el MPASM( te recuerdo que todo esto lo estoy haciendo solo teoricamente, por lo que no está probado y puede que me equivoque en algunos detalles)

LINEA:DIRECCION FLASHCódigo pseudo-ensamblado:
org 0x000--
clrf PCLATH0x000clrf 0x0A
pagesel pag10x001
0x002
pagesel 0x800
call pag10x003call 0x00
call pag00x004call 0x06
goto $0x005goto 0x05
pag0 nop0x006nop
retlw 0x000x007retlw 0x00
org 0x800--
pag1 nop0x800nop
retlw 0xAA0x801retlw 0xAA

Ahora otra pasada mas, un poco más profunda:

LINEA:DIRECCION FLASHCódigo pseudo-ensamblado:
org 0x000--
clrf PCLATH0x000clrf 0x0A
pagesel pag10x001
0x002
bsf PCLATH,3
bcf PCLATH,4
call pag10x003call 0x00
call pag00x004call 0x06
goto $0x005goto 0x05
pag0 nop0x006nop
retlw 0x000x007retlw 0x00
org 0x800--
pag1 nop0x800nop
retlw 0xAA0x801retlw 0xAA


Un poco más...

LINEA:DIRECCION FLASHCódigo pseudo-ensamblado:
org 0x000--
clrf PCLATH0x000clrf 0x0A
pagesel pag10x001
0x002
bsf 0x0A,3
bcf 0x0A,4
call pag10x003call 0x00
call pag00x004call 0x06
goto $0x005goto 0x05
pag0 nop0x006nop
retlw 0x000x007retlw 0x00
org 0x800--
pag1 nop0x800nop
retlw 0xAA0x801retlw 0xAA

Ahora creo que vamos a poder hablar con un poco más de prioridad.

La instrucción call(en los uC de 14bits de largo de palabra) sólo puede direccion 11 bits. Esto significa que puede llamar sólo dentro del rango(decimal): [0;2047].

En los uC que tienen más de 2KWords esto(11 bits) no alcanzaría. Y aquí cobran importancia los bits 3 y 4 el registro PCLATH. Ellos son los 2 bits adicionales que necesitamos para poder direccionar los 13 bits completos que necesitamos(es decir, direccionar un rango de 8KWords).

Como se puede apreciar más arriba, la instrucción call pag1 se transforma en un call 0x00...Esto parecería que la llamada está mal ya que nosotros queremos llamar a la subrutina pag1(ubicada en la posición 0x800). Pero como expliqué previamente, al ejecutarse una instrucción call, el uC también utiliza los bits 3 y 4 del PCLATH para completar los 13 bits que necesita. Como hemos sido inteligentes, los hemos precargado con el valor binario: 01

Ahora, armando lo que tenemos entre los bits PCLATH,4   PCLATH,3 y la dirección a la que llama la instrucción call tendríamos:
                             PCLATH,4   PCLATH,3   call 0x00

En binario:                   0                   1        000 00000000

Todos juntos: 01000000000000
lo que en hexadecimal resulta: 0x800


¡Qué barbaro,¿no?! Resulta que hemos llamado realmente a la posición 0x800.

Ahora una vez realizada la llamada,el nop y el retlw, surge el problema...cuando queremos llamar a la subrutina "pag0". ¿Por que? Porque el PCLATH[4,3] continúa cargado con el valor binario 01.

Entonces, en lugar de llamar a la posición 0x006(que es donde se encuentra la subrutina pag0) estaríamos haciendo:

                             PCLATH,4   PCLATH,3  call 0x06

En binario:                   0                   1        000 00000110

Todos juntos: 0100000000110
lo que en hexadecimal resulta: 0x806

Por lo que estaríamos yendonos a una posición completamente alejada de la que queríamos. Es por ello, que debemos utilizar la instrucción pagesel $, que acomodará nuevamente los bits 4 y 3 del PCLATH para asegurar que en futuras llamadas no nos suceda esto.

Espero que haya quedado claro.

Un saludo.
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 18 de Agosto de 2009, 14:28:51
Si. Es una comparacion bastante bien aproximada...

Y a lo segundo también. Cada vez que llames a una subrutina que no esté en la misma página que desde donde la estás llamando, necesitás configurar la página antes de llamarla, y volver a configurar la página actual después de haberlo hecho.

No necesitás hacer ninguna macro. Era solo para que no tengas que hacer la tediosa tarea de agregar las macros antes y después de cada llamada a subrutinas de otras páginas.

Te comento el motivo del por qué es necesario el pagesel $ después de cada llamada a subrutinas de otras páginas.(He hablado sobre este tema en el foro extensamente, aunque no recuerdo bien en qué tema...tal vez si haces una busqueda en el foro logres encontrar algo).

La MACRO pagesel setea los bits necesarios del registro PCLATH. Estos bits se utilizan a la hora de ejecutar una instrucción call. Cuando por ejemplo haces:

       pagesel subrutina_pag1
       call       subrutina_pag1
      
la primer linea(pagesel) setea los bits para la pagina donde se encuentre la subrutina "subrutina_pag1"(que supuestamente esta en la pagina 1). Luego se realiza el call correctamente. Al volver de la subrutina, los bits del PCLATH siguen cargados con la página 1, entonces acá surgen los problemas si intentás llamara normalmente a otra subrutina,ya que deberías volver a la página actual antes de hacerlo.

Por ello, es necesario la instrucción pagesel $, que hará que los bits del PCLATH vuelvan a configurarse para la página actual.


Vamos con un ejemplo más real:

Código: ASM
  1. org 0x000
  2.  
  3.         clrf PCLATH
  4.  
  5.         pagesel pag1
  6.         call pag1
  7.      
  8.         call pag0
  9.  
  10.         goto $
  11.  
  12. pag0    nop
  13.         nop
  14.         retlw 0x00
  15.  
  16.         org 0x800                 ;vector de pagina 1
  17.         pag1 nop
  18.  
  19.         retlw 0xAA

Este codigo no se va a comportar bien...Veamos en profundidad el por qué.

Primero vamos a anotar dónde se guarda cada línea en la memoria FLASH:

LINEA:DIRECCION FLASH
org 0x000-
clrf PCLATH0x000
pagesel pag10x001
0x002
call pag10x003
call pag00x004
goto $0x005
pag0 nop0x006
retlw 0x000x007
org 0x800-
pag1 nop0x800
retlw 0xAA0x801

Ahora vamos a empezar a ensamblar de a poquito las líneas tal cual lo haría el MPASM( te recuerdo que todo esto lo estoy haciendo solo teoricamente, por lo que no está probado y puede que me equivoque en algunos detalles)

LINEA:DIRECCION FLASHCódigo pseudo-ensamblado:
org 0x000--
clrf PCLATH0x000clrf 0x0A
pagesel pag10x001
0x002
pagesel 0x800
call pag10x003call 0x00
call pag00x004call 0x06
goto $0x005goto 0x05
pag0 nop0x006nop
retlw 0x000x007retlw 0x00
org 0x800--
pag1 nop0x800nop
retlw 0xAA0x801retlw 0xAA

Ahora otra pasada mas, un poco más profunda:

LINEA:DIRECCION FLASHCódigo pseudo-ensamblado:
org 0x000--
clrf PCLATH0x000clrf 0x0A
pagesel pag10x001
0x002
bsf PCLATH,3
bcf PCLATH,4
call pag10x003call 0x00
call pag00x004call 0x06
goto $0x005goto 0x05
pag0 nop0x006nop
retlw 0x000x007retlw 0x00
org 0x800--
pag1 nop0x800nop
retlw 0xAA0x801retlw 0xAA


Un poco más...

LINEA:DIRECCION FLASHCódigo pseudo-ensamblado:
org 0x000--
clrf PCLATH0x000clrf 0x0A
pagesel pag10x001
0x002
bsf 0x0A,3
bcf 0x0A,4
call pag10x003call 0x00
call pag00x004call 0x06
goto $0x005goto 0x05
pag0 nop0x006nop
retlw 0x000x007retlw 0x00
org 0x800--
pag1 nop0x800nop
retlw 0xAA0x801retlw 0xAA

Ahora creo que vamos a poder hablar con un poco más de prioridad.

La instrucción call(en los uC de 14bits de largo de palabra) sólo puede direccion 12 bits. Esto significa que puede llamar sólo dentro del rango(decimal): [0;2047].

En los uC que tienen más de 2KWords esto(12 bits) no alcanzaría. Y aquí cobran importancia los bits 3 y 4 el registro PCLATH. Ellos son los 2 bits adicionales que necesitamos para poder direccionar los 14 bits completos que necesitamos(es decir, direccionar un rango de 8KWords).

Como se puede apreciar más arriba, la instrucción call pag1 se transforma en un call 0x00...Esto parecería que la llamada está mal ya que nosotros queremos llamar a la subrutina pag1(ubicada en la posición 0x800). Pero como expliqué previamente, al ejecutarse una instrucción call, el uC también utiliza los bits 3 y 4 del PCLATH para completar los 14 bits que necesita. Como hemos sido inteligentes, los hemos precargado con el valor binario: 01

Ahora, armando lo que tenemos entre los bits PCLATH,4   PCLATH,3 y la dirección a la que llama la instrucción call tendríamos:
                             PCLATH,4   PCLATH,3   call 0x00

En binario:                   0                   1        0000 00000000

Todos juntos: 01000000000000
lo que en hexadecimal resulta: 0x800


¡Qué barbaro,¿no?! Resulta que hemos llamado realmente a la posición 0x800.

Ahora una vez realizada la llamada,el nop y el retlw, surge el problema...cuando queremos llamar a la subrutina "pag0". ¿Por que? Porque el PCLATH[4,3] continúa cargado con el valor binario 01.

Entonces, en lugar de llamar a la posición 0x006(que es donde se encuentra la subrutina pag0) estaríamos haciendo:

                             PCLATH,4   PCLATH,3  call 0x06

En binario:                   0                   1        0000 00000110

Todos juntos: 01000000000110
lo que en hexadecimal resulta: 0x806

Por lo que estaríamos yendonos a una posición completamente alejada de la que queríamos. Es por ello, que debemos utilizar la instrucción pagesel $, que acomodará nuevamente los bits 4 y 3 del PCLATH para asegurar que en futuras llamadas no nos suceda esto.

Espero que haya quedado claro.

Un saludo.


Hola de nuevo, algo más entendí, evidentemente soy un brut... hice algunas modificaciones en el programa, con lo cual ahorré algunas líneas y pude avanzar, pero estoy al límite de pasarme de nuevo y faltan desarrollar muchísimas funciones más, lo que hice fue esto:



;****************************** INICIO DEL PROGRAMA PRINCIPAL *********************************

           clrf   PORTA         ;SE LIMPIAN LOS POSIBLES VALORES ERRÓNEOS DE LOS PUERTOS
           clrf   PORTB 
           clrf   PORTC 
           clrf   PORTD
           clrf   PORTE     
           
           clrf   PIR1                     ;SE PONE A 0 A PIR1 Y RCREG A 0
           clrf   RCREG 

           pagesel  RET_1_SEG    ;PCLATH adquiere el valor 0x08, tal como lo explicaste         

           call        RET_1_SEG     ;COMO PRECAUCIÓN SE GENERA UN RETARDO DE 1 SEGUNDO   

           pagesel $                    ;PCLATH adquiere el valor 0x00, tal como lo explicaste
       
           bsf    PORTD,7             ;SE CONMUTA LA LLAVE ELECTRÓNICA PARA PODER COMUNICAR LA
                                             ;CENTRAL CON EL MÓDULO DE CONTROL DEL DISPLAY

                     
           .....
           .....
           .....
         
Seguramente, si sigo agregando líneas de programación, ocurrirá lo mismo, voy a ver si puedo profundizar y entender bien las excelentes explicaciones. Gracias nuevamente por la paciencia, saludos







Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 18 de Agosto de 2009, 14:51:59
Hola. Podes agregar lineas siempre y cuando hagas lo que te mencioné.

Hace así: antes de la primer subrutina de demora(que vi que tenes varias), agregá un org 0x800 para indicarle que ya eso empieza a estar en la página 1.

De esta manera te da un poco de margen para que puedas agregar las lineas que te hagan falta en la pagina 0 y no se te vayan despalzando con cada linea que agregas.
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: tapi8 en 20 de Agosto de 2009, 15:31:19
Citar
[/quLa instrucción call(en los uC de 14bits de largo de palabra) sólo puede direccion 12 bits. Esto significa que puede llamar sólo dentro del rango(decimal): [0;2047].
ote]

Bruno creo que aqui tuviste un pequeño lapsus, creo que son 11 bits los que direcciona la instruccion, los 8 del PCL y los 3 menos significativos del PCLATCH.
Lo digo para que no haya confusiones, no por querer quitarle defectos a esta excelente explicacion.

tapi8
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 20 de Agosto de 2009, 15:59:10
Es verdad tapi! Gracias por la corrección.
Saqué mal la cuenta...efectivamente son 11 bits, pero no es como dices lo otro.

Se pasan 11 bits en la Word CALL. Y sólo los bits 4 y 3 del PCLATH son pasados para completar la parte alta del direccionamiento.

CALL Call Subroutine

Syntax: [ label ] CALL k

Operands: 0 ≤ k ≤ 2047

Operation: (PC)+ 1→ TOS,
                 k → PC<10:0>,
                 (PCLATH<4:3>) → PC<12:11>

Status Affected: None

Description: Call Subroutine. First, return
address (PC+1) is pushed onto
the stack. The eleven-bit immediate
address is loaded into PC bits
<10:0>. The upper bits of the PC
are loaded from PCLATH. CALL is
a two-cycle instruction

Saludos!
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: tapi8 en 20 de Agosto de 2009, 16:41:02
Si Bruno yo quise decir eso mismo, igual no lo exprese bien.
Si puedes ( y quieres y tienes ganas ) corrige los ejemplos del final y borrales un 0, para que no haya equivocaciones.

[qEn binario:                   0                   1        0000 00000000
uote][/quote]

saludos
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 20 de Agosto de 2009, 16:59:38
OK. Ya lo corregí
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: tapi8 en 22 de Agosto de 2009, 07:06:44

He adaptado este sencillo programa para ver en el MPLAB como se comportaba y corroborar lo explicado por Bruno. Si no se hacen los PAGESEL al retornar de la subrutina, el programa se pierde cuando ejecuta el "GOTO MAIN", hasta ese punto parece que funciona bien pero cuando llega a ese punto desaparece la flecha de la simulacion y se queda flipao. Si no se hacen los PAGESEL antes de los CALL se pierde en cuanto ejecuta el CALL.
Creo que si a alguien le quedo alguna duda despues de la teoria de Bruno, simulando este programa se le quitaran.



LIST   P=16F877A,            ; usar PIC 16F877A
   #include <p16f877A.inc>

   __CONFIG 3FF1               ; configuracion

Contador1   equ   20            ; definimos nuestros registros               
Contador2   equ   21            ; para el retardo
Contador3   equ   22
Contador4   equ   23

   org   0X00               ; VECTOR DE RESET
   GOTO   INICIO               ; va a inicio
   ORG   0x04               ; VECTOR DE INTERRUPCIONES



   ORG   0X05
INICIO
   BSF   STATUS,5            ; activa la pagina 1
   MOVLW   0XFF               ; carga FF en W
   MOVWF   TRISA               ; puerto A todos entradas aunque este puerto no se va a usar
   MOVLW   0X00               ; carga 00000000 en W
   MOVWF   TRISB               ; mueve W a puerto B (todos salidaS)
   BCF   STATUS,5            ; volvemos a la pagina 0
   CLRF   PORTB               ; ponemos a cero el puerto B para empezar con
                     ; todos los LEDs apagados
MAIN                     ; etiqueta bucle principal
   MOVLW   0X0F               ; cargamos 0b00001111 en W
   MOVWF   PORTB               ; cargamos el puerto B con 0F
   pagesel   DELAY               ; cargamos el PCLATCH con la pag donde esta el DELAY
   CALL   DELAY               ; llama a delay de 0,5 seg
   MOVLW   0X00               ; apagamos leds RB0 a RB3
   MOVWF   PORTB               ; cargamos el puerto b
   pagesel   DELAY1               ; cargamos PCLATH 3 Y 4 para ir a DELAY1
   CALL   DELAY1               ; llama a delay de 0,5 seg
   GOTO   MAIN               ; va a main y repite bucle               
       

ORG         0X800            ; ponemos DELAY en pag.1
DELAY
   movlw   .255               ; cargamos 255 en W
   movwf   Contador1            ; lo cargamos en contador1   
REPITE1   
   movlw   .255                    ; cargamos 255 en W    
   movwf   Contador2            ; lo cargamos en contador2   
REPITE2   
   decfsz   Contador2,1            ; Decrementa Contador2 y se essale.-   
   goto   REPITE2   
   decfsz   Contador1,1            ; Decrementa Contador1 y si es 0 sale   
   goto   REPITE1               ; Si no es cero repetimos ciclo.-
   pagesel   MAIN               ; preparamos el PCLATH para retornar   
   return                  ; retorna de subrutina.-
ORG         0X1F00            ; ponemos DELAY1 en pag.4
DELAY1
   movlw   .255               ; cargamos 255 en W
   movwf   Contador3            ; lo cargamos en contador1   
REPITE3   
   movlw   .255                    ; cargamos 255 en W    
   movwf   Contador4            ; o cargamos en contador2   
REPITE4   
   decfsz   Contador4,1            ; Decrementa Contador2 y si es 0 sale.-   
   goto   REPITE4   
   decfsz   Contador3,1            ; Decrementa Contador1 y si es 0 sale   
   goto   REPITE3               ; Si no es cero repetimos ciclo.-
   pagesel   MAIN               ; preparamos PCLATH para retornar   
   return                  ; retorna de subrutina.-
   END
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 24 de Agosto de 2009, 10:31:52
OK. Ya lo corregí

Hola de nuevo gente, había desaparecido un poco debido que estaba aplicando las recomendaciones que ustedes me dieron. Logré avanzar bastante, hice modificaciones, tales como no llamar subrutinas, si el contenido de estas se ejecutan una sola vez, así evito hacer un “call”, con lo que el pcl no realiza “saltos”.
Estoy teniendo algunos inconvenientes cuando hago un “go to”, espero resolverlos, creo que con todo lo que he aprendido con ustedes será así, tengo otra consulta sobre parte del desarrollo del programa en cuestión, la parte en la que hago una lectura secuencial de la memoria externa, en este caso leo 16 posiciones de esta, y cada dato leído lo deposito en 16 registros diferentes, le busqué la vuelta y no pude resolverlo tal como figura a continuación:   
         
;*** PROCESO DE CARGA DE LOS VALORES LEÍDOS EN LA MEMORIA EN LOS REGISTROS CORRESPONDIENTES ***

  LER_MEM_INI movlw 0x01          ;SE MUEVE EL VALOR 0x01 A CON_DAT_I2C, DE ESTA FORMA, SE VAN A 
           movwf  CON_DAT_I2C      ;DEPOSITAR CORRECTAMENTE, EN EL REGISTRO QUE CORRESPONDE, LOS
                                                  ;DATOS LEÍDOS DE LA MEMORIA
   
           movf    DAT_OBT_I2C,W    ;SE MUEVE DAT_OBT_I2C A W   
           movwf  NVL_SEC               ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE             

REP_LEC_MEM incf  CON_DAT_I2C,F ;CON_DAT_I2C SE INCREMENTA EN UNA UNIDAD
                           
           movlw  0xA1                ;SE MUEVE EL VALOR 0xA1 A SEL_DIS, DE ESTA FORMA SE VUELVE A
           movwf  SEL_DIS_I2C   ;SELECCIONAR LA MEMORIA EXTERNA Y SE INDICA QUE SE VA A LEER EN
                                             ;ELLA   
           
           pagesel SEC_SEL_DIS  ;SE PASA A LA SEGUNDA PÁGINA             

           call   SEC_SEL_DIS
           call   LER_I2C
           call   DET_I2C

           pagesel $            ;SE PASA A LA PRIMERA PÁGINA
   
           movf   CON_DAT_I2C,W ;SE MUEVE CON_DAT_I2C A W
           sublw  0x02          ;SE LE RESTA EL VALOR 0x02           
           btfsc  STATUS,2      ;¿ES EL SEGUNDO DATO? 
           goto   DAT_002       ;SI
           
           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x03          ;SE LE RESTA EL VALOR 0x03           
           btfsc  STATUS,2      ;¿ES EL TERCER DATO? 
           goto   DAT_003       ;SI
             
           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x04          ;SE LE RESTA EL VALOR 0x04           
           btfsc  STATUS,2      ;¿ES EL CUARTO DATO? 
           goto   DAT_004       ;SI
         
           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x05          ;SE LE RESTA EL VALOR 0x05           
           btfsc  STATUS,2      ;¿ES EL QUINTO DATO? 
           goto   DAT_005       ;SI

           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x06          ;SE LE RESTA EL VALOR 0x06           
           btfsc  STATUS,2      ;¿ES EL SEXTO DATO? 
           goto   DAT_006       ;SI

           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x07          ;SE LE RESTA EL VALOR 0x07           
           btfsc  STATUS,2      ;¿ES EL SÉPTIMO DATO? 
           goto   DAT_007       ;SI
           
           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x08          ;SE LE RESTA EL VALOR 0x08           
           btfsc  STATUS,2      ;¿ES EL OCTAVO DATO? 
           goto   DAT_008       ;SI
                     
           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x09          ;SE LE RESTA EL VALOR 0x09           
           btfsc  STATUS,2      ;¿ES EL NOVENO DATO? 
           goto   DAT_009       ;SI

           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x0A          ;SE LE RESTA EL VALOR 0x0A           
           btfsc  STATUS,2      ;¿ES EL DÉCIMO DATO? 
           goto   DAT_010       ;SI

           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x0B          ;SE LE RESTA EL VALOR 0x0B           
           btfsc  STATUS,2      ;¿ES EL NÚMERO 11? 
           goto   DAT_011       ;SI

           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x0C          ;SE LE RESTA EL VALOR 0x0C           
           btfsc  STATUS,2      ;¿ES EL NÚMERO 12? 
           goto   DAT_012       ;SI

           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x0D          ;SE LE RESTA EL VALOR 0x0D           
           btfsc  STATUS,2      ;¿ES EL NÚMERO 13? 
           goto   DAT_013       ;SI
           
           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x0E          ;SE LE RESTA EL VALOR 0x0E           
           btfsc  STATUS,2      ;¿ES EL NÚMERO 14? 
           goto   DAT_014       ;SI
 
           movf   CON_DAT_I2C,W ;NO, SE MUEVE CON_DAT_I2C A W
           sublw  0x0F          ;SE LE RESTA EL VALOR 0x0A           
           btfsc  STATUS,2      ;¿ES EL NÚMERO 15? 
           goto   DAT_015       ;SI
           goto   DAT_016       ;NO, ES EL ÚLTIMO, EL NÚMERO 16


 
DAT_002    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  RET_DIS       ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE           
           goto   REP_LEC_MEM

DAT_003    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  NVL_CON       ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE                                   
           goto   REP_LEC_MEM

DAT_004    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  NVL_BRL       ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE
           goto   REP_LEC_MEM

DAT_005    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  NVL_REF_INF   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE             
           goto   REP_LEC_MEM

DAT_006    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  NVL_REF_NOR   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE               
           goto   REP_LEC_MEM

DAT_007    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  NVL_REF_SUP   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE                 
           goto   REP_LEC_MEM

DAT_008    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  VEL_PRO       ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE                 
           goto   REP_LEC_MEM

DAT_009    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  EST_BUZ       ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE                 
           goto   REP_LEC_MEM

DAT_010    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  PEL_PRO       ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE               
           goto   REP_LEC_MEM

DAT_011    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  FLG_INI_PRO   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE                           
           goto   REP_LEC_MEM

DAT_012    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  FLG_FIN_PRO   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE
           goto   REP_LEC_MEM
         
DAT_013    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  DIG_MEM_001   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE
           goto   REP_LEC_MEM

DAT_014    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  DIG_MEM_002   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE
           goto   REP_LEC_MEM

DAT_015    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  DIG_MEM_003   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE
           goto   REP_LEC_MEM

DAT_016    movf   DAT_OBT_I2C,W ;IDEM A LÍNEA
           movwf  DIG_MEM_004   ;SE COPIA EL DATO EN EL REGISTRO QUE CORRESPONDE                 

;**********************************************************************************************
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: BrunoF en 24 de Agosto de 2009, 17:24:38
Por favor, en estos casos es necesario que muestres todo el código. Primero comprimilo en formato zip o rar y luego adjuntalo a un post para poder ayudarte...

Saludos.
Título: Re: PROBLEMAS CON PCL, EN PIC16F877
Publicado por: GRUTTIS en 24 de Agosto de 2009, 17:53:47
Por favor, en estos casos es necesario que muestres todo el código. Primero comprimilo en formato zip o rar y luego adjuntalo a un post para poder ayudarte...

Saludos.

Hola, bien acá va de nuevo con las modificaciones qye he hecho hasta ahora: