El concepto detrs del ensamblador es hacer accesible los recursos de hardware del procesador. Estos recursos son todos los componentes del hardware, como la unidad central de proceso (CPU) y su seridor de matemticas, la unidad aritm!tico"l#$ica (A%U), las unidades de almacenamiento diersas (RA& interna y e'terna, el almacenamiento EEPR(&), los puertos y las caracter)sticas de los bits de control del puertos, los tempori*adores, los conertidores A+ y otros dispositios. El acceso al hardware es directo y no mediante driers u otras inter,aces -ue proporcionan los sistemas operatios. Es el control directo de la inter,a* serial o el conersor A+, no hay una capa entre usted y el hardware. Como premios a sus es,uer*os, el e-uipo completo est a sus #rdenes, no s#lo la parte -ue el dise.ador del compilador y el pro$ramador del sistema o,recen para usted. /C#mo traba0a la CPU1 %o ms importante para la comprensi#n del ensamblador es entender como ,unciona la CPU. %a CPU lee las instrucciones de la memoria de pro$rama (,lash), las traduce y las e0ecuta en arios pasos. En los AVR, las instrucciones estn escritas como n2meros de 34 bits en la memoria ,lash y se leen de all) (primer paso). El n2mero le)do a continuaci#n se traduce (56 paso) como por e0emplo llear el contenido de los re$istros R7 y R3 a la A%U (tercer paso), sumarlos (86 paso) y escribir el resultado en el re$istro R7 (96 paso). %os re$istros son simples almacenes de : bits de ancho de los -ue se puede leer o escribir y llear directamente a la A%U. Al$unos e0emplos de codi,icaci#n de las instrucciones; (peraci#n de laCPU C#di$o binario Cod. <e'. Eniar a la CPU a dormir 3773.7373.3777.3777 =9:: >umar el re$istro R3 al re$istro R7 7777.3377.7777.7773 7C73 Restar el re$istro R3 del re$istro R7 7773.3777.7777.7773 3:73 Escribir la constante 3?7 al re$istro R34 3337.3737.7777.3737 EA7A &ultipli-ue el re$istro R@ con el re$istro R5 y escribir el resultado a los re$istros R3 (&>A) y R7 (%>A) 3773.3377.7733.7737 =C@5 Por lo tanto, si la CPU lee en he'adecimal =9:: de la memoria ,lash, detiene su ,uncionamiento y no trae ms instrucciones. Bo preocuparse, hay otro mecanismo necesario antes de -ue la CPU e0ecute esto, y adems, se puede despertar a la CPU. E0ecutando las instrucciones >i la CPU lee 7C73 he'adecimal, se suma el re$istro R3 al re$istro R7 y el resultado se escribe en el re$istro R7. Esto se e0ecuta como se muestra en la ima$en. 3 En primer lu$ar la instrucci#n (palabra de 34 bits) se lee de la memoria ,lash y es traducida al e0ecutable. E. si$uiente paso conecta los re$istros a las entradas de la A%U y suma su contenido. A continuaci#n, el resultado se escribe en el re$istro. >i la CPU lee =C5@ he'adecimal del ,lash, los re$istros R@ y R5 son muliplicados y el resultado se escribe en R3 (los : bits ms altos) y R7 (los : bits ms ba0os). >i la A%U no soporta la multiplicaci#n, no est e-uipada con el hardware para la multiplicaci#n (por e0emplo en un Attiny3@), la instrucci#n =C5@ no hace nada en absoluto, ni si-uiera abrir una entana de error. En principio, la CPU puede e0ecutar 49.9@4 (34 bits) instrucciones di,erentes. Bo obstante, debido a -ue 3?7 deben escribirse en un re$istro espec),ico, y adems los alores son de entre 7 y 599 en cual-uier re$istro de entre R34 y R@3, la cantidad de instrucciones da 594C34D8.7=4 de los 49.9@4 te#ricamente posibles. %a instrucci#n de car$a directa de una constante c (c?...c7) y los re$istros r (r@...r7, r8 son siempre 3 y no codi,icados), es codi,icado como esto; Ait 39 38 3@ 35 33 37 = : ? 4 9 8 @ 5 3 7 %+E R,C 3 3 3 7 c? c4 c9 c8 r@ r5 r3 r7 c@ c5 c3 c7 Por -u! esos bits se colocan as) en la palabra de instrucci#n si$ue siendo secreto de AF&E%. %a suma y resta re-uieren @5 C @5 D 3.758 combinaciones y los re$istros ob0etio (tar$et) R7...R@3 (t8...t7) y los re$istros ,uente (source) R7...R@3 (s8...s7) son codi,icados as); Ait 39 38 3@ 35 33 37 = : ? 4 9 8 @ 5 3 7 A++ Rt,Rs 7 7 7 7 3 3 s8 t8 t@ t5 t3 t7 s@ s5 s3 s7 >UA Rt,Rs 7 7 7 3 3 7 s8 t8 t@ t@ t3 t7 s@ s5 s3 so Por ,aor, no aprendan estas colocaciones de bits, no lo necesitar ms adelante. >#lo hau -ue entender c#mo se codi,ica y se e0ecuta una palabra de instrucci#n. Enstrucciones en ensamblador Bo hay necesidad de aprender la colocaci#n de bits en los n2meros de 34 bits por-ue en ensamblador utili*ar abreiaturas llamadas mnemot!cnicos para ayudar a la memoria. %a representaci#n he'adecimal =9:: en ensamblador es la abreiatura G>%EEPH, -ue es ms ,cil de recordar. >umar simplemente es GA++H. %os dos re$istros -ue se suman estn representados como parmetros. >implemente escriba GA++ R7,R3H, -ue se traduce a la palabra de 34 bits 7C73. %a traducci#n es reali*ada por el ensamblador. %a CPU s#lo entiende 7C73. El ensamblador traduce la l)nea a la palabra de 34 bits, -ue se escribe en la memoria ,lash. %a CPU la lee de la memoria ,lash y la e0ecuta. Cada instrucci#n de la CPU tiene su correspondiente mnemot!cnico y iceersa. %a capacidad de la CPU determina el alcance de las instrucciones -ue estn disponibles en ensamblador. El len$ua0e de la CPU es la base, la mnemotecnia s#lo representa la capacidad de la propia CPU. +i,erencias con los len$ua0es de alto niel En los len$ua0es de alto niel las construcciones no son dependientes del hardware o la capacidad de una CPU. Esas construcciones traba0an con procesadores di,erentes si hay un compilador del len$ua0e para las diersas ,amilias de procesadores. El compilador traduce las construcciones del len$ua0e al 5 len$ua0e binario del procesador. Un I(F( en Aasic se parece a un J&P en ensamblador, pero hay una di,erencia de concepto entre los dos. Una trans,erencia de c#di$o de un procesador a otro, s#lo ,unciona si el hardware es capa* de hacer lo mismo. >i un procesador de una CPU no tiene acceso a un tempori*ador de 34 bits, el compilador de un len$ua0e de alto niel tiene -ue simularlo utili*ando un tempori*ador de : bits y un c#di$o de consumo"tiempo. >i hay disponibles tres tempori*adores y el compilador est escrito para s#lo dos o uno, el hardware disponible no se utili*a, por lo -ue se depende totalmente de la capacidad del compilador, no de las capacidades de la CPU. (tro e0emplo se muestra con la instrucci#n G&U%H. En ensamblador, el procesador de destino determina si se puede utili*ar esta instrucci#n o se tiene -ue escribir una rutina de multiplicaci#n. >i en un len$ua0e de alto niel se utili*a una multiplicaci#n, el compilador inserta una biblioteca matemtica -ue multiplica todo tipo de n2meros, incluso si s#lo tiene n2meros de : bits y s#lo con utili*ar &U% le bastase. %a librer)a le o,rece un n2mero entero pe-ue.o, una palabra lar$a y otras rutinas de multiplicaci#n -ue no son necesarias. Un pa-uete completo de cosas -ue realmente no necesita, as) -ue te -uedas pronto sin memoria ,lash en un AVR muy pe-ue.o y tienes -ue cambiar a un 'me$a de @9 pines con puertos no utili*ados s#lo por tener su $ran librer)a con rutinas super,luas ocupando espacio en la memoria ,lash. Eso es lo -ue se obtiene a partir de un simple G C H sin ni si-uiera pedirlo. Ensamblador no es len$ua0e m-uina +ebido a -ue el ensamblador se acerca ms al hardware -ue cual-uier otro len$ua0e, a eces se le llama len$ua0e m-uina. Esto no es correcto por-ue la CPU s#lo entiende instrucciones de 34 bits en ,ormato binario. %a cadena GA++ R7,R3H no se puede e0ecutar, y el ensamblador es mucho ms simple -ue el len$ua0e m-uina. %as similitudes entre el len$ua0e m-uina y ensamblador son una caracter)stica, no un error. Ent!rprete y ensamblador Un int!rprete traduce c#di$o cercano al len$ua0e humano a c#di$o binario para la CPU. El int!rprete tiene estas caracter)sticas; Primero lee la secuencia de te'to GA D A K AH (nuee caracteres de un byte cada uno), tira los cuatro espacios en blanco del te'to, locali*a las ariables A y A (ubicaci#n en los re$istros o >RA&, la precisi#n, lon$itud, etc), identi,ica el si$no K como operador, prepara una secuencia de m-uina e0ecutable -ue es e-uialente a la ,ormulaci#n del te'to. En consecuencia, el c#di$o m-uina resultante ser)a arias palabras lar$as, leer y escribir ariables de y a >RA&, sumar enteros de 34 bits, $uardar y restaurar re$istro de la pila, etc... %a di,erencia entre el int!rprete y el ensamblador es -ue despu!s de ensamblar la CPU obtiene sus palabras e0ecutables directamente. En la interpretaci#n, la CPU pasa la mayor parte del tiempo reali*ando la tarea de traducci#n. %a traducci#n puede re-uerir de 57 # 577 pasos de CPU, antes de -ue se puedan e0ecutar @ # 8 palabras. %a elocidad de e0ecuci#n es muy lenta. Esto no es problema si hay una elocidad de relo0 muy rpida, pero no es apropiado en situaciones de tiempo cr)ticas, donde se re-uiere una rpida respuesta a un eento. Badie sabe en -ue est ocupada e'actamente la CPU y cuanto tiempo re-uiere. Bo tener -ue pensar en problemas de tiempo conduce a la incapacidad del pro$ramador para resoler problemas de tiempo y esta i$norancia le mantiene incapa* de resoler estas cosas si es necesario. @ %en$ua0es de alto niel y ensamblador %os len$ua0es de alto niel a.aden ciertas capas de separaci#n no transparente entre la CPU y el c#di$o ,uente. Un e0emplo de concepto poco transparente son las ariables. %as ariables pueden almacenar un n2mero, una cadena de te'to o un simple alor booleano. En el c#di$o ,uente, un nombre de ariable representa un lu$ar donde se encuentra dicha ariable y hay -ue declararla; el tipo, si es un n2mero y su ,ormato, una cadena y su lon$itud, etc. Para aprender ensamblador solo hay -ue olidar el concepto de ariable de los len$ua0es de alto niel. Ensamblador s#lo sabe de bits, re$istros, bytes y bytes de >RA&. %a e'presi#n ariable no tiene nin$2n si$ni,icado en ensamblador. Adems, los t!rminos relacionados como GtipoH son in2tiles y no tienen tampoco nin$2n sentido a-u). %os len$ua0es de alto niel re-uieren la declaraci#n de ariables antes de su primer uso en el c#di$o ,uente, c#mo por e0emplo, si es un byte (: bits), palabra doble (34 bits), entero (39 bits ms uno de si$no), etc. %os compiladores de estos len$ua0es tienen -ue ubicar las ariables declaradas en al$2n lu$ar del espacio de almacenamiento disponible, incluyendo los @5 re$istros. >i esta posici#n se selec" ciona a cie$as por el compilador o si se utili*a al$una re$la de prioridad, como lo hace el pro$ramador en ensamblador cuidadosamente, depende -ui*s del precio del compilador. El pro$ramador s#lo puede tratar de entender -ue criterio utili*# el compilador cuando puso la ariable. El poder de decisi#n se le ha dado al compilador -ue GliberaH al pro$ramador de los problemas de decisi#n, pero lo conierte en un GesclaoH del compilador. En la instrucci#n GA D A K AH si A se de,ine como un carcter y A como un n2mero (por e0emplo 5), la ,ormulaci#n no es aceptada por-ue los caracteres no se pueden sumar con n2meros. %os pro$ramadores de alto niel creen -ue la eri,icaci#n de tipos les preiene de una pro$ramaci#n sin sentido. %a protecci#n -ue el compilador proporciona en este caso mediante el error de tipo, es ms bien in2til; la adici#n de 5 a la letra GLH, por supuesto, debe dar G<H como resultado. El ensamblador le permite hacer esto, pero no un compilador. El ensamblador le permite sumar y restar n2meros como ? o 8: a cada byte almacenado, no importa -ue tipo de cosas haya en el almacenamiento de bytes. Esto es decisi#n del pro$ramador, no de un compilador. >i cuatro re$istros representan un alor de @5 bits o cuatro caracteres A>CEE, si esos cuatro bytes se colocan del ms ba0o al alto o iceersa o me*clados por completo, es s#lo cuesti#n del pro$ramador. Ml es el maestro de la colocaci#n, nadie ms. %os tipos son desconocidos, todo se com" pone de bits y bytes en el almacenamiento disponible. El pro$ramador no solo tiene la tarea de or$a" ni*ar sino tambi!n la tarea de optimi*ar. E$ual pasa con otras re$las. (l)dese de la mayor)a de las re$las en ensamblador. Para pro$ramar ensamblador es preciso contar con al$unas re$las tambi!n, pero di,erentes; %a mayor)a son creadas por el pro$ramador para ayudarse a s) mismo. As) -ue usted puede pro$ramar como -uiera, no lo -ue el compilador decida por usted o lo -ue los pro,esores te#ricos creen -ue ser)a buenas re$las de pro$ramaci#n. %os pro$ramadores de alto niel son adictos a una serie de conceptos -ue se interponen en el camino de aprendi*a0e del ensamblador; separaci#n en di,erentes nieles de acceso en el hardware, controladores y otros inter,aces. En ensamblador esta separaci#n es una tonter)a. %a separaci#n les condiciona a numerosas soluciones si -uieren hacerlo de una manera #ptima. Encluso los pro$ramadores puristas de alto niel rompen estas re$las. En ensamblador nada le impide ser creatio, tiene acceso total al hardware, a la memoria, cual-uier cosa se puede cambiar. %a responsabilidad es 2nicamente del pro$ramador -ue tiene -ue usar su cerebro para eitar con,lictos de acceso al hardware. %a otra cara de la ,alta de mecanismos de protecci#n es la libertad de hacer lo -ue -uiera y como -uiera, ir desarrollando sus propias re$las para eitar errores de e0ecuci#n. /Nue es lo -ue es realmente ms ,cil en ensamblador1 Fodas las palabras y los conceptos -ue el pro$ramador de ensamblador necesita estn en la ho0a de datos del procesador; las instrucciones y la tabla de puertos. OPa estQ Con esto ya se puede construir 8 al$o. Bo son necesarios otros documentos. /Como se inicia el tempori*ador1 (est escrito en GFimer.>tart)G%+E R34,7'75H y G(UF FCCR7,R34H. /C#mo se reinicia a cero1 RC%R R34H y G(UF FCCR7,R34R, todo est en la ho0a de datos. Bo hay necesidad de consultar una documentaci#n ms o menos buena de c#mo el compilador de,ine esto o a-uello. Bo hay palabras especiales dise.ados por el compilador y los conceptos -ue hay -ue aprender estn todos en la ho0a de datos. >i desea utili*ar un contador de tiempo en el procesador para un ,in determinado puede utili*ar cual-uier modo de los 39 posibles modos di,erentes, no hay nin$una re$la en la ,orma de acceder al contador de tiempo, para detenerlo o reiniciarlo, etc. /Nue en un len$ua0e de alto niel es ms ,cil escribir GA D A K AH -ue R&U% R34,R3?R1 Bo mucho. >i A y A no se de,inen como bytes o si el procesador es muy pe-ue.o y no entiende &U%, el simple &U% tiene -ue ser intercambiado con otro c#di$o ,uente tal como ,ue dise.ado por el pro$ramador de ensamblador o copiar y pe$ar y adaptarlo a sus necesidades. Bo hay nin$una ra*#n para importar una librer)a opaca, simplemente descarte la pere*a en su cerebro y comience a aprender. El ensamblador le ense.a directamente como ,unciona el procesador. +ebido a -ue un compilador no se hace car$o de las tareas, usted es completamente el capitn del procesador. %a recompensa por esto es -ue se le concede acceso a todo. >i lo desea puede pro$ramar una elocidad en baudios de 89,89 bps en el UARF, un a0uste de elocidad -ue no le permite un pc con windows por-ue el sistema opera" tio s#lo permite m2ltiplos de ?9 (/por-ue1 +ebido a -ue hist#ricamente los escritores de teletipos mecanicos ten)an las ca0as de en$rana0es dise.adas para hacer una selecci#n rpida de ?9 o @77 bps). >i adems, desea un re$istro de 3 byte y medio en lu$ar de uno de 3 o de 5, /por-ue no pro$ramar su propio dispositio con ensamblador1 Nuien es capa* de pro$ramar en ensamblador tiene una idea de todo lo -ue el procesador le permite. El procesador entero est a la orden del pro$ramador. +e esta manera puede adoptar soluciones de alta sensibilidad de ,orma ,ina y est!tica. <ardware para la pro$ramaci#n en ensamblador AVR %a inter,a* E>P (pro$ramaci#n en sistema) le permite leer y escribir el pro$rama en la memoria ,lash y en la EEPR(& inte$rada. Esta inter,a* traba0a en serie y solo necesita tres lineas de se.al; >CS; Una se.al de relo0 para despla*ar los bits -ue se escriben en la memoria en un re$istro de despla*amiento interno y para despla*ar los bits -ue se an a leer de otro re$istro de despla*a" miento. &(>E; %a se.al de datos -ue en)a los bits -ue se escriben en el AVR. &E>(; %a se.al de datos -ue recibe los bits le)dos desde al AVR. Estos tres pines se conectan internamente a la m-uina de pro$ramaci#n s#lo si cambia el pin de RE>EF (a eces tambi!n llamado R>F o restart) a cero. +e lo contrario, durante el ,uncionamiento normal del AVR, estos pines son pro$ramables como lineas de entradaTsalida como todos los dems. >i desea utili*ar estos pines para otros ,ines durante el ,uncionamiento normal y en el sistema de pro$ramaci#n, tendr -ue tener cuidado de -ue estos dos ob0etios no entren en con,licto. En $eneral, habr -ue disociarlos por medio de resistencias o un multiple'or. Bo es necesario pero si recomendable en el modo E>P (in"system" pro$rammin$), -ue el hardware de pro$ramaci#n suministre la tensi#n de alimentaci#n. Esto re-uiere dos lineas adicionales entre el pro$ramador y el AVR; IB+, Fierra com2n o polo ne$atio y VFI (tar$et olta$e), tensi#n de alimentaci#n (por lo $eneral K9.7 oltios). Esto suma 4 lineas entre el hardware 9 pro$ramador y el AVR, y se llama cone'i#n E>P4 se$2n la de,inici#n de Atmel. %os standards siempre tienen standards alternatios -ue se utili*aron anteriormente. Esta la base t!cnica -ue constituye la industria del adaptador. En este caso, el standard alternatio se dise.# como E>P37 y ha sido utili*ado en la placa >FS577, tambi!n llamada inter,a* CAB+A. Foda)a es un stan" dard muy e'tendido e incluso la placa >FS977 ms reciente est e-uipado con !l. El E>P37 tiene una se.al adicional para un led ro0o, -ue indicar)a -ue el pro$ramador estar)a haciendo su traba0o. Es una buena idea, solo tiene -ue conectar el led con una resistencia y la tensi#n de alimentaci#n positia.
<erramientas para pro$ramar en ensamblador AVR El editor, el pro$rama ensamblador, la inter,a* de pro$ramaci#n de chips y el simulador. <ay dos posibles )as; 1. Fodo en un pa-uete y 2. Cada tarea se reali*a con un pro$rama espec),ico y los resultados se an almacenando en archios espec),icos. Ieneralmente se eli0e la primera )a, pero para comprender el mecanismo subyacente, amos a describir la 5U )a, -ue muestra la ,orma de un archio de te'to con palabras de instrucci#n en la memoria ,lash. Estructuraci#n del c#di$o ensamblador %a estructura bsica de un pro$rama en ensamblador AVR consta de ; comentarios, in,ormaci#n de encabe*ado, c#di$o al inicio del pro$rama y estructura $eneral. Comentarios El te'to ms 2til en un pro$rama de ensamblador son los comentarios. >i usted necesita entender c#di$o anti$uo -ue escribi#, a eces a.os antes, apreciar el tener al$unas su$erencias y toda)a me0or, lo -ue ocurre en cada linea de c#di$o. >i le $usta mantener sus ideas en secreto y ocultarlas contra si mismo y los dems, no use los comentarios. Un comentario empie*a con un punto y coma. Fodo lo -ue si$ue por detrs en la misma linea ser i$norado por el compilador. >i tiene -ue escribir un comentario de arias lineas, comience cada linea con un punto y coma. Cada pro$rama en ensamblador debe comen*ar as); V V ClicW.asm, Pro$rama para conmutar un rel! de abierto a cerrado cada 5 se$undos V Escrito por I. >chmidt, 2ltima modi,icaci#n; 37T7?T5773 V Pon comentarios en todas las partes del pro$rama, ya sea en una subrutina completa o una tabla. En el comentario hay -ue hablar de las caracter)sticas de la subrutina y las condiciones preias necesarias 4 para llamarla o e0ecutarla. Fambi!n se pueden mencionar los resultados de la subrutina en caso de -ue ms tarde se puedan encontrar errores o para ampliarla despu!s. %os comentarios de una sola l)nea se a.aden mediante un punto y coma en la linea despu!s del comando; %+E R34,7'7A VA-u) se car$a al$o &(V R3?,R34 Vy se copia en otro lu$ar En,ormaci#n de encabe*ado En la parte superior o encabe*ado del pro$rama debe ir el prop#sito y ,unci#n del mismo, el autor, la ersi#n y otros posibles comentarios. +espu!s deber)a ir el tipo de procesador para el cual est escrito, las constantes pertinentes y una lista con los nombres de los re$istros. El tipo de procesador es espe" cialmente importante, ya -ue los pro$ramas en ensamblador no se suelen e0ecutar en di,erentes tipos de chips sin cambios. %as instrucciones no son entendidas i$ual por todos los tipos de chips. Cada dispositio tiene di,erentes caracter)sticas y capacidades de EEPR(& y >RA&. Fodas estas carac" ter)sticas especiales se incluyen en un archio de encabe*ado -ue se denomina ''''de,.inc, donde '''' es el tipo de chip como 5@3@, tn5@5@ o m:939. Estos archios estn disponibles y los proporcio" na Atmel. Es un buen estilo de pro$ramaci#n incluir este archio al comien*o de cada pro$rama; .B(%E>F V Bo liste lo si$uiente en el archio de lista .EBC%U+E Rm:939de,.incR V Emportaci#n del archio de de,iniciones .%E>F V Cambiar a lista de nueo %a ruta de acceso, donde se puede encontrar este archio, es necesaria si usted no traba0a con el so,tware estudio de AF&E%. +urante el ensamble, por de,ecto, se $enera un ,ichero C.lst -ue lista los resultados. Este ,ichero podr)a ser muy lar$o si se incluye el ,ichero de encabe*ado. %a directia .B(%E>F omite el listado hasta -ue no se uela a actiar. Veamos breemente el archio de encabe*ado. En primer lu$ar este archio de,ine el tipo de procesador; .DEVICE ATMEGA8515 ; El tipo de dispositivo de destino La directiva .DEVCE hace que el ensamblador compruebe si estn disponibles todas las instrucciones para este tipo de AVR. El resultado es un mensaje de error si se utilizan secuencias de cdigo que no estn definidas para este tipo de procesador. El archivo de encabezado define tambin los registros XH, XL, YH, YL, ZH y ZL. Esto es necesario si usted va a utilizar los punteros de 16 bits X, Y o Z para acceder a los bytes de mayor y menor peso (higher o lower) por separado. Todas las ubicaciones de los puertos tambin se definen en el archivo de encabezado. Un nmero hexadecimal indica donde se encuentra definido un puerto en el dispositivo. Los puertos se definen con los nombres que vienen en las hojas de daros para cada procesador. Esto tambin se aplica a los bits individuales de cada puerto. El acceso de lectura al bit 3 del puerto B se hace usando el nombre PNB3 tal como se define en la ficha tcnica. En otras palabras, si usted olvida de incluir el archivo de encabezado se encontrar con un montn de men- sajes de error durante la ejecucin del ensamblaje. Los mensajes de error que se produzcan no necesa- riamente tienen que estar relacionados con que falta el archivo de encabezado. Otras cosas que deberan estar al principio de sus programas son las definiciones de registros con los que trabaja, por ejemplo: .DEF mpr = R16 ; Deine !n n!evo nom"re p#r# el re$istro R16 Esto tiene la ventaja de tener una lista completa de los registros y adems poder ver los registros que todava estn disponibles sin utilizar. Cambiar el nombre de los registros evita conflictos en su uso y adems los nombres son ms fciles de recordar. Al principio del programa y ms adelante hay que definir las constantes, especialmente las que tienen un papel relevante en diferentes partes del programa. Tales constantes, por ejemplo la frecuencia Xtal a la que debe ajustarse el programa, si utiliza en la placa la interfaz serie, se definen as: ? .E%& ' = ()))))) ; deini*i+n de re*!en*i# ,t#l As), desde el principio del c#di$o ,uente se puede er rpidamente para -ue relo0 se ha escrito el pro$rama, mucho ms ,cil -ue buscar esta in,ormaci#n perdida dentro de 38:5 l)neas de c#di$o ,uente. %o -ue se debe hacer al iniciar el pro$rama +espu!s de haber hecho la cabecera debe comen*ar el c#di$o del pro$rama. Al principio del c#di$o se debe colocar los ectores de reset "y de interrupci#n" (er su ,unci#n en la secci#n JU&P). A medida -ue se produ*can saltos relatios se deben colocar detrs las respectias subrutinas de sericio de interrupci#n. En el caso de dispositios Atme$a con mayor memoria ,lash, las instrucciones de salto se pueden colocar a-u), pero siendo cuidadoso. <ay a-u) un poco de espacio de sobra para al$unas subrutinas antes de colocar el pro$rama principal, -ue siempre comien*a con la iniciali*aci#n del puntero de pila, el establecimiento de los re$istros con los alores por de,ecto y la iniciali*aci#n de los componentes de hardware -ue se an a utili*ar. El c#di$o si$uiente es espec),ico para cada pro$rama. El Ensamblador Fenemos un archio de te'to con caracteres A>CEE. El si$uiente paso es traducir el c#di$o de tal ,orma -ue pueda ser comprendido por el chip AVR. Esto se llama ensambla0e, -ue si$ni,ica Gponer las palabras de instrucci#n de ,orma correctaH. El pro$rama -ue lee el archio de te'to y produce otro de salida se llama Ensamblador. En su ,orma ms simple es una aplicaci#n de l)nea de comandos -ue cuando se le llama recibe como ar$umentos la ruta del archio de te'to y al$unos modi,icadores opcionales para comen*ar a ensamblar las instrucciones -ue encuentra en el citado archio. >i su editor de te'to permite llamar a pro$ramas e'ternos esto es una tarea ,cil. >i no, es ms coneniente escribir un pe-ue.o archio por lotes o script (de nueo con un editor). Este archio por lotes deber)a tener una l)nea como esta; PathToAssembler\Assembler.exe -options PathToTextfile\Textfile.asm Al hacer click en el lugar del editor que llama al programa externo o en el archivo por lotes se incia el ensamblador de linea de comandos. %a entana pe-ue.a in,orma de proceso completo de traducci#n. En este caso no hay errores. >i se producen estos son noti,icados 0unto con su tipo y n2mero de l)nea. El ensamblador ha producido una palabra de c#di$o resultante de la instrucci#n RJ&P -ue se ha usado. El ensamblador de nuestro 2nico archio de te'to asm ha producido otros cuatro archios, aun-ue no todos se aplican a-u). Uno de estos cuatro nueos archios, FE>F.EEP, : contiene lo -ue se a a escribir en la EEPR(& del AVR. Esto no es muy interesante en este caso, ya -ue no se $enera nin$2n contenido para la EEPR(&, por lo -ue el ensamblador lo -ue hace es elimi" nar este archio por-ue est ac)o. El si$uiente archio, FE>F.<EX, es ms releante ya -ue contiene las instrucciones con las -ue se a a pro$ramar el chip. %os n2meros he'adecimales se escriben en ,orma A>CEE especial, 0unto con la in,ormaci#n de la direcci#n y una suma de comprobaci#n, esto para cada linea. Este ,ormato se llama intel he'adecimal, es muy anti$uo y proiene del mundo de la in,ormtica. El tercer archio, FE>F.(AJ, ser presentado ms adelante, este archio es necesario para simular un AVR. >u ,ormato es he'adecimal y de,inido por AF&E%. El contenido de un editor he'adecimal se parece a esto. Atenci#n, este ,ormato de archio no es compatible con el so,tware de pro$ramaci#n. El archio ob0 s#lo lo $eneran al$unos ensambladores de Atmel, no espere estos archios en todos los ensambladores. El cuarto archio, FE>F.%>F, es un archio de te'to. >u contenido se puede er con un simple editor. El archio muestra el pro$rama con todas sus direcciones, instrucciones y mensa0es de error en un ,ormato le$ible. Puede necesitar este archio en casos en los haya errores por motios de depura" ci#n. Estos archios de listado solo se $eneran si se incluye la opci#n corres" pondiente en la linea de comandos y si la directia .B(%E>F no lo suprime. Programacin del chip Para pro$ramar el c#di$o he'adecimal, tiene -ue disponer de !l en un archio de te'to y de un so,tware de pro$ramaci#n AVR. Este so,tware lee los archios .<EX y trans,iere su contenido ya sea bit a bit (pro$ramaci#n serie) o byte a byte (pro$ramaci#n en paralelo) a la memoria ,lash del AVR. = %a ima$en ser)a un e0emplo, pero ten$a en cuenta -ue la entana -ue aparece es del so,tware AVR E>P.e'e, un pro$rama hist#rico -ue ya no distribuye Atmel. Ahora hay otros pro$ramas similares. El so,tware $rabar nuestro c#di$o en la memoria de pro$rama del chip. El hardware de pro$ramaci#n y distintas alternatias de so,tware para di,erentes sistemas operatios estn disponibles en internet. &encionamos a-u) PonyPro$5777 como un e0emplo para la pro$ramaci#n en paralelo o por el puerto de comunicaci#n serial. >imulaci#n en el so,tware >tudio Al$unas eces, aun-ue el ensamblado no produ*ca errores, el c#di$o no reali*a e'actamente lo -ue deber)a cuando se $raba en el chip. Festear el so,tware directamente en el chip podr)a ser complicado, especialmente si usted tiene un hardware m)nimo sin oportunidad de mostrar los resultados proisio" nales o las se.ales de depuraci#n. En estos casos el pa-uete de so,tware >tudio de Atmel o,rece opor" tunidades ideales para la depuraci#n. El c#di$o del pro$rama puede ponerse a prueba paso a paso para er los resultados. %as im$enes -ue mostramos a continuaci#n han sido tomadas de la ersi#n 8 de >tudio, -ue est disponible $ratuitamente preio re$istro en el sitio web de Atmel. %a aplicaci#n >tudio tiene todo lo necesario para desarrollar, depurar, simular y $rabar sus pro$ramas de ensamblador en el tipo de AVR de su elecci#n. El primer cuadro de dilo$o le pre$unta si -uiere abrir un proyecto ya en curso o si a a empe*ar uno nueo. +espu!s de marcar nueo proyecto, el bot#n si$uiente le llea a la con,i$uraci#n de su nueo proyecto. En este cuadro de dilo$o selecciona GAtmel AVR AssemblerH como tipo de proyecto, le asi$na un nombre (en este caso test3) y despu!s una ubicaci#n para el proyecto donde se tiene acceso de escritura. El bot#n si$uiente abre el cuadro de dilo$o de selecci#n de dispositios. 37 Como plata,orma de depuraci#n seleccionar AVR simulador o AVR simulador 5. Como dispo" sitio, a-u) ,ue seleccio" nado un Atme$a:. >e cierra esta entana con el bot#n ,inali*ar y se abre una $ran entana -ue contiene un mont#n de di,erentes sub"entanas. %a entana de la i*-uierda le permite er y manipular todos los archios del proyecto. En el centro, la entana del editor le permite escribir el c#di$o ,uente (no se preocupe por los colores, el resaltado de sinta'is es a$re$ado por el editor). En la parte in,erior i*-uierda est la entana de Gconstrucci#nH donde deben aparecer los mensa0es de error. En el lado derecho una rara entana de entradaTsalida con la parte in,erior en blanco (la eremos ms adelante). Fodas las entanas se pueden redimensionar y despla*ar independientemente por la pantalla. 33 +espu!s de escribir su pro$rama completo en c#di$o ,uente, aya al men2 construir (build), pinche en el submen2 construir y el resultado se mostrar en la entana de construcci#n. Ase$2rese de leer todo el contenido de la entana una e* ya -ue le brindar mucha in,ormaci#n. >i ha echo todo correctamente aparecer un circulo erde con un mensa0e indicndoselo, de lo contrario aparecer un circulo ro0o. +espu!s puede ir a los men2s +ebu$, Ver, <erramientas y Procesador, cambiar su tama.o o posici#n, o modi,icar su contenido. +eber)a tener este aspecto; %a entana del editor tiene ahora una ,lecha amarilla. Esta ,lecha apunta a la si$uiente instrucci#n -ue se e0ecutar (realmente es una simulaci#n). %a entana de procesador muestra el alor actual del contador de pro$ra" ma (el pro$rama se inicia en la direcci#n 7), el puntero de pila, un contador de ciclos y un cron#" metro. >i pulsa en el pe-ue.o G+H a la i*-uierda de la palabra GRe$istersH se muestra el conte" nido de los @5 re$is" tros (todos estn ac)os al inicio de la simulaci#n). Ahora amos a proceder con la primera instrucci#n. En el men2 G+ebu$H y despu!s Gstep intoH o simplemente pulsando L33 se e0ecuta la primera instrucci#n. 35 %a instrucci#n Gldi rmp,7b33333333H car$a el alor binario 3333.3333 en el re$istro R34. %a ,lecha amarilla ya ha aan*ado una instrucci#n hacia aba0o, se encuentra ahora en la instrucci#n (UF. En la entana de procesa" dor, el contador de pro" $rama y el de ciclos han aan*ado uno a su e*. El re$istro 34, en la lista de re$istros, est en ro0o y muestra el alor 7'LL en he'adecimal, -ue en binario es 3333.3333. Aan*ando un paso ms se e0ecuta la instrucci#n (UF (pulsando la tecla L33 por e0emplo) y muestra la si$uiente in,ormaci#n. %a instrucci#n Gout ++RA,rmpH escribe 7'LL al puerto llamado ++RA. Ahora la acci#n se encuentra en la entana ET(. >i se pulsa en el pe-ue.o G+H a la i*-uierda de P(RFA, se muestra el alor 7'LL en el puerto ++RA de dos ,ormas di,erentes; como 7'LL en la parte superior de la entana y con : cua" draditos en ne$ro en la parte in,erior. Pulsamos 5 eces L33 y se escribe 7'99 en el P(RFA. Como era de esperar, hay cambios en el contenido del P(RFA. <ay ahora cuatro casillas en ne$ro y las otras cuatro en blanco. 3@ (tros dos L33 y se escribe 7'AA en el P(RFA y se ha inertido el color en los cuadraditos. Es lo -ue se esperaba. Pero, /-ue ha ocurrido en PEBA1 Fiene los colores opuestos a P(RFA, i$ual -ue los ten)a el P(RFA en el paso anterior. PEBA es un puerto de entrada para los pines e'ternos. Como la direcci#n de los puertos en ++RA estn ,i0ados para ser salidas, PEBA si$ue el estado de los pines en P(RFA 0usto en ciclo ms tarde. Bo hay nada mal a-u). Para comprobarlo, basta con pulsar L33 arias eces para comprobar -ue es correcto. Esta es una pe-ue.a muestra del so,tware simulador. El simulador es capa* de mucho ms, asi -ue debe ser aplicado e'tensiamente en los casos de errores de dise.o. Enesti$ue los elementos de los men2s, hay muchas cosas -ue se pueden mostrar. Por el momento, antes de se$uir 0u$ando con el simulador, hay -ue aprender al$unas cosas bsicas del len$ua0e ensamblador, as) -ue de0aremos el so,tware studio por un tiempo. /Nu! es un re$istro1 %os re$istros son dep#sitos especiales con capacidad de : bits y se en as); Ait ? Ait 4 Ait 9 Ait 8 Ait @ Ait 5 Ait 3 Ait 7 38 Fen$a en cuenta la numeraci#n de los bits, el menos si$ni,icatio es el cero (matemticamente 5 0 D 3). Un re$istro puede almacenar n2meros del 7 al 599 sin si$no, o n2meros de "35: a 35? (n2meros enteros con el bit ? de si$no). Fambi!n puede alamacenar un alor -ue representa un carcter codi,icado en A>CEE (por e0em. YAY), o tan s#lo : bits indiiduales -ue no tienen relaci#n entre s) (por e0em. : banderas indiiduales, utili*adas para se.alar : alores booleanos). %as caracter)sticas especiales de los re$istros, comparndolas con otras ,ormas de almacenamiento, son; estn conectados directamente con la unidad central de proceso, llamada acumulador. Pueden ser utili*ados directamente en las instrucciones de ensamblador, ya sea como destino de un resultado o para leer el contenido y e,ectuar un clculo o trans,erencia. %as operaciones con su contenido solo re-uieren una palabra de instrucci#n. <ay @5 re$istros en un AVR. (ri$inalmente su denominaci#n a de R7 a R@3, pero se les puede cambiar el nombre a otro ms si$ni,icatio con una directia del ensamblador. Un e0emplo; .+EL Re$istroPre,erido D R34 %as directias de ensamblador siempre empie*an con un punto, a di,erencia de las instrucciones y eti-uetas -ue BUBCA empie*an con un punto. Fen$a en cuenta -ue las directias s#lo tienen sentido para el ensamblador, no producen nin$2n c#di$o e0ecutable en el chip de destino. El nombre GRe$istroPre,eridoH no se mostrar en el c#di$o he'adecimal ensamblado, por lo -ue no podr ser deriado de !ste. En lu$ar de utili*ar el nombre de re$istro R34, ahora podremos utili*ar nuestro propio nombre GRe$istroPre,eridoH si -ueremos utili*ar R34 en una instrucci#n. Fenemos -ue escribir un poco ms de te'to cada e* -ue usemos este re$istro, pero en cambio, tenemos una asociaci#n de lo -ue podr)a ser el contenido de este re$istro. El uso en la linea de instrucci#n; LDI RegistroPreferido, 150 -ue si$ni,ica car$ar el n2mero 397 inmediatamente en el re$istro R34 (%oa+ Enmediate). %+E car$a un alor ,i0o o una constante al re$istro. Fras el ensamblado o traducci#n de este c#di$o a binario o he'adecimal, el pro$rama almacenado en el chip luce as); )))))) E-)6 Esto aparecer en el listado, el archio C.lst producido por el ensamblador -ue es un simple archio de te'to. Fodos los n2meros estan en ,ormato he'adecimal. El primero (777777) indica la direcci#n en la memoria ,lash donde se escribe y el se$undo (E=74) es el c#di$o de la instrucci#n. E=74 indica al procesador tres cosas di,erentes en una sola palabra, aun-ue no lo ea directamente; Un c#di$o bsico de instrucci#n de car$a, sin#nimo de %+E, el re$istro de destino (R34), donde se a a escribir el alor 397, y el alor de la constante (397). Bo tiene -ue recordar todo esto. El ensamblador sabe como traducirlo para dar ,inalmente E=74 y el AVR lo e0ecutar. 39 En una instrucci#n dos di,erentes re$istros pueden desempe.ar una ,unci#n. Un e0emplo ,cil de una instrucci#n de este tipo es la instrucci#n de copia, &(V. El nombre de esta instrucci#n induce a con,usi#n por-ue el contenido de un re$istro no se puede moer (/-ue -uedar)a en el re$istro si se muee el contenido a otra parte1). &e0or deber)a llamarse C(PP, ya -ue lo -ue hace es copiar el contenido de un re$istro a otro re$istro. +e esta manera; .DEF Re$istro.reerido = R16 .DEF /troRe$istro = R15 0DI Re$istro.reerido1 15) M/V /troRe$istro1 Re$istro.reerido %as dos primeras l)neas de este peda*o de pro$rama son directias -ue de,inen los nueos nombres de los re$istros R34 y R39. Como se mencion# antes, estas dos lineas no producen c#di$o para el AVR. %as l)neas con las instrucciones %+E y &(V producen el si$uiente c#di$o; )))))) E-)6 )))))1 2F)1 -ue escribe el alor 397 en el re$istro R34 y copia su contenido al re$istro de destino R39. AVE>( E&P(RFABFE; El primer registro es siempre el registro de destino donde se escribe el resultado. Esto es di,erente a como se lee o escribe y puede con,undir al principio, pero de i*-uierda a derecha o de derecha a i*-uierda, son simples conenciones. Re$istros di,erentes El principiante -ue -uiera escribir las instrucciones de arriba de esta manera; .DEF /troRe$istro = R15 0DI /troRe$istro1 15) <a perdido. >olo los re$istros R34 a R@3 car$an una constante de inmediato con la instrucci#n %+E. R7 a R39 no hacen esto. Esta restricci#n no es muy ,ina, pero no pudo eitarse durante el proceso de construcci#n del con0unto de instrucciones de los AVR. >in embar$o, hay una e'cepci#n a esta re$la; el establecimiento a cero de un re$istro. %a instrucci#n; CLR RegistroPreferido es lida para todos los re$istros. Esta restricci#n, adems de en la instrucci#n %+E, se da en las si$uientes instrucciones; AND Rx,K ; and-bit al registro Rx con un valor constante K, CBR Rx,M ; Borrar todos los bits del registro Rx y establecerlos al valor de la mscara constante M, CP Rx,K ; Compara el contenido del registro Rx con un valor constante K, SBC Rx,K ; Reste la constante K y el valor actual de la bandera de acarreo al contenido del registro Rx y almacena el resultado en este ltimo. SBR Rx,M ; Establecer a 1 todos los bits del registro Rx, que son 1 en la mscara constante M, SER Rx ; Establecer a 1, todos los bits del registro Rx (igual que LD Rx,255), SUB Rx,K ; Restar la constante K del contenido del registro Rx y almacenar el resultado en este ltimo. En todas estas instrucciones, el re$istro debe ser cual-uiera de entre R34 y R@3. >i a a utili*ar estas ins" trucciones, hay -ue seleccionar uno de estos re$istros para operar. Es ms corto y ms ,cil de pro$ra" mar. Esta es una ra*#n ms por la -ue se debe utili*ar la directia para de,inir el nombre de un re$istro. 34 Registros de puntero Una ,unci#n e'tra muy especial se de,ine para los pares de re$istros; R5?;R54, R5=;R5: y R@3;R@7. El papel es tan importante -ue estas pare0as tienen nombres cortos e'tra en ensamblador AVR; X, P y Z. Estos nombres cortos son entendidos por el ensamblador. Estos pares son re$istros de puntero de 34 bits, capa* de apuntar a las direcciones con un m'. 34 bits de lon$itud, por e0emplo en lu$ares de >RA& (X, P o Z) o en lu$ares de memoria de pro$rama (Z). Acceder a posiciones de memoria con punteros El byte ms ba0o del puntero de 34 bits se encuentra en el re$istro in,erior y el ms alto en el re$istro superior. Ambas partes tienen su propio nombre. El byte ms alto de Z se denomina Z< (DR@3) y el ms ba0o es Z% (DR@7). Estos nombres estn de,inidos en el ensamblador. +iidir una palabra de 34 bits constante en sus dos bytes y escribir estos en un re$istro de puntero se hace como si$ue; .EQU address = RAMEND ;RAMEND es la direi!" de 1# $its %&s alta de la %e%oria 'RAM, ()e ;est& defi"ida e" el orres*o"die"te ar+i,o de a$eera -def.i", LDI ./,/I0/1direi!"2 ;Cargar el M'3 1$4te %&s sig"ifiati,o2 de la 5direi!"5 LDI .L,L671direi!"2 ;Cargar el L'3 1$4te %e"os sig"ifiati,o2 de la 5direi!"5 El acceso a travs de registros de puntero se programa con instrucciones diseadas especialmente. El acceso de lectura se denomina LD (LoaD) y el acceso de escritura ST (Store). Ejemplos con el puntero X (del mismo modo se puede usar Y y Z para tal fin): Puntero Secuencia ejemplos X %ecturaTescritura de direcci#n X, no cambia el puntero LD R1,X o ST X,R1 X+ %ecturaTescritura desdeThacia direcci#n X e incremento del puntero despu!s en uno LD R1,X+ o ST X+,R1 -X Primero, disminuir el puntero en uno y lecturaTescritura desdeThacia la nuea direcci#n, despu!s LD R1,-X o ST -X,R1 %ectura de la memoria de pro$rama ,lash con el puntero Z >#lo hay una instrucci#n para el acceso de lectura en el espacio de almacena0e del pro$rama. >e de,ine para el puntero Z y -ue se denomina %P& (car$a de memoria de pro$rama). %a instrucci#n copia el byte de la direcci#n del pro$rama Llash a Z y al re$istro R7. Como la memoria de pro$rama est or$ani*ada por palabras (una instrucci#n en una direcci#n se compone de 34 bits o 5 bytes o 3 palabra), el bit menos si$ni,icatio selecciona el byte in,erior o superior (7 D byte ba0o, 3 D byte alto). +ebido a esto la direcci#n ori$inal se debe multiplicar por 5 y el acceso est limitado a 39 bits o @5 WA de memoria de pro$rama. +e esta manera; 0DI 3414IG4526#ddress7 0DI 3010/8526#ddress7 0.M +espu!s de esta instrucci#n, la direcci#n debe ser incrementada para apuntar al si$uiente byte en la memoria de pro$rama. Como se utili*a muy a menudo, se ha de,inido una instrucci#n especial de incremento de puntero; ADI8 3011 0.M 3? ADI8 5Add Immedi#te 8ord7. De esta manera se pueden sumar hasta un mximo de 63. Hay que tener en cuenta que le ensamblador espera la parte baja, ZL, del registro de puntero como primer parmetro. Esto es algo confuso ya que la adicin se hace como una operacin de 16 bits. La ins- truccin complementaria, que resta un valor constante entre 0 y 63 al registro de puntero de 16 bits, se llama 9:I8 59!:tr#*t Immedi#te 8ord7. ADW y SBW son vlidas para los pares de registros de punteros X, Y y Z y para los pares de registros R25:R24 en tanto que no tienen un nombre extra y no se permite el acceso a posiciones de memoria de programa o SRAM. El par R25:R24 es ideal para manejar valores de 16 bits. Como el incremento despu!s de la lectura es muy a menudo necesario, los nueos tipos de AVR sopor" tan la instrucci#n LPM R,Z+ Esto permite llevar el byte ledo a cualquier ubicacin R y auto-incrementa el puntero de registro. Listas en la memoria flash de programables Ahora que sabemos cmo leer desde la memoria flash es posible que desee colocar una lista de constantes o una cadena de texto. C#mo insertar una lista de alores en la memoria de pro$rama1 Esto se hace con las directias del ensamblador .+A y .+[ con las -ue se pueden insertar listas de alores por bytes o por palabras. (r$ani*ar listas por bytes tiene este aspecto; .D: 12;1(516<18- ;una lista de cuatro bytes, escritos en ,orma decimal .D: =T>is is # te?t.= ;una lista de caracteres de un byte, escrito como te'to >iempre se debe colocar un n2mero par de bytes en cada l)nea. +e lo contrario el ensamblador a.adir un byte cero al ,inal, lo -ue podr)a no ser deseado. Una lista similar de palabras se parece a esto; .D8 12;(516<8- ;una lista con dos palabras constantes En lu$ar de constantes tambi!n se pueden colocar eti-uetas (por e0emplo, los ob0etios de salto) en esa lista, as); 0#"el1@ A ... #'!B #l$!n#s instr!**iones ... C 0#"el2@ A ... #'!B #l$!n#s instr!**iones ... C 0ist#@ .D8 0#"el110#"el2 ;!n# list# de eti'!et#s por p#l#"r#s Las etiquetas deben comenzar en la columna 1 y tienen que terminar con ":". Tenga en cuenta que en la lectura de las etiquetas de la lista con LPM (y el incremento posterior del puntero) se obtiene primero el byte ms bajo de la palabra y despus el byte superior. Acceso a los registros con punteros Una aplicacin muy especial para los registros de puntero es el acceso a los mismos registros. Los registros se encuentran en los primeros 32 bytes del espacio de direcciones del chip (desde la direccin 0x0000 a la 0x001F). Este acceso slo es vlido si tienes que copiar el contenido de algn registro hacia la SRAM o la EEPROM o leer estos valores desde ellas hacia algn registro. Es ms comn el uso de punteros para el acceso a tablas con valores fijos en el espacio de memoria de programa. Como ejemplo, una tabla con 10 valores diferentes de 16 bits, donde se carga el 5 valor a R25:R24, as : 3: MDT#"le@ .D8 )?12;(1)?2;(51)?;(561)?(5681)?56<8 ;V#lores de l# t#"l# or$#niE#d# .D8 )?6<8-1)?<8-A1)?8-A:1)?-A:C1)?A:CD ;por p#l#"r#s Re#d5@ 0DI 3414IG45MDT#"le627 ;dire**i+n en l# t#"l# #l p!ntero 3 0DI 3010/85MDT#"le627 ;m!ltipli*#do por 2 p#r# el #**eso "Dte # "Dte ADI8 3011) ;p!ntero #l '!into v#lor de l# t#"l# 0.M ;le*t!r# del 09: de l# memori# de pro$r#m# M/V R2(1R) ;*opi# 09: #l re$istro de 16 "its ADI8 3011 ;p!ntero #l M9: en l# memori# de pro$r#m# 0.M ;le*t!r# del v#lor M9: de l# t#"l# M/V R251R) ;*opi# M9: #l re$istro de 16 "its Este es s#lo un e0emplo. >e puede calcular la direcci#n de la tabla en Z de un cierto alor de entrada, lleando los respectios alores de la tabla. %as tablas pueden ser or$ani*adas byte a byte y tambi!n por caracteres. Recomendaciones de uso de los re$istros %as si$uientes recomendaciones, si se si$uen, pueden decidir si usted es un pro$ramador en ensamblador e,ica*; +e,inir nombres para los re$istros con la directia .+EL, no utili*ar nunca su nombre directo R'. >i necesita acceso al puntero resere los re$istros R54 a R@3para tal ,in. Un alor de 34 bits situarlo me0or en R59;R58. >i tiene -ue leer de la memoria del pro$rama, por e0emplo tablas ,i0as, resere Z (R@3;R@7) y R7 para tal ,in. >i usted planea tener acceso a bits indiiduales dentro de ciertos re$istros (por e0emplo, banderas de testeo), el utilice los re$istros R34 a R5@ para tal ,in. %os re$istros necesarios para las matemticas estn me0or situados de R3 a R39. >i tiene re$istros ms -ue su,icientes, colo-ue las ariables en los re$istros. >i se -ueda corto de re$istros, colo-ue tantas ariables como sea necesario en >RA&. Puertos /Nu! es un puerto1 %os puertos en los AVR son puertas de la unidad central de proceso a los componentes de hardware y so,tware interno y e'terno. %a CPU se comunica con estos componentes, lee de ellos o les escribe, como los contadores o los puertos paralelos, etc. El puerto ms utili*ado es el re$istro de banderas, donde se se.ali*an las operaciones y se leen las condiciones de bi,urcaci#n. <ay 48 puertos di,erentes, -ue no estn ,)sicamente disponibles en todos los tipos de AVR. +ependiendo del espacio de almacenamiento y otros componentes internos, los di,erentes puertos estn disponibles y accesibles o no. %os puertos -ue pueden ser utili*ados en un determinado tipo de ar con su correspondiente procesador estn especi,icados en las ho0as t!cnicas de datos. %os Atme$a y AFXme$a ampliados tienen ms de 48 puertos, pero el acceso a los puertos ms all de \4@ es di,erente (ese ms adelante). %os puertos tienen una direcci#n ,i0a, con la cual se comunica la CPU. %a direcci#n es independiente del tipo de AVR. As), por e0emplo, la direcci#n de puerto del puerto A es siempre 7'3: (en notaci#n he'adecimal. 7'3: en decimal es 58). Usted no tiene -ue recordar estas direcciones de los puertos, ya 3= -ue tienen un alias coneniente. Estos nombres se de,inen en los archios Y include Y (archios de cabecera) para los di,erentes tipos de AVR y -ue son proporcionados por el ,abricante. %os archios incluyen una l)nea -ue de,ine la direcci#n del puerto A de la si$uiente manera; .ENU P(RFA, 7'3: As) -ue s#lo tenemos -ue recordar el nombre del puerto A, no su ubicaci#n en el espacio de entradasTsalidas del chip. El archio de inclusi#n :939de,.inc est inolucrado en la directia de ensamblador; .EBC%U+E RC;]al$2nlu$ar]:939de,.incR y los re$istros del :939 tambi!n son de,inidos en este archio. %os puertos por lo $eneral se or$ani*an como n2meros de : bits, pero tambi!n puede contener hasta : bits indiiduales -ue no tienen mucho -ue er entre s). Estos bits tienen un si$ni,icado y tienen su propio nombre asociado en el archio de inclusi#n, por e0emplo para habilitar la manipulaci#n de un solo bit. %a conenci#n de nombre se da para no tener -ue recordar estos bits y su posici#n. En las ho0as de datos se pueden encontrar las tablas de puertos. El acceso de escritura a los puertos A modo de e0emplo, el re$istro de control $eneral del &CU, llamado &CUCR, consiste en un n2mero de bits de control -ue controlan las propiedades $enerales del chip. <e a-u) los detalles del puerto &CUCR del AF=7>:939, tomados de las ho0as de datos del dispositio (otros puertos son similares); Es un puerto empacado de : bits de control con sus propios nombres (E>C77, E>C73, ...). >i -uiere eniar a su AVR a un pro,undo sue.o, tiene -ue mirar en su ho0a de datos como con,i$urar los bits implicados, As); .+EL Re$istroPre,erido D R34 %+E Re$istroPre,erido, 7b77377777 (UF &CUCR, Re$istroPre,erido >%EEP %a instrucci#n (UF trae el contenido de Re$istroPre,erido, con el bit >E (>leep"Enable"Ait) actiado, al puerto &CUCR. El bit >E permite al AVR irse a dormir, cada e* -ue la instrucci#n >%EEP apare*" ca en el c#di$o. Fodos los bits del puerto &CUCR tambi!n se pueden establecer con las instrucciones anteriores. >i el bit >& (>leep"&ode) se establece a cero, el AVR entrar en un modo denominado GduermeelaH; no se e0ecutarn ms instrucciones pero el chip reacciona toda)a al tempori*ador y otras interrupciones de hardware. Estos eentos interrumpen el sue.o del AVR si tienen -ue noti,icar a la CPU. %a ,ormulaci#n anterior no es muy transparente, por-ue R7b77377777R no es ,cil de recordar, y no se e ,cilmente -ue se ha establecido en una de estas instrucciones. Por lo tanto, es una buena idea ,ormular la instrucci#n %+E de la si$uiente manera; LDI RegistroPreferido, 1<<SE 57 Esta ,ormulaci#n indica al ensamblador; Fomar un uno (G3H), %eer la posici#n del bit >E, tal como se de,ine en la lista de s)mbolos del archio de cabecera :939de,.inc, -ue da un alor de 9 en este caso, +espla*ar (G^^H) el 3 cinco eces a la i*-uierda (G3^^9H) en los pasos; 3) inicial; 7777.7773, 5) primer despla*amiento a la i*da.; 7777.7737, @) se$undo despla*. a la i*da.; 7777.7377 y as) sucesiamente hasta 4) -uinto despla*. a la i*da.; 7737.7777. asociar este alor a Re$istroPre,erido e insertar esta instrucci#n %+E en el c#di$o. /Como se hace si se -uieren establecer en la misma instrucci#n %+E, los bits >& y >E al mismo tiempo1 >&D3 y >ED3 establecen al AVR en modo apa$ado (power down), por lo -ue s#lo llee esto a cabo si entiende cules son las consecuencias. %a ,ormulaci#n es la si$uiente; LDI RegisroPreferido, (1<<SM) | (1<<SE) Ahora, el ensamblador calcula primero el alor del primer tramo, (3 ^^>&), un R3R se despla*# cuatro eces a la i*-uierda y se produce 7773.7777, a continuaci#n, calcula el se$undo tramo, (3 ^^>E ), un R3R se despla*a cinco eces a la i*-uierda produciendo 7737.7777. El R_R entre los dos alores produce una operaci#n AEF"(R ente ellos por cada bit uno a uno. El resultado de hacer esto con 7773.7777 y 7737.7777 da en este caso 7733.7777, -ue es el alor deseado para la instrucci#n %+E. A pesar de -ue la ,ormulaci#n; (!!"#$ | (!!"%$ podr)a, en el primer ista*o, no ser ms transparente -ue el alor resultante; &&.&&&& para un principiante, es ms ,cil de entender -ue los bits del &CUCR estn propuestos a ser manipula" dos con esta instrucci#n %+E. Especialmente si usted tiene -ue leer y entender el c#di$o al$unos meses ms tarde los bits >& y >E son una indicaci#n de -ue a-u) se est estableciendo el modo sleep o dor" mir. +e otra manera, tendr)a -ue consultar el libro de datos del dispositio con mucha ms ,recuencia. El acceso de lectura a los puertos %eer el contenido de un puerto es posible en la mayor)a de los casos con la instrucci#n EB. %a si$uien" te secuencia; .DEF Re$istro.reerido = R16 IF Re$istro.reerido1 MC&CR lee los bits del puerto &CUCR para el re$istro de nombre Re$istroPre,erido. Como al$unos puertos tienen bits sin de,inir y sin usar, estos se leen siempre como ceros. &s a menudo -ue la lectura de los : bits de un puerto, hay -ue reaccionar a un determinado estado de un bit dentro de un puerto. En ese caso, no necesita leer todo el puerto solo aislar el bit releante. Para ello, ciertas instrucciones proporcionan la circunstancia de e0ecutar otras instrucciones dependiendo del estado de cierto de bit de al$2n puerto (er la secci#n de salto). Acceso de lectura"modi,icaci#n"escritura a los puertos Es posible actiar o desactiar determinados bits de un puerto sin cambiar bits de otro puerto y adems sin leer o escribir los otros bits del puerto. <ay dos instrucciones -ue son >AE (>et Ait ET() y CAE (Clear Ait ET(). %a e0ecuci#n es as); 53 .EQU 3itAti,o=0 ;El $it ()e se ,a a a%$iar '3I Port3, 3itAti,o ;'e esta$lee e" 1 C3I Port3, 3itAti,o ;'e $orra esta$lei8"dolo a ero Estas dos instrucciones tienen una limitaci#n; s#lo se pueden mane0ar los puertos con una direcci#n ms ba0a de 7'57, por encima de esta direcci#n no se pueden acceder los puertos de esta manera. +ebido a -ue el puerto &CUCR de los e0emplos anteriores tiene la direcci#n he'adecimal `@:, los bits del mismo no se pueden establecer o borrar de esta manera. Bo obstante todos los bits de los puertos -ue controlan los pines e'ternos del AVR (P(FF', ++R', PEB'), si son accesibles de esta manera. Asi$naci#n de memoria de acceso al puerto Para pro$ramadores e'#ticos o dispositios $randes como los Atme$a y AFXme$a, donde Atmel se -ued# sin direcciones de acceso a puertos, !stos se pueden acceder tambi!n usando instrucciones de acceso >RA&, como por e0emplo >F y %+. >#lo tiene -ue sumar 7'57 para la direcci#n de puerto y ya tiene direcciones de acceso (recordar -ue las primeras @5 direcciones estn asociadas a los re$istros). Por e0emplo; .DE9 RegistroPreferido = R1# LDI :/,/I0/1P6R;3<=>2 LDI :L,L671P6R;3<=>2 LD RegistroPreferido,: Nue s#lo tiene sentido en ciertos casos, ya -ue re-uiere ms instrucciones, tiempo de e0ecuci#n y l)neas de ensamblador, pero es posible. Es tambi!n la ra*#n de por -ue la locali*aci#n para la primera direcci#n de >RA& es 7'47 y 7'377 en al$unos tipos de AVRs ms $randes. Puertos releantes de los AVR en detalle %a si$uiente tabla contiene los puertos ms utili*ados del Gpe-ue.oH AF=7>:939. Bo ,i$uran todos en esta lista. Al$unos de los tipo &EIA y AF=7>88@8T:9@9 se omiten. En caso de duda consulte la re,e" rencia ori$inal. Componente Nombre de Puerto Registro de Puerto Acumulador >REI Re$istro de Estado Pila >P%T>P< Puntero de Pila >RA& T Enterrupci#n e'ternas &CUCR Re$istro de control $eneral &CU Enterrupciones e'ternas IE&>S Re$istro de mscara de interrupci#n IELR Re$istro de bandera de interrupci#n Fempori*ador de interrupci#n FE&>S Re$istro de mscara de contador de interrupci#n FELR Re$istro de bandera de contador de interrupci#n Fempori*ador 7 de : bits FCCR7 Re$istro de control de contadorTtempori*ador 7 FCBF7 Fempori*adorTcontador 7 Fempori*ador 3 de 34 bits T''(A Re$istro de control de contadorTtempori*ador 3 A T''() Re$istro de control de contadorTtempori*ador 3 A T'*T Fempori*adorTcontador 3 +'(A Re$istro de comparaci#n de salida 3 A 55 +'() Re$istro de comparaci#n de salida 3 A ,'(-./ Re$istro de captura de entrada Fempori0ador de vigilancia 12T'( Re$istro de control del tempori*ador de i$ilancia Acceso EEPR(& EEAR Re$istro de direcciones EEPR(& EE+R Re$istro de datos EEPR(& EECR Re$istro de control EEPR(& Enter,a* peri,!rico serie >PE >PCR Re$istro de control peri,!rico serie >P>R Re$istro de estado peri,!rico serie >P+R Re$istro de datos peri,!rico serie Comunicaci#n serial UARF 1;ra"s%isor?Ree*tor As@"ro"o U"i,ersal) U+R Re$istro de datos UARF U>R Re$istro de estado UARF UCR Re$istro de control UARF UARR Re$istro de elocidad de transmisi#n (baud rate) UARF Comparador anal#$ico AC>R Control de comparador anal#$ico y Re$istro de estado Puertos ET( (entradaTsalida) P(RF' Re$istro de puerto de salida ++R' Re$istro de direcci#n de puerto PEB' Re$istro de puerto de entrada El re$istro de estado como puerto ms utili*ado Con mucho, el puerto ms utili*ado es el re$istro del estado, con sus : bits. Por lo $eneral, el acceso a este puerto se hace mediante con,i$uraci#n automtica, borrado de bits por la CPU o acumulador, acceso por lectura o rami,icaci#n a ciertos bits de este puerto y en al$unos casos es posible la manipulaci#n di" recta de estos bits utili*ando las instrucciones de ensamblador >e' o Cl' donde ' se.ala el bit. %a mayo" r)a de estos bits estn actiados o desactiados por el acumulador para operaciones de test, comparaci#n o clculo. %os bits -ue ms se utili*an son; "Z; >i est a 3, la instrucci#n anterior tuo como resultado cero. "C; >i est a 3, la instrucci#n anterior caus# un acarreo del bit ms si$ni,icatio. %a si$uiente lista tiene todas las instrucciones de ensamblador para actiar o desactiar los bits de estado en ,unci#n del resultado de la e0ecuci#n de la instrucci#n anterior; Bit Clculo Lgico Comparacin Bits Desplazamiento Otro 3 A224 A2'4 A2,14 2%'4 ,*'4 "5)4 "5),4 ")'4 ")',4 "),1 A*24 A*2,4 +(4 +(,4 %+(4 '+#4 *%64 ")(4 ')( 'P4 'P'4 'P, )'-( 34 )"%T 34 '-34 "%34 T"T A"(4 -"-4 -"(4 (+-4 (+( '-( ' A224 A2'4 A2,14 "5)4 "5),4 ")'4 ")',4 "),1 '+#4 *%6 'P4 'P'4 'P, )'-( '4 )"%T '4 '-'4 "%' A"(4 -"-4 -"(4 (+-4 (+( - B A224 A2'4 A2,14 2%'4 ,*'4 "5)4 "5),4 ")'4 ")',4 "),1 A*24 A*2,4 +(4 +(,4 %+(4 '+#4 *%64 ")(4 ')( 'P4 'P'4 'P, )'-( *4 )"%T *4 '-*4 "%*4 T"T A"(4 -"-4 -"(4 (+-4 (+( '-( 5@ V A224 A2'4 A2,14 2%'4 ,*'4 "5)4 "5),4 ")'4 ")',4 "),1 A*24 A*2,4 +(4 +(,4 %+(4 '+#4 *%64 ")(4 ')( 'P4 'P'4 'P, )'-( 74 )"%T 74 '-74 "%74 T"T A"(4 -"-4 -"(4 (+-4 (+( '-( > "),1 " " )'-( "4 )"%T "4 '-"4 "%" " " < A224 A2'4 "5)4 "5),4 ")'4 ")', *%6 'P4 'P'4 'P, )'-( /4 )"%T /4 '-/4 "%/ " " F " " " )'-( T4 )"%T T4 )"T4 '-T4 "%T " " E " " " )'-( ,4 )"%T ,4 '-,4 "%, " (%T, %os detalles de los puertos ms comunes se muestran en una tabla adicional (ane'o). SRAM Casi todos los dispositios AVR disponen de memoria RA& esttica ">RA&" (al$unos pocos anti$uos no la llean). >#lo los pro$ramas muy simples en ensamblador, pueden eitar el uso de este espacio de memoria, por tener toda la in,ormaci#n necesaria en los re$istros. >i te -uedas sin re$istros debes ser capa* de pro$ramar la >RA& para utili*ar ms espacio. /Nu! es la >RA&1 %a >RA& es una memoria -ue no es directamente accesible por la CPU (unidad aritm!tica l#$ica "A%U" a eces llamada acumulador) como si son los re$istros. >i se accede a estos espacios de memoria hay -ue utili*ar un re$istro como almacenamiento proisional. En el e0emplo, se muestra como un alor de >RA& se copia en el re$istro R5 (3U instrucci#n), se hace un clculo con un alor en el re$istro R@(5U ins" trucci#n) y despu!s, el resultado se uele a escribir en la misma ubicaci#n de la >RA& (@U instrucci#n, no mostrada a-u)). Por lo cul, es claro -ue las operaciones con alores almacenados en la >RA& son ms lentas de reali*ar -ue utili*ando re$istros. >in embar$o, incluso el ms pe-ue.o de los AVR tienen 35: bytes de >RA& disponibles, mucho ms de lo -ue pueden contener los @5 re$istros. %os AVR desde el AF=7>:939 en adelante, o,recen la capacidad de conectar RA& e'terna adicional, ampliando la interna 935 bytes. +esde el punto de ista del ensamblador, a la >RA& e'terna se accede como >RA& interna. Bo hay instrucciones adicionales. /Para -u! ,ines puedo usar >RA&1 Adems de almacenamiento simple de los alores, la >RA& o,rece oportunidades adicionales para su uso. Bo s#lo es posible el acceso con direcciones ,i0as, sino tambi!n el uso de punteros, por lo -ue se puede 58 pro$ramar el acceso ,lotante a la >RA&. As), se pueden crear b2,,eres de anillo para almacenamiento proisional de alores o tablas (ariables) de clculo. Esto no es muy ,recuente con los re$istros, por-ue adems de ser pocos, se pre,ieren para el acceso ,i0o. A2n ms habitual es el acceso mediante un despla*amiento de una direcci#n ,i0a a partir de un re$istro de puntero. En este caso, una direcci#n ,i0a se almacena en un re$istro puntero, un alor constante se suma a esta direcci#n y la lecturaTescritura se hace con un despla*amiento de esa direcci#n. Este tipo de acceso a tablas es mucho ms e,ica*. Pero el uso ms releante de la >RA& son las llamadas a la pila. >e pueden poner alores (ariables) en la pila, ya sea el contenido de un re$istro -ue es temporalmente necesario para otro ,in, ya sea una direcci#n de retorno antes de llamar a una subrutina o la direcci#n de retorno antes de atender una interrupci#n. /C#mo usar >RA&1 +ireccionamiento directo Para copiar un alor a una posici#n de memoria de la >RA& tiene -ue de,inir la direcci#n. %as direccio" nes >RA& -ue puede utili*ar abarcan desde la direcci#n de inicio (muy a menudo 7'7747 en pe-ue.os AVRs, 7'7377 en Atme$a ms $randes) hasta el ,inal ,)sico de la >RA& (en el AF=7>:939 el lu$ar accesible de la >RA& interna ms alto es 7'759L, er la ho0a de datos de cada AVR para los detalles). Con la instrucci#n; >F> 7'7747, R3 el contenido del re$istro R3 se copia en la primera direcci#n de memoria 7'7747. Con; %+> R3, 7'7747 el contenido de la >RA& en la direcci#n 7'7747 se copia en el re$istro. Este es el acceso directo con una direcci#n -ue tiene -ue ser de,inida por el pro$ramador. %os s)mbolos de,inidos en el archio de inclusi#n Cde,.inc, >RA&a>FARF y RA&EB+, permiten colocar las ariables en el espacio de >RA&, por lo -ue es me0or utili*ar estas de,iniciones para acceder al -uinceao byte de memoria, as); %+> R3,>RA&a>FARFK39 %os nombres simb#licos se puede utili*ar para eitar la manipulaci#n de direcciones ,i0as, -ue re-uieren mucho traba0o, si lue$o se -uiere cambiar la estructura de los datos en la >RA&. Estos nombres son ms ,ciles de mane0ar -ue los n2meros he'adecimales, por lo -ue ocuparse de dar un nombre como; .E%& MD.reerred9tor#$eCell = 9RAMG9TART 9T9 MD.reerred9tor#$eCell1 R1 Si, el nombre es ms largo, pero ms fcil de recordar. Use cualquier nombre que crea conveniente. Puntero a direcciones Otro tipo de acceso a la SRAM es a travs de punteros. Se necesitan dos registros para este fin que contengan la direccin de 16 bits. Como hemos visto en la divisin de registros de puntero, los registros de puntero son los pares de registros X (XH:XL, R27:R26), Y (YH:YL, R29:R28) y Z (ZH:ZL, R31:R30), que permiten el acceso directo a la ubicacin que elija (ej.: ST X, R1). O despus de decrementar la direccin con por ej.: ST -X, R1 o despus de incrementarla (ST X+, R1). Un acceso completo a una hilera de tres celdas de memoria lucira as: 59 .E%& MD.reerred9tor#$eCell = 9RAMG9TART .DEF MD.reerredRe$ister = R1 .DEF Anot>erRe$ister = R2 .DEF AndHetAnot>erRe$ister = R; 0DI ,41 4IG45MD.reerred9tor#$eCell7 0DI ,01 0/85MD.reerred9tor#$eCell7 0D MD.reerredRe$ister1 ,I 0D Anot>erRe$ister1 ,I 0D AndHetAnot>erRe$ister1 , Con los punteros es fcil operar, tanto como en otros idiomas a parte del ensamblador, que dicen ser ms fciles de aprender. Puntero con desplazamiento La tercera construccin es un poco ms extica y slo programadores experimentados deben usar esto en ciertos casos. Vamos a suponer que en nuestro programa a menudo se necesita acceder a tres lugares de SRAM consecutivos. Vamos a suponer tambin que an disponemos de un par de registros de puntero de repuesto, por lo que puede darse el lujo para el siguiente propsito. Si queremos utilizar las instrucciones ST / LD siempre tenemos que cambiar el puntero si accedemos a otra ubicacin de las tres del ejemplo anterior. Para evitar esto (y para confundir a los principiantes) se invent el acceso con desplazamiento. Durante este acceso el valor del registro no se modifica. La direccin se calcula temporalmente sumando un desplazamiento fijo. En el ejemplo anterior el acceso a la ubicacin 0x0062 se vera de la siguiente manera. Primero, el registro de punteo se ajusta a nuestra ubicacin central SRAM_START: .E%& MD.reerred9tor#$eCell = 9RAMG9TART .DEF MD.reerredRe$ister = R1 0DI H41 4IG45MD.reerred9tor#$eCell7 0DI H01 0/85MD.reerred9tor#$eCell7 En algn lugar ms adelante del programa me gustara escribir en la celda 2 por encima de SRAM_START: 9TD HI21 MD.reerredRe$ister %a correspondiente instrucci#n para la lectura >RA& con un despla*amiento tambi!n es posible; 0DD MD.reerredRe$ister1 HI2 Fen$a en cuenta -ue el 5 no se suma realmente a P, s#lo temporalmente durante la e0ecuci#n de esta instrucci#n. Para Gcon,undirH ms, esto s#lo se puede hacer con los pares de re$istro Z e P, no se puede hacer con el puntero X. +e cada 377 casos, el uso de esta t!cnica se muestra ms e,ica* en un solo caso, as) -ue no importa si no entiende esto en detalle. Es s#lo para e'pertos y necesario s#lo en al$unos casos. El uso de >RA& como pila El uso ms com2n y releante de la >RA& es como pila. %a pila es como una torre de blo-ues. Cada blo-ue -ue se a.ade a en la parte superior de la torre, cada llamada a un alor elimina el blo-ue ms alto de la torre. %a eliminaci#n de blo-ues de la base o de cual-uier porci#n ba0a de la torre es demasiado complicado y desestructurar)a el con0unto de la pila, por lo -ue se recomienda no probar nunca esto. Esta estructura de pila se denomina %EL( (%ast"En"Lirst"(ut, el 2ltimo en entrar es el primero en salir). +e,inici#n de >RA& como pila Para usar la >RA& como pila se re-uiere primero el establecimiento del puntero de pila. Mste es de 34 bits y es accesible como puerto. El doble re$istro se denomina >P<;>P%. >P< contiene el octeto ms si$ni,i" catio y >P%, el menos si$ni,icatio. 54 Esto s#lo es lido, si el tipo de AVR tiene ms de 594 bytes de >RA&. >i no, >P< no es necesario, no est de,inido, y no se debe ni se puede utili*ar. En los si$uientes e0emplos asumiremos -ue tenemos una >RA& con ms de 594 bytes. Para construir la pila, el puntero de pila se car$a con la direcci#n disponible ms alta de la >RA&. (En nuestro caso la torre crece hacia aba0o, hacia las direcciones ba0as, s#lo por ra*ones hist#ricas y para OGcon,undirH a los principiantesQ). .DEF Re$istro.reerido = R16 0DI Re$istro.reerido1 4IG45RAMEFD7 ;"Dte #lto /&T 9.41Re$istro.reerido ;del p!ntero de pil# 0DI Re$istro.reerido1 0/85RAMEFD7 ;"Dte "#Jo /&T 9.01Re$istro.reerido ;del p!ntero de pil# Por supuesto, el valor RAMEND es especfico para el tipo de procesador y est definido en el archivo de inclusin. En el archivo 8515def.inc la lnea: .e'! RAMEFD =K25F ;Lltim# dire**i+n del *>ip El archivo 8515def.inc se incluye en la directiva de ensamblador: .IFC0&DE =C@M#l$Lnl!$#rM8515de.in*= al principio de nuestro cdigo fuente ensamblador. Por lo tanto, se define la pila ahora, y no tiene que preocuparse ms por el puntero de pila debido a que las manipulaciones de este indicador son automticas en su mayora. El uso de la pila El contenido de los registros se ponen en la pila de la siguiente manera: .&94 Re$istro.reerido ;.one el v#lor en l# *im# de l# pil# En caso de que el valor deje de tener inters, como el puntero de pila se decrementa despus de ponerlo, no tiene que preocuparse. Si necesitamos el contenido de nuevo, simplemente aadimos la siguiente instruccin: ./. Re$istro.reerido ;0eer de n!evo el v#lor de l# *im# de l# pil# Con POP acaba de obtener el valor que fue puesto por ltima vez en el tope de la pila. Poner y quitar registros tiene sentido si: El contenido es necesario algunas lneas de cdigo ms tarde, todos los registros estn en uso, y si no existe otra opcin de almacenar ese valor en otra parte. Si estas condiciones no se dan, el uso de la pila para guardar los registros es intil y una prdida de tiempo de procesador. Donde ms sentido tiene el uso de la pila es con las subrutinas, donde despus de ejecutarlas se tiene que volver a la ubicacin del programa que llam a la subrutina. Este pone la direccin de retorno (el valor actual del contador de programa) en la pila y salta temporalmente a la subrutina. Cuando acaba sta, se coje la direccin de retorno de la pila y se carga de nuevo en el contador de programa. La ejecucin del programa contina exactamente en la instruccin siguiente en la que estaba el programa cuando ocurri la llamada: RCALL algo ;Saltar a la etiqueta "algo" [.] aqu despus se continuar con el programa. Aqu el salto a la etiqueta "algo" en algn lugar del cdigo del programa, algo: ;esta es la direccin del salto. [.] aqu hacemos algo 5? [.] termina, y se vuelve a desde donde se hizo la llamada RET Durante la ejecucin de la instruccin rcall el contador de programa se incrementa. Una direccin de 16 bits se inserta en la pila en dos pasos (2 PUSH), el %>A y el &>A. Al lle$ar a la instrucci#n REF, el contenido del contador de pro$rama se uele a car$ar con estos dos bytes (5 P(P) y desde a-u) contin2a la e0e" cuci#n. Bo tiene -ue preocuparse por la direcci#n de la pila desde donde se car$a el contador, ya -ue esta direcci#n se $enera automticamente, incluso si se llama a otra subrutina dentro de la anterior sub" rutina, la pila ,unciona bien. >e ponen dos direcciones de retorno en la parte superior de la pila, la de la subrutina anidada encima de la -ue llama, -ue cuando termina su e0ecuci#n retorna a la subrutina -ue la llam# y !sta a su e* hace lo propio. &ientras haya su,iciente memoria >RA&, todo est bien. El sericio de interrupciones de hardware no es posible sin la pila. Una interrupci#n, como su nombre indica, interrumpe la e0ecuci#n normal del pro$rama. +espu!s de la e0ecuci#n de la rutina de sericio a la interrupci#n, el pro$rama debe oler 0usto a donde estaba cuando se produ0o la interrupci#n. Esto no ser)a posible si no se pudiera almacenar la direcci#n de retorno en la pila. %as enormes enta0as de tener una pila para poder atender las interrupciones son la ra*#n por la -ue hasta el ms m)nimo AVR sin necesidad de >RA&, ten$a el menos una pe-ue.a pila en hardware. Errores comunes en la operaci#n de pila %os principiantes, como es normal, cometen una $ran cantidad de errores cuando comien*an a apren" der a utili*ar la pila. Bo es muy inteli$ente el uso de la pila sin establecer o de,inir primero el puntero de pila. +ebido a -ue este puntero se establece en cero al inicio del pro$rama, apunta a la direcci#n 7'7777 -ue es donde se encuentra el re$istro R7. Poner un byte (PU><) escribiendo en dicho re$istro, sobreescribir)a su con" tenido anterior. Un PU>< adicional escribir)a en 7'LLLL -ue es una posici#n inde,inida si no tiene memoria >RA& e'terna. RCA%% y REF deolern direcciones e'tra.as en la memoria de pro$rama y puede estar se$uro de -ue no habr nin$una adertencia como la aparici#n de una entana diciendo al$o as) como Gacceso ile$al a direcci#n de memoria ''''H. (tros errores comunes son olidarse de sacar de la pila un alor puesto anteriormente o intentar sacar un alor sin haberlo puesto antes. Fambi!n puede suceder en al$2n caso, el desbordamiento de pila por deba0o de la primera direcci#n >RA&. Esto se da cuando se produce una llamada recursia sin ,in. +espu!s de alcan*ar la direcci#n ms ba0a de >RA& los si$uientes PU>< escriben en los puertos (desde 7'779L hasta 7'7757), y los si$uientes en los re$istros (de 7'773L a 7'7777). >i esto contin2a, cosas diertidas e impredecibles pueden suceder en el chip. Eite este error, Oincluso puede destruir su hardware e'ternoQ >alto y Rami,icaci#n A-u) hablaremos de todas las instrucciones -ue controlan la e0ecuci#n secuencial de un pro$rama. >e inicia con la secuencia de arran-ue del procesador, contin2a con saltos, interrupciones, etc. Control secuencial de la e0ecuci#n del pro$rama /Nu! sucede durante un reinicio1 Cuando al AVR se le suministra la tensi#n de alimentaci#n y el procesador comien*a su labor, se actia una secuencia de reinicio. %os puertos se establecen a sus alores iniciales, tal como se de,ine en la ho0a de datos del dispositio y el contador de pro$rama se establece a cero y en esta direcci#n 5: comien*a la e0ecuci#n del pro$rama, donde debemos tener nuestra primera palabra de c#di$o. Pero no s#lo durante el encendido se actia esta direcci#n; >i se produce un reset e'terno en el pin de reset el dispositio e0ecuta un reinicio. >i lle$a a su alor m'imo el contador del perro $uardin (watchdo$) tambi!n se e0ecuta un reinicio. El tempori*ador de i$ilancia es un relo0 interno -ue debe ser reseteado de e* en cuando por el pro$rama, de lo contrario, se reinicia el procesador. Usted puede llamar a reinicio por un salto directo a esa direcci#n (!ase la secci#n salto "0ump" ms adelante). El tercer caso no es un reset real, por-ue no se e0ecuta el rea0uste automtico de alores de re$istros y puertos a un alor por de,ecto bien de,inido. Por lo tanto, nos olidamos de esto por el momento. El a0uste del watchdo$ a cero para eitar un reinicio re-uiere la e0ecuci#n de la instrucci#n; WDR +espu!s de la e0ecuci#n de un reset, con el establecimiento de re$istros y puertos a los alores por de,ecto, el c#di$o en la direcci#n 7777 (tipo palabra) comien*a a e0ecutarse en el procesador. El contador de pro$rama se incrementa en uno y la si$uiente palabra de c#di$o est ya en el bu,,er de lectura. >i la instrucci#n e0ecutada no re-uiere un salto se e0ecuta la si$uiente inmediatamente. Esta es la ra*#n por la -ue los AVR son tan rpidos, cada ciclo dde relo0 e0ecuta una instrucci#n si no se producen saltos. %a primera instrucci#n de un archio e0ecutable se encuentra siempre en la direcci#n 7777. Para indicar al compilador (ensamblador del pro$rama) -ue nuestro c#di$o ,uente empie*a a-u) y ahora, puede colocarse al principio una directia especial; .C9EG ./RG )))) La primera directiva. CSEG, permite al compilador cambiar su salida a una seccin de cdigo, es decir define el inicio de un segmento de cdigo. Todo lo siguiente se traduce como cdigo y se escribe en la seccin del procesador de la memoria de programa. Otro segmento destino sera la seccin EEPROM del chip, donde tambin se pueden escribir bytes o palabras. .E9EG %l tercer segmento es la secci8n de "(A#. .D9EG E'cepto en la EEPR(&, donde el contenido es realmente lo -ue est pasando en la EEPR(& durante la pro$ramaci#n del chip, el contenido del se$mento +>EI no est pro$ramado para el chip. Bo tiene posibilidad de $rabar contenido en >RA&. As) -ue +>EI. s#lo se utili*a para el clculo de la eti-ueta correcta durante el proceso de ensamblado. Un e0emplo; .D9EG ;0#s si$!ientes son deini*iones de eti'!et# dentro del se$mento 9RAM .rimer#V#ri#"le:Dte@ .:HTE 1 ;El p!ntero D9EG se m!eve >#*i# #rri"# !n "Dte 9e$!nd#V#ri#"le.#l#"r#@ .:HTE 2 ;El p!ntero D9EG se m!eve >#*i# #rri"# dos "Dtes Ter*er#V#ri#"le:!er@ .:HTE ;2 ;El p!ntero D9EG se m!eve >#*i# #rri"# ;2 "Dtes 5= As, slo se definen tres etiquetas en el cdigo, no se produce contenido. %a directia (RI en el se$mento de c#di$o, pasa por encima de la primera palabra de c#di$o y manipula la direcci#n donde debe ir, es decir establece el inicio ((RiIin) del pro$rama. En los pro$ramas dise.ados para -ue de todas ,ormas empiecen en la direcci#n 7'7777, las directias C>EIT(RI son triiales y puede pasarlas por alto sin $enerar error. Podr)amos comen*ar en 7'7377, pero no tiene nin$2n sentido real cuando el procesador comien*a su e0ecuci#n en 7777. >i desea colocar una tabla e'actamente en un determinado lu$ar del se$mento de c#di$o, puede utili*ar .(RI, pero ten$a cuidado con lo si$uiente; Con .(RI solo se da el salto hacia delante, nunca hacia atrs. Por lo -ue hay -ue tener cuidado tambi!n, ya -ue el salto ,or*ado por .(RI en espacio de memoria ,lash donde se ubica el c#di$o corriente, est lleno de la instrucci#n 7'LLLL. Esta instrucci#n no hace nada, solo ir a la si$uiente instrucci#n, asi -ue ase$urese de -ue su e0ecuci#n no salte en medio de tal espacio inde,inido. >i en el principio de su secci#n de c#di$o desea establecer una se.al clara, despu!s de las de,iniciones con las directias .+EL y .ENU, puede uasr la secuencia C>EIT(RI como una se.al para usted, aun-ue no hubiera sido necesario hacerlo. Como la primera palabra de c#di$o est siempre en la direcci#n cero, a este lu$ar se le llama tambi!n el ector de reset. Fras !ste, las si$uientes posiciones en el espacio de memoria, las direcciones 7'7773, 7'7775, etc, son ectores de interrupci#n. Estas son las posiciones a las -ue salta la e0ecuci#n si se produce una interrupci#n interna o e'terna. Estos ectores son espec),icos para cada tipo de procesador y dependen del hardware interno (!ase ms adelante). %a instrucci#n para reaccionar ante una interrupci#n dada debe ser colocada en el ector adecuado. >i se utili*an interrupciones, el primer c#di$o en el ector de reset, debe ser una instrucci#n de salto, para sortear estos otros ectores. Cada ector de interrupci#n -ue se plani,i-ue -ue est! habilitado, debe tener una instrucci#n de salto a la rutina de sericio de interrupci#n respectia. >i el ector no se utili*a, lo ms indicado es poner una instrucci#n REFE (Retorno de interrupci#n) ,icticia. %a secuencia t)pica del pro$rama al principio es como si$ue; .C9EG ./RG )))) RNM. 9t#rt ;el ve*tor de reset RNM. Int9ervRo!t1 ;l# r!tin# de servi*io de l# 1O interr!p*i+n RETI ;instr!**i+n i*it*i# de interr!p*i+n sin !s#r RNM. Int9ervRo!t; ;l# r!tin# de servi*io p#r# l# ;O interr!p*i+n A...C aqu ponemos las otras instrucciones del vector de interrupcin A...C D #'!B es !n "!en l!$#r p#r# l#s r!tin#s de servi*io de interr!p*i+n Int9ervRo!t1@ A...C C+di$o de l# r!tin# de servi*io de l# 1O interr!p*i+n RETI ;Fin#l de l# 1O r!tin# de servi*io Int9ervRo!t2@ A...C C+di$o de l# r!tin# de servi*io de l# ;O interr!p*i+n RETI ;Fin#l de l# 2O r!tin# de servi*io A...C otro *+di$o 9t#rt@ ;Aqu el inicio del programa A...C A'!B el pro$r#m# prin*ip#l La instruccin "RJMP Start resulta en un salto a la etiquete Start:, que se encuentra algunas lneas debajo. Recuerde que las etiquetas terminan siempre con un " : . Las etiquetas que no cumplan esta condicin no se tienen en cuenta, dando un mensaje de error "Undefined label" (etiqueta no definida) y se interrumpe la compilacin. Ejecucin lineal del programa y bifurcaciones @7 La ejecucin del programa es siempre lineal, si nada cambia la ejecucin secuencial. Estos cambios pueden producirse por la ejecucin de una interrupcin o de instrucciones de ramificacin. Ramificacin La ramificacin se suele producir en funcin de alguna condicin llamada bifurcacin condicional. Como ejemplo vamos a suponer que queremos construir un contador de 32 bits utilizando los registros R1 a R4. El byte menos significativo en R1 se incrementa en uno. Si el registro se desborda durante la operacin (255 + 1 = 0), incrementamos R2. Si se desborda R2, incrementamos R3 y as sucesivamente. El incremento en uno se hace con la instruccin NC. Si ocurre un desbordamiento durante la ejecucin de NC R1, el bit cero en el registro de estado se establece a 1 (el resultado de la operacin es cero). El bit de acarreo en el registro de estado se establece a 1 cuando hay un desbordamiento, no cambia cuando se ejecuta NC. Se trata de no confundir al principiante pero el acarreo se puede utilizar para otros fines. Si no hay desbordamiento podemos salir de la secuencia de conteo. Si el bit cero est establecido a 1, se debe ejecutar el incremento del registro superior siguiente. La instruccin de ramificacin que se utiliza en este caso es BRNE (Branch if Not Equal). La secuencia de conteo del contador de 32 bits debera tener este aspecto: IFC R1 ;in*rement# el *ontenido del re$istro R1 :RFE Go/n;2 ;si no es *ero1 ir # l# r#m# Go/n;2@ IFC R2 ;in*rement# el *ontenido del re$istro R2 :RFE Go/n;2 IFC R; :RFE Go/n;2 IFC R( Go/n;2@ Esto es todo. La condicin opuesta a BRNE es BREQ (Branch Equal). Cul de los bits de estado, tambin llamados banderas del procesador, cambian durante la ejecucin de una instruccin, se muestra en las tablas de cdigos de instrucciones, consulte la lista de instrucciones. Al igual que el bit cero se podran utilizar otros bits de estado, como por ejemplo, Eti'!et#s :RCCP:RC9; "#nder# de #*#rreo ) 5:RCC7 o 1 5:RC97 Eti'!et# :R94; i$!#l o m#Dor Eti'!et# :R0/; menor Eti'!et# :RMI; menos Eti'!et# :R.0; mQs Eti'!et# :RGE; M#Dor o i$!#l 5*on "it de si$no7 Eti'!et# :R0T; menor 5*on "it de si$no7 Eti'!et#s :R4CP:R49; "#nder# medio des"ord#miento1 ) o 1 Eti'!et#s :RTCP:RT9; "it T ) o 1 Eti'!et#s :RVCP:RV9; "#nder# de *omplemento # dos1 ) o 1 Eti'!et#s :RIEP:RID; interr!p*i+n #*tiv#d# o des#*tiv#d# para reaccionar a las diferentes condiciones. La ramificacin siempre se produce si se cumple la condicin. La mayora de estas instrucciones se utilizan muy poco. Para el principiante, con el bit cero y el de acarreo son suficientes. El tiempo durante la ejecucin del programa Como se ja mencionado anteriormente, el tiempo necesario para ejecutar una instruccin es igual a un ciclo de reloj del procesador. Si el procesador corre a una frecuencia de reloj de 4 Mhz, una @3 instruccin requiere de microsegundo 250 ns. A 10 MHz requerira 100 ns. El tiempo requerido es tan exacto como lo sea el reloj interno o externo o Xtal. Si necesitamos el tiempo exacto, un AVR es la solucin. Tenga en cuenta que hay algunas instrucciones que requieren dos o ms ciclos como las instrucciones de ramificacin (si se produce la ramificacin) o la lectura/escritura secuencial de SRAM. Consulte la tabla de instrucciones para los detalles. Para poder definir el momento exacto, debe haber una oportunidad de no hacer nada ms que retrasar la ejecucin del programa. Se pueden utilizar otras instrucciones que no hagan nada, pero es mejor utilizar la instruccin NOP (no-operation). Esta es la instruccin ms inoperante: NOP Esta instruccin no hace ms que perder tiempo de procesador. A 4 Mhz, necesitamos justo cuatro instrucciones NOP para consumir 1 s. No hay otros ocultos significados aqu en la instruccin NOP. Para un generador de seal de 1 Khz no es necesario aadir 4.000 instrucciones NOP a nuestro cdigo fuente. En este caso se utilizara un contador de software y algunas instrucciones de ramificacin con los que se construira un bucle que se ejecuta un determinado nmero de veces y hacen el retardo con exactitud. Un contador podra ser un registro de 8 bits que se decrementa con la instruccin DEC, as por ejemplo, de esta manera: C0R R1 ;!n *i*lo de reloJ Co!nt@ DEC R1 ;!n *i*lo de reloJ :RFE Co!nt ;dos p#r# l# "i!r*#*i+n1 !no por l# no "i!r*#*i+n Esta secuencia consume (1) + (255*2) + (1*3) = 514 ciclos de reloj 128,5 s a 4 MHz. Fambi!n se puede utili*ar un contador de 34 bits para hacer un retardo e'acto de esta ,orma; 0DI 3414IG45655;57 ;!n *i*lo de reloJ 0DI 3010/85655;57 ;!n *i*lo de reloJ Co!nt@ 9:I8 3011 ;dos ciclos de reloj :RFE Co!nt ;dos p#r# l# "i!r*#*i+n1 !no por l# no "i!r*#*i+n Esta secuencia consume (1+1) + (65534*4) + (1*3) = 262,141 ciclos de reloj 65.535,25 s a 4 Mhz. Si se utilizan ms registros para construir contadores anidados se puede llegar a cualquier retraso, y ste es tan exacto como lo sea la fuente de reloj, incluso sin un temporizador de hardware. Las macros y la ejecucin del programa A menudo se tienen que escribir secuencias de cdigo idnticas o similares en diferentes ocasiones y lugares en el cdigo fuente. Si quiere puede escribirlo una sola vez utilizando una macro para evitar el cansancio de escribir la misma secuencia varias veces. Las macros son secuencias de cdigo, que una vez diseadas y comprobado su correcto funcionamiento, se insertan en el cdigo por el nombre de la macro. Como ejemplo vamos a suponer que tenemos que retrasar varias veces el tiempo de ejecucin del programa en 1 s con un reloj de 4 Mhz. En algn lugar del fichero fuente se define una macro: .MACR/ Del#D1 F/. F/. F/. F/. .EFDMACR/ @5 Esta definicin de la macro an no produce ningn cdigo, no hace nada. El cdigo slo se producir si se llama a esa macro por su nombre: A...C en #l$Ln l!$#r del *+di$o !ente Del#D1 A...C el *+di$o v# #'!B Esto hace que cuatro instrucciones NOP sean insertadas en el cdigo en ese lugar. Adicionales "DELAY1" insertaran otras cuatro instrucciones NOP. Si la macro tiene secuencias muy largas de cdigo o si tiene poco espacio de almacenamiento de cdigo, debe evitar el uso de macros y utilizar subrutinas en su lugar. Al llamar a una macro por su nombre, puede agregar algunos parmetros para manipular el cdigo producido, pero por ahora esto es lo que debe saber como principiante acerca de las macros. Subrutinas Al contrario que las macros las subrutinas hacen ahorrar espacio de almacenamiento de programa. La secuencia se almacena una sola vez en el cdigo y luego se puede llamar desde cualquier parte del mismo. Para asegurar la ejecucin continua de la secuencia siguiente despus de ejecutar la subrutina, se necesita volver a la secuencia llamadora. Para un retraso de 10 ciclos se necesitara por ejemplo esta subrutina: Del#D1)@ ;l# ll#m#d# de l# s!"r!tin# re'!iere #l$!nos *i*los F/. ;retr#so de !n *i*lo F/. ;retr#so de !n *i*lo F/. ;retr#so de !n *i*lo RET ;Volver de l# ll#m#d# Para que se pueda saltar a ellas, las subrutinas siempre empiezan con una etiqueta. En el ejemplo la etiqueta es "Delay10:. Le sigue tres instrucciones NOP y una instruccin RET. Si se cuentan los ciclos se encuentran 7 (3 para las NOP y 4 para la RET). Las 3 que faltan son para llamar a la subrutina: A...C@ RCA00 Del#D1) A...C mQs #del#nte en el *+di$o !ente Rcall es una llamada relativa. La llamada se codifica como salto relativo. La distancia relativa desde la rutina llamadora hasta la subrutina es calculada por el compilador. La instruccin RET salta de nuevo a la rutina llamadora. Tenga en cuenta que antes de hacer llamadas a subrutinas debe esta- blecer el puntero de pila, debido a que la direccin de retorno debe ser puesta en la cima de la pila durante la instruccin RCALL. Si desea ir directamente a alguna otra parte del cdigo, tiene que utilizar la instruccin de salto: A...C en #l$Ln l!$#r del *+di$o !ente RNM. Del#D1) Ret!rn@ A...C mQs #del#nte en el *+di$o !ente Tenga en cuenta que RJMP tambin es una instruccin de salto relativo con la distancia limitada. Slo los AVRs Atmega tienen una instruccin JMP que permite saltos en el espacio completo de memoria flash, pero esta instruccin requiere dos palabras y ms tiempo de instruccin que RJMP por lo que es mejor evitarla si es posible. La rutina que salt no puede utilizar la instruccin RET en este caso, porque RJMP no coloca la direccin actual de ejecucin en la pila. Para volver de vuelta al lugar de la llamada se requiere @@ agregar otra etiqueta y la rutina llamada salta de nuevo a esta etiqueta. Este salto no es como llamar a una subrutina porque no se la puede llamar desde distintas ubicaciones del cdigo. RCALL y RJMP son bifurcaciones incondicionales. Para ir a otro lugar de forma condicionada tiene que combinarlas con otras. Una llamada a subrutina condicionada, sde puede hacer con las siguientes (confusas) instrucciones. Si quiere llamar a una subrutina en funcin de cierto bit de un registro puede utilizar la siguiente secuencia: 9:RC R11< ;9#lt#r l# si$!iente instr!**i+n si el "it < en el re$istro 1 es ) RCA00 &p0#"el ;0l#m#d# # s!"r!tin# SBRC es Skip siguiente inst. si Bit x en Registro es Clear (=Cero). La instruccin RCALL a "UpLabel solo se ejecuta si el bit 7en el registro R1 es 1, ya que la siguiente instruccin a SBRC se saltara si fuese 0. Si se quisiera que sea al contrario, llamar a la subrutina en caso de que el bit correspondiente fuese 0, se utilizara la instruccin SBRS. La siguiente instruccin a SBRS/SBRC puede ser de una palabra o de doble palabra. En todo caso, el procesador sabe el salto que tiene que hacer, pero tenga en cuenta que los tiempos de ejecucin son diferentes. Para saltar ms all de la siguiente instruccin, SBRS/SBRC no se pueden utilizar. Si tuviera que saltar una instruccin para el caso de dos registros que tuvieran el mismo valor se puede utilizar la siguiente extica instruccin (que se utiliza raras veces): C.9E R11R2 ;Comp#r#r R1 D R2 D s#lt#r l# si$!iente instr!**i+n si son i$!#les RCA00 Al$!n#9!"r!tin# ;0l#m#d# # Al$!n#9!"r!tin# Si por ejemplo tuviera que saltar la instruccin siguiente en funcin de determinado bit de un puerto, se utilizaran las instrucciones SBC y SBS (Skip si el Bit /O es Clear -o Set-), as: 9:IC .IF:1) ;9#lt#r l# si$!iente instr!**i+n si el "it ) en el p!erto : es ) RNM. AT#r$et ;9#lt#r # l# eti'!et# At#r$et La instruccin RJMP slo se ejecuta si el bit 0 en el puerto B est alto. Esto es algo confuso para el principiante. El acceso a los bits de puerto se limita a la mitad inferior de los puertos, los 32 puertos superiores no se pueden utilizar aqu. Ahora, a modo de ejemplo, otra extica aplicacin para expertos. Supongamos que tenemos un interruptor de bits con 4 interruptores conectados al puerto B. Dependiendo del estado de esos 4 bits habra que ir a 16 lugares diferentes en el cdigo. Entonces tenemos que leer el puerto y utilizar varias instrucciones de bifurcacin para ir al lugar adecuado. Como alternativa, se puede escribir una tabla que contenga las 16 direcciones as: MDT#"@ RNM. Ro!tine1 RNM. Ro!tine2 A...C RNM. Ro!tine16 En el cdigo copiamos la direccin de la tabla para el registro de puntero Z: 0DI 3414IG45MDT#"7 0DI 3010/85MDT#"7 y sumamos el estado actual del puerto B (en R16) a esta direccin ADD 301R16 :RCC Fo/verloR IFC 34 Fo/verloR@ @8 Ahora podemos ir a esta ubicacin en la tabla, ya sea para llamar a una subrutina: ICA00 ;ll#m# # l# s!"r!tin# '!e se en*!entr# en l# dire**i+n 3 o como un salto sin camino de regreso: INM. ;ir dire*t#mente # l# dire**i+n en 3 El procesador carga el contenido del par Z en el contador de programa y contina la operacin all. Mejor que bifurcar una y otra vez! nterrupciones y ejecucin del programa A menudo tenemos que reaccionar a condiciones de hardware u otros eventos. Un ejemplo es un cambio en un pin de entrada. Usted puede haber programado un bucle que pregunta si se produce un cambio en un pin para tomar una decisin. Este mtodo se llama pollin$ (sondeo), que se aseme- ja a una abeja dando vueltas en crculo buscando nuevas flores. Si no hay otras cosas que hacer y el tiempo de respuesta no importa, se puede dedicar el procesador a esto. Si tiene que detectar pulsos de menos de 1 s, este mtodo no sirve. En este caso, se necesita programar una interrupcin. Una interrupcin se activa por ciertas condiciones de hardware. Todas las interrupciones de hardware estn deshabilitadas de forma predeterminada en el reset, por lo que hay que activar la condicin en primer lugar. Se establecen primero los bits de puerto correspondientes que permitan habilitar las interrupciones. El procesador tiene un bit en su registro de estado que le permite habilitar el respon- der a las interrupciones, la bandera de habilitacin de interrupcin. La activacin general de respues- ta a las interrupciones requiere de la instruccin: 9EI ;9et Int En#"le :it Despus, para estar habilitadas, cada interrupcin por separado requiere adems la manipulacin en el puerto correspondiente. Si se produce la condicin que lleva a la interrupcin, por ejemplo, un cambio en un bit de un puerto, el procesador pone en la pila (habiendo habilitado primero el puntero de pila) el valor actual del con- tador de programa. Sin esto, el procesador no sera capaz de volver al lugar donde se produjo la in- terrupcin (que puede ser en cualquier momento y en cualquier lugar durante la ejecucin del pro- grama). Despus, el procesador salta a la ubicacin predefinida, el vector de interrupcin, y ejecuta la instruccin. Por lo general, sta suele ser una instruccin de salto (JUMP) a la rutina de servicio de la interrupcin, que se encuentra en algn lugar del cdigo. El vector de interrupcin es una localiza- cin especfica del procesador y va en funcin de los componentes de hardware y de la condicin que conduce a la interrupcin. Cuntos ms componentes de hardware y ms condiciones, ms vec- tores. Los diferentes vectores para algunos tipos de AVR antiguos se enumeran en la tabla siguiente. El primer vector no es de interrupcin, es el de reset que no realiza ninguna operacin con la pila. Nombre Direcc. del vector de interrupcin Provocada por 2313 2323 8515 RESET 0000 0000 0000 /ard9are (eset4 Po9er-+n-(eset4 1atchdog (eset NT0 0001 0001 0001 Cambio de nivel en el pin externo NT0 NT1 0002 - 0002 Cambio de nivel en el pin externo NT1 TMER1CAPT 0003 - 0003 Captura de eventos en Timer/Counter 1 TMER1 COMPA - - 0004 Timer/Counter 1 = Compare value A TMER1 COMPB - - 0005 Timer/Counter 1 = Compare value B TMER1 COMP1 0004 - - Timer/Counter 1 = Compare value 1 @9 TMER1 OVF 0005 - 0006 Timer/Counter 1 Overflow TMER0 OVF 0006 0002 0007 Timer/Counter 0 Overflow SP STC - - 0008 Transmisin serie completa UART TX 0007 - 0009 UART Disponible un carcter en el bfer UART UDRE 0008 - 000A UART transmisor corri vaco UART TX 0009 - 000B UART Todo enviado ANA_COMP - - 000C Comparador Analgico Hay que tener en cuenta que la capacidad de reaccionar ante los acontecimientos es muy diferente para los diferentes AVRs. Las direcciones son secuenciales, pero las mismas para los diferentes tipos. Consulte la hoja de datos para cada tipo de AVR. Cuanto ms alto sea un vector en la lista, mayor es su prioridad. Si dos o ms componentes tienen una condicin de interrupcin en espera al mismo tiempo, el vector con la direccin ms alta gana. La interrupcin inferior tiene que esperar hasta que la interrupcin superior este servida. La deshabili- tacin de interrupciones bajas durante la ejecucin de la rutina de servicio de una primera interrup- cin se realiza con una bandera del procesador que la rutina de servicio debe volver a activar una vez que acabe. Para volver a establecer el bit de estado hay dos formas. La rutina de servicio puede terminar con la instruccin: RETI Este retorno de la rutina restaura el bit despus de que la direccin de retorno se ha cargado al contador de programa. La segunda forma es activar el bit con la instruccin: 9EI ;9et Interr!pt En#"led RET ;Volver Esto no es igual que con RET ya que las interrupciones posteriores ya estn habilitadas antes que el contador de programa se cargue con la direccin de retorno. Si otra interrupcin est pendiente, su ejecucin ya ha comenzado antes que la direccin de retorno se haya extrado de la pila. Dos o ms direcciones estaran anidadas en la pila. Normalmente no tiene porqu producir error, pero es un ries- go innecesario. Es mejor utilizar RET y evitar este flujo innecesario en la pila. Un vector de interrupcin slo puede contener una sla instruccin de salto con respecto a la rutina de servicio. Si una interrupcin est indefinida o no se utiliza hay que asociarla con una instruccin RET, para el caso de que suceda la interrupcin errneamente antes de haber escrito la rutina de servicio. En algunos casos es absolutamente necesario para responder a estas falsas interrupciones. Puede darse el caso de que la respectiva rutina de servicio no restablezca automticamente la ban- dera de interrupcin del perifrico. Entonces una simple RET restablecera la interrupcin que de otro modo no acabara nunca. Esto se ds con algunas de las interrupciones del UART. Tenga en cuenta que dispositivos grandes tienen una organizacin de palabra doble en la tabla de vectores. En estos casos, en lugar de RJMP, debe ser utilizada la instruccin JMP y la instruccin RET seguida por una NOP para que apunte a la direccin siguiente de la tabla de vectores. Como despus de que entra una interrupcin, la ejecucin de las interrupciones de menor prioridad est bloqueada, las rutinas de servicio a interrupcin deben ser lo ms cortas posible. Si usted nece- sita tener una rutina grande para servir a la interrupcin, utilice uno de los dos mtodos siguientes. El primero es permitir interrupciones con SE (Set nterrupt Enabled) en la rutina de servicio cada vez que haya terminado con las tareas ms urgentes. Aunque no es muy inteligente. Es ms conveniente llevar a cabo las tareas urgentes, establecer la bandera en un registro en algn lugar de reaccin @4 lenta y regresar a la interrupcin inmediatamente. Una regla importante para las rutinas de servicio de int. es: La primera instruccin es siempre para salvar los indicadores de estado del procesador en un registro o en la pila. Haga esto antes de usar las instrucciones que podran cambiar las banderas del registro de estado. La razn es que el programa principal interrumpido slo podra estar en un estado mediante los indicadores de estado y la interrupcin acaba de cambiar las banderas a otro estado. Cosas diverti- das que ocurren de vez en cuando. Por lo tanto, la ltima instruccin antes de RET es copiar las banderas en un registro para traerlas de vuelta al puerto de estado o poner el contenido del registro de estado en la pila para restaurarlo a su estado anterior. A continuacin se muestran ejemplos de cmo hacerlo: "alvando en un registro: Isr@ IF R1519REG ;$!#rd#r "#nder#s A... more instr!*tions...C /&T 9REG1R15 ;rest#!r#r "#nder#s RETI ;volver de l# interr!p*i+n Salvando en la pila: Isr@ .&94 R15 ;s#lv#ndo el re$istro en l# pil# IF R151 9REG A...more instr!*tions...C /&T 9REG1R15 ;rest#!r#r "#nder#s ./. R15 RETI ;volver de l# interr!p*i+n El mtodo de abajo es ms lento. El mtodo de arriba requiere un registro exclusivamente a tal fin. En general: Todos los registros utilizados en una rutina de servicio deben ser reservados exclusiva- mente a este efecto o deben ser guardados en la pila y restaurados a finales de la rutina de servicio. Dentro de una rutina de servicio de int., nunca cambie el contenido de un registro que es utilizado en alguna otra parte del programa, sin restaurarlo. Debido a estos requisitos bsicos, un ejemplo ms sofisticado para una rutina de servicio de int.: .C9EG ;#'!i empieE# !n se$mento de *+di$o ./RG )))) ;en l# dire**i+n *ero RNM. 9t#rt ;el ve*tor de reset en l# dire**i+n )))) RNM. I9ervi*e ;)))1@ primer ve*tor de int.1 r!tin# de servi*io IFT) ASC otros ve*tores 9t#rt@ ;#'!B comienza el programa principal A...C #'!B p#r# l# deini*i+n de l# pil# D otr#s *os#s I9ervi*e@ ;aqu comienza la rutina de servicio de int. .&94 R16 ;guardar registro enla pila IF R1619REG ;leer el registro de estado .&94 R16 ;y ponerlo en la pila A...C aqu la rutina de servicio de int. hace algo y utiliza el registro R16 ./. R16 ;o"tener el re$istro de "#nder# #nterior de l# pil# @? /&T 9REG1R16 ;restaurar el anterior estado ./. R16 ;obtener el contenido anterior de R16 de la pila RETI ;D retorn#r desde int. Parece un poco complicado, pero es un requisito previo para usar interrupciones sin que se produz- can errores graves. Saltar PUSH R16 y POP R16 si no se puede permitir reservar el registro para uso exclusivo dentro de la rutina de servicio. Como una rutina de servicio de int. no puede ser inte- rrumpida (a no ser que se permitan otras interrupciones dentro de la rutina) todas las diferentes ruti- nas de servicio de int. pueden utilizar el mismo registro. Ahora deber ser claro por qu permitir interrupciones dentro de una rutina de servicio de int. y no al final con RET no es una buena idea. Clculos Aqu hablaremos de todas las instrucciones necesarias para el clculo en lenguaje ensamblador AVR. Esto incluye los sistemas de numeracin, ajustes de bits, desplazamiento y rotacin, sumar, restar o comparar y formatos de conversin. Sistemas de numeracin en ensamblador Los siguientes formatos de nmeros son comunes en ensamblador: Nmeros enteros positivos (bytes, palabras, palabras largas, etc) Nmeros enteros con signo (enteros pequeos y grandes) Dgitos codificados en binario (BCD) BCD empacado. ASC con formato numrico. Si usted viene de un lenguaje de alto nivel olvide los formatos predefinidos de nmero. El ensambla- dor no tiene ese concepto ni sus limitaciones: usted es el dueo de su propio formato. Nmeros enteros positivos (bytes, palabras, etc) El nmero entero menor que se maneja en ensamblador es un byte de ocho bits. ste cdigo numrico abarca desde el 0 al 255. Estos bytes encajan exactamente en un registro del MCU. Los nmeros ms grandes deben estar basados en este formato base, com ms de un registro. Dos bytes producen una palabra (desde 0 a 65.535), tres bytes forman una palabra larga (desde 0 a 16.777.215) y cuatro bytes forman una palabra doble (desde 0 a 4.294.967.295). Un byte, una palabra o una palabra doble se pueden almacenar en cualquier registro que se elija. Las operaciones con estos bytes se programan byte a byte, por lo que no hay que ponerlos en una fila. Formar una fila para almacenar una palabra doble podra ser as: .DEF r16 = dR) .DEF r1< = dR1 .DEF r18 = dR2 .DEF r1- = dR; Los registros dw0 a dw3 estn en una fila pero no es necesario. Si tenemos que iniciar esta palabra doble (por ejemplo, 4.000.000) al comienzo de una aplicacin, puede tener este aspecto: .E%& dRi = ()))))) ;se deine l# *onst#nte 0DI dR)10/85dRi7 ;09: # R16 0DI dR11:HTE25dRi7 ;"its 8 .. 15 # R1< 0DI dR21:HTE;5dRi7 ;"its 16 .. 2; # R18 0DI dR;1:HTE(5dRi7 ;"its 2( .. ;1 # R1- @: Hemos dividido este nmero decimal, llamado dwi, en sus partes binarias byte4 a byte1 y empacado en un paquete de 4 bytes. Ahora se pueden hacer clculos con esta palabra doble. Nmeros enteros con signo A veces, aunque en casos raros, se necesita hacer clculos con nmeros negativos. Un nmero negativo se define por interpretar el bit ms significativo de un byte como bit de signo. Si es 0 el nmero es positivo. Si es 1 es negativo. Si el nmero es negativo por lo general no se almacena el resto del nmero tal como est, sino que usamos su valor invertido. nvertido significa que -1 no se escribe como 1000.0001, sino como 1111.1111. Esto significa: restar 1 a 0 (y olvidar el desborda- miento). El primer bit es el bit de signo, lo que indica que se trata de un nmero negativo. Se utiliza este formato diferente (restar el nmero de 0) porque la suma de -1 (1111.1111) y 1 (0000.0001) da exactamente cero, si se olvida el desbordamiento producido con la operacin (el noveno bit). En un byte el nmero entero ms grande que se maneja es 127 (binario 01111111)y el ms pequeo es -128 (binario 10000000). En otros lenguajes de programacin este formato de nmero se llama entero corto. Si usted necesita un mayor rango de valores puede aadir otro byte para formar un valor entero ms grande, que va desde 32.767 .. -32.768, cuatro bytes proporcionan un rango desde 2147483647 .. -2147483648, llamado en otros lenguajes entero largo o doble. Dgitos en codificacin binaria, BCD Hemos hablado anteriormente del formato ms eficaz para usar el espacio disponible con nmeros enteros positivos o con signo. Otro formato menos denso y ms fcil de entender y manejar es almacenar nmeros decimales en bytes, un dgito en cada byte. El dgito decimal se almacena en su formato binario en un byte. Cada dgito comprendido entre 0 .. 9 necesita 4 bits (valores binarios 0000 .. 1001) y los cuatro bits superiores del byte son siempre ceros. Para manejar el valor 250 se necesitan por lo menos tres bytes, por ejemplo: Valor de bit 128 6 32 16 8 2 1 R16, Digito 1 = 2 0 0 0 0 0 0 1 0 R17, Digito 2 = 5 0 0 0 0 0 1 0 1 R18, Digito 3 = 0 0 0 0 0 0 0 0 0 ;Iinstr!**iones de !so@ 0DI R1612 0DI R1<15 0DI R181) Se puede hacer clculos con estos nmeros, pero es un poco ms complicado en ensamblador que calcular con valores binarios. Las ventajas de este formato es que se pueden manejar nmeros tan grandes como se quiera, siempre y cuando haya suficiente espacio de almacenamiento. Los clculos son tan precisos como haga falta (por ejemplo, si programa el AVR para aplicaciones de banca), y se pueden convertir muy fcilmente a cadenas de caracteres. BCD empacado Si se empaquetan dos dgitos decimales en un byte no se pierde tanto espacio de almacenamiento. Este mtodo se llama empacado de dgitos en codificacin binaria. Las dos parte de un byte se llaman nibble superior e inferior. El nible superior por lo general tiene el dgito ms significativo, que conlleva ventajas para hacer los clculos (instrucciones especiales en ensamblador AVR). El nmero decimal 250 lucira as en el formato BCD empacado: @= !"te d#gito valor 8 2 1 8 2 1 2 4 y 3 02 0 0 0 0 0 0 1 0 1 2 y 1 50 0 1 0 1 0 0 0 0 ;Instr!**iones p#r# *oni$!r#r@ 0DI R1<1)?)2 ;"Dte s!perior 0DI R161)?5) ;"Dte inerior Para establecer los bits apropiados a su posicin de nibble correcta puede utilizar la notacin binaria (0b...) o la hexadecimal (0x...). Los clculos con BCD embalado son un poco ms complejos comparndolos con la forma binaria. El cambios de formato a cadenas de caracteres es casi tan fcil como con BCD y la longitud de los nmeros y la precisin de los clculos slo estn limitadas por el espacio de almacenamiento. Nmeros en formato ASC (Cdigo Estndar Americano para ntercambio de nformacin) Muy similar al formato BCD desempaquetado es almacenar nmeros en formato ASC. Los dgitos del 0 al 9 se almacenan utilizando su representacin en ASC. Este es un formato muy antiguo, desarrollado y optimizado para los teletipos, innecesariamente complicado para el uso con ordenador y muy limitado para un rango de distintos idiomas (slo 7 bits por carcter). Hoy en da todava se utiliza mucho en las comunicaciones debido a que no se ha echo un esfuerzo por parte de los progra- madores de sistemas operativos para encontrar un sistema de caracteres ms eficaz. Este antiguo sistema slo es superado por el conjunto de caracteres de teletipo europeo de 5 bits llamado Baudot o por el cdigo Morse, que todava es utilizado por algunas personas de dedos nerviosos. En el sistema de cdigo ASC el dgito 0 decimal es representado por el nmero 48 (0x30 hexadeci- mal, 0b0011.0000 binario) y el dgito 9 por el 57 (0x39 hexadecimal, 0b0011.1001 binario). ASC no fue diseado al principio para tener estos nmeros en el conjunto de cdigo ya que existen caracte- res instruccin como EOT (%nd +f Transmission$ para el teletipo. As que hay que sumar 48 a un BCD (o establecer los bits 4 y 5 a 1) para convertir un BCD a ASC. Cargar el nmero 250 a un conjunto de registros que representaran a este nmero se vera asi: 0DI R181T2T 0DI R1<1T5T 0DI R161T)T La representacin ASC de estos caracteres se escribiran en los registros. Manipulacin de bits Para convertir un nmero BCD en su representacin en ASC necesitamos establecer los bits 4 y 5 a 1. En otras palabras, necesitamos hacer una operacin OR al BCD con un valor constante 0x30 hexadecimal. En ensamblador esto se hace as: /RI R161)?;) Si tenemos un registro que ya est establecido en 0x30 hexadecimal podemos hacer el OR con este registro para convertir el BCD: /R R11R2 Traer un carcter ESC de un BCD es tambin fcil. La instruccin AFDI R161)?)F 87 aisla los 4 bits bajos (=el nibble inferior). Tenga en cuenta que OR y AND slo son posibles con registros por encima de R15, utilice los registros desde R16 a R31. Si el valor hexadecimal 0x0F ya est en el registro R2, puede hacer AND al carcter ASC con este registro: AFD R11R2 Las otras instrucciones para manipulacin de bits en un registro tambin estn limitadas para los registros por encima de R15. Se formularan de esta manera: 9:R R161)"))11)))) ;poner "its ( D 5 # !no C:R R161)"))11)))) ;poner "its ( D 5 # *ero Si uno o ms bits de un byte tienen que ser invertidos puede utilizar la siguiente instruccin (que no es vlida para usarla con una constante): 0DI R161)"1)1)1)1) ;invertir todos los "its imp#res E/R R11R16 ;en el re$istro R1 $!#rd#ndo el res!lt#do en el mismo Para invertir todos los bits de un byte (se llama complemento a uno): C/M R1 que invierte el contenido en el registro R1 y reemplaza los ceros por uno y viceversa. A diferencia de que del complemento a dos, que convierte un nmero positivo con signo a su complemento negativo (restando de cero). Esto se hace con la instruccin: FEG R1 As que +1 (decimal: 1) produce -1 (1.1111111 en binario), +2 produce -2 (1.1111110 en binario), y as sucesivamente. Adems de la manipulacin de los bits en un registro, es posible la copia de un slo bit con el denominado T-bit del registro de estado. Con :9T R11) el bit T se carga con una copia del bit 0 del registro R1. El bit T puede ser activado o desactivado y su contenido se puede copiar a cualquier bit de cualquier registro: C0T ;poner # *ero el TU"it1 o 9ET ;poner # 1 el TU"it1 o :0D R212 ;*opi#r el TU"it #l "it 2 del re$istro R2 Desplazamiento y rotacin El desplazamiento y la rotacin de nmeros binarios se hace mediante el mtodo de multiplicar y dividir por dos. El desplazamiento tiene varias sub-instrucciones. La multiplicacin por dos se realiza desplazando todos los bits de un byte una posicin a la izquierda y escribiendo un cero en el bit menos significativo. Esto se conoce como desplazamiento lgico a la izquierda o LSL (logical shift left). El antiguo bit 7 del byte se lleva al bit de acarreo del registro de estado. 090 R1 83 La divisin inversa por dos es la instruccin llamada LSR (logical shift right) desplazamiento lgico a la derecha. 09R R1 Aqu, en el antiguo bit 7, que ahora es el bit 6, se pone un cero, y el antiguo bit de la posicin 0 se lleva al bit de acarreo del registro de estado. El bit de acarreo puede ser utilizado para redondear hacia arriba y hacia abajo (Si est en 1 se suma 1 al resultado). Por ejemplo, la divisin por cuatro con redondeo: LSR R1 ;divisin por 2 BRCC Div2 ;saltar si no se redondea NC R1 ;redondear Div2: LSR R1 ;otra vez divisin por 2 BRCC DivE ;saltar si no se redondea NC R1 ;redondear DivE: As, la divisin es fcil con los binarios siempre y cuando se divida por mltiplos de 2. Si se usan enteros con signo, el desplazamiento lgico a la derecha sobreescribir el bit 7 de signo. La instruccin ASR (arithmetic shift right) desplazamiento aritmtico a la derecha, deja al bit 7 sin tocar, desplazando los 7 bits bajos e inserta un cero en el bit 6. ASR R1 Al igual que con el desplazamiento lgico, el antiguo bit 0 se lleva al bit de acarreo del registro de estado. Qu hay acerca de multiplicar por 2 una palabra de 16 bits? El bit ms significativo del byte menor se desplaza para obtener el bit ms bajo del byte mayor. En este paso se establece el bit ms bajo a cero, pero tenemos que cambiar el bit de acarreo del paso anterior del byte inferior por el bit 0 del byte superior. Esto se denomina rotacin. Durante la rotacin, el bit de acarreo del registro de estado se desplaza al bit 0 y el antiguo bit 7 se desplaza al bit de acarreo. LSL R1 ;Desplazamiento lgico a la izquierda del byte inferior ROL R2 ;Rotacin a la izquierda del byte superior (Rotate Left) La primera instruccin es el desplazamiento lgico a la izquierda que desplaza el bit 7 al bit de acarreo. La instruccin ROL rota el bit 0 del byte superior. Despus de la 2 instruccin el bit de acarreo tiene el antiguo bit 7 del byte superior, que puede ser utilizado tanto para indicar un exceso de capacidad o desbordamiento (en el caso de clculos de 16 bits) o para rotar en siguientes bytes superiores (si los clculos son de ms de 16 bits). Tambin es posible la rotacin a la derecha, dividiendo por 2 y desplazando al acarreo el bit 7 del resultado: LSR R2 ;desplazamiento lgico a la derecha, el bit 0 al acarreo ROR R1 ;Rotacin a la derecha y desplazar el bit al acarreo Como se ve es fcil dividir con nmeros grandes y el aprendizaje de ensamblador no es tan complicado. La ltima instruccin, ROR (Rotate Right), se utiliza con mucha frecuencia para desplazar cuatro bits en un solo paso con los paquetes BCDs. Esta instruccin cambia un nibble superior por el inferior y viceversa. En el ejemplo tenemos que cambiar el nibble superior a la posicin del nibble inferior. En 85 lugar de hacer ROR R1 ROR R1 ROR R1 ROR R1 se puede hacer con una sola instruccin SWAP R1 Esta instruccin intercambia el nibble superior por el nibble inferior. Tener en cuenta que el contenido del nibble superior ser diferente segn se aplique uno u otro de estos dos mtodos. Sumar, restar y comparar Sumar y restar nmeros de 16 bits Para empezar complicadamente, se van a sumar dos nmeros de 16 bits en los registros R1:R2 y R3:R4 (en esta notacin, el primer registro es el byte ms significativo y el segundo el menos significativo). ADD R2,R4 ;primero se suman los dos bytes bajos ADC R1,R3 ;a continuacin los dos bytes bajos+ En lugar de un segundo ADD usamos ADC en la segunda instruccin, que significa sumar y llevar o acarrear, que se establece o no durante la primera instruccin, en funcin del resultado. Para restar R3:R4 de R1:R2 SUB R2,R4 ;primero el byte bajo SBC R1,R3 ;despus el byte alto Otra vez el mismo truco: en la segunda instruccin restamos otro 1 si en el resultado de la primera ha habido un exceso de capacidad o desbordamiento. Comparar nmeros de 16 bits Ahora comparamos la palabra de 16 bits en R1:R2 con la que hay en R3:R4 para evaluar si es ms grande. En lugar de SUB utilizamos la instruccin de comparacin CP y en lugar de SBC utilizamos CPC: CP R2,R4 ;compara los bytes bajos CPC R1,R3 ;compara los bytes altos Si ahora se establece o pone a 1 la bandera de acarreo R1:R2 es ms pequeo que R3:R4. Comparar con constantes Ahora se compara el contenido del registro R16 con una constante: 0b10101010. CP R16,0xAA Si despus de esta operacin el bit Zero del registro de estado se establece en 1, el registro R16 es igual a 0xAA. Si se establece el bit de acarreo, como ya sabemos, es que es ms pequeo. Si no se ha establecido ninguno de estos dos bits en el registro de estado, es que es ms grande. 8@ Para comprobar si por ejemplo R1 es cero o negativo TST R1 Si se establece en 1 el Z-bit, el registro R1 es cero y podemos seguir con las instrucciones BREQ, BRNE, BRM, BRPL, BRLO, BRSH, BRGE, BRLT, BRVC o BRVS de ramificacin alrededor de un pequeo bit. Matemticas con paquetes BCD Ahora algunos clculos con paquetes BCD. La suma de dos paquetes BCD puede dar lugar a dos desbordamientos distintos. El acarreo habitual muestra un exceso de capacidad, si el nibble mayor es ms de 15 decimal. El otro desbordamiento se produce del nibble inferior al superior, si al sumar dos nibbles bajos da ms de 15 decimal. Por ejemplo, podemos sumar 2 BCDs empacados como 49 (=hex 49) y 99 (=hex 99) para producir 148 (=hex 148). Esta suma en clculo binario da como resultado un byte con un valor hexadecimal de 0xE2, sin producirse desbordamiento del byte. Pero en el nibble inferior si se produce desbordamiento porque 9+9=18 y el nibble inferior solo puede manejar nmeros hasta 15. El desbordamiento se aade al bit 4, el bit menos significativo del nibble superior, que es correcto, pero el nibble inferior debe estar en 8 y est a slo 2 (18 = 0b0001.0010). Hay que sumar 6 a dicho nibble para obtener el resultado correcto. Esto es lgico porque cada vez que el nibble inferior alcanza ms de 9 hay que sumarle 6 para corregirle. El nibble superior es totalmente incorrecto, porque es 0xE y debe ser de 3 (con un desbordamiento en el siguiente dgito superior del BCD empacado). Si sumamos 6 a 0xE obtenemos 0x4 y se esta- blece el acarreo (=0x14). As que el truco est en primero sumar estos dos nmeros y a continuacin aadir 0x66 para corregir los 2 dgitos del BCD empacado. Pero un momento, y si la suma del primer y segundo nmero no da lugar a un desbordamiento del siguiente nibble, es decir no da una cifra superior a 9 en el nibble inferior? Aadir 0x66 producira entonces un resultado totalmente incorrecto. Solamente se le aade 6 al nibble inferior si este se desborda al nibble superior por una cifra superior a 9. Lo mismo con el nibble superior. Cmo sabemos si se produce un desbordamiento del nibble inferior al superior? El MCU establece a 1 el bit H en el registro de estado, que es el bit de acarreo a la mitad. A continuacin se muestra el algo- ritmo para los diferentes casos posibles despus de sumar dos nibbles y despus de sumar 0x6 hex. 1. Sumar los nibbles. Si ocurre un desbordamiento (C para el nibble superior o H para el nibble inferior) sumar 6 para corregir, sino, hacer el paso 2. 2. Sumar 6 al nibble. Si ocurre un desbordamiento (C resp. H) ya est hecho. Si no, restar 6. Para programar un ejemplo, supongamos que tenemos 2 BCDs empacados en R2 y R3, R1 realizar el desbordamiento y R16 y R17 estn disponibles para los clculos. R16 es el registro de la adicin pa- ra sumar 0x66 (con el registro R2 no se puede sumar un valor constante) y R17 se utiliza para corregir el resultado en funcin de las correspondientes banderas. La suma de R2 y R3 se podra ver as: 0DI R161)?66 ;p#r# s!m#r )?66 #l res!lt#do 0DI R1<1)?66 ;p#r# l!e$o rest#r del res!lt#do ADD R21R; ;sumar los dos digitos BCDs :RCC FoCD1 ;saltar a NoCy1 si no se produce desbordamiento de byte IFC R1 ;incrementar el siguiente byte superior AFDI R1<1)?)F ;no rest#r 6 #l ni""le #lto FoCD1@ :R4C Fo4*1 ;ir si no ha ocurrido un acarreo a la mitad AFDI R1<1)?F) ;no rest#r 6 del ni""le "#Jo Fo4*1@ 88 ADD R21R16 ;sumar 0x66 al resultado :RCC FoCD2 ;ir si no a habido acarreo IFC R1 ;incrementar el siguiente byte superior AFDI R1<1)?)F ;no rest#r 6 del ni""le #lto FoCD2@ :R4C Fo4*2 ;ir si no ha ocurrido un acarreo a la mitad AFDI R1<1)?F) ;no restar 6 del nibble bajo Fo4*2@ 9&: R21R1< ;rest#r l# *orre**i+n Un poco ms corto: ADD R21R16 ADD R21R; :RCC FoCD IFC R1 AFDI R161)?)F FoCD@ :R4C Fo4* AFDI R161)?F) Fo4*@ 9&: R21R16 Pregunta para pensar: Por qu es igualmente correcto, la mitad de corto y menos complicado, y dnde est el truco? Conversin de formato de nmeros Cualquier formato numrico se puede convertir a cualquier otro formato. Ya se vi anteriormente la conversin de BCD a ASC (manipulacin de bits). Ahora veremos otras. Conversin de BCD empacado a BCD, ASC o Binario La conversin de paquetes BCD no es complicada. Primero tenemos que copiar el nmero a otro registro. Al valor copiado le intercambiamos los nibbles con la instruccin SWAP. La parte superior se despeja a cero por ejemplo hacindole una operacin AND con 0x0F y nos queda el nibble el antiguo nibble superior que se puede utilizar tal cual (BCD) o estableciendo el bit 4 y 5 a 1 para convertirlo al juego de caracteres ASC. Despus volvemos a copiar el byte y tratamos con el nibble inferior sin hacerle intercambio como antes y obtenemos el BCD inferior. La conversin de dgitos BCD a binario es ms complicada. Dependiendo de los nmeros que se ma- nejen, primero hay que despejar a cero los bytes necesarios para hacer la conversin. A continuacin comenzamos con los dgitos BCD ms altos que hay que multiplicarlos por 10. Con el fin de hacer esta multiplicacin, hay que copiar el resultado en otro lugar. A continuacin se multiplica el resultado por 4 (dos desplazamientos a la izquierda). Sumando el nmero copiado anteriormente a esto produce una multiplicacin por 5. Ahora, una multiplicacin por 2 (un desplazamiento a la izquierda) produce el re- sultado multiplicado por 10. Por ltimo se aade el BCD y se repite el algoritmo hasta que se han con- vertido todos los dgitos decimales. Si durante una de estas operaciones se produce un acarreo del re- sultado, el BCD es demasiado grande para ser convertido, por lo que este algoritmo maneja nmeros de cualquier longitud, siempre y cuando estn preparados los registros para los resultados. [Conversin de un nmero decimal de 5 digitos en BCD a binario natural de 16 bits. ;El mximo nmero a convertir ser pues el b'1111111111111111'=0xFFFF=d'65535' ; El metodo usado para la conversin de un nmero BCD a binario natural, se basa en que cada dgito de un nmero codifcado en BCD tiene un peso igual a la potencia de diez asociada a su posicin. ara convertir el nmero BCD a su equivalente binario slo es necesario multiplicar cada dgito BCD por su peso correspondiente ! luego sumar todos los productos parciales obtenidos, el resultado es el nmero binario natural buscado. 89 ; Es decir el valor de un nmero B! de 5 d"#itos se puede expresar como$ ; 10%& !ecenas'illar ( 10%3 'illares ( 10%) entenas ( 10 !ecenas ( *nidades = 10+10+10+10 !ecenas'illar ( 10+10+10 'illares ( 10+10 entenas ( 10 !ecenas ( *nidades ; ; Finalmente una subrutina aplica el si#uiente al#oritmo$ 10,10,10,10 !ecenas'illar ( 'illares- ( entenas- ( !ecenas- ( *nidades = .esultado ; ; El resultado se obtiene en 16 bits/ es decir en ) re#istros de 0 bits1] Conversin de binario a BCD La conversin de binario a BCD es menos complicado. Para convertir 16 bits en binario restamos 10.000 (0x2710) hasta que se produce un desbordamiento, dando el primer dgito. A continuacin repetimos con 1.000 (0x03E8) dando el segundo dgito y as sucesivamente con 100 (0x0064), 10 (0x000A) y el resto es el ltimo dgito. Las constantes 10.000, 1.000, 100 y 10 se pueden almacenar en palabras en la memoria de programa y organizadas en una tabla: DezTab: .DW 10000, 1000, 100, 10 y as pueden ser ledas de la tabla por palabra con la instruccin LPM. Una alternativa es una tabla que contenga el valor decimal de cada bit en 16 bits binarios: .DB 0,3,2,7,6,8 .DB 0,1,6,3,8,4 .DB 0,0,8,1,9,2 .DB 0,0,4,0,9,6 .DB 0,0,2,0,4,8 ;y as sucesivamente hasta .DB 0,0,0,0,0,1 A continuacin se cambian los bits individuales en binario desplazando hacia el registro de la izquierda el acarreo. Si es un uno, se suma al nmero de la tabla resultado de la instruccin LPM. Esto es ms complicado de programar y un poco ms lento. Un tercer mtodo consiste en calcular el valor de la tabla partiendo de 000001, mediante la suma del BCD consigo mismo, cada vez despus de haber cambiado a la derecha un bit al binario y sumndole el resultado BCD. Hay varios mtodos y hay que aplicar el ms optimo. Multiplicacin Para multiplicar 2 binarios de 8 bits, se puede hacer como con nmeros decimales: 1234 * 567 = ? -------------------------------------------- 1234 * 7 = 8638 + 1234 * 60 = 74040 + 1234 * 500 = 617000 -------------------------------------------- 1234 * 567 = 699678 ========================= 84 Estos son los pasos del ejemplo: Se multiplica el primer nmero por la cifra menos significativa del segundo nmero. Se vuelve a multiplicar el primer nmero por 10 y por el siguiente dgito significativo del segundo nmero y se suma el resultado al anterior. Y se vuelve a multiplicar el primer nmero por 100 y por el siguiente dgito (ahora el ms significativo) del segundo nmero y se suma el resultado al anterior obtenindose el resultado final. Multiplicacin binaria Ahora en binario. La multiplicacin por 10 en decimal lleva a la multiplicacin por 2 en binario. Esta multiplicacin se hace facilmente ya sea por la suma de la cantidad a si misma o bien por el despla- zamiento de todos los bits una posicin a la izquierda y aadiendo un cero a la derecha. Programa en ensamblador AVR En el cdigo fuente siguiente se muestra la multiplicacin en ensamblador. ; M!lt8.#sm m!ltipli*# 2 nLmeros de 8 "its prod!*iendo !n res!lt#do de 16 "its ; .F/0I9T .IFC0&DE =C@M#vrtoolsM#ppnotesM8515de.in*= .0I9T ; ; Fl!Jo de l# m!ltipli*#*i+n ; ; 1.0os "in#rios m!ltipli*#dos se despl#E#n "it # "it en el "it de #*#rreo. 9i es !n !no se s!m# #l res!lt#do D ; si no es !no *#m"i# de posi*i+n D no se s!m# ; 2.El nLmero "in#rio se m!ltipli*# por 2 D se despl#E# !n# posi*i+n # l# iE'!ierd# poniendo !n *ero en l# ; posi*i+n dere*># '!e '!ed# v#*B#. ; ;.9i el "in#rio # m!ltipli*#r no es *ero1 se repite el *i*lo. ; ; Registros usados ; .DEF rm1 = R) ; el nLmero "in#rio # m!ltipli*#r 58 :it7 .DEF rm> = R1 ; almacenamiento temporal .DEF rm2 = R2 ; el nLmero "in#rio *on el '!e se v# # m!ltipli*#r 58 :it7 .DEF rel = R; ; Res!lt#do 09: 516 :it7 .DEF re> = R( ; Res!lt#do1 M9: .DEF rmp = R16 ; Re$istro m!ltiprop+sito p#r# l# *#r$# ; .C9EG ./RG )))) ; rJmp 9TART ; 9TART@ ldi rmp1)?AA ; eJemplo "in#rio 1)1).1)1) mov rm11rmp ; ten el primer re$istro ldi rmp1)?55 ; eJemplo "in#rio )1)1.)1)1 mov rm21rmp ; en el segundo registro ; ; Aqu empieza la multiplicacin de los dos binarios en rm1 y rm2, el resultado ir a reh:rel (16 bits) ; M&0T8@ ; ; V#lores de ini*io despeJ#dos # *ero *lr rm> ; almacenamiento temporal despejado *lr rel ; registros de resultados despejados *lr re> 8? ; ; Aqu comienza el ciclo de multiplicacin ; M&0T8#@ ; ; .#so 1@ se rot# el "it mQs "#Jo del se$!ndo nLmero "in#rio # l# "#nder# de #*#rreo 5se divide por 2 D se rot# ; !n *ero #l "it <7 ; *l* ; a cero el bit de acarreo ror rm2 ; bit 0 al acarreo, bits 1 a 7 una posicin a la derecha, el valor en el acarreo al bit 7 ; ; .#so 2@ :i!r*#*i+n dependiendo si es !n *ero o !n !no lo '!e se ># rot#do #l "it de #*#rreo ; "r** M&0T8" ; saltar la suma si el acarreo es cero ; ; .#so ;@ 9!m#r los 16 "its en rm>@rml #l res!lt#do *on el des"ord#miento desde el 09: #l M9: ; #dd rel1rm1 ; sumar el LSB de rm1 al resultado #d* re>1rm> ; sumar el acarreo y el MSB a rm1 ; M&0T8"@ ; ; .#so (@ M!ltipli*#r rm>@rm1 por 2 516 "its1 despl#E#miento # l# iE'!ierd#7 ; *l* ; # *ero el "it de #*#rreo rol rm1 ; rot#r 09: # l# iE'!ierd# 5m!ltipli*#r por 27 rol rm> ; desplazar el MSB una posicin a la izquierda y llevar el acarreo ; ; .#so 5@ Compro"#r si tod#vB# >#D !nos en el se$!ndo nLmero "in#rio D si los >#D1 # m!ltipli*#r ; tst rm2 ; VTodos los "its # *eroW "rne M&0T8# ; si no, seguir en el bucle ; ; Fin#liE#*i+n del# m!ltipli*#*i+n1 res!lt#do en re>@rel ; ; "!*le sin in ; 0//.@ rJmp loop Rotacin binaria Para entender la operacin de multiplica- cin, es necesario comprender las instruc- ciones de rotacin binaria ROL y ROR. Estas instrucciones desplazan todos los bits de un registro una posicin a la izquierda (ROL) o a la derecha (ROR). La posicin que queda vaca se llena con el contenido del bit de acarreo del registro de estado y el bit que sale del registro se desplaza al bit de acarreo. Esta operacin se demuestra utilizando 0xAA como ejemplo para ROL, y 0x55 como ejemplo para ROR. Hardware de multiplicacin Todos los ATmega, ATXmega, AT90CAN y AT90PWM incluyen un multiplicador de hardware que puede llevar a cabo multiplicaciones de 8 bits en slo dos ciclos de reloj. As que cuando haya que hacer multiplicaciones y el software no necesite ejecutarse en chips AT90S -o ATtiny-, se puede 8: utilizar esta caracterstica de hardware. A continuacin se muestra cmo multiplicar binarios 8 por 8 " 16 por 8 " 16 por 16 " 16 por 24 Multiplicacin por hardware de binarios 8 por 8 Se hace de forma simple y directa: Si los dos binarios que se van a mul- tiplicar estn en los registros R16 y R17 slo hay que poner mul R16,R17
El resultado de la multiplicacin de es- tos dos binarios de 8 bits pude ser de hasta 16 bits de longitud, por lo que el resultado se escribir en los registros R1 (byte ms significativo) y R0 (byte menos significativo). Esto es todo. El programa muestra la simulacin en el software Studio. Se multiplica el decimal 250 (hex FA) por el decimal 100 (hex 64), en los registros R16 y R17. Despus de la ejecucin, los registros R0 (LSB) y R1 (MSB) contienen el nmero 61A8 hex. o 25.000 decimal. Y si. Slo requiere dos ciclos, o 2 microsegundos con un reloj a 1 Mcs/s. Multiplicacin por hard- ware de binarios 16 por 8 Hay que multiplicar un binario ms grande? El hardware est limitado a 8, por lo que tenemos que emplear algunas buenas ideas. Para resolver el problema con binarios mayores vamos a ver en primer lugar la combinacin de 16 y 8. La comprensin de este concepto ayuda a entender el mtodo por el que ser capaz de resolver ms tarde el problema de la multiplicacin de 32 por 64 bits. Primero las matemticas: un binario de 16 bits m1M:m1L es simplemente dos binarios de 8 bits m1M y m1L, donde el byte ms significativo m1M es multiplicado por 256 decimal o por 100 hex. Recordemos por ejemplo que el decimal 1234 es simplemente (12 multiplicado por 100) ms 34, o )1 multiplicado por mil) ms (2 multiplicado por 100) ms (3 multiplicado por 10) y ms 4. 8= As que el binario de 16 bits m1 es igual a 256*m1M ms m1L, donde miM es el MSB y m1L es el LSB. Multiplicar m1 por un binario de 8 bits m2 es formulado matemticamente: - m1 * m2 = (256*m1M + m1L) * m2, - 256*m1M*m2 + m1L*m2. As que slo tenemos que hacer dos multiplicaciones y sumar ambos resultados. Si ves tres asteriscos en la frmula, se siente: la multiplicacin por 256 en el mundo binario no requiere ningn hardware en absoluto, porque es un simple movimiento en el byte de orden superior. Al igual que la multiplicacin en el mundo decimal se hace simplemente moviendo el primer nmero a la izquierda y escribiendo un cero como dgito menos significativo. Vamos a un ejemplo prctico. Primero necesitamos algunos registros para Cargar los nmeros m1 y m2, proporcionar espacio para el resultado que podra tener 24 bits de longitud. ; ; .r!e"# de m!ltipli*#*i+n por >#rdR#re 16 por 8 "its ; ; Deini*i+n de los re$istros@ ; .de Res1 = R2 .de Res2 = R; .de Res; = R( .de m10 = R16 .de m1M = R1< .de m2 = R18 Primero cargamos los nmeros: ; ; C#r$#ndo los re$istros ; .e'! m1 = 1)))) ; ldi m1M14IG45m17 ;8 "its #ltos de m1 en m14 ldi m1010/85m17 ;8 "its "#Jos de m1 en m10 ldi m2125) ;*onst#nte de 8 "its en m2 Los dos nmeros se cargan en R17:R16 (10000 decimal = 2710 hex) y R18 (250 dec = FA hex). A continuacin, primero se multiplica el LSB: ; ; M!ltipli*#ndo ; m!l m101m2 ;m!ltipli*#ndo el 09: mov Res11R) ;copiando el resultado al registro de resultado mov Res21R1 97 La multiplicacin del LSB, 10 hex por FA hex produce 0FA0 hex, que se escribe en los registros R0 (LSB A0 hex) y R1 (MSB 0F hex). El resultado se copia en los bytes inferiores del registro de resultado, R3:R2. Multiplicacin del MSB de m1 por m2: m!l m1M1m2 ;m!ltipli*#ndo el M9: La multiplicacin del MSB de m1, 27 hex, por m2, FA hex, produce 2616 hex en R1:R0 Ahora se realizan dos pasos a la vez, la multiplicacin por 256 y sumar el resultado con el anterior. Esto se hace mediante la suma de R1:R0 a Res3:Res2 en lugar de a Res2:Res1. R1 slo se puede copiar a Res3 y entonces R0 se suma Res2. Si se establece el acarreo despus de la suma, el siguiente byte alto Res3 se incrementa en uno. mov Res;1R1 ;*opi# el M9: #l res!lt#do del "Dte ; #dd Res21R) ;D s!m#r el 09: #l res!lt#do del "Dte 2 "r** FoIn* ;si no >#D #*#rreo1 s#lt#r in* Res; FoIn*@ El resultado en R4:R3:R2 es 2625A0 hex, 2500000 en decimal, lo que es obviamente correcto. Adems, estas operaciones consumen 10 ciclos que con un reloj de 1 Mhz son 10 microsegundos. Mucho ms rpido que la multiplicacin por software. Multiplicacin por hardware de binarios 16 por 16 Ahora que tenemos claros los principios, debera ser fcil hacer 16 por 16. El resultado ahora requiere 4 bytes (Res4:Res3:Res2:Res1, ubicados en R5:R4:R3:R2). La frmula sera: m ; m<=(<>?;m# @ m-$ ; (<>?;m<# @ m<-$ =?>>A?;m#;m<# @ <>?;m#;m<- @ <>?;m-;m<# @ m-;m<- Obviamente ahora hay que hacer 4 multiplicaciones. Comenzamos con la primera y la ltima que son las ms sencillas: sus resultados simplemente se copian en las posiciones correctas de los respectivos registros de resul- tado. Los resultados de las multiplica- ciones de en medio se aadirn a los 93 registros de resultado tambin de en medio llevndonos los posibles acarreos al byte ms significa- tivo. Para esto hay un simple truco fcil de entender: ; ; .r!e"# de m!ltipli*#*i+n >#rdR#re 16 por 16 ; ; Deini*i+n de re$istros ; .de Res1 = R2 .de Res2 = R; .de Res; = R( .de Res( = R5 .de m10 = R16 .de m1M = R1< .de m20 = R18 .de m2M = R1- .de tmp = R2) ; ; Cargar valores de entrada ; .e'! m1 = 1)))) .e'! m2 = 25))) ; ldi m1M14IG45m17 ldi m1010/85m17 ldi m2M14IG45m27 ldi m2010/85m27 ; ; M!ltipli*#ndo ; *lr R2) ;DespeJ#r p#r# #*#rreo m!l m1M1m2M ;M!ltipli*#r M9:s mov Res;1R) ;*opD to M98 Res!lt mov Res(1R1 m!l m101m20 ;M!ltipli*#r 09:s mov Res11R) ;*opD to 098 Res!lt mov Res21R1 m!l m1M1m20 ;M!ltipli*#r 1M *on 20 #dd Res21R) ;9!m#r #l res!lt#do #d* Res;1R1 #d* Res(1tmp ;s!m#r #*#rreo m!l m101m2M ;M!ltipli*#r 10 *on 2M #dd Res21R) ;9!m#r #l res!lt#do #d* Res;1R1 #d* Res(1tmp ; ; M!ltipli*#*i+n >e*># ; La simulacin muestra los siguientes pasos: La carga de dos constantes 10000 (2710 hex) y 25000 (61A8 hex) en los registros del espacio superior de registros... Multiplicacin de los dos MSBs (27 y 61 hex) y copia del resultado a los registros R1:R0 desde los registros de resultado superior R5:R4... 95 Multiplicacin de los dos LSBs (10 y A8 hex) y copia del resultado en R1:R0 desde los registros de resultado inferior R3:R2... Multiplicacin del MSB de m1 con el LSB de m2 y suma del resultado en R1:R0 de los registros de resultado de los bytes del medio. No hay acarreo... Multiplicacin del LSB de m1 con el MSB de m2 y suma del resultado en R1:R0 de los registros de resultado de los bytes del medio. No hay acarreo. El resultado es 0EE6B280 hex, 250000000 decimal, obviamente correcto. Para esta multiplicacin son necesarios 19 ciclos de reloj, que es mucho ms rpido que el software de multiplicacin. Tambin: el tiempo requerido ser siempre de exactamente 19 ciclos y no depende de los n- meros de entrada, como pasa con la multiplica- cin por software que produce acarreo, en la que hay que aadir un cero. Multiplicacin por hardware de binarios 16 por 24 La multiplicacin de un binario de 16 bits 'a' con un binario de 24 bits 'b' produce resultados con una longitud de hasta 40 bits. El esquema de multiplica- cin requiere seis multiplica- ciones de 8 por 8 bits suman- do los resultados en la posi- cin apropiada de los registros de resultados. Cdigo fuente en ensamblador: ; M!ltipli*#*i+n >#rdR#re 16 por 2( .in*l!de =m8de.in*= ; ; Deini*i+n de re$istros .de #1 = R2 ; deine 16U"it re$ister .de #2 = R; .de "1 = R( ; deine 2(U"it re$ister .de "2 = R5 .de "; = R6 .de e1 = R< ; deine ()U"it res!lt re$ister .de e2 = R8 .de e; = R- .de e( = R1) .de e5 = R11 .de *) = R12 ; re$istro de #D!d# p#r# s!m#r .de rl = R16 ; re$istro de *#r$# ; 9@ ; C#r$# de *onst#ntes .e'! # = 1)))) ; m!ltipli*#dor #1 >e? 2<1) .e'! " = 1)))))) ; m!ltipli*#dor "1 >e? )F(2() ldi rl1:HTE15#7 ; *#r$# de # mov #11rl ldi rl1:HTE25#7 mov #21rl ldi rl1:HTE15"7 ; *#r$# de " mov "11rl ldi rl1:HTE25"7 mov "21rl ldi rl1:HTE;5"7 mov ";1rl ; ; DespeJ#r re$istros *lr e1 ; DespeJ#ndo re$istros de res!lt#dos *lr e2 *lr e; *lr e( *lr e5 *lr *) ; DespeJ#ndo re$istro de #D!d# ; ; M!ltipli*#*i+n m!l #21"; ; tXrmino 1 #dd e(1R) ; s!#mndo #l res!lt#do #d* e51R1 m!l #21"2 ; tXrmino 2 #dd e;1R) #d* e(1R1 #d* e51*) ; 5s!m#ndo posi"le #*#rreo7 m!l #21"1 ; tXrmino ; #dd e21R) #d* e;1R1 #d* e(1*) #d* e51*) m!l #11"; ; tXrmino ( #dd e;1R) #d* e(1R1 #d* e51*) m!l #11"2 ; tXrmino 5 #dd e21R) #d* e;1R1 #d* e(1*) #d* e51*) m!l #11"1 ; tXrmino 6 #dd e11R) #d* e21R1 #d* e;1*) #d* e(1*) #d* e51*) ; ; >e*>o. nop ; El res!lt#do de"e ser )25():E()) >e? La ejecucin completa requiere 10 ciclos de reloj para la carga de las constantes, 6 ciclos de reloj para despejar (poner a cero) los registros y 98 33 ciclos de reloj para la multiplicacin. Divisin No, desafortunadamente no existe divisin por hardware, hay que hacerlo por software. Divisin decimal Comenzamos con la divisin decimal para comprender mejor la divisin binaria. Se parte de dividir por ejemplo, 5678 entre 12: 5678 : 12 = ? ----------------------------------- - 4 * 1200 = 4800 -------- 878 - 7 * 120 = 840 ------ 38 - 3 * 12 = 36 ---- 2 Resultado 5678 : 12 = 473 con Resto 2 ================================ Divisin Binaria En binario, la multiplicacin del segundo nmero como en el ejemplo decimal anterior no es necesa- ria debido al hecho de que slo tenemos 0 y 1 como dgitos. Los nmeros binarios tienen mucha ms cantidad de dgitos que su equivalente decimal, por lo que la transferencia de la divisin decimal a su equivalente binaria es un poco inconveniente. As que el programa funciona de una manera diferente. La divisin de un nmero binario de 16 bits entre un binario de 8 bits en ensamblador AVR se muestra en el siguiente cdigo: ; Div8 divide !n nLmero de 16 "its entre !n nLmero de 8 "its 5.r!e"#@ 16U"itUn!m"er@ )?AAAA1 8U"itUn!m"er@ ; ; )?557 .F/0I9T .IFC0&DE =C@M#vrtoolsM#ppnotesM8515de.in*= ; ajuste la ruta correcta en su sistema! .0I9T ; Re$istro .DEF rd1l = R) ; 09: del nLmero de 16 "its '!e se divide .DEF rd1> = R1 ; M9: del nLmero de 16 "its '!e se divide .DEF rd1! = R2 ; registro provisional .DEF rd2 = R; ; n!mero de 8 "its por el '!e se divide .DEF rel = R( ; 09: res!ltado .DEF re> = R5 ; M9: res!ltado .DEF rmp = R16; registro multiproposito para carga ; .C9EG ./RG ) rJmp st#rt st#rt@ ; C#r$#r los nLmeros en los re$istros #propi#dos ldi rmp1)?AA ; )?AAAA a dividir mov rd1>1rmp mov rd1l1rmp 99 ldi rmp1)?55 ; )?55 por el que se divide mov rd21rmp ; Divide rd1>@rd1l "D rd2 div8@ *lr rd1! ; despejar registro provisional *lr re> ; 5los re$istros de res!lt#do *lr rel ; tambin se utilizan para contar hasta 16 para los pasos de la divisin in* rel ; se est#"le*e en 1 en el #rr#n'!e7 ; Aqu comienza el ciclo de la divisin div8#@ *l* ; despejar el bit de acarreo rol rd1l ; rotar el bit superior siguiente del nmero rol rd1> ; al registro provisional (se multiplica por 2) rol rd1! "r*s div8" ; se llev# !n !no # l# iE'!ierd#1 por lo '!e se rest# *p rd1!1rd2 ; resultado de la divisin 1 0? "r*s div8* ; s#lt#r l# rest# si es menor div8"@ s!" rd1!1rd2; rest#r el nLmero por el '!e se divide se* ; est#"le*er el "it de #*#rreo1 el res!lt#do es !n 1 rJmp div8d ; s#lt#r #l *#m"io del "it de res!lt#do div8*@ *l* ; despeJ#r el "it de #*#rreo1 el "it res!lt#nte es !n ) div8d@ rol rel ; rot#r el "it de #*#rreo # los re$istros de res!lt#do rol re> "r** div8# ; mientr#s se# *ero se$!ir *on el *i*lo de divisi+n ; Fin de l# divisi+n stop@ rJmp stop ; "!*le sin in Pasos del programa durante la divisin Definicin y seleccin de los registros para los nmeros binarios de la divisin Preajuste del registro provisional y el par de registros de resultado (los registros de resultado son preseleccionados en 0x0001). El binario de 16 bits en rd1h:rd1l se rota bit a bit al registro provisional rd1u (multiplicacin por 2) si se rota un 1 a rd1u, el programa bifurca al paso 4 de la resta inmediatamente, el contenido del registro provisional se compara con el nmero de 8 bits en rd2, si este es ms pequeo se resta del registro provisional y el bit de acarreo se establece a 1. Si rd2 es mayor, no se hace la resta y el bit de acarreo se establece a 0, el contenido de la bandera de acarreo se rota al registro de resultado reh:rel a la derecha, si es un cero se rota fuera del registro de resultado y se repite el bucle de la divisin. Si es un 1 se ha completado la divisin. Si no se entiende la rotacin, esta operacin est expuesta en la seccin de la multiplicacin. Conversin de nmeros En ensamblador es muy frecuente la conversin de nmeros porque en los procesadores el clculo se hace en binario mientras que las personas en un terminal prefieren nmeros decimales. Para que haya comunicacin desde el interior de una rutina en ensamblador con una persona, es necesaria la conversin de nmeros. Hay que aprender un poco como se realiza la conversin entre diferentes sistemas numricos. Por favor consulte el sitio web en http://www.avr-asm-tutorial.net/avr_en/calc/CONVERSON.html si usted necesita el cdigo fuente o una mejor comprensin. Las fracciones decimales 94 Primero, no utilice punto flotante a menos que no quede ms remedio. El punto flotante deja sin recursos al AVR y necesita un tiempo de ejecucin extremo. Si se encuentra en este dilema y piensa que ensamblador es demasiado complicado puede preferir basic u otros lenguajes como C o Pascal. Pero si no es as y prefiere utilizar ensamblador, aqu se muestra como realizar la multiplicacin con nmeros reales de punto fijo en menos de 60 microsegundos e incluso, en casos especiales en 18 microsegundos, a 4 MHz de frecuencia de reloj, sin necesidad de trucos caros como extensiones de procesador de punto flotante. Esto se hace volviendo a las races de las matemticas. La mayora de las tareas con nmeros reales de coma flotante se pueden hacer utilizando nmeros enteros. Con stos, es fcil y rpido programar en ensamblador. El punto flotante se queda en el cerebro del programador y se aade en algn lugar de la secuencia de dgitos decimales. Nadie se da cuenta y este es el truco. Conversiones lineales A modo de ejemplo: un convertidor AD de 8 bits toma muestras de una seal de entrada en el rango desde 0,00 a 2,55 voltios y devuelve el resultado en sistema binario en el rango desde $00 a $FF. El resultado, una tensin, se muestra en una pantalla LCD. Es un ejemplo muy fcil: el binario se convierte a una cadena decimal ASC entre 000 y 255, y hay que insertar la coma decimal justo detrs del primer dgito y ya est! Pero el mundo de la electrnica es a veces ms complicado. Por ejemplo, el convertidor AD devuelve un hexadecimal de 8 bits para la tensin de entrada de entre 0,00 y 5,00 voltios. Ahora nos quedamos confusos y no sabemos como proceder. Para mostrar el resultado correcto en la pantalla LCD, tendramos que multiplicar el binario por el resultado de la divisin 500/255, que es 1,9608. Este es un nmero tonto ya que es casi 2, pero slo casi, y no queremos esta inexactitud de un 2% mientras que tenemos un convertidor AD con un margen de error en torno a 0,25%. Para afrontar esto, se multiplica la entrada por el resultado de 500 / 255 * 256, que es 501,96, y luego se divide por 256. Por qu primero se multiplica por 256 y luego se vuelve a dividir por 256? Para una mayor precisin. Si multiplicamos la entrada por 502 en lugar de por 501,96, el error es del orden del 0,008%, suficiente para nuestro convertidor AD, podemos vivir con eso. Y dividir por 256 es una tarea fcil, porque es una potencia muy conocida de 2. Al dividir con nmeros que son potencia de 2, el AVR se encuentra cmodo y funciona muy rpido. Al dividir entre 256, el AVR es incluso ms rpido, porque slo tenemos que quitar el ltimo byte del nmero binario, ni siquiera hay desplazamiento o rotacin. La multiplicacin de un binario de 8 bits con el binario de 9 bits 502 (1F6 hex) puede tener un resultado superior a 16 bits, as que tenemos que reservar 24 bits o 3 registros para el mismo. Durante la multiplicacin, la constante 502 se ha de desplazar a la izquierda (multiplicacin por 2) para aadir estas cifras con el resultado y se hace un desplazamiento cada vez que cambia el nmero de entrada. Como esto puede necesitar hasta 8 desplazamientos a la izquierda, necesitamos otros tres bytes para esta constante. As que podemos optar por la siguiente combinacin de registros para la multiplicacin: N$mero Valor%e&emplo' (egistro Valor de entrada 255 R1 multiplicando 502 R4:R3:R2 resultado 128,010 R7:R6:R5 Despus de colocar el valor 502 (00.01.F6) en los registros R4:R3:R2 y despejar los registros de resultado R7:R6:R5, la multiplicacin es la siguiente: 1. Test, si el nmero de entrada es cero, hemos terminado. 9? 2. Si no, en el nmero de entrada se desplaza a la derecha un bit, que se lleva al acarreo y se coloca un cero en el bit 7. Esta instruccin se llama Logical-Shift-Right o LSR. 3. Si el bit de acarreo es 1, le sumamos el multiplicando (en el paso 1 el valor es 502, en el paso2 es 1004 y as sucesivamente) al resultado. Durante la suma no hay que olvidarse del acarreo, (la suma de R2 a R5 con ADD, la suma de R3 a R6 y R4 a R7 con ADC). Si elbir de acarreo es un cero, no se hace la suma del multiplicando con el resultado y se pasa el siguiente paso. 4. Ahora el multiplicando se multiplica por 2, ya que el siguiente bit desplazado con respecto al nmero de entrada vale tanto como el doble. Se desplaza R2 a la izquierda (mediante la insercin de un cero en el bit 0) con LSL y el bit 7 se desplaza al acarreo. A continuacin se rota el acarreo a R3, desplazando su contenido a la izquierda y el bit 7 al acarreo. Lo mismo con R4. 5. As terminamos con un dgito del nmero de entrada y se procede con el paso 1 de nuevo. El resultado de la multiplicacin por 502 ahora est en los registros de resultado R7:R6:R5. Si nos limitamos a pasar por alto el registro R5 (divisin por 256), ya tenemos el resultado deseado. Para mejorar la precisin, podemos usar el bit 7 de R5 para redondear el resultado. Ahora slo tenemos que convertir el resultado de su forma binaria a decimal ASC. Si aadimos el punto decimal en el lugar correcto de la cadena ASC, tenemos una cadena con el voltaje lista para ser mostrada en el display. El programa completo, desde el nmero de entrada hasta la cadena ASC resultante, requiere entre 79 y 288 ciclos de reloj, dependiendo del nmero de entrada. Una rutina de punto flotante como sta en un lenguaje ms sofisticado que ensamblador, conlleva ms tiempo de conversin, ms programa flash y ms uso de memoria. Ejemplo 1: Convertidor AD de 8 bits con punto flotante ; Demostracin de conversin de punto flotante en ensamblador, (C) 2003 www.avr-ASM-tutorial.net ; La tarea: Se lee un resultado de 8 bits de un convertidor analgico-digital en un rango que va desde 00 a FF ;hexadecimal y hay que convertirlo en un nmero de punto flotante en el rango de 0,00 a 5,00 voltios. ;Esquema del programa: ;1. Multiplicacin por 502 (01F6 hex). Se multiplica por 500 y por 256 y se divide por 255 en un slo paso. ;2. Redondear el resultado y omitir el ltimo byte (esto ltimo divide por 256). Antes de omitir el ltimo byte ;hay que coger el bit 7 para el redondeo. ;3. Convertir la palabra resultante a ASC y establecer el signo decimal en el lugar correcto. La palabra ;resultante en el rango de 0 a 500 se muestra en caracteres ASC como 0,00 a 5,00. ;Registros utilizados: ;La rutina utiliza los registros R8..R1 sin salvarlos previamente. Tambin se requiere un registro multipropsito ;al que se le llama rmp localizado en la mitad superior de los registros. Hay que tener cuidado de que este ;registro no entre en conflicto con los registros utilizados en el resto del programa. ;Al entrar en la rutina se espera el nmero de 8 bits en el registro R1. La multiplicacin usa los registros ;R4:R3:R2 para mantener el multiplicador 502 (se desplaza a la izquierda mximo 8 veces durante la ;multiplicacin). El resultado de la multiplicacin se calcula en los registros R7:R6:R5. El resultado de la ;llamada a la divisin por 256 ignora R5. R7:R6 se redondea en funcin del bit ms alto de R5 y el resultado se ;copia a R2:R1. ;La conversin a cadena ASC utiliza la entrada en R2:R1, los registros R4:R3 como divisor y coloca el ;resultado en R5:R6:R7:R8 (R6 es la parte decimal) ;Otras convenciones: ;La conversin est estructurada en subrutinas con la utilizacin de la pila. Esta debe funcionar bien para el uso ;en tres niveles (6 bytes de SRAM). ;Tiempos de conversin: ;La rutina completa requiere como mximo 228 ciclos de reloj (conversin $FF) y mnimo 79 (conversin $00). ;A 4 MHz los tiempos son de 56,75 y 17,75 microsegundos respectivamente. ;Definiciones: ;Registros .DEF rmp = R16 registro multipropsito 9: ;Avr tipo: Probado para el AT90S8515. Slo se requiere establecer la pila. Las rutinas trabajan bien con otros ;AT90S. .NOLST .NCLUDE "8515def.inc .LST ;nicio del programables ;Escribe un nmero en R1 y comienza la rutina de conversin. Slo para propsitos de prueba. .C9EG ./RG K)))) rJmp m#in m#in@ ldi rmp14IG45RAMEFD7 ; est#"le*er l# pil# o!t 9.41rmp ldi rmp10/85RAMEFD7 o!t 9.01rmp ldi rmp1KFF ; Convertir KFF mov R11rmp r*#ll p*onv8 ; llamada a la rutina de conversin noGend@ ; bucle sin fin, cuando se hace rJmp noGend ; Envoltorio de rutina de conversin, llamadas a los diferentes pasos de conversin p*onv8@ r*#ll p*onv8m ; m!ltipli*#r por 5)2 r*#ll p*onv8r ; redonde# D divide por 256 r*#ll p*onv8# ; convierte a cadena ASC ldi rmp1T.T ; establecer cadena decimal mov R61rmp ret ; todo hecho ; 9!"r!tin# p#r# m!ltipli*#r por 5)2 p*onv8m@ *lr R( ; est#"le*er el m!ltipli*#dor p#r# 5)2 ldi rmp1K)1 mov R;1rmp ldi rmp1KF6 mov R21rmp *lr R< ; "orr#r el res!lt#do *lr R6 *lr R5 p*onv8m1@ or R11R1 ; comprobar si el nmeros es todo ceros "rne p*onv8m2 ; todava hay unos, ir a convertir ret ; listo, volver p*onv8m2@ lsr R1 ; desplazar el nmero a la derecha (dividir por 2) "r** p*onv8m; ; si el bit ms bajo fue 0, entonces salto a la suma #dd R51R2 ; s!m#r el nLmero en R6@R5@R(@R; *on el res!lt#do #d* R61R; #d* R<1R( p*onv8m;@ lsl R2 ; m!ltipli*#r R(@R;@R2 por 2 rol R; rol R( rJmp p*onv8m1 ; repetir p#r# el si$!iente "it ; Redondeo del v#lor en R<@R6 *on el "it < de R5 p*onv8r@ *lr rmp ; poner# # *ero rmp lsl R5 ; rrot#r el "it < #l #*#rreo #d* R61rmp ; s!m#r 09: *on el #*#rreo #d* R<1rmp ; s!m#r el M9:m *on el #*#rreo 9= mov R21R< ; Copi#r el v#lor # R2@R1 5dividir por 2567 mov R11R6 ret ; Convertir l# p#l#"r# en R2@R1 # !n# *#den# A9CII en R5@R6@R<@R8 p*onv8#@ *lr R( ; Est#"le*er el v#lor del divisor de*im#l # 1)) ldi rmp11)) mov R;1rmp r*#ll p*onv8d ; o"tener dB$itos A9CII por s!str#**i+n repetid# mov R51rmp ; est#"le*er *#den# de *#r#*teres de l# *enten# ldi rmp11) ; Est#"le*er el v#lor del divisor de*im#l # 1) mov R;1rmp r*#ll p*onv8d ; o"tener el si$!iente dB$ito A9CII mov R<1rmp ; est#"le*er *#den# de *#r#*teres de l# de*en# ldi rmp1T)T ; *onvertir el resto # !n *#rQ*ter A9CII #dd rmp1R1 mov R81rmp ; est#"le*er l# *#den# de *#r#*teres ret ; Convertir l# p#l#"r# "in#ri# en R2@R1 # dB$ito de*im#l rest#ndo el v#lor del divisor en R(@R; 51))1 1)7 p*onv8d@ ldi rmp1T)T ; ComienE# *on el v#lor de*im#l ) p*onv8d1@ *p R11R; ; Comp#r#r l# p#l#"r# *on el v#lor del divisor de*im#l *p* R21R( "r** p*onv8d2 ; A*#rreo # *ero. Rest#r el v#lor del divisor ret ; rest# >e*># p*onv8d2@ s!" R11R; ; rest#r el v#lor del divisor s"* R21R( in* rmp ; in*rement#r !n dB$ito rJmp p*onv8d1 ; !n# veE mQs ; Fin de l# r!tin# de pr!e"# de *onversi+n Ejemplo 2: Convertidor AD de 10 bits con punto flotante ; Demostracin de conversin de punto flotante ; en ensamblador, (C)2003 www.avr-asm-tutorial.net ; ; La tarea: Se lee el resultado de 10 bits de un convertidor analgico-digital. El nmero est en ;el rango de 0000 a 03FF hexadecimal. Hay que convertirlo a un nmero de punto flotante en ;el rango de 0,000 a 5,000 voltios. ; ; Esquema del programa: ; 1. Comprobar que el nmero es menor de $0400, para prevenir desbordamientos no permitidos ; durante la siguiente multiplicacin. ; 2. Multiplicacin por 320313 (04E338 hex). Se multiplica por 5000, por 65536 y se divide por 1023 ; en un slo paso. ; 3. Redondear el resultado y cortar los dos ltimos bytes (dividir por 65536). Para redondear se ; ; ; utiliza antes el bit 15. ; 4. Convertir la palabra resultante a ASC y establecer la posicin correcta del punto decimal. ; La palabra resultante en el rango de 0 a 5,000 se muestra en caracteres ASC. ; ; Registros utilizados: ; Las rutinas utilizan los registros R10..R1 sin salvar previamente. Tambin se requiere un registro ;multipropsito al que se le llama rmp localizado en la mitad superior de los registros. Hay que tener ;cuidado de que este ;registro no entre en conflicto con los registros utilizados en el resto del ;programa. ; ; Al entrar en la rutina el nmero de 10 bits se espera en el par de registros R2:R1. Si el nmero es 47 ;mayor de $03FF la rutina retorna con el bit de acarreo establecido y la cadena resultante en ;R5:R6:R7:R8:R9:R10 se establece como cadena ASC con terminacin nula "E.EEEE ; La multiplicacin utiliza los registros R6:R5:R4:R3 para contener el multiplicador 320313 (que se ;puede desplazar mximo 10 veces durante la multiplicacin). El resultado de la multiplicacin se ;calcula en los registros R10:R9:R8:R7. El resultado de la llamada a la divisin por 65536 ignora ;R8:R7 y el resultado en R10:R9 se redondea en funcin del bit ms alto de R8. Por ltimo el ;resultado final se copia en R2:R1. ; La conversin a cadena ASC utiliza la entrada en R2:R1 y el par de registros R4:R3 como divisor ;para la conversin y coloca el resultado como cadena ASC en R5:R6:R7:R8:R9:R10 ;(null-terminated o terminada en cero) ;Otras convenciones: ;La conversin est estructurada en subrutinas con la utilizacin de la pila. Esta debe funcionar bien ;para el uso en tres niveles (6 bytes de SRAM). ;Tiempos de conversin: ; La rutina completa requiere mximo 326 ciclos de reloj (conversin de $03FF) y mnimo 111 ;(conversin de $0000). A 4 MHz los tiempos son de 81,25 y 27,5 microsegundos respectivamente. ; ; Definiciones: ; Registros .DEF rmp = R16 ; registro multi-propsito ; ;Avr tipo: Probado para el AT90S8515. Slo se requiere establecer la pila. Las rutinas trabajan bien ;con otros AT90S. .NOLST .NCLUDE "8515def.inc" .LST ; ; Comienza el programa ; ; Escribe un nmero en R2:R1 y comienza la rutina de conversin. Slo para propsitos de prueba. ; .CSEG .ORG $0000 rjmp main ; main: ldi rmp,HGH(RAMEND) ; Set the stack out SPH,rmp ldi rmp,LOW(RAMEND) out SPL,rmp ldi rmp,$03 ; Convert $03FF mov R2,rmp ldi rmp,$FF mov R1,rmp rcall fpconv10 ; call the conversion routine no_end: ; unlimited loop, when done rjmp no_end ; ; Conversion routine wrapper, calls the different conversion steps ; fpconv10: rcall fpconv10c ; Check the input value in R2:R1 brcs fpconv10e ; if carry set, set "E.EEE" rcall fpconv10m ; multiplicate by 320,313 rcall fpconv10r ; redondear and divide by 65536 43 rcall fpconv10a ; convert to ASC string rjmp fpconv10f ; set decimal point and null-termination fpconv10e: ldi rmp,'E' ; set error condition to result string mov R5,rmp mov R7,rmp mov R8,rmp mov R9, rmp fpconv10f: ldi rmp,'.' ; set decimal point mov R6,rmp clr rmp ; null-terminate ASC string mov R10,rmp ret ; all done ; ; Subrutina de verificacin de entrada ; fpconv10c: ldi rmp,$03 ; compare MSB with 03 cp rmp,R2 ; if R2>$03, set carry on return ret ; ; Subroutine multiplication by 320,313 ; ; Starting conditions: ; +---+---+ ; | R2+ R1| nput number ; +---+---+ ; +---+---+---+---+ ; | R6| R5| R4| R3| Multiplicant 320.313 = $00 04 E3 38 ; | 00| 04| E3| 38| ; +---+---+---+---+ ; +---+---+---+---+ ; |R10| R9| R8| R7| Result ; | 00| 00| 00| 00| ; +---+---+---+---+ ; fpconv10m: clr R6 ; set the multiplicant to 320.313 ldi rmp,$04 mov R5,rmp ldi rmp,$E3 mov R4,rmp ldi rmp,$38 mov R3,rmp clr R10 ; clear the result clr R9 clr R8 clr R7 fpconv10m1: mov rmp,R1 ; check if the number is clear or rmp,R2 ; any bit of the word a one? brne fpconv10m2 ; still one's, go on convert ret ; ready, return back fpconv10m2: lsr R2 ; shift MSB to the right (div by 2) 45 ror R1 ; rotate LSB to the right and set bit 7 brcc fpconv10m3 ; if the lowest bit was 0, then skip adding add R7,R3 ; add the number in R6:R5:R4:R3 to the result adc R8,R4 adc R9,R5 adc R10,R6 fpconv10m3: lsl R3 ; multiply R6:R5:R4:R3 by 2 rol R4 rol R5 rol R6 rjmp fpconv10m1 ; repeat for next bit ; ; Round the value in R10:R9 with the value in bit 7 of R8 ; fpconv10r: clr rmp ; put zero to rmp lsl R8 ; rotate bit 7 to carry adc R9,rmp ; add LSB with carry adc R10,rmp ; add MSB with carry mov R2,R10 ; copy the value to R2:R1 (divide by 65536) mov R1,R9 ret ; ; Convert the word in R2:R1 to an ASC string in R5:R6:R7:R8:R9:R10 ; ; +----+----+ ; + R2| R1| nput value 0..5,000 ; +----+----+ ; +----+----+ ; | R4| R3 | Decimal divider value ; +----+----+ ; +----+----+----+----+----+-----+ ; | R5 | R6 | R7| R8| R9| R10| Resulting ASC string (for input value 5,000) ; |' 5 ' | ' . ' | '0' | '0' | '0' | $00 | null-terminated ; +----+----+----+----+----+-----+ ; fpconv10a: ldi rmp,HGH(1000) ; Set the decimal divider value to 1,000 mov R4,rmp ldi rmp,LOW(1000) mov R3,rmp rcall fpconv10d ;obtener dgitos ASC por sustraccin repetida mov R5,rmp ; establecer la cadena de caracteres del millar clr R4 ; Set the decimal divider value to 100 ldi rmp,100 mov R3,rmp rcall fpconv10d ; get the next ASC digit mov R7,rmp ; establecer la cadena de caracteres de la centena ldi rmp,10 ; Set the decimal divider value to 10 mov R3,rmp rcall fpconv10d ; get the next ASC digit mov R8,rmp ; establecer la cadena de caracteres de la decena ldi rmp,'0' ; convert the rest to an ASC char add rmp,R1 mov R9,rmp ; establecer la cadena de la unidad 4@ ret ; ; Convert binary word in R2:R1 to a decimal digit by substracting ; the decimal divider value in R4:R3 (1000, 100, 10) ; fpconv10d: ldi rmp,'0' ; start with decimal value 0 fpconv10d1: cp R1,R3 ; Compare word with decimal divider value cpc R2,R4 brcc fpconv10d2 ; Carry clear, subtract divider value ret ; done subtraction fpconv10d2: sub R1,R3 ; subtract divider value sbc R2,R4 inc rmp ; incrementar un dgito rjmp fpconv10d1 ; una vez ms ; ; End of floating point conversion routines ; ; End of conversion test routine Plani)icar un pro"ecto en ensamblador *V( Ahora se vern los conceptos bsicos de como planificar un proyecto simple para programar en ensamblador. Debido a que lo que ms determina es el componente hardware, primero se ver las consideraciones de hardware. A continuacin use vern las interrupciones y despus el tema de los tiempos. Consideraciones de hardware Para decidir que tipo de AVR se ajusta mejor a las necesidades hay que tener en cuenta una serie de consideraciones. He aqu las ms relevantes: 1. Que conexiones de puerto con ubicacin fija se necesitan? Los puertos de /O de los componentes internos slo estn disponibles en pines determinados y no se pueden cambiar. A continuacin habra que tener en cuenta: 1. Si el procesador debe ser programable en circuito (interface SP), tienen que asignarse para este propsito los pines SCK, MOS y MSO. Hay que ver si el perifrico permite que estos puedan ser utilizados como entradas (por ejemplo SCK y MOS) o como salidas (por disociacin a travs de resistencias o multiplexores). 2. Si se necesita una interfaz serie, hay que reservar RXD y TXD para tal fin. Si se utiliza el protocolo de hardware de enlace RTS/CTS, son necesarios dos pines de puerto adicionales aunque se puede utilizar cualquiera que este libre. 3. Si se necesita un comparador analgico. AN0 y AN1 tendran que ser reservados para ello. 4. Si se necesita seales externas para monitorizar cambios de nivel, hay que reservar NT0 y/o NT1. 5. Si se van a utilizar convertidores AD, deben emplazarse y reservarse las entradas ADC. Si el convertidor lleva conexiones AVCC y AREF externas se deben cablear en consecuencia. 6. Si se van a contar pulsos externos, los pines de entrada de temporizador T0, T1 y T2 son fijos y exclusivos para esto. 7. Si hay que aadir SRAM externa, hay que reservar la respectiva direccin y los puertos de datos junto con ALE, RD y WR. 8. Si el reloj del procesador debe ser generado a partir de un oscilador de cristal externo, hay que reservar XTAL1. Si se utiliza un cristal externo o un resonador cermico para controlar la 48 frecuencia de reloj, XTAL1 y XTAL2 han sido fijados para tal fin. 2. Hay componentes externos que requieran ms de un portpin (2, 4 u 8) para ser leidos o escritos? stos deben definirse de manera adecuada (en el mismo puerto, en el orden correcto). 1. Si para el control de un dispositivo externo se requiere la lectura o escritura de ms de un bit a la vez, ej. una interfaz de pantalla LCD de cuatro u ocho bits, los bits de puerto necesarios deben estar en el orden correcto. Si no es posible colocar toda la interfaz en un solo puerto, la interfaz se puede dividir en dos partes y para el software es ms fcil, si las partes se ajustan de izquierda a derecha. 2. Si se requieren dos o ms canales ADC, para el software es ms fcil si stos se colocan en orden, por ejemplo, ADC2+ADC3+ADC4. 3. Al final, todos los componentes externos pueden estar colocados de forma que no requieran pines fijos. 1. Si por un simple pin hay que seleccionar un dispositivo ms grande, puede considerar utilizar el pin de RESET para evitarlo. ste puede ser usado si se establece determinado fusible. El ajuste de este fusible desactiva la programacin SP y el chip slo se puede programar en el modo de alto voltaje. Esto es aceptable para produccin final pero no para la creacin de un prototipo. En el caso de crear un prototipo con una interfaz de programacin de alto voltaje, el pin de SP puede ser utilizado si el componente en el pin de RESET est protegido contra los 12 V durante la programacin SP, con una resistencia y un diodo zener. Otras consideraciones para elegir con cul procesador va a trabajar mejor pueden ser: Que temporizadores son necesarios y que resolucin deben stos proporcionar. Qu valores/datos hay que preservar cuando se apaga la alimentacin? (Capacidad de EEPROM) Cunto espacio de almacenamiento se requiere? (Capacidad de SRAM) Qu requerimientos de espacio hay en el PCB? Qu procesador encaja mejor y que tipos de empaquetado hay disponibles? Voltajes de operacin y requisitos de energa. Si la tensin de alimentacin proviene de una batera o un acumulador. Las caractersticas de poder pueden jugar un papel importante. Precio del dispositivo. Es relevante para una gran produccin en serie. No todo depende del procesador interno y las condiciones del mercado son impredecibles. Disponibilidad? Si uno comienza un proyecto con un AT90S1200 de un cajn de objetos usados le puede salir muy barato, pero tal decisin no es muy sostenible. Trasladar un proyecto de un pequeo a un gran dispositivo o viceversa termina en un completo rediseo de software. Es mejor tenerlo en cuenta desde el principio porque as se v y se trabaja mejor y es cuestin de una pequea fraccin de lineas de cdigo. Consideraciones sobre las interrupciones Tareas muy simples funcionan bien sin las interrupciones. Si el consumo de energa es un problema, esto ya no es cierto. Casi todos los proyectos requieren interrupciones y esto debe ser planificado cuidadosamente. Requisitos bsicos de operacin por interrupciones Si no hay que tener en cuenta nada ms he aqu los fundamentos: - Habilitacin de interrupciones: Las interrupciones requieren la pila de hardware. As que hay que establecer SPL (y en dispositivos grandes SPH) al principio de RAMEND y reservar la parte superior de la 49 SRAM para este propsito (por ejemplos los ltimos 8 a x bytes). Cada componente interno con su respectiva condicin de provocacin de una interrupcin se habilitan mediante el establecimiento del correspondiente bit de bandera de habilitacin de interrupcin. Los cambios de estos bits conllevan cierto riesgo por lo que sera mejor disear el software sin tener que cambiarlos. La bandera en el registro de estado SREG tiene que establecerse al principio y permanecer establecida durante la operacin. Si es necesario despejar la bandera durante una operacin fuera de la rutina de servicio de la interrupcin, agregue la instruccin de establecimiento de la bandera en unas pocas instrucciones. - Tabla de vectores de interrupcin: Cada componente interno con su respectiva condicin de interrupcin corresponden a un vector especfico de interrupcin situado en una determinada direccin de memoria flash de programa. La instruccin en esta direccin es la instruccin RJMP de una palabra o en los procesadores grandes Atmega, la instruccin JMP de dos palabras que salta a la respectiva rutina de servicio de interrupcin. Las direcciones de los vectores son especficas del tipo de AVR. Al portar el software a un tipo diferente se requieren ajustes. A cada direccin de vector en la tabla que actualmente no es utilizada, se le da una instruccin RET(en los tipos grandes Atmega, una RET seguida de una NOP). Esto impide la ejecucin de una interrupcin fantasma por error. El uso de la directiva .ORG para ajustar las direcciones de vector no ofrece seguridad ante estos posibles eventos. Si se produce una condicin de interrupcin, se establece la respectiva bandera en el registro de control del componente interno. sta se pone a cero automticamente si se ejecuta la interrupcin. En algunos casos excepcionales (por ejemplo el caso de una condicin de interrupcin de una UART por un buffer TX vaco al que no se le va a enviar ms caracteres) tiene que ser puesta a cero primero la bandera de habilitacin de interrupcin del componente y la bandera de condicin de interrupcin despus. Si se da la condicin de interrupcin en ms de un componente a la vez, la interrupcin con la direccin ms baja tiene preferencia. - Rutinas de servicio de interrupcin: Cada rutina de servicio de interrupcin comienza guardando el registro de estado SREG en un registro reservado exclusivamente para tal fin, y termina con la restauracin del registro de estado como estaba al producirse la interrupcin. Debido a que una interrupcin puede ocurrir en cualquier momento incluso cuando el procesador est ejecutando las instrucciones del bucle principal del programa, cualquier alteracin del registro de estado puede causar un funcionamiento impredecible. Antes de saltar a la rutina de servicio, el procesador lleva el contador de la instruccin en curso a la pila. La interrupcin y el respectivo salto a la rutina de servicio deshabilita otras interrupciones temporalmente poniendo a cero la bandera en el registro de estado SREG. Cada rutina de servicio termina con la instruccin RET que retorna de la pila la instruccin siguiente a la que se estaba ejecutando cuando ocurri la int. y establece de nuevo la bandera . Debido a que durante la ejecucin de una rutina de servicio puede haber nuevas solicitudes de interrupcin, incluso de mayor prioridad, cada rutina de servicio tiene que ser lo ms breve posible y realizar las operaciones crticas de la tarea en el mnimo tiempo. Las operaciones de respuesta demasiado largas deben realizarse fuera de la rutina de servicio de interrupcin. Como interrumpir una rutina de servicio de interrupcin no puede suceder, todas las rutinas de servicio de interrupcin pueden utilizar el mismo registro temporal. - nterfaz de rutina de servicio de interrupcin y bucle de programa principal: 44 La comunicacin entre la rutina de servicio de int. y el bucle del programa principal se realiza a travs de banderas individuales, que se establecen dentro de la rutina de servicio y se ponen a cero en el bucle del programa principal. Esto ltimo se hace con una simple palabra de instruccin o deshabilitando temporalmente las interrupciones durante este paso para bloquear sebreescrituras errneas de otras banderas que se han podido cambiar entre las tres fases de lectura-modificacin-escritura. Los valores que proporcionan las rutinas de servicio de int. son puestos en los registros dedicados o en lugares especficos de SRAM. Cada cambio de esos valores (que se utilizan ms tarde fuera de la rutina de servicio) tiene que ser comprobado por posible corrupcin si en medio ocurre otra interrupcin. Manejar un slo byte es fcil, pero la entrega de dos o ms bytes requiere un protocolo de transferencia (desactivar interrupciones durante la transferencia, establecer la bandera para evitar sobreescrituras, etc). Por ejemplo, la entrega de un valor del temporizador de 16 bits requiere primero la desactivacin de las interrupciones, de lo contrario la lectura de un segundo byte no es correspondiente al primer byte ledo si ha ocurrido una interrupcin de por medio. - Bucle de programa principal: En el bucle principal del programa el procesador se enva a dormir seleccionando el modo de espera "inactivo. Cada interrupcin despierta al procesador que salta a la rutina de servicio de int. correspondiente y despus del retornar de la interrupcin contina la operacin en el bucle principal. Tiene sentido comprobar que no se establecieron banderas dentro de la rutina de servicio y si se da el caso hay que realizar el tratamiento de la bandera. Despus de realizar todas las operaciones se puede realizar otro chequeo de la configuracin de las banderas (para rutinas muy largas) y el procesador se puede enviar de vuelta a dormir. Ejemplo de un programa ensamblador por interrupciones A continuacin un programa de ensamblador por interrupciones que utiliza todas las reglas mencionadas anteriormente: ; ; Definicin de registros ; .EQU rsreg = R15 ; salvar el estado durante las interrupciones .EQU rmp = R16 ; registro de las interrupciones temporales externo .EQU rimp = R17 ; registro de las interrupciones temporales interno .EQU rflg = R18 ; registro de bandera para la comunicacin .EQU bint0 = 0 ; bit de bandera para la sealizacin de servicio NT0 .EQU btc0 = 1 ; bit de bandera para la sealizacin de desbordamiento TC0 ; ... ; Tabla SR ; .ORG $0000 rjmp main ; Vector de reset, ejecutado en el arranque rjmp isr_int0 ;vector NT0, ejecutado en los cambios de nivel en la linea de entrada NT0 reti ; interrupcin sin uso reti ; interrupcin sin uso rjmp isr_tc0_Overflow ; vector de desbordamiento TC0 reti ; interrupcin sin uso reti ; interrupcin sin uso ; ... otros vectores de int. ; ; Rutinas de servicio de interupcin ; 4? isr_int0: ; Rutina de servicio a para NT0 in rsreg,SREG ; salvar estado in rimp,PNB ; leer del puerto B el registro de temperatura out PORTC,rimp ; escribir en el puerto C el registro de temperatura ; ... hacer otras cosas sbr rflg,1<<bint0 ; sealizacin de NT0 fuera out SREG,rsreg ; restaurar estado reti ; retornar y habilitar las interrupciones isr_tc0_Overflow: ; rutina de servicio de desbordamiento TC0 in rsreg,SREG ; salvar estado in rimp,PNB ; leer del puerto B el registro de temperatura out PORTC,rimp ; escribir en elpuerto C el registro de temperatura ; ... hacer otras cosas sbr rflg,1<<btc0 ; establecer la bandera TC0 out SREG,rsreg ; restaurar estado reti ; retornar y habilitar las interrupciones ; ; nicio del programa principal ; main: ldi rmp,HGH(RAMEND) ; establecer el registro de pila out SPH,rmp ldi rmp,LOW(RAMEND) out SPL,rmp ; ... otras cosas a hacer ; activar interrupcin para desbordamiento TC0 ldi rmp,1<<TOE0 ; habilitacin de interrupcin de desbordamiento del temporizador 0 out TMSK,rmp ; establecer la mascara de desbordamiento del temporizador ldi rmp,(1<<CS00)|(1<<CS02) ; preescalador en 1024 out TCCR0,rmp ; inicio del temporizador ; habilitar interrupcin en la entrada NT0 ldi rmp,(1<<SE)|(1<<SC00) ; habilitar modo inactivo e interrupcin NT0 en todos los cambios de nivel out MCUCR,rmp ; al registro de control ldi rmp,1<<NT0 ; habilitar interrupciones NT0 out GCR,rmp ; al registro de control de interrupcin ; establecer bandera de estado de interrupcin sei ; establecer bandera de interrupcin ; ; Bucle de programa principal ; loop: sleep ; procesador a dormir nop ; ficitcia para despertar sbrc rflg,bint0 ; no se establece bandera NT0 rcall mache_int0 ; manejar el evento en NT0 sbrc rflg,btc0 ; no se establece bandera de desbordamiento TC0 rcall mache_tc0 ; manejar desbordamiento TC0 rjmp loop ; volver a dormir ; ; Manejar resultados de evento ; mache_int0: ; manejar resultado NT0 cbr rflg,1<<bint0 ; despejar bandera NT0 ; ... hacer otras cosas ret ; listo, retornar al bucle mache_tc0: ; manejar desbordamiento TC0 cbr rflg,1<<btc0 ; despejar bandera TC0 ; ... hacer otras cosas ret ; listo, retornar al bucle 4: Consideraciones de tiempo Si un proyecto AVR va ms all de sondear un puerto /O y en funcin de esto hacer algo, es necesario considerar el tema tiempo, que: Comienza con la seleccin del tipo de procesador. Contina con la pregunta de que es lo que ha de ser ejecutado peridicamente y con que precisin. Si hay posibilidades de control de sincronizacin y cmo se pueden combinar las cosas. Seleccin de la frecuencia de reloj del procesadores La cuestin principal est en la precisin necesaria del reloj del procesador, aunque en aplicaciones que permitan un pequeo porcentaje de inexactitud, el oscilador interno RC de la mayora de los AVR es suficiente. En los tipo tinD y me$# se puede hacer una calibracin del oscilador por lo que se reduce la diferencia entre la frecuencia nominal y la efectiva. Hay que tener en cuenta que en el byte de calibracin interna por defecto fue seleccionada una tensin de servicio determinada. Si el voltaje de operacin se fija en un nivel diferente, volver a escribir el byte de calibracin aporta ms precisin. Si el voltaje de funcionamiento es fluctuante, el error puede ser demasiado grande. Si el reloj interno RC es demasiado lento o demasiado rpido, algunos tipos de dispositivo tienen un preescalador de reloj. Con esta caracterstica pueden ser seleccionadas diferentes frecuencias de reloj y permite optimizar la frecuencia. Esto se hace de una vez cambiando un fusible de hardware (el fusible DV8) o por software (por ejemplo para reducir el consumo de energa durante las pausas). Pero hay que tener en cuenta que algunos dispositivos con una especificacin de reloj limitada (los de tipo V), no deben establecerse ms all de su lmite o no volvern a funcionar correctamente. Si el oscilador RC interno es demasiado impreciso, los fusibles se pueden configurar para un oscilador externo, un cristal (Xtal) o un dispositivo cermico. Dado que una configuracin errnea de los fusibles puede dar lugar a una catstrofe, una placa de rescate con un oscilador externo podra ser la ltima oportunidad para recuperar el dispositivo reseteando el fusible de nuevo. La frecuencia de reloj absoluta debe ser la apropiada para la aplicacin. Se puede utilizar como indicador la frecuencia que ms a menudo realiza el paquete de trabajo. Si por ejemplo, tiene que ser consultada una tecla cada 2 ms, y esperar 20 veces este tiempo que debe ser lo suficientemente largo para que no haya efecto rebote, hay un montn de tiempo si se utiliza un reloj de 1 MHz (2.000 ciclos de reloj entre dos consultas, 20.000 para la ejecucin repetida del comando de teclado). Si hay que llegar a una frecuencia alta para una seal PWM (modulacin por ancho de pulso) de alta resolucin, como por ejemplo una frecuencia PWM de 10 KHz y 8 bits de resolucin, 2.56 MHz son demasiado lentos para una solucin basada en software. Mejor si un contador de tiempo con cierta sobrecarga de software lo puede asumir. 4=