Y seguí con los mates nomás, hasta que quedes verde.
Mis explicaciones son muchas veces muy extensas, porque me gusta ir pasito a pasito, "baby steps"
Espectacular, sorprendente, magistral, garcias BRUNO, entendi a la perfeccion esto de las MACROS, sus pro y sus contras...llevo poco tiempo en este FORO, y me sorprende gratamente, la molestia que te has tomado en escribirme, y explicar esto de las MACROS...(no digo explicarme, porque esta exposicion, tan detallada, sera patrimonio del FORO de ahora en mas).
En definitiva, el programa de donde saque esto...llama a esa MACRO, con:
DELAY 21 (a cual le da bolilla ??? - a las otras, ya entendi que las pasa de largo)
DELAY 28 (lo mismo !!!)
DELAY 48 (este es el mas raro)
DELAY 5 (esta parece la mas facil) creo que esta llamada ejecutara
if (Time==5)
goto $+1
goto $+1
nop
exitm
endif
Lo que no me "avivo", es como se resuelven las otras cuentas para que den 8 - 11 - 21 - 28 - 45 - 48 y estas llamadas, sí, estan hechas en el programa... ( quiero decir, no las puse yo, como ejemplos al azar...)
OK. Me fui tanto por las ramas que ovidé explicar lo que sucede con DELAY 21...jeje
La MACRO que expones tal vez no es la más simple para comprender. Posee varias "cositas" bien calculadas que dificultan su compresiòn si no tenes bien claro el tema de los IF.
Fijate que la MACRO arranca primero comparando Time con 1, luego con 2, 3,4,5,6 y 7. Luego recién viene el otro conjunto de IFs que resolverán cualquier número entre 8 y 0(si. Digo 0 y no 255 porque en este caso poniendo 0 SUPONGO que obtenés el mayor tiempo de retardo posible: es decir, 256us @4Mhz).
¿Es esto casualidad? ¿Se podría invertir el orden de las comparaciones(IFs) y obtener el mísmo código asm de salida para cada valor de "Time"?
La respuesta es NO.
¿Por qué no?
Los casos cuando Time vale de 1 a 7 son fáciles. Los otros cuatro IFs son los que abarcan cualquier número. ¡Cualquiera! Inclusive del 1 al 7 también.
Como ya expliqué, el símbolo % signifíca en este lenguaje MOD. MOD es el resto de una división.
Si tengo por ejemplo: 1%4, entonces el resto de esa división es 1.
Si tengo: 2%4, entonces el resto de esa división es 2.
Si tengo: 3%4, entonces el resto de esa división es 3.
Si tengo: 4%4, entonces el resto de esa división es 0.
Si tengo: 5%4, entonces el resto de esa división es 1.
... ...
Entonces, generalizando: el resultado de hacer X%Y es siempre un valor entre 0 e (Y-1).
Como están contemplados dentro de esta MACRO los cuatro casos posibles de restos de una divisón por 4(nótese que se contemplan los casos para resto 0,1,2 y 3), esto significa que CUALQUIER valor de TIME satisfacerá uno y sólo uno de estos 4 casos de resto.
Ahora vamos con un ejemplo para ver la diferencia si invierto el orden de los IFs.
Hagamos primero el caso por ejemplo: DELAY 5
Si los dejo como los expones vos:
if (Time==1)...
if (Time==2)...
if (Time==3)...
if (Time==4)...
if (Time==5)...
if (Time==6)...
if (Time==7)...
if (Time%4==0)...
if (Time%4==1)...
if (Time%4==2)...
if (Time%4==3)...
Más allá de lo que se vaya a ejecutar dentro de la MACRO o no, podemos analizar a simple vista que el número 5 satisface dos Ifs:
Satisface tanto:
if (Time==5)...
como este:
if (Time%4==1)...
Entonces, fijate en la MACRO original y verás que al satisfacerse el if (Time==5) el MPASM agregará todo el código dentro del IF al archivo a ensamblar.
Pero aquí viene la línea crucial, y es que aparece dentro de IF, un endm (end macro). Esto hace que inmediatamente el MPASM salga de la MACRO, impidiendo que revise el resto de los otros IFs restantes.
¿Por qué? Porque el código necesario para crear un DELAY de 5US ya está dentro del if (Time==5). Si no saliera de la macro usando el endm, entonces también se cumpliría if (Time%4==1) produciendo más código y una demora errónea.
Entonces el código asm generado por la macro para DELAY 5 es:
goto $+1
goto $+1
nop
Lo que es correcto ya estas 3 líneas consumen 5 ciclos de ejecución, y a 4mhz son 5us.
Ahora, si los invierto:
if (Time%4==0)...
if (Time%4==1)...
if (Time%4==2)...
if (Time%4==3)...
if (Time==1)...
if (Time==2)...
if (Time==3)...
if (Time==4)...
if (Time==5)...
if (Time==6)...
if (Time==7)...
Se va a cumplir primero (Time%4==1)
Veámos qué hay dentro de este IF...:
movlw (Time-5)/4
call Delay_us
nop
Reemplacemos Time por 5 para obtener el verdadero código asm que ensamblará.
movlw (5-5)/4
call Delay_us
nop
Entonces, el asm resultante será:
movlw 0
call Delay_us
nop
Lo que ya sería erróne. Esas líneas @ 4mhz por más rápida que sea la subrutina Delay_us, llevaría 6 ciclos de ejecución(1 del movlw + 2 del call + 2 del return + 1 del nop)
Fijate que también hay endm en estos IFs, por lo que el MPASM enseguida sale de la MACRO sin revisar los restantes, pero ya el error está cometido(aunque no he analizado la subrutina Delay_us para precisar en cuántos us).
Entonces, el orden de los IFs, en este caso, altera el resultado.Por eso están como están.
Vayamos ahora al caso del ya famoso: DELAY 21
PRIMERO OJO!!!!
DELAY 21 NO NECESARIAMENTE ES LO MISMO QUE DELAY .21!!!!
Por defecto el MPLAB trabaja en formato hexadecimal, por lo que si pones: DELAY 21, en realidad está haciendo DELAY .33 en sistema decimal!!!
Lo mísmo se aplica al resto de los casos. Yo voy a suponer que estamos hablando en sistema decimal. ¿Ok?
Ahora, ¿qué condición se cumple?
Se cumple sólo ésta:
if (Time%4==1)...
Ya que 21/4= 5 y resto 1. Y el resto es lo único que le interesa a la función MOD(%).
Entonces...vemos que en este caso el MPASM generaría esto:
movlw (.21-5)/4
call Delay_us
nop
Lo que finalmente sería:
movlw 4
call Delay_us
nop
Oh casualidad! analicemos un poco. Necesito hacer 25us de retardo.
Veámos si mis premoniciones son verdaderas o falsas:
Tengo un movlw que ya me consume 1 ciclo, y tengo un call y un return que ya me consumen 4 ciclos más y luego un NOP que me consume 1 ciclo más.
En total sin contar lo que suceda o no dentro de la subrutina Delay_us, ya tengo seguro 6 ciclos(ya lo había mencionado arriba
).
Entonces el lo que sea que suceda entre que llamo al Delay_us y antes de que salga de él me debe llevar 15 ciclos de ejecución.
Veámos si entonces se cumple mi "premonición":
Delay_us ADDLW -1 ;precise delays used in I/O (esto esta buenisimo de sumar -1)
btfss STATUS,Z
goto Delay_us
return
Dijiste: "esto esta buenisimo de sumar -1".
Esto exíste para simplificarte la vida. Lo que no quiere decir que efectivamente sume -1 ya que los negativos no existen "naturalmente" en estos microcontroladores.
Pero puedo decir que: ADDLW -1 es lo mísmo que decir ADDLW .255, es decir, 256- 1
Esto debe ser precisamente lo que hace el MPASM. Es mucho más fácil cometer errores restando que sumando.
Veamos la subrutina:
W ingresa valiendo 4(véase anteriormente movlw 4)
Entonces voy a "estirar" todo el ciclo que genera esto:
Delay_us ADDLW .3 ;precise delays used in I/O (esto esta buenisimo de sumar -1)
btfss STATUS,Z
goto Delay_us
Delay_us ADDLW .2 ;precise delays used in I/O (esto esta buenisimo de sumar -1)
btfss STATUS,Z
goto Delay_us
Delay_us ADDLW .1 ;precise delays used in I/O (esto esta buenisimo de sumar -1)
btfss STATUS,Z
goto Delay_us
Delay_us ADDLW .0 ;precise delays used in I/O (esto esta buenisimo de sumar -1)
btfss STATUS,Z
;salta al return y sale.
Ahora sumo la cantidad de ciclos que lleva cada una(por dios! que de 15!
)
Delay_us ADDLW .3 ;+1
btfss STATUS,Z ;+1
goto Delay_us ;+2
Delay_us ADDLW .2 ;+1
btfss STATUS,Z ;+1
goto Delay_us ;+2
Delay_us ADDLW .1 ;+1
btfss STATUS,Z ;+1
goto Delay_us ;+2
Delay_us ADDLW .0 ;+1
btfss STATUS,Z ;+2
;salta al return y sale.
Sumamos y da: 15!!!!!
Entonces en total tenemos: 6 ciclos + 15 = 21! Uau! lo hemos logrado! y con tan poquito código! qué bonito!
Si miras sucederá de manera similar lo mísmo para los otros casos DELAY 8, DELAY 11, DELAY28, DELAY 45, DELAY 48.
¿Puedo expresar cuántos ciclos lleva la subrutina Delay_us en función de el valor con el que ingresa W?
Si.
Su función es:
Cantidad de ciclos de Delay_us = (W - 1) x 4 + 3
¿Bien?
Ahora, podría dedicarme a complicarte un poco el asunto, y unirte los cuatro caso de MOD en uno sólo que valga para todos haciendo:
DELAY macro Time
if (Time==1)...
if (Time==2)...
if (Time==3)...
if (Time==4)...
if (Time==5)...
if (Time==6)...
if (Time==7)...
movlw (Time-4-Time%4)/4
call Delay_us
if ((Time%4)%2==1)
nop
endif
endm
Ese caso vale para generar el mísmo código que generan los 4 en la MACRO original. No es necesario que lo estudies, simplemente son manías mías
Pero si decidís usarlo en reemplazo de los otros 4 casos, deberías obtener el mísmo código final.(Ensamblá el .asm con em MPLAB y andá a menú View --> Dissasembly Listing para ver qué código generó).
Espero que haya quedado claro.
Ademas, se puede llamar a esta MACRO con otros valores, o solo se llama con los valores que puede atender ??? (segun lo que interprete en tu post, la respuesta es NO, pero confirmame, plz...)
Se puede llamar con absolutamente cualquier valor natural entre 0 y 255.
En algun lado lei que estan disponibles, como el IF en las MACROS...los operandos, como los de tu ejemplo >, <, =, &, /...estare estudiando algo de eso y si me surgen dudas (casi con seguridad que asi pasara...) te estare consultando...tambien lei sobre THEN, ELSE, pero no estoy 100% seguro que tenga relacion con el ASM...
En el MPLAB ,anda a HELP -> Topics -> MPASM Assembler y buscá que ahí tenés explicado todo el potencial del MPASM que muchas veces es ignorado por completo por la gente que lo usa.
Hasta ahora en el RANKING del ALMACEN del ASM, mis posiciones son:
1º - DIOS
2º - BRUNO
3º - TODO LO DEMAS (sin ofender a nadie) tambien lei algo de CHARLY, que te pelea el puesto cuerpo a cuerpo !!! lol
Como el "barba", no me contesta (anda con otros "kilombetes"), para mi sos el GURU del ALMACEN...Bueno BRUNO, me voy a sacar la segunda "pava" de la hornalla...Ahi tengo una ROSAMONTE DESPALADA, a estrenar...ahi te paso un amargo !!!
Jajaja no creo que haya rankings aquí. Todos aportamos lo que podemos en las áreas que más sabemos, y entre todos logramos formar este gigante, este coloso que es Todopic.
Al mate te lo acepto, pero dulce
Apéndice:
¿Qué pasa si pongo DELAY 0?
¿No generará demora alguna? ¿Generará 256 us¿ ¿O generará otra demora?
Analicemos:
Veremos que el único IF que se cumple para Time = 0 es:
if (Time%4==0)
movlw (Time-4)/4
call Delay_us
exitm
endif
Entonces nos quedaría:
movlw (0-4)/4
call Delay_us
exitm
Y oh! que pasa si hacemos 0-4?
Se produce un numero negativo -3. Pero los negativos no existen aqui!
Entonces...El MPASM transformarà el -3 en: 256 - 3.
Quedandonos: .253
Volvamos entonces a la macro:
movlw (.253)/4
call Delay_us
exitm
Esa división no da como resultado un número entero. El MPASM elimina la parte decimal, de esta manera queda:
movlw .63
call Delay_us
exitm
Ahora apliquemos la formulita que habia creado anteriormente:
Cantidad de ciclos de Delay_us = (W - 1) x 4 + 3 = (.63 - 1) x 4 + 3 = .251
Ahora, sumemosle 1 del movlw, 2 del call, y 2 mas del return:
= .251+ .5 = .256 us.
Ahora si puedo afirmar que el DELAY 0 es el mayor retardo posible y su duración es 256 us.
Tal vez decir DELAY 0 para implicar 256 us parece dificil de asociar.
Pues podrìas hacer DELAY .256 en su lugar y obtendrías exactamente el mísmo retardo(y de regalo te sale una advertencia del MPASM diciendo que se usarán sólo los bits menos significativos del .256
)
Ahora si. Fin.
Exitos.