Propeller, el gigante de 8 cabezas

Page 1

PROPELLER: El gigante de 8 cabezas “Un documento en castellano basado en la docuentación del fabricante ‘Parallax’ y destinado a los clientes y usuarios de ‘Ingeniería de Microsistemas Programados S.L.’ distribuidor de Parallax en España”

INGENIERIA DE MICROSISTEMAS PROGRAMADOS S.L. C/ Alda. Mazarredo Nº 47 - 1º Dpto. 2 48009 BILBAO - BIZKAIA Tel/Fax: 94 4230651 email: info@microcontroladores.com www.microcontroladores.com


PROPELLER: EL GIGANTE DE 8 CABEZAS Indice general

www.microcontroladores.com info@microcontroladores.com

Un documento en castellano basado en la documentación del fabricante “Parallax” destinado a los clientes de “Ingeniería de Microsistemas Programados S.L.” distribuidor de Parallax en España

INDICE GENERAL CAPITULO 1: ARQUITECTURA, FUNCIONAMIENTO Y CARACTERÍSTICAS DEL PROPELLER 1.1. ¿Qué es el Propeller? 1.2. Tipos de encapsulado 1.3. Diagrama de conexiones 1.4. El arranque o Reset 1.5. Proceso de ejecución 1.6. Modo de apagado 1.7. Diagrama por bloques de la arquitectura interna 1.8. Los recursos compartidos 1.9. El reloj del sistema 1.10. Cogs (procesadores) 1.11. El Hub 1.12. Pines de E/S 1.13. Contador del sistema 1.14. Registro CLK 1.15. Semáforos 1.16. Memoria Principal 1.17. RAM Principal 1.18. ROM Principal 1.19. Definición de caracteres 1.20. Tablas de registro y contra-registro 1.21. Tabla de seno 1.22. Boot Loader e Intérprete Spin

CAPITULO 2: MANEJO Y DESARROLLO DE APLICACIONES 2.1. La concepción del software 2.2. Organización de la pantalla 2.2.1. Panel 1: Panel de visualización de objetos 2.2.2. Panel 2: Campo de carpetas recientes y lista de carpetas 2.2.3. Panel 3: La lista de archivos y filtro de archivos 2.2.4. Panel 4: Panel del editor 2.3. Componentes del menú 2.4. Tabla de caracteres (CARÁCTER CHART) 2.5. Modos de visión, bookmarks y números de línea 2.6. Selección de bloques y movimiento de selección 2.7. Identing y Outdenting 2.8. Indicadores de bloque-grupo 2.9. Teclas de acceso rápido

i-1


PROPELLER: EL GIGANTE DE 8 CABEZAS Indice general CAPITULO 3: EL LENGUAJE “SPIN” 3.1. Introducción 3.2. Listado por categorías del lenguaje Spin del Propeller 3.3. Descripción de los elementos del lenguaje Spin 3.3.1. ABORT 3.3.2. BYTE 3.3.3. BYTEFILL 3.3.4. BYTEMOVE 3.3.5. CASE 3.3.6. CHIPVER 3.3.7. CLKFREQ 3.3.8. _CLKFREQ 3.3.9. CLKMODE 3.3.10. _CLKMODE 3.3.11. CLKSET 3.3.12. CNT 3.3.13. COGID 3.3.14. COGINIT 3.3.15. COGNEW 3.3.16. COGSTOP 3.3.17. CON 3.3.18. CONSTANT 3.3.19. CTRA, CTRB 3.3.20. DAT 3.3.21. DIRA, DIRB 3.3.22. FILE 3.3.23. FLOAT 3.3.24. _FREE 3.3.25. FRQA, FRQB 3.3.26. IF 3.3.27. INA, INB 3.3.28. LOCKCLR 3.3.29. LOCKNEW 3.3.30. LOCKRET 3.3.31. LOCKSET 3.3.32. LONG 3.3.33. LONGFILL 3.3.34. LONGMOVE 3.3.35. LOOKDOWN, LOOKDOWNZ 3.3.36. LOOKUP, LOOKUPZ 3.3.37. NEXT 3.3.38. OBJ 3.3.39. OPERADORES 3.3.39. OUTA, OUTB 3.3.40. PAR 3.3.41. PHSA, PHSB 3.3.42. PRI 3.3.43. PUB 3.3.43B. QUIT 3.3.44. REBOOT 3.3.45. REPEAT 3.3.46. RESULT 3.3.47. RETURN 3.3.48. ROUND

i-2

www.microcontroladores.com info@microcontroladores.com


PROPELLER: EL GIGANTE DE 8 CABEZAS Indice general 3.3.49. SPR 3.3.50. _STACK 3.3.51. STRCOMP 3.3.52. STRING 3.3.53. STRSIZE 3.3.54. TRUNC 3.3.55. VAR 3.3.56. VCFG 3.3.57. VSCL 3.3.58. WAITCNT 3.3.59. WAITPEQ 3.3.60. WAITPNE 3.3.61. WAITVID 3.3.62. WORD 3.3.63. WORDFILL 3.3.64. WORDMOVE 3.3.65. _XINFREQ

i-3

www.microcontroladores.com info@microcontroladores.com


PROPELLER: EL GIGANTE DE 8 CABEZAS Indice general

i-4

www.microcontroladores.com info@microcontroladores.com


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

CAPITULO 1: ARQUITECTURA, FUNCIONAMIENTO Y CARACTERISTICAS DEL PROPELLER 1.1 ¿QUÉ ES EL PROPELLER? El procesador Propeller está diseñado para proporcionar un elevadísimo rendimiento para los sistemas embebidos mientras mantiene un bajo consumo de energía y ocupa una superficie de instalación pequeña. Además de ser rápido, el Propeller proporciona flexibilidad y potencia a través de sus ocho procesadores, llamados Cogs, que pueden realizar simultáneamente tareas independientes o cooperativas, todo esto mientras soporta una arquitectura relativamente simple que es fácil de aprender y de utilizar. El diseño resultante del Propeller libera al desarrollador programación de sistemas embebidos. Por ejemplo:

de aplicaciones de las complejidades típicas de la

El mapa de memoria es plano. No hay necesidad de paginar los bloques del código, de datos o de variables. Esto permite ahorrar mucho tiempo durante el desarrollo de la aplicación.

Los acontecimientos asíncronos son más fáciles de controlar que con dispositivos que utilizan interrupciones. El Propeller no tiene necesidad de interrupciones; sólo hay que asignar algunas patitas a tareas de alta frecuencia y mantener otras patitas libres. El resultado es una aplicación más receptiva que es más fácil de mantener.

El lenguaje ensamblador del Propeller ofrece la ejecución condicional y la escritura opcional del resultado para cada instrucción individual.

1.2. Tipos de encapsulado El chip Propeller está disponible en los encapsulados mostrados en la Figura 1-1.

Figura1-1.-Encapsulados del Propeller.

1-1


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

Descripciones de patitas o “pines”

Nombre de PIN P0-P31

VDD VSS BOEn

Dirección E/S (E/S)

--I

Descripción Puerto A de E/S de propósito general. Los pines mostrados a continuación tienen un propósito especial sobre encendido/reset pero son de propósito general E/S de todas formas. P28 – Conexión opcional de I2C LCC a EEPROM externa. P29 – Conexión opcional de I2C SDA a EEPROM externa. P30 - Tx al host. P31 - Rx del host. 2.7 – 3.3 VDC Tierra. 0 VDC Brown Out Enable. Debe conectarse con Vdd o el Vss. Si es baja, RESn se convierte en una salida débil (que entrega Vdd con 5 K Ω) para monitorizar, pero puede todavía utilizarse para crear un reset. Si es alta, RESn actúa como entrada de CMOS con Schmitt Trigger.

RESn

E/S

XI

I

XO

O

Reset (activa con nivel bajo) Cuando es baja, resetea el chip Propeller; deshabilita todos los cogs y los pines de E/S. El Propeller se resetea 50 ms después de las transiciones de RESn de baja a alta cuando Vdd/Vss es suficiente. Entrada del Cristal. Puede conectarse a la salida del cristal/oscilador (con XO izquierdo desconectado), o con una pata de cristal (con XO conectado con la otra patita del cristal o del resonador) dependiendo de los ajustes del registro de CLK. No se requiere ninguna resistencia o condensador externos. Salida del Cristal. Proporciona la regeneración para un cristal externo, o puede ser desconectado dependiendo de ajustes del registro de CLK. No se requiere ninguna resistencia o condensador externos.

El Propeller (P8X32A) tiene 32 patitas de E/S (Puerto A, pines P0 a P31). Los últimos cuatro pines de E/S, P28P31 son de propósito especial para encendido/reset. En encendido/reset, los pines P30 y P31 se comunican con un host para programar y los pines P28 y P29 interactúan con una EEPROM (24LC256) de 32 KB externa.

1-2


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

Especificaciones

Modelo Requerimientos de arranque Velocidad de Reloj Externo Velocidad de Reloj del sistema Oscilador RC Interno

RAM/ROM Global Cog RAM Organizacion RAM/ROM Pines E/S Fuente/ Sumidero actual por E/S Fuente/ Sumidero actual por chip Current Draw @ 3.3 vdc, 70 °F

P8X32A 3.3 VDC DC a 80 MHz (4 MHz a 8 MHz con el Reloj PLL en ejecucion) DC a 80 MHz 12 MHz o 20 kHz (aprox. rango de 8 MHz – 20 MHz, o 13 kHz – 33 kHz, respectivamente) 64 K bytes; 32 K RAM / 32 K ROM 2 K bytes cada Cog 32 bits (4 bytes) 32, CMOS, VDC, ½ VDD umbral lógico de 1.65 V. 50 mA TBD mA 500 uA por MIPS (MIPS = Freq en MHz / 4 * Número de Cogs Activos)

1.3. Diagrama de conexionado La Figura 1-3 muestra un ejemplo del diagrama que conecta el host y el acceso a la EEPROM al chip Propeller. En este ejemplo el acceso al host se consigue a través del servicio Clip Propeller (conversor USB a serie TTL).

Figura 1-3.- Esquema de conexionado del Propeller a un host ( To PC) y a una EEPROM externa de 32 KB.Se utiliza un cristal externo.

1-3


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

1.4. El arranque o reset El proceso de encendido o reset se divide en las siguientes fases: 1. El oscilador interno RC del Propeller comienza a funcionar a 12 MHz aproximadamente; entonces, tras un retraso de reset de 50 ms, el primer procesador (Cog 0) carga el programa embebido del Boot Loader y arranca. 2. El Boot Loader realiza una o más de las siguientes tareas, en este orden: a. Detecta la comunicación de un host, por ejemplo un PC, en los pines P30 y P31. Si se detecta la comunicación de un host, el Boot Loader conversa con el host para identificar el chip Propeller y posiblemente para descargar un programa en RAM global y opcionalmente en la EEPROM externa 32 KB. b. Si no se detectó ninguna comunicación del host, el Boot Loader busca la EEPROM externa 32 KB en los pines P28 y P29. Si se detecta una EEPROM, se cargan los 32 KB en el RAM global del Propeller. c.

Si no se detectó ninguna EEPROM, el Boot Loader se para, se detiene el Cog 0, el chip del Propeller entra en modo de parada, y todos los pines de E/S se fijan como entradas.

3. Si los pasos 2a o 2b son capaces de cargar un programa en la RAM global, y el host no ha mandado un comando de suspensión, el Cog 0 se re arranca con el intérprete Spin embebido y el código del usuario se ejecuta desde la RAM global. 1.5. Proceso de Ejecución Una “Aplicación Propeller” es un programa de usuario compilado a su forma binaria (ejecutable) y descargado en la RAM/EEPROM del Propeller. La aplicación consiste de código escrito en lenguaje Spin del Propeller (código de alto nivel) con componentes opcionales del lenguaje ensamblador del Propeller (código de bajo nivel). El código escrito en lenguaje Spin es interpretado durante tiempo de ejecución por un Cog que ejecuta el intérprete Spin mientras que el código escrito en ensamblador Propeller es ejecutado directamente por un Cog. Cada Aplicación Propeller consiste en, por lo menos, un código Spin y debe ser escrito todo en Spin o combinando Spin y ensamblador. El intérprete Spin del Propeller arranca en el paso 3 del proceso de reset, para ejecutar la aplicación. Una vez finalizado el proceso de arranque y se esté ejecutando una aplicación, arranca en el Cog 0, cualquier otra actividad es definida por la misma aplicación. La aplicación tiene control completo sobre aspectos como la velocidad de reloj interna, uso de pines de E/S, registros de configuración, y “cuándo, cuáles y cuántos” Cogs están funcionando en un momento dado. Todo esto es variable en el tiempo de ejecución, según la aplicación, incluyendo la velocidad de reloj interna. 1.6. Modo de apagado Cuando el Propeller entra modo de apagado, el reloj interno se para causando la parada de todos los Cogs y fijando como entradas (alta impedancia) a todos los pines de E/S. Este modo puede ser causado por uno de estos tres acontecimientos: 1º) Vdd cae por debajo del umbral del brown-out (~2.7 VDC), cuando el brown-out del circuito está activo. 2º) El pin de RESn pasa a ser activo por tensión baja. 3º) La aplicación solicita un “reboot” (véase más adelante el comando del REBOOT). Continúa el modo de parada cuando el voltaje sube y alcanza el umbral del brown-out y el pin de RESn es alto.

1-4


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

1.7. Diagrama por bloques de la arquitectura interna

Figura 1-4.- Arquitectura interna del Propeller. La arquitectura del Propeller se basa en 8 procesadores, denominados Cogs, unos recursos propios de cada procesador y otros compartidos por todos ellos, y un controlador principal, llamado Hub, que se encarga de mantener la integridad del sistema y asignar el funcionamiento de los Cogs y el reparto de los recursos comunes. La interacción Cog/Hub es crítica para el chip Propeller. El Hub controla que el cog pueda tener acceso a los recursos comunes-exclusivos (mutuo-exclusivos), tales como RAM/ROM principal, registros de configuración, etc. El Hub proporciona el acceso exclusivo a un cog cada vez siguiendo el procedimiento "round robin", desde el Cog 0 a el Cog 7 y volviendo al Cog 0 otra vez, sin importar cuántos cogs están funcionando, en lugar de mantener el criterio de sincronización. 1.8. Los recursos compartidos Hay dos tipos de recursos compartidos, o "recursos," en el Propeller: 1) común, y 2) mutuo-exclusivo. Los recursos comunes se pueden emplear en cualquier momento por cualquier número de Cogs. Los recursos mutuo-exclusivos se pueden alcanzar por cualquier Cog, pero solamente un Cog a la vez. Los recursos comunes son los pines de E/S y el contador del sistema. El resto de los recursos compartidos son mutuoexclusivos por naturaleza y el acceso a ellos es controlado por el Hub. 1.9. El reloj del sistema El reloj del sistema es el oscilador principal o central para casi todos los componentes del Propeller. La señal del reloj del sistema se proporciona a partir de una de las tres posibles fuentes: 1) 2) 3)

El oscilador interno de RC El circuito PLL El oscilador de cristal (un circuito interno que es alimentado por un cristal externo). La fuente se determina en los ajustes del registro CLK, que es seleccionable en tiempo de ejecución. Los únicos componentes que no utilizan el reloj del sistema directamente son el Hub y el Bus, que dividen por 2 el reloj del sistema.

1-5


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

1.10. Cogs (Procesadores) El Propeller contiene ocho procesadores, llamados Cogs, numerados del 0 al 7. Cada Cog contiene los siguientes componentes: un procesador, RAM local de 2 KB configurados como 512 registros (512 x 32 bits), dos Asistentes de E/S y PLLs, un generador video, registro de salida de E/S, registro de dirección de E/S, y otros registros no mostrados en el diagrama. Cada Cog puede ejecutar tareas independientes. Los ocho Cogs se manejan desde la misma fuente de reloj, el reloj del sistema, así pueden mantener la misma referencia del tiempo y los Cogs activos pueden ejecutar instrucciones simultáneamente. También pueden tener acceso a los mismos recursos compartidos, como los pines de E/S, la RAM global, y el contador del sistema. Los Cogs se pueden arrancar y parar en el tiempo de ejecución y se pueden programar para realizar tareas simultáneamente, independientemente o con la coordinación de otros Cogs a través de la RAM principal. Sin importar la naturaleza de su uso, un diseñador de Aplicaciones Propeller tiene un control completo sobre cómo y cuándo se utiliza cada Cog. Este método autoriza al desarrollador para delegar la sincronización, el consumo de energía, y la respuesta de su aplicación embebida. Cada Cog tiene su propia RAM, llamada Cog RAM, que contiene 512 registros de 32 bits cada uno. La Cog RAM se compone de RAM de propósito general, a excepción de los 16 últimos registros, que son registros de propósito especial, según lo expuesto en la Tabla 1-2. La Cog RAM se utiliza para código ejecutable, datos, variables, y las 16 últimas localizaciones sirven como interfaz al contador del sistema, a los pines de E/S, y a los periférico locales del Cog. Cuando un Cog arranca, las posiciones comprendidas entre la 0 ($000) y la 495 ($1EF) se cargan secuencialmente de la RAM principal/ROM mientras que sus posiciones de propósito especial, desde 496 ($1F0) a 511 ($1FF), se inicializan a cero. Después de la carga, el Cog comienza a ejecutar las instrucciones, comenzando por la posición 0 de la Cog RAM. Continúa ejecutando código hasta que se pare o se reinicie por sí mismo u otro Cog, o se ejecute un reset.

1-6


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

Nota 1: Sólo accesible como Registro Fuente (ej: MOV DEST,FUENTE) Nota 2: Reservado para uso futuro. Cada registro de propósito especial se puede acceder por los siguientes métodos: 1) Por su registro físico de direcciones 2) Por sus sus nombres predefinidos 3) Indirectamente, en lenguaje Spin, a través de una variable de array de registros, SPR, con un índice de 0 a de 15 o PAR a VSCL. Los siguientes son ejemplos de ensamblador para el Propeller: MOV $1F4, #$FFFF MOV OUTA, #$FFFF

'Poner OUTA todo a unos 'Lo mismo que arriba

Los siguientes son ejemplos en lenguaje Spin: SPR[$1F4] := $FFFF OUTA := $FFFF SPR[OUTA] := $FFFF

'Poner OUTA todo a unos 'Lo mismo que arriba 'Lo mismo que arriba

1.11. El Hub Para mantener la integridad del sistema, los recursos mutuo-exclusivos no deben ser accedidos por más de un Cog a la vez. El Hub mantiene esta integridad controlando el acceso a los recursos mutuo-exclusivos, dando a cada Cog un turno para acceder a ellos de forma "round robin" desde el Cog 0 a el Cog 7 y volviendo al Cog 0 otra vez. El Hub y el Bus que lo controla, funcionan a la mitad de la frecuencia del reloj del sistema. Esto significa que el Hub da a acceso al Cog a los recursos mutuo-exclusivos una vez cada 16 ciclos de reloj del sistema. Las instrucciones del Hub, las instrucciones de ensamblador del Propeller que tienen acceso a recursos mutuoexclusivos, requieren 7 ciclos para ejecutarse, pero primero necesitan ser sincronizadas en el comienzo de la Ventana de Acceso del Hub. Necesita como máximo 15 ciclos (16 menos 1, si acabamos de perderlo) para sincronizarse a la Ventana de Acceso del Hub, más 7 ciclos para ejecutar la instrucción del Hub, así que las instrucciones del Hub consumen de 7 a 22 ciclos para completarse. Las Figuras 1-5 y 1-6 muestran ejemplos donde el Cog 0 tiene una instrucción Hub para ejecutar. La Figura 1-5 muestra el escenario del mejor-caso; la instrucción Hub está lista justo en el comienzo de la Ventana de Acceso de ese Cog. La instrucción Hub se ejecuta inmediatamente (7 ciclos) dejando los 9 ciclos adicionales para otras instrucciones antes de que llegue la siguiente Ventana de Acceso del Hub.

Figura 1-5.- Interacción entre Cog/Hub en el escenario del caso mejor, cuando la instrucción Hub está lista justo al comienzo de la Ventana de Acceso al Cog 0.

1-7


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

La Figura 1-6 muestra el peor caso; la instrucción Hub está lista justo en el siguiente ciclo antes del comienzo de la Ventana de Acceso del Cog 0; justo acaba de perderlo. El Cog espera hasta que la siguiente Ventana de Acceso del Hub (15 ciclos más adelante) entonces la instrucción del Hub se ejecuta (7 ciclos), sumando un total de 22 ciclos para esa instrucción del Hub. Una vez más, hay 9 ciclos adicionales después de que llegue la instrucción del Hub para que otras instrucciones se ejecuten antes de la siguiente Ventana de Acceso del Hub. Para conseguir la mayor eficacia en las rutinas de ensamblaje del Propeller que tienen acceso frecuente a recursos mutuo-exclusivos, puede ser beneficioso interpolar instrucciones del no-Hub con instrucciones del Hub con el fin de disminuir el número de los ciclos que esperan la siguiente Ventana de Acceso del Hub. Como la mayoría de las instrucciones de ensamblador del Propeller necesitan 4 ciclos, se podrían ejecutar dos de estas instrucciones entre instrucciones contiguas de Hub.

Figura 1-6.- Interacción Cog/Hub en el escenario del peor caso. Hay que tener presente que una instrucción del Cog en el Hub en particular, no interfiere, de ninguna manera, con las instrucciones de otro Cog gracias el mecanismo del Hub. El Cog 1, por ejemplo, puede comenzar una instrucción Hub durante el ciclo de reloj del sistema 2, solapando posiblemente su ejecución con el Cog 0 sin ningún efecto perjudicial. Mientras tanto, el resto de los Cogs pueden continuar ejecutando instrucciones del noHub, o aguardando sus Ventanas individuales de Acceso del Hub sin importar lo que están haciendo los otros.

1.12 Pines de E/S El Propeller tiene 32 pines de E/S, 28 de los cuales están destinados para fines de propósito general. Cuatro pines de E/S (28 - 31) son de propósito especial durante el arranque y luego están disponibles para usos generales. Después del arranque, cualquier pin de E/S se puede utilizar por cualquier Cog en cualquier momento puesto que el conjunto de pines de E/S es un recurso común. Es tarea del desarrollador de la aplicación asegurarse que dos Cogs no coincidan utilizando el mismo pin de E/S durante el tiempo de ejecución. Cada Cog tiene su propio registro direcciones de E/S de 32 bits y su registro salida de E/S de la misma longitud. El resultado para la configuración de un pin de E/S sigue las siguientes reglas simples: 1. Un pin es una entrada solo de Cog no activos que lo fija a una salida. 2. Un pin tiene salida a nivel bajo sólo si todos los Cogs activos que se fijan como salida están también a nivel bajo. 3. Un pin tiene salida a nivel alto si algún Cog activo que se fija como salida está también a nivel alto. La Tabla 1-3 muestra algunas combinaciones posibles de la influencia de los Cogs en un pin particular de E/S, en este ejemplo es el P12. Para la simplificación, estos ejemplos asumen que es el bit 12 del hardware de E/S de cada Cog, con excepción de su registro de la salida de E/S, están inicializados a cero (0).

1-8


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

Cualquier Cog al ser desactivado deja su registro de direcciones y sus estados influenciando al estado final de los pines de E/S que los restantes Cogs activos también tiene su propio registro de 32 bits de entrada. Este registro de entrada es cada vez que se lee, los estados reales de los pines de E/S se leen, sin importar salida.

www.microcontroladores.com info@microcontroladores.com

de salida puestos a cero, no están controlando. Cada Cog realmente un pseudo-registro; su dirección de entrada o de

1.13 Contador del Sistema El contador del sistema es un contador global de 32 bits, que se incrementa cada ciclo de reloj del sistema. Los Cogs pueden leer el contador del sistema (vía su registro CNT) para realizar cálculos de sincronización y pueden utilizar el comando de WAITCNT para crear retrasos eficaces dentro de su proceso. El contador del sistema es un recurso común; los Cogs pueden leerlo simultáneamente. El contador del sistema no se inicia a cero en el arranque puesto que su uso práctico es para la sincronización diferenciada. Si un Cog necesita controlar el tiempo a partir de un momento específico, simplemente necesita leer y salvar el contador inicial en ese momento, y comparar los últimos valores del contador con ese valor inicial. 1.14 Registro CLK El registro de CLK es el de control de configuración del reloj del sistema; determina la fuente y las características del Reloj del Sistema. Más exactamente, el registro de CLK configura el oscilador RC, el reloj PLL, el oscilador de cristal, y los circuitos del selector del reloj. (Ver la Figura 1-4). Es configurado en el tiempo de compilación por la declaración CLKMODE y es escribible en el tiempo de ejecución con el comando CLKSET. Siempre que se escriba el registro de CLK ocurre un retraso global de unos 100 µs. Siempre que se modifica este registro, una copia del valor escrito se debe poner en la posición del valor del Modo Reloj (que es BYTE[4 ] en RAM principal) y la frecuencia de reloj principal resultante se debe escribir en la posición del valor de la frecuencia de reloj (que es LONG[0 ] en RAM principal), de modo que los objetos que se refieren a estos datos tengan información actual para sus cálculos de la sincronización. (ver CLKMODE y _ XINFREQ) Cuando es posible, se recomienda utilizar el comando de CLKSET, que actualiza automáticamente todas las posiciones mencionadas con la información apropiada.

1-9


PROPELLER: EL GIGANTE DE 8 CABEZAS CapĂ­tulo 1: Arquitectura y funcionamiento

1-10

www.microcontroladores.com info@microcontroladores.com


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

1.15. Semáforos Hay ocho semáforos disponibles para facilitar el acceso exclusivo a los recursos definidos por el usuario entre los múltiples Cogs. Si un bloque de memoria va a ser utilizado por dos o más Cogs inmediatamente y ese bloque tiene más de un long (cuatro octetos), cada Cog tendrá que realizar múltiples lecturas y escrituras para recuperar o actualizar ese bloque de memoria. Esto conduce a la posibilidad de contención de lectura/escritura en ese bloque de memoria donde un Cog puede escribir mientras que otro está leyendo, dando por resultado malas interpretaciones y/o pérdidas de escritura. Los semáforos son bits globales accedidos a través del Hub con las siguientes instrucciones: LOCKNEW, LOCKRET, LOCKSET y LOCKCLR. Porque los semáforos solo pueden ser accedidos a través del Hub, sólo un Cog a la vez puede afectarlos, conformando todo esto un mecanismo eficaz de control. El Hub mantiene un inventario de los semáforos que estén en uso y sus estados actuales y de los Cogs que pueden comprobar, devolver, fijar, y resetear los semáforos, según lo que se precise durante tiempo de ejecución. 1.16 Memoria Principal La memoria principal es un bloque de 64 K bytes (16 K longs) que es accesible por todos los Cogs como recurso mutuo-exclusivo a través del Hub. Está formada por 32 KB de RAM y 32 KB de ROM. Los 32 KB de RAM principal son de propósito general y constituyen el destino de una “aplicación Propeller”, que puede ser descargada de un host o cargada de los 32 KB de EEPROM externa.

1-11


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

Los 32 KB de la ROM principal contienen todos los recursos del código y los datos vitales para la función del Propeller: definiciones del carácter, registro, funciones de contra-registro y de seno, el Boot Loader y el intérprete Spin. La organización de la memoria principal se muestra en la Figura 1-6.

Figura 1-6.- Estructura de la memoria ROM principal. 1.17. RAM Principal La primera mitad de la memoria principal es tipo RAM. Este espacio se utiliza para almacenar el programa, datos, variables y pila(s); todo lo cual se conoce como la Aplicación Propeller. Cuando un programa se carga en el chip, desde un host o desde una EEPROM externa, se escribe en todo el espacio de esta memoria. Las primeras 16 localizaciones, $0000 - $000F, contienen datos de la inicialización usados por el intérprete. El código ejecutable y los datos de su programa comenzarán en $0010 y se extenderán un cierto número de long. El área después del código ejecutable, que se extiende hasta $7FFF, se utiliza como lugar dedicado a contener variables y espacio de pila. Hay dos valores interesantes almacenados en el área de la inicialización para el programa: el long en $0000 contiene la frecuencia de reloj principal inicial, en Hercios, y el siguiente byte $0004 contiene el valor inicial escrito en el registro CLK. Estos dos valores pueden ser de leídos/escritos usando sus direcciones físicas (LONG[$0 ] y BYTE[$4 ]) y también pueden ser leídos usando sus nombres predefinidos (CLKFREQ y CLKMODE). Si se cambia el registro de CLK sin usar el comando de CLOCKSET, también se necesitará poner al día estas dos posiciones de modo que los objetos que se refieren a ellas tengan información actual.

1.18 ROM Principal La segunda mitad de la memoria principal es tipo ROM. Este espacio se utiliza para almacenar la definición de caracteres, funciones matemáticas, el Boot Loader y el intérprete Spin. 1.19 Definición de caracteres La primera mitad de la ROM contiene un sistema de 256 definiciones de carácter. Cada definición de carácter corresponde a 16 píxeles de ancho y 32 píxeles de alto. Estas definiciones de carácter se pueden utilizar para las presentaciones de vídeo, LCD gráfico, impresión, etc. El juego de caracteres se basa en una norma “norteamericana/europea”, además existe un juego de caracteres especiales. Los caracteres especiales los forman conectores en forma de onda y bloques de constructores, símbolos griegos usados comúnmente en electrónica, y varias flechas. Figura 1-7.

1-12


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

Figura 1-7.- Caracteres fuente del Propeller. Las definiciones de caracteres se numeran de 0 a 255, de izquierda a derecha, de arriba a abajo en la Figura 1-7. En la ROM, se ordenan con cada par de caracteres adyacentes “par-impar” combinados juntos para formar 32 longs. El primer par de caracteres está situado en los octetos $8000-$807F. El segundo par ocupa los octetos $8080-$80FF, etcétera, hasta que el último par llena $BF80-$BFFF. La herramienta Propeller incluye una tabla interactiva de caracteres que tiene una ROM Bitmap (mapa de bits) que muestra donde reside cada carácter en la ROM. Los pares de caracteres están combinados fila-por-fila de tal forma que los 16 píxeles horizontales de cada carácter se espacian y se interpolan con sus vecinos y así al carácter par le corresponden los bits 0, 2, 4... 30, y el carácter impar los bits 1, 3, 5... 31. Los píxeles extremos izquierdos están en los bits más bajos, mientras que los píxeles derechos están en los bits más altos, según lo mostrado en la Figura 1-8. Esto forma un long (4 octetos) para cada fila de píxeles para el par del carácter. Todo esto se combina con la selección de color para exhibir el carácter par o el impar.

Figura 1-8.- Interpolación de caracteres en el Propeller. Algunos códigos de carácter tienen significados concretos, como 9 para el tabulador, 10 para avance de línea, y 13 para el retorno del carro. Estos códigos de carácter invocan acciones y no se comparan a las definiciones estáticas del carácter. La Figura 1-9 se muestra un ejemplo de un botón con los bordes biselados 3D hechos de algunos de estos caracteres.

Figura 1-9.- Ejemplo de un botón con los bordes biselados 3D.

1-13


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 1: Arquitectura y funcionamiento

www.microcontroladores.com info@microcontroladores.com

La herramienta del Propeller incluye y usa la fuente True Type® de Parallax que sigue el diseño de la fuente Propeller embebida en hardware. Con esta fuente, y la herramienta del Propeller, se pueden incluir diagramas esquemáticos, diagramas de coordinación y otros diagramas en código fuente de la aplicación. 1.20 Tablas de registro y contra-registro Las tablas de registro y de contra-registro son útiles para convertir valores entre formato numérico y formato exponencial. Cuando los números se codifican en forma exponencial, las operaciones simples matemáticas adquieren efectos más complejos. Por ejemplo ' add ' y ' subtract' se convierten en ' multiply ' y ' divíde'. ‘Shift left' se convierte en ' square' y la ' Shift right ' se convierte en ‘square-root '. 'Divide by 3 ' (dividir entre 3) se convertirá en ' cube root ' (raíz cúbica). Una vez que el exponente s e convierta de nuevo a un número, el resultado será evidente. 1.21 Tabla del seno La tabla del seno proporciona 2.049 muestras de seno de 16 bits que van de 0° hasta el 90° inclusive (resolución de 0.0439°). Los valores del seno para el resto de los cuadrantes que cubren de 91° a 359° se pueden calcular a partir de transformaciones en esta tabla del seno de un cuadrante. La tabla del seno se puede utilizar para los cálculos relacionados con los fenómenos angulares. 1.22 Boot Loader e Intérprete Spin La última sección de la ROM principal contiene el Boot Loader del Propeller y los programas del intérprete Spin. El Boot Loader es responsable de inicializar el Propeller en el encendido/reset. Cuando comienza el proceso de arranque, el Boot Loader se carga en el Cog 0 de la RAM y el Cog ejecuta el código que comienza en la posición 0. El programa del Boot Loader primero chequea el host y los pines de comunicación desde code/data a download/upload de la EEPROM, procesa dicha información y finalmente lanza el programa del Intérprete Spin en el Cog 0 de la RAM (que se sobreescribe) para ejecutar la aplicación Propeller del usuario, o para poner el Propeller en modo parada. El programa del Intérprete Spin recupera y ejecuta la aplicación Propeller de la RAM Principal. Esto puede precisar lanzar Cogs adicionales para ejecutar más código Spin o código ensamblador del Propeller, si lo solicita la aplicación.

1-14


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

CAPITULO 2: MANEJO Y DESARROLLO DE APLICACIONES 2.1. LA CONCEPCIÓN DEL SOFTWARE Este capítulo describe las características del software que utiliza el Propeller, comenzando por su gestación y su estructura, pasando por la organización y el propósito de la pantalla del software, los detalles de las funciones del menú y las características avanzadas, para terminar con las teclas rápidas. Los ingenieros de desarrollo de Parallax han utilizado muchos ambientes durante más de 20 años. En bastantes ocasiones han tenido que resolver preguntas tales como: • • • •

¿Sería más amigable el sistema haciendo que la característica "x" fuera más fácil de buscar/invocar?. ¿Dónde se colocan los archivos del proyecto y por qué hay tantos? ¿Se podrá instalar/recompilar/mantener este sistema en otra computadora, en los próximos años? ¿No hay una solución más económica?

Estas dudas han conducido a tomar la determinación de crear herramientas sencillas y baratas para los productos Parallax. La herramienta para el Propeller fue diseñada con la idea de proporcionar muchas funciones útiles mientras se mantiene un sencillo y constante ambiente de trabajo que anima al desarrollo rápido y fácil de los objetos de los programas para el Propeller. El software del Propeller consta de: a) un archivo ejecutable, b) unos archivos de ayuda on-line y c) archivos de la biblioteca del Propeller, todo ello almacenado en la misma carpeta por el instalador, que por defecto es: C:\Program Files\Parallax Inc\Propeller. El fichero ejecutable "Propeller.exe" puede ser copiado y ejecutado desde cualquier carpeta en la computadora. Cada archivo de la biblioteca (archivos con extensión "spin") es un objeto independiente, disponible para utilizar en los proyectos Propeller, con código fuente y documentación incorporado. Son realmente archivos de texto, tipo ANSI o Unicode-encoded, que pueden ser corregidos en cualquier editor de texto que soporte dicho tipo de codificación; incluso el Notepad de Windows® 2000 (y posteriores) soporta el ANSI y los archivos de texto Unicode-encoded. Es posible escribir la documentación de usuario para un objeto dentro del archivo fuente del objeto. Esto significa que habrá menos archivos para mantener y una probabilidad más alta que la documentación permanezca en armonía con la revisión del código fuente. Para permitir este proceso, se han creado: • • •

Dos tipos de comentarios en el fuente: 1º) los comentarios del código, y 2º) comentarios de documento (dentro del código, pero pensado para SER LEÍDO con la opción de "vista de documentación". El modo de “vista de la documentación" que extrae la documentación del código fuente de un objeto para los propósitos de visualización. Una fuente especial, la fuente Parallax, que contiene caracteres especiales para elementos como diagramas esquemáticos, diagramas de tiempo y tablas que hay en la documentación del objeto.

La fuente Parallax es una fuente True Type® construida en la Herramienta del Propeller ejecutable. Fue diseñada en el mismo estilo que la fuente construida en la ROM del chip Propeller. Usando los caracteres especiales de la fuente, la documentación del objeto puede incluir los diagramas interesantes en ingeniería tales como los de la Figura 2-1.

2-1


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Figura 2-1.- Esquemas realizados con los caracteres especiales. Después de arrancar la herramienta Propeller al menos una vez, esta fuente está disponible para otros programas de esa computadora de modo que se pueden ver estos diagramas especiales usando otros editores de texto, tales como Notepad, o en el software para email, con tal que soporte el texto Unicode-encoded (requisito de los caracteres especiales). Cada objeto que se crea para el proyecto también será almacenado en el mismo formato que los archivos de biblioteca (con una extensión del "spin") pero en el directorio de trabajo que se seleccione. Todo esto está diseñado para incitar a que se comparta y se aprenda de objetos existentes, ya sean diseñados por nosotros o por otros usuarios de los productos Propeller. 2.2. ORGANIZACIÓN DE LA PANTALLA La ventana principal del software de la herramienta Propeller está partida en cuatro secciones, llamadas "paneles" cada uno de ellos tiene una función específica. Figura 2-2.

2-2


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Figura 2-2.- La ventana principal del software de la herramienta Propeller contiene cuatro secciones importantes llamados "paneles." Los paneles uno, dos y tres de la Figura 2-2 corresponden a la parte del explorador integrado. El explorador integrado está situado en el panel 4, que proporciona las vistas del proyecto que se está trabajando así como carpetas y archivos en disco. Una barra alta vertical separa al explorador integrado del panel del editor, que se puede reajustar su tamaño con el ratón en cualquier momento. El explorador integrado puede incluso ser ocultado reajustando su tamaño hasta cero, seleccionando File → Hide Explorer, o pulsando Ctrl+E. Las opciones del menú y las teclas rápidas cambian el modo del Explorador Integrado entre visible e invisible.

Figura 2-3.- El Explorador integrado y sus componentes pueden ser reajustados en tamaño con las barras de división. 2.2.1. Panel 1: Panel de visualización de objetos. El lenguaje Spin está basado en objetos y un proyecto Propeller se puede componer de múltiples objetos. La pantalla del visor de objetos muestra la vista jerárquica del proyecto que se compiló con éxito por última vez. Usando la vista del objeto, se puede determinar qué objetos se utilizan, cómo encajan con otros objetos, su localización física en disco (carpeta del trabajo, carpeta de biblioteca o editor), optimización de la redundancia (si hubiera) y cualquier potencial de colisión entre objetos.

2-3


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

2.2.2 Panel 2: Campo de carpetas recientes y lista de carpetas El panel 2 contiene dos componentes: 1) el campo de carpetas recientes, y 2) la lista de carpetas. Estos dos componentes trabajan juntos para proporcionar el acceso de navegación a las unidades de disco disponibles en la computadora. La lista de carpetas exhibe una vista jerárquica de carpetas dentro de cada unidad de disco y se puede manipular de manera similar al del panel izquierdo del explorador de Windows®. El campo de carpetas recientes (sobre la lista de la carpeta) proporciona una lista desplegable de carpetas especiales así como de carpetas más recientes. El primer ítem en la lista de carpetas recientes es la "biblioteca Propeller" y la "biblioteca Demo Propeller." Esos archivos se incluyen al instalar la herramienta Propeller. Seleccionar el modo de mostrar carpetas recientes es una manera de navegar de forma rápida a las carpetas mas comúnmente usadas del proyecto Propeller entre un sistema grande de carpetas sin relación. 2.2.3. Panel 3: La lista archivos y filtro de archivos El panel 3 contiene dos componentes: 1) la lista archivos, y 2) el campo del filtro. La lista de archivos muestra todos los archivos contenidos en la carpeta seleccionada de la lista de la carpeta que emparejan los criterios del filtro del campo del filtro. La lista de archivos se puede utilizar de una manera similar al del panel derecho del explorador de Windows. El campo del filtro (debajo de la lista de archivos) proporciona una lista desplegable de las extensiones de archivo, llamados filtros, para mostrar la lista de archivos. Por defecto, sólo se pueden ver los archivos Spin (con extensiones de archivo "spin") pero también se puede elegir que se muestren los archivos de texto o cualquier archivo. Si se navega a una carpeta y no se ven los archivos esperados, se recomienda revisar el campo filtro. Los archivos en la lista de archivos se pueden abrir en el editor de las siguientes formas: 1) haciendo “doble-click” sobre ellos, 2) seleccionándolos y arrastrándolos al panel del editor o 3) “clickando” con el botón derecho y seleccionando Open del menú rápido. 2.2.4. Panel 4: Panel del editor El panel 4 es el panel del editor que proporciona una vista de los archivos de código fuente Spin que se hayan abierto y esta área es donde se puede repasar, corregir, o manipular todos los objetos de código fuente del proyecto. Cada archivo (objeto del código de fuente) abierto se organiza dentro del panel del editor como una pestaña individual con el nombre del archivo que contiene. La pestaña activa del editor destaca de forma diferentemente que el resto. Se puede tener tantos archivos abiertos a la vez como se quiera, el límite sólo lo determina la capacidad de la memoria. Se puede cambiar entre pestañas abiertas de las siguientes formas: 1) clickando en la etiqueta deseada con el ratón, 2) presionando Alt+CrsrLeft o Alt+CrsrRight, o 3) presionando Ctrl+Tab o Ctrl+Shift+Tab. Si se deja el cursor del ratón sobre una pestaña bastante tiempo se mostrará un mensaje con la ubicación completa y el nombre del archivo que representa.

Figura 2-4.- Muestra una etiqueta al pasar el ratón para ver el path completo y el nombre del fichero que contiene la tabla. El editor puede mostrar el código fuente de 4 formas: 1) fuente completa, 2) condensada, 3) resumen, o 4) documentación. El modo de la vista puede ser considerado o cambiado, en cada pestaña, 1) seleccionando el

2-4


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

botón respectivo con el ratón, 2) presionando Alt+Up o Alt+Down, 3) presionando Alt+<letra>; donde <letra> es la letra de acceso rápido de visión deseada, o 4) presionando Alt y moviendo la rueda del ratón para arriba o abajo. No se podrá acceder a la vista de documentación si el objeto no se puede compilar completamente en ese momento. Puesto que un proyecto puede consistir en muchos objetos, desarrollar un proyecto puede ser costoso a menos que se puedan ver el objeto en el que se está trabajando y el objeto sobre el que se está interactuando. El panel del editor ofrece ayuda permitiendo que cada editor pueda ser arrastrado y desplegado en distintas localizaciones. Por ejemplo, una vez que los objetos estén abiertos, se puede utilizar el botón izquierdo del ratón para seleccionar y para arrastrar la pestaña de un objeto hacia la mitad inferior del panel del editor y dejarlo allí.

Paso 1: Para ver más detalles del código fuente del objeto, mantener clickado el ratón y arrastrar una pestaña del editor a una parte más baja del panel del editor.

Paso 2: Soltar el botón para dejar la pestaña del editor. La pestaña y su contenido aparecen ahora en la nueva región.

2-5


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Paso 3: Repetir los pasos 1 y 2 para otras pestañas y reajustar el tamaño de ambas regiones usando el divisor horizontal entre ellas.

Figura 2-4: Viendo y arreglando objetos El tamaño vertical de estas dos regiones se puede cambiar arrastrando el divisor horizontal que las separa. Por supuesto, los objetos que se están interconectando pueden ser vistos en cualquier modo, mientras que el objeto que se está desarrollando requiere la vista del fuente completa (la única visión editable). El panel del editor permite incluso que sus pestañas sean arrastradas totalmente fuera de la herramienta del Propeller. Cuando se hace esto, las nuevas pestañas ocupan una ventana nueva y se pueden manipular independientemente de la ventana de aplicación de la herramienta del Propeller. Esto es particularmente útil para el desarrollo en los ordenadores con más de un monitor; las pestañas se pueden arrastrar de la aplicación que se muestra en un monitor y dejarla sobre el escritorio de un segundo monitor.

Paso 1: Si el espacio de escritorio lo permite, se puede incluso arrastrar las pestañas del editor fuera de la misma aplicación; clickando el ratón y arrastrando una pestaña del editor a una región fuera de la herramienta del Propeller.

2-6


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Paso 2: Soltar el botón para dejar la pestaña del editor; se convertirá en una ventana independiente de la herramienta del Propeller. Se pueden arrastrar más pestañas de esta nueva forma.

Figura 2-5: Arreglando objetos La barra de estado que se encuentra en la parte inferior de la herramienta Propeller, se divide en seis paneles, cada uno de ellos muestra la información útil de las distintas etapas del proceso del desarrollo. El panel 1 de la barra de estado muestra siempre la posición de la fila y columna del cursor activo del editor.

Figura 2.6: Barra de estado Lo que se muestra en el panel 2 es el estado modificado del editor actual: 1) en blanco, que significa no modificado, 2) modificado, o 3) sólo lectura. El panel 3 muestra el modo actual de escritura: 1) alineado (por defecto para el código Spin), 2) Insert (por defecto para código no-Spin) o 3) sobre escribir. El modo de escritura puede ser cambiado presionando la tecla Insert. El panel 4 muestra el estado de compilación del editor actual: 1) en blanco significa no-compilado, o 2) compilado. Este panel indica si el código fuente que representa todavía está en la forma en la que fue compilado por última vez. Si el código no se ha cambiado, este panel dirá "Compiled." El panel 5 contiene la información de contexto sobre el código fuente del panel actual en el caso de que ese código no haya cambiado desde la última vez que se compiló. Moviendo el cursor dentro de los bloques PUB/PRI se puede ver la información perteneciente a esta región. El panel 6 muestra mensajes temporales sobre la operación mas reciente. En este área de la barra de estado se exhibe el mensaje de error, si lo hay, de la última compilación realizada. En dicha área también se indica las compilaciones satisfactorias, los cambios del tamaño del fuente y otros estados.

2-7


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

2.3. COMPONENTES DEL MENÚ

Menú archivo New Open...

Crea una nueva pestaña que contiene un editor vació. Las pestañas existentes no se ven afectadas. Abre un archivo en un nuevo editor.

Open From...

Abre un archivo en un nuevo editor de la carpeta mas recientemente utilizada.

Save

Salva el contenido de la pestaña actual usando el nombre del archivo existente, si es aplicable.

Save As...

Salva el contenido de la pestaña actual con un nuevo

Save To...

Salva el contenido de la pestaña en disco en la carpeta mas recientemente utilizada usando el dialogo Save As…

Save All

Salva todo lo no guardado en disco usando sus nombres existentes, si son aplicables.

Close

Cierra la pestaña actual.

Close All

Cierra todas las pestañas del editor.

Select Top Object File…

Selecciona el fichero objeto superior del proyecto actual.

nombre.

Archive ÆProyect...

Recoge todos los objetos y ficheros de datos para el proyecto mostrado en Object View y los almacena en un archivo comprimido (zip) junto con un fichero "readme" que contiene la información del archivo y de la estructura.

ÆProyect + Propeller Tool...

Realiza la misma tarea que la anterior pero agrega la herramienta Propeller ejecutable al archivo comprimido.

Hide/Show Explorer

Muestra o esconde los paneles integrados del explorador (lado izquierdo de la ventana del editor).

Print Preview...

Muestra una vista preliminar de la salida antes de imprimir.

Print...

Imprime el contenido actual de la pestaña.

<recent files>

El área del menú entre Print... y Exit muestra hasta un máximo de diez archivos mas recientemente accedidos. Solo hay que seleccionar uno de estos archivos para abrirlo.

Exit

Cierra la herramienta Propeller.

2-8


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Menú Edit Undo

Deshace la última acción editable en la pestaña. Cada pestaña editable tiene su propio buffer de históricos de Undo. Están permitidas muchas acciones de Undo, limitado solamente por memoria.

Redo

Rehace la acción deshecha en la pestaña actual. Cada editor tiene su propio buffer de históricos de Redo. Están permitidas muchas acciones de Redo, limitado solamente por memoria.

Cut

Borra el texto seleccionado del editor actual y lo copia al portapapeles de Windows.

Copy

Copia el texto seleccionado del editor al portapapeles de Windows.

Paste

Pega el texto del portapapeles de Windows y lo pega en el editor actual en la posición en la que se encuentre el cursor.

Select All

Selecciona todo el texto del editor actual.

Find/Replace...

Abre el diálogo de Buscar/Reemplazar (Find/Replace)

Find Next

Busca la siguiente ocurrencia de la ultima secuencia de caracteres introducida en el dialogo Find/Replace.

Replace

Sustituye la selección actual por la secuencia de caracteres introducida en el campo del reemplazar (Replace) del diálogo de Find/Replace.

Go To Bookmark

Va al bookmark 1, 2, 3... (visible solamente cuando se muestran los bookmarks).

Text Bigger

I

Incrementa el tamaño de la fuente de todos los editores.

Text Smaller

Decrementa el tamaño de la fuente de todos los editores.

Preferences...

Abre la ventana de preferencias. Los usuarios pueden modificar los ajustes para requisitos particulares dentro de la herramienta Propeller usando esta característica.

Run Menu Compile Current ÆVisión Info...

Compila el código de fuente del editor actual y si la compilación es satisfactoria, muestra el formulario de Object Info con los resultados. El formulario de Object Info exhibe muchos detalles sobre el objeto incluyendo la estructura del objeto, el tamaño de código, el espacio variable, el espacio libre y optimizaciones de la redundancia.

ÆUpdate Status

El estado de la actualización compila código de fuente de la pestaña actual y si es satisfactoria, pone al día el estado Info en la barra de estado para cada objeto del proyecto.

ÆLoad RAM +Run

Compila código de fuente del editor actual y si es satisfactoria, descarga la aplicación resultante en el RAM del chip Propeller y lo ejecuta.

2-9


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

ÆLoad EEPROM +Run

Compila código de fuente del editor actual y si es satisfactoria, descarga la aplicación resultante en la EEPROM ( y RAM) del chip Propeller y lo ejecuta.

ÆLoad EEPROM

Compila código de fuente del editor actual y si es satisfactoria, descarga la aplicación resultante en la EEPROM del chip Propeller pero no lo ejecuta. El siguiente reset del chip Propeller hara que se ejecute desde la EEPROM.

Compile Top

Este menú es igual que Compile Current, excepto que la compilación comienza del archivo designado como el "fichero objeto superior" (“Top Object File.”)

ÆView Info... ÆUpdate Status ÆLoad RAM + Run Æ Load EEPROM + Run Æ Load EEPROM Identify Hardware...

Escanea los puertos disponibles para el chip Propeller y si encuentra, muestra el numero de puerto al que se conecta y la versión hardware.

Help Menu Propeller Tool...

Muestra la ayuda on-line sobre la herramienta Propeller.

Spin Languaje...

Muestra la ayuda on-line sobre el lenguaje Spin.

Assembly Lenguaje...

Muestra la ayuda on-line sobre el lenguaje ensamblador del Propeller.

Example Projects...

Muestra la ayuda on-line que contiene proyectos del Propeller del ejemplo.

View Carácter Chart...

Muestra la Tabla de caracteres interactiva de Parallax. Esta Tabla de caracteres muestra el juego de caracteres fuente de Parallax en tres visiones posibles: Orden estándar, BITMAP de la ROM y orden simbólica. La orden estándar es la orden estándar del ANSI. La BITMAP de la ROM muestra cómo los datos de carácter se organizan en la ROM del chip Propeller. La orden simbólica enumera los caracteres en una orden categórica (es decir: los caracteres de la alfa, los caracteres numéricos, puntuación, los símbolos esquemáticos, etc).

View Parallax Website...

Abre el Web site de Parallax usando el navegador web por defecto de la computadora.

E-mail Parallax Support...

Abre el software del email por defecto de la computadora y abre un nuevo mensaje dirigido al soporte Parallax.

About...

Muestra la ventana About que contiene los detalles de la herramienta Propeller.

2-10


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Diálogo Find/Replace Este diálogo se usa para buscar o reemplazar texto en el editor de la pestaña actual.

Figura 2-7: Dialogo Find/Replace Find: Es el campo donde se introduce la secuencia de caracteres que se desea buscar. Si se selecciona una palabra o frase del editor, esta se introducirá automáticamente en el campo Find al abrir este dialogo. Este campo recuerda las últimas diez búsquedas realizadas. Replace: Es el campo donde se introduce la secuencia de caracteres que se quieren sustituir por la secuencia del campo Find. El campo Replace recuerda las diez últimas cadenas de caracteres introducidas en el. Match Agrupa controles de cómo debería buscarse la secuencia introducida en el campo Find. Las opciones Match son: 1) Whole Words Æpalabras enteras, 2) Case Æ sensible a mayúsculas y minúsculas, y 3) With Wildcards Æcon comodines. Origin Agrupa controles que indican desde donde se desea comenzar la busqueda; si desde el principio del archivo (Top) o desde la posición del cursor (Cursor). Nota: La opción "Top" cambia al "Bottom" (abajo) si fija el grupo de Direction a Backwards (al revés). Scope Agrupa controles que indican el alcance de la búsqueda; si se quiere buscar el todo el archivo () o solo en la parte seleccionada. Por defecto se realiza la búsqueda en todo el archivo y solo se habilitan estas opciones cuando existe una región seleccionada en el archivo. En este caso Scope tomaría automáticamente el valor Selection. Direction Agrupa los controles que indican la dirección de la búsqueda; Fordward (hacia delante) o Backward (hacia detrás). Si se elige la opción Backward la opción Top (arriba) del campo Origin cambia a Bottom (abajo), que significa que el origen de la búsqueda es el final del archivo. Boton Find El botón de Find inicia el proceso de búsqueda basado en todos los ajustes realizados en el diálogo Find/Replace. Si el texto del editor empareja los criterios, se selecciona y el texto del botón Find cambia a Find Next (Buscar Siguiente). También se puede utilizar la tecla F3, con o sin el diálogo de Find/Replace abierto, para realizar más búsquedas.

2-11


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Boton Replace Este botón se muestra activo únicamente si se ha introducido una secuencia de caracteres en el campo Replace y permite sustituir en contenido del ese por la secuencia del campo Find en el caso de que exista una coincidencia en el texto. Para sustituir se pueden utilizar tanto el botón Replace como la tecla F4. Después de realizar una sustitución es necesario pulsar el botón Find Next o F3 para poder realizar de nuevo un Replace. Si se mantiene presionada la tecla control (Ctrl) el botón Replace cambia a Find/Replace, que realiza las dos acciones, búsqueda y sustitución, a la vez. Para esto también se puede utilizar la combinación Ctrl+F4. Boton Replace All Este botón se muestra activo únicamente si se ha introducido una secuencia de caracteres en el campo Replace y permite sustituir todas las coincidencias encontradas en el texto. Al pulsar este botón, el dialogo se cierra y se muestra otro dialogo con el numero de ocurrencias encontradas y sustituidas. Boton Close Cierra el diálogo de Find/Replace. Vista de Objetos (Object View) El visor de objetos muestra una vista jerárquica del proyecto que se más recientemente compiló de forma satisfactoria. Hay dos vistas de objetos en la herramienta Propeller: 1) la vista de objetos en la parte superior del explorador integrado en la ventana de la aplicación principal y la vista de información de objetos en la parte superior izquierda del formulario del Object Info (se detalla mas adelante). Ambas vistas de objetos funcionan de una manera similar. La vista de objetos proporciona un feedback visual de la estructura de última compilación realizada con éxito así como la información para cada objeto dentro del proyecto compilado.

Figure 2-8: Ejemplo del visor de Objetos mostrando la estructura de la compilación del Producto ABC En la Figura 2-8 arriba, la vista del objeto indica la estructura de la aplicación de producto ABC. En este ejemplo, el objeto del producto ABC es el “fichero objeto superior”. Los nombres de objeto que se muestran son los nombres reales de los archivos sin la extensión. El nombre incluye su extensión solamente si es un archivo de datos y este nombre se mostraría en cursiva. Los iconos a la izquierda de cada nombre de objeto indican la carpeta en la cual reside el objeto. A continuación se muestran las cuatro posibilidades: (amarilla): El objeto está dentro de la carpeta del trabajo (azul): El objeto está dentro de la carpeta de la biblioteca (rayada): El objeto está en la carpeta del trabajo pero hay otro objeto con el mismo nombre que también se está utilizando de la carpeta de la biblioteca (hueca): El objeto no está en ninguna carpeta porque nunca no se ha salvado. Carpeta de trabajo La carpeta del trabajo (amarilla) es la carpeta donde existe el fichero objeto superior. Cada proyecto tiene una, y solamente una, carpeta del trabajo.

2-12


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Carpeta Librería La carpeta de librería (azul) es donde existen los objetos de librería de la herramienta Propeller, por ejemplo las que vinieron con el software de la herramienta Propeller. La carpeta librería es la carpeta por la que siempre comienza el ejecutable de la herramienta Propeller, y de cada objeto (archivo con extensión .spin) dentro de ella se considera ser un objeto de la librería. Carpeta rayada Los objetos rayados de indican que existe un conflicto de nombres entre objetos del mismo nombre que existen tanto en la carpeta del trabajo y como en la carpeta librería. Este objeto de mismo nombre puede ser: 1) una copia exacta del mismo objeto, 2) dos versiones del mismo objeto, o 3) dos objetos totalmente diversos que han coincidido en tener el mismo nombre. Independientemente de la situación, se recomienda resolver este problema potencial cuanto antes puesto que puede conducir a futuros problemas, como por ejemplo no poder utilizar las características de archivo. Carpeta Hueca Los objetos huecos indican que el objeto fue creado en el editor y nunca ha sido guardado en ninguna carpeta ni disco. Esta situación, como la mencionada antes, no es un problema inmediato pero puede conducir a problemas futuros si no se trata pronto. Para obtener información adicional de los objetos se puede usar el ratón para seleccionar un objeto. Si clickamos sobre un objeto de la Vista de Objetos, este, se abre en el panel del editor. El botón izquierdo abre ese objeto en la vista de fuente completa, el botón derecho abre la vista de documentación y el doble click abre el objeto y todos sus sub-objetos en la vista de fuente completa. Pasando el ratón sobre un objeto en la vista de objetos muestra una etiqueta con la información adicional para ese objeto. La Figura 2-9a muestra la etiqueta para el objeto del producto ABC. Esta etiqueta indica que 1) el objeto del producto del ABC es el fichero objeto superior del proyecto, 2) reside en la carpeta del trabajo, y 3) su path y nombre del archivo son: C:\Source\ABC Product.spin. De esta información se puede también deducir que la carpeta del trabajo para este proyecto es: C:\Source

Figura 2-9: Pasando el ratón sobre un objeto se Ver pestañas con información adicional La Figura 2-9b demuestra la etiqueta para el objeto Numbers: 1) es un fichero objeto (es decir: un objeto secundario), 2) él está en la carpeta de librería, y 3) su path y nombre de archivo: C:\Program Files\Parallax Inc\Propeller\Numbers.spin. De esta información se puede también deducir que la carpeta librería para este proyecto es: C:\Program Files\Parallax Inc\Propeller.

2-13


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Object Info La ventana del objeto Info muestra los detalles sobre el proyecto que se acaba de compilar con éxito usando la función Current/TopÆView Info…

Figura 2-10: La ventana del Objet Info muestra los detalles sobre "la compilación del proyecto del producto ABC".

Info Object View La vista del Objet Info funciona exactamente como la vista del objeto con algunas excepciones:

Al clickar en un objeto dentro de la vista del Objet Info actualiza el display del Objet Info con la información que pertenece a ese objeto Doble-click en un objeto dentro de la vista del Objet Info abre ese objeto en el panel del editor Los ficheros de datos no son seleccionables en la vista del Objet Info.

El panel del uso RAM El panel del uso RAM muestra la estadística sobre la asignación del RAM al objeto seleccionado actualmente en la vista del Objet Info. La barra horizontal da una visión global del RAM con su leyenda sobre los colores y detalles numéricos. Por ejemplo, la figura 2-10 muestra que el objeto del producto ABC consume 524 longs (2096 octetos) de espacio de programa y 12 longs (48 octetos) de espacio variable, dejando alrededor de 7k longs (los octetos del excedente 30k) libres. Reloj del Panel El panel del reloj, bajo del panel del uso del RAM, muestra los ajustes de reloj/oscilador del objeto seleccionado actualmente en la vista del Objet Info. Por ejemplo, la figura 2-10 muestra que el objeto del producto ABC configuró el reloj para RCFAST, aproximadamente 12 megaciclos y ninguna frecuencia de XIN.

2-14


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Vista Hex El botón Show/Hide de la ventana del Object Info, muestra u oculta la vista detallada de hexadecimal del objeto. Como se ve en el cuadro 2-11 de la página siguiente. La vista hexadecimal muestra los datos compilados reales del objeto, en hexadecimal, que se cargan en el RAM/EEPROM del Propeller.

Figura 2-11: Ejemplo de ventana del objeto Info Los botones bajo el display de la vista hexadecimal permiten descargar y cargar los datos actualmente exhibidos. Los primeros tres botones, Load RAM + Run, Load EEPROM + Run, y Load EEPROM, realizan la misma función que los ítems del menú Compile Current /Top de mismo nombre. Es importante observar que utilizan el objeto actual (el que está seleccionado en la vista del Objet Info) como la fuente a descargar. Los dos siguientes botones Save Binary File, y Save EEPROM File, guardan los datos hexadecimales del objeto actualmente seleccionado a un archivo en disco. Save Binary File guarda solamente la porción usada realmente por el objeto; los datos del programa, pero no el espacio variable o stack/free. Save EEPROM File salva la imagen entera de EEPROM, incluyendo el espacio variable y de stack/free. Se debe usar Save EEPROM File si se desea tener un archivo que se pueda cargar en un programador EEPROM para los propósitos de producción. 2.4. TABLA DE CARACTERES (CHARACTER CHART) La ventana de Tabla de caracteres esta disponible en HelpÆ View Character Chart… Muestra el juego de caracteres para la fuente de Parallax que es utilizada por la herramienta Propeller y también construida en la ROM del chip Propeller. Hay tres vistas en la tabla de caracteres: 1) orden estándar, 2) BITMAP de la ROM, y 3) orden simbólica. Orden Estándar El orden estándar, mostrado en el cuadro 2-12, muestra los caracteres en el orden que sigue el ANSI y es el usado típicamente por las computadoras modernas del día.

2-15


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Figura 2-12: Tabla de caracteres fuente Parallax en orden estándar La información de la parte de abajo de la ventana muestra el tamaño de fuente, en puntos, y la localización del carácter en el juego de caracteres en decimal, hexadecimal, y Unicode. Nota: El valor de Unicode es la dirección del carácter en el archivo de fuente verdadero de Type® que es utilizado por la herramienta del Propeller. Los valores decimales y hexadecimales son las direcciones lógicas del carácter en el juego de caracteres dentro del la chip Propeller y corresponden a esa localización en el juego de caracteres de ANSI usado por la mayoría de las computadoras. Bitmap ROM La figura 2-13, muestra los caracteres en una manera representativa de cómo se almacenan en la ROM del Propeller. Esta visión utiliza cuatro colores, blanco, gris claro, gris oscuro, y negro, para representar la configuración de bits de cada carácter.

Cada carácter, en la ROM del Propeller, se define con dos bits del color. Las filas de cada par de caracteres adyacentes se solapan en memoria con el fin de crear caracteres en tiempo de ejecución para dibujar botones 3D. La información en la parte de abajo de la ventana muestra el tamaño de fuente, en puntos, y el rango de dirección de los datos del píxel del carácter seleccionado en la ROM del Propeller.

Figura 2-13: Tabla de caracteres fuente Parallax en Bitmap ROM

2-16


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Orden Simbólica La orden simbólica muestra los caracteres dispuestos categóricamente. Esto es útil para encontrar los caracteres especiales en la fuente Parallax para representar líneas, flechas, y diagramas esquemáticos. Figura 214

Figura 2-14.- Caracteres para la orden simbólica.

2.5. MODOS DE VISIÓN, BOOKMARKS Y NÚMEROS DE LÍNEA Hay una serie de características construidas en la herramienta Propeller para poder navegar más rápidamente a ciertas regiones de código como pueden ser los modos de visión, los bookmarks y los números de línea. Los modos de visión Cada editor puede mostrar la fuente de un objeto en uno de cuatro modos de la visión, 1) fuente completa, 2) condensado, 3) resumen, y 4) documentación • • • •

La visión de la fuente completa muestra cada línea del código fuente del objeto y es la única visión que es que es editable. La visión condensada, oculta las líneas que contienen comentarios del código así como las líneas contiguas que están en blanco; mostrando únicamente el código compilable. La visión resumen muestra solamente las líneas de título del bloque (CON, VAR, OBJ, PUB, PRI, y DAT); una manera fácil para ver la estructura del objeto entero en un vistazo. La visión de documentación muestra la documentación del objeto generada por el copilador que se genera con los comentarios del código de fuente.

Cambiando a otra visión se puede localizar la rutina o la región del código deseada.

2-17


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

¿No puedes encontrar una rutina en un objeto?

Paso 1: Selecciona el modo Resumen Paso2: Clicka la línea de la rutina.

2-18


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Paso 3: Selecciona el modo de fuente completa otra vez; el código se reamplía alrededor de la línea del cursor, -oDoble-click en la línea deseada del paso 2.

Figura 2-15: Ejemplo de Modos de visión Bookmarks También se pueden fijar bookmarks en varias líneas en cada editor para saltar rápidamente a las localizaciones deseadas. La figura 2-16 muestra un ejemplo de dos bookmarks fijados en el margen del editor. Para activar bookmarks, se debe presionar Ctrl+B y clickar en el margen junto a la línea a la que se quiere poder navegar. De esta forma, desde cualquier sitio del código se puede navegar directamente a un Bookmark pulsando Ctrl+#, donde # es el número del bookmark al que se desea ir. Se pueden fijar hasta 9 bookmarks (1 – 9) en cada editor. Los bookmarks no se salvan con el código fuente; sin embargo, la herramienta Propeller recuerda los bookmark de los 10 últimos archivos accedidos.

Figura 2-16: Ejemplo del editor con los bookmarks habilitados y dos bookmarks fijados.

2-19


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Números de Línea Puede resultar fácil recordar una región de código por su número de línea. En cualquier momento, se pueden habilitar o deshabilitar los números de línea del editor. Las líneas se numeran automáticamente mientras se crean; son sólo un artículo visual y no se almacenan en el código de fuente. Aunque los números de línea compartan espacio con los bookmarks, son independientes el uno del otro y se pueden habilitar o deshabilitar individualmente. Los números de línea pueden ser impresos, si se quiere.

Figura 2-17: Ejemplo de un editor con los bookmarks y los números de línea habilitados Modos Edit Hay tres modos proporcionados por el panel del editor: 1) insertar (defecto), 2) alinear (disponible para el código de la vuelta solamente), y 3) sobrescribir. Se puede cambiar entre cada modo usando la tecla Insert. El modo actual se observa en la forma del cursor y en el tercer panel de la barra de estado. Figura 2-18: Modos Edit Modo Insertar.

Modo Alinear.

Modo Sobrescribir.

2-20


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Modos Insertar y Sobrescribir (Insert y Overwrite) Los modos insertar y sobrescribir son modos similares a muchos otros editores de textos. Éstos son los únicos dos modos disponibles en el editor si este contiene un código no-spin. Modo Alinear (Align) El modo del alinear es una versión especial del modo de insertar diseñado específicamente para código de fuente. Para entender este modo, primero hay considerar técnicas de programación comunes. Hay dos prácticas muy comunes usadas al escribir código de fuente moderno: tabulación del código y alineación de comentarios a la derecha del código. También es común que el código de fuente se lea y se edite usando más de un editor de programa. Históricamente, los programadores han utilizado tabulaciónes o espacios con propósitos de alineación, y pueden resultar un problema ya que cada editor puede tener una fijación del tabulador distinta. Aquí hay algunos ejemplos; la Figura 2-19 es nuestro código original.

Figura 2-19: Alineación Común - Código Original. Si el código original utilizó caracteres tabuladores para alinear los comentarios, al cambiar "Delay" por "BtnDelay" hará que un comentario cambie de posición a la derecha si el texto modificado cruza el límite del tabulador.

Figura 2-20: Alineación Común – Tab Alineado. Si el código original utilizó caracteres de espacio para alinear los comentarios, al cambiar "Delay" por "BtnDelay" hará que los comentarios cambien de posición a la derecha tres caracteres.

2-21


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Figura 2-21: Alineación Común – Espacio Alineado. Para el código Spin, la herramienta Propeller soluciona este problema primero rechazando caracteres de tabulador (al pulsar el tabulador se emiten el número apropiado de caracteres de espacio), y segundo proporcionando el modo de edición Align. En el modo Aling, los caracteres insertados en una línea afectan los caracteres vecinos pero no los caracteres separados por más de un espacio. El resultado es que los comentarios y otros ítems separados por más de un espacio mantienen su alineación prevista, según lo demostrado en la Figura 2-22.

Figura 2-22: Efectos del modo Align Con el modo Align, cambiando "Delay" por "BtnDelay deja todos los comentarios en su localización original, alineada. No es necesario la realineación de comentarios. Puesto que el modo alinear mantiene alineaciones existentes, se pierde mucho menos tiempo realineando los elementos en los posibles futuros cambios que realice el programador. Además, puesto que se utilizan los espacios en vez de caracteres de tabulación, el código mantiene el mismo aspecto y sensación en cualquier editor. Sin embargo, el modo Align no es perfecto para todas las situaciones. Se recomienda usar el modo Insert para la mayoría de la escritura del código y cambiar brevemente a este modo para alinear y mantener código existente. La tecla Insert rota de modo en este orden: InsertÆAlignÆOverwrite . Las teclas rápidas Ctrl+Insert cambian solamente entre los modos Insert y Aling. Con la practica de estos dos modos el programador ahorrara tiempo de programación. Hay que tener el cuenta que el código no-Spin no permite el modo Align. Esto es porque, para código no-Spin, la herramienta Propeller está diseñado para mantener cualquier carácter de tabulación existente e insertar caracteres de tabulación cuando el tabulador se pulsa y así mantener el aspecto original del archivo.

2.6. SELECCIÓN DE BLOQUES Y MOVIMIENTO DE SELECCIÓN Además de las selecciones normales del texto hechas con el ratón, la herramienta del Propeller permite las selecciones de bloque (regiones rectangulares de texto). Para hacer una selección del bloque, primero hay que mantener presionada la tecla Alt, pulsar el botón izquierdo del ratón y arrastrar el ratón hasta seleccionar la región de texto que se desea. Después de la selección, las operaciones de cortar y copiar se hacen como con cualquier otra selección de texto. La Figura 2-23 muestra la selección del bloque y el movimiento del bloque de texto con el ratón.

2-22


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Figura 2-23: selección de bloque y el movimiento de selección.

Código original. Quisiéramos mover los comentarios de “LCD Screen Addr” a la derecha de la rutina de PrintMode.

Primero hay que mantener presionada la tecla Alt, pulsar el botón izquierdo del ratón y arrastrar el ratón para hacer la selección.

Finalmente, el clickar y desplazar (dentro del bloque seleccionado) y dejar la selección en la localización deseada.

2.7. INDENTING Y OUTDENTING. Una práctica común de programación es tabular los bloques del código que están en bucles o bloques condicionales para hacer ese código más fácil leer. A esto se llama "indenting." Llamaremos la acción opuesta, cambiando la posición del código a la izquierda, "outdenting." Lenguaje Spin requiere esta clase de formato para indicar que líneas pertenecen a bucles y que líneas son de bloques condicionales. La herramienta Propeller incluye las siguientes características para facilitar esto, mientras se crea o se mantiene código. Líneas independientes Para el código Spin, la herramienta Propeller utiliza conjunto fijo que tabulaciones que se pueden cambiar en EditÆ Preferences menu. Cada bloque Spin (CON, VAR, OBJ, publicación, PRI, y DAT) tiene sus propias posiciones del tabulador fijas. La tecla del tabulador mueve el cursor a la posición siguiente de tabulación (a la derecha) y las teclas Shift + Tab mueve el cursor a la posición de tabulación anterior (a la izquierda). Además, la tecla de retroceso (Backspace) se mueve a la posición de tabulación anterior dependiendo del texto alrededor de ella. Las fijaciones del tabulador por defecto para los bloques PUB y PRI incluyen posiciones de tabulación cada dos caracteres, para apoyar sangrías comunes del código. Por ejemplo, la Figura 2-24, abajo, muestra un método público, FSqr, conteniendo varios niveles la sangría, cada dos caracteres.

Figura 2-24: Tabulación ajustada para los bloques PUB y PRI

2-23


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Usando el tabulador, este código se habría podido introducir rápidamente con la secuencia siguiente en el teclado: • • •

Tipo: “PUB FSqr” <Enter> Tipo: <Tab> “repeat 31” <Enter> Tipo: "<Tab> “result |= root” <Enter>, etc.

Observe que la tecla Enter alinea automáticamente el cursor con el nivel de la sangría actual; esto significa que el tabulador solo necesita pulsarse una vez para tabular al nivel siguiente. Si hay caracteres a la derecha del cursor cuando se presiona el tabulador, se desplazan también a la derecha, como en la Figura 2-25. Figura 2-25: “Indenting” Si el cursor está justo a la izquierda del primer carácter en una línea, tanto las teclas Shift + Tab como la tecla de Backspace hacen que el cursor y el se desplacen a la izquierda a la posición del tabulador anterior; es decir: “outdenting”. Sin embargo, si el cursor no está justo a la izquierda del primer carácter en una línea, la tecla Backspace actúa normal (suprimiendo el carácter anterior) y las teclas Shift + Tab mueven solamente el cursor a la posición del tabulador anterior. Figura 2-26: “Outdenting” Líneas Múltiples Además de afectar líneas independientes, en las líneas múltiples del código se puede realizar “indenting” o “outdenting” sobre las posiciones de tabulación fijas.

Figura 2-27: Ejemplo de Bloque de Código. Deseamos hacer las primeras cuatro líneas se repitan 31 veces.

Supongamos que se desea coger las primeras cuatro líneas de este ejemplo y encapsularlas en un bucle de “Repeat 31”; para repetir esas líneas 31 veces. Habría que seguir los pasos siguientes: 1) incorpora la línea de la "repeat 31" sobre las líneas existentes, 2) con el ratón, seleccionar las cuatro líneas, y 3) pulsar el tabulador. Estos pasos se ilustran en la Figura 2-28.

2-24


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

Figura 2-28: “Indenting” en un bloque de código Paso1: Insertar la instrucción repeat 31 sobre el bloque. Paso 2: Con un ratón, seleccionar las cuatro líneas para tabular a la derecha (“Indenting”). Paso 3: Presionar el tabulador para tabular las líneas seleccionadas. Las cuatro líneas que seleccionadas en el segundo paso ahora están tabuladas a la siguiente posición fija de tabulación (dos espacios a la derecha del comienzo del "repeat") y a la selección ha cambiado a una sola columna que contiene los primeros caracteres de las líneas. La selección cambia para indicar que se ha realizado una tabulación de líneas múltiples. El segundo tipo de selección, la selección de bloques, se puede también utilizar para tabular hacia fuera o hacia dentro los grupos de líneas. Por ejemplo, la Figura 2-29 muestra un ejemplo con comentarios a la derecha de las líneas.

Figura 2-29: Muestra de código con comentarios a la derecha Si se realiza una selección de bloque sobre los primeros caracteres de los comentarios (Alt + botón izquierdo de ratón y arrastrar, figura 2-30), podemos presionar el tabulador para tabularlos a la siguiente posición fijada. Presionando Shift + Tab se realiza la acción inversa (outdent) tabulándolos hacia la izquierda, como máximo hasta que se topen con cualquier carácter a ese lado, como ocurre en la Figura 2-30. Paso 1: Seleccionar al bloque de las líneas de comentarios (Alt + botón izquierdo y arrastrar con el ratón).

Paso 2: Presione Tab para tabular los comentarios.

Figura 2-30: Selección de bloque a los comentarios de Outdent.

2-25


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones

www.microcontroladores.com info@microcontroladores.com

2.8 INDICADORES DE BLOQUE-GRUPO A veces puede ser difícil ver exactamente cómo los grupos del código se arreglan lógicamente simplemente por su nivel de sangría. La herramienta Propeller puede señalar los bloques-grupos lógicos de bloques condicionales o de bloques de repetitivas como se muestra en la Figura 2-31. Para activar/desactivar esta característica, presionar a Ctrl + I.

Figura 2-31: Indicadores Bloque-Grupo.

Hay que observar que sólo el código compilable que esté dentro de un bloque condicional o un bloque finito se realza con los indicadores de la sangría. Esto es simplemente una ayuda visual para ver cómo el código será ejecutado; no afecta al código ni al archivo de fuente físicamente; solamente los niveles reales de sangría. 2.9 TECLAS DE ACCESO RÁPIDO Listados Categóricos En la tabla 2-1, las teclas de acceso rápido se agrupan por funciones relacionadas. En la tabla 2-2, las teclas de acceso rápido son agrupadas por tecla más que por la función. Tabla 2-1: Teclas de acceso rápido – Listado Categórico Función Teclas Abrir Ctrl + O Cerrar Alt + Q Guardar Ctrl + S Guardar todo Ctrl + Alt + S Imprimir Ctrl + P Mostrar/Ocultar Bookmarks Ctrl + B Mostrar/Ocultar Bookmarks de la línea actual Ctrl + Shift + B Indicadores de la sangría de bloque Ctrl + I Mostrar/Ocultar el explotador Ctrl + E Mostrar/Ocultar Numero de Linea Ctrl + N Incrementar tamaño fuente Ctrl + Arriba -o- Ctrl +Rueda ratón arriba Decrementar tamaño fuente Ctrl + Abajo-o- Ctrl +Rueda ratón abajo Seleccionar el modo de visión Fuente Alt + S completa Seleccionar el modo de visión Condensado Alt + C Seleccionar el modo de visión Resumen Alt + U Seleccionar el modo de visión Documentación Alt + D Seleccionar modo de visión alterna Alt + Arriba Seleccionar modo de visión alterna Alt + Abajo -o- Alt + Rueda ratón abajo Seleccionar la edición activa Esc Hardware F7 Compilar fichero actual y ver información F8 Compilar fichero actual y actualizar el estado F9 Compilar fichero actual , Cargar RAM y F10 ejecutar Compilar fichero actual, Cargar EEPROM y F11 ejecutar

2-26


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones Compilar fichero actual y Cargar EEPROM solo Compilar fichero raíz y ver información Compilar fichero raíz y actualizar el estado Compilar fichero raíz, Cargar RAM y ejecutar Compilar fichero raíz, Cargar EEPROM y ejecutar Compilar fichero raíz y Cargar EEPROM solo Seleccionar pestaña de editor siguiente Seleccionar pestaña de editor anterior Ir a pagina anterior Ir a pagina siguiente Ir al comienzo de la siguiente palabra Ir al comienzo de la palabra anterior Saltar al comienzo de línea Saltar al fin de línea Saltar al inicio de pagina Saltar al fin de pagina Saltar al inicio de archivo Saltar al final de archivo Seleccionar palabra Seleccionar línea Seleccionar hasta el principio de la siguiente palabra Seleccionar hasta el principio de la palabra anterior Seleccionar hasta el comienzo de línea Seleccionar hasta fin de línea Seleccionar hasta inicio de pagina Seleccionar hasta fin de pagina Seleccionar hasta pagina anterior Seleccionar hasta pagina siguiente Seleccionar hasta inicio de fichero Seleccionar hasta fin de fichero Edición Deshacer Rehacer Seleccionar Todo Copiar Cortar Pegar Buscar/Reemplazar Buscar siguiente Reemplazar Reemplazar y buscar siguiente Cambiar el modo de edición Cambiar el modo de edición entre Insert /Align Tabulación Borrar espacios hasta la tabulación anterior Borrar línea actual Borrar hasta fin de línea Renombrar fichero/archivo Símbolos Insertar el carácter superíndice de menos uno (¯¹)

F12 Ctrl + F8 Ctrl + F9 Ctrl + F10 Ctrl + F11 Ctrl + F12 Alt + Drcha-o- Ctrl + Tab Alt + Izda -o- Ctrl + Sift + Tab Re Pag Av Pag Ctrl + Drcha Ctrl + Izda Inicio Fin Ctrl + Re Pág Ctrl + Av Pág Ctrl + Inicio Ctrl + Fin Doble Click Triple Click Ctrl + Shift + Drcha Ctrl + Shift + Izda Shift + Inicio Shift + Fin Ctrl + Shift + Re Pág Ctrl + Shift + Av Pág Shift + Re Pág Shift + Av Pág Ctrl + Shift + Inicio Ctrl + Shift + Fin Ctrl + Z Ctrl + Shift + Z Ctrl + A Ctrl + C Ctrl + X Ctrl + V Ctrl + F F3 F4 Ctrl + F4 Insert Ctrl + Insert Tab Shift + Tab Ctrl + Y Ctrl + Shift + Y F2 Ctrl + Alt + 1

2-27

www.microcontroladores.com info@microcontroladores.com


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones Insertar carácter de superíndice uno( ¹ ) Insertar carácter de superíndice dos ( ² ) Insertar carácter de superíndice tres ( ³ ) Insertar carácter ( ● ) Insertar un carácter de rectángulo ( █ ) Insertar carácter ( ◄ ) Insertar carácter ( ► ) Insertar carácter de flecha hacia abajo (↓ ) Insertar carácter de flecha hacia la izda ( ← ) Insertar carácter de flecha hacia la drcha ( → ) Insertar carácter de flecha hacia arriba ( ↑ ) Insertar carácter de Euro ( € ) Insertar carácter de Yen ( ¥ ) Insertar carácter ( £ ) Insertar carácter de flecha hacia la izda ( ← ) Insertar carácter de flecha hacia la drcha ( → ) Insertar carácter de flecha hacia arriba ( ↑ ) Insertar carácter de flecha hacia abajo (↓ ) Insertar carácter de grado ( ° ) Insertar carácter de mas/menos ( ± ) Insertar carácter de multiplicación ( × ) Insertar carácter de división ( ÷ ) Insertar carácter de Radical ( √ ) Insertar carácter de infinito ( ∞ ) Insertar carácter de Delta ( δ ) Insertar carácter de Mu ( µ ) Insertar carácter de Omega ( ω ) Insertar carácter de Pi ( π ) Insertar carácter de Sigma ( σ )

Tabla 2-2: Teclas de acceso rápido Teclas o Ratón F2 F3 F4 F7 F8 F9 F10 F11 F12 Fin Esc Inicio Insert Av Pág Re Pág Tab Doble Click Triple Click Ctrl + … Ctrl + A Ctrl + B Ctrl + C

www.microcontroladores.com info@microcontroladores.com

Ctrl + Shift + 1 Ctrl + Shift + 2 Ctrl + Shift + 3 Ctrl + Shift + . Ctrl + Alt + . Ctrl + Shift + Alt + < Ctrl + Shift + Alt + > Ctrl + Shift + Alt + Izda Ctrl + Shift + Alt + Drcha Ctrl + Shift + Alt + Arriba Ctrl + Shift + Alt + Abajo Ctrl + Shift + $ Ctrl + Alt + $ Ctrl + Shift + Alt + $ Ctrl + Alt + Izda Ctrl + Alt + Drcha Ctrl + Alt + Arriba Ctrl + Alt + Abajo Ctrl + Shift + % Ctrl + Shift + Ctrl + Shift + * Ctrl + Shift + / Ctrl + Shift + R Ctrl + Shift + I Ctrl + Shift + D Ctrl + Shift + M Ctrl + Shift + O Ctrl + Shift + P Ctrl + Shift + S

Función Renombrar carpeta/fichero Buscar siguiente ; Find Next Reemplazar ; Replace Identificar Hardware Compilar fichero actual y ver información Compilar fichero actual y actualizar el estado Compilar fichero actual , Cargar RAM y ejecutar Compilar fichero actual, Cargar EEPROM y ejecutar Compilar fichero actual y Cargar EEPROM solo Saltar al final de línea Seleccionar la vista de fuente completa Saltar al comienzo de línea Cambiar el modo de edición Saltar a la siguiente pagina Saltar a la pagina anterior Tabular Seleccionar una palabra Seleccionar una línea Seleccionar todo Mostrar/Ocultar Bookmarks Copiar

2-28


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones Ctrl + E Ctrl + F Ctrl + I Ctrl + N Ctrl + O Ctrl + S Ctrl + P Ctrl + T Ctrl + V Ctrl + X Ctrl + Y Ctrl + Z Ctrl + F4 Ctrl + F8 Ctrl + F9 Ctrl + F10 Ctrl + F11 Ctrl + F12 Ctrl + Abajo Ctrl + Fin Ctrl + Inicio Ctrl + Insert Ctrl + Izda Ctrl + Av pág Ctrl + Rueda ratón abajo Ctrl + Rueda ratón arriba Alt + … Alt + C Alt + D Alt + S Alt + Q Alt + U Alt + Abajo Alt + Izda Alt + Rueda ratón abajo Alt + Rueda ratón arriba Alt + Drcha Alt + Arriba Shift + … Shift + Fin Shift + Inicio Shift + Av Pág Shift + Re Pág Shift + Tab Ctrl + Alt + … Ctrl + Alt + . Ctrl + Alt + $ Ctrl + Alt + 1 Ctrl + Alt + S Ctrl + Alt + Abajo Ctrl + Alt + Izda Ctrl + Alt + Drcha

www.microcontroladores.com info@microcontroladores.com

Mostrar/Ocultar el explotador Buscar/ Remplazar ; Find / Replace Indicadores de la sangría de bloque Mostrar/Ocultar Numero de Línea Abrir Guardar Imprimir Seleccionar el fichero raíz Pegar Cortar Borrar línea actual Deshacer Reemplazar y Buscar siguiente Compilar fichero raíz y ver información Compilar fichero raíz y actualizar el estado Compilar fichero raíz, Cargar RAM y ejecutar Compilar fichero raíz, Cargar EEPROM y ejecutar Compilar fichero raíz y Cargar EEPROM solo Decrementar el tamaño de fuente Saltar al final del archivo Saltar al comienzo de archivo Cambiar el modo de edición entre Insert / Align Saltar hasta el comienzo de la siguiente palabra Saltar hasta fin de página Decrementar el tamaño de fuente Incrementar el tamaño de fuente Seleccionar el modo de visión Condensado Seleccionar el modo de visión Documentación Seleccionar el modo de visión Fuente completa Cerrar Seleccionar el modo de visión Resumen Seleccionar el modo de visión alternos Seleccionar la pestaña del editor anterior Seleccionar el modo de visión alternos (desde Documentación) Seleccionar el modo de visión alternos (desde fuente completa) Seleccionar la siquiente pestaña del editor Seleccionar el modo de visión alternos (desde fuente completa) Seleccionar hasta fin de línea Seleccionar hasta principio de línea Seleccionar hasta la siguiente pagina Seleccionar hasta la pagina anterior Borrar espacios hasta la tabulación anterior Insertar un carácter de rectángulo ( █ ) Insertar un carácter Yen ( ¥ ) Insertar el carácter superíndice de manos uno (¯¹) Guardar todo Insertar carácter de flecha hacia abajo (↓ ) Insertar carácter de flecha hacia la izda ( ← ) Insertar carácter de flecha hacia la drcha ( → )

2-29


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 2: Manejo y desarrollo de aplicaciones Ctrl + Alt + Arriba Ctrl + Shift + … Ctrl + Shift + $ Ctrl + Shift + % Ctrl + Shift + * Ctrl + Shift + Ctrl + Shift + . Ctrl + Shift + / Ctrl + Shift + = Ctrl + Shift + 1 Ctrl + Shift + 2 Ctrl + Shift + 3 Ctrl + Shift + B Ctrl + Shift + D Ctrl + Shift + I Ctrl + Shift + M Ctrl + Shift + O Ctrl + Shift + P Ctrl + Shift + R Ctrl + Shift + S Ctrl + Shift + Y Ctrl + Shift + Z Ctrl + Shift + Fin Ctrl + Shift + Inicio Ctrl + Shift + Izda Ctrl + Shift + Av Pág Ctrl + Shift + Re Pág Ctrl + Shift + Drcha Ctrl + Shift + Tab Ctrl + Shift + Alt… Ctrl + Shift + Alt + $ Ctrl + Shift + Alt + < Ctrl + Shift + Alt + > Ctrl + Shift + Alt + Abajo Ctrl + Shift + Alt + Izda Ctrl + Shift + Alt + Drcha Ctrl + Shift + Alt + Arriba

www.microcontroladores.com info@microcontroladores.com

Insertar carácter de flecha hacia arriba ( ↑ ) Insertar carácter de Euro ( € ) Insertar carácter de grado ( ° ) Insertar carácter de multiplicación ( × ) Insertar carácter de mas/menos( ± ) Insertar carácter ( ● ) Insertar carácter de división ( ÷ ) Insertar carácter de aproximación ( ≈ ) Insertar carácter de superíndice uno( ¹ ) Insertar carácter de superíndice dos ( ² ) Insertar carácter de superíndice tres ( ³ ) Bookmark de la línea actual Insertar carácter de Delta ( δ ) Insertar carácter de infinito ( ∞ ) Insertar carácter de Mu ( µ ) Insertar carácter de Omega ( ω ) Insertar carácter de Pi ( π ) Insertar carácter de Radical ( √ ) Insertar carácter de Sigma ( σ ) Borrar hasta fin de línea Rehacer Seleccionar hasta fin de archive Seleccionar hasta principio de archivo Seleccionar hasta la palabra anterior Seleccionar hasta fin de pagina Seleccionar hasta principio de pagina Seleccionar hasta siguiente palabra Seleccionar hasta siguiente tabulación Insertar carácter Insertar carácter Insertar carácter Insertar carácter Insertar carácter Insertar carácter Insertar carácter

2-30

(£) (◄) (►) (↓) (←) (→) (↑)


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

CAPITULO 3: EL LENGUAJE SPIN 3.1. INTRODUCCIÓN Este capítulo describe los elementos del lenguaje Spin del Propeller y se divide en dos secciones principales: 1) El listado por categorías de todos los elementos del lenguaje Spin del Propeller. Todos ellos, incluyendo operadores y símbolos de la sintaxis, están agrupados por la función relacionada. Esto es una manera de localizar rápidamente la amplitud del lenguaje y qué características están disponibles para las aplicaciones específicas. Algunos de los elementos mencionados están marcados con un exponente “a” que indica que están también disponibles en ensamblador del Propeller, aunque la sintaxis puede variar. 2) La descripción de los elementos del lenguaje Spin. La mayoría de los elementos tienen su propia subdivisión, dispuesta alfabéticamente para facilitar su búsqueda. Los elementos individuales sin subdivisión, tales como operadores, símbolos y algunas constantes, se agrupan dentro de otras subdivisiones relacionadas. 3.2. LISTADO POR CATEGORÍAS DEL LENGUAJE SPIN DEL PROPELLER Los elementos marcados con un subíndice “a” están también disponibles en ensamblador del Propeller. Declaraciones de Bloque CON VAR OBJ PUB PRI DAT

Declaración de constantes Declaración de variables Declaración de referencias de objetos Declaración de métodos públicos Declaración de métodos privados Declaración de datos

Configuración CHIPVER CLKMODE _CLKMODEa CLKFREQ _CLKFREQa CLKSETa _XINFREQa _STACKa _FREEa RCFASTa RCSLOWa XINPUTa XTAL1a XTAL2a XTAL3a PLL1Xa PLL2Xa PLL4Xa PLL8Xa PLL16X

Obtener el numero de versión del chip Propeller Obtener el modo de configuración actual de reloj Modo de reloj definido por la aplicación (solo lectura) Obtener el modo actual de frecuencia Frecuencia definido por la aplicación (solo lectura) Poner el modo y frecuencia de reloj Frecuencia de reloj externo definido por la aplicación (solo lectura) Espacio de pila reservado por la aplicación (solo lectura) Espacio libre reservado por la aplicación (solo lectura) Constante para _CLKMODE: oscilador rápido interno Constante para _CLKMODE: oscilador lento interno Constante para _CLKMODE: oscilador/reloj externo Constante para _CLKMODE: cristal externo de velocidad baja Constante para _CLKMODE: cristal externo de velocidad media Constante para _CLKMODE: cristal externo de velocidad alta Constante para _CLKMODE: valor de frecuencia externa 1 Constante para _CLKMODE: valor de frecuencia externa 2 Constante para _CLKMODE: valor de frecuencia externa 4 Constante para _CLKMODE: valor de frecuencia externa 8 Constante para _CLKMODE: valor de frecuencia externa 16

3-1


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Control de Cog COGIDa COGNEW COGINITa COGSTOPa REBOOT

Obtener el Id de Cog actual (0-7) Iniciar el siguiente Cog disponible Iniciar o reiniciar un cog por su Id Detener un cog por su Id Resetear el chip Propeller

Control de Proceso LOCKNEWa LOCKRETa LOCKCLRa LOCKSETa WAITCNTa WAITPEQa WAITPNEa WAITVIDa

Comprobar un nuevo semáforo Devolver un semáforo Poner un semáforo a ceros por Id Fijar un semáforo por Id Esperar a que el Contador del Sistema alcance el valor Esperar a que el/los pin(es) se igualen a un valor Esperar a que el/los pin(es) no sean igual a un valor Esperar a la sincronización de video y repartir el siguiente grupo color/pixel

Control de Flujo IF …ELSEIF …ELSE

Ejecuta condicionalmente uno o más bloques de código

CASE …OTHER

Evalúa una expresión y ejecuta el bloque de código que satisface la condición

REPEAT …FROM …TO …STEP …UNTIL …WHILE

Ejecuta un bloque de código repetidamente un numero de veces finito o infinito, opcionalmente con un contador, intervalos, condiciones de salida y continuidad

NEXT QUIT RETURN ABORT

Salta el resto del bloque REPEAT y va la siguiente iteración del bucle Sale del bucle REPEAT Sale de PUB/PRI con estado normal y opcionalmente con un valor de retorno Sale de PUB/PRI con estado de abort y opcionalmente con un valor de retorno

Memoria BYTE WORD LONG BYTEFILL WORDFILL LONGFILL BYTEMOVE WORDMOVE LONGMOVE LOOKUP LOOKUPZ LOOKDOWN LOOKDOWNZ STRSIZE STRCOMP

Declarar un símbolo de tamaño byte o acceso byte de la memoria principal Declarar un símbolo de tamaño word o acceso word de la memoria principal Declarar un símbolo de tamaño long o acceso long de la memoria principal Rellena bytes de la memoria principal con un valor Rellena words de la memoria principal con un valor Rellena longs de la memoria principal con un valor Copia bytes de una región a otra de la memoria principal Copia words de una región a otra de la memoria principal Copia longs de una región a otra de la memoria principal Recupera el valor de una posición (1..N) de una lista Recupera el valor de una posición de base cero (0..N-1) de una lista Recupera el índice (1..N) del valor que coincida en una lista Recupera el índice de base cero (0..N-1) del valor que coincida en una lista Recupera el tamaño en bytes de un string Compara un string de bytes con otro string de bytes

3-2


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Directivas STRING Declaración de expresiones de tipo string CONSTANT Declaración de expresiones de tipo constante FLOAT Declaración de expresiones de punto flotante ROUND Redondea en tiempo de compilación FLOATs a integer TRUNC Trunca en tiempo de compilación FLOATs s decimal FILE Importa datos de un fichero externo Registros DIRAa Registro de Direcciones de 32-bits del puerto A DIRBa Registro de Direcciones de 32-bits del puerto B (uso futuro) INAa Registro de Entrada de 32-bits del puerto A INBa Registro de Entrada de 32-bits del puerto B (uso futuro) OUTAa Registro de Salida de 32-bits del puerto A OUTBa Registro de Salida de 32-bits del puerto B (uso futuro) CNTa Registro de Contador del Sistema de 32-bits CTRAa Contador A del Registro de Control CTRBa Contador B del Registro de Control FRQAa Contador A del Registro de Frecuencia FRQBa Contador B del Registro de Frecuencia PHSAa Contador A del Registro de PLL PHSBa Contador B del Registro de PLL VCFGa Registro de Configuración de Video VSCLa Registro de Escala de Video PARa Registro de Parámetros de Arranque del Cog SPR Array de Registros de Propósito especial; acceso indirecto de registros cog Constantes TRUEa True (verdadero) lógico: -1 ($FFFFFFFF) FALSEa False (falso) lógico: 0 ($00000000) POSXa Valor entero máximo positivo: 2,147,483,647 ($7FFFFFFF) NEGXa Valor entero máximo negativo: -2,147,483,648 ($80000000) PIa Valor de punto flotante PI: ~3.141593 ($40490FDB)

Variables RESULT

Variable por defecto para el resultado de método PUB/PRI

Operadores Unitarios + -++ ^^ || ~ ~~ ? |< >| !

Positivo (+X); forma unitaria de suma Negativo (-X); forma unitaria de resta Pre-decremento (--X) o post-decremento (X--) y asignación Pre-incremento (++X) o post-incremento (X++) y asignación Raíz cuadrada Valor absoluto Signo extendido desde el bit 7 (~X) o post-asignación de 0 (X~) Signo extendido desde el bit 15 (~~X) o post-asignación de 0(X~~) Random de un numero hacia delante (?X) o hacia detrás (X?) Descifra un valor (0-31) en un long single-high-bit Cifra un long en valores (0-32) como prioridad de high-bit Modo bit: NOT

3-3


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN NOT @ @@

www.microcontroladores.com info@microcontroladores.com

Boleado: NOT Dirección de símbolo Valor de símbolo y dirección de Objeto

Operadores Binarios = := + * ** / // #> <# ~> << >> <-> >< & | ^ AND OR == <> < > =< =>

--y---y---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o--

= := += -= *= **= /= //= #>= <#= ~>= <<= >>= <-= ->= ><= &= |= ^= AND= OR= === <>= <= >= =<= =>=

asignación constante (bloques CON) asignación variable (bloques PUB/PRI) Suma Resta Multiplicación y resultado menor de 32 bits (con signo) Multiplicación y resultado mayor que 32 bits (con signo) División (con signo) Resto (con signo) Limite mínimo (con signo) Limite máximo (con signo) Desplazamiento aritmético a la derecha Modo bit: Desplazamiento a la izquierda Modo bit: Desplazamiento a la derecha Modo bit: Rotación izquierda Modo bit: Rotación derecha Modo bit: Reverso Modo bit: AND Modo bit: OR Modo bit: XOR Boleado: AND Boleado: OR Boleado: Es igual Boleado: NO es igual Boleado: es menor que (con signo) Boleado: es mayor que (con signo) Boleado: es menor o igual (con signo) Boleado: es mayor o igual (con signo)

Sintaxis de Símbolos # . .. : | \ , () [] {} {{ }} ‘ “

Referencia a Constante de Objeto: Ej. obj#constant Referencia a método de Objeto: Ej. obj.método(param) Indicador de rango: Ej. 0..7 Separador de resultado: Ej. método PUB:sym o asignación a object Separador de variable local: Ej. método PUB | temp, str Barra de abort: Ej. \método(params) Delimitador de lista: Ej. en método (param1, param2) Signo de parámetros de una lista: Ej. en método (params) Signo de índices de array: Ej. INA[2] Signo de comentarios de código línea o multilínea Signo de comentarios de documento línea o multilínea Signo de comentario de código Signo de comentario de documento

3-4


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3. DESCRIPCIÓN DE LOS ELEMENTOS DEL LENGUAJE SPIN El resto de este capítulo describe, en orden alfabético, los elementos del lenguaje Spin mostrados arriba. Algunos se explican dentro del contexto de otros para mayor claridad. Muchos de los elementos están disponibles en Spin y ensamblador del Propeller. Reglas de Símbolos Los símbolos son nombres alfanuméricos creados por el compilador (words reservadas) o por el desarrollador del código (words definidas por el usuario). Se utilizan para representar valores (constantes o variables) y para hacer el código de fuente más fácil entender y mantener. Los nombres de símbolo no son sensibles a mayúsculas o minúsculas. Los símbolos definidos por el usuario deben seguir las siguientes reglas: 1) Comienzan con una letra (a - z) o un guión bajo ‘_ ‘. 2) Contienen solamente letras, números, y guiones bajos (a - z, 0 - 9, _); no se permiten espacios. 3) deben ser 32 caracteres o menos. 4) debe ser único al objeto; no una word reservada o un símbolo previamente definido por el usuario. Representaciones del Valor Los valores se pueden introducir en formatos decimales, binarios, hexadecimales, o carácter. Los valores numéricos pueden también utilizar guiones, ‘ _ ‘, como separador de grupo. A continuación se muestran ejemplos de estos formatos. 1024 2_147_483_647 %1010 %11110000_10101100 $1AF $FFAF_126D_8755_1CE9 “A”

número decimal. número decimal con separadores en los millares. número binario. número binario con separadores en los bytes. número del hexadecimal. número hexadecimal con separadores en las words. Carácter.

Definiciones De Sintaxis Además de descripciones detalladas, las siguientes páginas contienen las definiciones sintácticas para los elementos que describen las opciones de ese elemento. Las definiciones sintácticas utilizan símbolos especiales para indicar cuando y cómo deben ser utilizadas ciertas características del elemento. BOLDCAPS

Los ítem en mayúscula en negrita se deben mecanografiados de esta misma forma.

Bold Italics

Los ítem en negrita y cursiva deben ser sustituidos por el texto del usuario; símbolos, operadores, expresiones, etc..

. ... : , # Los puntos, los doble-puntos, los dos puntos, las comas, la almohadilla, raya vertical, la barra, los corchetes y paréntesis deben ser mecanografiados de esta manera. <> Los corchetes angulosos contienen ítem opcionales. (( | )) ... ↵

| \ [] ()

la

El símbolo de dobles paréntesis incluye los ítem mutuo-exclusivos, separados por una barra. El símbolo de la repetición indica que el ítem anterior, o el grupo de ítem, se puede repetir las numerosas veces. El símbolo de nueva línea y de la tabulación indica que los puntos siguientes deben aparecer en la línea siguiente y tabulados por lo menos un espacio. El símbolo de la tabulación indica que los puntos siguientes se deben tabular por lo menos un espacio.

3-5


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN Línea única:

Separa varias opciones de la estructura del sintaxis.

Línea doble:

Separa la instrucción del valor que devuelve.

www.microcontroladores.com info@microcontroladores.com

3.3.1. ABORT Salida del método de PUB/PRI usando estado Abort con valor de retorno opcional. ABORT <Value> Devuelve: El valor del RESULTADO actual, o Value si proporciona. •

Value es una expresión opcional cuyo valor debe ser devuelto, con estado de la interrupción, del método PUB o PRI.

Explicación ABORT es uno de dos comandos (ABORT y RETURN) que terminan la ejecución de un método PUB o PRI. ABORT causa el retorno de un método de PUB o PRI con estado Abort; esto significa que hace pop sobre la pila de llamadas (Call Stack) en varias ocasiones hasta que la pila de llamadas queda vacía o se encuentra un llamador con un Abort Trap (\), y entrega un valor en el proceso. ABORT es útil para los casos donde un método necesita terminar e indicar un estado anormal o elevado al llamador inmediato o a sus llamadores anteriores. Cuando el ABORT aparece sin el valor opcional, devuelve el valor actual de la variable incorporada del RESULT de PUB/PRI. Si el campo de valor fue incorporado, PUB o PRI aborta y devuelve ese valor.

Sobre la pila de llamadas (Call Stack) Cuando los métodos son llamados simplemente invocándoles de otros métodos, debe haber un cierto mecanismo para almacenar donde debe retornar una vez que se termine el método llamado. Este mecanismo es el llamado "stack" (pila) pero utilizaremos el término "call stack" aquí. Este mecanismo es simplemente memoria RAM, usada para almacenar las direcciones y los valores de retorno, los parámetros y los resultados intermedios. La pila de llamadas va aumentando a medida que se van haciendo llamadas a métodos y disminuye cuando los métodos terminan, ya sea vía Return o alcanzando el final del método. La pila aumenta y disminuye de tamaño con estas dos acciones: 1)"push" que introduce valores sobre la pila y 2) "pop" que saca los valores contenidos en la pila El comando RETURN hace un pop de los datos más recientes de la pila de llamadas devolviendo el dato al llamador inmediato; quién llamó directamente al método que acaba de volver. El comando de la ABORT, sin embargo, realiza pops repetidamente de la pila de llamadas hasta que encuentra un llamador con un Abort trap (ver abajo); devolviendo a algún llamador de alto nivel . Uso de ABORT Cualquier método puede elegir utilizar un comando ABORT. Es labor del código de alto nivel comprobar si hay un estado Abort y tratarlo. Este código puede ser cualquier código de alto nivel que llame a un método que aborte directamente, o vía otro sistema de métodos. Para utilizar un comando ABORT, se debe seguir el ejemplo siguiente: if <condición mala > abort

‘Si se ha encontrado una mala condición, Abortar

—o—

3-6


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN if < condición mala > abort <valor >

www.microcontroladores.com info@microcontroladores.com

‘Si se ha encontrado una mala condición, Abortar ‘devolviendo un valor

... donde < condición mala > es la condición que determina si el método debe abortar y <valor> es un valor a devolver al abortar. El Abort Trap ( \ ) Para capturar un ABORT, la llamada al método o cadena de métodos que podrían abortar potencialmente se deben preceder con el símbolo del Abort Trap (/) por ejemplo,

if \MayAbort abort <value>

‘Llamada a MayAbort con abort trap ‘Proceso abort

El tipo de salida que esta usando MayAbort , ABORT o RETURN, no puede conocer el abort trap; por lo que el código debe ser escrito de tal manera que se pueda detectar qué tipo fue utilizado. Algunas posibilidades son: 1) el código puede ser diseñado para que un método de alto nivel sea el único lugar que capture una interrupción y otros procesos de código de nivel medio 2) los métodos “abortables” puede devolver un valor especial que no pueda darse en ninguna circunstancia normal, o 3) se puede fijar un flan global por el método abort antes de abortar. Lo siguiente es un ejemplo de una aplicación de robot en la que el robot debe huir de un objeto usando sus cuatro sensores. ( izquierda, derecha, delante y detrás). Se asume que CheckSensors, Beep, y MotorStuck son métodos definidos en otra parte. CON #0, None, Left, Right, Front, Back

‘Enumeracion de Direcciones

PUB Main | Direction Direction := None repeat case CheckSensors Left : Direction := Right Right : Direction := Left Front : Direction := Back Back : Direction := Front other : Direction := None if not \Move(Direction) Beep

‘Recoger el sensor activo ‘Objecto en izda? Ve a la drcha ‘Objecto en drcha? Ve a la izda ‘Objecto delante? Ve hacia atrás ‘Objecto atras? Ve hacia delante ‘Otro caso, mantente quieto ‘Mueve robot ‘Pitar

PUB Move(Direction) result := True if Direction == None return repeat 1000 DriveMotors(Direction) PUB DriveMotors(Direction) <code to drive motors> if MotorStuck abort False <more code>

‘se entiende que va bien ‘Retornar si no hay dirección ‘Conducir motor 1000 veces

‘Si el motor esta bloqueado, abort

3-7


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

El ejemplo anterior muestra tres métodos de varios niveles lógicos, Main ("de alto nivel"), Move ("nivel medio") y DriveMotors ("bajo nivel"). El método de alto nivel, Main, es el que toma las decisiones de la aplicación ; decidiendo cómo responder a los acontecimientos como activaciones del sensor y movimientos del motor. El método de nivel medio, Move, es responsable de mover el robot una distancia corta. El método de bajo nivel, DriveMotors, maneja los detalles de conducir los motores correctamente y de verificar que es correcto. En una aplicación como esta, los acontecimientos críticos podrían ocurrir en el código de bajo nivel que necesitarían ser tratados por código de alto nivel. El método principal recoge entradas del sensor y decide a qué dirección mover el robot con la declaración de CASE. Entonces llama a Move de una manera especial, precediéndola con \. El método Move fija su RESULT a verdadero y después llama a DriveMotors en un bucle finito. Si termina con éxito, Move devuelve verdadero. El método de DriveMotors maneja la complicación de mover los motores del robot para alcanzar la dirección deseada, pero si determina están boqueados y no puede moverlos; aborta con un valor falso. Si no retorna normalmente. 3.3.2. BYTE Declaración de símbolos o datos tamaño-byte, o lectura / escritura de bytes en memoria principal. BYTE Symbol <[Count]> BYTE Data BYTE [BaseAddress] <[Offset]> • • • • •

Symbol es el nombre deseado para la variable. Count es una expresión opcional que indica el número de elementos de tamaño byte, dispuestos en un array desde el elemento 0 al elemento Count-1. Data es una expresión constante o una lista de expresiones constantes. También se permiten strings de caracteres; se tratan como una lista de caracteres. BaseAddress es una expresión que describe la dirección en memoria principal para leer o para escribir. Si se omite Offset, BaseAddress es la dirección real a operar. Si se especifica Offset, BaseAddress + Offset seria la dirección real. Offset una expresión opcional que indica un ajuste sobre la dirección que especifica BaseAddress.

Explicación El BYTE es una de las tres declaraciones de propósito múltiple (BYTE, WORD, y LONG) que declaran o operan en memoria. El BYTE se puede utilizar para: 1) declarar un símbolo de tamaño byte o un array de elementos de tamaño byte en un bloque del VAR, o 2) declarar datos de alineación byte, y de tamaño byte, en un bloque de DAT, o 3) leer o escribir un byte en memoria principal en una dirección base con un ajuste opcional. Declaración Variable del Byte (Sintaxis 1) En bloques del VAR, la sintaxis 1 del BYTE se utiliza para declarar las variables globales, simbólicas de tamaño byte, o es cualquier array de bytes. Por ejemplo: VAR byte Temp byte Str[25]

'Temp es un byte 'Str es un array de byte

El ejemplo anterior declara dos variables, Temp y Str. Temp es simplemente una variable de tamaño byte. La línea siguiente utiliza el campo de Count opcional para crear un array de 25 elementos variables llamado Str. Temp y str se pueden alcanzar desde cualquier método PUB o PRI dentro del mismo objeto que este bloque del VAR. Un ejemplo: PUB SomeMethod

3-8


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN Temp := 250 Str[0] := "A" Str[1] := "B" Str[24] := "C"

www.microcontroladores.com info@microcontroladores.com

‘Fija Temp a 250 ‘Fija el primer elemento de Str a "A" ‘Fija el segundo elemento de Str a "B" ‘Fija el ultimo elemento de Str a "C"

Declaración de Datos Byte (Sintaxis 2) En bloques de DAT, la sintaxis 2 del BYTE se utiliza para declarar datos byte que se compilan como valores constantes en memoria principal. Por ejemplo: DAT MyData MyString

byte byte

64, $AA, 55 "Hello",0

‘datos de tamaño y alineación byte ‘Un string de bytes (caracteres)

El ejemplo anterior declara dos símbolos de datos, MyData y MyString. Cada símbolo de datos señala el comienzo de datos en memoria principal. Los valores de MyData, en memoria principal, son 64, $AA y 55, respectivamente. Los valores de MyString, en memoria principal, son "H", "e", "l", "l", "o", y 0, respectivamente. Estos datos se compilan en el objeto y en la aplicación resultante como parte de la sección ejecutable de código y se pueden alcanzar usando la forma de lectura / escritura, sintaxis 3, del BYTE (ver abajo). Lectura / escritura de Bytes en memoria principal (Sintaxis 3) En bloques PUB y PRI, la sintaxis 3 del BYTE se utiliza para leer o para escribir valores byte en memoria principal. Si se asume que el objeto contiene el bloque DAT del ejemplo de arriba, se podía utilizar el siguiente ejemplo para tener acceso a esos datos.

PUB GetData | Index, Temp Temp := BYTE[MyData] <do something with Temp> Index := 0 repeat Temp := BYTE[MyString][Index++] <do something with Temp> while Temp > 0

‘Lee el primer byte de MyData ‘a Temp ‘Realiza una tarea con Temp

‘Lee un dato string a Temp, ‘un carácter por vez ‘Realiza una tarea con caracter ‘en Temp ‘Bucle hasta el final

La primera línea del método GetData, arriba, utiliza la declaración del BYTE para leer un byte de memoria principal en localización MyData y lo almacena en Temp, en este caso, el valor 64. A continuación en el bucle de REPEAT, la declaración del BYTE lee un byte de memoria principal en localización MyString + el índice Index y lo almacena en Temp. Puesto que Index se fija a 0, el primer byte de MyString se lee, "H". Esa misma línea tiene un postincremento de Index con ++, por lo que la siguiente vuelta del bucle lee el siguiente byte, MyString + 1 (la "e"), y la próxima vez MyString + 2 (el "l"), etc. Usando una sintaxis similar, los bytes de memoria principal se pueden escribir también, mientras sean localizaciones RAM. Por ejemplo: BYTE[MyString][0] := "M"

‘Escribe M al primer carácter de MyString

Esta línea escribe el carácter "M" al primer byte de datos de la secuencia en MyString, cambiando la secuencia para ser "Mello", 0.

3-9


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.3. BYTEFILL Rellena la memoria principal con un valor. BYTEFILL (StartAddress, Value, Count ) • StartAddress es una expresión que indica la localización del primer byte en memoria a llenar del valor Value. • Value es una expresión que indica el valor de los bytes con los que se quiere rellenar. • Count es una expresión que indica el número de bytes a rellenar, comenzando con StartAddress. Explicación BYTEFILL es uno de tres comandos (BYTEFILL, WORDFILL, y LONGFILL) usados para llenar bloques de memoria principal de un valor específico. BYTEFILL rellena Count bytes de memoria principal con valor, comenzando en la localización StartAddress. Uso de BYTEFILL BYTEFILL es una gran manera de inicializar grandes bloques de la memoria. Por ejemplo: VAR byte Buff[100] PUB Main bytefill(@Buff, 0, 100)

‘Inicializar Buff a 0

La primera línea del método principal, arriba, fija el array entero Buff de 100-bytes a ceros. BYTEFILL es más rápido en esta tarea que es un bucle dedicado de la REPEAT. 3.3.4. BYTEMOVE Copia bytes de una región a otra en memoria principal. BYTEMOVE (DestAddress, SrcAddress, Count ) • • •

DestAddress es una expresión que especifica la localización destino en memoria principal para copiar el primer byte. SrcAddress es una expresión que especifica la localización en memoria principal del primer byte fuente para copiar. Count es una expresión que indica el número de bytes fuente para copiar al destino.

Explicación BYTEMOVE es uno de tres comandos (BYTEMOVE, WORDMOVE, y LONGMOVE) usados para copiar bloques de memoria principal a partir de una área a otra. BYTEMOVE copia Count Bytes de memoria principal que empiezan con SrcAddress a la memoria principal que comienza en DestAddress. Uso de BYTEMOVE BYTEMOVE es una gran manera de copiar grandes bloques de memoria byte. Por ejemplo: VAR byte Buff1[100] byte Buff2[100] PUB Main bytemove(@Buff2, @Buff1, 100)

'Copia Buff1 a Buff2

La primera línea del método principal, arriba, copia el array entero de 100-byte Buff1 al array Buff2. BYTEMOVE es más rápido en esta tarea que es un bucle dedicado de REPEAT.

3-10


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.5. CASE Compara una expresión emparejándola con otras expresiones y ejecuta el bloque de código en el que la expresión resulte verdadera. CASE CaseExpression MatchExpression : Statement(s) < MatchExpression : Statement(s) > < OTHER : Statement(s) > • • •

CaseExpression es la expresión a comparar. MatchExpression es una expresión, o una expresión de rango a comparar con CaseExpression. Cada MatchExpression debe seguir por dos puntos (:). Statement(s) es un bloque de una o más líneas de código a ejecutarse cuando CaseExpression empareja con el MatchExpression asociado. La primera, o única, declaración en Statement(s) puede aparecer a la derecha de los dos puntos en la línea de MatchExpression, o debajo de ella y tabulado levemente sobre MatchExpression.

Explicación CASE es uno de los dos comandos condicionales principales (IF y CASE) que ejecuta un bloque de código condicional. CASE es la estructura preferida a utilizar, en comparación con IF..ELSEIF..ELSE, cuando se necesita comparar la igualdad de CaseExpression a un número de distintos valores. CASE compara CaseExpression con los valores de cada MatchExpression, en orden, y si se encuentra una igualdad, ejecuta el Statement(s) asociado. Si no se encuentra ninguna igualdad en los emparejamientos anteriores, el Statement(s) asociado al comando opcional OTHER se ejecuta. La Sangría es critica IMPORTANTE: La sangría es crítica. El lenguaje Spin confía en la sangría (de un espacio o más) en líneas que siguen comandos condicionales para determinar si pertenecen a ese comando o no. Para que la herramienta Propeller indique éstos bloques de código agrupados lógicamente en pantalla, se puede presionar Ctrl + I y encender los indicadores de grupo . Presionando Ctrl + I otra vez esa característica se desactivara. Uso de CASE CASE es muy práctico donde se necesita que se realice una de varias acciones dependiendo del valor de una expresión. El siguiente ejemplo asume que A, X e Y son variables definidas anteriormente.

case X+Y 10 : !outa[0] A*2 : !outa[1] 30..40 : !outa[2] X += 5

‘Testea X+Y ‘X = 10? Activar P0 ‘X = A*2? Activar P1 ‘X en 30 a 40? Activar P2 ‘Suma 5 a X

Puesto que las líneas de MatchExpression están tabuladas de la línea de CASE, pertenecen a la estructura del CASE y se ejecutan basadas en los resultados de la comparación de CaseExpression. La línea siguiente, X + = 5, no está tabulada de CASE, así que se ejecuta sin importar los resultados del CASE. Este ejemplo compara el valor de X + Y con 10, A*2 y el rango 30 a 40. Si X + Y es igual a 10, se activa P0. Si X + Y es igual a A*2, se activa P1. Si X + Y está en el rango 30 a 40, inclusivo, entonces P2 se activa. Si o no ningún fósforo fue encontrado, X + = la línea 5 se ejecuta después.

3-11


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Uso de OTHER El componente opcional OTHER del CASE es similar al componente OTHER opcional de la estructura IF. Por ejemplo: case X+Y 10 : !outa[0] 25 : !outa[1] 20..30 : !outa[2] OTHER : !outa[3] X += 5

'Testea X+Y 'X = 10? Activar P0 'X = 25? Activar P1 'X en 20 a 30? Activar P2 ‘Si no, Activar P3 ‘Suma 5 a X

Este ejemplo es similar el anterior excepto que ése el tercer MatchStatement comprueba el rango 20 a 30 y hay un componente OTHER. Si X + Y no es igual a 10, ni 25, ni está en el rango 20 a 30, el bloque OTHER de Statement(s) siguiente se ejecuta. Siguiendo eso, se ejecuta la línea X + = 5. Hay un concepto importante a observar sobre este ejemplo. Si X + Y es 10, se activa P0, o si X + Y es 25, se activa P1, o si X + Y es 20 a 30, P2, etc. Esto es porque el MatchExpressions se comprueba uno por vez, en el orden en el que se enumeran y solamente se ejecuta el código de la primera expresión que se iguale esta. No se comprueban el resto de expresiones. Esto significa que si hubiéramos cambiado las líneas 25 y 20..30, para comprobar el rango de 20..30 primero, habría un fallo en nuestro código. Se hizo esto abajo:

case X+Y 10 : !outa[0] 20..30: !outa[2] 25 : !outa[1]

‘Testea X+Y ‘X = 10? Activar P0 ‘X en 20 a 30? Activar P2 ‘X = 25? Activar P1 <-- ESTE CODIGO NO SE ‘EJECUTARA NUNCA

El ejemplo anterior contiene un error porque, mientras que X + Y podría ser igual a 25, esa expresión nunca sería probada desde la anterior, porque se probaría 20..30 primero, y puesto que es verdad, se ejecutaría su bloque y no se aria ninguna comprobación posterior. Variaciones en Statement(s) Los ejemplos anteriores solo usan una línea como bloque de Statement(s), pero cada bloque puede tener varias líneas. Además, el bloque de Statement(s) puede también aparecer abajo, y tabulado levemente MatchExpression. Los dos ejemplos siguientes demuestran estas variaciones. case A 4 Z+1

: :

10..15:

!outa[0] !outa[1] !outa[2] !outa[3]

case A 4: !outa[0] Z+1: !outa[1] !outa[2] 10..15: !outa[3]

‘Testea A ‘A = 4? Activar P0 ‘A = Z+1? Activar P1 ‘Y Activar P2 ‘A en 10 a 15? Activar P3

‘Testea A ‘A = 4? ‘Activar P0 ‘A = Z+1? ‘Activar P1 ‘Y Activar P2 ‘A en 10 a 15? ‘Activar P3

3-12


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.6. CHIPVER Recoge el número de versión del chip del Propeller. CHIPVER Devuelve: El numero de versión del chip Propeller.

Explicación El comando CHIPVER lee y devuelve el número de versión del chip Propeller. Por ejemplo: V: = chipver Este ejemplo asigna a V con número de versión del chip Propeller, 1 en este caso. Las futuras Aplicaciones del Propeller pueden utilizarlo para determinar la versión y el tipo de chip del Propeller que están ejecutando y para hacer modificaciones a sus operaciones como sea necesario. 3.3.7. CLKFREQ Recoge la frecuencia de reloj actual del sistema; la frecuencia en la cual cada Cog está ejecutándose. CLKFREQ Devuelve: Frecuencia de reloj actual del sistema, en el Hz.

Explicación El valor devuelto por CLKFREQ es la frecuencia de reloj actual del sistema según lo determinado por el modo de reloj actual (tipo del oscilador, aumento, y ajustes de PLL) y la frecuencia externa del pin XI, si la hay. Los objetos usan CLKFREQ para determinar el retraso apropiado para operaciones muy sensibles al tiempo. Por ejemplo: waitcnt(clkfreq / 10 + cnt)

' esperar, 1 segundos (100ms).

Esta declaración divide CLKFREQ por 10 y asigna el resultado a CNT (el valor actual del Contador del Sistema) entonces espera (WAITCNT) hasta que el contador del sistema alcanza el valor del resultado. Puesto que CLKFREQ es el número de ciclos por segundo, hay que dividir por 10 el número de los ciclos de reloj por 0.1 segundo, o 100 ms. Así, sin hacer caso del tiempo que toma para procesar la expresión, esta declaración pausa la ejecución de programa del Cog en 100ms.

El valor que CLKFREQ devuelve puede cambiarse siempre que la aplicación cambie el modo de reloj, manualmente o a través del comando CLKSET. Los objetos que son sensibles al tiempo deben comprobar CLKFREQ en los puntos estratégicos para adecuarse a los nuevos ajustes automáticamente. CLKFREQ vs. _CLKFREQ CLKFREQ está relacionado con _CLKFREQ, pero no son iguales. CLKFREQ es el comando que devuelve la frecuencia de reloj actual del sistema mientras que _CLKFREQ es una constante definida por la aplicación que contiene la frecuencia de reloj del sistema en el arranque. Es decir CLKFREQ es la frecuencia de reloj actual y _CLKFREQ es la frecuencia de reloj original; ambos pueden tener el mismo valor pero ciertamente pueden ser diferentes.

3-13


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.8. _CLKFREQ Constante predefinida, ajustable una sola vez para especificar la frecuencia de reloj del sistema. CON _CLKFREQ = Expression •

Expression es una expresión del número entero que indica la frecuencia de reloj del sistema en el arranque de la aplicación.

Explicación _CLKFREQ especifica la frecuencia de reloj del sistema para el arranque. Es un símbolo constante predefinido cuyo valor es determinado por el fichero objeto superior de una aplicación. _CLKFREQ se puede ajustar directamente por la misma aplicación, o indirectamente como resultado de los ajustes de _CLKMODE y _XINFREQ. El fichero objeto superior en una aplicación (donde empieza la compilación) puede especificar un ajuste para _CLKFREQ en su bloque CON. Esto define la frecuencia de reloj inicial del sistema para la aplicación y es la frecuencia a la cual el reloj del sistema cambiará tan pronto como la aplicación arranque y la ejecución comience. La aplicación puede especificar tanto _CLKFREQ como _XINFREQ en el bloque CON; son mutuamente exclusivos y el no especificado se calcula y se fija automáticamente como resultado de la otra especificación. Los siguientes ejemplos asumen que están contenidos dentro del fichero objeto superior. Cualquier ajuste de _CLKFREQ en objetos hijo son simplemente ignorados por el compilador. Por ejemplo: CON _CLKMODE = XTAL1 + PLL8X _CLKFREQ = 32_000_000 La primera declaración en el bloque CON anterior, fija el modo de reloj para un cristal externo de poca velocidad y un PLL del reloj múltiplo de 8. La segunda declaración fija la frecuencia de reloj del sistema a 32 Mhz, que significa que la frecuencia del cristal externo debe ser 4 Mhz, porque 4 Mhz * 8 = 32 Mhz. El valor de _XINFREQ se fija automáticamente a 4 Mhz debido a estas declaraciones. CON _CLKMODE = XTAL2 _CLKFREQ = 10_000_000 Estas dos declaraciones fijaron el modo de reloj para un cristal externo de velocidad media, ningún multiplicador del reloj PLL, y una frecuencia de reloj del sistema de 10 Mhz. El valor de _XINFREQ se fija automáticamente a 10 Mhz, también, debido a estas declaraciones. _ CLKFREQ Vs CLKFREQ _CLKFREQ está relacionado con CLKFREQ, pero no iguales. _CLKFREQ contiene la frecuencia de reloj del sistema de la aplicación en el arranque mientras que CLKFREQ es un comando que devuelve la frecuencia de reloj actual del sistema. Es decir, _CLKFREQ es la frecuencia de reloj original del sistema y CLKFREQ es la frecuencia de reloj actual del sistema; ambos pueden tener el mismo valor pero ciertamente pueden ser diferentes.

3-14


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.9. CLKMODE Recoge el modo actual del reloj.

CLKMODE Devuelve: Modo actual del reloj.

Explicación El ajuste del modo de reloj es un valor de tamaño byte, fijado normalmente en tiempo en compilación, que es una combinación de las constantes de RCxxxx, de XINPUT, de XTALx y de PLLxx. Por ejemplo: Mode: = clkmode Esta declaración se puede utilizar para fijar una variable, Mode, al ajuste actual del modo de reloj. Muchas aplicaciones mantienen un ajuste estático del modo de reloj; sin embargo, algunas aplicaciones cambian el modo de reloj y lo fijan durante el tiempo de ejecución para ajustes de la velocidad de reloj, los modos de baja potencia, el etc. Puede ser necesario que algunos objetos presten la atención a los modos de reloj dinámicos para mantener la sincronización y la funcionalidad apropiadas. CLKMODE vs _CLKMODE CLKMODE está relacionado con _CLKMODE, pero no son iguales. CLKMODE es un comando que devuelve el modo de reloj actual mientras que _CLKMODE es una constante definida por la aplicación que contiene el modo de reloj solicitado por la aplicación en el arranque. Es decir, CLKMODE es el modo de reloj actual y _CLKMODE es el modo de reloj original; ambos pueden suceder tener el mismo valor pero ciertamente pueden ser diferentes. 3.3.10. _CLKMODE Constante predefinida, ajustable una sola vez para especificar ajustes del modo de reloj a nivel de aplicación. CON _CLKMODE = Expression •

Expression es una expresión de número entero cuyo resultado es un valor 8-bit del modo reloj. Éste será el modo de reloj en el arranque de la aplicación.

Explicación _CLKMODE se utiliza para especificar la naturaleza deseada del reloj del sistema. Es un símbolo constante predefinido cuyo valor es determinado por el fichero objeto superior de una aplicación. El ajuste del modo de reloj es un valor de tamaño byte que es una combinación de las constantes de RCxxxx, de XINPUT, de XTALx y de PLLxx. La tabla 4-1 ilustra el modo de reloj que fija constantes.

3-15


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

1. Todas las constantes están también disponibles en ensamblador del Propeller. 2. Todos los resistores/capacitadores necesarios se incluyen en chip Propeller. El fichero objeto superior en una aplicación (donde empieza la compilación) puede especificar un ajuste para _CLKMODE en su bloque CON. Esto define el modo de reloj inicial para la aplicación y es el modo al que cambiara el reloj del sistema, tan pronto como se arranque la aplicación y comience la ejecución. Los siguientes ejemplos asumen que están contenidos dentro del fichero objeto superior. Cualesquier ajuste de _ CLKMODE en objetos hijo son simplemente ignorados por el copilador. Por ejemplo: CON _CLKMODE = RCFAST Esto fija el modo de reloj para el circuito interno, RC rápido de Clock/Oscillator en el que el reloj del sistema funcionaría en aproximadamente 12 Mhz con este ajuste. El ajuste de RCFAST es el ajuste por defecto, así que si no se definiera ningún _CLKMODE, éste sería el ajuste utilizado. Observe que el reloj PLL no se puede utilizar con el RC interno Clock/Oscillator. Aquí hay un ejemplo con un reloj externo: CON _ CLKMODE = XTAL1 + PLL8X Esto fija el modo de reloj para un cristal externo de poca velocidad (XTAL1), que activa el circuito del reloj PLL y fija el reloj del sistema para utilizar el 8x del reloj PLL (PLL8X). Si se uniese un cristal externo de 4 Mhz a XI y XO, por ejemplo, su señal sería multiplicada por 16 (el reloj PLL se multiplica siempre por 16) pero se utilizaría el resultado 8x; el reloj del sistema sería 4 Mhz * 8 = 32 Mhz. CON _ CLKMODE = XINPUT + PLL2X Esto fija el modo de reloj para un reloj-oscilador externo, conectado solamente con XI, y activa el circuito del reloj PLL y fija el reloj del sistema para utilizar el resultado 2x. Observe que el reloj PLL no está requerido y puede ser inhabilitado simplemente no especificando ningún ajuste del multiplicador, por ejemplo: CON _ CLKMODE = XTAL1

3-16


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Esto fija el modo de reloj para un cristal externo de poca velocidad pero con las hojas del reloj PLL inhabilitadas; el reloj del sistema será igual a la frecuencia del cristal externo. Los ajustes de _CLKFREQ y _XINFREQ Para la simplicidad, los ejemplos de arriba solamente muestran ajustes de _CLKMODE, pero se requieren tanto ajustes de _CLKFREQ como de _XINFREQ para continuar, de modo que los objetos puedan determinar su frecuencia de reloj actual del sistema. Lo siguiente es el segundo ejemplo con una frecuencia de cristal externa (_ XINFREQ) de 4 Mhz. CON _CLKMODE = XTAL1 + PLL8X _XINFREQ = 4_000_000

‘cristal de baja velocidad x 8 ‘cristal externo 4 MHz

Este ejemplo es exactamente igual al segundo ejemplo de arriba, pero _ XINFREQ indica que la frecuencia del cristal externo es 4 Mhz. El chip Propeller utiliza este valor junto con el ajuste de _CLKMODE para determinar la frecuencia de reloj del sistema, de modo que los objetos puedan ajustarse correctamente su sincronización. _CLKMODE vs CLKMODE _ CLKMODE está relaciona con CLKMODE, pero no son iguales. _CLKMODE contiene el modo de reloj solicitado por la aplicación en el arranque mientras que CLKMODE es un comando que devuelve el modo de reloj actual. Es decir, _CLKMODE es el modo de reloj original y CLKMODE es el modo de reloj actual; ambos pueden tener ser el mismo valor pero ciertamente pueden ser diferentes. 3.3.11. CLKSET Fija el modo de reloj y la frecuencia de reloj del sistema en el tiempo de ejecución. CLKSET (Mode, Frequency) • •

Mode es una expresión de número entero compuesta de una combinación de los valores de RCxxxx, de XINPUT, de XTALx, y de PLLxx. El modo de reloj del Propeller será cambiado a Mode. Frequency es una expresión de número entero que indica la frecuencia de reloj del sistema.

Explicación Una de las características más potentes del chip Propeller es la capacidad de cambiar el comportamiento del reloj en el tiempo de ejecución. Una aplicación puede elegir activar o desactivar entre una velocidad de reloj lenta (para una consumición de potencia baja) y una velocidad de reloj rápida (para las operaciones de mucho ancho de banda), por ejemplo. CLKSET se utiliza para cambiar el modo y la frecuencia de reloj durante tiempo de ejecución. Es el equivalente en tiempo de ejecución las constantes _CLKMODE y _CLKFREQ definidas por la aplicación en de tiempo de compilación. Por ejemplo: clkset(XTAL1 + PLL2X,

4_000_000)

Esto fija el modo de reloj a un cristal externo de poca velocidad y un multiplicador del reloj PLL de 2, y fija la frecuencia de reloj del sistema a 4 Mhz. Después de ejecutar este comando, los comandos de CLKMODE y de CLKFREQ divulgarán los ajustes actualizados para los objetos que los utilizan.

3-17


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.12. CNT Registro Contador del Sistema. CNT Devuelve: El valor actual de 32-bits del Contador del Sistema. Explicación El registro de CNT contiene el valor actual de 32-bits del contador global del sistema. El contador del sistema sirve como referencia del tiempo central para todos los Cogs; incrementa su valor de 32-bits una vez por ciclo de reloj del sistema. Sobre encendido/reset, el contador del sistema comienza con un valor arbitrario y cuenta en ascendente desde ese valor, incrementándolo en cada ciclo de reloj del sistema. Puesto que el contador del sistema es un recurso inalterable, cada Cog puede leerlo simultáneamente y puede utilizar el valor devuelto para sincronizar acontecimientos, contar ciclos y medir tiempo. Uso de CNT Lee CNT para conseguir el valor actual del contador del sistema. El valor real en sí mismo no es importante para ningún propósito en particular, pero la diferencia en lecturas sucesivas si resulta ser muy importante. Habitualmente, el registro de CNT se utiliza para retrasar la ejecución por un período específico o sincronizar un acontecimiento al comienzo de una ventana de tiempo. Los ejemplos siguientes utilizan la instrucción de WAITCNT para alcanzar lo explicado. waitcnt(3_000_000 + cnt)

‘Espera a 3 millones de ciclos de reloj

El código anterior es un ejemplo de un "retraso fijo." Retrasa la ejecución del Cog en 3 millones de ciclos de reloj del sistema (alrededor de ¼ segundos si se esta ejecutando con un oscilador interno rápido). El siguiente es un ejemplo del " retraso sincronizado."

PUB Activa | TimeBase, OneMS dira[0]~~ OneMS := clkfreq / 1000 TimeBase := cnt repeat waitcnt(TimeBase += OneMS) !outa[0]

‘Fija P0 como salida ‘Calcula ciclos para 1 milisegundo ‘Recoge el contador actual ‘bucle infinito ‘Espera al comienzo del siguiente ‘milisegundo ‘ Activar P0

Aquí, el pin 0 de E/S se fija a la salida. Entonces la variable local OneMS se fija a la frecuencia de reloj actual del sistema dividida por 1000; es decir: el número de los ciclos de reloj del sistema por 1 milisegundo de tiempo. Después, la variable local timeBase se fija al valor actual del contador del sistema. Finalmente, las ultimas dos líneas del código repiten sin fin; esperando al comienzo del próximo milisegundo y activando el estado de P0. 3.3.13. COGID Recoge el numero de ID actual del Cog (0-7). COGID Devuelve: El ID actual del Cog (0-7).

3-18


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Explicación El valor devuelto por COGID es el identificador del Cog que ejecutó el comando. Normalmente, el código del Cog actual que se está ejecutando no importa, sin embargo, para algunos objetos puede que sea importante no perderlo de vista. Por ejemplo: PUB StopMyself ‘Detiene el cog que se está ejecutando cogstop(cogid) El método del ejemplo, StopMyself, tiene una línea de código que llama simplemente COGSTOP con COGID como parámetro. Como COGID devuelve la identificación del Cog en ejecución, esta rutina causa que el Cog se detenga. 3.3.14. COGINIT Arranca o reanuda un cog por su ID para ejecutar el código Spin o el código ensamblador del Propeller. COGINIT (CogID, SpinMethod <(ParameterList)>, StackPointer ) COGINIT (CogID, AsmAddress, Parameter ) • • • •

• •

CogID es la identificación (0 - 7) del Cog a arrancar, o reanudar. SpinMethod es el método Spin de PUB o PRI que debe ejecutar el Cog afectado. Opcionalmente, puede seguirle una lista de parámetros incluida entre paréntesis. ParameterList es una lista opcional, de unos o varios parámetros limitados por comas para SpinMethod. Debe ser incluido solamente si SpinMethod requiere parámetros. StackPointer es un indicador de memoria, como un array de longs, reservado para el espacio en pila del Cog afectado. El Cog afectado utiliza este espacio para almacenar datos temporales durante futuras llamadas y evaluaciones de expresiones. Si se asigna poco espacio, la aplicación no podrá ejecutarse o se ejecutará con extraños resultados. AsmAddress es la dirección de una rutina del ensamblador Propeller de un bloque de DAT. Parameter se utiliza para pasar opcionalmente un valor al Cog nuevo. Este valor termina en el registro de solo lectura (PAR) del cog. Parameter se puede utilizar para pasar un valor de 14-bit o la dirección de un bloque de memoria que se utilizará por la rutina del ensamblador. Parameter es requerido por COGINIT, pero si se necesita para su rutina simplemente se fija a un valor inofensivo como cero (0).

Explicación COGINIT trabaja exactamente como COGNEW con dos excepciones: 1) lanza código sobre un Cog específico cuya ID es CogID, y 2) no devuelve un valor. Puesto que COGINIT opera en un Cog específico, CogID, puede ser utilizado para detener y para reanudar un Cog activo en un solo paso. Código Spin (Sintaxis 1) Para ejecutar un método Spin en un Cog específico, el comando COGINIT necesita la identificación del Cog, el nombre del método, sus parámetros, y un puntero a un espacio de pila. Por ejemplo: coginit(1, Square(@X), @SqStack)

‘Lanza el cuadrado en Cog 1

Este ejemplo lanza el método Square en el Cog 1, pasando la dirección de X en Square y la dirección de SqStack como puntero de pila de COGINIT's. Código Ensamblador del Propeller (Sintaxis 2) Para ejecutar código ensamblador del Propeller en un Cog específico, el comando de COGINIT necesita la identificación del Cog, la dirección de la rutina del ensamblador , y un valor que se pueda utilizar opcionalmente por la rutina del ensamblador . Por ejemplo: coginit(2, @Update, Pos)

3-19


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Este ejemplo lanza la rutina del ensamblador del Propeller, Update, en el Cog 2 con la dirección de Pos en PAR del Cog 2. 3.3.15. COGNEW Arranca el siguiente Cog disponible para ejecutar el código Spin o código ensamblador del Propeller. COGNEW (SpinMethod <(ParameterList)>, StackPointer ) COGNEW (AsmAddress, Parameter ) Devuelve: El ID del nuevamente arrancado Cog (0-7) si es correcto, o -1 si es falso. • • •

• •

SpinMethod es el método Spin de PUB o PRI que debe ejecutar el nuevo Cog. Opcionalmente, puede seguirle una lista de parámetros incluida entre paréntesis. ParameterList es una lista opcional, de unos o varios parámetros limitados por comas para SpinMethod. Debe ser incluido solamente si SpinMethod requiere parámetros. StackPointer es un indicador de memoria, como un array de longs, reservado para el espacio en pila del Cog afectado. El Cog afectado utiliza este espacio para almacenar datos temporales durante futuras llamadas y evaluaciones de expresiones. Si se asigna poco espacio, la aplicación no podrá ejecutarse o se ejecutará con extraños resultados. AsmAddress es la dirección de una rutina del ensamblador Propeller de un bloque de DAT. Parameter se utiliza para pasar opcionalmente un valor al Cog nuevo. Este valor termina en el registro de solo lectura (PAR) del cog. Parameter se puede utilizar para pasar un valor de 14-bit o la dirección de un bloque de memoria que se utilizará por la rutina del ensamblador . Parameter es requerido por COGINIT, pero si se necesita para su rutina simplemente se fija a un valor inofensivo como cero (0).

Explicación COGNEW arranca un Cog nuevo y ejecuta un método Spin o una rutina de ensamblador del Propeller. Si es correcto, COGNEW devuelve el ID del Cog arrancado. Si no había Cogs disponibles, COGNEW devuelve -1. Código Spin (Sintaxis 1) Para ejecutar un método Spin en otro Cog, el comando COGNEW necesita el nombre del método, sus parámetros, y un puntero a un espacio de pila. Por ejemplo: VAR long SqStack[6]

‘Espacio de pila para Square cog

PUB Main | X X := 2 cognew(Square(@X), @SqStack) <check X here>

‘Inicializa X ‘Lanza Square en cog ‘Bucle y chequea X

PUB Square(XAddr) ‘Cuadrado del valor en XAddr repeat long[XAddr] *= long[XAddr] waitcnt(2_000_000 + cnt)

‘Repite lo siguiente de forma infinita ‘ Cuadrado del valor y lo reasigna ‘ Espera 2 millones de ciclos

Este ejemplo muestra dos métodos, Main y Square. Main arranca otro Cog que ejecuta de manera infinita Square, entonces Main puede mostrar los resultados en la variable X. Square, ejecutándose por otro Cog, toma el valor de XAddr, realiza el cuadrado de su valor y almacena el resultado nuevamente dentro de XAddr, después espera 2 millones de ciclos antes de que lo repita. El método principal, Main, declara una variable local, X, que se fija a 2 en su primera línea. Entonces Main arranca un Cog nuevo, con COGNEW, para ejecutar el método Square en otro Cog. El primer parámetro de COGNEW, Square(@X), es el método Spin a ejecutar y su parámetro requerido; en este caso le pasamos la dirección de la

3-20


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

variable X. El segundo parámetro de COGNEW, @SqStack, es la dirección del espacio de pila reservado para el nuevo Cog. Cuando un Cog se arranca para ejecutar código Spin, necesita un cierto espacio donde pueda almacenar datos temporales tales como pila de llamadas, parámetros de pila y la expresión resultante intermedia. Este ejemplo requiere solamente 6 longs de espacio de pila para operación apropiada. Después de que se ejecute el comando de COGNEW, se están ejecutando dos Cogs; el primero todavía está ejecutando el método principal y el segundo está comenzando a ejecutar el método Square. A pesar del hecho de que están utilizando código del mismo objeto Spin, se están ejecutando independientemente. La línea <check X here> se puede sustituir por código que utiliza el valor de X de alguna manera. Código Ensamblador del Propeller (Sintaxis 2) Para ejecutar código ensamblador del Propeller en otro Cog, el comando de COGNEW necesita la dirección de la rutina del ensamblador y un valor que se pueden utilizar opcionalmente por la rutina del ensamblador . Por ejemplo:

VAR byte Cog

‘Usado para almacenar el ID del nuevo cog ejecutar

PUB Start(Pos) : Pass ‘Arranca un nuevo cog para ejecutar Update con Pos, ‘devuelve Verdadero si es correcto Pass := (Cog := cognew(@Update, Pos) + 1) > 0 PUB Stop ‘Detiene el cog que arrancamos anteriormente, si lo hubiera. if Cog cogstop(Cog~ - 1) Este ejemplo muestra dos métodos, Start y Stop, dentro de un objeto hipotético. El diseño de ese objeto necesita lanzar otro Cog para ejecutar una rutina en ensamblador , llamada Update (no mostrada), y le pasa un parámetro, Pos. Puede necesitar más adelante parar ese nuevo Cog. El método Start toma un solo parámetro, Pos, y devuelve verdadero o falso para indicar si un nuevo Cog fue arrancado con éxito. Primero, llama COGNEW, "cognew(@Update, Pos)" con la dirección de la rutina Update como primer parámetro y Pos como el segundo parámetro. Además, toma el valor devuelto por COGNEW, que es el ID del Cog nuevo, o -1 si no hay ninguno disponible, suma 1 y almacena el resultado en la variable Cog; "Cog: = cognew(@Update, Pos) + 1 ". Por ultimo, si el Cog es mayor que (0) la fija su valor de retorno, Pass, a verdadero; si no se fija a falso. En este punto, si un Cog nuevo se arranca con éxito, ese nuevo Cog comienza a cargar el código ensamblador del Propeller llamado Update, y lo ejecuta. Mientras tanto la variable Cog de este objeto (en el Cog original) estará en el rango 1 a 8, representando el nuevo ID del Cog, 0 a 7. Si no se arrancó ningún Cog, Cog será 0. Más adelante, si se llama el método Stop, primero chequea la condición, "if Cog". Esta condición es verdadera solamente si el Cog es diferente a cero. Si es verdad era (es decir: un Cog se ha arrancado con éxito por la rutina Start) entonces se ejecuta la línea siguiente, "cogstop(Cog~ - 1)", y se pasa el ID del Cog para que este se detenga. La expresión Cog~ - 1 devuelve el resultado del Cog - 1 para el parámetro COGSTOP, y inicializa la variable del Cog a cero (0). Este ejemplo se puede mejorar haciendo que la llamada al método Stop esté en el método Start. Por ejemplo: PUB Start(Pos) : Pass ‘Arranca un nuevo cog para ejecutar Update con Pos, ‘devuelve verdadero si es correcto Stop Pass := (Cog := cognew(@Update, Pos) + 1) > 0

3-21


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Es importante observar que el campo Parameter está pensado para pasar una dirección larga, y solamente 14-bits (bits de 2 a 15) se pasan en el registro PAR del Cog. 3.3.16. COGSTOP Detiene un cog por su ID. COGSTOP (CogID ) • CogID es el ID (0 – 7) del cog a detener. Explicación COGSTOP detiene un Cog cuya ID sea CogID y pone ese Cog en un estado inactivo. En el estado inactivo, el Cog deja de recibir pulsos del reloj del sistema para reducir notablemente el consumo de energía. Para detener un Cog, hay que utilizar el comando COGSTOP con el ID del Cog a parar. Por ejemplo:

VAR byte Cog

‘Usado para almacenar el ID del nuevo cog ejecutar

PUB Start(Pos) : Pass ‘Arranca un nuevo cog para ejecutar Update con Pos, ‘devuelve verdadero si es correcto Pass := (Cog := cognew(@Update, Pos) + 1) > 0 PUB Stop ‘Detiene el cog arrancado antes, si lo hubiera. if Cog cogstop(Cog~ - 1) Este ejemplo, de la descripción de COGNEW, utiliza COGSTOP en el método PUB Stop para detener el Cog que fue arrancado previamente por el método Start. 3.3.17. CON Declara un bloque de Constantes. CON Symbol = Expression <((, | )) Symbol = Expresión>… CON #Expression (( ,| ))Symbol <((,.| )) Symbol>… CON Symbol <(( ,| )) Symbol>… • •

Symbol es el nombre deseado para la constante. Expression es cualquier número válido entero, o con punto flotante, o una expresión algebraica constante. Expression puede incluir otros símbolos constantes si estos fueron definidos previamente.

Explicación El bloque Constante es una sección del código fuente que declara símbolos constantes globales y ajustes globales de la configuración del Propeller. Ésta es una de las seis declaraciones especiales (CON, VAR, OBJ, PUB, PRI, y DAT) que proporcionan la estructura inherente a la lengua Spin. Las constantes son valores numéricos que no pueden cambiar en tiempo de ejecución. Pueden ser definidas en términos de valores únicos (1, $F, 65000, %1010, "A", los etc.) o como expresiones, llamadas expresiones constantes, (25 + 16/2, 1000 * 5, etc.) que siempre hacen referencia a un número específico.

3-22


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

El bloque Constante es un área de código usada específicamente para asignar símbolos (nombres útiles) a las constantes, para poder utilizar los símbolos en cualquier parte del código donde sea necesario usar ese valor constante. Esto hace que el código sea más legible y más fácil mantener, si más adelante hubiese que cambiar el valor de una constante a la que se haga referencia en varios lugares. Estas constantes son globales al objeto, de modo que cualquier método dentro de él puede utilizarlas. Hay muchas maneras de definir las constantes, que se describen abajo. Declaraciones Comunes de Constantes (Sintaxis 1) Las formas más comunes de declaración de constantes comienzan con CON en una línea, seguida por una o más declaraciones. CON debe comenzar en la columna 1 (la columna extrema izquierda) de la línea actual y las líneas siguientes se deben tabular por lo menos un espacio. Las expresiones pueden ser combinaciones de números, operadores, paréntesis, y caracteres acotados. Ejemplo: CON Delay = 500 Baud = 9600 Achar = “A” -oCON Delay = 500, Baud = 9600, AChar = “A” Ambos ejemplos crean un símbolo llamado Delay que es igual a 500, un símbolo llamado Baud que es igual a 9600, y un símbolo llamado AChar que es igual al carácter "A". Para la declaración Delay, por ejemplo, se podría también haber utilizado una expresión algebraica, por ejemplo: Delay = 250 * 2 La declaración anterior da como resultado un valor igual a 500, como antes, pero la expresión puede hacer que el código sea más fácil de entender. El bloque CON también se utiliza para especificar ajustes globales, como ajustes del reloj del sistema. El ejemplo de abajo se muestra cómo fijar el modo de reloj a cristal de poca velocidad, al reloj PLL a 8x, y especificar que el pin frecuencia de XIN es 4 Mhz. CON _CLKMODE = XTAL1 + PLL8X _XINFREQ = 4_000_000

Los valores de punto flotante también se pueden definir como constantes. Los valores de punto flotante son números reales (con los componentes fraccionarios) y están codificados en 32-bits. Para especificar una constante de punto flotante, se debe especificar que el valor es un valor de punto flotante; la expresión debe ser un valor de punto flotante o estar compuesto enteramente de valores de punto flotante (ningún número entero). Los valores de punto flotante se deben escribir de la siguiente forma: 1) dígitos decimales seguidos por un punto decimal y por un dígito decimal más por lo menos, 2) dígitos decimales seguidos por "e" (para el exponente) y un valor entero del exponente, o, 3) una combinación de 1 y 2. Los siguientes son ejemplos de constantes válidas: 0.5 valor de punto flotante 1.0 valor de punto flotante

3-23


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN 3.14 1e16 51.025e5 3+4 3.0 + 4.0 3.0 + 4 3.0 + FLOAT(4)

www.microcontroladores.com info@microcontroladores.com

valor de punto flotante valor de punto flotante valor de punto flotante expresión entera expresión de punto flotante expresión invalida; causa error de compilación expresión de punto flotante

A continuaron se muestra un ejemplo que declara una constante entera y dos constantes de punto flotante. CON Num1 = 20 Num2 = 127.38 Num3 = 32.05 * 18.1 - Num2 / float(Num1) El código anterior fija Num1, Num2 y Num3 a 20, a 127.38 y a 573.736, respectivamente. Hay que tener en cuenta que la expresión anterior de Num1 tiene que ser incluida en la declaración FLOAT de modo que el compilador lo trate como valor de punto flotante. El compilador del Propeller maneja constantes de punto flotante como números reales de simple precisión según lo descrito por el estándar IEEE-754. Enumeraciones (Sintaxis 2 y 3) Los bloques constantes pueden también declarar símbolos constantes enumerados. Las enumeraciones son símbolos agrupados lógicamente que tienen asignado un valor entero incremental único para el grupo. Por ejemplo, un objeto puede tener la necesidad de ciertos modos de operación. Cada uno de estos modos se puede identificar por un número, un 0, un 1, 2 y 3, por ejemplo. Los números por si mismos no son importantes para nuestro propósito; solo necesitan ser únicos dentro del contexto del modo de operación. Por ejemplo: CON ‘Declara los modos de operación RunTest = 0 RunVerbose = 1 RunBrief = 2 RunFull = 3 El ejemplo anterior sería suficiente para nuestro propósito; porque los usuarios de este objeto pueden indicar "RunFull" en vez de "3" para especificar el modo de operación deseado. El problema esta en que, definir un grupo lógico de ítems de esta manera puede causar fallos y problemas de mantenimiento porque si se altera algún valor (a propósito o por accidente) sin cambiar el resto por consiguiente, puede causar fallos en el programa. También, se puede imaginar un caso en el que haya 20 modos de operación. Ése sería un sistema mucho más largo de constantes y de más posibilidades de incidencias en el mantenimiento. Las enumeraciones solucionan este problema automáticamente incrementando el valor para los símbolos. Podemos rescribir el ejemplo anterior con sintaxis de enumeración: CON ‘Declara los modos de operación #0, RunTest, RunVerbose, RunBrief, RunFull Aquí, # 0, dice a compilador que comience a contar desde el número 0 y que fije el símbolo siguiente a ese valor. Entonces, cualquier símbolo adicional que no especifique su propio valor se asigna automáticamente el valor anterior más 1. El resultado es que RunTest es igual a 0, RunVerbose es igual a 1, RunBrief es igual a 2 y RunFull es igual a 3. Definir valores enumerados de esta manera tiene las ventajas de asegurar que los valores asignados sean únicos y contiguos dentro del grupo. Usando el ejemplo anterior, los métodos que los utilizan pueden hacer cosas como la siguiente (se asume que Mode es un símbolo fijado por un objeto llamador):

3-24


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

case Mode RunTest : <test code here> RunVerbose : <verbose code here> RunBrief : <brief code here> RunFull : <full code here> -oif Mode > RunVerbose <brief and run mode code here>

Lo siguiente también funciona y deja sitio para comentarios sobre cada modo.

CON ‘Declara los modos de operación #0 RunTest ‘Ejecuta en modo test RunVerbose ‘Ejecuta en modo verbose RunBrief ‘Ejecuta en modo brief RunFull ‘Ejecuta en modo full

El ejemplo anterior hace lo mismo que el ejemplo visto antes, pero ahora tenemos sitio conveniente para describir el propósito de cada modo sin perder la ventaja del incremento automático. Mas adelante, si hubiera una necesidad de agregar un quinto modo, lo agrega simplemente a la lista en cualquier posición que sea necesaria. Si hubiera necesidad de que la lista comenzase en un cierto valor, habría que cambiar el #0 a lo que se necesite: # 1, # 20, etc. Es posible incluso modificar el valor enumerado en el centro de la lista. CON ‘Declara los modos de operación #1, RunTest, RunVerbose, #5, RunBrief, RunFull Alcance de Constantes Las constantes simbólicas definidas en bloques constantes son globales al objeto en el cual se definen pero no fuera de ese objeto. Esto significa que las constantes se pueden alcanzar directamente en cualquier lugar dentro del objeto pero su nombre no estará en conflicto con los símbolos definidos en otros objetos padre o hijo. Las constantes simbólicas se pueden alcanzar indirectamente por objetos padre, usando la sintaxis de referencia constante. Ejemplo: OBJ Num : “Numbers” PUB SomeRoutine Format := Num#DEC

‘Fija Format a la constante Decimal de Numbers

Aquí un objeto, “Numbers," se declara como símbolo Num. Num es la referencia del objeto, # indica que necesitamos acceder a las constantes del objeto, y la DEC es la constante dentro del objeto que necesitamos. Esta característica permite que los objetos definan constantes para su propio uso y para que los objetos padre tengan acceso a esas constantes sin interferir con cualquier símbolo que crearon.

3-25


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.18. CONSTANT Declara expresiones constantes en línea para ser totalmente resueltas en tiempo de compilación. CONSTANT (ConstantExpression ) Devuelve: El valor resuelto de la expresión constante. • ConstantExpression es la expresión constante deseada.

Explicación El bloque CON se puede utilizar para crear constantes de expresiones que se referencian desde múltiples lugares en el código, pero hay ocasiones en las que una expresión constante se necesita con propósitos temporales. Sin el uso de la directiva CONSTANT, las expresiones en línea de un método se resuelven en el tiempo de ejecución, incluso si la expresión es un valor constante. Uso de CONSTANT La directiva CONSTANT puede crear expresiones constantes de un solo uso que guardan espacio de código y aumentan la velocidad de ejecución en tiempo de ejecución. Se muestran dos ejemplos abajo: Ejemplo 1, usando expresiones estándares en tiempo de ejecución: CON X = 500 Y = 2500 PUB Blink !outa[0] waitcnt(X+200 + cnt) !outa[0] waitcnt((X+Y)/2 + cnt)

‘expresión estándar en tiempo de ejecución ‘expresión estándar en tiempo de ejecución

Ejemplo 2, igual que arriba, pero con la directiva CONSTANT alrededor de expresiones constantes: CON X = 500 Y = 2500 PUB Blink !outa[0] waitcnt(constant(X+200) + cnt) CONSTANT !outa[0] waitcnt(constant((X+Y)/2) + cnt) CONSTANT

‘Uso de expresión en tiempo de ejecución

‘Uso de expresión en tiempo de ejecución

Los dos ejemplos anteriores hacen exactamente lo mismo: su método Blink activa P0, espera X+200 ciclos, activa de nuevo P0 y espera (X+Y)/2 ciclos antes de volver. Mientras que los símbolos de X y de Y del bloque CON pueden que necesiten usarse en múltiples lugares dentro del objeto, las expresiones de WAITCNT usadas en el método Blink solamente deberían necesitarse en ese lugar. Por esta razón, no tiene sentido definir constantes adicionales en el bloque CON para cosas como X+200 y (X+Y)/2. La directiva CONSTANT es perfecta para esta situación, porque resuelve cada expresión constante de un solo uso a un valor único, estático, guardando espacio de código y velocidad de ejecución. En el ejemplo 1, el método Blink consume 33 bytes de espacio de código mientras que método Blink del ejemplo 2, con la adición de la directiva CONSTANT, sólo requiere 23 bytes de espacio. Hay que observar que la porción de las expresiones de "+ cnt" no

3-26


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

está incluida dentro del paréntesis de la directiva CONSTANT; esto es porque cnt es una variable (variable del contador del sistema; vear CNT) así que su valor no puede resolverse en tiempo de compilación. Si una constante necesita utilizarse en más de un lugar del código, es mejor definirlo en el bloque CON, definiéndola solamente una vez y el símbolo que la representa se puede utilizarse múltiples veces. Constantes (pre-definidas) Las siguientes constantes están predefinidas por el compilador: TRUE FALSE POSX NEGX PI RCFAST RCSLOW XINPUT XTAL1 XTAL2 XTAL3 PLL1X PLL2X PLL4X PLL8X PLL16X

Verdadero lógico: -1 ($FFFFFFFF) Falso lógico: 0 ($00000000) Entero positivo máximo: 2,147,483,647 ($7FFFFFFF) Entero negativo máximo: -2,147,483,648 ($80000000) Valor Float para PI: ~3.141593 ($40490FDB) Oscilador interno rápido: $00000001 (%00000000001) Oscilador interno lento: $00000002 (%00000000010) Reloj/Oscilador externo: $00000004 (%00000000100) Cristal externo de baja velocidad: $00000008 (%00000001000) Cristal externo de media velocidad: $00000010 (%00000010000) Cristal externo de alta velocidad: $00000020 (%00000100000) Frecuencia externa 1: $00000040 (%00001000000) Frecuencia externa 2: $00000080 (%00010000000) Frecuencia externa 4: $00000100 (%00100000000) Frecuencia externa 8: $00000200 (%01000000000) Frecuencia externa 16: $00000400 (%10000000000)

(Todas estas constantes están también disponibles en el ensamblador del Propeller) TRUE y FALSE TRUE y FALSE se usan normalmente con propósito de comparación Boleana: if (X = TRUE) or (Y = FALSE) <código a ejecutar si la condición total se da> POSX y NEGX POSX y NEGX se usan típicamente con propósito de comparación o como un flag de un evento especifico: if Z > NEGX < código a ejecutar si Z no ha alcanzado el menor negativo> -oPUB FindListItem(Item) : Index Index := NEGX ‘Por defecto se fija a “no encontrado” <código para buscar un Item en la lista> if <se ha encontrado ítem > Index := <índice del ítem> PI PI se puede utilizar para cálculos de punto flotante, o constantes de punto flotante o valores variables de punto flotante que usan el objeto FloatMath. De RCFAST a PLL16X De RCFAST a PLL16X son constantes de ajusts del modo de reloj. Se explican en detalle en la sección de _CLKMODE.

3-27


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.19. CTRA, CTRB Registros de Control Contador A y Contador B CTRA CTRB Devuelve: El valor actual del contador A o contador de B del registro de control, si se usan como variable fuente. Explicación CTRA y CTRB son dos de los seis registros (CTRA, CTRB, FRQA, FRQB, PHSA, y PHSB) que afectan al comportamiento de los módulos del Contador de un Cog. Cada Cog tiene dos módulos contadores idénticos (A y B) que puede realizar muchas tareas repetitivas. Los registros de CTRA y de CTRB contienen los ajustes de la configuración del contador A y del contador B, respectivamente. La siguiente discusión utiliza CTRx, FRQx y PHSx para referirse a ambos pares de A y de B de cada registro. Cada uno de los dos módulos de contadores puede controlar o supervisar hasta dos pins de E/S y realizar la acumulación condicional de 32-bits del valor del registro de FRQx al registro de PHSx, en cada ciclo de reloj. Los módulos de contadores tienen su propio bucle de fase-bloqueada (PLLx) que se pueda utilizar para sintetizar frecuencias desde 64 Mhz a 128 Mhz. Con una pequeña configuración y en algunos casos un poco mantenimiento del Cog, los módulos de contadores se puede utilizar para: • • • • • • • • • •

Síntesis de la frecuencia. Medida de la frecuencia. Contador del pulso. Medida del pulso. Medida del estado multi-pin. Modulación de la anchura de pulso (PWM). Medida del tiempo de utilización. Conversión de digital a analógico (DAC). Conversión de analógico a digital (ADC). Y más.

Para algunas de estas operaciones el Cog puede fijar la configuración del contador, vía CTRA o CTRB, y realizará su tarea totalmente independientemente. Para otros, el Cog puede utilizar WAITCNT para alinear en tiempo en el que el contador lee y escribe dentro de un bucle; creando el efecto de una máquina de estados más compleja.

Campos del Registro de Control Cada registro CTRA y el CTRB contienen cuatro campos mostrados en la tabla abajo.

APIN El campo de APIN de CTRA selecciona un pin primario de E/S para ese contador. Puede ser ignorado si no se utiliza. %0xxxxx = puerto A, %1xxxxx = puerto B (reservado para uso futuro). En ensamblador del Propeller, el campo APIN se puede escribir usando la instrucción MOVS. Si se escribiese un cero en CTRA inhabilitaría inmediatamente el contador A y pararía todo el pin a salida y la acumulación a PHSA.

3-28


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

BPIN El campo de BPIN de CTRx selecciona un pin secundario de E/S para ese contador. Este campo puede ser ignorado si no se utiliza. %0xxxxx = puerto A, %1xxxxx = puerto B (reservado para uso futuro). En ensamblador del Propeller, el campo BPIN se puede escribir usando la instrucción MOVD. PLLDIV El campo de PLLDIV de CTRx selecciona una salida para PLLx. Esto determina qué energía de las dos divisiones de la frecuencia del VCO se utilizara como la salida final de PLLx (un rango de 500 KHz a 128 Mhz). Este campo puede ser ignorado si no se utiliza. En ensamblador del Propeller, el campo de PLLDIV se puede escribir, junto con CTRMODE, usando la instrucción MOVI.

CTRMODE El campo de CTRMODE de CTRA y de CTRB selecciona uno de los 32 modos de funcionamiento para el contador correspondiente A o B. En ensamblador del Propeller, el campo de CTRMODE se puede escribir, junto con PLLDIV, usando la instrucción MOVI. Los modos de %00001 a %00011 causan FRQx-a-PHSx, una acumulación que se da cada ciclo de reloj. Esto crea un oscilador controlado numéricamente (NCO) en PHSx[31], que alimenta la entrada de referencia del PLLx. El PLLx multiplicará esta frecuencia por 16 usando el controlado de voltaje del oscilador (VCO). Para operaciones estables, se recomienda que la frecuencia de VCO esté entre 64 Mhz y 128 Mhz. Esto se traduce a una frecuencia NCO de 4 Mhz a 8 Mhz. Uso de CTRA and CTRB En Spin, CTRx puede ser leido/escrito como cualquier otro registro o variable predefinida. En cuanto se escribe en este registro, el nuevo modo de funcionamiento entra en efecto para el contador. Por ejemplo: CTRA := %00100 << 26 El código anterior fija el campo CTRA de CTRMODE al modo NCO (%00100) y al resto de bits a cero.

3-29


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

* Debe fijar el correspondiente bit de DIR para afectar al pin A1 = Entrada APIN retrasada por 1 reloj A2 = Entrada APIN retrasada por 2 relojes B1 = Entrada BPIN retrasada por 1 reloj 3.3.20. DAT Declara un Bloque de Dato. DAT <Symbol>Size <Data><, <Size>Data>… DAT <Symbol><Condition>Instruction <Operand(s)><Effect(s)> • • • • •

Symbol es un nombre opcional para los datos, el espacio reservado, o la instrucción que sigue. Size es la alineación y el tamaño deseados (BYTE, WORD, o LONG) de los elementos de datos. Todos los datos serán alineados según la primera ocurrencia del tamaño Size. Cualquier otra ocurrencia de Size en la misma línea indica el tamaño del dato siguiente; la alineación no se cambia. Data es una expresión constante o una lista de expresiones constantes separadas por comas. También se permiten Las sentencias protegidas de caracteres; se tratan como una lista de caracteres separadas por comas. Condition es una condición en lenguaje ensamblador, IF_C, IF_NC, IF_Z, etc. Instruction es una instrucción en lenguaje ensamblador, ADD, SUB, MOV, etc.

3-30


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN • •

www.microcontroladores.com info@microcontroladores.com

Operand(s) es/son uno o dos operandos separados por comas en lenguaje ensamblador, "# valor", "x, # 8", etc. Effect(s) es/son uno, dos o tres efectos en lenguaje ensamblador, que causan que el resultado de la instrucción sea escrito o no, NR, WR, WC, o WZ.

Explicación Un bloque de datos es una sección de código fuente que contiene datos predefinidos, memoria reservada para el uso en tiempo de ejecución y el código ensamblador del Propeller. Ésta es una de las seis declaraciones especiales (CON, VAR, OBJ, PUB, PRI, y DAT) que proporcionan la estructura inherente al lenguaje Spin. Los bloques de datos son secciones multiusos de código fuente, que se utilizan para las tablas de datos, el espacio de trabajo en tiempo de ejecución, y código ensamblador del Propeller. El código y los datos de ensamblador se pueden entremezclar, en caso de necesidad, para cargar datos en un Cog junto con el código ensamblador . Declaring Data (Sintaxis 1) Los datos se declaran con una alineación y un tamaño específicos (BYTE, WORD, o LONG) para indicar cómo deben almacenarse en memoria. La localización en la que están actualmente almacenados los datos depende de la estructura del objeto y de la aplicación en la que se compila, si los datos están incluidos como parte del código compilado. Por ejemplo: DAT byte 64, “A”, “String”, 0 word $FFC2, 75000 long $44332211, 32 Lo primero que hay en la línea dos de este ejemplo, BYTE, indica que los datos que la siguen, deben ser de tamaño y alineación byte. En tiempo de compilación, los datos BYTE, 64, "A", etc., se almacenan en memoria de programa en el siguiente byte disponible. La línea tres especifica datos de tamaño y alineación word. Sus datos, $FFC2 y 75000, comenzarán en la siguiente posición al límite de word. La cuarta línea especifica datos long. La tabla 4-5 muestra lo que contendría la memoria (mostrada en hexadecimal).

Los primeros nueve bytes (0 - 8) son los datos del byte de la línea uno; $40 = 64 (decimal), $41 = "A", $53 = "S", etc. El byte 9 se rellena con ceros para alinear la primera palabra de datos word, $FFC2, en el byte 10. Los Bytes 10 y 11 (word 5) contienen el primer valor de tamaño word, $FFC2, almacenado en el formato “byte-bajo-primero” como $C2 y $FF. Los Bytes 12 y 13 (word 6) toman el valor de la palabra más baja de 75000; que se comentara mas adelante. Los Bytes 14 y 15 (word 7) se rellena a ceros para alinear el primer long de datos, $44332211. Los Bytes 16 a 19 (long 5) contienen ese valor en el formato “byte-bajo-primero”. Finalmente, los bytes 20 a 23 (long 6) contiene el segundo long de datos, 32, en el formato “byte-bajo-primero”. Se puede notar que el valor 75000 fue especificado como word. El número 75000 en hexadecimal es $124F8, pero como es mayor que un word, sólo se almaceno el valor del word mas bajo ($24F8). Esto da lugar al word 6 (bytes 12 y 13) que contiene $F8 y $24, y word 7 (bytes 14 y 15) que contiene $00 y $00 debido al “relleno” para los valores long siguientes.

3-31


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Este fenómeno, intencionado o no , ocurre también para los datos byte, por ejemplo: DAT Byte

$FFAA,

$BB995511

... da lugar a que solamente se almacenen los bytes mas bajos de cada valor, $AA y $11 . De vez en cuando, puede ser deseable almacenar un valor grande entero como unidades elementales más pequeñas. Para hacer esto, hay que especificar el tamaño justo antes del mismo valor. DAT byte word $FFAA, long $BB995511 Este ejemplo especifica datos alineados byte, pero un valor de tamaño word seguido por un valor de tamaño long. El resultado es que la memoria contiene $AA y $FF, consecutivamente, y seguido de, $11, $55, $99 y $BB. Si modificamos la línea tres del primer ejemplo de esta forma: word $FFC2, long 75000 ... entonces terminaríamos con $F8, $24, $01, y $00 ocupando los bytes de 12 a 15. El byte 15 es el byte de valor superior y va a pasar a estar inmediatamente a la izquierda del límite long siguiente así que no hay necesidad de rellenar los bytes a cero. Opcionalmente, el campo Symbol del sintaxis 1 se puede usar para "nombrar" los datos. Esto hace que sea mas fácil referirse a los datos de un bloque PUB o PRI. Por ejemplo: DAT MyData

byte $FF, 25, %1010

PUB GetData | Temp Temp := BYTE[MyData][0]

‘Recoge el primer byte de la tabla de datos

Este ejemplo crea una tabla de datos llamada MyData que contiene los bytes $FF, 25 y %1010. El método público, GetData, lee el primer byte de MyData de la memoria principal y lo almacena en su variable local, Temp. Escribir código Ensamblador del Propeller (Sintaxis 2) Además de los datos numéricos y strings, el bloque de los datos se utiliza para el código ensamblador del Propeller. Por ejemplo, DAT Loop

org rdlong if_z jmp movd :arg mov

t1, par WZ #loop :arg, #arg0 t2, t1

‘resetea el puntero de dirección ‘espera a comando ‘salto de cero ‘recoge 8 argumentos

Este ejemplo contiene símbolos opcionales, "loop" y ":arg", un condicional, "IF_Z", el campo de la instrucción, ORG, RDLONG, etc, seguidos por operandos y una declaración, "wz." 3.3.21. DIRA, DIRB Registro de Direcciones para los puertos A y B de 32 bits. DIRA <[Pin(s)]> DIRB <[Pin(s)]>(Reservado para uso futuro)

3-32


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Devuelve: Valor actual de los bits de dirección de E/S de Pin(s) en los puertos A o B, si está utilizado como variable fuente. • Pin(s) es una expresión opcional, o una expresión de rango, que especifica el pin ,o pins, de E/S para acceder al puerto A (0-31) o al puerto B (32-63). Si se da una expresión única, solamente se tendrá acceso al pin especificado. Si se da una expresión de tipo rango (dos expresiones en un formato rango; x..y) se tendrá acceso a los pins contiguos desde el comienzo de la expresión hasta el fin. Explicación DIRA y DIRB son uno de los seis registros (DIRA, DIRB, INA, INB, OUTA y OUTB) que afectan directamente los pins de E/S. El registro DIRA contiene los estados de la dirección de cada uno de los 32 pins de E/S en el puerto A; los bits 0 a 31 corresponden de P0 a P31. El registro de DIRB contiene los estados de la dirección de cada uno de los 32 pins de E/S en el puerto B; los bits 0 a 31 corresponden de P32 a P63. NOTA: DIRB está reservado para el uso futuro; el Propeller P8X32A no incluye los pins de E/S del puerto B. DIRA se utiliza para fijar y recoger los estados de la dirección actual de uno o más pins de E/S en el puerto A. Un bit bajo (0) fija el pin correspondiente de E/S a una dirección de entrada. Un bit alto (1) fija el pin correspondiente de E/S a una dirección de salida. El registro de DIRA es cero por defecto, en el arranque del Cog; todos los pins de E/S están fijados como entradas por ese Cog hasta que el código diga lo contrario. Cada Cog tiene acceso a todos los pins de E/S en cualquier momento. Esencialmente, todos los pins de E/S están conectados directamente con cada Cog. Esta configuración se puede describir con las siguientes reglas: A. Un pin es una entrada sólo de Cogs no activos fijados a salida. B. Un pin es una salida si cualquier Cog activo lo fija a salida.

Uso de DIRA Fija a uno o a cero los bits en DIRA para afectar a la dirección de los pins de E/S según lo deseado. Por ejemplo: DIRA := %00000000_00000000_10110000_11110011 El código anterior fija el registro completo de DIRA (los 32-bits de una vez) a un valor que hace los pins de E/S 15, 13, 12, 7, 6, 5, 4, 1 y 0 a salidas y al resto a entradas. Usando los operadores unitarios post-clear (~) y post-set (~~), el Cog puede fijar todos los pins de E/S a entradas, o a salidas, respectivamente; aunque generalmente no es deseable fijar todos los pins de E/S a salidas. Por ejemplo: DIRA~ --y-DIRA~~

‘Fija a 0 el registro DIRA (todas las E/S son entradas) ‘Fija a 1 el registro DIRA (todas las E/S son salidas)

Para afectar solamente un pin de E/S (un bit), se debe incluir el campo opcional Pin(s). Esto trata el registro de DIRA como array de 32-bits. DIRA[5]~~

‘Fija a 1 el bit 5 de DIRA (P5 a salida)

Esto fija P5 a salida. Todos los demás bits de DIRA siguen en su estado anterior. El registro DIRA soporta una forma especial de expresión, llamada expresión de rango, que permite afectar a un grupo de pins de E/S, sin afectar otros fuera del rango especificado. DIRA[5..3]~~

‘Fija a 1 desde el bit 5 al 3de DIRA (P5-P3 ‘a salida)

Esto fija P5, P4 y P3 a salida; todos los demás bits de DIRA recuerdan su estado previo. A contignación se muestra otro ejemplo:

3-33


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN DIRA[5..3] := %110

www.microcontroladores.com info@microcontroladores.com

‘Fija P5 y P4 a salida y P3 a entrada

El ejemplo anterior fija los bits 5, 4 y 3 de DIRA a 1, 1, y 0, respectivamente, dejando el resto de los bits en su estado anterior. Por lo tanto, P5 y P4 ahora son salidas y P3 es una entrada.

Normalmente DIRA se escribe pero también se puede leer para recuperar el pin de direcciones de E/S actual. El ejemplo siguiente asume que Temp es una variable creada en otra parte:

Temp := DIRA[7..4]

‘Recoge la dirección de P7 a P4

Lo anterior fija Temp a los bits 7, 6, 5, y 4 de DIRA; es decir: los 4 bits más bajos de Temp son iguales ahora DIRA7:4 y los otros bits de Temp se aclararon a cero. 3.3.22. FILE Importa un fichero externo como datos. FILE “FileName” •

FileName es el nombre, sin la extensión, del fichero de datos. FileName puede contener cualquier carácter válido de fichero; los caracteres no permitidos son \, /,:, *?, ", y |.

Explicación El directorio FILE se utiliza para importar un fichero de datos externo (generalmente un archivo binario) en el bloque de DAT de un objeto. De esta manera los datos se pueden alcanzar por el objeto, como cualquier dato normal del bloque de DAT. Uso de FILE FILE se utiliza en los bloques de DAT de manera similar a como se usan BYTE, WORD o LONG excepto que lo que sigue es un nombre de fichero en vez de valores de los datos. Por ejemplo: DAT Str byte Data file

“This is a data string.”, 0 “Datafile.dat”

En este ejemplo, el bloque de DAT se compone de una secuencia (string) de bytes seguida por los datos de un fichero llamado Datafile.dat. Antes de la compilación, la herramienta Propeller buscará por de las etiquetas de editores, del directorio en uso o del directorio de biblioteca para un archivo llamado Datafile.dat y cargará sus datos en el primer byte de string libre. Los métodos pueden acceder a los datos importados usando declaraciones BYTE, WORD o LONG como los datos normales. Por ejemplo: PUB GetData | Index, Temp Index := 0 repeat Temp := byte[Data][Index++] ‘Lee el dato a Temp 1 byte por vez <do something with Temp> ‘Realiza una tarea con valor para Temp while Temp > 0 ‘Bucle hasta que encuentre en final

Este ejemplo leerá los datos importados, un byte cada vez, hasta que encuentra un byte igual a 0.

3-34


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.23. FLOAT Convierta una expresión entera a un valor de punto flotante en tiempo de compilación. FLOAT (IntegerConstant) Devuelve: El valor resuelto de la expresión de la constante entera como número de punto flotante. •

IntegerConstant es la expresión deseada de la constante entera que se utilizará como valor constante de punto flotante.

Explicación El FLOAT es una de las tres directivas (FLOAT, ROUND and TRUNC) usadas para las expresiones constantes de punto flotante. La directiva FLOAT convierte un valor constante entero a un valor constante de punto flotante. Uso de FLOAT Mientras que la mayoría de las constantes son valores enteros de 32-bits, el compilador del Propeller soporta valores de 32-bits de punto flotante y expresiones constantes para el uso en tiempo de compilación. Hay que tener en cuenta que esto es únicamente para expresiones constantes, no para expresiones variables en tiempo de ejecución. Para declaraciones constantes de punto flotante, la expresión se debe mostrar como valor de punto flotante en una de estas tres maneras siguientes: 1) como número entero seguido por un punto y por lo menos un dígito, 2) como número entero con una E seguido por un valor del exponente, o 3) 1 y 2. Por ejemplo: CON OneHalf = 0.5 Ratio = Miles = 10e5

2.0 / 5.0

El código anterior crea tres constantes de punto flotante. OneHalf es igual a 0.5, el Ratio es igual a 0.4 y Miles es igual a 1.000.000. Se aprecia que en el ejemplo anterior, cada componente de cada expresión está mostrado como un valor de punto flotante. Ahora se muestra el ejemplo siguiente: CON Two Ratio

= =

2 Two / 5.0

Aquí, Two se define como una constante entera y Ratio aparece definida como constante de punto flotante. Esto causa un error en la línea Ratio porque, para las expresiones constantes de punto flotante, cada valor dentro de la expresión debe ser un valor de punto flotante; no se puede mezclar valores de número entero y de punto flotante como en Ratio = 2/5.0. Se puede, sin embargo, utilizar la directiva FLOAT para convertir un valor de número entero a un valor de punto flotante, por ejemplo en el siguiente: CON Two = 2 Ratio = float(Two) / 5.0 La directiva FLOAT en este ejemplo convierte la constante entera, Two, en la forma de punto flotante de ese valor para poderlo utilizarlo en la expresión de punto flotante. Sobre el Punto Flotante El compilador del Propeller maneja constantes de punto flotante como números reales de simple precisión según lo descrito por el estándar IEEE-754.

3-35


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.24. _FREE Constante predefinida, ajustable una sola vez para especificar el tamaño del espacio libre de una aplicación. CON _FREE = Expression • Expression es un número entero que indica que el número de longs a reservar para el espacio libre. Explicación _FREE es una constante opcional predefinida, ajustable una sola vez que especifica la memoria libre requerida de una aplicación. Este valor se agrega a _STACK, si está especificado, para determinar la cantidad total de memoria de free/stack a reservar para una aplicación Propeller. Se utiliza _FREE si una aplicación requiere una cantidad mínima de memoria libre para ejecutarse correctamente. Si la aplicación compilada resultante es demasiado grande para permitir la memoria libre especificada, se mostrara un mensaje de error. Por ejemplo: CON _FREE = 1000 La declaración de _FREE en el bloque CON anterior indica que la aplicación necesita tener por lo menos 1.000 longs de memoria libre después de la compilación. 3.3.25. FRQA, FRQB Contador A y B del Registro de Frecuencia. FRQA FRQB Devuelve: Valor actual del contador A o del contador B del registro de frecuencia, si está utilizado como variable de fuente. Explicación FRQA y FRQB son dos de los seis registros (CTRA, CTRB, FRQA, FRQB, PHSA, y PHSB) que afectan el comportamiento de los módulos del Contador de un Cog. Cada Cog tiene dos módulos Contador idénticos (A y B) que puede realizar muchas tareas repetitivas. El registro de FRQA contiene el valor que se acumula en el registro de PHSA. El registro de FRQB contiene el valor que se acumula en el registro de PHSB. Uso de FRQA and FRQB FRQA y FRQB pueden ser leidos/escritos como cualquier otro registro o variable predefinida. Por ejemplo: FRQA := $00001AFF El código anterior fija FRQA a $00001AFF. Dependiendo del campo de CTRMODE del registro de CTRA, este valor en FRQA se puede sumar en el registro de PHSA en una frecuencia determinada por el reloj del sistema y los pins primarios y/o secundarios de E/S. 3.3.26. IF Comprueba una o varias condiciones y ejecuta un bloque de código en el aso de que sean verdadero. IF Condition(s) IfStatement(s) <ELSEIF Condition(s) ElseIfStatement(s) >… <ELSE

3-36


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

ElseStatement(s) > • • • •

Condition(s) es una o más expresiones boleanas a probar. IfStatement(s) es un bloque de una o más líneas del código para ejecutarse cuando si Condition(s) es verdadero. ElseIfStatement(s) es un bloque opcional de una o más líneas del código para ejecutarse cuando todo el Condition(s) anterior es falso y el Condition(s) del ELSEIF es verdadero. ElseStatement(s) es un bloque opcional de una o más líneas del código para ejecutarse cuando todos los Condition(s) anteriores son falsos.

Explicación IF es uno de los dos comandos condicionales principales (IF y CASE) que ejecuta de forma condicional un bloque del código. IF se puede combinar opcionalmente con uno o más comandos de ELSEIF y/o un comando de. IF comprueba Condition(s) y, si es verdadero, ejecuta IfStatement(s). Si Condition(s) es falso, se comprueban los siguientes Condition(s) opcionales de ELSEIF, en orden, hasta que se encuentra una línea verdadera de la condición, entonces se ejecuta el bloque asociado de ElseIfStatement(s). Se ejecuta el bloque opcional de ElseStatement(s) si no se encuentra ninguna condición verdadera anterior. La Sangría es critica IMPORTANTE: La sangría es crítica. El lenguaje Spin confía en la sangría (de un espacio o más) en líneas que siguen comandos condicionales para determinar si pertenecen a ese comando o no. Para que la herramienta Propeller indique éstos bloques de código agrupados lógicamente en pantalla, se puede presionar Ctrl + I y encender los indicadores de grupo . Presionando Ctrl + I otra vez esa característica se desactivara. Sentencia IF Simple La forma más común del comando IF condicional realiza una acción si, y solo si, una condición es verdadera. Esto se escribe como una declaración IF seguida por una o más líneas tabuladas de código. Por ejemplo: if X > 10 !outa[0] !outa[1]

‘Si X es mayor que 10 ‘Activa P0 ‘Activa P1

Este ejemplo comprueba si X es mayor que 10; si es así, se activa el pin 0 de E/S. Sea o no verdadera la condición IF, el pin P1 de E/S se activara después. Como la línea !outa[0] está tabulada desde la línea IF, pertenece al bloque de IfStatement(s) y ejecutada solamente si la condición IF es verdadera. La línea siguiente, !outa[1 ], no está tabulada desde la línea IF, así que esta se ejecuta después Condition(s) sea o no verdad. Aquí hay otra versión del mismo ejemplo: if X > 10 !outa[0] !outa[1] waitcnt(2_000 + cnt)

‘Si X es mayor que 10 ‘Activa P0 ‘Activa P1 ‘Espera a 2,000 ciclos

Este ejemplo es muy similar al primero, excepto que ahora haya dos líneas de código tabuladas de declaración IF. En este caso, si X es mayor que 10, se activa P0 entonces se activa P1 y finalmente se ejecuta la línea del waitcnt. Si, por el contrario, X no era mayor que 10, se saltarían las líneas de !outa[0] y !outa[1] (puesto que están tabuladas y son parte del bloque de IfStatement(s)) y se ejecuta la línea de waitcnt (puesto que no está tabulada; no es parte del bloque de IfStatement(s)).

3-37


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Combinando Condiciones El campo Condition(s) se evalúa como una sola condición boleana, pero se puede componer de más de una expresión boleana combinando con los operadores AND y OR. Por ejemplo: if X > 10 AND X < 100 ‘Si X es mayor que 10 y menor que 100 Esta declaración del IF sería verdadera si, y solo si, X es mayor que 10 y X es también menor que 100. Es decir, X es verdadero si está en el rango de 11 a 99. Para hacer más fácil leer este tipo de condiciones, se pueden utilizar paréntesis para agrupar cada subcondición, por ejemplo como el siguiente. if (X > 10) AND (X < 100)

‘Si X es mayor que 10 y menor que 100

Usando IF con ELSE La segunda forma común del comando condicional IF realiza una acción si una condición es verdad o una diversa acción si esa condición es falsa. Esto se escribe como una declaración IF seguida por su bloque de IfStatement(s), después un ELSE seguido por su bloque de ElseStatement(s), según lo mostrado abajo: If

X > 100 !outa[0] else !outa[1]

‘Si X es mayor que 100 ‘Activa P0 ‘Si no, X <= 100 ‘Activa P1

Aquí, si X es mayor que 100, se activa el pin 0 de E/S, si no, X debe ser menor o igual a 100, y se activa el pin 1 de E/S. Esta estructura de IF... ELSE, realiza siempre una activación de P0 o P1; nunca ambos, y ninguno. Uso de IF con ELSEIF La tercera forma del comando condicional IF realiza una acción si una condición es verdadera o una diversa acción si esa condición es falsa pero otra condición es verdad, etc. Esto se escribe como declaración del IF seguida por su bloque de IfStatement(s), después una o más declaraciones de ELSEIF seguidos por sus bloques respectivos de ElseIfStatement(s). Aquí hay un ejemplo: if X > 100 !outa[0] elseif X == 90 !outa[1]

‘Si X es mayor que 100 ‘Activa P0 ‘Si no, si X = 90 ‘Activa P1

Aquí, si X es mayor que 100, se activa el pin 0 de E/S, si no, si X es igual a 90, el pin 1 de E/S se activa, y si ninguna de esas condiciones son verdaderas, ni se activa P0 ni P1. Ésta es una forma de escritura levemente más corta que el código siguiente: if X > 100 !outa[0] else if X == 90 !outa[1]

‘Si X es mayor que 100 ‘Activa P0 ‘Si no, ‘Si X = 90 ‘Activa P1

Ambos ejemplos realizan las mismas acciones, pero el primero es más corto y generalmente se considera más fácil leer. if X > 100 !outa[0] elseif X == 90 !outa[1] elseif X > 50 !outa[2]

‘Si X es mayor que 100 ‘Activa P0 ‘Si no, si X = 90 ‘Activa P1 ‘Si no, si X > 50 ‘Activa P2

3-38


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

En este ejemplo, tenemos tres condiciones y tres acciones posibles. Como el ejemplo anterior, si X es mayor que 100, se activa P0, si no, si X es igual a 90, se activa P1, pero si no se cumplen ninguna de las condiciones y X es mayor que 50, se activa P2. Si no se cumple ninguna condición, no se ejecuta ninguna acción. Hay un concepto importante a observar sobre este ejemplo. Si X es 101 o superior, se activa P0, si X es 90, se activa P1, y si X es de 51 a 89, o 91 a 100, P2. Esto es porque las condiciones del IF y de ELSEIF se comprueban de forma secuencial y solo se ejecuta el código de la primera condición que resulte verdadera. Esto significa que si hubiéramos cambiado de orden los dos ELSEIFs, de modo que se comprobase primero "X > 50", tendríamos un fallo en nuestro código. Por ejemplo: if X > 100 !outa[0] elseif X > 50 !outa[2] elseif X == 90 !outa[1]

‘Si X es mayor que 100 ‘Activa P0 ‘Si no, si X > 50 ‘Activa P2 ‘Si no, si X = 90 <-- ERROR DE COND. ‘Activa P1 <-- ESTE CODIGO NO SE ‘ALCAZARIA NUNCA

Uso de IF with ELSEIF and ENDIF La forma final del comando condicional del IF realiza una de varias acciones si una de esas condiciones fuera verdadera, o una acción alternativa si ningunas de las condiciones anteriores se cumpliera. Esto se escribe con un IF, uno o más ELSEIF, y finalmente un ELSE. Aquí hay un ejemplo: if X > 100 !outa[0] elseif X == 90 !outa[1] elseif X > 50 !outa[2] else !outa[3]

‘Si X es mayor que 100 ‘Activa P0 ‘Si no, si X = 90 ‘Activa P1 ‘Si no, si X > 50 ‘Activa P2 ‘Si no, ‘Activa P3

3.3.27. INA, INB Registros de entrada de 32-bits Puerto A y B. INA <[Pin(s)]> INB <[Pin(s)]>(Reservado para uso futuro) Devuelve: Estado actual de los pins E/S de Puerto A o B. •

Pin(s) es una expresión opcional, o una expresión de rango, que especifica el pin ,o pins, de E/S para acceder al puerto A (0-31) o al puerto B (32-63). Si se da una expresión única, solamente se tendrá acceso al pin especificado. Si se da una expresión de tipo rango (dos expresiones en un formato rango; x..y) se tendrá acceso a los pins contiguos desde el comienzo de la expresión hasta el fin.

Explicación INA e INB son uno de los seis registros (DIRA, DIRB, INA, INB, OUTA y OUTB) que afectan directamente los pins de E/S. El registro INA contiene los estados actuales de cada uno de los 32 pins de E/S en el puerto A; los bits 0 a 31 corresponden de P0 a P31. El registro de DIRB contiene los estados actuales de cada uno de los 32 pins de E/S en el puerto B; los bits 0 a 31 corresponden de P32 a P63. NOTA: INB está reservado para el uso futuro; el Propeller P8X32A no incluye los pins de E/S del puerto B.

3-39


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

INA es de solo-lectura y no está realmente implementado como un registro es mas como una dirección que, lee los pins del puerto A E/S en el momento en el que es accedida. El resultado puede mostrar, un bit bajo (0) que indica que el pin correspondiente E/S está a tierra, y un bit alto (1) que indica que el pin correspondiente de E/S está a VDD (3.3 voltios). Cada Cog tiene acceso a todos los pins de E/S en cualquier momento. Esencialmente, todos los pins de E/S están conectados directamente con cada Cog. Debido a la naturaleza "wired-OR" de los pins de E/S, no hay contención eléctrica entre los Cogs, y se puede tener acceso a los pins de E/S simultáneamente. Es función del desarrollador de la aplicación asegurarse de que ningunos de los Cogs causan contención lógica en el mismo pin de E/S durante el tiempo de ejecución. Uso de INA Lee INA para conseguir el estado de los pins de E/S en ese momento. El ejemplo siguiente asume que Temp fue creado en otra parte.

Temp := INA

‘Recoge el estado de P0 a P31

Este ejemplo lee los estados de los 32 pins de E/S del puerto A y los deja en Temp. Usando el campo opcional Pin(s), el Cog puede leer un pin de E/S (un bit) a la vez. Por ejemplo: Temp := INA[16]

‘Recoge el estado de P16

La línea anterior lee el pin 16 de E/S y almacena su estado (0 o 1) en el bit más bajo de Temp; el resto de los bits de Temp se ponen a 0. En Spin, el registro de INA soporta una forma especial de expresión, llamada una expresión de rango, que permite que se lean un grupo de pins de E/S inmediatamente, sin leer los que quedan fuera del rango especificado. Para leer los múltiples pins, contiguos de E/S, hay que utilizar una expresión de rango (como x..y) en el campo de Pin(s). Temp := INA[18..15]

‘Recoge los estados de P18:P15

Aquí, los cuatro bits más bajos de Temp (3, 2, 1, y 0) se fijan a los estados de los pins 18, 17, 16, y 15, respectivamente, y el resto de los bits de E/S de Temp se fijan a 0. IMPORTANTE: El orden de los valores en una expresión de rango afecta a la utilización. Por ejemplo: Temp := INA[15..18]

‘Recoge los estados de P15:P18

Aquí, los bits 3, 2, 1, y 0 de Temp se fijan a los estados de los pins 15, 16, 17, y 18 de E/S, respectivamente (al contrario del ejemplo anterior). 3.3.28. LOCKCLR Fija el semáforo a falso y recoge su estado anterior.

LOCKCLR ( ID ) Devuelve: El estado previo del semáforo (Verdadero o Falso). •

ID es el ID (0 – 7) del semáforo que se quiere poner a falso.

Explicación

3-40


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

LOCKCLR es uno de los cuatro comandos del semáforo (LOCKNEW, LOCKRET, LOCKSET, y LOCKCLR) usados para manejar los recursos que son definidos por el usuario y de uso mutuo-exclusivo. LOCKCLR fija a falso el semáforo de identificador ID semáforo y recupera el estado anterior de ese semáforo (verdadero o falso). Lo siguiente asume que un Cog (éste u otro) ya ha comprobado un semáforo usando LOCKNEW y ha compartido ya el ID con este Cog, que se guarda como SemID. También asume que este Cog tiene un array de longs llamado LocalData. PUB ReadResource | Idx repeat until not lockset(SemID) repeat Idx from 0 to 9 LocalData[Idx] := long[Idx] lockclr(SemID) PUB WriteResource | Idx repeat until not lockset(SemID) repeat Idx from 0 to 9 long[Idx] := LocalData[Idx] lockclr(SemID)

‘espera hasta que bloqueemos el recurso ‘leer todos los longs (10) del array ‘desbloquea el recurso

‘espera hasta que bloqueemos el recurso ‘escribe todos los longs (10) del array al ‘recurso ‘desbloquea el recurso

Ambos métodos, ReadResource y WriteResource, siguen las mismas reglas antes y después de acceder al recurso. Primero, esperan indefinidamente en el primer bucle de repetición hasta que se bloquee el recurso; es decir: se ha fijado con éxito el semáforo asociado a falso. Si LOCKSET devuelve verdadero, la condición "until not lockset..." es falso, y significa que actualmente hay otro Cog accediendo al recurso, de modo que el primer bucle se repetirá otra vez. Si LOCKSET devuelve falso, la condición " until not lockset..." es verdadero, significando se ha bloqueado el recurso. El segundo bucle de repetición de cada método, lee o escribe el recurso, a través de las declaraciones long[Idx] y LocalData[Idx]. La ultima línea de cada método, lockclr(SemID), fija el semáforo asociado del recurso a falso, lógicamente desbloqueando o liberando el recurso para otros usos. 3.3.29. LOCKNEW Chequea un semáforo nuevo y recoge su ID.

LOCKNEW Devuelve: El idetificativo ID (0-7) del semáforo que se ha chequeado o –1 si no había ninguno disponible.

Explicación LOCKNEW es uno de los cuatro comandos del semáforo (LOCKNEW, LOCKRET, LOCKSET, y LOCKCLR) usados para manejar los recursos que son definidos por el usuario y usado como mutuo-exclusivo. LOCKNEW comprueba un semáforo único, del Hub, y recupera la identificación ID de ese semáforo. Si no hay semáforos disponibles, el retorno de LOCKNEW es -1. Sobre los semáforos El semáforo es un mecanismo que se usa para la comunicación entre dos o mas entidades. En el chip del Propeller, un semáforo es simplemente uno de los ocho bits globales en un registro protegido dentro del Hub. El Hub mantiene un inventario de cuales son los semáforos que están en uso y sus estados actuales. Los Cogs pueden comprobar, fijar, y devolver semáforos según lo necesario durante el tiempo de ejecución para indicar si un ítem compartido, como puede ser un bloque de memoria, está disponible o no. Como los semáforos son manejados solamente por el Hub, solo puede afectarlo un Cog cada vez, siendo un mecanismo eficaz de control. En las aplicaciones donde están compartiendo la misma memoria dos o más Cogs, se puede requerir una herramienta como un semáforo para evitar que ocurran colisiones. El Hub evita que tales colisiones ocurran en datos elementales (como byte, word o long) en un momento dado, pero no puede prevenir las colisiones "lógicas" en bloques de múltiples elementos (como un bloque de bytes, words, longs o cualquier combinación de éstos).

3-41


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Los semáforos sirven como flags que notifican a cada Cog cuándo un bloque de memoria es seguro para manipular o no. Uso de LOCKNEW Un recurso definido por el usuario, mutuo-exclusivo se debe instalar inicialmente por un Cog, entonces ese mismo Cog debe comprobar un semáforo único en el que manejar ese recurso, utilizando LOCKNEW y pasar la identificación de ese semáforo a cualquier otro Cog que la requiera. Por ejemplo: VAR byte SemID PUB SetupSharedResource <código para instalar recursos definidos por el usuario, recursos compartidos> if (SemID := locknew) == -1 <error, no hay semáforos disponibles> else <comparte el valor de SemID con otros cogs> El ejemplo llama a LOCKNEW y almacena el resultado en SemID. Si ese resultado es -1, es que ha ocurrido un error. Si SemID no es -1, es que se ha chequeado un semáforo valido y ese SemID necesita ser compartido con otros Cogs junto con la dirección del recurso que SemID está utilizado. El método usado para comunicar la dirección de SemID y del recurso depende de la aplicación, pero normalmente se pasan como parámetros al método Spin que se lanza en un Cog, o como el parámetro PAR al lanzar una rutina de ensamblador en un Cog. Sugerencia de reglas para semáforos Lo siguiente son reglas sugeridas para el uso de semáforos. • Los objetos que necesitan un semáforo para manejar un recurso definido por el usuario, mutuo-exclusivo deben comprobar un semáforo usando LOCKNEW y guardar la identificación de retorno, la llamamos aquí SemID. Solamente un Cog debe comprobar este semáforo. El Cog que comprobó el semáforo debe comunicar SemID a el resto de los Cogs que utilicen el recurso. • Cualquier Cog que necesite tener acceso al recurso debe primero fijar con éxito el semáforo SemID. Se fija con éxito cuando LOCKSET(SemID) devuelve falso. Si LOCKSET devuelve verdadero, entonces otro Cog debe tener acceso al recurso; por lo que se debe esperar e intentar otra vez más adelante conseguir “fijarlo” con éxito. • El Cog que ha conseguido fijar un semáforo con éxito puede manipular el recurso como sea necesario. Cuando haya finalizado, debe despejar el semáforo con LOCKCLR(SemID) para que otro Cog pueda tener acceso al recurso. • Si un recurso ya no es necesario, o llega a ser no-exclusivo, el semáforo asociado se debe volver al pool de semáforos con LOCKRET(SemID). Normalmente esto lo el mismo Cog que comprueba originalmente el semáforo. Las aplicaciones deben ser escritas para que los semáforos no se accedan con LOCKSET o LOCKCLR a menos que sea para una comprobación. 3.3.30. LOCKRET Libera el semáforo al pool de semáforos, haciéndolo disponible otra vez para futuras peticiones LOCKNEW.

LOCKRET ( ID ) •

ID es el identificativo ID (0 – 7) del semáforo que se devuelve al pool de semáforos.

Explicación LOCKRET es uno de los cuatro comandos del semáforo (LOCKNEW, LOCKRET, LOCKSET, y LOCKCLR) usados para manejar los recursos que son definidos por el usuario y usados como mutuo-exclusivo. LOCKRET devuelve un semáforo, por su ID, de nuevo al pool de semáforos del Hub para poder reutilizarse por otros Cogs mas adelante. Por ejemplo:

3-42


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

LOCKRET(2) Este ejemplo devuelve el semáforo 2 de nuevo al Hub. Esto no previene los Cogs de acceder al semáforo 2 mas adelante, solamente permite que el Hub lo reasigne a los Cogs que llaman a LOCKNEW en el futuro. Las aplicaciones deben ser escritas para que los semáforos no se alcancen con LOCKSET o LOCKCLR a menos que sea para una comprobación. Se debe tener en cuenta que los recursos definidos por el usuario no son bloqueados por el Hub ni por el semáforo que se ha comprobado. La característica del semáforo solamente proporciona los medios para que los objetos bloqueen de forma cooperativa esos recursos. Es labor de los mismos objetos el decidir las reglas de uso del semáforo y qué recurso(s) será gobernado por ellos. Además, el Hub no asigna directamente un semáforo al Cog que llama a LOCKNEW, sino que simplemente las marca como que está siendo “comprobado” por un Cog; cualquier otro Cog puede devolver semáforos al pool de semáforos disponibles. También, cualquier Cog puede tener acceso a cualquier semáforo con los comandos de LOCKCLR y de LOCKSET incluso si esos semáforos no han sido comprobados; aunque generalmente no se recomienda debido a el estrago que puede causar con otros objetos de la aplicación. 3.3.31. LOCKSET Fija el semáforo a verdadero y recoge su estado anterior.

LOCKSET ( ID ) Devuelve: El estado previo del semáforo (Verdadero o Falso). •

ID es el ID (0 – 7) del semáforo que se quiere poner a verdadero.

Explicación LOCKSER es uno de los cuatro comandos del semáforo (LOCKNEW, LOCKRET, LOCKCLR, y LOCKCLR) usados para manejar los recursos que son definidos por el usuario y de uso mutuo-exclusivo. LOCKCLR fija a falso el semáforo de identificador ID semáforo y recupera el estado anterior de ese semáforo (verdadero o falso). Lo siguiente asume que un Cog (éste u otro) ya ha comprobado un semáforo usando LOCKNEW y ha compartido ya el ID con este Cog, que se guarda como SemID. También asume que este Cog tiene un array de longs llamado LocalData. PUB ReadResource | Idx repeat until not lockset(SemID) repeat Idx from 0 to 9 LocalData[Idx] := long[Idx] lockclr(SemID) PUB WriteResource | Idx repeat until not lockset(SemID) repeat Idx from 0 to 9 long[Idx] := LocalData[Idx] lockclr(SemID)

‘espera hasta que bloqueemos el recurso ‘leer todos los longs (10) del array ‘desbloquea el recurso

‘espera hasta que bloqueemos el recurso ‘escribe todos los longs (10) del array al ‘recurso ‘desbloquea el recurso

Ambos métodos, ReadResource y WriteResource, siguen las mismas reglas antes y después de acceder al recurso. Primero, esperan indefinidamente en el primer bucle de repetición hasta que se bloquee el recurso; es decir: se ha fijado con éxito el semáforo asociado a falso. Si LOCKSET devuelve verdadero, la condición "until not lockset..." es falso, y significa que actualmente hay otro Cog accediendo al recurso, de modo que el primer bucle se repetirá otra vez. Si LOCKSET devuelve falso, la condición " until not lockset..." es verdadero, significando se ha bloqueado el recurso. El segundo bucle de repetición de cada método, lee o escribe el recurso, a través de las declaraciones long[Idx] y LocalData[Idx]. La ultima línea de cada método, lockclr(SemID), fija el semáforo asociado del recurso a falso, lógicamente desbloqueando o liberando el recurso para otros usos.

3-43


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.32. LONG Declara símbolos de tamaño long, datos de alineación long, o n long de lectura / escritura de la memoria principal. LONG Symbol <[Count]> LONG Data LONG [BaseAddress] <[Offset]> • • • • •

Symbol es el nombre deseado para la variable. Count es una expresión opcional que indica el número de elementos de tamaño long para Symbol, dispuestos en un array del elemento 0 al elemento Count-1. Data son una expresión constante o una lista separada por comas de expresiones constantes. BaseAddress es una expresión que describe la dirección en memoria principal para leer o para escribir. Si se omite Offset, BaseAddress es la dirección real a operar. Si se especifica Offset, BaseAddress + Offset seria la dirección real. Offset una expresión opcional que indica un ajuste sobre la dirección que especifica BaseAddress.

Explicación LONG es una de las tres declaraciones de propósito múltiple (BYTE, WORD, y LONG) que declaran o operan en memoria. El LONG se puede utilizar para: 1) declarar un símbolo de tamaño long o un array de elementos de tamaño long en un bloque del VAR, o 2) declarar datos de alineación long, y de tamaño long, en un bloque de DAT, o 3) leer o escribir un long en memoria principal en una dirección base con un ajuste opcional. Declaración Variable del Long (Sintaxis 1) En bloques del VAR, la sintaxis 1 del LONG se utiliza para declarar las variables globales, simbólicas de tamaño long, o es cualquier array de longs. Por ejemplo: VAR long Temp long List[25]

'Temp es un long 'Str es un array de long

El ejemplo anterior declara dos variables, Temp y Str. Temp es simplemente una variable de tamaño long. La línea siguiente utiliza el campo de Count opcional para crear un array de 25 elementos variables llamado List. Temp y List se pueden alcanzar desde cualquier método PUB o PRI dentro del mismo objeto que este bloque del VAR. Un ejemplo: PUB SomeMethod Temp := 25_000_000 Str[0] := 500_000 Str[1] := 9_000 Str[24] := 60

‘Fija Temp a 250,000,000 ‘Fija el primer elemento a 500,000 ‘Fija el segundo elemento a 9,000 ‘Fija el ultimo elemento de List a 60

Declaración de Datos Long (Sintaxis 2) En bloques de DAT, la sintaxis 2 del LONG se utiliza para declarar datos long que se compilan como valores constantes en memoria principal. Por ejemplo: DAT MyData long 640_000, $BB50 ‘datos de tamaño y alineación long MyList byte long $FF995544, 1_000 ‘datos de tamaño long y alineación byte

El ejemplo anterior declara dos símbolos de datos, MyData y MyList. MyData señala el comienzo de datos long en memoria principal. Los valores de MyData, en memoria principal, son 640,000 y $BB50 respectivamente. MyList utiliza una sintaxis especial del bloque DAT para un LONG que crea datos de tamaño long pero de alineación Byte en memoria principal. Los valores de MyList, en memoria principal, son $ FF995544 y 1,000, respectivamente.

3-44


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Cuando se accede un byte cada vez, MyList contiene $44, $55, $99, $FF, 232 y 768, 0 y 0 puesto que los datos se almacenan en formato little-endian. Estos datos se compilan en el objeto y en la aplicación resultante como parte de la sección ejecutable de código y se pueden alcanzar usando la forma de lectura / escritura, sintaxis 3, del LONG (ver abajo). Lectura / escritura de Longs en memoria principal (Sintaxis 3) En bloques PUB y PRI, la sintaxis 3 del LONG se utiliza para leer o para escribir valores long en memoria principal. Si se asume que el objeto contiene el bloque DAT del ejemplo de arriba, se podía utilizar el siguiente ejemplo para tener acceso a esos datos. PUB GetData | Index, Temp Temp := LONG[MyData] <do something with Temp> repeat Index from 0 to 1 Temp := LONG[MyList][Index] <do something with Temp>

‘Lee el primer byte de MyData ‘a Temp 'Realiza una tarea con Temp ‘Repite dos veces ‘Lee los datos a Temp, ‘un long por vez 'Realiza una tarea con valor ‘en Temp

La primera línea del método GetData, arriba, utiliza la declaración del LONG para leer un byte de memoria principal en localización MyData y lo almacena en Temp, en este caso, el valor 640,000. A continuación en el bucle de REPEAT, la declaración del LONG lee un long de memoria principal en localización MyList + el índice Index y lo almacena en Temp. Puesto que Index se fija a 0, el primer long de MyString se lee, $FF995544. La siguiente vuelta del bucle lee el siguiente long, MyString + 1 (1,000). Usando una sintaxis similar, los longs de memoria principal se pueden escribir también, mientras sean localizaciones RAM. Por ejemplo: LONG[MyList][0] := 2_000_000_000

‘Escribe 2 mil millones al primer long de

‘MyList

Esta línea escribe el valor 2,000,000,000 al primer long de datos de MyList. 3.3.33. LONGFILL Rellena la memoria principal con un valor. LONGFILL (StartAddress, Value, Count ) • StartAddress es una expresión que indica la localización del primer long en memoria a llenar del valor Value. • Value es una expresión que indica el valor de los long con los que se quiere rellenar. • Count es una expresión que indica el número de longs a rellenar, comenzando con StartAddress. Explicación LONGFILL es uno de tres comandos (BYTEFILL, WORDFILL, y LONGFILL) usados para llenar bloques de memoria principal de un valor específico. LONGFILL rellena Count long de memoria principal con valor, comenzando en la localización StartAddress. Uso de LONGFILL LONGFILL es una gran manera de inicializar grandes bloques de la memoria. Por ejemplo: VAR long Buff[100] PUB Main longfill(@Buff, 0, 100)

Inicializar Buff a 0

3-45


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

La primera línea del método principal, arriba, fija el array entero Buff de 100-longs a ceros. LONGFILL es más rápido en esta tarea que es un bucle dedicado de la REPEAT. 3.3.34. LONGMOVE Copia longs de una región a otra en memoria principal. LONGMOVE (DestAddress, SrcAddress, Count ) • • •

DestAddress es una expresión que especifica la localización destino en memoria principal para copiar el primer long. SrcAddress es una expresión que especifica la localización en memoria principal del primer long fuente para copiar. Count es una expresión que indica el número de longs fuente para copiar al destino.

Explicación LONGMOVE es uno de tres comandos (BYTEMOVE, WORDMOVE, y LONGMOVE) usados para copiar bloques de memoria principal a partir de una área a otra. LONGMOVE copia Count longs de memoria principal que empiezan con SrcAddress a la memoria principal que comienza en DestAddress.

Uso de LONGMOVE LONGMOVE es una gran manera de copiar grandes bloques de memoria long. Por ejemplo: VAR long Buff1[100] long Buff2[100] PUB Main longmove(@Buff2, @Buff1, 100)

'Copia Buff1 a Buff2

La primera línea del método principal, arriba, copia el array entero de 100-longs Buff1 al array Buff2. LONGMOVE es más rápido en esta tarea que es un bucle dedicado de REPEAT. 3.3.35. LOOKDOWN, LOOKDOWNZ Recoge el índice de un valor en una lista. LOOKDOWN ( Value : ExpressionList ) LOOKDOWNZ ( Value : ExpressionList ) Devuelve: Posición del índice de base-uno (LOOKDOWN) o posición del índice de base-cero (LOOKDOWNZ) de un valor Value en la ExpresionList, o 0 si Value no se encontró. • •

Value es una expresión que indica el valor a buscar en ExpressionList. ExpressionList es una lista de expresiones separadas por comas. También se permiten los strings acotados de caracteres; se tratan como lista de caracteres separadas por comas.

Explicación LOOKDOWN y LOOKDOWNZ son los comandos que recuperan índices de valores de una lista de valores. LOOKDOWN vuelve la posición de índice de base-uno (1..N) del valor de ExpressionList. LOOKDOWNZ es como LOOKDOWN pero devuelve la posición de índice de base-cero (0..N-1). Para ambos comandos, si el valor no se encuentra en ExpressionList entonces se devuelve 0.

3-46


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Uso de LOOKDOWN o LOOKDOWNZ LOOKDOWN y LOOKDOWNZ son útiles para mapear un sistema de números no-contiguos (25, -103, 18, de etc.) a un sistema de números contiguos (1, 2, 3, etc. - o 0, 1, 2, etc.) . El ejemplo siguiente asume que Print es un método creado en otra parte. PUB ShowList | Index Print(GetIndex(25)) Print(GetIndex(300)) Print(GetIndex(2510)) Print(GetIndex(163)) Print(GetIndex(17)) Print(GetIndex(8000)) Print(GetIndex(3)) PUB GetIndex(Value): Index Index := lookdown(Value, 25, 300, 2_510, 163, 17, 8_000, 3) El método de GetIndex en este ejemplo utiliza LOOKDOWN para encontrar Value y devuelve el índice donde se encuentra en el ExpressionList, o 0 si no lo encuentra. El método de ShowList llama a GetIndex en varias ocasiones con diversos valores visualiza el índice resultante. Asumiendo que Print es un método que visualiza o imprime un valor, este ejemplo visualizara 1, 2, 3, 4, 5, 6 y 7. Si se utilizase LOOKDOWNZ en vez de LOOKDOWN este ejemplo mostraría 0, 1, 2, 3, 4, 5, y 6. Si el valor no se encontrase, LOOKDOWN, o LOOKDOWNZ, devolverían 0. Si se usa LOOKDOWNZ, hay que tener muy en cuenta que puede volver 0 si o el valor no fue encontrado o si el valor está en el índice 0; esto podría causar un error en el código y si fuera el caso seria as conveniente usar LOOKDOWN . 3.3.36. LOOKUP, LOOKUPZ Recoge el valor de una posición de una lista indexada. LOOKUP ( Index : ExpressionList ) LOOKUPZ ( Index : ExpressionList ) Devuelve: El valor en la posición de índice de base-uno (LOOKUP) o la posición de índice de base-cero (LOOKUPZ) de ExpressionList, o 0 si es está fuera de rango. • •

Index es una expresión que indica la posición del valor deseado en ExpressionList. Para LOOKUP, Index es de base-uno (1..N). Para LOOKUPZ, Index es de base –cero (0..N-1). ExpressionList es una lista de expresiones separada por comas. También se permiten los strings acotados de caracteres; se tratan como lista de caracteres separadas por comas.

Explicación LOOKUP y LOOKUPZ son los comandos que recuperan entradas de una lista de valores. LOOKUP devuelve el valor de ExpressionList que esté situado en la posición de base-uno (1..N) dada por Index. LOOKUPZ es como LOOKUP pero utiliza un índice de base-cero (0..N-1). Para ambos comandos, si el índice está fuera del rango entonces se devuelve 0. Uso de LOOKUP o LOOKUPZ LOOKUP y LOOKUPZ son útiles para mapear un sistema contiguo de números (1, 2, 3, etc. - o 0, 1, 2, los etc.) a un sistema de los números no-contiguos (45, -103, 18, de etc.). El ejemplo siguiente asume que Print es un método creado en otra parte. PUB ShowList | Index, Temp

3-47


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

repeat Index from 1 to 7 Temp := lookup(Index, 25, 300, 2_510, 163, 17, 8_000, 3) Print(Temp) Este ejemplo busca todos los valores en ExpressionList de LOOKUP y los muestra. El bucle de REPEAT cuenta con índice de 1 a 7. Cada iteración del bucle, LOOKUP utiliza Index para recuperar un valor de su lista. Si Index se iguala a 1, se devuelve el valor 25. Si Index se iguala a 2, se devuelve el valor 300. Asumiendo que Print es un método que muestra o visualiza el valor de Temp, este ejemplo mostrara 25, 300, 2510, 163, 17, 8000 y 3. Si se utiliza LOOKUPZ, la lista con base-cero (0..N-1) en vez de con base-uno; Index de 0 devuelve 25, Index de 1 devuelve 300, etc. Si Index está fuera de rango se devuelve 0. Lo mismo, para LOOKUP, si la declaración de REPEAT fuera de 0 a 8, en vez de 1 a 7, este ejemplo mostraría 0, 25, 300, 2510, 163, 17, 8000, 3 y 0. 3.3.37. NEXT Salta las declaraciones restantes del bucle de REPEAT y continúa con la siguiente iteración del bucle. NEXT Explicación NEXT es uno de los dos comandos (NEXT y QUIT) que afectan los bucles de REPEAT. NEXT hace que se salte cualquier declaración siguiente el bucle REPEAT y que comience la siguiente iteración del bucle. Uso de NEXT NEXT se utiliza normalmente como caso de excepción, en una declaración condicional, en los bucles de REPEAT para ir inmediatamente a la siguiente iteración del bucle. Por ejemplo, se asume que X es una variable creada anteriormente y Print() es un método creado en otra parte que muestra un valor: repeat X from 0 to 9 if X == 4 next byte[$7000][X] := 0 Print(X)

‘Repite 10 veces ‘Salta si X = 4 ‘Limpia o fija a cero las localizaciones de RAM ‘Muestra X por pantalla

El código anterior limpia iterativamene las localizaciones RAM y muestra el valor de X por pantalla, pero con una excepción. Si X es igual a 4, la declaración IF ejecuta el comando NEXT Esto tiene el efecto de limpiar (fijar a 0) las localizaciones de la RAM de $7000 a $7003 y de $7005 a $7009 y de mostrar 0, 1, 2, 3, 5, 6, 7, 8, 9 por pantalla. El comando NEXT se puede utilizar solamente dentro de un bucle REPEAT; si no, ocurriría un error. 3.3.38. OBJ Declara un Bloque Objeto. OBJ Symbol <[Count]>: “ObjectName” < Symbol <[Count]>: “ObjectName”>… • •

Symbol es el nombre deseado para el símbolo del objeto. Count es una expresión opcional, incluida entre paréntesis, que indica que éste es un array de objetos, con el número Count de elementos. Para referirse a estos elementos, comienzan con el elemento 0 y terminan con el elemento Count-1.

3-48


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN •

www.microcontroladores.com info@microcontroladores.com

ObjectName es el nombre de fichero, sin la extensión, del objeto deseado. El nombre del objeto puede contener cualquier carácter válido de fichero; los caracteres no permitidos son \, /,:, *?, ", y |.

Explicación El bloque del objeto es una sección del código fuente que declara qué objetos se utilizan y los símbolos del objeto que los representan. Ésta es un de las seis declaraciones especiales (CON, VAR, OBJ, PUB, PRI, y DAT) que proporcionan la estructura inherente al lenguaje Spin. Las declaraciones del objeto comienzan con OBJ en una línea seguida por una o más declaraciones. OBJ debe comenzar en la columna 1 (la columna extrema izquierda) de la línea en la que se encuentra y las líneas siguientes se deben tabular por lo menos un espacio. OBJ Num : “Numbers” Term : “TV_Terminal” Este ejemplo define Num como símbolo de objeto de tipo "Numbers" y Term como símbolo de objeto de tipo "TV_Terminal". Los métodos públicos y privados pueden entonces referirse a estos objetos usando los símbolos del objeto como en el ejemplo siguiente. PUB Print | S S := Num.ToStr(LongVal, Num#DEC) Term.Str(@S) Este método público, Print, llama al método de ToStr de Numbers y también al método Str de TV_Terminal. Esto se hace usando los símbolos de Num y de Term del objeto seguido por la referencia del método del Objeto (un punto ‘.') y finalmente el nombre del método a llamar. Num.ToStr, por ejemplo, llama al método público de ToStr del objeto Numbers. Term.Str llama al método público Str de TV_Terminal. En este caso el Num.ToStr tiene dos parámetros, entre paréntesis, y Term.Str tiene un parámetro. El segundo parámetro de la llamada de Num.ToStr es Num#DEC. El símbolo # es el símbolo de referencia del Objeto-Constante; da acceso a las constantes de un objeto. En este caso, Num#DEC se refiere a la constante DEC (formato decimal) en el objeto Numbers. Las instancias múltiples de un objeto se pueden declarar con el mismo símbolo de objeto usando la sintaxis del array y pueden accedidos de manera similar al del array. Por ejemplo: OBJ PWM[2] : “PWM” PUB GenPWM PWM[0].Start PWM[1].Stara Este ejemplo declara PWM como un array de dos objetos (dos casos del mismo objeto). Al mismo objeto también se le ha llamado "PWM". El método público, GenPWM, llama al método Start de cada caso usando los índices 0 y 1 con el símbolo de objeto del array, PWM. Ambas instancias del objeto PWM se compilan en la aplicación como una copia de su código de programa (PUBs, PRIs, y DATs) y dos copias de sus bloques variables (VARs). Esto es porque, para cada instancia, el código es igual pero puede variar el espacio para operar independiente de la otra.

3-49


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Alcance de símbolos de objeto Los símbolos de objeto definidos en bloques de objeto son globales al objeto en el que se definen pero no son disponibles desde el exterior de ese objeto. Esto significa que estos símbolos de objeto se pueden alcanzar directamente desde cualquier sitio dentro del objeto pero su nombre no estará en conflicto con los símbolos definidos en otros objetos padre o hijo. Operadores El chip Propeller ofrece un sistema de gran alcance de operadores matemáticos y lógicos. Un subconjunto de estos operadores es soportado por el lenguaje ensamblador del Propeller; sin embargo, como el lenguaje Spin tiene un uso para cada forma de operador apoyado por el Propeller, esta sección describe a cada operador detalladamente. Espacio de Trabajo de Expresiones El Propeller es un dispositivo de 32-bits y, a menos que se indique lo contrario, las expresiones se evalúan siempre usando un entero con signo de 32-bits. Esto incluye también resultados intermedios. Si cualquier resultado intermedio desborda por arriba o por abajo (overflow o underflow) del entero con signo de 32-bits (sobre 2.147.483.647 o debajo de -2.147.483.648), el resultado final de la expresión no será el esperado. El espacio de trabajo de 32 bits proporciona mucho espacio para resultados intermedios, aunque hay que tener presente las posibilidades de que ocurra un overflow/underflow. Atributos de los Operadores Los operadores tienen las siguientes atributos o cualidades importantes, cada una de las cuales se muestra en las dos tablas siguientes y se explican mas adelante: • • • •

Unitaio/Binario Normal/Asignado Expresión constante y/o variable Nivel de precedencia

3-50


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Unitario / Binario Cada operador es unitario o binario por naturaleza. Los operadores unitarios son los que funcionan en un único operando. Por ejemplo: !Flag

‘NOT tipo bit de Flag

3-51


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN ^^Total

www.microcontroladores.com info@microcontroladores.com

‘ raíz cuadrada de Total

Los operadores binarios son los que funcionan en dos operandos. Por ejemplo: X+Y Num << 4

‘ suma X e Y ‘desplaza Num a la derecha 4 bits

Hay que observar que el término "operador binario" significa "dos operandos," y no tiene nada que ver con los dígitos binarios. Para distinguir a los operadores cuya función se relaciona con los dígitos binarios, utilizaremos el término "bitwise" o de “tipo bit”. Normal / Asignación Los operadores normales, como Suma ` + ' y desplazamiento a la izquierda ‘<<', operan proporcionan el resultado para el uso del resto de expresiones, sin afectar al operando o operadores de asignación, sin embargo, escriben su resultado en a la variable sobre la sobre la variable a su izquierda (binaria), además de proporcionar el resultado para expresiones. A continuación se muestra un ejemplo de operadores: Count++ Data >>= 3

sobre sus operandos y operandos mismos. Los que operan (unitario), o el uso por el resto de

‘ (Unitario) evalúa Count + 1 ‘ y escribe el resultado a Count ‘ (Binario) desplaza Data 3 bits a la derecha ‘ y escribe el resultado en Data

Los operadores binarios tienen formas especiales que terminan en igual ` = ' que los hace operadores de asignación. Los operadores unitarios no tienen forma especial de asignación; algunos asignan siempre mientras que otros asignan solamente en situaciones especiales. Expresiones Constantes y/o Variables Los operadores que tienen atributos de expresiones enteras constantes pueden ser utilizados en tiempo de ejecución en expresiones variables, y en de tiempo de compilación en expresiones constantes. Los operadores que tienen atributos de expresiones de punto flotante constante pueden ser utilizados en expresiones constantes en tiempo de compilación. Los operadores sin atributos de expresiones constantes pueden ser utilizados solamente en tiempo de ejecución en expresiones variables. La mayoría de los operadores tienen una forma normal, de no asignación, que permite que se utilicen en expresiones constantes y variables. Nivel de Precedencia Cada operador tiene un nivel asignado de precedencia que se determina cuando tomará acción en relación a otros operadores dentro de la misma expresión. Por ejemplo, se sabe comúnmente que las reglas algebraicas toman la multiplicación y la división como operaciones de mayor nivel de precedencia que las operaciones de suma y resta. Además, la multiplicación y la división son conmutables; ambos están en el mismo nivel de precedencia, así que sus operaciones dan como resultado el mismo valor sin importar el orden en que se realizan. Los operadores conmutativos siempre se avalúan de izquierda a derecha a menos que haya un paréntesis que elimine esa regla. El chip del Propeller aplica las reglas de orden de operaciones igual que en álgebra. Después de estas reglas, el Propeller evaluará: X = 20 + 8 * 4 – 6 / 2 ... que dará como resultado 49; es decir, 8 * 4 = 32, 6/2 = 3, y 20 + 32 - 3 = 49. Si se quiere que la expresión se evalúe de manera diferente, basta con utilizar paréntesis para establecer un nivel superior de preferencia. Por ejemplo: X = (20 + 8) * 4 – 6 / 2 Este ejemplo, evaluará primero la expresión entre paréntesis, 20 + 8, haciendo que ahora esta expresión de cómo resultado 109, en vez de 49.

3-52


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Los operadores con una precedencia más alta se procesan antes que operadores de una precedencia más baja. La única excepción es cuando se incluyen paréntesis; que eliminan cada nivel de precedencia. Asignación Intermedia El motor de expresiones del chip Propeller permite, y procesa, operadores de asignación en etapas intermedias. Esto se llaman "asignaciones intermedias" y se pueden utilizar para realizar cálculos complejos en menos código. Por ejemplo, la ecuación siguiente depende de X, y X + 1. X := X - 3 * (X + 1) / ||(X + 1) La misma declaración se podía rescribir, aprovechándose de la característica de la asignación intermedia del operador del incremento: X := X++ - 3 * X / ||X Asumiendo que X comienza en -5, ambas declaraciones dan como resultado -2, y ambas almacenan ese valor en X cuando acaban. La segunda declaración, sin embargo, lo hace dependiendo de una asignación intermedia (la parte de X++) para simplificar el resto de la declaración. El del operador del incremento ‘++ ' se evalúa en primer lugar (precedencia más alta) y lo incrementa X de -5 a -4. Puesto que esto es un " post incremento " primero devuelve el valor original del X, -5, a la expresión y entonces escribe el nuevo valor, -4, en X. De esta forma: 5 – 3 * -4 / ||-4 . -5 – 3 * -4 / 4 . -5 – 3 * -1 . -5 – -3 = -2 De vez en cuando, el uso de asignaciones intermedias puede comprimir múltiples líneas de expresiones en una sola expresión, dando por resultado un tamaño de código levemente más pequeño y una ejecución más rápida. Asignación Constante ‘=’ El operador de asignación constante se usa dentro de bloques CON para declarar constantes en tiempo de compilación. Por ejemplo, CON _xinfreq = 4096000 WakeUp = %00110000 Este código fija el símbolo _xinfreq a 4.096.000 y el símbolo wakeUp a %00110000. Durante el resto del programa el compilador utilizará estos números en lugar de sus respectivos símbolos. Estas declaraciones son expresiones constantes, y pueden ser utilizadas por operadores normales para calcular un valor constante final en tiempo de compilación. Por ejemplo, puede estar más claro rescribir el ejemplo anterior como sigue: CON _xinfreq Reset Initialize WakeUp

= 4096000 = %00100000 = %00010000 = Reset & Initialize

Aquí, wakeUp todavía está fijado a %00110000 en tiempo de compilación, pero es obvio que el símbolo del wakeUp contiene los códigos binarios Reset y Initialize para esa aplicación particular. Los ejemplos anteriores crean constantes de entero con signo de 32-bits; aunque, también es posible crear constantes de 32-bits de punto flotante. Para ello, la expresión se debe expresar como valor de punto flotante en una de las tres maneras siguientes1) como número entero seguido por un punto y por lo menos un dígito, 2) como número entero con una E seguido por un valor del exponente, o 3) 1 y 2. Por ejemplo: CON OneHalf = 0.5 Ratio = Miles = 10e5

2.0 / 5.0

3-53


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

El código anterior crea tres constantes de punto flotante. OneHalf es igual a 0.5, el Ratio es igual a 0.4 y Miles es igual a 1.000.000. Se observa que si Ratio fuera definido como 2/5 en vez de 2.0/5.0, la expresión sería tratada como constante entera y el resultado sería una constante entera igual a 0. Para las expresiones constantes de punto flotante, cada valor dentro de la expresión debe ser un valor de punto flotante; no se pueden mezclar valores de número entero y de punto flotante como en Ratio = 2/5.0. Se puede, sin embargo, utilizar la directiva FLOAT para convertir un valor de número entero a un valor de punto flotante, como Ratio = FLOAT(2)/5.0.

El compilador del Propeller maneja constantes de punto flotante como números reales de simple precisión según lo descrito por el estándar IEEE-754. Asignación Variable‘:=’ El operador de asignación variable se usa dentro de métodos (los bloques PUB y PRI) para asignar un valor a una variable. Por ejemplo, Temp := 21 Triple := Temp * 3 En el tiempo de ejecución este código fijaría la variable de Temp igual a 21 y fijaría Triple a 21 * 3, que es 63. Como con otros operadores de asignación, el operador de asignación variable puede ser utilizado dentro de expresiones para asignar resultados intermedios, por ejemplo: Triple := 1 + (Temp := 21) * 3 Este ejemplo primero fija Temp a 21, entonces multiplica Temp por 3 y le suma 1, finalmente asignando el resultado, 64, a Triple. Suma ‘+’, ‘+=’ El operador de la Suma, suma dos valores. Puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y + 5 La Suma tiene una forma de asignación, + =, que utiliza la variable de su izquierda como el primer operando y la destino del resultado. Por ejemplo, X += 10

‘Forma abreviada de X := X + 10

Aquí, el valor de X se suma a 10 y el resultado se almacena en X. La forma de la asignación de la suma también se puede utilizar dentro de expresiones para los resultados intermedios. Positivo ‘+’ (forma untaría de la Suma) Positivo es la forma untaría de la suma y puede ser usado de manera similar a Negativo excepto que este nunca será un operador de asignación. El compilador esencialmente lo ignora, pero es práctico cuando es importante acentuar el signo de operandos. Por ejemplo: Val := +2 – A Resta ‘-’, ‘-=’ El operador Resta, resta dos valores. Puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y – 5 La Resta, tiene una forma de asignación, -=, que utiliza la variable de su izquierda como el primer operando y la destino del resultado. Por ejemplo,

3-54


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

X -= 10 ‘Forma abreviada de X := X - 10 Aquí, 10 se resta del valor de X y el resultado se almacena en X. La forma de la asignación de la resta también se puede utilizar dentro de expresiones para los resultados intermedios. Negativo ‘-’ (forma untaría de Resta) Negativo es la forma untaría de la Resta. Negativo, activa el signo del valor que se encuentra a su derecha; un valor positivo se convierte en negativo y un valor negativo en positivo. Por ejemplo: Val := -2 + A Negativo es un operador de asignación cuando es el único operador a la izquierda de una variable en una línea. Por ejemplo: -A Esto negaría el valor de A y almacenaría el resultado de nuevo en A. Decremento, pre- o post- ‘- -’ El operador Decremento es un operador especial, un operador inmediato que decrementa, en uno, una variable y asigna el nuevo valor a ésa misma variable. Puede ser utilizada solamente en expresiones variables en tiempo de ejecución. El decremento tiene dos formas, pre-decremento y post-decremento, dependiendo del lado en el que aparece variable. La forma del pre-decremento aparece a la izquierda de una variable y la forma del postdecremento aparece a la derecha de una variable. Esto es extremadamente útil en la programación puesto que hay muchas situaciones que llaman al decremento de una variable justo antes o después de el uso del valor de esa varible. Por ejemplo: Y := --X + 2 El ejemplo anterior muestra la forma de pre-decremento; significa "decrementar antes de proporcionar el valor para la operación siguiente". Decrementa el valor de X en uno, escribe que resultado en X y proporciona ese resultado al resto de la expresión. Si X comenzase con el valor 5 en este ejemplo, --X almacenaría 4 en X, entonces se evalúa la expresión, 4 + 2, finalmente escribiendo el resultado, 6, en Y. Después de esta declaración, X iguala 4 e Y es igual a 6. Y := X-- + 2 El ejemplo anterior muestra la forma de post-decremento; significa "decrementar después de proporcionar el valor para la operación siguiente". Proporciona el valor actual de X para la operación siguiente en la expresión, después decrementa el valor de X en uno y escribe ese resultado a X. Si X comenzase con 5 en este ejemplo, X-proporcionaría el valor actual para la expresión (5 + 2) y entonces almacenarían 4 en X. Se evalúa la expresión 5 + 2 y el resultado, 7, se almacena en Y. Después de esta sentencia, X es igual a 4 e Y es igual a 7. Como el decremento es siempre un operador de asignación, pueden aplicarse también las reglas de asignaciones intermedias. Asumiendo que X comienza con 5 como los ejemplos siguientes. Y := --X + X Aquí, primero X se fija a 4, entonces se evalúa 4 + 4 e Y se fija a 8. Y := X-- + X Aquí, el valor actual del x, 5, se guarda para la operación siguiente (la suma) y X se decrementa a 4, entonces se evalúa 5 + 4 e Y se fija a 9. Incremento, pre- o post- ‘+ +’ El operador Incremento es un operador especial, un operador inmediato que incrementa, en uno, una variable y asigna el nuevo valor a ésa misma variable. Puede ser utilizada solamente en expresiones variables en tiempo de

3-55


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

ejecución. El incremento tiene dos formas, pre-incremento y post-incremento, dependiendo del lado en el que aparece variable. La forma del pre-incremento aparece a la izquierda de una variable y la forma del postincremento aparece a la derecha de una variable. Esto es extremadamente útil en la programación puesto que hay muchas situaciones que llaman al incremento de una variable justo antes o después de el uso del valor de esa varible. Por ejemplo: Y := ++X – 4 El ejemplo anterior muestra la forma de pre-incremento; significa "incrementar antes de proporcionar el valor para la operación siguiente". Incrementa el valor de X en uno, escribe que resultado en X y proporciona ese resultado al resto de la expresión. Si X comenzase con el valor 5 en este ejemplo, ++X almacenaría 6 en X, entonces se evalúa la expresión, 6 - 4, finalmente escribiendo el resultado, 2, en Y. Después de esta declaración, X iguala 6 e Y es igual a 2. Y := X++ - 4 El ejemplo anterior muestra la forma de post-incremento; significa "incrementar después de proporcionar el valor para la operación siguiente". Proporciona el valor actual de X para la operación siguiente en la expresión, después incrementa el valor de X en uno y escribe ese resultado a X. Si X comenzase con 5 en este ejemplo, X++ proporcionaría el valor actual para la expresión (5 -4) y entonces almacenarían 4 en X. Se evalúa la expresión 5 4 y el resultado, 1, se almacena en Y. Después de esta sentencia, X es igual a 4 e Y es igual a 1. Como el incremento es siempre un operador de asignación, pueden aplicarse también las reglas de asignaciones intermedias. Asumiendo que X comienza con 5 como los ejemplos siguientes. Y := ++X + X Aquí, primero X se fija a 6, entonces se evalúa 6 + 6 e Y se fija a 12. Y := X-- + X Aquí, el valor actual del x, 5, se guarda para la operación siguiente (la suma) y X se incrementa a 6, entonces se evalúa 5 + 6 e Y se fija a 11. Multiplicación, devuelve bajo‘*’, ‘*=’ A este operador también se le llama Multiply-Low. Puede ser utilizado en expresiones variables y constantes. Cuando se utiliza con expresiones variables o expresiones de constante entera, este operando multiplica dos valores y devuelve los 32 bits más bajos del resultado de 64-bits. Cuando se usa con expresiones constantes de punto flotante, Multiplicación multiplica dos valores y devuelve el resultado de 32-bits de punto flotante de simple precisión. Ejemplo: X := Y * 8 La Multiplicación tiene una forma de asignación, * =, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo,

X *= 20

‘Forma abreviada de X := X * 20

Aquí, el valor de X es multiplicado por 20 y los 32 bits más bajos del resultado se almacenan en X. La forma de la asignación también se puede utilizar con las expresiones para resultados intermedios. Multiplicación, devuelve alto ‘**’, ‘**=’ A este operador también se le llama Multiply-High. Puede ser utilizado en expresiones variables y constantes. Cuando se utiliza con expresiones variables o expresiones de constante entera, este operando multiplica dos valores y devuelve los 32 bits más altos del resultado de 64-bits. Ejemplo:

3-56


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

X := Y ** 8 Si Y comenzase con el valor de 536.870.912 (229) entonces Y ** 8 es igual a 1; el valor sol los 32 bits superiores del resultado. La Multiplicación tiene una forma de asignación, * =, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo, X **= 20

‘Forma abreviada de X := X ** 20

Aquí, el valor de X es multiplicado por 20 y los 32 bits más altos del resultado se almacenan en X. La forma de la asignación también se puede utilizar con las expresiones para resultados intermedios. División ‘/’, ‘/=’ División puede ser utilizado en expresiones variables y constantes. Cuando se utiliza con expresiones variables o expresiones de constante entera, este operando divide dos valores y devuelve el resultado de los 32 bits del numero entero. Cuando se usa con expresiones constantes de punto flotante, divide dos valores y devuelve el resultado de 32-bits de punto flotante de simple precisión. Ejemplo: X := Y / 4 La división tiene una forma de asignación, /=, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo,

X /= 20

‘Forma abreviada de X := X / 20

Aquí, el valor de X es dividido por 20 y el resultado del número entero se almacena en X. La forma de la asignación de la división también se puede utilizar en las expresiones para los resultados intermedios. Resto ‘//’, ‘//=’ El Resto se puede utilizar en expresiones variables y constantes enteras, pero no en expresiones constantes de punto flotante. El resto, divide un valor por otro y devuelve el resto de 32-bits de número entero. Ejemplo: X := Y // 4 Si Y comenzase con el valor 5 entonces Y // 4 es igual a 1, significando que el resto es ¼. El Resto tiene una forma de asignación, //=, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo,

X //= 20

‘Forma abreviada de X := X // 20

Aquí, el valor de X es dividido por 20 y el resto del número entero 32-bits se almacena en X. La forma de la asignación del resto también se puede utilizar en las expresiones para los resultados intermedios. Limite Mínimo ‘#>’, ‘#>=’ El operador Limite Mínimo compara dos valores y devuelve el valor más alto. El Limite Mínimo se puede utilizar en expresiones variables y constantes. Ejemplo: X := Y - 5 #> 100

3-57


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

El ejemplo anterior resta 5 de Y y limita el resultado a un valor mínimo a 100. Si Y fuera 120 entonces 120 - 5 = 115; seria mayor que 100 así que X se fija a 115. Si Y fuera 102 entonces 102 - 5 = 97; es menos de 100 así que X se fija a 100. El Limite Mínimo tiene una forma de asignación, #>=, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo, X #>= 50

‘Forma abreviada de X := X // 20

Aquí, el valor de X se limita a un valor mínimo de 50 y el resultado se almacena en X. La forma de la asignación del resto también se puede utilizar en las expresiones para los resultados intermedios. Limite máximo ‘<#’, ‘<#=’ El operador Limite máximo compara dos valores y devuelve el valor más bajo. El Limite máximo se puede utilizar en expresiones variables y constantes. Ejemplo: X := Y + 21 <# 250 El ejemplo anterior suma 21 a Y y limita el resultado a un valor máximo a 250. Si Y fuese 200 entonces 200 + 21 = 221; es menor de 250 así que X se fijaría a 221. Si Y fuera 240 entonces 240 + 21 = 261; es mayor que 250 así que X se fijaría a 250. El Limite máximo tiene una forma de asignación, <#=, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo, X <#= 50

‘Forma abreviada de X := X <# 50

Aquí, el valor de X se limita a un valor máximo de 50 y el resultado se almacena en X. La forma de la asignación del Limite máximo se puede utilizar en las expresiones para los resultados intermedios. Raíz Cuadrada ‘^^’ El operador de la raíz cuadrada devuelve la raíz cuadrada de un valor. La raíz cuadrada se puede utilizar en expresiones variables y constantes. Cuando se utiliza con expresiones variables o expresiones de constante entera, la raíz cuadrada devuelve un resultado de 32-bits de número entero. Cuando se utiliza con expresiones constantes de punto flotante, la raíz cuadrada devuelve el resultado de 32-bits de punto flotante de simpleprecisión. Ejemplo: X := ^^Y La raíz cuadrada se convierte en un operador de asignación cuando es el único operador a la izquierda de una variable en una línea. Por ejemplo: ^^Y Esto almacenaría la raíz cuadrada del valor de Y nuevamente dentro de Y.

Valor Absoluto ‘||’ El operador del valor absoluto, también llamado Absoluto, devuelve el valor absoluto (la forma positiva) de un número. El valor absoluto se puede utilizar en expresiones variables y constantes. Cuando se utiliza con expresiones variables o expresiones de constante entera, el valor absoluto devuelve el resultado de 32-bits de número entero. Cuando se utiliza con expresiones constantes de punto flotante, el valor absoluto devuelve el resultado de 32-bits de punto flotante de simple-precisión. Ejemplo: X := ||Y

3-58


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Si Y fuera -15, el valor absoluto, 15, se almacenaría en X. El valor absoluto se convierte en un operador de asignación cuando es el único operador a la izquierda de una variable en una línea. Por ejemplo: ||Y Esto almacenaría el valor absoluto de Y nuevamente dentro de Y. Extensión del signo 7 o Post-Clear‘~’ Este operador es un operador especial, inmediato que tiene un propósito dual dependiendo del lado de la variable en el que aparezca. Puede ser utilizado solamente en expresiones variables en tiempo de ejecución. La forma del la Extensión de Signo 7 del operador aparece a la izquierda de una variable y la forma Post-Clear aparece a la derecha de una variable. Lo siguiente es un ejemplo de la forma del operador Extensión de Signo 7: Y := ~X + 25 El operador Extensión de Signo 7 en este ejemplo extiende el signo del valor, X en este caso, del bit 7 hasta el bit 31. Un entero con signo de 32-bits se almacena en forma de complemento a dos y el bit más significativo (31) indica el valor del signo (positivo o negativo). Puede haber veces donde los cálculos sobre datos simples dan lugar a valores de tamaño byte que se deben tratar como entero con signo en el rango de -128 a +127. Cuando se necesita realizar otros cálculos con esos valores de tamaño byte, se debe utilizar el operador Extensión de Signo 7 para convertir el número en forma apropiada de 32-bits de entero con signo. En el ejemplo anterior, si se asume que X representa el valor -20, que en forma de 8-bits en complemento a dos es realmente el valor 236 (%11101100). La porción de la expresión ~X extiende el signo de bit del bit 7 hasta el bit 31, convirtiendo el número a la forma 32-bits apropiada del complemento a dos de -20 (%11111111 11111111 11111111 11101100). Sumando 25 al valor de signo extendido el resultado seria 5, el resultado previsto, mientras que habría dado lugar a 261 sin la extensión de signo apropiada. Lo siguiente es un ejemplo de la forma del operador Post-Clear. Y := X~ + 2 El operador Post-Clear en este ejemplo fija la variable a 0 (todos los bits a bajo) después de proporcionar su valor actual para la operación siguiente. En este caso, si X fuera 5, el valor de la expresión seria (5 + 2) y se almacenaría 0 en X. Extensión de Signo 15 o Post-Set ‘~~’ Este operador es un operador especial, inmediato que tiene un propósito dual dependiendo en de el cual el lado de la variable él aparezca. dependiendo del lado de la variable en el que aparezca. Puede ser utilizado solamente en expresiones variables en tiempo de ejecución. La forma del la Extensión de Signo 15 del operador aparece a la izquierda de una variable y la forma Post-Set aparece a la derecha de una variable. Lo siguiente es un ejemplo de la forma del operador Extensión de Signo 15: Y := ~~X + 50

El operador Extensión de Signo 15 en este ejemplo extiende el signo del valor, X en este caso, del bit 15 hasta el bit 31. Un entero con signo de 32-bits se almacena en forma de complemento a dos y el bit más significativo (31) indica el valor del signo (positivo o negativo). Puede haber veces donde los cálculos sobre datos simples dan lugar a valores de tamaño word que se deben tratar como entero con signo en el rango de -32768 a +32767. Cuando se necesita realizar otros cálculos con esos valores de tamaño byte, se debe utilizar el operador Extensión de Signo 15 para convertir el número en forma apropiada de 32-bits de entero con signo. En el ejemplo anterior, si se asume que X representa el valor -300, que en forma de 16-bits en complemento a dos es realmente el valor 65.236 (%11111110 11010100). La porción de la expresión ~~X extiende el signo de bit del bit 15 hasta el bit 31, convirtiendo el número a la forma 32-bits apropiada del complemento a dos de -300 (%11111111 11111111 11111110 11010100). Sumando 50 al valor de signo extendido el resultado seria -250, el resultado previsto, mientras que habría dado lugar a 65.286 sin la extensión de signo apropiada. Lo siguiente es un ejemplo de la forma del operador Post-Set.

3-59


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Y := X~~ + 2 El operador Post-Set en este ejemplo fija la variable a -1(todos los bits a alto) después de proporcionar su valor actual para la operación siguiente. Desplazamiento Aritmético a la Derecha ‘~>’, ‘~>=’ El operador Desplazamiento Aritmético a la Derecha es como el operador de Desplazamiento a la derecha con la excepción de que este mantiene el signo, como una división de 2, 4, 8, el etc en un valor con signo. El Desplazamiento Aritmético a la derecha se puede utilizar en expresiones de constante entera y variables, pero no en expresiones constantes de punto flotante. Ejemplo: X := Y ~> 4 El ejemplo anterior desplaza Y la derecha por 4 bits, manteniendo el signo. Si Y fuera -3200 (%11111111 11111111 11110011 10000000) entonces el -3200 ~> 4 = -200 (%11111111 11111111 11111111 00111000). Si se hubiera hecho la misma operación con el operador de Desplazamiento a la Derecha, el resultado habría sido 268.435.256 (%00001111 11111111 11111111 00111000). El operador Desplazamiento Aritmético a la Derecha tiene una forma de asignación, el ~>=, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo, X ~>= 2

‘Forma abreviada de X := X ~> 2

Aquí, el valor de X se desplaza 2 bits a la derecha, manteniendo el signo, y el resultado se almacena en X. La forma de la asignación del Desplazamiento Aritmético a la Derecha se puede utilizar en las expresiones para los resultados intermedios. Random ‘?’ El operador Random es un operador especial, inmediato que utiliza el valor de una variable como semilla para crear un pseudo número al azar y asigna ese número a la misma variable. Puede ser utilizada solamente en expresiones variables run-time. Random tiene dos formas, hacia delante y hacia atrás, dependiendo del lado de la variable en la que aparece. La forma del Random hacia delante aparece a la izquierda de la variable y la forma reversa aparece a la derecha de la variable. Random genera los números pseudo-aleatorios de rango desde -2.147.483.648 a +2.147.483.647. Se llama "pseudo-aleatorio" porque los números aparecen de forma aleatoria, pero realmente se generan mediante una operación lógica que utiliza un valor "semilla" como base de una secuencia de 4 mil millones de números. Si se utilizase otra vez el mismo valor semilla, se generaría la misma secuencia de números. Aquí hay un ejemplo: ?X El ejemplo anterior muestra la forma de Random hacia delante; utiliza el valor actual del X para recuperar el siguiente número pseudo-aleatorio hacia delante y lo almacena en X. Si se ejecutase ?X otra vez daría como resultado otro numero diferente, almacenado nuevamente dentro de X. X? El ejemplo anterior muestra la forma de Random hacia atrás; utiliza el valor actual del X para recuperar el siguiente número pseudo-aleatorio hacia atrás y lo almacena en X. Si se ejecutase ?X otra vez daría como resultado otro numero diferente, almacenado nuevamente dentro de X. Random es siempre un operador de asignación y se puede utilizar en las expresiones para los resultados intermedios.

3-60


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Decodificar modo bit ‘|<’ El operador en modo bit de Decodificar decodifica un valor (0 - 31) en un valor long de 32-bits. Decodificar puede ser utilizado en expresiones de constante entera y en expresiones variables pero no en expresiones constantes de punto flotante. Ejemplo: P := |<PinNum El ejemplo anterior fija P igual al valor de 32-bits cuyo bit alto corresponde a la posición indicada por PinNum. Si PinNum fuese 3, P se fijaría a %00000000 00000000 00000000 00001000. Si PinNum fuese 31, se fijaría a %10000000 00000000 00000000 00000000. Hay muchos usos para Decodificar, pero uno de los mas útiles consiste en convertir un número de pin de E/S al patrón de 32-bits que describe el número de pin en relación a los registros de E/S. Decodificar por ejemplo, es muy práctico para el parámetro de la máscara de los comandos de WAITPEQ y de WAITPNE. Descifrar es un operador de asignación cuando es el único operador a la izquierda de una variable en una línea. Por ejemplo: |<PinNum Esto almacenaría el valor decodificado de PinNum nuevamente dentro de PinNum. Codificar en modo bit ‘>|’ El operador en modo bit de Codificar codifica un valor 32-bits en el valor (0 - 32) que representa el sistema más alto de bits, más 1. Codificar puede ser utilizado en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Ejemplo: PinNum := >|P El ejemplo anterior fija PinNum igual al número del bit más alto fijado en P, más 1. Si P fuera %00000000 00000000 00000000 00000000, PinNum se fijaría a 0; no se fijaría ningún bit. Si P fuese %00000000 00000000 00000000 10000000, PinNum se fijaría a 8; se fija el bit 7. Si P fuese %10000000 00000000 00000000 00000000, PinNum se fijaría a 32; se fijaría el bit 31. Desplazamiento a la Izquierda en modo bit ‘<<’, ‘<<=’ El operador Desplazamiento a la Izquierda desplaza los bits del primer operando a la izquierda por el número de los bits indicados en el segundo operando. El Desplazamiento a la Izquierda se puede utilizar en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Ejemplo: X := Y << 2 Si Y comenzase como: %10000000 01110000 11111111 00110101 ... el operador Desplazamiento a la Izquierda cambiaría de puesto ese valor a la izquierda por dos bits, fijando X a: %00000001 11000011 11111100 11010100. Puesto que la naturaleza del binario es base-2, desplazar un valor a la izquierda es como multiplicar ese valor por potencias de dos, 2b, donde b es el número de los bits cambiados de puesto. El operador Desplazamiento a la Izquierda tiene una forma de asignación, <<=, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo, X <<= 4

‘Forma abreviada de X := X << 4

3-61


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Aquí, el valor de X se desplaza cuatro bits a la izquierda y se almacena en X. La forma de asignación de Desplazamiento a la izquierda también se puede utilizar dentro de expresiones para los resultados intermedios. Desplazamiento a la derecha en modo bit ‘>>’, ‘>>=’ El operador Desplazamiento a la Derecha desplaza los bits del primer operando a la izquierda por el número de los bits indicados en el segundo operando. El Desplazamiento a la Derecha se puede utilizar en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Ejemplo: X := Y >> 3 Si Y comenzase como: %10000000 01110000 11111111 00110101 ... el operador Desplazamiento a la Derecha cambiaría de puesto ese valor a la Derecha por dos bits, fijando X a: %00010000 00001110 00011111 11100110. Puesto que la naturaleza del binario es base-2, desplazar un valor a la derecha es como dividir ese valor por potencias de dos, 2b, donde b es el número de los bits cambiados de puesto. El operador Desplazamiento a la Derecha tiene una forma de asignación, >>=, que utiliza la variable de su izquierda como el primer operando y destino del resultado. Por ejemplo, X >>= 2

‘Forma abreviada de X := X >> 2

Aquí, el valor de X se desplaza cuatro bits a la derecha y se almacena en X. La forma de asignación de Desplazamiento a la derecha también se puede utilizar dentro de expresiones para los resultados intermedios. Rotación a la Izquierda de modo bit ‘<-’, ‘<-=’ El operador de Rotación a la Izquierda en modo bit es similar al operador de Desplazamiento a la Izquierda, excepto que los MSBs (bits extremos izquierdos) se rotan con los LSBs (bits de derecha). La Rotación a la Izquierda puede ser utilizada en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Ejemplo: X := Y <- 4 Si Y comenzase como: %10000000 01110000 11111111 00110101 el operador de Rotación a la Izquierda rotaría ese valor a la izquierda por cuatro bits, moviendo los cuatro originales MSBs a los cuatro LSBs nuevos, y fijando X a: %00000111 00001111 11110011 01011000 La Rotación a la Izquierda tiene una forma de asignación,<-=, que utiliza la variable a su izquierda como primer operando y destino del resultado. Por ejemplo, X <-= 1

‘Forma abreviada de X := X <- 1

Aquí, el valor de X se rota a la izquierda un bit y se almacena en X. La forma de asignación de Rotación a la Izquierda también se puede utilizar dentro de expresiones para resultados intermedios. Rotación a la Derecha en modo bit ‘->’, ‘->=’ El operador de Rotación a la Derecha en modo bit es similar al operador de Desplazamiento a la Derecha, excepto que los LSBs (bits extremos derechos) se rotan con los MSBs (bits de la izquierda). La Rotación a la Derecha

3-62


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

puede ser utilizada en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Ejemplo: X := Y -> 5 Si Y comenzase como: %10000000 01110000 11111111 00110101 el operador de Rotación a la Izquierda rotaría ese valor a la derecha por cinco bits, moviendo los cinco originales LSBs a los cuatro MSBs nuevos, y fijando X a: %10101100 00000011 10000111 11111001. La Rotación a la Derecha tiene una forma de asignación,->=, que utiliza la variable a su izquierda como primer operando y destino del resultado. Por ejemplo, X ->= 3

‘Forma abreviada de X := X -> 3

Aquí, el valor de X se rota a la derecha tres bits y se almacena en X. La forma de asignación de Rotación a la Derecha también se puede utilizar dentro de expresiones para resultados intermedios. Reverso en modo bit ‘><’, ‘><=’ El operador Reverso devuelve los bits del primer operando en su orden reverso, el número total de bits que se indique en el segundo operando. El resto de bits a la izquierda se ponen a cero. El Reverso se puede utilizar en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Ejemplo: X := Y >< 6 Si Y comenzase como: %10000000 01110000 11111111 00110101 ... el operador Reverso devolverían los seis LSBs en orden reverso con el resto de los bits a cero, fijando X a: %00000000 00000000 00000000 00101011. Reverse tiene una forma de asignación, ><=, que utiliza la variable a su izquierda como primer operando y destino del resultado. Por ejemplo, X ><= 8

‘Forma abreviada de X := X >< 8

Aquí, los ocho LSBs del valor de X se invierten, el resto de los bits se fijan a cero y el resultado se almacena en X. La forma de asignación de Reverso también se puede utilizar dentro de expresiones para resultados intermedios. AND en modo bit ‘&’, ‘&=’ El operador AND en modo bit realiza un AND de los bits del primer operando con los bits del segundo operando. AND se puede utilizar en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Cada bit de los dos operandos sigue la siguiente lógica:

3-63


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Ejemplo: X := %00101100 & %00001111 El ejemplo anterior realiza un AND con %00101100 y %00001111 y escribe el resultado, %00001100, sobre X. AND tiene una forma de asignación, &=, que utiliza la variable a su izquierda como primer operando y destino del resultado. Por ejemplo, X &= $F

‘Forma abreviada de X := X & $F

Aquí, el valor de X realiza un AND con $F y el resultado se almacena en X. La forma de la asignación AND se puede utilizar también dentro de expresiones para resultados intermedios. Hay que tener cuidado en no confundir el AND en modo bit con el AND Boleano. AND en modo bit es para la manipulación de bits mientras que el AND boleano es para propósitos de la comparación. OR en modo bit ‘|’, ‘|=’ El operador OR en modo bit realiza un OR de los bits del primer operando con los bits del segundo operando. OR se puede utilizar en expresiones de constante entera y de variable y, pero no en expresiones constantes de punto flotante. Cada bit de los dos operandos sigue la siguiente lógica:

Ejemplo: X := %00101100 | %00001111 El ejemplo anterior realiza un OR entre %00101100 y %00001111 y escribe el resultado, %00101111, sobre X. OR tiene una forma de asignación, |=, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X |= $F

‘Forma abreviada de X := X | $F

Aquí, el valor de X realiza un OR con $F y el resultado se almacena en X. La forma de la asignación OR también se puede utilizar dentro de expresiones para resultados intermedios.

3-64


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Hay que tener cuidado en no confundir el OR en modo bit con el OR Boleano. OR en modo bit es para la manipulación de bits mientras que el OR boleano es para propósitos de la comparación.

XOR en modo bit ‘^’, ‘^=’ El operador de XOR en modo bit realiza un XOR de los bits del primer operando con los bits del segundo operando. XOR se puede utilizar en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Cada bit de los dos operandos sigue la siguiente lógica:

Ejemplo: X := %00101100 | %00001111 El ejemplo anterior hace un XOR entre %00101100 y %00001111 y escribe el resultado, %00100011, sobre X. XOR tiene una forma de asignación, ^ =, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X ^= $F

‘Forma abreviada deX := X ^ $F

Aquí, el valor de X hace un XOR con $F y el resultado se almacena en X. La forma de asignación de XOR se puede también utilizar dentro de expresiones para resultados intermedios. NOT en modo bit ‘!’ Operador NOT `!' en modo bit realiza un NOT (lo contrario, o su-complemento) de los bits del operando que lo sigue. NOT se puede utilizar en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Cada bit de los dos operandos sigue la lógica siguiente:

Ejemplo: X := !%00101100 El ejemplo anterior hace un NOT en %00101100 y escribe el resultado, %11010011, sobre X. NOT es un operador de asignación cuando es el operador único a la izquierda de una variable en una línea. Por ejemplo: ¡Flag

3-65


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Esto almacenaría el valor invertido de Flag nuevamente dentro Flag. Hay que tener cuidado en no confundir el NOT en modo bit con el NOT Boleano. NOT en modo bit es para la manipulación de bits mientras que el NOT boleano es para propósitos de la comparación. AND Booleano ‘AND’, ‘AND=’ El operador boleano AND compara dos operandos y devuelve verdadero (-1) si ambos valores son ciertos (diferente a cero), o devuelve (0) falso si uno o ambos operandos son falsos (0). AND Boleano puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y AND Z El ejemplo anterior compara el valor de Y con el valor de Z y fija X a: Verdadero (-1) si Y y Z son diferentes a cero, o (0) falso si Y o Z son cero. Esta expresión se convertiría en: "si Y es verdadero y Z es verdad.ero.." Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF (Y == 20) AND (Z == 100) Este ejemplo evalúa el resultado de Y== 20 con el de Z== 100, y si ambos son verdadero, el operador AND devuelve verdadero (-1). El AND Boleano tiene una forma de asignación, AND=, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X AND= True

‘Forma abreviada deX := X AND True

La forma de asignación de AND boleano se puede también utilizar dentro de las expresiones para resultados intermedios. Hay que tener cuidado en no confundir el AND Boleano con el AND en modo bit. AND boleano es para propósitos de comparación mientras que el AND en modo bit es para la manipulación de bits. OR Booleano ‘OR’, ‘OR=’ El operador OR boleano compara dos operandos y devuelve verdadero (-1) si cualquier valor es verdadero (diferente a cero), o devuelve (0) falso si ambos operandos son falsos (0). El OR boleano puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y OR Z El ejemplo anterior compara el valor de Y con el valor de Z y fija X a: Verdadero (-1) si Y o Z es diferente a cero, o (0) falso si Y y Z son cero. Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF (Y == 1) OR (Z > 50) Este ejemplo evalúa el resultado de Y == 1 contra el de Z>50, y si sea verdadero, el operador OR boleano devuelve verdadero (-1). El OR boleano tiene una forma de asignación, OR=, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X OR= Y

‘Forma abreviada deX := X OR Y

La forma de asignación del OR boleano se puede también utilizar dentro de expresiones para resultados intermedios.

3-66


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Hay que tener cuidado en no confundir el OR Boleano con el OR en modo bit. OR boleano es para propósitos de comparación mientras que el OR en modo bit es para la manipulación de bits. NOT Boleano ‘NOT’ Operador boleano devuelve verdadero (-1) si el operando es falso (0), o devuelve (0) falso si el operando es verdadero (diferente a cero). El NOT boleano puede ser utilizado en expresiones variables y constantes. Ejemplo: X := NOT Y El ejemplo anterior devuelve el boleano contrario de Y; Verdadero (-1) si Y es cero, o (0) falso si Y es diferente a cero. Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF NOT ( (Y > 9) AND (Y < 21) ) Este ejemplo evalúa el resultado de (Y> 9 AND Y < 21), y devuelve como resultado el valor boleano contrario; Verdadero (-1) si Y está en el rango 10 a 20, en este caso. El NOT boleano es un operador de asignación cuando es el único operador a la izquierda de una variable en una línea. Por ejemplo: NOT Flag Esto almacenaría el boleano contrario de Flag nuevamente dentro de Flag. Hay que tener cuidado en no confundir el NOT Boleano con el NOT en modo bit. NOT boleano es para propósitos de comparación mientras que el NOT en modo bit es para la manipulación de bits. Es igual a Boleano ‘==’, ‘===’ El operador boleano Es igual a compara dos operandos y devuelve verdadero (-1) si ambos valores son iguales, o devuelve falso (0), si no. Es igual a puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y == Z El ejemplo anterior compara el valor de Y con el valor de Z y fija X a: Verdadero (-1) si Y tiene el mismo valor que Z, o (0) falso si Y no tiene el mismo valor que Z. Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF (Y == 1) Aquí, el operador Es igual a devuelve Verdadero si Y es igual a 1. Es igual a tiene una forma de asignación, ===, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X === Y

‘Forma abreviada deX := X == Y

Aquí, X se compara con Y, y si son iguales, X se fija a verdadero (-1), si no X se fija a falso (0). La forma de asignación de Es igual a se puede también utilizar dentro de expresiones para resultados intermedios.

No es igual a Boleano ‘<>’, ‘<>=’

3-67


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

El operador boleano No es igual a compara dos operandos y devuelve verdadero (-1) si los valores no son iguales, o devuelve falso (0), si no. No es igual a puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y <> Z El ejemplo anterior compara el valor de Y con el valor de Z y fija X a: Verdadero (-1) si Y no tiene el mismo valor que Z, o (0) falso si Y tiene el mismo valor que Z. Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF (Y <> 25) Aquí, el operador No es igual a devuelve verdadero si Y no es 25. No es igual a tiene una forma de asignación, <>=, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X <>= Y

‘Forma abreviada de X := X <> Y

Aquí, X se compara con Y, y si no son iguales, X se fija a verdadero (-1), si no X se fija a falso (0). La forma de asignación de No es igual a se también puede utilizar dentro de expresiones para resultados intermedios.

Es Menor que Boleano ‘<’, ‘<=’ El operador boleano Es menor que compara dos operandos y devuelve verdadero (-1) si el primer valor es menor que el segundo valor, o devuelve falso (0), si no. Es menor que puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y < Z El ejemplo anterior compara el valor de Y con el valor de Z y fija X a: Verdadero (-1) si Y es menor que el valor de Z, o (0) falso si Y es igual o mayor que el valor de Z. Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF (Y < 32) Aquí, el operador Es menor que devuelve verdadero si Y es menor que 32. Es menor que una forma de la asignación,<=, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X <= Y

‘Forma abreviada deX := X < Y

Aquí, X se compara con Y, y si X es menor que Y, X se fija a verdadero (-1), si no X se fija a falso (0). La forma de asignación de Es menor que también puede ser utilizado dentro de expresiones para resultados intermedios. Es Mayor que Boleano ‘>’, ‘>=’ El operador boleano Es mayor que comparan dos operandos y devuelve verdadero (-1) si el primer valor es mayor que el segundo valor, o devuelve falso (0), si no. Es mayor que puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y > Z El ejemplo anterior compara el valor de Y con el valor de Z y fija X a: Verdadero (-1) si Y es mayor que el valor de Z, o (0) falso si Y es igual o menor que al valor de Z.

3-68


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF (Y > 50) Aquí, el operador Es mayor que devuelve verdadero si Y es mayor que 50. Es mayor que tiene una forma de asignación, >=, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X >= Y

‘Forma abreviada deX := X > Y

Aquí, X se compara con Y, y si X es mayor que Y, X se fija a verdadero (-1), si no X se fija a falso (0). La forma de la asignación de Es mayor que también puede ser utilizado dentro de expresiones para resultados intermedios. Es menor o igual Boleano ‘=<’, ‘=<=’ El operador boleano Es menor o igual compara dos operandos y devuelve verdadero (-1) si el primer valor es menor o igual que al segundo valor, o devuelve falso (0), si no. Es menor o igual puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y =< Z El ejemplo anterior compara el valor de Y con el valor de Z y fija X a: Verdadero (-1) si Y es menor o igual que el valor de Z, o (0) falso si Y es mayor que el valor de Z. Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF (Y =< 75) Aquí, el operador Es menor o igual devuelve verdadero si Y es menor o igual que 75. Es menor o igual tiene una forma de asignación, =<=, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X =<= Y

‘Forma abreviada deX := X > Y

Aquí, X se compara con Y, y si X es menor o igual que Y, X se fija a verdadero (-1), si no X se fija a falso (0). La forma de la asignación de Es menor o igual también puede ser utilizada dentro de expresiones para resultados intermedios.

Es mayor o igual Boleano ‘=>’, ‘=>=’ El operador boleano Es mayor o igual compara dos operandos y devuelve verdadero (-1) si el primer valor es mayor o igual que el segundo valor, o devuelve falso (0), si no. Es mayor o igual puede ser utilizado en expresiones variables y constantes. Ejemplo: X := Y => Z El ejemplo anterior compara el valor de Y con el valor de Z y fija X a: Verdad (-1) si Y es mayor o igual que el valor de Z, o (0) falso si Y es menor que el valor de Z. Este operador se utiliza a menudo junto con otros operadores de comparación, por ejemplo en el ejemplo siguiente. IF (Y => 100) Aquí, el operador Es mayor o igual devuelve verdadero si Y es mayor o igual que 100.

3-69


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Es mayor o igual tiene una forma de asignación, =>=, que utiliza la variable a su izquierda como el primer operando y destino del resultado. Por ejemplo, X =>= Y

‘Forma abreviada deX := X => Y

Aquí, X se compara con Y, y si X es mayor o igual que Y, X se fija a verdadero (-1), si no X se fija a falso (0). La forma de la asignación de Es mayor o igual también puede ser utilizada dentro de expresiones para resultados intermedios. Dirección de Símbolo ‘@’ El operador dirección de Símbolo devuelve la dirección del símbolo que la sigue. La dirección del símbolo se puede utilizar en expresiones de constante entera y de variable, pero no en expresiones constantes de punto flotante. Ejemplo: BYTE[@Str] := “A” En el ejemplo anterior, el operador de la dirección del símbolo devuelve la dirección del símbolo Str, que es utilizado por la referencia del array de memoria BYTE para almacenar el carácter "A" en esa dirección. La dirección de símbolo se utiliza a menudo para pasar la dirección de secuencias y de estructuras de datos, definida en un bloque de DAT, a los métodos que operan sobre ellos. Es importante observar que éste es un operador especial que se comporta de manera diferente en expresiones variables o en expresiones constantes. En tiempo de ejecución, como en el ejemplo, devuelve la dirección absoluta del símbolo que la sigue. Esta dirección en tiempo de ejecución, absoluta consiste en la dirección base del programa objeto más la dirección del símbolo. En expresiones constantes, devuelve solamente el ajuste de dirección del símbolo en el objeto. No puede devolver la dirección absoluta, eficaz en el tiempo de ejecución, porque esa dirección cambia dependiendo de la dirección real del objeto en el tiempo de ejecución.

Dirección de Objeto y Símbolo ‘@@’ El operador de Dirección de objeto más símbolo devuelve el valor del símbolo que lo sigue más la dirección base actual del programa objeto. La dirección del objeto más símbolo se puede utilizar solamente en expresiones variables. Este operador es útil para crear una tabla de las direcciones de ajuste, y en tiempo de ejecución, usar esos ajustes para referirse a direcciones absolutas que representan en tiempo de ejecución. Por ejemplo, un bloque DAT puede contener un número de strings de las que se quiere tener acceso directo e indirecto. Aquí hay un bloque DAT de ejemplo. DAT Str1 byte “Hello.”, 0 Str2 byte “This is an example”, 0 Str3 byte “of strings in a DAT block.”,0 En tiempo de ejecución podemos tener acceso a esas secuencias directamente, usando @Str1, @Str2, y @Str3, pero tener acceso indirecto es molesto porque cada secuencia es de una longitud distinta; haciéndolo difícil de utilizar. La solución podría ser simplemente hacer otra tabla de las direcciones mismas, como en: DAT StrAddr word @Str1, @Str2, @Str3

3-70


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Esto crea una tabla de words, comenzando en StrAddr, donde cada word contiene la dirección de un único string. Desafortunadamente, para las constantes en tiempo de compilación (como los de la tabla de StrAddr), la dirección devuelta por @ es solamente la dirección de ajuste en tiempo de compilación, más que la dirección absoluta en tiempo de ejecución, del símbolo. Para conseguir la dirección real, en tiempo de ejecución, necesitamos agregar la dirección base del programa objeto a la dirección de ajuste del símbolo. Eso es lo que lo hace el operador de la dirección de objeto más símbolo. Ejemplo: REPEAT Idx FROM 0 TO 2 PrintStr (@@StrAddr [Idx]) El ejemplo anterior incrementa Idx de 0 a 2. La declaración de StrAddr [Idx] recupera el ajuste del string almacenado en el elemento Idx de la tabla de StrAddr en tiempo de compilación. El operador @@ que está delante de la declaración de StrAddr [Idx] suma la dirección base del objeto al valor de ajuste que fue recuperado en tiempo de compilación, dando por resultado una dirección válida en tiempo de ejecución. El método de PrintStr, cuyo código no se muestra en este ejemplo, puede utilizar esa dirección para procesar cada carácter del string. 3.3.39. OUTA, OUTB Registros de salida de 32-bits Puerto A y B. OUTA <[Pin(s)]> OUTB <[Pin(s)]>(Reservado para uso futuro) Devuelve: Valor actual de los pins de salida de Puerto A o B. •

Pin(s) es una expresión opcional, o una expresión de rango, que especifica el pin ,o pins, de E/S para acceder al puerto A (0-31) o al puerto B (32-63). Si se da una expresión única, solamente se tendrá acceso al pin especificado. Si se da una expresión de tipo rango (dos expresiones en un formato rango; x..y) se tendrá acceso a los pins contiguos desde el comienzo de la expresión hasta el fin.

Explicación OUTA y OUTB son uno de los seis registros (DIRA, DIRB, INA, INB, OUTA y OUTB) que afectan directamente los pins de E/S. El registro OUTA contiene los estados de salida de cada uno de los 32 pins de E/S en el puerto A; los bits 0 a 31 corresponden de P0 a P31. El registro de DIRB contiene los estados de salida de cada uno de los 32 pins de E/S en el puerto B; los bits 0 a 31 corresponden de P32 a P63. NOTA: OUTB está reservado para el uso futuro; el Propeller P8X32A no incluye los pins de E/S del puerto B. OUTA se usa tanto para fijar como para recoger el estado actual de salida de uno o mas pins E/S en el Puerto A. Un bit bajo (0) indica que el pin correspondiente E/S está a tierra, y un bit alto (1) indica que el pin correspondiente de E/S está a VDD (3.3 voltios). El registro OUTA está por defecto a cero, con todos los bits a 0, hasta el arranque del cog. Cada Cog tiene acceso a todos los pins de E/S en cualquier momento. Esencialmente, todos los pins de E/S están conectados directamente con cada Cog. Esta configuración se puede describir con las siguientes reglas: A. Un pin es una entrada sólo de Cogs no activos fijados a salida. B. Un pin es una salida si cualquier Cog activo lo fija a salida.

Debido a la naturaleza "wired-OR" de los pins de E/S, no hay contención eléctrica entre los Cogs, y se puede tener acceso a los pins de E/S simultáneamente. Es función del desarrollador de la aplicación asegurarse de que ningunos de los Cogs causan contención lógica en el mismo pin de E/S durante el tiempo de ejecución. Uso de OUTA

3-71


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Fija o inicializa los bits en OUTA para afectar al estado de salida de los pins E/S deseados. Hay que asegurarse también fijar los bits correspondientes de DIRA para hacer que ese pin sea una salida. DIRA := %00000100_00110000_00000001_11110000 OUTA := %01000100_00110000_00000001_10010000 La línea de arriba de DIRA fija los pins 25, 21, 20, 8, 7, 6, 5 y 4 de E/S a salida y el resto a entradas. La línea de OUTA fija los pins 30, 25, 21, 20, 8, 7, y 4 a alto, el resto de E/S a bajo. El resultado es que los pins de E/S 25, 21, 20, 8, 7, y 4 están fijados como salida alta y los pins 6 y 5 de E/S como salida baja. El pin 30 de E/S se fija a una dirección de entrada (según DIRA) así que el estado alto en el bit 30 de OUTA se ignora y el pin se toma como entrada de acuerdo con ese Cog. Si se usa el campo opcional Pin(s), y los operadores unitarios post-clear (~) y post-set (~~), un Cog puede afectar a un pin de E/S (un bit) a la vez. El campo Pin(s) trata los registros de pins de E/S como array de 32-bits. Por ejemplo:

DIRA[10]~~ OUTA[10]~ OUTA[10]~~

‘Fija P10 a salida ‘Pone P10 a bajo ‘Pone P10 a alto

La primera línea del código fija el pin 10 de E/S a salida. La segunda línea hace un “clear” sobre el bit de salida P10, haciendo que P10 sea una salida baja (tierra). La tercera línea fija el bit de P10 , haciendo que P10 sea una salida alta (VDD). En Spin, el registro de OUTA soporta una forma especial de expresión, llamada una expresión de rango, que permite que se lean un grupo de pins de E/S inmediatamente, sin leer los que quedan fuera del rango especificado. Para leer los múltiples pins, contiguos de E/S, hay que utilizar una expresión de rango (como x..y) en el campo de Pin(s). DIRA[12..8]~~ OUTA[12..8] := %11001

‘Fija DIRA12:8 (P12-P8 a salida) ‘Fija P12:8 a 1, 1, 0, 0, y 1

La primera línea, "DIRA...," fija P12, P11, P10, P9 y P8 a la salida; el resto de los pins permanecen en su estado anterior. La segunda línea, "OUTA...," fija P12, P11, y P8 como salida alta, y P10 y P9 como salida baja. IMPORTANTE: El orden de los valores en una expresión de rango afecta a la utilización. Por ejemplo: DIRA[8..12]~~ OUTA[8..12] := %11001

‘Fija DIRA8:12 (P8-P12 a salida) ‘Fija OUTA8:12 a 1, 1, 0, 0, y 1

Aquí, los bits de 8 a 12 de DIRA se fijan a salida (como antes) pero los bits 8, 9, 10, 11 y 12 de OUTA se fijan igual a 1, 1, 0, 0, y 1, respectivamente, haciendo que P8, P9 y P12 sean salidas altas y P10 y P11 salidas bajas. Ésta es una característica de gran alcance de expresiones de rango, pero si no se tiene cuidado puede tomar resultados no esperados inintencionadamente. OUTA normalmente solo de escritura pero también puede ser leído para recuperar el estado de salida actual de pins de E/S. Esto es SOLAMENTE los estados de cierre de la salida del Cog, no necesariamente los estados reales de la salida de los pins de E/S del Propeller, pues pueden ser afectados más adelante por otros Cogs o otro hardware de E/S de este Cog (el generador video, Count A, etc.). El ejemplo siguiente asume que Temp una variable creada en otra parte: Temp := OUTA[15..13]

‘Recoge los estados de salida finales de P15 a P13

Lo anterior fija Temp. Igual a los bits 15, 14, y 13 de OUTA; es decir: los 3 bits más bajos de Temp son iguales ahora a OUTA15:13 y los otros bits de Temp se ponen a cero.

3-72


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.40. PAR Registro de Parámetros de arranque del Cog. PAR Devuelve: El valor de dirección pasado durante arranque con COGINIT o COGNEW. Explicación El registro PAR contiene el valor de dirección pasado en el campo Parameter de un comando de COGINIT o de COGNEW. El contenido del registro PAR lo utiliza el código Ensamblador Propeller para localizar y para ejecutar la memoria compartida entre el código Spin y el código ensamblador . Puesto que el registro PAR está pensado para contener una dirección de arranque del Cog, el valor almacena en él a través de COGINIT y COGNEW y se limita a 14-bits; un word de 16-bit con dos bits más bajos puestos a cero. Uso de PAR PAR es afectado por código Spin y utilizada por código ensamblador como mecanismo de indicador de memoria para apuntar a la memoria principal compartida entre los dos. El comando de COGINIT o COGNEW, al lanzar el ensamblador Propeller sobre un Cog, afecta el registro PAR. Por ejemplo: VAR long Shared

‘Variable Shared (Spin & Ens)

PUB Main | Temp cognew(@Process, @Shared) repeat <hacer algo con Shared vars> DAT Process :loop

Mem res 1 ValReg

org 0 mov Mem, PAR <hacer algo> wrlong ValReg, Mem jmp :loop jmp :loop

‘Mueve el valor ValReg a Shared

res 1

En el ejemplo de arriba, el método principal lanza la rutina en ensamblador Process en un Cog nuevo con COGNEW. El segundo parámetro de COGNEW es utilizado por Main para pasar la dirección de una variable, Shared. La rutina de ensamblador, Process, recupera que valor de dirección de su registro PAR y lo almacena localmente en Mem. Entonces realiza alguna tarea, actualizando su registro local ValReg (creado en el final del bloque de DAT) y finalmente actualiza la variable Shared a través de wrlong ValReg, Mem. 3.3.41. PHSA, PHSB Contador A y Contador B de los Registros Phase Lock Loop (PLL). PHSA PHSB Devuelve: Valor actual del Contador A o Contador B del registro PLL, si está utilizado como variable fuente. Explicación

3-73


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

PHSA y PHSB son dos de los seis registros (CTRA, CTRB, FRQA, FRQB, PHSA, y PHSB) que afectan el comportamiento de los módulos Contador de un Cog. Cada Cog tiene dos módulos Contador idénticos (A y B) que pueden realizar muchas tareas repetitivas. Los registros de PHSA y de PHSB contienen los valores que se pueden leer o escribir directamente por el Cog, pero pueden también ser acumulados con el valor de FRQA y de FRQB, respectivamente, en cada ciclo potencial de reloj del sistema. Uso de PHSA and PHSB PHSA y PHSB pueden ser leidos/escritos como otros registros o variables predefinidas. Por ejemplo: PHSA := $1FFFFFFF El código anterior fija PHSA a $1FFFFFFF. Dependiendo del campo de CTRMODE del registro de CTRA, este valor puede seguir siendo el mismo, o se puede incrementar automáticamente por el valor en FRQA en una frecuencia determinada por el reloj del sistema y los pins primarios y/o secundarios de E/S. Hay que tener presente que la escritura a PHSA o a PHSB elimina directamente el valor actual acumulado y cualquier acumulación programada para el mismo momento que se realiza la escritura. 3.3.42. PRI Declara un Bloque de método Privado. PRI Name <(Param<,Param>…)> <:Rvalue> <|LocalVar<[Count]>> <,LocalVar <[Count]>>… SourceCodeStatements • •

• •

Name es el nombre deseado para el método privado. Param es un nombre del parámetro (opcional). Los métodos pueden contener cero o más parámetros delimitados con comas, incluidos entre paréntesis. Param debe ser globalmente único, pero otros métodos pueden también utilizar el mismo nombre de símbolo. Cada parámetro es esencialmente una variable long y se puede tratar como tal. RValue es un nombre para el valor de retorno del método (opcional). Esto se convierte en un alias a la variable incorporada RESULT del método. RValue debe ser globalmente único, pero otros métodos pueden también utilizar el mismo nombre de símbolo. El RValue (y/o la variable RESULT) se inicializa a cero (0) en cada llamada al método. LocalVar es un nombre para una variable local (opcional). LocalVar debe ser globalmente único, pero otros métodos pueden también utilizar el mismo nombre de símbolo. Todas las variables locales son de tamaño long (cuatro bytes) y no se inicializan en cada llamada al método. Los métodos pueden contener cero o más variables locales delimitadas por comas. Count es una expresión opcional, incluida entre corchetes, que indica que es una variable local de array, con el número de Count elementos; cada uno es de tamaño long. Al referirse a estos elementos, comienzan con el elemento 0 y terminan con el elemento Count-1. SourceCodeStatements es una o más líneas del código fuente ejecutable, tabuladas por lo menos un espacio, que realizan la función del método.

Explicación PRI es el declaración de un bloque de método privado. Un método privado es una sección del código fuente que realiza una función específica y devuelve un valor de resultado. Ésta es una de las seis declaraciones especiales (CON, VAR, OBJ, PUB, PRI, y DAT) que proporcionan la estructura inherente a la lengua Spin. Cada objeto puede contener un número de métodos privados (PRI) y públicos (PUB). Los métodos privados se pueden alcanzar o llamar solamente desde adentro del objeto y sirven para realizar funciones vitales, protegidas, para el objeto. Los métodos privados son como métodos públicos, excepto que están declarados con PRI, en vez de PUB, y no son accesibles desde fuera del objeto.

3-74


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.43. PUB Declara un Bloque de método Publico. PUB Name <(Param <,Param>…)> <:Rvalue> <|LocalVar<[Count]>> <,LocalVar <[Count]>>… SourceCodeStatements • •

• •

Name es el nombre deseado para el método publico. Param es un nombre del parámetro (opcional). Los métodos pueden contener cero o más parámetros delimitados con comas, incluidos entre paréntesis. Param debe ser globalmente único, pero otros métodos pueden también utilizar el mismo nombre de símbolo. Cada parámetro es esencialmente una variable long y se puede tratar como tal. RValue es un nombre para el valor de retorno del método (opcional). Esto se convierte en un alias a la variable incorporada RESULT del método. RValue debe ser globalmente único, pero otros métodos pueden también utilizar el mismo nombre de símbolo. El RValue (y/o la variable RESULT) se inicializa a cero (0) en cada llamada al método. LocalVar es un nombre para una variable local (opcional). LocalVar debe ser globalmente único, pero otros métodos pueden también utilizar el mismo nombre de símbolo. Todas las variables locales son de tamaño long (cuatro bytes) y no se inicializan en cada llamada al método. Los métodos pueden contener cero o más variables locales delimitadas por comas. Count es una expresión opcional, incluida entre corchetes, que indica que es una variable local de array, con el número de Count elementos; cada uno es de tamaño long. Al referirse a estos elementos, comienzan con el elemento 0 y terminan con el elemento Count-1. SourceCodeStatements es una o más líneas del código fuente ejecutable, tabuladas por lo menos un espacio, que realizan la función del método.

Explicación PUB es el declaración de un bloque de método privado. Un método publico es una sección del código fuente que realiza una función específica y devuelve un valor de resultado. Ésta es una de las seis declaraciones especiales (CON, VAR, OBJ, PUB, PRI, y DAT) que proporcionan la estructura inherente a la lengua Spin. Cada objeto puede contener un número de métodos privados (PRI) y públicos (PUB). Los métodos privados se pueden alcanzar o llamar solamente desde adentro del objeto y sirven para realizar funciones vitales, protegidas, para el objeto. Los métodos públicos se pueden alcanzar fuera del objeto y sirven para crear el interfaz a un objeto.

Declaración de métodos Públicos Las declaraciones de métodos públicos comienzan con PUB, en la columna 1 de una línea, seguidas por un nombre único y opcionalmente de un sistema de parámetros, de una variable del resultado, y de variables locales. Ejemplo: PUB Init <initialization code> PUB MotorPos : Position Position := <code to retrieve motor position> PUB MoveMotor(Position, Speed) : Success | PosIndex <code that moves motor to Position at Speed and returns True/False> Este ejemplo contiene tres métodos públicos, Init, MotorPos y MoveMotor. El método de Init no tiene ningún parámetro y no declara ningún valor de retorno o variable local. El método MotorPos no tiene ningún parámetro pero declara un valor de retorno llamado Position. El método MoveMotor tiene dos parámetros, Position y Speed, un valor de retorno, Success, y una variable local, PosIndex.

3-75


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Todas las declaraciones ejecutables que pertenecen a un método de PUB aparecen debajo de su declaración, tabulado por lo menos un espacio. El valor de Retorno Una declaración de PUB especifique o no un RValue, hay siempre un valor de retorno implícito, que es cero (0) por defecto. Hay un nombre predefinido para este valor de retorno dentro de cada método de PUB, llamado RESULT. En cualquier momento dentro de un método, RESULT puede ser actualizado como cualquier otra variable y, mientras exista el método, el valor actual del RESULT se pasará de nuevo al llamador. Además, si se declara un RESULT para el método, ese nombre se puede utilizar alternativamente con variable, incorporada por defecto, RESULT. Parameters and Local Variables Los parámetros y las variables locales son todas long (cuatro bytes). De hecho, los parámetros son variables que se inicializan a los valores correspondientes especificados por el llamador del método. Las variables locales, sin embargo, no se inicializan; contienen datos al azar cuando se llama el método. Todos los parámetros se pasan al método por valor, no por referencia, así que los cambios de parámetros no se reflejan fuera del método. Por ejemplo, si llamamos a MoveMotor usando una variable llamadora Pos para el primer parámetro, puede ser algo como esto: Pos := 250 MoveMotor(Pos, 100) Cuando se ejecuta el método MoveMotor, recibe el valor de Pos en su parámetro Position, y el valor 100 en su parámetro Speed. Dentro del método MoveMotor, puede cambiar Position y Speed en cualquier momento, pero sigue teniendo el valor de Pos (la variable del llamador) a 250. Si una variable tiene que ser alterada por una rutina, el llamador debe pasar la variable por referencia; es decir, que debe pasar la dirección de la variable en vez del valor de la variable, y la rutina debe tratar ese parámetro como la dirección de una posición de memoria en la cual operar. La dirección de una variable, u otro símbolo basado en los registros, puede ser recuperada usando al operador de Dirección de símbolo, ` @ '. por ejemplo, Pos := 250 MoveMotor(@Pos, 100) El llamador pasa la dirección de Pos para el primer parámetro de MoveMotor. Lo que recibe MoveMotor en su parámetro Position es la dirección de la variable llamadora Pos. La dirección es un número, como cualquier otro, y el método de MoveMotor tiene que estar diseñado para que lo trate como dirección, el lugar de un valor. El método MoveMotor debería utilizar algo como: PosIndex := LONG[Position] ... para recuperar el valor de la variable llamadora Pos, y será algo como: LONG[Position] := <some expression> ... para modificar la variable llamadora Pos, en caso de necesidad. Salida de un método Se sale de un método, tanto si ha llegado a la ultima sentencia del método o cuando alcanza un comando de RETURN o ABORT. Un método puede tener solamente un punto de la salida (la ultima sentencia ejecutable), o puede tener muchos puntos de la salida (cualquier comando RETURN o ABORT además de la ultima sentencia ejecutable). Los comandos RETURN y ABORT se pueden utilizar también para fijar el RESULT variable en la salida.

3-76


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.43B. QUIT Salida de un bucle REPEAT inmediatamente. QUIT

Explicación QUIT es uno de los dos comandos (NEXT y QUIT) que afectan a los bucles de REPEAT. QUIT hace que un bucle de REPEAT termine inmediatamente. Uso de QUIT QUIT se utiliza como un caso de excepción, en una declaración condicional, en los bucles REPEAT para terminar el bucle prematuramente. Por ejemplo, se asume que DoMore y SystemOkay son métodos creados en otra parte y que cada uno devuelve valores boleanos: repeat while DoMore !outa[0] <do something> if !SystemOkay quit <more code here>

‘Repetir mientras haya DoMore ‘Activa el Pin 0 ‘Realiza alguna tarea ‘Si hay fallo en System, salir ‘Realiza otras tareas

El código anterior activa P0 y realiza otras tareas mientras que el método de DoMore devuelva verdadero. Sin embargo, si el método de SystemOkay devuelve falso, la declaración de IF ejecuta el comando de QUIT que hace que el bucle termine inmediatamente. El comando de QUIT se puede utilizar solamente dentro de un bucle de REPEAT; de otra manera, daría lugar a error. 3.3.44. REBOOT Resetea el chip Propeller. REBOOT

Explicación Esto es un reset controlado por software, pero actúa como un reset hardware vía el pin de RESn. REBOOT sed utiliza si se quiere resetear el chip Propeller a su estado inicial. Como todo lo basado en hardware, el encendido/reset crea un retraso, igual que el proceso de arranque, se utiliza como si el Propeller hubiera sido reseteado vía el pin de RESn o un ciclo de power. 3.3.45. REPEAT Ejecuta un bloque de código repetitivamente. REPEAT <Count> Statement(s) REPEAT Variable FROM Start TO Finish <STEP Delta> Statement(s) REPEAT (( UNTIL. WHILE )) Condition(s) Statement(s) REPEAT Statement(s) ((UNTIL. WHILE )) Condition(s)

3-77


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN • • • • • • •

www.microcontroladores.com info@microcontroladores.com

Count es una expresión opcional que indica el número finito de veces a ejecutar Statement(s). Si se omite Count, la sintaxis 1 crea un bucle infinito compuesto de Statement(s). Statement(s) es un bloque opcional de una o más líneas del código a ejecutarse repetidamente. Omitir Statement(s) es raro, pero puede ser útil en la sintaxis 3 y 4 si Condition(s) alcanza los efectos necesarios. Variable es una variable, generalmente definida por el usuario, que será iterada de comienzo al final, opcionalmente en unidades de Delta por iteración. Variable se puede utilizar en Statement(s) para determinar o para utilizar la cuenta de la iteración. Start es una expresión que determina el valor de inicio de Variable en la sintaxis 2. Si Start es menor Finish, la variable será incrementada cada iteración; y decrementada de la otra manera. Finish es una expresión que determina el valor final de Variable en la sintaxis 2. Si Finish es mayor que Start, la variable será incrementada cada iteración; y decrementada de la otra manera. Delta es una expresión opcional que determina las unidades en las cuales se quiere incrementar/decrementar la Variable en cada iteración (sintaxis 2). Si está omitida, la variable se incrementara/decrementara en 1 cada iteración. Condition(s) es un o más expresiones boleanas usadas por la sintaxis 3 y 4 para continuar o para terminar el bucle. Cuando está precedido de UNTIL, Condition(s) termina el bucle cuando es verdadero. Cuando está precedido de WHILE, Conditions(s) termina el bucle cuando es falso.

Explicación REPEAT es una estructura repetitiva muy flexible para el código Spin. Puede ser utilizada para crear cualquier tipo de bucle, incluyendo: infinito, finito, con o sin contador de bucle, y el de cero a N o de N a cero. La Sangría es critica IMPORTANTE: La sangría es crítica. El lenguaje Spin confía en la sangría (de un espacio o más) en líneas que siguen comandos condicionales para determinar si pertenecen a ese comando o no. Para que la herramienta Propeller indique éstos bloques de código agrupados lógicamente en pantalla, se puede presionar Ctrl + I y encender los indicadores de grupo . Presionando Ctrl + I otra vez esa característica se desactivara. Bucles Infinitos (Sintaxis 1) Realmente, cualquiera de las cuatro formas de REPEAT se pueden hacer en bucles infinitos, pero la forma usada para este propósito es la sintaxis 1 sin el campo Count. Por ejemplo: repeat !outa[25] waitcnt(2_000 + cnt)

‘Repite sin fin ‘Activa P25 ‘Pausa en 2,000 ciclos

Este código repite !outa[25 ] y waitcnt(2_000 + cnt) sin fin. Ambas líneas están tabuladas de REPEAT así que pertenecen al bucle REPEAT. Puesto que Statement(s) es realmente una parte opcional de REPEAT, el comando de la REPEAT por sí mismo se puede utilizar como bucle sin fin que no haga nada pero mantiene el Cog activo. Esto puede ser intencional, pero es a veces inintencional debido a una sangría incorrecta. Por ejemplo: repeat !outa[25]

‘Repite sin fin ‘Activa P25 <-- Esto no se ejecutara

El ejemplo anterior es erróneo; la línea anterior nunca se ejecuta porque el REPEAT que hay sobre ella es un bucle sin fin que no tiene ningún Statement(s); no hay nada tabulado inmediatamente debajo de él, así que el Cog se queda simplemente en un lazo sin fin en la línea REPEAT que no hace nada pero mantiene el Cog activo y consumiendo energía. Bucles finitos Simples (Sintaxis 1) La mayoría de los bucles son finitos por naturaleza; ejecutan solamente un número limitado de iteraciones. La forma más simple es la sintaxis 1 con el campo de Countt incluido. Por ejemplo:

3-78


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN repeat 10 !outa[25] byte[$7000]++

www.microcontroladores.com info@microcontroladores.com

‘Repite 10 veces ‘Activa P25 ‘Incrementa localización RAM $7000

El código anterior activa P25 diez veces, y entonces incrementa el valor de la localización RAM $7000. Bucles Finitos Contados (Sintaxis 2) A menudo es absolutamente necesario contar las iteraciones del bucle para que el código del bucle pueda realizarse basado en esa cuenta. El comando REPEAT hace que esto sea fácil de hacer con la sintaxis 2. El siguiente ejemplo asume que la variable Index fue creada previamente. repeat Index from 0 to 9 byte[$7000][Index]++

‘Repite 10 veces ‘Incrementa localización RAM de ‘ $7000 a $7009

Como el ejemplo anterior, el código repite el bucle 10 veces, pero cada vez ajusta la variable Index. La primera vez a que se ejecute el bucle, el índice será 0 (según lo indicado por " from 0") y cada iteración siguiente será 1 más que el anterior (según lo indicado por "to 9"): ..1. 2, 3... 9. Después de la décima iteración, el índice será incrementado a 10 y el bucle terminará, haciendo que se ejecuten las siguientes sentencias al bucle REPEAT, si es que existen. El código en el bucle utiliza Index como ajuste para afectar la memoria, byte[$7000][Index]++; en este caso está incrementando cada uno de los valores de tamaño byte en las localizaciones $7000 a $7009 del RAM en 1, cada vez. El comando REPEAT determina automáticamente si el rango sugerido por Start y Finish es ascendente o descendente. Como el ejemplo anterior utilizó 0 a 9, el rango es un Rango ascendente; ajustando Index en +1 cada vez. Para conseguir que la cuenta vaya al revés, simplemente habría que invertir los valores del Start y Finish, como en: repeat Index from 9 to 0 byte[$7000][Index]++

‘Repite 10 veces ‘Incrementa localización RAM $7000

de ‘$7009 hacia

Este ejemplo también repite el bucle 10 veces, pero cuenta con Index de 9 a 0; ajustando Index en -1 cada vez. Como los campos de Start y Finish pueden ser expresiones, pueden contener variables. El ejemplo siguiente asume que S y F son variables creadas previamente. S := 0 F := 9 repeat 2 repeat Index from S to F byte[$7000][Index]++ S := 9 F := 0

‘Repite 2 veces ‘Repite 10 veces ‘Incrementa localización RAM de 7000..$7009

El ejemplo anterior utiliza un bucle anidado. El bucle externo (primero) repite 2 veces. El bucle interno repite con Index desde S a F, estas variables han sido fijadas previamente de 0 a 9, respectivamente. El bucle interno incrementa el valor de las localizaciones $7000 a $7009 de la RAM, en ese orden, porque el bucle interno está contando iteraciones a partir de la 0 a 9. Entonces, este bucle termina (con Index fijado a 10) y las ultimas dos líneas ponen S a 9 y F a 0, intercambiando los valores de Start y Finish. Puesto que esto todavía está dentro del lazo externo, el lazo externo entonces ejecuta su contenido (para la segunda vez) que hace otra vez que el bucle interno repita con Index desde 9 a 0 (en sentido contrario al bucle anterior). Los bucles REPEAT no tienen por que ser limitados a incrementar o a decrementar en 1. Si el comando REPEAT utiliza el sintaxis opcional Delta, incrementará o decrementara la variable en la cantidad que indique Delta. El ejemplo siguiente incluye el valor opcional Delta, llamado Step, para incrementar por 2. repeat Index from 0 to 8 step 2 byte[$7000][Index]++

‘Repite 5 veces ‘Incrementa la RAM $7000 a ‘$7008

3-79


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Aquí, REPEAT realiza el bucle cinco veces, con Index fijado a 0, 2, 4, 6, y 8, respectivamente. Este código incrementa las localizaciones RAM (las localizaciones numeradas) a partir de $7000 a $7008 y terminan con Index igual a 10.

El campo Delta puede ser positivo o negativo, sin importar el rango natural de los valores Start y Finish, y se puede incluso ajustar dentro del bucle para alcanzar efectos interesantes. Por ejemplo, asumiendo que Index y D son variables definidas previamente, el código siguiente fija Index a la siguiente secuencia: 5. 6, 6, 5, 3. D := 2 repeat Index from 5 to 10 step D --D Este bucle comienza con Index a 5 y Delta (D) de +2. Pero cada iteración decrementa D por uno, así que en el final de la primera iteración, Index = 5 y D = +1. la iteración 2 tiene Index = 6 y D = 0. La iteración 3 tiene Index = 6 y D = -1. la iteración 4 tiene Index = 5 y D = -2. la iteración 5 tiene Index = 3 y D = -3. El bucle termina entonces porque Index más Delta (3 + - 3) está fuera de el rango de Start y Finish (5 a 10). Bucles Condicionales (Sintaxis 3 and 4) Las formas finales de REPEAT, sintaxis 3 y 4, son bucles finitos con salidas condicionales. Estas dos formas de REPEAT se refieren generalmente como "repeat while" o "repeat until". La forma REPEAT de la sintaxis 3, consiste en el comando REPEAT seguido por WHILE o UNTIL entonces Condition(s) y finalmente, en las líneas de abajo, Statement(s) opcionales. Por ejemplo, se asume que es X una variable creada anteriormente: X := 0 repeat while X < 10 byte[$7000][X] := 0 X++

‘Repite mientras X es menor que 10 ‘Incrementa el valor de RAM ‘Incrementa X

Este ejemplo, primero fija X a 0 y repite el bucle mientras que X sea menor que 10. El código del bucle inicializa a 0 las localizaciones RAM basadas en X (que comienza en la localización $7000) e incrementa X. Después de la décima iteración del bucle, X se iguala a 10, haciendo la condición mientras que X < 10 sea falso y el bucle termina. Este bucle se dice que utiliza la lógica "positiva" porque continúa "WHILE" o mientras que una condición sea verdad. Podía también escribirse con lógica "negativa" usando UNTIL, en su lugar. Por ejemplo: X := 0 repeat until X > 9 byte[$7000][X] := 0 X++

‘Repite hasta que X sea mayor que 9 ‘Incrementa el valor de RAM ‘Incrementa X

Este ejemplo realiza la misma manera que el alo mismo que el anterior, pero utilizando lógica negativa porque continúa "UNTIL" o hasta que una condición sea verdad; es decir: continúa mientras que una condición es falsa. En cualquiera de los dos ejemplos, si X fuera igual a 10 o superior antes de que la primera iteración del bucle REPEAT, la condición nunca llegaría a ejecutarse. La forma de la REPEAT descrita por el sintaxis 4 es muy similar al sintaxis 3, pero la condición se prueba en el final de cada iteración, haciendo un bucle de uno a N. Por ejemplo:

3-80


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN X := 0 repeat byte[$7000][X] := 0 X++ while X < 10

www.microcontroladores.com info@microcontroladores.com

‘Incrementa el valor de RAM ‘Incrementa X ‘Repite mientras X sea menor que 10

Esto también funciona igual que los ejemplos anteriores, ejecutando el bucle 10 veces, aunque la condición no se prueba hasta el final de cada iteración. Otras opciones REPEAT Hay otros dos comandos que afectan al comportamiento o a los bucles REPEAT: NEXT y QUIT. 3.3.46. RESULT Es el valor variable de retorno de métodos. RESULT Explicación La variable de RESULT es una variable local predefinida para cada método de PUB y PRI. El RESULT contiene el valor de retorno del método; este valor se pasa al llamador del método, cuando termina el método. Cuando se llama un método público o privado, su variable RESULT se inicializa a cero (0). Si ese método no altera RESULT, ni llama RETURN o ABORT con un valor especifico, entonces el valor de retorno de la terminación de ese método será cero. Uso de RESULT En el ejemplo de abajo, el método de DoSomething pone RESULT igual a 100 en su final. El método principal llama DoSomething y fija su variable local, Temp, igual al resultado; de modo que cuando DoSomething sale, Temp se fija a 100. PUB Main | Temp • Temp := DoSomething PUB DoSomething <do something here> result := 100

‘Llama a DoSomething, fija Temp con el valor de ‘retorno

‘Fija result a 100

también se puede proporcionar un nombre alias a la variable RESULT de un método para hacerla más clara. Por ejemplo: PUB GetChar : Char <do something> Char := < carácter recuperado>

‘Fija Char (result) al carácter

El método anterior, GetChar, declara Char como alias para su variable incorporada de RESULT. El método de GetChar realiza unas tareas para recoger un carácter y entonces fija Char con el carácter recuperado. también podría haber utilizado "result: = ... " para fijar el valor de retorno si la declaración afecta el valor de retorno del método. Tanto la variable del RESULT, como el alias proporcionado para ello, se pueden modificar múltiples veces dentro del método antes de la salida del método pero solo se devolverá el ultimo valor de RESULT.

3-81


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.47. RETURN Sale de un método PUB/PRI con un valor de retorno opcional. RETURN <Value> Devuelve: El valor del RESULTADO actual o un valor (Value) si se provee. • Value es una expresión opcional que valor debe ser devuelto del método PUB o PRI.

Explicación RETURN es uno de dos comandos (ABORT y RETURN) que terminan la ejecución de un método PUB o PRI. RETURN causa un retorno de un método PUB o PRI con estado normal; esto significa que realiza un solo pop de la pila de llamadas y retorna al llamador de este método, entregando un valor en el proceso. Cada método PUB o PRI tiene un RETURN implícito en su final, pero RETURN se puede también escribir manualmente en uno o más lugares dentro del método para crear múltiples puntos de salida. Cuando RETURN aparece sin valor opcional, devuelve el valor actual de la variable incorporada en el RESULT de PUB/PRI. Si el campo valor fue incorporado, el PUB o el PRI devuelve ese valor. Sobre la pila de llamadas (Call Stack) Cuando los métodos son llamados simplemente invocándoles de otros métodos, debe haber un cierto mecanismo para almacenar donde debe retornar una vez que se termine el método llamado. Este mecanismo es el llamado "stack" (pila) pero utilizaremos el término "call stack" aquí. Este mecanismo es simplemente memoria RAM, usada para almacenar las direcciones y los valores de retorno, los parámetros y los resultados intermedios. La pila de llamadas va aumentando a medida que se van haciendo llamadas a métodos y disminuye cuando los métodos terminan, ya sea vía Return o alcanzando el final del método. La pila aumenta y disminuye de tamaño con estas dos acciones: 1)"push" que introduce valores sobre la pila y 2) "pop" que saca los valores contenidos en la pila El comando RETURN hace un pop de los datos más recientes de la pila de llamadas devolviendo el dato al llamador inmediato; quién llamó directamente al método que acaba de volver. Uso de RETURN El siguiente ejemplo muestra dos aplicaciones de RETURN. Se asume que DisplayDivByZeroError es un método definido en otra parte. PUB Add(Num1, Num2) Result := Num1 + Num2 return PUB Divide(Dividend, Divisor) if Divisor == 0 DisplayDivByZeroError return 0 return Dividend / Divisor

‘Suma Num1 + Num2

‘Mira si Divisor = 0 ‘Si es así, muestra error ‘y retorna con 0 ‘sino, devuelve el resultado

El método de la suma (Add) asigna su variable RESULT igual a Num1 más Num2, entonces ejecuta RETURN. Las causas de RETURN agregan para volver el valor de RESULT al llamador. El método Divide comprueba el valor Divisor. Si Divisor se iguala a cero, llama al método de DisplayDivByZeroError y después ejecuta el return 0, que hace inmediatamente que el método retorne con el valor

3-82


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

0. Si, sin embargo, Divisor no es igual a cero, ejecuta Dividend / Divisor y hace que el método retorne con el resultado de la división. 3.3.48. ROUND Redondea una constante de coma flotante en el entero mas cercano. ROUND ( FloatConstant ) Devuelve: El entero mas cercano al valor original de la constante de punto flotante. •

FloatConstant es la expresión constante de punto flotante que se redondeará al número entero más cercano.

Explicación ROUND es una de tres directivas (FLOAT, ROUND y TRUNC) usadas para las expresiones constantes de punto flotante. ROUND devuelve una constante entera con el valor más cercano del número entero a la expresión dada en FloatConstant. Los valores fraccionarios de ½ (.5) o superiores se redondean al siguiente número entero más cercano mientras que fracciones más bajas se redondearan hacia abajo. Uso de ROUND ROUND se puede utilizar para redondear constantes de punto flotante hacia arriba o abajo al valor más cercano del número entero. Hay que tener en cuenta que esto es solo para expresiones constantes en tiempo de compilación, no para expresiones variables en tiempo de ejecución. Por ejemplo:

CON OneHalf Smaller Rnd1 Rnd2 Rnd3

= 0.5 = 0.4999 = round(OneHalf) = round(Smaller) = round(Smaller * 10.0) + 4

El código anterior crea dos constantes, OneHalf y Smaller de punto flotante, igual a 0.5 y a 0.4999, respectivamente. Las tres constantes siguientes, Rnd1, Rnd2 y Rnd3, son las constantes enteras que se basan en OneHalf y Smaller usando la directiva ROUND. Rnd1 = 1, Rnd2 = 0, y Rnd3 = 9.

Sobre el punto flotante El compilador del Propeller maneja constantes con punto flotante como números reales de simple-precisión según lo descrito por el estándar IEEE-754. los números reales de simple -precisión se almacenan en 32-bits, con una muestra de 1-bit, un exponente de 8-bit, y una mantisa de 23-bit (la parte fraccionaria). Esto da lugar a aproximadamente 7.2 dígitos decimales significativos. Las expresiones de punto flotante se pueden definir y utilizar para muchos propósitos en tiempo de compilación, pero para operaciones en tiempo de ejecución de punto flotante, los objetos de FloatMath y de FloatString proveen de las funciones de la matemáticas compatibles números de simple-precisión.

3-83


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.49. SPR Registro Array de propósito especial; proporciona acceso indirecto a los registros especiales del Cog. SPR [Index] Devuelve: El valor del registro de propósito especial de ese índice (Index). •

Index (índice) es una expresión que especifica el índice (0-15) del registro de propósito especial a acceder (desde PAR a VSCL).

Explicación SPR es un array de los 16 registros de propósito especial en el Cog. El elemento 0 es el registro PAR y el elemento 15 es el registro de VSCL. Ver la tabla 4-12 abajo. SPR proporciona un método indirecto para tener acceso a los registros de propósito especial del Cog.

Nota 1: Reservado para uso futuro.

Uso de SPR SPR se puede utilizar como cualquier otro array de longs. Lo siguiente asume que Temp es una variable definida en otra parte. spr[4] := %11001010 Temp := spr[2]

‘Fijar el registro de salida ‘Recoger el valor de entrada

Este ejemplo fija el registro de OUTA (índice 4 de SPR) a %11001010 y después fija Temp igual al registro de INA (índice 2 de SPR).

3-84


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.50. _STACK Una constante predefinida, ajustable una sola vez para especificar el espacio libre de pila de la aplicación. CON _STACK = Expression • Expression es una expresión de número entero que indica que el número de longs a reservar para el espacio de pila. Explicación _ STACK es Una constante predefinida, ajustable una sola vez para especificar el espacio libre de pila de la aplicación. Este valor se añade a _FREE si está especificado, para determinar la cantidad total de memoria stack/free a reservar para una aplicación Propeller. Se debe usar _ STACK si una aplicación requiere una cantidad mínima de espacio de pila para ejecutarse correctamente. Si la aplicación compilada resultante es demasiado grande para permitir el espacio especificado de pila, se exhibirá un mensaje de error. Por ejemplo: CON _STACK = 3000 La declaración de _STACK en el bloque anterior de CON indica que la aplicación necesita tener por lo menos 3.000 longs de espacio de pila después de la compilación en el caso de que eso no se cumpla, se mostrara un mensaje de error, indicando cuanto se ha excedido. Esta es una buena manera de prevenir que compilaciones satisfactorias fallen en tiempo de ejecución por falta de memoria. 3.3.51. STRCOMP Compara la igualdad de dos strings. STRCOMP (StringAddress1, StringAddress2 ) Devuelve: Verdadero si los dos strings son iguales y falso en caso contrario. • StringAddress1 es una expresión que especifica la dirección de comienzo del primer string para comparar. • StringAddress2 es una expresión que especifica la dirección de comienzo del segundo string para comparar. Explicación STRCOMP es uno de dos comandos (STRCOMP y STRSIZE) que recuperan la información sobre un string. STRCOMP compara el contenido del string en StringAddress1 al contenido del string en StringAddress2, y devuelve verdadero si ambas secuencias son equivalentes, falso en caso contrario. Esta comparación es sensible a mayúsculas y minúsculas.

Uso de STRCOMP El siguiente ejemplo asume que PrintStr es un método creado a parte. PUB Main if strcomp(@Str1, @Str2) PrintStr(string(“Str1 y Str2 son iguales”)) else PrintStr(string(“Str1 y Str2 son diferentes”)) DAT Str1 byte “Hello World”, 0 Str2 byte “Testing.”, 0

3-85


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

El ejemplo anterior tiene dos strings en el bloque DAT, el Str1 y el Str2. El método principal llama a STRCOMP para comparar el contenido de cada string. 3.3.52. STRING Declara constantes de tipo cadena (string) y recoge su dirección. STRING (StringExpression ) Devuelve: La dirección de la constante string. •

StringExpression es la expresión string que se utilizará temporalmente.

Explicación El bloque DAT se utiliza a menudo para crear strings o string buffers que son reutilizables para varios propósitos, pero hay ocasiones cuando un string se necesita para propósitos temporales como eliminar errores o aplicaciones de un solo uso de objeto. La directiva de STRING se utiliza para esas aplicaciones de una sola vez; compila un string en línea en memoria y devuelve la dirección de ese string. Uso de STRING STRING es muy bueno para crear strings de un solo uso y pasar la dirección de ese string a otros métodos. Por ejemplo: PrintStr(string("Esto es un string de prueba.")) El ejemplo anterior utiliza el directorio de STRING para compilar el string, "Esto es un string de prueba", en memoria y devuelve la dirección de ese string como el parámetro para el método ficticio de PrintStr. Si un string necesita ser utilizado en más de un lugar en código, es mejor definirlo en el bloque DAT y así la dirección se puede utilizar múltiples veces. 3.3.53. STRSIZE Recoge el tamaño de un string. STRSIZE ( StringAddress ) Devuelve: El tamaño (en bytes) de strings. •

StringAddress es una expresión que especifica la dirección de comienzo del string a medir.

Explicación STRSIZE es uno de dos comandos (STRCOMP y STRSIZE) que recuperan la información sobre un string. STRSIZE mide la longitud de un string en StringAddress, en bytes, hasta un byte de terminación cero. Uso de STRSIZE El ejemplo siguiente asume que Print es un método creado a parte. PUB Main Print (strsize(@Str1)) Print (strsize(@Str2)) DAT Str1 byte “Hello World”, 0 Str2 byte “Testing.”, 0

3-86


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

El ejemplo anterior tiene dos strings terminados en cero, en el bloque de DAT, el Str1 y el Str2. El método principal llama a STRSIZE para conseguir la longitud de cada secuencia. Print es un método que muestra un valor, en este ejemplo imprime 11 y 8 en la pantalla. Símbolos Los símbolos en la tabla 4-13 responden a uno o más propósitos especiales en código Spin.

Tabla 4-13: símbolos Símbolo propósito 1) referencia Objeto-Constante: usado para referirse a las constantes de un secundario-objeto. # 2) Enumeración: utilizado en un bloque CON para fijar el comienzo de un sistema enumerado de símbolos. 3) Literal del Ensamblador : usado para indicar una expresión o un símbolo es un valor literal más que una dirección de registro. 1) referencia al método de un Objeto: se refiere a los métodos de un objeto . secundario. 2) punto decimal: usado en expresiones constantes con punto flotante. .. Indicador de rango: indica un rango a partir de una expresión a otra para las declaraciones de CASE o de índice de registro de E/S. 1) separador de retorno del valor: aparece inmediatamente antes del retorno de un valor simbólico en una declaración PUB o PRI. 2) asignación del objeto: aparece en una declaración de un objeto en un bloque de : OBJ. 3) separador de la instrucción CASE: aparece inmediatamente después de las expresiones en una estructura CASE. 1) separador variable local: aparece inmediatamente antes de una lista de variables | locales en una declaración PUB o PRI. 2) Modo bit OR: utilizado en expresiones. \ Abort Trap (interrupción): aparece inmediatamente antes de una llamada a un método que potencialmente podría abortar. , Delimitador de la lista: separaban artículos en listas. () Designadores de lista de parámetros: rodean parámetros del método. [] Designadores de índice de Array: usado para rodear índices en arraysde variables o referencias a memoria principal. Signo del comentario de código: para incorporar los comentarios de código de línea ‘ (texto no-compilado) para los propósitos de visión del código. Signo del comentario de documento: para incorporar comentarios de documento de “ línea (texto no-compilado) para propósitos de visión de la documentación. Signo del comentario de código multi-línea: para incorporar comentarios multilínea de {} código (texto no-compilado) para propósitos de visión del código. Signo del comentario de documento multi-línea: para incorporar comentarios {{ }} multilínea del documento (texto no-compilado) para propósitos de visión de la documentación. 3.3.54. TRUNC Quita o Trunca la porción fraccional de una constante de punto flotante. TRUNC ( FloatConstant ) Devuelve: El número entero que es el valor constante dado en punto flotante truncado a decimal. •

FloatConstant es la expresión constante con punto flotante que se truncará a un número entero.

3-87


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Explicación TRUNC es una de las tres directivas (FLOAT, ROUND y TRUNC) usadas para las expresiones constantes de punto flotante. TRUNC devuelve una constante entera que es la expresión constante dada en punto flotante sin la porción fraccionaria. Uso de TRUNC TRUNC se puede utilizar para recuperar la porción del número entero de una constante en punto flotante. Por ejemplo: CON OneHalf = Bigger = Int1 = Int2 = Int3 =

0.5 1.4999 trunc(OneHalf) trunc(Bigger) trunc(Bigger * 10.0) + 4

El código anterior crea dos constantes con punto flotante, OneHalf y Bigger, igual a 0.5 y a 1.4999, respectivamente. Las tres constantes siguientes, Int1, Int2 e Int3, son las constantes enteras que se basan en OneHalf y Bigger con la directiva TRUNC. Int1 = 0, Int2 = 1, e Int3 = 18.

Sobre el punto flotante El compilador del Propeller maneja constantes con punto flotante como números reales de simple-precisión según lo descrito por el estándar IEEE-754. los números reales de simple -precisión se almacenan en 32-bits, con una muestra de 1-bit, un exponente de 8-bit, y una mantisa de 23-bit (la parte fraccionaria). Esto da lugar a aproximadamente 7.2 dígitos decimales significativos. Las expresiones de punto flotante se pueden definir y utilizar para muchos propósitos en tiempo de compilación, pero para operaciones en tiempo de ejecución de punto flotante, los objetos de FloatMath y de FloatString proveen de las funciones de la matemáticas compatibles números de simple-precisión. 3.3.55. VAR Declara un bloque de variables. VAR Size Symbol <[Count ]> < Size Symbol <[Count ]>>... Size Symbol <[Count ]> <Symbol <[Count ]>>... • • •

Size es el tamaño deseado de la variable, del BYTE, del WORD o LONG. Symbol es el nombre deseado para la variable. Count es una expresión opcional, incluida entre corchetes, que indica que esto es una variable de array, con el número Count de elementos; siendo cada uno del tamaño byte, word o long. Estos elementos, comienzan con el elemento 0 y terminan con el elemento Count-1.

Explicación VAR es el declaración de un bloque variable. El bloque variable es una sección de código de fuente que declara variables globales. Ésta es una de las seis declaraciones especiales (CON, VAR, OBJ, PUB, PRI, y DAT) que proporcionan la estructura inherente a la lengua Spin. Declaración de Variables (Sintaxis 1) La forma más común de declaración de variables comienza con una línea VAR seguido por una o más declaraciones. VAR debe comenzar en la columna 1 (la columna extrema izquierda) de la línea en la que se encuentra y las líneas siguientes tienen que ser tabuladas por lo menos un espacio.

3-88


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN VAR byte word long

www.microcontroladores.com info@microcontroladores.com

Str[10] Code LargeNumber

Este ejemplo define Str como un array de bytes de 10 elementos, Code como word (dos bytes) y LargeNumber como long (cuatro bytes). Los métodos públicos y privados se pueden referir a estas variables de las maneras similares a la siguiente: PUB SomeMethod Code := 60000 LargeNumber := Code * 250 GetString(@Str) if Str[0] == “A” <more code here>

Hay que fijarse que Code y LargeNumber son utilizados directamente por expresiones. La referencia Str en la lista de parámetros del método de GetString parece diferente; tiene @, el operador del símbolo de dirección, precediéndolo. Esto es porque el método ficticio de GetString necesita escribir de nuevo en la variable Str. Si hubiera sido GetString(Str), entonces el primer byte de Str, el elemento 0, habría sido pasado a GetString. Usando al operador del símbolo de dirección, @, se hace que la dirección del Str pase a GetString y así, se puede usar esa dirección para escribir a elementos del Str. Por ultimo, se utiliza Str[0 ] en la condición del IF para ver si el primer byte es igual al carácter "A". Hay que recordar que, el primer elemento de un array es siempre cero (0). Declaraciones de Variables (Sintaxis 2) Una variación en el sintaxis 1 permite variables delimitadas con comas del mismo tamaño. A continuación se muestra un ejemplo, similar al ejemplo anterior, pero se declaran dos words, Code e Index. VAR byte Str[10] word Code, Index long LargeNumber

Alcance de Variables Las variables definidas en bloques variables, son globales al objeto en el cual se definen pero no fuera de ese objeto. Esto significa que estas variables se pueden acceder directamente en cualquier sitio dentro del . Los métodos públicos y privados tienen la capacidad de declarar sus propias variables locales. Las variables globales no son accesibles desde el exterior de un objeto a menos que la dirección de esa variable se pase a otro objeto con una llamada de un método. 3.3.56. VCFG Registro de Configuración de Video. VCFG Devuelve: El valor actual del registro de configuración de video del Cog, si está utilizado como variable fuente.

Explicación VCFG es uno de dos registros (VCFG y VSCL) que afectan al comportamiento del generador video de un Cog. Cada Cog tiene un módulo generador de video que facilita la transmisión de datos de la imagen video en un ratio

3-89


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

constante. El registro de VCFG contiene los ajustes de la configuración del generador de video, según lo mostrado en la tabla 4-14.

VMode El campo de 2-bit VMode (modo video) selecciona el tipo y la orientación de la salida de video, si la hay, según la tabla 4-15.

En ensamblador del Propeller, el campo de VMode se puede escribir convenientemente usando la instrucción de MOVI a través de los campos de ASubCar. CMode El campo de CMode (modo de color) selecciona modo de dos o cuatro colores. 0 = modo dos colores y 1 = modo de cuatro colores. En ensamblador del Propeller, el campo de VMode se puede escribir convenientemente usando la instrucción de MOVI a través de los campos de ASubCar. BroadCma El campo BroadCma (broadcast chroma) habilita o inhabilita el chroma (color) en la señal broadcast. 0 = inhabilitado, 1 = habilitado. BaseCma El campo BaseCma (baseband chroma) habilita o inhabilita el chroma (color) en la señal de baseband. 0 = inhabilitado, 1 = habilitado. En ensamblador Propeller, el campo de Vmode se puede escribir convenientemente usando la instrucción de MOVI a través de los campos de ASubCar. ASubCar El campo ASubCar (aural sub-carrier) selecciona la frecuencia del sub-carrier de la fuente FM (audio) de para modularla. La fuente es el PLLA de uno de los Cogs, identificado por el valor de ASubCar.

3-90


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

En ensamblador Propeller, el campo de VMode se puede escribir convenientemente usando la instrucción de MOVI a través de los campos de ASubCar. VGroup El campo de VGroup (video output pin group) selecciona el grupo de 8 pins de E/S para fijar el vídeo de salida.

En ensamblador Propeller, el campo de VGroup se puede escribir convenientemente usando la instrucción de MOVD. VPins El campo de VPins (video output pins) es una máscara aplicada a los pins de VGroup que indica qué pins son la salida de las señales de video.

Uso de VCFG VCFG puede ser leido/escrito como otros registros o variables predefinidas. Por ejemplo: VCFG: = %0_10_1_0_1_000_00000000000_001_0_00001111 Esto fija la configuración del registro de video para habilitar el modo compuesto de 1 con 4 colores, el chroma de baseband (color), en el grupo 1 de pins que son los 4 pins más bajos (los pins P11:8).

3-91


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.57. VSCL Registro de la escala de Video VSCL Devuelve: El valor actual del Registro de escala de Video del Cog , si se usa como variable fuente.

Explicación VSCL es uno de dos registros (VCFG y VSCL) que afectan al comportamiento del generador de video de un Cog. Cada Cog tiene un módulo de generador de video que facilita la transmisión de datos de la imagen video en un ratio constante. El registro de VSCL fija el ratio en la cual se generan los datos de video.

PixelRate El campo 8-bit de PixelRate (tarifa del píxel) indica el número de relojes por el pixel; el número de los relojes que deben transcurrir antes de que cada pixel sea cambiado de puesto hacia fuera por el módulo video del generador. Estos relojes son los relojes de PLLA, no el reloj del sistema. FrameRate El campo de 12-bit FrameRate (tarifa del marco) indica el número de relojes por marco; el número de los relojes que deben transcurrir antes de que cada marco sea cambiado de puesto hacia fuera por el módulo video del generador. Estos relojes son los relojes de PLLA, no el reloj del sistema. Un marco es uno de largo de datos del pixel (entregados vía el comando de WAITVID). Puesto que los datos del pixel son 16-bits por 2-bits, o 32- bits por 1-bit (píxeles del significado 16 de par en par con 4 colores, o 32 píxeles de par en par con 2 colores, respectivamente), el FrameRate es típicamente 16 o 32 veces que del PixelRate valoran. Uso de VSCL VSCL puede ser leido/escrito como otros registros o variables predefinidas. Por ejemplo: VSCL: = %000000000000_10100000_101000000000 Esto fija el registro video de la escala para 160 un reloj PixelRate y 2.560 un reloj FrameRate (para un 16-pixel por el marco del color 2-bit). Por supuesto, la tarifa real en que los píxeles registra hacia fuera depende de la frecuencia de PLLA conjuntamente con este factor de posicionamiento. 3.3.58. WAITCNT Detiene la ejecución de un Cog temporalmente. WAITCNT ( Value ) • Value es el valor de 32-bits que se desea que el contador del sistema espere. Explicación WAITCNT, “Wait for System Counter,”es uno de cuatro comandos de espera (WAITCNT, WAITPEQ, WAITPNE, y WAITVID) usados para detener la ejecución de un Cog hasta que se resuelve una condición. WAITCNT detiene el Cog hasta que el contador global del sistema iguala Value. Cuando está ejecutado, WAITCNT activa el hardware especial de "espera" en el Cog que evita que el reloj del sistema cause la ejecución adicional del código dentro del Cog hasta el momento que los valores del contador del

3-92


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

sistema Value se igualan. El hardware de wait checkea el contador del sistema en cada ciclo del reloj y el consumo de energía del Cog se reduce aproximadamente 7/8s durante este tiempo. En aplicaciones normales, WAITCNT se puede utilizar estratégicamente para reducir el consumo de energía en cualquier sitio del programa donde se pierda el tiempo esperando a eventos de banda estrecha. Hay dos tipos de retrasos WAITCNT se puede utilizar para: retrasos fijos y retrasos sincronizados. Ambos se explican abajo. Retrasos Fijos Los retrasos fijos son los que no tienen relación con un punto específico en tiempo y responden al propósito de detener la ejecución por una cantidad de tiempo fija. Un retraso fijo, por ejemplo, puede ser utilizado para esperar 10 milisegundos después de que ocurra un acontecimiento, antes de proceder con otra acción. Por ejemplo: CON _clkfreq = xtal1 _xinfreq = 5_000_000 repeat !outa[0] waitcnt(50_000 + cnt)

‘Fija a cristal lento ‘Usa cristal 5 MHz

‘Activa el pin 0 ‘Espera 10 ms

Este código activa el estado del pin P0 de E/S y espera 50.000 ciclos de reloj del sistema antes del loop de repetición. IMPORTANTE: Desde que WAITCNT detiene el Cog hasta que el contador del sistema lo empareja al valor dado, hay que tener cuidado para asegurarse que el valor dado no haya sobrepasado ya el contador del sistema

Retrasos Sincronizados Los retrasos sincronizados son los que están relacionados directamente con un punto específico en el tiempo, un tiempo “base”, y sirven a para alinear en el tiempo acontecimientos futuros, en relación con ese punto. Los retrasos sincronizados, por ejemplo, pueden utilizarse para hacer salir o entrar una señal en un intervalo específico. Para entender la diferencia con el retraso fijo, miremos el diagrama que mide el tiempo de ese ejemplo.

La figura anterior muestra la salida del ejemplo anterior de retraso fijo. Se puede ver como el pin P0 se activa cada 10 milisegundos, aunque no es exacto. De hecho, hay un error acumulativo que hace que el retraso sea cada vez mayor. Se puede usar WAITCNT de una manera levemente diferente, porque el retraso sincronizado, eliminará este error de sincronización. El ejemplo siguiente asume que estamos utilizando un cristal externo de 5 Mhz. CON _clkfreq = xtal1 _xinfreq = 5_000_000 PUB Activa | Time Time := cnt repeat waitcnt(Time += 50_000)

‘Se fija un cristal lento ‘Usa 5 MHz cristal

‘Recoge el valor actual del contador de Sis ‘Espera 10 ms

3-93


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN !outa[0]

www.microcontroladores.com info@microcontroladores.com

‘Activa pin 0

Este código, primero recupera el valor del contador del sistema, entonces comienza el bucle Repeat donde espera el contador de sistema alcance Time + 50.000, se activa del estado del pin P0 de E/S y repite bucle otra vez. La declaración Time + = 50_000 es realmente una declaración de asignación; que suma al valor Time 50.000, almacena el resultado nuevamente dentro de Time y después ejecuta el comando de WAITCNT usando ese resultado. Cada iteración sucesiva, espera a que el contador del sistema sea a igual otro múltiplo de 50.000 a partir del tiempo base. Este método compensa automáticamente el tiempo consumido arriba por las declaraciones del bucle: repeat,!outa[0 ] y waitcnt. La salida que resulta parece la siguiente figura.

3.3.59. WAITPEQ Detiene la ejecución de un Cog hasta que los pins de E/S coincida con los estados designados. WAITPEQ (State, Mask, Port ) • •

State es el estado lógico para comparar los pins. Es un valor 32-bits que indica los estados altos o bajos de hasta 32 pins de E/S. Solamente el estado de los bits que corresponden a los bits altos (1) de la Mask (máscara) se utilizan para la comparación. Mask (máscara) es el/los pin(s) que se quieren supervisar. Mask es un valor 32-bits que contiene los bits altos (1) para cada pin de E/S que deban ser supervisados; los bits bajos (0) indican los pins que deben ser ignorados. Los pins supervisados se comparan con los bits correspondientes de State hasta que la condición se cumpla. Port (puerto) es un valor de 1-bit que indica el puerto de E/S al monitor; 0 = Puerto A, 1 = Puerto B. Solo existe el Puerto A en el chip Propeller actual (P8X32A).

Explicación WAITPEQ, " Wait for Pin(s) to Equal, " es uno de cuatro comandos de espera (WAITCNT, WAITPEQ, WAITPNE, y WAITVID) usados para detener ejecución de un Cog hasta que se resuelve una condición. WAITPEQ detiene el Cog hasta que por lo menos uno de los pins de E/S del puerto, indicado por alto (1) en la máscara, no coincide con los bits correspondientes del estado. Cuando está ejecutado, WAITPEQ activa el hardware especial "wait" en el Cog, que evita que el reloj del sistema cause una ejecución adicional de código dentro del Cog, hasta el momento que el pin señalado, o el grupo de pins, no coincida con los del estado. El hardware de wait chequea los pins de E/S en cada ciclo del reloj del Sistema y el consumo de energía del Cog se reduce aproximadamente 7/8s durante este tiempo. Uso de WAITPEQ WAITPEQ es una gran manera de sincronizar código a los acontecimientos externos. Por ejemplo: waitpeq(%0100, %1100, 0) outa[0] := 1

‘Espera a que P3 & P2 sean bajo & alto ‘Fija P0 a alto

El código detiene el Cog hasta que el pin 3 de E/S sea bajo y el pin 2 de E/S sea alto, después fija el pin 0 de E/S como alto. Uso de Números Variables de Pin Para los objetos Propeller, es necesario que supervisen a menudo un solo pin cuyo número se especifique fuera del mismo objeto. Una manera fácil de traducir ese número de pin al valor apropiado de 32-bits de la máscara es

3-94


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

usando el operador Decodificar en modo bit "|<". Por ejemplo, si el número de pin fue especificado por la variable Pin, y se necesita esperar hasta que ese pin sea alto, se podría utilizar el siguiente código: waitpeq(-1, |< Pin, 0)

‘Espera a que los pins sean alto

Esperar a la Transición Si necesitamos esperar a una transición de un estado a otro (alto-a-bajo, por ejemplo) podríamos utilizar el código siguiente: waitpeq(1, 5, 0) waitpeq(0, 5, 0)

‘Espera al Pin 5 que sea alto ‘Entonces espera a que el Pin 5 sea bajo

Este primer ejemplo espera a P5 para pasar a ALTO, entonces lo espera para pasar a BAJO; una transición altoa-baja. Si se hubiera utilizado la segunda línea del código, el Cog no se habría detenido si P5 hubiese sido bajo en el comienzo. 3.3.60. WAITPNE Detiene la ejecución de un Cog hasta que los pins de E/S no sean igual a los estados designados. WAITPNE (State, Mask, Port ) • •

State es el estado lógico para comparar los pins. Es un valor 32-bits que indica los estados altos o bajos de hasta 32 pins de E/S. Solamente el estado de los bits que corresponden a los bits altos (1) de la Mask (máscara) se utilizan para la comparación. Mask (máscara) es el/los pin(s) que se quieren supervisar. Mask es un valor 32-bits que contiene los bits altos (1) para cada pin de E/S que deban ser supervisados; los bits bajos (0) indican los pins que deben serignorados. Los pins supervisados se comparan con los bits correspondientes de State hasta que la condición no se cumpla. Port (puerto) es un valor de 1-bit que indica el puerto de E/S al monitor; 0 = Puerto A, 1 = Puerto B. Solo existe el Puerto A en el chip Propeller actual (P8X32A).

Explicación WAITPNE, " Wait for Pin(s) to Not Equal, " es uno de cuatro comandos de espera (WAITCNT, WAITPEQ, WAITPNE, y WAITVID) usados para detener ejecución de un Cog hasta que se resuelve una condición. WAITPNE es la forma complementaria de WAITPEQ; detiene el Cog hasta que por lo menos uno de los pins de E/S del puerto, indicado por alto (1) en la máscara, no coincide con los bits correspondientes del estado. Cuando está ejecutado, WAITPNE activa el hardware especial "wait" en el Cog, que evita que el reloj del sistema cause una ejecución adicional de código dentro del Cog, hasta el momento que el pin señalado, o el grupo de pins, no coincida con los del estado. El hardware de wait chequea los pins de E/S en cada ciclo del reloj del Sistema y el consumo de energía del Cog se reduce aproximadamente 7/8s durante este tiempo.

Uso de WAITPNE WAITPNE es una gran manera de sincronizar código a los acontecimientos externos. Por ejemplo: waitpeq(%0100, %1100, 0) waitpne(%0100, %1100, 0) outa[0] := 1

‘Espera a que P3 & P2 sean & y alto ‘Espera a que P3 & P2 no coincida con el estado prev ‘Fija P0 a alto

El código anterior detiene el Cog hasta que P3 sea bajo y P2 sea alto, después detiene el Cog otra vez hasta que uno o ambos pins cambien los estados, entonces se fija P0 alto.

3-95


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

3.3.61. WAITVID Detiene la ejecución de un cog hasta que su Generador de Video esté disponible para recoger los datos píxel. WAITVID (Colors, Pixels ) • •

Colors (colores) es un Long conteniendo cuatro valores del color de tamaño Byte, cada uno describe los cuatro colores posibles de los patrones del pixel en Pixels . Pixels (pixeles) son los siguientes 16-pixel entre 2 bit (o 32-pixel entre 1 bit )al lado por 1-bit) patrón del pixel a mostrar.

Explicación WAITVID, " Wait for Video Generador,” es uno de cuatro comandos de espera (WAITCNT, WAITPEQ, WAITPNE, y WAITVID) usados para detener la ejecución de un Cog hasta que se resuelve una condición. WAITVID detiene el Cog hasta que su hardware del Generador de Video este listo para los siguientes datos del pixel, después el Generador de Video acepta los datos y el Cog continúa la ejecución con la siguiente línea de código. Cuando está ejecutado, WAITVID activa el hardware especial "wait" en el Cog, que evita que el reloj del sistema cause una ejecución adicional de código dentro del Cog, hasta el momento que el generador de video este listo. El hardware de wait chequea el estado del Generador de Video en cada ciclo del reloj del Sistema y el consumo de energía del Cog se reduce perceptiblemente durante este tiempo. Uso de WAITVID WAITVID es simplemente un mecanismo de entrega de datos al hardware del Generador de video del Cog. Puesto que el funcionamiento del Generador de Video es independientemente del Cog en sí mismo, los dos se deben sincronizar cada vez que los datos son necesarios para el mecanismo de exhibición de datos. La frecuencia en la cual esto ocurre depende del mecanismo de exhibición y de los ajustes correspondientes para el Generador de Video, pero en cada caso, el Cog debe tener nuevos datos disponibles el momento que el Generador de Video este listo para él. El Cog utiliza el comando de WAITVID para esperar el tiempo adecuado y entonces “hacer entrega” de estos datos al Generador de Video. El parámetro de Color es un valor 32-bits que contiene cuatro valores de color de 8-bit. Los 6 bits superiores del valor del color son 2-bit el rojo, 2-bit el verde, y 2-bit el azul que describen el color deseado. Los últimos dos bits no se utilizan. Cada uno de los valores de color corresponde a uno de los cuatro colores posibles por el patrón 16x2 o 32x1. Los pixeles describen el patrón del pixel a exhibir, 16 pixeles o 32 pixeles dependiendo de la configuración de la profundidad de color del Generador de Video. 3.3.62. WORD Declara símbolos o datos tamaño-word, o lectura / escritura de words en memoria principal. WORD Symbol <[Count]> WORD Data WORD [BaseAddress] <[Offset]> • • • • •

Symbol (símbolo) es el nombre que se le quiere poner a la variable. Count (contador) es una expresión opcional que indica el número de elementos tamaño-word para Symbol, dispuestos en un array del elemento 0 al elemento Count-1. Data (datos) son una expresión constante o una lista separada por comas, de expresiones constantes. BaseAddress (dirección base) es una expresión que indica la dirección de la memoria principal para leer o escribir. Si se omite la Offset, BaseAddress es la dirección real donde operar. Si se especifica la Offset, la dirección real seria BaseAddress + Offset . Offset (ajuste) es una expresión opcional que indica el ajuste de BaseAddress.

3-96


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

Explicación WORD es uno de tres declaraciones multiusos (BYTE, WORD, y LONG) que declaran o operan en memoria. WORD se puede utilizar para: 1) declarar un símbolo tamaño-word o un array de simbolos de elementos tamaño-word en un bloque del VAR, o 2) declarar datos de tipo alineación de words, y/o tamaño-word, en un bloque de DAT, o 3) leer o escribir una word de la memoria principal en una base de dirección con un ajuste opcional. Declaración de la Variable Word (Sintaxis 1) En bloques VAR, sintaxis 1 de WORD se utiliza para declarar las variables globales, variables simbólicas tanto tamaño-word como cualquier array de words. Por ejemplo: VAR word Temp word List[25]

‘Temp es una word(2 bytes) ‘List es un array de words

El ejemplo declara dos variables; Temp y List. Temp es simplemente una variable tamaño-word. La siguiente línea utiliza el campo opcional Count para crear un array de elementos de 25 words llamado List. Temp y List pueden ser accedidos desde cualquier método PUB o PRI que tenga el mismo objeto que este bloque VAR; porque son globales al objeto. A continuación un ejemplo de esto. PUB SomeMethod Temp := 25_000 List[0] := 500 List[1] := 9_000 List[24] := 60_000

‘Fija Temp a 25,000 ‘Fija el primer elemento de List a 500 ‘Fija el Segundo elemento de List a 9,000 ‘Fija el ultimo elemento de List a 60,000

Declaración de Datos Word (Sintaxis 2) En bloques DAT, se utiliza esta sintaxis 2 para declarar los datos Word (word) que se compilan como valores constantes en memoria principal. Los bloques DAT permiten que esta declaración tenga un símbolo opcional el precediéndole, que se puede utilizar para una referencia posterior. Por ejemplo: DAT MyData word 640, $AAAA, 5_500 MyList byte word $FF99, 1_000

‘Datos alineados y de tamaño word ‘Datos tamaño word pero alineación byte

El ejemplo declara dos símbolos de datos, MyData y MyList. MyData señala al comienzo de datos word-alineados y tamaño-word, en memoria principal. Los valores de MyData, en memoria principal, son 640, $AAAA y 5.500, respectivamente. MyList utiliza una sintaxis especial del bloque DAT de WORD que crea un sistema de datos bytealineado pero de tamaño-word en memoria principal. Los valores de MyList, en memoria principal, son $FF99 y 1.000, respectivamente. Cuando se accede a un byte a la vez, MyList contiene $99, $FF, 232 y 768 puesto que los datos se almacenan en formato endian-pequeño. Estos datos se compilan en el objeto y en la aplicación resultante como parte del código ejecutable y se pueden acceder usando la forma de lectura / escritura, sintaxis 3, de WORD . Lectura / escritura de Words en Memoria Principal (Sintaxis 3) En los bloques PUB y PRI, la sintaxis 3 de WORD se utiliza para leer o para escribir valores de tamaño-word de la memoria principal. Si se asume que nuestro objeto contiene el bloque DAT del ejemplo arriba, se podía utilizar el siguiente para tener acceso a esos datos. PUB GetData | Index, Temp Temp := WORD[MyData] ‘Lee la primera word de MyData a Temp <do something with Temp> ‘Realizar una tarea con Temp repeat Index from 0 to 1 ‘Repetir dos veces Temp := WORD[MyList][Index] ‘Lee el dato a Temp 1 word por vez <do something with Temp> ‘Realizar una tarea con valor Temp

3-97


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

La primera línea dentro del método de GetData, arriba, utiliza la declaración de WORD para leer una word de la memoria principal en la localización MyData y lo almacena en Temp, en este caso, el valor 640. Mas abajo, en el loop del REPEAT, la declaración de WORD lee una word de la memoria principal de la localización MyList + índice y la almacena en Temp. Puesto que la primera iteración del loop tiene índice fijado a 0, la primera word de MyList se lee, en $FF99. La próxima vez que pasa por el loop lee la siguiente word, efectivamente, MyList + 1 (1.000). Usando una sintaxis similar, las words de la memoria principal se pueden escribir a también, mientras son localizaciones del RAM. Por ejemplo: WORD[MyList][0] := 8_192

‘Escribe 8,192 a la primera word de MyList

Esta línea escribe 8,192 a la primera word de MyList. 3.3.63. WORDFILL Rellena la memoria principal con un valor. WORDFILL (StartAddress, Value, Count ) • • •

StartAddress (dirección de comienzo) es una expresión que indica la localización de la primera word de memoria para llenar con Value. Value (valor) es una expresión que indica el valor con el que rellenar las words. Count (contador) es una expresión que indica el número de words, comenzando con StartAddress.

Explicación WORDFILL es uno de tres comandos (BYTEFILL, WORDFILL, y LONGFILL) usados para llenar bloques de la memoria principal con un valor específico. WORDFILL rellena Count words de la memoria principal con Value, comenzando en la localización StartAddress. Uso de WORDFILL WORDFILL es una gran manera de limpiar grandes bloques de memoria tamaño-word. Por ejemplo: VAR word Buff[100] PUB Main wordfill(@Buff, 0, 100)

‘Limpia Buff a 0´s

La primera línea del método principal, limpia el array entero de 100-words (200-byte) a todos los ceros. WORDFILL es más rápido realizando esta tarea que un loop REPEAT dedicado. 3.3.64. WORDMOVE Copia words (palabras) de una región a otra en memoria principal. WORDMOVE (DestAddress, SrcAddress, Count ) • • •

DestAddress (dirección de destino) es una expresión que especifica la localización de memoria principal donde copiar la primera word fuente. SrcAddress (dirección fuente) es una expresión que especifica la localización de memoria principal de la primera word de la fuente para copiar. Count (Contador) es una expresión que indica el número de las words fuente para copiar al destino.

Explicación

3-98


PROPELLER: EL GIGANTE DE 8 CABEZAS Capítulo 3: El lenguaje SPIN

www.microcontroladores.com info@microcontroladores.com

WORDMOVE es uno de tres comandos (BYTEMOVE, WORDMOVE, y LONGMOVE) usados para copiar bloques de la memoria principal a partir de una área a otra. WORDMOVE copia Count words de la memoria principal que empiezan desde SrcAddress a la memoria principal que comienza en DestAddress. Uso de WORDMOVE WORDMOVE es una gran manera de copiar bloques grandes de memoria tamaño-word. Por ejemplo: VAR word Buff1[100] word Buff2[100] PUB Main wordmove(@Buff2, @Buff1, 100)

‘Copia Buff1 a Buff2

La primera línea del método principal, copia el array entero Buff1 de 100-words (200-byte) al array Buff2. WORDMOVE es más rápido desempeñando esta tarea que si se codificase lo mismo en un loop de REPEAT. 3.3.65. _XINFREQ Constante predefinida y ajustable una vez para especificar la frecuencia del cristal externo. CON _XINFREQ = Expresión •

Expresión es un número entero que indica la frecuencia del cristal externo; la frecuencia en el pin XI. Este valor se utiliza para el arranque de la aplicación.

Explicación _ XINFREQ especifica la frecuencia del cristal externo, que se utiliza junto con el modo de reloj para determinar la frecuencia de reloj del sistema en el arranque. Es un símbolo constante predefinido que valor es determinado por el fichero objeto superior dela aplicación. _ XINFREQ se ajusta directamente por la misma aplicación, o se ajusta indirectamente como resultado de los ajustes _ CLKMODE y _ CLKFREQ. El fichero objeto superior en una aplicación (donde empieza la compilación) puede especificar un ajuste para _ XINFREQ en su bloque CON. Esto, junto con el modo de reloj, define la frecuencia que a la que cambiara el reloj, tan pronto como se arranque la aplicación y comience la ejecución. La aplicación puede especificar tanto _ XINFREQ como _ CLKFREQ en el bloque CON; son mutuamente exclusivos y el no-especificado se calcula y se fija automáticamente como resultado de especificar el otro. Los siguientes ejemplos asumen que están contenidos dentro del fichero objeto superior. Cualesquier ajuste de _XINFREQ en objetos hijo son simplemente ignorados por el copilador. Por ejemplo: CON _CLKMODE = XTAL1 + PLL8X _XINFREQ = 4_000_000 La primera declaración en este bloque CON fija el modo de reloj para un cristal externo de poca velocidad y un multiplicador del reloj PLL de 8. La segunda declaración indica la frecuencia del cristal externo es 4 Mhz, que significa que la frecuencia de reloj del sistema será 32 Mhz porque 4 Mhz * 8 = 32 Mhz. El valor de _ CLKFREQ se fija automáticamente a 32 Mhz debido a estas declaraciones. CON _CLKMODE = XTAL2 _XINFREQ = 10_000_000 Estas dos declaraciones fijan el modo de reloj para un cristal externo de velocidad media, ningún multiplicador del reloj PLL, y una frecuencia del cristal externo de 10 Mhz. El valor de _ CLKFREQ, y también la frecuencia de reloj del sistema, se fijan automáticamente a 10 Mhz, debido a estas declaraciones.

3-99


PROPELLER: EL GIGANTE DE 8 CABEZAS CapĂ­tulo 3: El lenguaje SPIN

3-100

www.microcontroladores.com info@microcontroladores.com


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.