Lenguaje ensamblador para pic ?

Mira, sucede esto:

Cuando pones:

Código:
	CO1	equ	0x20
	CO2	equ	0x21

Estas haciendo dos cosas a la vez:

Estas asignando a la dirección de RAM 0x20 el nombre de CO1 y estas determinando una constante llamada CO1 que tiene el valor de 0x20, lo mismo pasa con CO2, la dirección RAM 0x21 se llamara CO2 y puedes usar a el nombre CO2 como una constante.

¿Como es esto posible?

Te lo explico con un ejemplo:
---------------------------------------------------------------------------------------------------------
Cargaremos a W con el valor del registro de la RAM 0x20, es decir con el valor de RAM de CO1:

Código:
	MOVF	CO1,W

Aqui, lo que contenga la RAM con direccion 0x20 sera depositado en W y podra ser un valor entre 0 y 255, dependiendo de lo que haya sido puesto en el con anterioridad.
---------------------------------------------------------------------------------------------------------
Cargaremos a W con el valor constante de CO1, es decir el valor constante de 0x20, no cargaremos al valor de RAM que es un valor variable, si no el constante que vendría siendo un 32 decimal.

Código:
	MOVLW	CO1
---------------------------------------------------------------------------------------------------------

Entonces, lo que podrás deducir con esto, es que en el siguiente código:

Código:
	movlw	RETARD1
	movwf	CO2

Tu profesor esta cargado al Registro RAM con dirección 0x20, cuyo nombre con el que lo bautizaste es CO1, el valor constante de RETARD1, que viene siendo un 218 decimal.

Si se pone la siguiente instrucción:

Código:
	movf	RETARD1,W
	movwf	CO2

Entonces estaríamos cargando el valor de la RAM con dirección 0:LOL:A, que puede ser cualquier número aleatorio entre 0 y 255.


CO1, CO2, CO3, RETARD1 y RETARD2 son nombres con los que, principalmente, vas a recordar ciertas direcciones RAM, digo, no creo que vayas a querer estar recordando que la dirección 0x20 es de un contador, la 0x21 es otro contador y asi sucesivamente, por eso se les asignan nombres. Pero, de manera implícita, el nombre lleva un valor constante, que vendría siendo el valor constante de la dirección RAM, no el valor del registro propio.

Espero que me haya explicado de manera clara. Si no fue así, entonces renunciare a mi intención de ser maestro :cry: .
 
Están en hexadecimal y los he pasado a binario.
Supongo que es mejor tenerlo en binario para saber que registros pondremos a 0 y a cuales 1
Pues no... en este caso no nos interesa el valor en binario, sino su valor entero, porque lo único que vamos a hacer es... dar vueltas en una serie de bucles.

Ahora vamos a (creo que se llama así) rutina que le llamaremos: Delay_1seg
Código:
movlw  RETARD1
movwf  CO2 
movlw  RETARD2
movwf  CO3
clrf   CO1
Vale. Aquí está mi gran duda. Intentaré ir por pasos.

1) Yo digo que CO1,CO2,CO3 (contadores ) que como le hemos puesto equ, son constantes.
No. Los contadores son registros (posiciones de la memoria RAM.

Pues vale. A su pregunta: ¿Por qué carga a los registros CO2 y CO3 con las constantes de RETARDO1 y RETARDO2?

(No sería si digo una tontería)
Estamos dando unos valores a los registros, que hacen poner unos bits de dentro del registro a 0 o a 1 según sea el valor del literal.
Más sencillo: inicializamos los contadores con unos valores. No estamos inicializando los contadores con valores constantes, si no que solo se inicializan con unos valores. A partir de ahí, el resto de programa va modificando los contadores (por efecto de los decrementadores).

Y lo que tenga que hacer el registro, dure lo que valga el retardo y luego por arte de magia se limpia el registro CO1
¿Magia? Por desgracia, aquí no hay magia.

Si un contador se inicializa a 0 (con un clr, por ejemplo), entonces es lo mismo que si lo hubiéramos inicializado a 256, ya que la primera ejecución de decfsz lo hará pasar de 0 a 255. Seguirá decrementando hasta que llegue a 0, y en ese momento sí que terminará el bucle.

Bien. Según por lo que he podido leer, avanza.
¿Es una subrutina a la que hemos llegado a ella con un CALL que pone todos los contadores a 0 y se vuelve a la rutina de donde esta el CALL (que nos ha llevado hasta avanza) y empieza a ejecutar la instrucción siguiente del CALL?
Sí. La presencia del 'return' así lo indica.

Te aconsejo que leas los enlaces que te he dejado antes.

Este código hará el retardo de 1 segundo utilizando el procesador.

Inciso (por si voy mal encaminado):
El tiempo de operación son 4 por 1 tiempo de reloj, que un tiempo de reloj es 1/f=1/20 MHz = 50 ns
4 por 50 ns = 200 ns por instrucción.
¿Estás completamente seguro de que este código es para un microcontrolador funcionando a 20 Mhz?

He sumado los ciclos que consumen los bucles y me da una cifra cercana a un millón de ciclos, por lo que, para ser el retardo de 1 s, es necesario que el microcontrolador funcione a 4 Mhz.

Si está a 20 Mhz, ese retardo será de 1/5 s.

(Salvo que me haya equivocado en el cálculo de los ciclos.)
 
Última edición por un moderador:
Hola, el jueves de la semana que viene tengo el examen de esta asignatura, entra hasta el tema 4, y todo esto es del tema 3, necesito entender bien esto y pasar ya al siguiente tema. Ademas, este jueves tengo examen de sistemas operativos y ademas de otros trabajos que entregar.La verdad es que estoy temblando de lo que me viene encima, de lo difícil de entender y del poco tiempo que tengo.
Una vez que me he desahogado vamos a lo importante.

Voy hacer un resumen de todo el código que incluya todo lo que me habéis dicho y todas las explicaciones paso por paso para intentar entenderlo bien.
Allá voy:
--------------------------------------------------
Tenemos el siguiente código=
Código:
CO1            equ   0x20
                       CO2            equ   0x21
                       CO3            equ   0x22
                       RETARD1  equ   0xDA
                       RETARD2  equ   0x07

Delay_1seg:
                     movlw  RETARD1
                     movwf  CO2 
                     movlw  RETARD2
                     movwf  CO3
                     clrf   CO1

avanza:
                 decfsz  C01,F
                 goto    avanza
                 decfz   C02,F
                 goto    avanza
                 decfsz  C03,F
                 goto    avanza
                 return
--------------------------------------------------
Vamos a estructurar nuestro código en 3 partes:

Parte 1
Código:
CO1            equ   0x20
                       CO2            equ   0x21
                       CO3            equ   0x22
                       RETARD1  equ   0xDA
                       RETARD2  equ   0x07
Podemos decir que esta parte es la de inicialización y la creación de las variables

A) Nos fijamos en este "trozo de código", y vemos que tenemos 5 elementos. Por intuición vemos que a 3 valores: CO1,CO2 y CO3 (son abreviaciones de la palabra contadores) se está utilizando el comando equ,

"cuya utilización es para darle unos valores a estos nombres y convertirlos en unas constantes, para que , igual de recordar valores necesarios que utilizamos repetidamente, utilizamos nombres, ya que es mas fácil de recordar/utilizar"

Estos valores que se le están asignando, por sus valores que se les dá son posiciones de la memoria RAM libres, que , como no hemos hecho ningun cambio, son posiociones libres de la memoria RAM ubicados en el trozo del BANCO 0.

Hasta aquí, hemos hecho= Alquilar unas posiciones de la memora RAM libres del BANCO 0 y asignales un nombre(Recordar que:No hemos puesto ningun valor dentro de los contadores) por lo tanto, ahora podemos decir que CO1,CO2 y CO3 , son registros


B) Para las otras 2 'cosas' (ya se que no se le llaman cosas pero lo digo en sentido del primer momento que lo miramos) que vemos en un principio, por intuición vemos que son NOMBRES con equ con unos valores, pero valores en sentido de LITERAL, por lo tanto RETARD1 y RETARD2 , podemos decir que son constantes

Parte 2

Código:
Delay_1seg:
                     movlw  RETARD1
                     movwf  CO2 
                     movlw  RETARD2
                     movwf  CO3
                     clrf   CO1

Esta parte, como dice su instrucción en ingles, la llamaremos , retraso 1 segundo.

Después de pegarle un ojo al pequeño código, a primera vista, se trata de meter el valor de la constantes RETARD en los registros(Recordemos que están vacíos, no hemos metido nada- aun así antes de todo podríamos hacer una limpieza de los registros contadores por si acaso)

Okey, pues a grosso modo, lo que se hace es , metemos el valor de RETARD1 en el acumulador(w) y despues lo pasamos al contador 2 , y hacemos luego lo mismo con RETARD2.(Recordemos= el acumulador no almacena datos, se sobrescribe y lo que estaba se pierde) metemos su valor en el contador 3. La ultima instrucción es de limpiar / poner a 0 el contaor 1(esto lo hacemos por que será necesario para el siguiente trozo de codigo <- de esto no estoy seguro)

Resumen= hemos colocado los valores de RETARD1 y RETARD2 en los registros C02 y C03 respectivamente. Tambien hemos hemos limpiado el registro CO1 para hacer la funcion :

"Si un contador se inicializa a 0 (con un clr, por ejemplo), entonces es lo mismo que si lo hubiéramos inicializado a 256, ya que la primera ejecución de decfsz lo hará pasar de 0 a 255. Seguirá decrementando hasta que llegue a 0, y en ese momento sí que terminará el bucle."" <- ESTO NO LO ENTIENDO(mirar haber si lo digo bien en la parte 3)

Parte 3

Código:
avanza:
                 decfsz  C01,F
                 goto    avanza
                 decfz   C02,F
                 goto    avanza
                 decfsz  C03,F
                 goto    avanza
                 return
Vale, ultima parte
Si hacemos una simple vista podemos decir que , al haber un return, esto es una subrutina de alguna rutina que tiene un CALL y nos manda aqui(cuando en esta subrutina se llegue a return, volveremos a la rutina que tenia ese CALL, pero ya empezaremos por la ejecución siguiente/o la de debajo , de ese CALL)

Pues bien, decrementamos el registro C01, que según la explicación de Joanquin, habrá que hacerlo 255 veces. recordad que no lo entiendo esto bien, me he leido la explicación 20 veces y creo entender esto:
el registro C01 de forma predeterminada esta en la memoria RAM vació , con un valor '0'. Vale, este valor 0=256.
Por lo tanto, la primera instrucción será: 0->255, la siguiente instrucción 255->254, la siguiente instrucción 254->253....y así sucesivamente.
Peró ¿para que hacemos esto? Supongo que para la ecuación de los tiempo , saldrá que los ciclos del registro C01 deberá ser 256 veces (uno arriba, uno abajo)

Sigamos, pues cuando en el registro C01 halla de nuevo el valor 0=256, saltará el goto(hay que sumarle 1 al tiempo de poner a 0) y pasará a la instrucción de decrementar el registro contador C02 , pero aquí será menos tiempo, aquí se tardará 0:LOL:A->(base decimal) 218 ciclos + 1 ciclo/tiempo de saltar el goto.
Hacemos lo mismo para
Código:
decfsz  C03,F
                 goto    avanza
                 return
Y FINAL, nos vamos a la rutina principal , a seguir con la instruccion del codigo debajo del CALL.


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

Buenoo gente , espero que esté bien, y me podáis confirmar que lo entiendo y que puedo pasar al siguiente tema.
Cualquier cosa que diga mal corregidmela por que lo he detallado todo al máximo para intentar plasmar todo el conocimiento que tengo.

Gracias.(ahora mientras me contestais , empezaré con la ultima parte del tema 3 que es calcular los tiempos de este codigo y estudiar para el examen de Sistemas Operativos de jueves.)
:)
 
Por intuición, nada. O se sabe, o no se sabe.

'equ' es la abreviatura de 'equal', que podemos traducir por 'igual a'.

Sirve para asociar un valor o texto a una constante, dentro del ámbito del programa en ensamblador.

'Delay_1seg' no es el nombre de la primera parte del código, sino de toda la subrutina.

Sobre CO1, olvídate del 256. Piensa que se inicializa en 0 (por efecto del clr). Entonces, siguiendo con la ejecución del programa, al llegar al primer decfsz, al ser 0, pasa a 255 (es un byte, y si vale 0, al restar 1, pasa a ser -1, que vemos como un 255 -repasa la numeración en complemento a 2-).

Por eso, el primer bucle son 256 vueltas. De las cuales se computan 255 vueltas que consumen 3 ciclos, y una más (la última) que consume 2 ciclos.

Lo mismo se aplica a los otros dos bucles.
 
-Entonces,quitando la instuición, como sabes que C01 será un registro y RETARD una constante , por que los dos tienen equ y los dos tienen un valor.....Lo siento, pero sigo sin entenderlo.

-okey, entendido! delay_1seg y avanza estan relacionados.

Gracias.
 
Tu piensa que 'equ', lo que hace, es crear definiciones.

Entonces, CO1 equ 0x20 quiere decir que, el ensamblador, cuando esté interpretando el código, cuando se encuentre con 'CO1', debe sustituirlo por '0x20'.

Por ejemplo, si en el código tenemos
PHP:
    clrf   CO1

es como si realmente hubiéramos escrito
PHP:
    clrf   0x20

O sea, que ponemos a cero el contenido de la dirección 0x20.

Como, para nosotros los humanos, es más fácil acordarnos de que CO1 significa 'contador 1', en lugar de usar 0x20, que para nosotros no es más que un número, pues esa es la razón de usar esas definiciones. Son solo etiquetas.

En otra parte del código, pone
PHP:
    movlw  RETARD1		# Cargamos el retardo 1
    movwf  CO2			# en contador 2

en realidad, es como si hubiéramos escrito
PHP:
    movlw  0xDA		# cargamos el entero 0xDA
    movwf  0x21		# en la dirección 0x21

Como ves, es más sencillo para nosotros los humanos usar las etiquetas, que los números.
 
Última edición por un moderador:
pic102 el "equ#" que se usa en ensamblador es como dice juaquinferrero pero ademas esta ligado con la memoria de datos del pic que uses...me explico por ejemplo en la memoria de datos del pic 16f84 esta vacia desde el registro 0C hasta el registro 4F ..entonces cuando usted declara alguna variable por ejemplo

casa equ 0Ch

significa que en la posiscion de memoria de datos 0C se guardara la variable casa y cada vez que la varible casa se modifique el valor se guardara en el registro 0C, esto se hace para facilitar el desarrollo del programa......yo personalmente tengo muchos años que no programo en ensamblador....pero yo creo que uno puede usar directamente los registro hexadesimales
 
Última edición:
Hola a todos, ya he pasado mi examen que tenia de jueves,me fue bien, ahora me queda una semana a tope para preparar el examen del jueves de Microprocesadores.

Ademas de eso, me han mandado un problema de entregar que mas adelante lo haré.
El examen es del tema 1,2,3 y 4

-------------------------(Como siempre, yo pongo todo lo que se, cualquier fallo decidmelo por favor)-----------------------

Una vez acabada la pequeña introducción, quiero acabar de una vez con este código:

Código:
CO1            equ   0x20
                       CO2            equ   0x21
                       CO3            equ   0x22
                       RETARD1  equ   0xDA
                       RETARD2  equ   0x07

Delay_1seg:
                     movlw  RETARD1
                     movwf  CO2 
                     movlw  RETARD2
                     movwf  CO3
                     clrf   CO1

avanza:
                 decfsz  C01,F
                 goto    avanza
                 decfz   C02,F
                 goto    avanza
                 decfsz  C03,F
                 goto    avanza
                 return
--------------------------------

Veamos, según el texto (me equivoque cuando lo dije la otra vez) el PIC trabaja con 4 MHz ( es decir, el oscilador).

Vale , pues nos diponemos a calcular el ciclo de instrucción.

Un ciclo de instrucción :es el período que tarda la unidad central de proceso en ejecutar una instrucción de lenguaje máquina.

En otras palabras, el tiempo que tarda el procesador, micro, en este caso, en procesar/determinar una instrucción

Una instrucción=4 veces el tiempo del relol
1 tiempo del reloj =1/frecuencia
frecuencia = 4 MHz(4*10^6)
1 tiempo del reloj =(1/4)*(1/1*10^6)
(1/1*10^6)= 1 nanosegundo
1 tiempo del reloj = 0.25 nanosegundos
4*0.25= 1 nanosegundos = 1*10^-6 segundos


1 instrucción, me tarda : 1*10^-6 segundo

Y nuestro código, quiero que me retarde 1 segundo( como dije anteriormente-si, ahora es cuando decimos, los retardos mas simples en ensamblador , es ir restando un numero tantas veces hasta que me salga 0 y este tiempo de ir restando valores, hacer que tarde 1 segundo, antes de pasar a la siguiente rutina/trozo de codigo/instrucción o lo que sea. )

Voy a comprobar que este código me tarda como dice el enunciado, 1 segundo.

Concepto:
1 instrucción = 1 tiempo de instrucción
Especiales:
decfsz -> Si su valor que restamos es diferente de 0,tarda 1 tiempo de instrucción
-> Si su valor que restamos es 0, no se hace resta y salta la que tenemos abajo(que suele ser un goto): 2 tiempo de instrucción
goto-> Siempre 2 ciclos de instrucción.

------------------
he pensado que antes de explicar este, intento explicar uno mas sencillo, lo dejo aqui para cuando me ponga con el
este de aquí abajo es el sencillo:
CONTADOR= valor cualquiera
Código:
Delay:  decfsz   COMPTADOR,F
                    goto delay


Voy a intentar explicarlo:
decfsz valdra 1 instruccion cuando su su resultado sea diferente de 0 y 2 cuando sea 0
(CONTADOR -1 )x1ciclo+2 ciclos <- hemos representado el tiempo del decremento.
Ahora le sumo el tiempo del goto
por la variable goto, pasar tantas veces como se reste 1 y no sea 0, es decir CONTADOR-1 y ahora le multiplicamos x2 por que nos lo dice la definicion.
(CONTADOR-1)x2

CONTADOR = n

[(n-1)x1+2] +(n-1)x2= (n-1)+2(n-1)+2= 3(n-1)+2

-------------------------------
a ver si me lo podeis revisar y decidme si esta bien calculado y la explicación esta bien.Si me lo confirmais, pasaré a calcular la formula del código grande


Gracias
 
Última edición:
Sí, en los PIC, se suele tener que el ciclo de instrucción ocupa cuatro ciclos de reloj.

Sobre el cálculo de los ciclos de instrucción, creo que te lías un poco.
PHP:
delay:  decfsz   CONTADOR,F    ; 1 o 2 ciclos
        goto     delay         ; 2 ciclos
En el documento DS31029A, en la página 29-22, donde se comenta el funcionamiento de DECFSZ, dice:

«Los contenidos del registro 'f' se decrementa. Si 'd' es 0, el resultado se coloca en el registro W. Si 'd' es 1, el resultado se vuelve a colocar en el registro 'f'. Si el resultado es 0, la siguiente instrucción (leída durante la siguiente ejecución de instrucción) se descarta y se ejecuta en su lugar un NOP, haciendo de ella una instrucción de dos ciclos». (Si no, se trata de una instrucción de un ciclo).

Entonces... mientras CONTADOR no llegue a 0, tenemos que DECFSZ consume 1 ciclo y ejecuta la siguiente instrucción (el GOTO), que consume 2 ciclos. Cuando CONTADOR llega a 0, DECFSZ consume 1 ciclo, más otro, para "saltar" el GOTO. Por eso decimos que si CONTADOR se inicializa a 'n', el número de ciclos consumidos es: (n-1) * 3 + 2

Todo esto está explicado anteriormente.
 
OKEY! entendido, pues en el codigo :

Código:
CO1            equ   0x20
                       CO2            equ   0x21
                       CO3            equ   0x22
                       RETARD1  equ   0xDA
                       RETARD2  equ   0x07

Delay_1seg:
                     movlw  RETARD1
                     movwf  CO2 
                     movlw  RETARD2
                     movwf  CO3
                     clrf   CO1

avanza:
                 decfsz  C01,F
                 goto    avanza
                 decfz   C02,F
                 goto    avanza
                 decfsz  C03,F
                 goto    avanza
                 return

Tenemos 4 instrucciones en el Delay que tardan 1 cada una , entonces el delay = 4 ciclos de instruccion.

En el avanza, para calcularlo, hacemos:
Contador1 = n1 = 0 =256
Contador2 = n2 = Retardo1= 218
Contador3 = n3 = Retardo = 7

Entonces, el tiempo de ciclos será =
([(n1-1)x1+2] +(n1-1)x2 )+( [(n2-1)x1+2] +(n2-1)x2 )+( [(n3-1)x1+2] +(n3-1)x2 ) +4

¿Está bien?
 
Pues... no :)

Sigue las instrucciones una a una... fíjate que los bucles están anidados...
 
Lo siento Joaquin pero le estoy dando vueltas toda la mañana y me sale lo mismo que mi ultimo mensaje. No se resolverlo. A ver si me puedes ayudar.
Gracias
 
A ver...

Cuando la CPU llega a la etiqueta avanza, comienza el bucle sobre CO1.

Cuando termina ese bucle, decrementa en uno el valor de CO2. Y como no aún no ha llegado a 0 (pues comenzó en 218), regresa a avanza. Y allí se vuelve a encontrar con el primer bucle.

Se decrementa CO1 otra vez, que pasa de 0 a 255 y realiza OTRO bucle entero de 256 vueltas. Y cuando termina, vuelve a decrementar CO2 (pasa de 217 a 216) y regresa a avanza.

Como ves, el bucle de CO2 manda repetir 218 veces el bucle de CO1.

Y esto lo aplicamos a CO3: mandará repetir TODO lo anterior 7 veces. Por eso hablamos de bucles anidados. Pero, ¡ojo!, a la segunda vez que CO3 manda repetir los dos bucles internos, CO2 NO empieza en 218, sino que empieza en 0, por lo que CO2 será un bucle de 256 vueltas. Esto complica un poco más el cálculo.

Te repito que todo esto está explicado en el enlace que te puse en el mensaje #29, más arriba. Aunque se refiere a un tipo de anidamiento ligeramente distinto, el cálculo es muy parecido.

Muéstranos qué tienes hecho hasta ahora.
 
Última edición por un moderador:
Me he leído de arriba abajo tu documento varias veces.Está genial explicado.

He visto que conoces una pagina que nos dio nuestro profesor para consultar los ciclos. Aun no se muy bine como funciona la pagina , pero creo que es interesante.3

http://www.piclist.com/techref/piclist/codegen/delay.htm

Vale. pues ahora ya te entiendo mejor. Cuando acabamos el primer bucle del contador 1 pasamos al contador 2 y este cuando su resultado es diferente de 0, vuelve al principio de delay, volviendo activar el bucle del contador 1.

Tambien tengo que tener en cuenta que el contador1 siempre será 0 cuando pasemos por él.Mientras el contador 2, en cuando volvamos a pasar por el a causa del contador 3, ya estará a 0, y tardará 255 ciclos.

Entonces, mis conclusiones.
Un bucle de decremento = 3(n-1)+2 por defecto

Hay bucle anidado, por lo que cada goto es 1+2xG
G= al numero de goto que vemos por debajo del decremento que nos localicemos.

Ejemplo, el decremento del contador 1 tiene por debajo 3 goto, H=3, por lo tanto 1+6 =7

Resuemiendo:

Contador1 = n1
Contador2 = n2
Contador3 = n3

7[3(n1-1)+2]+5[3(n2-1)+2]+3[3(n3-1)+2]

Pero esta formula seria para un delay donde todos los contadores están inicializados a 0 desde un principio.

Pero ahora tengo dudas en como fragmento la formula 5[3(n2-1)+2] para que me cuente cuando el primer bucle son 218 y luego 256

Por lo que creo que se sería : 1[3(218-1)+2] + 4[3(256-1)+2]


No se si estoy bien encamiendo.

Gracias
 
Según el StopWatch de MPLABX, la cifra final, sin contar el 'return', debe ser de 1 350 598 ciclos de instrucciones (cifra obtenida según los parámetros 0, 218 y 7, iniciales).

Si la primera vuelta del ciclo más exterior tenía inicialmente C02 = 218, entonces, 7-1 vueltas siguientes C02 valdrá 256.
 
Hola, buenos dias

Esta mañana estoy con este código


Código:
comprueba_10:
             sublw  0x0A
             btfsc  STATUS,Z
             retlw  0x00
             btfss  STATUS,C
             retlw  0xFF
             retlw  0x01

Entiendo que lo que hace es mirar si lo que tenemos dentro dentro del acumulador es 10 o no.
Resta 10 a w, si es 0, devuelve el valor 0, sino es 0, mirar si el resultado es negativo, si es asi, devuelve -1 y sino , devuelve 1.

Lo que no entiendo porque ponemos el registro STATUS, si lo que usamos es para cambiar de banco, y tambien me lia lo de C,Z,DC, no entiendo bien esto del carry .

A ver si me podeis aclarar un poco.

Gracias
 
No, no es así.

No estamos restando 10 a W. Es justo al revés: estamos restando W a 10, y el resultado queda en W.

PHP:
comprueba_10:
        sublw  0x0A        ; 10 - (W) => W
        btfsc  STATUS,Z    ; ¿el resultado es 0?            (salta si Z=0)
        retlw  0x00        ; sí, regresa con W =  0
        btfss  STATUS,C    ; no, ¿el resultado es positivo? (salta si C=1)
        retlw  0xFF        ; no, regresa con W = -1
        retlw  0x01        ; sí, regresa con W =  1

El registro STATUS (03h) no solo sirve para cambiar de banco, sino que también almacena los bits C y Z, que guardan el resultado de la última operación.

Z = 1 : el resultado de una operación aritmética o lógica es cero
Z = 0 : el resultado de una operación aritmética o lógica no es cero

C = 1 : ha ocurrido un acarreo en el bit de mayor peso después de la operación anterior
C = 0 : no ha ocurrido el acarreo

El bit DC es lo mismo que C, pero referido a operaciones de nibbles (4 bit).

Al hacer una resta, si la operación dio un número negativo, no ocurre el acarreo, y C se pone a 0. ¡Ojo! No vale con decir que mirando solamente el valor de C podemos saber si el resultado es positivo o negativo. Hay que mirar siempre ANTES el valor de Z.

Resumen:
C | Z | significado
0 | 0 | negativo
1 | 0 | positivo
x | 1 | es 0

Lo tienes explicado es las páginas de manual de SUBLW.

(Cuidado: el significado de C cambia si la operación es ADDLW o ADDWF)
 
Última edición por un moderador:
Hola Joaquin.
He tenido tutoria con el profesor para aclararme de una vez lo del tiempos. Y bueno, me ha dicho que habia un pequeño error, que deberia haber puesto que se volviera a cargar el valor en CO2 el que estaba predeterminado.

(y que sí , que tenia razon-tu tenias razon- que cuando volviera a pasar , el contador era 0 y que era follon hacer el calculo)

Es decir, en un principio teniamos esto:

Código:
CO1            equ   0x20
                       CO2            equ   0x21
                       CO3            equ   0x22
                       RETARD1  equ   0xDA
                       RETARD2  equ   0x07

Delay_1seg:
                     movlw  RETARD1
                     movwf  CO2 
                     movlw  RETARD2
                     movwf  CO3
                     clrf   CO1

avanza:
                 decfsz  C01,F
                 goto    avanza
                 decfz   C02,F
                 goto    avanza
                 decfsz  C03,F
                 goto    avanza
                 return

Pues me ha dicho que seria así:
Código:
CO1            equ   0x20
                       CO2            equ   0x21
                       CO3            equ   0x22
                       RETARD1  equ   0xDA
                       RETARD2  equ   0x07

Delay_1seg:
                     movlw  [COLOR="Green"]RETARD2[/COLOR]
                     [COLOR="green"]movwf  CO3[/COLOR] 
[COLOR="Red"]Carga_CO2 [/COLOR]          [COLOR="green"]movlw  RETARD1[/COLOR]
                     [COLOR="green"]movwf  CO2[/COLOR]
                     clrf   CO1

avanza:
                 [COLOR="Blue"]decfsz  C01,F
                 goto    avanza[/COLOR]
                 [COLOR="DarkSlateGray"]decfz   C02,F
                 goto    avanza[/COLOR]
                 [COLOR="yellow"]decfsz  C03,F
                 goto    CARGA_CO2[/COLOR]
                 return

y el los tiempos quedarían :

Tendriamos: (he agrupado en colores los decrementos)
A ( por ejemplo siendo A-> 3(CO1-1)*TIEMPOCICLO+2*TIEMPOCICLO )
B
C

y segun el quedaria así:
5*TIEMPOCICLO+(A*B*C)*TIEMPOCICLO * 2*TIEMPOCICLO

Tu crees que así esta bien?

Gracias.
---------------------------------------------------------------------------------------------------------------------------
Ya que estamos a ver si puedes ayudarme con el direccionamiento indirecto, que esto es un autentico lio.

Primeramente , no se que quiere decir/ o para que sirve.
Lo unico que encuentro es que es para mover cosas de sitios y no hacerlo directamente pero sigo sin entenderlo.


En este ejemplo,que es un subrutina que inicializa las posiciones de memoria.No consigo entender el direccionamiento.

Código:
inicializa:
            movlw  0x30 //
             movwf  FSR // el valor 48 -> al acumulador -> y lo paso al registro FSR
             
repite:
            clrf   INDF,F //  limpio INDF es un registro, pero ese F , creo que sobra
            incf  INDF,F//Incrementa el contenido de INDF en una unidad.
 El resultado se almacena de nuevo en INDF si F=1 y en W si F=0(en este caso INDF no varía) 

¡¡PERO NO SABEMOS EL VALOR DE F!!!



             incf   FSR,F // lo mismo de antes 
             btfss  FSR,6 // aqui ya me pierdo
             goto   repite
             return

Joaquin a ver si me ayudas a saber como tira esto de direccionamiento indirecto, ya que lo veo ilógico .

Gracias por todo.
 
Última edición:
He tenido tutoría con el profesor para aclararme de una vez lo del tiempos. Y bueno, me ha dicho que había un pequeño error, que debería haber puesto que se volviera a cargar el valor en CO2 el que estaba predeterminado.

(y que sí, que tenía razón -tú tenías razón- que cuando volviera a pasar, el contador era 0 y que era follón hacer el cálculo).
De follón, nada. Es cuestión de aplicar las matemáticas.

Adjunto hoja de cálculo con el resultado del cálculo. Haciendo

C01 = 172
C02 = 19
C03 = 6

se obtienen exactamente un millón de ciclos de espera, que funcionando en un micro a Fosc = 4 Mhz (Fcyc = 1 Mip) obtenemos exactamente 1 s de espera:
PHP:
;
; Prueba de delays con bucles anidados
;

    processor   16F877A                     ; 4 Mhz
    radix       dec
    errorlevel  -302                        ; Turn off banking message


;*******************************************************************************
; Bibliotecas

    include p16f877a.inc

    __CONFIG   _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC	; Configuración

    ORG     0x0000


	cblock 0x70
        C01
        C02
        C03
	endc


Delay:
                        ; 6 ciclos
        movlw	172
        movwf	C01
        movlw	19
        movwf	C02
        movlw	6
        movwf	C03

bucle:
                        ; 999 989 ciclos
        decfsz  C01,F
        goto    bucle

        decfsz  C02,F
        goto    bucle

        decfsz  C03,F
        goto    bucle

        nop             ; 1 ciclo
;       goto    $+1     ; 2 ciclos

                        ; 4 ciclos, 2 del return y 2 ciclos del call
        return

        END
Con más detalle:

6 ciclos que se consumen en la carga de los registros,
999 989 ciclos que se consumen en los tres bucles anidados,
4 ciclos extra que tenemos por la ejecución del return y del call,
1 ciclo extra que necesitamos con la ayuda de un nop.

Todo eso suma un millón de ciclos.

La fórmula general del cálculo de ciclos O para un determinado nivel n de profundidad es:

O(n) = O(n-1|par.1) + (par.n -1) * O(n-1|256) + (par.n -1) * 3 + 2

ciclos consumidos en este nivel =

ciclos consumidos por el nivel anterior, inicializado con el parámetro +

(parámetro de este nivel - 1) * ciclos consumidos por el nivel anterior, inicializado a 256 +

(parámetro de este nivel - 1) * 3 ciclos consumidos por decf y goto +

2 ciclos consumidos por decf y salto

Tendríamos: (he agrupado en colores los decrementos)
A ( por ejemplo siendo A-> 3(CO1-1)*TIEMPOCICLO+2*TIEMPOCICLO )
B
C

y según él quedaría así:

5*TIEMPOCICLO+(A*B*C)*TIEMPOCICLO * 2*TIEMPOCICLO

¿Tu crees que así está bien?
Pues... no sé de dónde sale esa fórmula. No conozco el desarrollo.

A mi me sale otro resultado. Ejecutando este segundo código en el MPLAB X IDE, con los parámetros 0, 218 y 7, me sale que generan 1 175 063 ciclos (sin contar otros 4 del return+call).

En este caso, hay que tener en cuenta que hay que sumar 4 ciclos de la recarga de los registros C02 y C01, multiplicados por C03.

En la hoja dejo el desarrollo. Con los parámetros

C0 = 112
C1 = 217
C2 = 6

más un nop y 5 goto $+1 extras, ya me sale un millón de ciclos, coincidente con lo que sale en MPLAB X IDE:
PHP:
;
; Prueba de delays con bucles anidados con recarga
;

    processor   16F877A                     ; 4 Mhz
    radix       dec
    errorlevel  -302                        ; Turn off banking message


;*******************************************************************************
; Bibliotecas

    include p16f877a.inc

    __CONFIG   _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC	; Configuración

    ORG     0x0000


	cblock 0x70
        C01
        C02
        C03
	endc


Delay:
                        ; 2 ciclos
        movlw	6
        movwf	C03
                        ; 999 983 ciclos
Delay_recarga:
        movlw	217
        movwf	C02
        movlw	112
        movwf	C01

Delay_bucle:
        decfsz  C01,f
        goto    Delay_bucle

        decfsz  C02,f
        goto    Delay_bucle

        decfsz  C03,f
        goto    Delay_recarga

        nop             ; 1 ciclo
        goto    $+1     ; 2 ciclos
        goto    $+1     ; 2 ciclos
        goto    $+1     ; 2 ciclos
        goto    $+1     ; 2 ciclos
        goto    $+1     ; 2 ciclos

                        ; 4 ciclos, 2 del return y 2 ciclos del call
        return

        END
 

Adjuntos

  • delay_goto_anidado.ods.zip
    45.2 KB · Visitas: 0
Atrás
Arriba