DOCUMENTACIÓN PARA EL TRABAJO CON LA PLATAFORMA GUADALBOT I.E.S VIRGEN DE LAS NIEVES Programación C para microcontroladores Tema 7. Directivas preprocesador Índice de contenidos Directivas de preprocesado (Preprocessor commands)........................................................................2 Del c estándar o ANSI C......................................................................................................................2 Cualificadores de función.....................................................................................................................4 Identificadores predefinidos.................................................................................................................7 Sistema operativo en tiempo real RTOS (Real Time Operating System).............................................8 Especificación de dispositivos..............................................................................................................9 Librerías incorporadas........................................................................................................................11 Control de memoria............................................................................................................................15 Control del compilador.......................................................................................................................18 Del lincador........................................................................................................................................19 1 Directivas de preprocesado (Preprocessor commands) Las directivas comienzan con el símbolo # seguido de un comando específico, dependiendo la sintaxis del comando. Muchas de las directivas son extensiones del C estandar (ANSI C). Vamos a describirlas según los grupos que aparecen en la ayuda de CCS. Del c estándar o ANSI C Disponemos de las siguientes: ANSI C #IF expr #DEFINE id string #LIST #IFDEF id #UNDEF id #NOLIST #IFNDEF #INCLUDE "FILENAME" #PRAGMA cmd #ELSE #WARNING #ERROR #ELIF #ENDIF • #IF expr - #ELSE - #ENDIF El preprocesador evalúa la expresión (puede ser una constante) y si es distinta de cero procesará las líneas hasta un posible #ELSE (que es opcional) o en su defecto hasta el #ENDIF. Su sintaxis es: #if expr codigo #elif expr codigo #else codigo #endif //Es opcional y podemos usar cualquier número //Opcional Por ejemplo: • #IFDEF id - #ELSE - #ENDIF - #IFNDEF - #ELIF Esta directiva actúa como #IF sólo que aquí el preprocesador simplemente comprueba que reconoce el id especificado (creado con un #DEFINE). Nótese que #IFDEF verifica si se definió un id pero #IFNDEF comprueba que no está definido el id. Su sintaxis es: #ifdef id code #elif code #else code #endif #ifndef id code #elif code #else code #endif 2 Por ejemplo: • #DEFINE id string Se utiliza simplemente para reemplazar el identificador (id) con string. Su sintaxis es: #define id text #define id(x,y...) text donde id es un identificador, text cualquier texto, x,y, ... identificadores locales para el preprocesador pudiendo, como se muestra, más de un identificador. Ejemplo: • #ERROR Esta directiva obliga al compilador a generar un error y emite el mensaje que se incluye a continuación (en la misma línea) de la propia directiva. El mensaje puede incluir macros. También puede utilizarse para alertar al usuario de una situación anómala en tiempo de compilación. Su sintaxis es: #error text #error / warning text #error / information text donde text es opcional y puede ser cualquier texto Ejemplo: • #INCLUDE "FILENAME" o #INCLUDE <FILENAME> Esta directiva hace que el compilador incluya en el fichero fuente el texto que contiene el archivo especificado en <FILENAME>. Si el nombre del fichero se incluye entre los símbolos '< >' el compilador busca el fichero en el directorio INCLUDE de la instalación. Si se pone entre comillas dobles el compilador busca primero en el directorio actual de trabajo y, si no lo encuentra, busca en los directorios INCLUDE del compilador. Su sintaxis es: #include #include <filename> "filename" siendo filename un nombre válido de fichero. Ejemplo: 3 • #LIST Guarda el código fuente en el archivo .LST. Comienza a insertar o reanuda la inserción de las líneas de código en el archivo. LST después de un #NOLIST. • #NOLIST No guarda el código fuente en el archivo .LST. Detiene la inserción de las líneas de código en el archivo. LST hasta un #LIST. • #PRAGMA cmd Esta directiva se usa para mantener la compatibilidad entre los compiladores de C. El compilador aceptará esta directiva antes que cualquier otro comando del preprocesador. Su sintaxis es: #pragma cmd donde cmd es cualquier directiva válida • #UNDEF id El identificador id deja de estar activo y ya no tendrá significando para el preprocesador. Su sintaxis es: #undef id siendo id un identificador definido con #define Por ejemplo: • #WARNING Fuerza a que el compilador genere una advertencia donde esta directiva aparece en el archivo. Su sintaxis es: #warning text donde text es opcional y puede ser cualquier texto Ejemplo: Cualificadores de función Son las siguientes. Cualificadores • #INLINE #INT_xxx #INT_GLOBAL #SEPARATE #INT_DEFAULT #INLINE Esta directiva le dice al compilador que el procedimiento que sigue a la directiva será llevado a cabo EN LÍNEA. Esto causará una copia del código que será puesto en cualquier parte donde se llame al procedimiento. Esto es útil para ahorrar espacio de la pila (stack) y aumentar la velocidad. Sin esta directiva es el compilador quien decidirá cuando es mejor hacer los procedimientos EN LÍNEA. 4 • #INT_DEFAULT La función que sigue a la directiva será llamada si el PIC activa una interrupción y ninguno de los flags de interrupción está activo. • #INT_GLOBAL La función que sigue a esta directiva reemplaza al distribuidor de interrupciones del compilador; dicha función toma el control de las interrupciones y el compilador no salva ningún registro. Normalmente no es necesario usar esto y debe tratarse con gran prudencia. • #INT_xxx Estas directivas especifican que la función que le sigue es una función de interrupción. Las funciones de interrupción no pueden tener ningún parámetro. Como es natural, no todas las directivas pueden usarse con todos los dispositivos. Las directivas de este tipo que disponemos son: #INT_AD #INT_ADOF #INT_BUSCOL #INT_BUTTON #INT_CANERR #INT_CANIRX #INT_CANRX0 #INT_CANRX1 #INT_CANTX0 #INT_CANTX1 #INT_CANTX2 #INT_CANWAKE #INT_CCP1 #INT_CCP2 #INT_CCP3 #INT_CCP4 #INT_CCP5 #INT_COMP #INT_COMP1 #INT_COMP2 #INT_EEPROM #INT_EXT #INT_EXT1 #INT_EXT2 Conversión A/D completada Retardo de la conversión A/D Colisión en BUS Botón pulsador Error en el módulo CAN Mensaje no válido en el bus CAN Búfer 0 receptor CAN recibe un nuevo mensaje Búfer 1 receptor CAN recibe un nuevo mensaje Búfer 0 emisor CAN completa la transmisión Búfer 1 emisor CAN completa la transmisión Búfer 2 emisor CAN completa la transmisión Actividad despertar en el bus CAN Modo captura de datos por CCP1 Modo captura de datos por CCP2 Modo captura de datos por CCP3 Modo captura de datos por CCP4 Modo captura de datos por CCP5 Comparador de interrupciones Detectado comparador 1 Detectado comparador 2 Escritura realizada Interrupción externa Interrupción externa número 1 Interrupción externa número 2 5 #INT_EXT3 #INT_I2C #INT_IC1 #INT_IC2 #INT_IC3 #INT_LCD #INT_LOWVOLT #INT_LVD #INT_OSC_FAIL #INT_OSCF #INT_PSP #INT_PWMTB #INT_RA #INT_RB #INT_RC #INT_RDA #INT_RDA0 #INT_RDA1 #INT_RDA2 #INT_RTCC #INT_SPP #INT_SSP #INT_SSP2 #INT_TBE #INT_TBE0 #INT_TBE1 #INT_TBE2 #INT_TIMER0 #INT_TIMER1 #INT_TIMER2 #INT_TIMER3 #INT_TIMER4 #INT_TIMER5 #INT_USB Interrupción externa número 3 Interrupción I2C Captura Entrada número 1 Captura Entrada número 2 Captura Entrada número 3 Actividad en la LCD Detectada tensión baja Detectada tensión baja Fallo en el sistema oscilador Fallo en el sistema oscilador Dato en el puerto paralelo esclavo PSP Base de tiempos de PWM Se detecta cambio en pines A0...A5 del puerto A Se detecta cambio en pines B4...B7 del puerto B Se detecta cambio en pines C4...C7 del puerto C Recepción de datos disponible vía RS232 Recepción de datos disponible vía RS232 en búfer 0 Recepción de datos disponible vía RS232 en búfer 1 Recepción de datos disponible vía RS232 en búfer 2 Desborde del Timer 0 (RTCC) Streaming puerto paralelo lectura/escritura Actividad en SPI o I2C Actividad en SPI o I2C para puerto 2 Búfer de transmisión RS232 vacío Búfer de transmisión 0 RS232 vacío Búfer de transmisión 1 RS232 vacío Búfer de transmisión 2 RS232 vacío Desborde del Timer 0 (RTCC) Desborde del Timer 1 Desborde del Timer 2 Desborde del Timer 3 Desborde del Timer 4 Desborde del Timer 5 Actividad en el bus USB El compilador salta a la función de interrupción cuando se detecta una interrupción. Es el propio compilador el encargado de generar el código para guardar y restaurar el estado del procesador. También es el compilador quien borrará la interrupción (el flag). Sin embargo, nuestro programa es el encargado de llamar a la función ENABLE_INTERRUPT() para activar previamente la interrupción junto con el señalizador (flag) global de interrupciones. • #SEPARATE Directiva que indica al compilador que el procedimiento o función que sigue a la directiva será llevado a cabo por SEPARADO. Esto es útil para evitar que el compilador haga automáticamente un procedimiento en línea (INLINE). Esto ahorra memoria ROM pero usa más espacio de la pila. El compilador hará todos los procedimientos #SEPARATE, separados, tal como se solicita, aun cuando no haya bastante pila. Ejemplo: 6 Identificadores predefinidos Disponemos de los siguientes: _ _DATE_ _ _ _LINE_ _ _ _PCH_ _ Identificadores _ _DEVICE_ _ _ _FILENAME_ _ _ _PCM_ _ predefinidos _ _FILE_ _ _ _TIME_ _ _ _PCB_ _ • _ _DATE_ _ Este identificador del preprocesador contiene la fecha actual (en tiempo de compilación) en el formato siguiente: "31-AGO-11". Ejemplo: • _ _PCH_ _; _ _PCM_ _ o _ _PCB_ _ Se utiliza para determinar si es el compilador PCH, PCM o PCB el que está haciendo la compilación. Ejemplo: • _ _DEVICE_ _ Este identificador del preprocesador es definido por el compilador con el número base del dispositivo actual. El número base normalmente es el número que sigue a la(s) letra(s) en el número de componente o referencia de un dispositivo. Por ejemplo los PIC16C84 tienen el número base 84, en los PIC16C622 es el 622 y en los PIC18F4550 es 4550. Ejemplo: • _ _FILE_ _ y _ _LINE_ _ El identificador del preprocesador es reemplazado (en tiempo de compilación) con la ruta y el nombre del archivo que está siendo compilado. • _ _FILENAME_ _ El identificador del preprocesador es reemplazado (en tiempo de compilación) con el nombre del archivo que se compila. Ejemplo: 7 • _ _TIME_ _ El identificador del preprocesador es reemplazado (en tiempo de compilación) con la hora en el momento de la compilación en la forma: "hh: mm: ss". Ejemplo: Sistema operativo en tiempo real RTOS (Real Time Operating System) RTOS • #TASK #USE RTOS #TASK Cada RTOS task (tarea) se especifica como una función que no tiene parámetros y no retorna nada. La directiva es necesaria antes de cada tarea RTOS para que el compilador sepa que las funciones son tareas RTOS. Una tarea RTOS no puede ser llamada directamente como una función regular. Su sintaxis es: #task (options), donde options son elementos separados por comas que pueden ser: rate=time (velocidad= tiempo) Donde time es un número seguido de s, ms, us, o ns. Así se especifica con qué frecuencia se ejecutará la tarea. max=time Donde time es un número seguido de s, ms, us, o ns. Así se especifica el tiempo destinado a la tarea. queue=bytes Especifica la cantidad de bytes para asignar a los mensajes entrantes de esta tarea. El valor predeterminado es 0. Ejemplo: • #USE RTOS El sistema operativo en tiempo real de CCS (RTOS) permite a un microcontrolador PIC ejecutar tareas periódicas, sin necesidad de interrupciones. Esto se logra mediante la función RTOS_RUN () que actúa como un distribuidor. Cuando una tarea está programada para ejecutarse, la función da el control del procesador a esa tarea. Cuando se termina de ejecutar la tarea o ya no necesita, el procesador devuelve el control del procesador a la función, que luego le dará el control del procesador a la siguiente tarea que está programado para ejecutarse en el momento adecuado. Este proceso se llama cooperativa multitarea. Su sintaxis es: #use rtos (options), donde options son elementos separados por comas que pueden ser: timer=X Donde X especifica el temporizador (0 a 4) que va a usar RTOS minor_cycle=time Donde time es un número seguido de s, ms, us, o ns. Este es el mayor tiempo que se ejecutará una tarea cualquiera. La tasa de ejecución de cada tarea debe ser un múltiplo de este tiempo. El compilador lo calcula si no se especifica. statistics Mantiene el tiempo total, mínimo y máximo de cada tarea. 8 Especificación de dispositivos Son las siguientes: #DEVICE chip #ID "filename" #HEXCOMMENT Especificacion de dispositivos #FUSES options #ID number #ID CHECKSUM • #SERIALIZE #DEVICE chip Esta directiva define al compilador la arquitectura hardware utilizada. Tiene la siguiente sintaxis: − #device chip options − #device Compilation mode selection En chip options, chip es el nombre especifico de un microcontrolador. Podemos ver una lista de todos los soportados dirigiendonos al menú inicio de windows, escogemos ejecutar y tecleamos CCSC +Q, obteniendo una ventana similar a la siguiente. En chip options, options son cualificadores para el normal funcionamiento del dispositivo. Las opciones válidas son: *=5: Usa punteros de 5 bits (todos los dispositivos) *=8: Usa punteros de 8 bits (dispositivos de 14 y 16 bits) *=16: Usa punteros de 16 bits (dispositivos de 14 bits) ADC=x: siendo x el número de bits que puede devolver read_adc() ICD=TRUE: Genera código compatible con el hardware de depuración ICD de microchips. WRITE_EEPROM=ASYNC: Impide WRITE_EEPROM mientras que la escritura tiene lugar. 9 HIGH_INTS=TRUE: Esta opción se usa para establecer la prioridad de interrupciones como alta/baja en los dispositivos PIC18. las %f=.: No pone el 0 antes del punto decimal en números f% menores que 1. OVERLOAD=KEYWORD: La sobrecarga de funciones es ahora compatible. OVERLOAD=AUTO: Modo por defecto para la sobrecarga. PASS_STRINGS=IN_RAM: Una nueva forma de pasar cadenas constantes a una función es copiar primero la cadena en la RAM y luego pasar un puntero de la memoria RAM a la función. CONST=READ_ONLY : Utiliza la palabra clave estándar CONST, por lo que las variables tipo CONST de sólo lectura deben ubicarse en la memoria del programa. CONST=ROM: Utiliza la palabra clave estándar CONST, por lo que las variables tipo CONST se encuentra en la memoria del programa. Este es el modo por defecto. En Compilation mode selection la directiva permite la selección de modo de compilación. Las palabras clave válidas CCS2, CCS3, CCS 4 y ANSI. El modo predeterminado es CCS4. Para el modo de CCS4 y ANSI, el compilador utiliza el valor por defecto de la configuración de fusibles NOLVP, PUT para los chips con estos fusibles. El fusible NOWDT está por defecto si no hay ninguna llamada a restart_wdt (). - CCS4: Modo por defecto de compilación. El tamaño del puntero para los modos PCM y PCH se establece a *=16 si el dispositivo tiene RAM por encima de 0FF. - ANSI: Tipo de datos predeterminado es con signo para todos los otros modos por defecto es sin signo. Compilación es sensible a mayúsculas y minúsculas, todos los otros modos no son sensibles a mayúsculas y minúsculas. El tamaño del puntero se establece en *=16 si el dispositivo tiene RAM por encima de 0FF. - CCS2 y CCS3: var16 = NegConst8 se compila como: var16 = NegConst8 y el tamaño 0xff (sin signo)Pointer se pone a *=8 para PCM y PCH y *=5 para PCB. Requiere la palabra reservada overload. - CCS2 solo: Por defecto #device ADC establece la resolución del dispositivo, todos los otros modos es 8 por defecto. onebit = eightbits se compila como onebit = (eightbits != 0) Todos los otros modos se compilan como: onebit = (eightbits & 1) Por ejemplo: 10 • #ID number, #ID "filename" e #ID CHECKSUM Permite grabar la identificación ID en el chip (uC, memoria, etc). Esta directiva no afecta a la compilación pero la información se pone en el archivo de salida. Las posibles formas de sintaxis son: #ID #ID #ID #ID number 16 number, number, number, number "filename" CHECKSUM La primera sintaxis necesita un número de 16-bit y pondrá un nible en cada una de las cuatro palabras del ID. La segunda sintaxis especifica el valor exacto en cada una de las cuatro palabras del ID. Cuando se especifica "filename" el ID se lee del archivo indicado; su formato debe ser texto simple con un CR/LF al final. La palabra CHECKSUM indica que el checksum (suma de control) del dispositivo debe tomarse como el ID. Por ejemplo: • #FUSES options Esta directiva define qué fusibles deben activarse en el dispositivo cuando se programe. Esta directiva no afecta a la compilación; sin embargo, esta información se pone en el archivo de salida. La opción SWAP tiene la función especial de intercambiar, los bytes alto y bajo de los datos que no son parte del programa, en el archivo Hex. Esta información es necesaria para algunos programadores de dispositivos. Algunas de las opciones más usadas son: • LP, XT, HS, RC WDT, NOWDT PROTECT, NOPROTECT PUT, NOPUT (Power Up Timer) BROWNOUT, NOBROWNOUT SWAP #HEXCOMMENT Pone un comentario en el archivo hexadecimal. A algunos programadores (MPLAB, en particular) no les gustan los comentarios al principio del archivo hexadecimal. Su sintaxis es: #HEXCOMMENT text comment for the top of the hex file #HEXCOMMENT\ text comment for the end of the hex file Por ejemplo: • #SERIALIZE Ayuda a crear números de serie más fácilmente cuando se trabaja con unidades ICD de CCS. Los comentarios se introducen en el archivo hex y el software ICD lo interpreta. Librerías incorporadas Son: #USE DELAY #USE FIXED_IO #USE RS232 Librerias incorporadas #USE FAST_IO #USE I2C #USE SPI 11 #USE STANDARD_IO • #USE DELAY Esta directiva indica al compilador la frecuencia del procesador, en ciclos por segundo (Hz), a la vez que habilita el uso de las funciones DELAY_MS() y DELAY_US(). Opcionalmente podemos usar la función restart_WDT() para que el compilador reinicie el WDT durante el retardo. Su sintaxis es: #use #use #use #use #use delay delay delay delay delay (clock=speed) (clock=speed, restart_wdt) (clock=speed, type) (clock=speed, type=speed) (type=speed) donde: speed es una constante de 1 a 100000000 (1 Hz a 100 MHz). Este número puede contener comas y soporta también las siguientes denominaciones: M, MHZ, K, KHZ. type define el tipo de reloj que usamos, siendo valores válidos: oscillator, osc (igual que oscillator), crystal, xtal (igual que crystal), internal, int (lo mismo que internal) o rc. El compilador establece automáticamente los bits de configuración del oscilador en base al tipo definido. Si hemos especificado interno, el compilador también ajusta automáticamente el oscilador interno a la velocidad definida. restart_wdt se reiniciará el WDT en cada uso de delay_us () y delay_ms (). Ejemplos válidos son: • #USE FAST_IO Esta directiva afecta al código que el compilador generará para las instrucciones de entrada y salida. Este método rápido de hacer I/O ocasiona que el compilador realice I/O sin programar el registro de dirección. Su sintaxis es: #use fast_io (port) pudiendo port ser: A, B, C, D, E, F, G, H, J o ALL Ejemplo: • #USE FIXED_IO Esta directiva afecta al código que el compilador generará para las instrucciones de entrada y salida. El método fijo de hacer I/O causará que el compilador genere código para hacer que un pin de I/O sea entrada o salida cada vez que se utiliza. Esto ahorra el byte de RAM usado en I/O normal. Su sintaxis es: #use fixed_io (port_outputs=pin, pin?) donde por puede ir de A a G y pin es una de las constantes pin definidas en el fichero .h del dispositivo. 12 Ejemplo: • #USE I2C La librería I2C contiene funciones para implementar un bus I2C. La directiva #USE I2C permanece activa para las funciones I2C_START, I2C_STOP, I2C_READ, I2C_WRITE e I2C_POLL hasta que se encuentre otra directiva #USE I2C. Se generan las funciones software a menos que se especifique la opción NOFORCE_SW. El modo SLAVE sólo debe usarse con las funciones SSP. Su sintaxis es: #use i2c (options) donde options son las opciones separadas por comas y que pueden ser: MASTER Establece el modo maestro o principal MULTI_MASTER Establece el modo multi-maestro SLAVE Modo esclavo SCL=pin Especifica el pin SCL (es un bit de dirección) SDA=pin Especifica el pin SDA ADDRESS=nn Especifica la dirección del modo esclavo FAST Usa la especificación rápida I2C FAST=nnnnnn Establece la velocidad a nnnnnn Hz SLOW Usa la especificación lenta I2C RESTART_WDT Reinicia el WDT mientras espera en I2C_READ FORCE_HW Usa funciones hardware I2C FORCE_SW Usa funciones software I2C NOFLOAT_HIGH No se permiten señales altas flotantes sino flanco de subida. SMBUS El bus usado no es I2C pero es muy similar STREAM=id Asocia un identificador tipo cadena con el puerto I2C. NO_STRETCH No se permite reloj streaching MASK=nn Establece una máscara de dirección en los dispositivos que lo soportan I2C1 En lugar de SCL= y SDA= establece los pines para el primer módulo I2C2 En lugar de SCL= y SDA= establece los pines para el segundo módulo Ejemplo: • #USE RS232 Esta directiva le dice al compilador la velocidad en baudios y los pines utilizados para la Entrada/Salida serie. Esta directiva tiene efecto hasta que se encuentra otra directiva RS232. La directiva #USE DELAY debe aparecer antes de utilizar #USE RS232. Esta directiva habilita el uso de funciones tales como GETCH, PUTCHAR y PRINTF. Si la I/O no es estandar es preciso poner las directivas FIXED_IO o FAST_IO delante de #USE RS232. Su sintaxis es: #use rs232 (options) donde options son las opciones separadas por comas y que pueden ser: 13 RESTART_WDT Hace que GETC() ponga a cero el WDT mientras espera un carácter. INVERT Invierte la polaridad de los pines serie (normalmente no es necesario con el convertidor de nivel, como el MAX232). No puede usarse con el SCI interno. PARITY=X Donde X es N, E, u O. BITS =X Donde X es 5-9 (no puede usarse 5-7 con el SCI). FLOAT_HIGH Se utiliza para las salidas de colecctor abierto. ERRORS Indica al compilador que guarde los errores recibidos en la variable RS232_ERRORS para restablecerlos cuando se producen. BRGH1OK Permite velocidades de transmisión bajas en chips (micros, memorias, etc) que tienen problemas de transmisión. Cuando utilizamos dispositivos con SCI y se especifican los pines SCI, entonces se usará el SCI. Si no se puede alcanzar una tasa de baudios dentro del 3% del valor deseado utilizando la frecuencia de reloj actual, se generará un error. ENABLE=pin El pin especificado estará a nivel alto durante la transmisión. FORCE_SW Usa una UART software en lugar del hardware aun cuando se especifican los pines del hardware. La definición de RS232_ERRORS es como sigue: Sin UART: El bit 7 es el 9º bit para el modo de datos de 9 bit. El bit 6 a nivel alto indica un fallo en el modo flotante alto. Con UART: Usado sólo para conseguir: Copia del registro RCSTA, excepto: que el bit 0 se usa para indicar un error de paridad. Por ejemplo: • #USE STANDARD_IO Esta directiva afecta al código que el compilador genera para las instrucciones de entrada y salida. El método standar de hacer I/O causará que el compilador genere código para hacer que un pin de I/O sea entrada o salida cada vez que se utiliza. En los procesadores de la serie 5X esto necesita un byte de RAM para cada puerto establecido como I/O estandar. Su sintaxis es: #USE STANDARD_IO (port) pudiendo port ser: A, B, C, D, E, F, G, H, J o ALL Ejemplo: • #USE SPI La directiva SPI contiene funciones para implementar un bus SPI. Después de ajustar todos los parámetros adecuados puede ser utilizado tanto para transferir como para recibir datos. 14 Control de memoria Están disponibles las siguientes #ASM #ENDASM #ROM #BIT id=id.const #FILL_ROM #TYPE Control de memoria #BIT id=const.const #LOCATE id=const #ZERO_RAM • #BYTE id=const #ORG #BYTE id=id #RESERVE #WORD #ASM - #ENDASM Las líneas entre #ASM y #ENDASM se tratan como código ensamblador. La variable predefinida _RETURN_ puede utilizarse para asignar un valor de retorno a la función desde el código en ensamblador. Su sintaxis es: #asm o #asm ASIS code #endasm donde code es una lista de instrucciones en lenguaje ensamblador. Por ejemplo: • #BIT id=id.const o #BIT id=const.const Esta directiva creará un identificador "id" que puede utilizarse como cualquier bit SHORT INT. Se usa principalmente para acceder al mapa de bits de los registros de funciones especiales, normalmente puertos, y tratarlos así como variables C.Su sintaxis es: #bit donde: id = x.y id es un identificador C válido, x es una variable o constante, y es una constante con valor 0 a 7. Ejemplo: 15 • #BYTE id=const o #BYTE id=id Esta directiva creará un identificador "id" que puede utilizarse como cualquier INT (un byte). El identificador referenciará un objeto en la posición de memoria x, donde x puede ser una constante u otro identificador. Si x es otro identificador, entonces éste estará localizado en la misma dirección que el identificador "id". Su sintaxis es: #byte id = x donde id es un indentificador válido de C, x es una variable o una constante Ejemplo: • #RESERVE Permite reservar posiciones de la RAM para uso del compilador. #RESERVE debe aparecer después de la directiva #DEVICE, de lo contrario no tendrá efecto. Sus sintaxis posibles son: #reserve address #reserve address, address, address #reserve start:end Ejemplos: • #ROM Esta directiva permite insertar datos en el archivo .HEX. En particular, se puede usar para programar la EEPROM de datos de la serie 84 de PIC. Por ejemplo: • #ZERO_RAM Directiva que pone a cero todos los registros internos que pueden usarse para mantener variables, antes de que comienze la ejecución del programa. Por ejemplo: • #FILL_ROM Esta directiva especifica los datos que se utilizan para llenar lugares no utilizados de la memoria ROM. Su sintaxis es: #fill_rom value donde value es una constane de 16 bit Ejemplo: • #TYPE Por defecto, el compilador trata los SHORT como un bit, INT como 8 bits y LONG hasta 16 bits. Convencionalmente en C el tamaño más eficiente para el procesador es el INT, razón por la que podemos usar esta directiva para cambiar los tipos y establecer compatibilidad de código. Su sintaxis es: 16 #type #type #type #type donde standard-type=size default=area unsigned signed standard-type es una palabra reservada C: short, int, long, o default size es 1,8,16, o 32 area es una región de memoria definida antes de #TYPE Ejemplo: • #LOCATE id=const Trabaja de la misma forma que #BYTE pero además evita que C use esa zona. Su sintaxis es: #locate id=x Ejemplo: • #ORG La directiva hace al compilador colocar el código que le sigue en una nueva dirección de memoria (la salida del compilador no solo coloca los códigos de operación sino también las direcciones de cada instrucción del programa). Sintaxis: #org #org #org #org #ORG #ORG start, end segment start, end {} start, end auto=0 start,end DEFAULT DEFAULT Ejemplo: 17 • #WORD id=x Si el id ya se conoce como una variable C entonces esto va a ubicar la variable en la dirección x. En este caso el tipo de variable no cambia de la definición original. Si la identificación no se conoce como una variable C se crea nueva y se coloca en la dirección x con el tipo Int16. Control del compilador Tenemos las siguientes: #CASE #IMPORT Control del compilador #EXPORT #IGNORE_WARNINGS • #PRIORITY #OPT n #MODULE #CASE Hace que el compilador diferencie entre mayúsculas y minúsculas. Por defecto el compilador hace esta distinción. • #OPT n Esta directiva sólo se usa con el paquete PCW y, establece el nivel de optimización. Se aplica al programa entero y puede aparecer en cualquier parte del archivo fuente. El nivel de optimización 5 es el nivel para los compiladores DOS. El valor por defecto para el compilador PCW es 9 que proporciona una optimización total. • #PRIORITY Esta directiva se usa para establecer la prioridad de las interrupciones. Los elementos de mayor prioridad van primero. Ejemplo: • #IGNORE_WARNINGS Para que los mensajes de advertencia del compilador sean ignorados u omitidos. Su sintaxis es: #ignore_warnings #IGNORE_WARNINGS #IGNORE_WARNINGS ALL NONE warnings ALL indica que no se generarán advertencias. NONE indica que todas las advertencias serán generadas. Los números que pongamos en lugar de warnings serán los avisos que se supriman. • #MODULE Todos los símbolos globales creados desde el #MODULE hasta el final del archivo sólo serán visible dentro de ese bloque de código (y por los archivos #include dentro de ese bloque). Esto se usa para limitar el alcance de las variables globales y funciones dentro de archivos include. 18 Del lincador Lincador • #IMPORT #EXPORT #BUILD #IMPORT Esta directiva indica al compilador que incluya (link) un objeto reubicable con esta unidad durante la compilación. Normalmente todos los símbolos globales desde el archivo especificado se vincularán, pero las opciones EXCEPT y ONLY sólo puede prevenir algunos de los símbolos de su vinculación. • #EXPORT Esta directiva indica al compilador que genere un fichero objeto reubicable o un hexadecimal independiente. Un fichero objeto reubicable se tiene que incorporar en nuestra aplicación, mientras que un hexadecimal independiente se puede programar directamente en el PIC. • #BUILD Dispositivos PIC18XXX con ROM externa o dispositivos PIC18XXX sin ROM interna pueden indicar directamente al compilador para utilizar la ROM. Cuando se enlazan (linking) varias unidades de compilación, esta directiva debe aparecer exactamente lo mismo en cada unidad de compilación. Su sintaxis es: #build(segment = #build(segment = #build(segment = #build(segment = #build(nosleep) address) address, segment = address) start:end) start: end, segment = start: end) Ejemplo: 19