Autor Tema: Cuando en una variable se opera con su valor y cuando con su dirección  (Leído 4245 veces)

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

Desconectado jurgen

  • PIC10
  • *
  • Mensajes: 6
Buenos días a todos;
Lo primero es agradecer de antemano, las explicaciones que me iréis dando sobre preguntas que me irán surgiendo en el estudio del PIC16F84A del libro MICROCONTROLADORES PIC16F84 "DESARROLLO DE PROYECTOS".
Deciros también que me perdonéis si pregunto alguna cosa repetida o que parezca una "bobada", ya que soy nuevo tanto en el estudio de microcontroladores como de este foro.

Sin más preámbulo, os cuento mi duda. Dado el código de abajo, simulándolo en MPLAB IDE 4.10, no sé realmente cuando se opera con el "valor" de la variable y cuando con su "dirección"
Inicio
   movlw   RAM_UltimaDireccion-RAM_Contador   ; Número de posiciones a escribir.
   movwf   RAM_Contador
   movlw   RAM_Contador+1      ; Primera posición de RAM libre


Dado que cuando simulo y me sitúo en esta parte, RAM_Contador obtiene un valor 67 procedente del WREG, pero luego al sumarle +1 en la siguiente instrucción, se mueve al WREG con un valor (su dirección + 1) de 13.

Un saludo y gracias

;*********************************** Indirecto_01.asm ***********************************
;
;   ===================================================================
;     Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;     E. Palacios, F. Remiro y L. López.
;      Editorial Ra-Ma.  www.ra-ma.es
;   ===================================================================
;
; Este programa comprueba el funcionamiento del direccionamiento indirecto. Se trata de
; escribir con el valor de una constante a partir de la última dirección ocupada de
; la memoria RAM de datos hasta el final.
; Su correcto funcionamiento debe comprobarse con el simulador del MPLAB.
;
; ZONA DE DATOS **********************************************************************

   __CONFIG   _CP_OFF  &  _WDT_OFF & _PWRTE_ON & _XT_OSC
   LIST      P=16F84A
   INCLUDE  <P16F84A.INC>

   CBLOCK   0x0C
   RAM_Contador
   ENDC

Constante      EQU   2Ah      ; Por ejemplo.
RAM_UltimaDireccion  EQU   4Fh      ; Ultima dirección de RAM de datos utilizada para
               ; el PIC16F84A.
; ZONA DE CÓDIGOS ********************************************************************

   ORG    0
Inicio
   movlw   RAM_UltimaDireccion-RAM_Contador   ; Número de posiciones a escribir.
   movwf   RAM_Contador
   movlw   RAM_Contador+1      ; Primera posición de RAM libre.
   movwf   FSR         ; Primera dirección de memoria RAM a escribir
RAM_EscribeConstante
   movlw   Constante         ; Escribe el valor de la constante en la posición
   movwf   INDF         ; apuntada por FSR. (W) -> ((FSR))
   incf   FSR,F         ; Apunta a la siguiente dirección de memoria.
   decfsz   RAM_Contador,F
   goto   RAM_EscribeConstante
Principal
   sleep            ; Pasa a reposo.

   END

;   ===================================================================
;     Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;     E. Palacios, F. Remiro y L. López.
;      Editorial Ra-Ma.  www.ra-ma.es
;   ===================================================================

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Cuando en una variable se opera con su valor y cuando con su dirección
« Respuesta #1 en: 24 de Junio de 2018, 10:47:34 »
Yo pienso que el ejemplo de aplicacion es ... raro. Pero tiene un par de puntos a considerar e interesantes.

Primero vamos a responder tu pregunta.

Citar
Cuando en una variable se opera con su valor y cuando con su dirección

Depende, si vos tenes que acceder a 1 valor, 2 valores, o multiples valores totalmente dispersos sin ninguna relacion matematica entre ellos, es mejor acceder de forma directa al registros.
Ejemplo si tuvieras un registro en la direccion 0x20, luego en 0x35 y finalmente en 0x37, es complejo de realizar UNA operacion matematica que transforme el 0x20 en 0x35, y luego el 0x35 en 0x37.

Distinto si vos tenes que trabajar con varios registros que se encuentran seguidos, suponete 0x20 ,0x21 ,0x22 ,0x23 ,0x24 ,0x25 hasta 0x39
Ahi usas el registro indirecto ( FSR) y luego le vas sumando 1 (tu operacion matematica) para recorrer facilmente todos esas posiciones de memoria.
Y aca es ... ¿cuando es que terminas? Por que si seguimos sumando de a 1, nunca vamos a parar, entonces podes hacerlo de 2 formas.
La primera es usar un contador, y cargar previamente la cantidad de direcciones de memoria, 32 en este ejemplo, Esto lo hace tu programa pero lo calcula al momento de compilarlo.
La otra es verificar cuando el FSR es igual a la ultima posicion de memoria que debo escribir, en este ejemplo para cuando FSR seas 0x39, ya no debo incrementar mas y salir o volver al inicio.

Doy otro ejemplo, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A , en ves de incrementar en 1 a FSR, esta ves lo haces de a 2, (suponete que son numeros de 16bits y tenes que pasar por estos)

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

Luego de solucionado CUANDO es que vas a usar el acceso indirecto, vamos a hablar un poco del codigo.

Código: ASM
  1. CBLOCK   0x0C
  2.    RAM_Contador
  3.    ENDC
  4.  
  5. Constante      EQU   2Ah      ; Por ejemplo.
  6. RAM_UltimaDireccion  EQU   4Fh      ; Ultima dirección de RAM de datos utilizada para

CBLOCK y EQU cumplen la misma funcion, ambos asignan a un nombre el valor de una constante, la diferencia es que CBLOCK ( bloque de constantes ) le das un valor inicial y se va incrementando desde alli. Si tuviera 1 "nombre" mas dentro del CBLOCK ese, tendria el valor 0x0D.

Como dije son CONSTANTES, por eso mismo uno puede operar moviendo ese valor constante a W, como si fuera un numero cualquiera. El compilador al compilar (valga la redundancia):

Código: ASM
  1. movlw   RAM_UltimaDireccion-RAM_Contador   ; Número de posiciones a escribir.
  2.    movwf   RAM_Contador
  3.    movlw   RAM_Contador+1      ; Primera posición de RAM libre.
  4.    movwf   FSR         ; Primera dirección de memoria RAM a escribir

Procede a reemplazar cada uno de esas constantes que definiste antes por sus valores numeros correspondientes.

Código: ASM
  1. movlw   0x4F - 0x0C   ; Número de posiciones a escribir.
  2.    movwf   0x0C
  3.    movlw   0x0C+1      ; Primera posición de RAM libre.
  4.    movwf   FSR         ; Primera dirección de memoria RAM a escribir

El problema viene ahora entender que cada instruccion funciona distinto. No es lo mismo MOVLW 0x0C que MOVWF 0x0C. A pesar que tienen el mismo valor, la primera hace que W sea igual a 0x0C, pero NO SIGNIFICA que en W voy a tener el CONTENIDO de la direccion de 0x0C. Entonces vamos a hacer un paso a paso con la version ya "compilada":

Código: ASM
  1. movlw   0x43   ; Número de posiciones a escribir 0x4F - 0x0C = 0x43 = W.
  2.    movwf   0x0C      ; Aca la direccion de 0x0C va a tener el valor 0x43
  3.    movlw   0x0C+1      ; Primera posición de RAM libre. W = 0x0D
  4.    movwf   FSR         ; Primera dirección de memoria RAM a escribir  FSR = 0x0D


Entonces lo primero que genera es la cantidad de posiciones a escribir que es el numero 0x43, computado con las constantes definidas antes.
Luego lo guarda en RAM_Contador, ya que es necesario llevar el contador en algun registro, para saber cuantos me faltan.
Y finalmente procede a cargar el FSR con la direccion de memoria que le sigue (0x0D) a RAM_Contador ( 0x0C ).
Y esa fue tu preparacion inicial, luego vas a decrementar RAM_Contador hasta que llegue a 0, para determinar cuando necesitas parar con tu codigo (lo que vas a repetir).
Y tu codigo lo unico que hace es asignar un valor llamado Constante ( 0x2A ) a cada una de las posiciones de memoria.

PD:

Por si no lo entendiste, pensa todo lo que definis como EQU y CBLOCK como constantes, no necesariamente necesitan ser una direccion de memoria RAM valida.

Por ejemplo suponete que tenes un programa, lo voy a hacer en pseudocodigo. A pesar que lo vas a hacer otra forma a este ejemplo, quiero mostrarte que podes hacer.

Código: [Seleccionar]
Si ( estado = 0 )
     -> Hago esto.
Si (estado = 1 )
    -> Hago lo otro
Si ..... etc, sigue como con 5 estados.

El principal punto de un codigo es que sea legible, cuando lo abras recuerdes facilmente que escribiste o hiciste, entonces estados 0,1,2,3,4 no se que es cada cosa.
Ahora supongamos que sabes que es cada cosa, y digamos que 0 es APAGADO, 1 es PRUEBA, 2 es COMUNICACION, esto por darle unos nombres. Vos podrias hacer:

Código: ASM
  1. CBLOCK 0x00
  2.   APAGADO     ;0x00
  3.   PRUEBA        ;0x01
  4.   COMUNICACION  ;0x02
  5.   ENDC

Y ahora en tu programa en ves de comparar con 0x1, 0x2, vas a comparar con APAGADO, PRUEBA, etc. Que para el compilador ES LO MISMO, ya que al compilar va a reemplazar esos nombres por los valores. Pero si observas no lo usamos como posiciones de memoria en la RAM a esas constantes.

Obviamente si usas una instruccion como MOVF, MOVWF con APAGADO, vas a intentar acceder a la posicion 0x00 que es la del registro INDF
« Última modificación: 24 de Junio de 2018, 11:02:09 por KILLERJC »

Desconectado jurgen

  • PIC10
  • *
  • Mensajes: 6
Re:Cuando en una variable se opera con su valor y cuando con su dirección
« Respuesta #2 en: 24 de Junio de 2018, 14:32:08 »
Buenas Tardes;
Gracias por responder tan rápido KILLERJC.
Si que entiendo que son constante definidas con "EQU" y variables definidas con "CBLOCK". Se también que las puedes usar como valores para operaciones o direcciones de memoria. También entendiendo lo que realiza el ejercicio que copie del libro. Realmente el problema que tengo es:
En una operación como por ejemplo esta:
Código: ASM
  1. movlw   RAM_UltimaDireccion-RAM_Contador   ; Número de posiciones a escribir.
  2.    movwf   RAM_Contador
  3.    movlw   RAM_Contador+1      ; Primera posición de RAM libre.
  4.    movwf   FSR         ; Primera dirección de memoria RAM a escribir
Cuando "RAM_Contador" realizando un operación su valor es de su dirección de memoria (0x0C) o cuando realizando otra operación tiene el valor contenido variable (0X43). Por ejemplo siguiendo el libro que he comentado antes, las instrucciones aritméticas que hasta el momento había visto hasta el momento de suma por ejemplo eran addlw, ... no con el símbolo "+". Entonces ¿si en dos variables definidas en CBLOCK escribo en el programa movlw Var1 + Var2, suma sus direcciones de memoria y no el valor que contenga dichas variables?


Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Cuando en una variable se opera con su valor y cuando con su dirección
« Respuesta #3 en: 24 de Junio de 2018, 15:35:45 »
Citar
Si que entiendo que son constante definidas con "EQU" y variables definidas con "CBLOCK"

Y es un error lo que decis, AMBAS SON CONSTANTES! es un numero nomas. No significan que estan atadas a una posicion de memoria, es decir al declararlas, uno declara constantes, no posiciones de memoria.

Pensalo como algo que va a ser reemplazado luego en el texto del codigo. Y que dependiendo de la instruccion que se use va a tomarse como un numero o como una posicion de memoria.

Citar
Por ejemplo siguiendo el libro que he comentado antes, las instrucciones aritméticas que hasta el momento había visto hasta el momento de suma por ejemplo eran addlw, ... no con el símbolo "+".

Entonces vamos a hablar de como es que se compila un programa. Cuando compilamos un programa, tenemos un compilador y un linker ( enlazador )

Uno provee el archivo .asm o .s al compilador, este lo compila y devuelve un archivo objeto, finalmente el/los archivos objetos pasan por el linker, y ahi se genera el "ejecutable" del micro.

Entonces tenemos 2 procesos, que son la compilacion y el enlazado.

Dentro de la compilacion, uno de los trabajos del compilador es tratar de optimizar un poco el codigo, o en caso de que uno le presente alguna operacion con constantes, reemplazarlo por la constante final. Ya que no tendria sentido realizarse en tiempo de ejecucion si se puede hacer antes, esto se nota mas en lenguajes de un nivel mas alto, ya que aca no permite la traduccion de simbolos +/- en instrucciones de ASM.

Distinto son las INSTRUCCIONES del microocontrolador. Que estas SI las ejecuta el micro.
Cuando vos tenes un MOVLW, el micro espera algo asi:

   movlw   0x00

Es decir una instruccion con un numero, Donde 0x00 seria el numero que vos desees. Entonces es trabajo del compilador y linker tratar de que eso sea asi ( y tuyo tambien). Por suerte el compilador nos provee que podamos usar restas/sumas/multiplicaciones/desplazamientos en nuestro codigo para realizarse en el proceso de compilacion. Al realizar esto:

   movlw   RAM_UltimaDireccion-RAM_Contador

En un primer momento, procede a reemplazar cada una de esas constantes por el valor que le corresponde. y en caso de tener una operacion realizarla (porque son numeros fijos) para que quede como debe ser la instruccion para el micro. Entonces queda como:

   movlw   0x43

Esto es lo que luego se pasa al linker, lo que luego se codifica como instruccion para el microcontrolador.
Tambien es de notar como te decia, es que son valores fijos, con esto me refiero a que en esa instruccion en tiempo de compilacion, JAMAS podrias leer el contenido de RAM_Contador o de cualquier otra posicion de memoria, porque no se esta resolviendo en tiempo de ejecución, sino mucho antes, en la compilacion.

Si no me crees que todo ese reemplazo ocurre ANTES de la ejecucion, trata de compilarlo y mirar el Disassembly del programa ( o el Program Memory ) y vas a ver que las instrucciones finales que ejecuta el "simulador" y por lo tanto el microcontrolador son esas.
Ahi en el program memory vas a ver las instrucciones que ejecuta el microcontrolador, todo lo que ocurre entre ese pedazo final y el original es parte de la compilacion/linkeo

Desconectado jurgen

  • PIC10
  • *
  • Mensajes: 6
Re:Cuando en una variable se opera con su valor y cuando con su dirección
« Respuesta #4 en: 29 de Junio de 2018, 17:48:02 »
Buenas Tardes;

Gracias por tu tiempo y por tu respuesta KILLERJC.

Un saludo.