Translate

lunes, 22 de diciembre de 2008

Una secuencia para LED's

Ahora que ya sabemos hacer blink en las salidas del PIC, podemos jugar con el puerto para hacer una secuencia de luces. La idea es correr el encendido de los LED's desde RB0 a RB7 y de RB7 a RB0.

Asi que vamos a usar los operadores corriemiento a la derecha(>>) y corrimiento a la izquierda(<<), para cambiar el sentido del corrimiento vamos a utilizar un botón, por lo que necesitaremos que un PIN actúe como entrada. Cuando este activado nos entregara un 1 lógico y la secuencia recorrerá de Rb0 a RB7 y cuando este desactivado nos entregara un 0  lógico y la secuencia recorrerá de RB7 a RB0. 

Para este fin usaremos el siguiente programa:

Como podemos ver el if..else es el que hace toda la tarea dependiendo del estado del botón, dentro del if..else hay un for que nos ayuda a recorrer el BIT 8 veces que son los pines del PORTB y la pausa que nos ayuda a visualizar el corrimiento.

Tenemos que notar que para cambiar el sentido del corrimiento tendremos que esperar a que se termine la secuencia de cada for, ya que no para de forma inmediata, para que se salga de forma inmediata se tendrá que hacer con una condición y la sentencia break, pero ojala eso lo puedan implementar ustedes.

Adjunto el video de la simulación:

sábado, 20 de diciembre de 2008

Accediendo a los Bits Individuales de los Registros

Hasta ahora hemos trabajado con los registros del PIC de manera directa, asignando un valor que determina el estado de todos los bits que están dentro del él, pero también podemos asignar valores individuales a todos los registros del PIC, por ejemplo, si en vez de hacer blink en todo el PORTB solo queremos hacerlo en uno de sus bits como por ejemplo en RB3, podríamos asignar el siguiente valor:
 
 PORTB=8;
 Delay10KTCYx(250);
 PORTB=0;
 Delay10KTCYx(250);
 
Seria valido, ya que solo asignamos un 1 a RB3 y posteriormente  asignamos 0 a todo el PORTB, pero sería mas sencillo si accediéramos al bit del registro directamente, lo cual es posible. Para acceder a los bits individuales de los registros tenemos que usar la siguiente sentencia:
 
 nombre_del_registrobits.nombre_del_bit 


De tal forma que para encender el bit RB3 de PORTB tendremos que asignar la siguiente sentencia: PORTBbits.RB3, 
recordemos que C18 es sensible a las mayúsculas, así que escribir portbbits.rb3 nos generará un error en la sintaxis. Esta forma de acceder a los bits es valida para todos los registros del PIC. pero siempre hay que especificar el nombre correcto del bit del registro, para ello podemos acceder a la librería del PIC por ejemplo a la librería p18f4520.h


Ahora hagamos un blink en el bit RB3 del PORTB con el siguiente programa

:


Y aqui la simulación del programa anterior:




El acceder a los bits individuales es práctico, ya que nos perrmite leer el estado de un solo bit, o cambiar el estado de un solo bit sin modificar el estado del registro.

viernes, 19 de diciembre de 2008

Añadiendo librerías

El siguiente paso es añadir librerías a nuestro primer programa, como había comentado la sentencia for  del ejemplo "hola mundo" sirve para crear una pausa entre poner el PORTB a cero y poner PORTB a 1, la pausa sera lo que tarda i en recorrer 500; sin embargo no manejamos con exactitud el lapso que tarda en hacer eso.

Para poder llevar una pausa mas real, podemos hacer uso de las librerías de C18, las librerías se encuentran en el directorio de instalación del compilador y en le subdirectorio h.  Para saber de cuales librerías disponemos basta con revisar el PDF llamado MPLAB C18 C COMPILER LIBRARIES  ubicado en la subcarpeta doc  del directorio de instalación.

Para nuestro programa vamos a usar la librería delays.h  la cual posee las siguientes funciones:

Delay1TCY                       Demora 1 ciclo.
Delay10TCYx                  Demora en multiplos de 10 ciclos.
Delay100TCYx               Demora en multiplos de 100 ciclos.
Delay1KTCYx                 Demora en multiplos de 1000 ciclos.
Delay10KTCYx              Demora en multiplos de 10000 ciclos.

Exceptuando Delay1TCY, las demás funciones necesitan un argumento de tamaño byte para poder generar la pausa. En general un ciclo esta dado por 4 instrucciones del reloj, de tal forma que para sacar una pausa en términos de segundos se necesita usar la formula:

 No de ciclos = ( Pausa deseada * FOSC) / 4

Donde No de ciclos  es le argumento que necesitamos para las funciones,  Pausa deseada  es el tiempo que queremos que demore la función, FOSC  es el acrónimo a Frecuency Oscilator que esta dada por el cristal que usemos, final mente 4 son los ciclos por instrucción.

De esta manera al programa de hola mundo agreguemos un pausa de medio segundo entre los cambios de estado del PORTB.

Pausa deseada = 0.5 segundos

FOSC = 20 MHz

  No de ciclos = ( 0.5 * 20,000,000 ) / 4

 No de ciclos =  2, 500,000

Ya que los argumentos de las funciones no deben sobrepasar un byte (255) el valor máximo que podemos meter para nuestra pausa es 250 así que 250 * 10,000 = 2,500,000. De esta forma la función que nos permitirá obtener una pausa de medio segundo será Delay10KTCYx. Solo tenemos que modificar el código anterior para obtener un  blink  en todo el PORTB cada medio segundo. 

Y aquí la simulación del programa

Optimizando

Se dice optimizar cuando se trata de hacer las mismas cosas, con los menores recursos posibles, para nuestro caso sería con el menor código posible. El código anterior lo podemos optimizar de la siguiente manera:

 

Como podemos ver en el código anterior eliminamos las sentencias:

   PORTB=0;

   Delay10KTCYx(250);

Y cambiamos la sentencia:

  PORTB=255;  por la sentencia

  PORTB ^= 255;

Recordemos que el operador XOR (^) regresa 1 si los bits son complementarios de lo contrario regresa cero y al hacer 255 xor 255 regresara cero, así podemos invertir el estado de 255 a 0 en una sola linea. y el resultado final será el mismo.

Analicemos el programa "hola mundo"

Bien,ya que hicimos nuestro primer programa vamos a describirlo linea a linea para que sea mas claro lo que hace cada comando.

Primero tenemos esta sentencia #include < p18f4520.h > Estamos haciendo uso de el operador de preprocesado (#) seguido de la palabra reservada include, con esto estamos indicando al compilador que durante la compilación incluya el archivo p18f4520.h, este archivo contiene las direcciones de todos los registros del PIC, así como sus bits individuales y su configuración. Es por esta razón que podemos usar directamente los nombres de los registros como PORTB, TRISB, ADCON0, etc. En dado caso que no insertaramos la librería del PIC, tendriamos que definir cada registro del PIC con el operador de preprocesado (#) y la palabra reservada define seguida del nombre y dirección del registro a usar.

Posteriormente tenemos las siguientes sentencias:

#pragma config OSC = HS, FCMEN = OFF, IESO = OFF 
#pragma config PWRT = OFF,BOREN = OFF,BORV = 0 
#pragma config WDT = OFF, WDTPS = 32768 
#pragma config MCLRE = ON, LPT1OSC = OFF,PBADEN = OFF, CCP2MX = PORTC

Como veran hacemos uso del operador  de preprocesado(#) seguido de la palabra reservada pragma y config  estas sentencias las usamos para configurar parte de configH y configL que es el registro del PIC donde declaramos el tipo de oscilador y otras funciones especiales, estos regisrtros varian dependiendo cada PIC, para este ejemplo configuramos un Oscilador externo en High Speed, con la sentecia OSC=HS, en las funciones especiales como Power on reset, brown out reset Bor, FCMEN IESO LPT, etc. Las declaramos como off,  es decir, que no las vamnos a usar. La función de Memory clear la activamos para poder hacer un reset fisico, MCLRE=ON.

Posteriormente tenemos la sentencia: unsigned int i; Con la cual estamos declarando una variable global, que pdemos usar entodo nuestro programa, de tipo entero sin signo que va de 0 a 65535.

Seguido de la declaracion de la variable i tenemos la siguiente sentecia:

void main(void)

Con la cual estamos dando inicio al programa, seguido del inicio del programa tenemos:

  TRISB = 0;          //  declaramos el puerto B como salida
 ADCON0 = 0;       //   sin AD canal 0 por defecto
 ADCON1 = 15;     //   Todas las salidas digitales sin Vrefs
 ADCON2 = 0;      //   8 bits no importa TAD ni FOSC
 PORTB = 0;        //  PORTB apagado

Estas sentencias fueron explicadas anteriormente y su comentario es muy claro, solo que hay que resaltar algo, PORTB en realidad es un alias de LATB en los PIC18F's los puertos son conocidos como LATx y escribir PORTx es una alias, asi que es igual escribir PORTB=0; que LATB=0;

Finalmente construimos el programa con:

    while(1)                                     // creamos un ciclo infinito
   {                                                    // abrimos el cilco infinito
     PORTB=255;                        // encendemos el Todo el PORTB
    for(i=0; i==500; i++);      // creamos una especie de pausa
    PORTB=0;                            // apagamos el puerto para hacer blink
   }                                                 // cerramos el ciclo infinito
 }                                                  // cerramos la funcion main
  

De igual manera es muy transparante esa porcion de código,  solo que me gustaria hacer énfasis en la parte del for, en este caso se uso la variable i dentro del for para ir de 0 a 500 como no tiene sentencias internas la estructuta for se le pone al final la terminación (;), ahora bien esta función lo que hace es un pausa muy arcaica es decir no es propiamente una pausa, si no un intervalo de ejecucion entre lo que termina de llegar i a 500 y la siguiente instrucción. Para usar una pausa formalmente necesitamos añadir una libreria adicional.

jueves, 18 de diciembre de 2008

Comencemos a Programar

El "hola mundo" de los PIC's

El programa llamado hola mundo es bien sabido por los programadores que es el comienzo para desarrollar mas cosas, no existe un compilador que no haga este programa, el nombre hace alusión a que empezamos a ver la luz con el compilador que se use, es decir, que esta vivo tanto el compilador como el cerebro del programador. XD

Bien el dispositivo que vamos a usar sera el 18F4520 con un oscilador de 20MHZ, la idea es hacer blink  en todo el puerto B.  Hay que seguir estos pasos:

  • Abrir MPLAB
  • Una vez cargado dirigirse a menu Project ---> Open..
  • Localizar nuestro proyecto, yo usare el del video anterior.
  • Abrir el menu Debugger---> Select Tool---> Mplab SIM
  • Abrir el menu Debugger---> Settings ---> Processor Frecuency poner 20MHz
  • Una vez cargado abrir el archivo main.c

Una vez dentro del archivo main.c comenzaremos a programar de acuerdo a nuestro esquema de programa anteriormente propuesto. Antes de comenzar echemos un vistazo a la hoja de datos del PIC18F4520 para localizar el puerto B y ver si posee funciones especiales:

Como podemos apreciar el PORTB se encuentra en los pines 33 a 40 del PIC (marcado con rojo), además de que cinco de sus pines poseen la característica de ser convertidores analógicos-digital (ADC, marcados en azul), por esta razón antes de usarlo debemos deshabilitar esos pines como ADC y ponerlos en modo de salidas digitales. Para esto revisamos dentro de la hoja de datos en la sección de 10-BIT ANALOG-TO-DIGITAL CONVERTER (A/D) MODULE  como es que trabajan sus registros.

Tenemos 3 registros asociados a los pines ADC, y estos son ADCON0 ADCON1 y ADCON2, vamos a ver como los debemos trabajar para poder usar los pines como salidas digitales.

 El registro ADCON0

 Este registro como se ve en la imagen anterior es de 8 bits de los cuales solo 6 bits se configuran, los bits 7 y 6 no se implementan y se leen como 0, los bits 2 a 5 configuran el canal AD con el que deseamos trabajar en este caso no queremos ninguno pero lo podemos dejar en Canal 0, el bit 1 indica si la conversión esta en progreso o ha finalizado si el canal AD esta activo, para este caso lo dejaremos a 0 ya que  no lo usaremos, por último el bit 0 configura si el AD estará activado o no, por lo que 0 indica que el modulo esta deshabilitado. De esta forma el registro ADCON0 tendrá el valor binario 0b00000000  por lo que podemos igualarlo en nuestro programa como:

 ADCON0=0;

El registro ADCON1

  Como vemos en la figura anterior el registro ADCON1 habilita las salidas como voltajes de referencia con los bits 4 y 5 los cuales podemos declarar como 0, los bits mientras que los bits 0 a 3 configuran las salidas digitales y AD según la tabla, como en este caso queremos que todas las salidas sean digitales usaremos el valor 1111 de la tabla, de esta manera el registro ADCON1 tendrá el valor  binario 0b00001111, por lo que en el programa lo podemos declarar como:

  ADCON1=15;

El registro ADCON2

 

Como se ve en la figura anterior, registro ADCON2 sirve para configurar el tipo de AD que usaremos, con el bit 7 definimos si sera de 10bits de resolución o de 8 bits, los bits 3 a 5 configuran el tiempo de adquisición y por ultimo los bits 0 a 2 configurar la conversión entre la frecuencia utilizada. Para este caso podemos declarar ADCON2 como 0b00000000.

  ADCON2=0;

Una vez hecho esto declaramos el puerto como salida y en estado inicial apagado.

Ahora insertaremos este código en el archivo main.c

Ahora solo falta compilar y para ello daremos click en el icono de build all (resaltado en rojo)

Y al final obtendremos  el siguiente texto  en la ventana de salida:

 

Como verán no recibimos ningún error y es hora de cargar el HEX en nuestro PIC, pero podemos simularlo primero:

Como se puede ver en el video anterior el puertoB del PIC cambia de estado entre 0 y 1 en todos sus bits. Así que el HOLA Mundo fue un éxito!

Estructuras de Control

Las estructuras de control son usadas para modificar el flujo del programa o para realizar ciertas acciones en condición de los estados de las diversas variables o del estado de los puertos del PIC. Existen dos tipos de estructuras de control:  de iteración  de selección.

Las estructuras de iteración sirven para repetir el flujo del programa mediante una condición y las más usadas son while, for y do..while, mientras que las estructuras de selección sirven para elegir la dirección del flujo de programa o el estado de una variable dependiendo de otro valor, las mas usadas son  if, if..else, select case.

Estructura WHILE

La traducción literal es mientras,  asi que podemos tomarla tal cual, mientras la condición se cumpla has...  Y su sintaxis es:

   while(condicion)

    {

      // sentencias

    }

Como se ve mientras la condición  sea verdad se ejecutarán las sentencias dentro de un WHILE. Por ejemplo:

    x=0;

   while(x<5)

   { x++;}

Como veran en principio x=0 y entrará en el while ya que es menor que 5 y se incrementará 1 a 1, cuando x>=6 el while dejará de ejecutar la sentencia de incremento y seguirá con la  instrucción debajo del while. Podemos implementar un loop infinito con el while haciendo:

 while(1);  o

 while(1)

 {

  // sentencias

 }

Esta sentencia sirve para detener el flujo de un programa.

Estructura FOR

La estructura for sirve para repetir las sentencias durante un lapso determinado, o para efectuar operaciones sucesivas. Su sintaxis es:

    for(variable inicial; variable final; paso de variable)

     {

        // sentencias

     }

Los argumentos variable inicial, variable final y paso de variable  son los que determinan el lapso a cumplir, por ejemplo:

   i=0;

  x=0;

  for ( i=0; i<=9; i++)

   { x++;}

 Como se puede ver la variable i es la que condiciona la iteración, comienza de 0 y su límite es 9 y su paso se incrementará 1 paso, es decir de uno en uno. Así pues, cuando i=0 x=0, i=1 x=1... i=9 x=9, cuando  llegue a 9 el programa seguirá con la  instrucción debajo del for. También se pueden hacer loops infinitos con un for de la siguiente manera:

  for (;;)

   {

     //sentencias

   }

 Estructura do..while

Esta estructura también se puede interpretar como su traducción: has..mientras. Es parecida a un while solo que la condición se evalua al final y no al principio como lo hace el while por lo que la condición puede estar dentro de este ciclo, su sintaxis es:

  do

 {

   // sentencias

  }while(condición);

Y un ejemplo puede ser:

  do

 { x++;}while(x==25);

La variable x se incrementa de uno en uno hasta que sea  igual a 25, despues continuara el programa con la siguiente instruccion debajo del do...while.

Estructura if

La traducción es: . Y  también la podemos tomar, if  es una estructura selectiva y evalúa una expresión, sí el resultado es verdadero efectuará las instrucciones que esten dentro de él. Su sintaxis es:

   if(expresión)

    {

     //sentencias

    }

Si el resultado de la expresión es falso el flujo del programa continuará con las sentencias debajo del if. Un ejemplo:

    x=6;

   if(x>6)

   { k++;}

Como se ve x tiene un valor y el  if  evalua su estatus, como el resulatdo es verdadero k incrementara su valor una sola vez y el flujo de programa continuará.

Estructura if..else

Esta estructura es idéntica al if,  solo que le añadimos la palabra reservada else,  que se traduce como: si no.  Por lo que es útil cuando una expresión es evaluada y su resultado es falso, podemos hacer otra cosa, su sintaxis es:

    if (expresión)

   {

      //sentencias

    }

   else

   {

     // sentencias

   }

De esta manera podemos mostrar el siguiente ejemplo:

    x=0;

    if( x ==5)

     {k++;}

  else

    {k--;}

Como la evaluación de x es falsa, k decrementará en uno su valor y continuará con el flujo del programa.

Estructura switch

Sirve para hacer selecciones multiples de acuerdo al valor de una expresión y es el equivalente al switch de ansi C. Su sintaxis es:

 swicth (valor)

 {   

  case 1: //sentencias

        break;

  case 2: //sentencias

     break;

 ....

  case n: //sentencias

   break;

  default: //sentencias

   break;

  }

 Como verán dependiendo de valor se selecciona el caso por ejemplo:

  x=3;

   switch (x){

    case 1: k= 20*2;

     break;

   case 2: k=20/2;

    break;

  case 3: k=20+2;

    break;}

Como x es igual a 3 el case efectuará la operación k=20+2, el uso de default  es opcional.

Todos los operadores de comparación y los lógicos pueden ser usados dentro de las sentencias de comparación y dentro del while y do while, para poder efectuar flujos mejor controlados.

Bifurcaciones

Son usadas para: parar, continuar o saltar el flujo normal de un programa,  para C18 se usan break, continue, goto.

 Break. Interrumpe la secuencia de un ciclo do..while, while y un for. No se debe confundir con el uso en select case.

 Continue. Es usado para pasar a la siguiente repetición dada una condición.

 Goto. Salta a una etiqueta de programa. Una Etiqueta es un nombre o identificador al cual le siguen los dos puntos(:) por ejemplo: 

 YO:

  if(k=0)

{ goto el}

 ....

 el:

  // sentencias

Como todo manual de C dire contra mi voluntad: el uso de goto  no es una buena práctica, ni se recomienda hacerlo en un programa.

Sintaxis del Programa Parte V

Operadores (continuación)

También podemos combinar los operadores aritméticos con el operador de asignación igual (=), lo que nos dará como resultado un operador mixto de asignación:

x = x + k;  // puede ser sustituido por

x += k;

Este tipo de asignación es valida para los operadores aritméticos,  la AND, XOR, OR inteligentes y rotar derecha y rotar izquierda. 

Operador Condicional

Este operador resulta muy útil en el lenguaje C y también en C18, sirve para evaluar una expresión, si su resultado es TRUE se le asigna el valor de la segunda expresión, si no se le asigna el valor de la tercera al resultado, es como una especie de IF mas compactado:

 resultado = expresión1 ? expresión2 : expresión3;

Un ejemplo si quisiéramos saber el estado de un LED, para imprimirlo posteriormente podemos usar el operador de condición:

 val = LED0_IO ? '1':'0';

De tal modo que val  tomara el valor ascii de 1 o 0 dependiendo del estado de LED0_IO, si LED0_IO esta encendido, es decir tiene un 1 lógico, la evaluación sera TRUE por tanto val tomara el valor de la expresión2 que en este caso es la representación ascii de 1, de lo contrario tomara la representación ascii de 0.

Operador de Preprocesado

El operador de preprocesado sirve para indicar algunas directivas al compilador, como usar macros, insertar archivos incluir cabeceras etc, este operador es el símbolo numeral mejor conocido como "gato" (#) y como habíamos visto anteriormente nos sirvió para insertar una librería con la sentencia #include.  Existen otras funciones del preprocesado que se verán posteriormente.

Ensamblador Empotrado

C18 también soporta el empotrado de lenguaje ensamblador y será compilado con MPASM, para insertar lineas con ensamblador se deberá hacer uso de _asm y _endasm.  Por ejemplo:

   _asm

     MOVLW 10
     MOVWF count, 0
       start:
     DECFSZ count, 1, 0
     GOTO done
     BRA start
     done:

 _endasm

miércoles, 17 de diciembre de 2008

Sintaxis del Programa Parte IV

Operadores

C18 trabaja con los operadores mas comunes para todos los compiladores como los: aritméticos, relacionales, lógicos, bitwise, de asignación condicionales y de preprocesado.

Operadores Relacionales

Son los mas comunes, son usados en comparaciones y regresan un valor TRUE o FALSE dependiendo del resultado:

Operadores Aritméticos

Son usados para efectuar las operaciones básicas de las matemáticas y regresan un valor numérico:

Operadores Lógicos

Son usados en comparaciones también, y regresan un valor TRUE o FALSE dependiendo de el resultado de la evaluación:

 

Operadores Inteligentes "bitwise"

Estos operadores son usados para modificar los BITS de una variable. C18 soporta los siguientes:

La AND inteligente (&) regresa 1 si ambos bits son 1 de otro modo regresa 0:

 x = 10;

 x = x & 2;  // x sera igual a 2 ya que:

         1010

   &  0010

    ----------- 

        0010

El OR (|) inteligente regresa 0 si ambos son cero de otro modo regresa 1:

 x = 7;

 x = x | 10; // x sera 15 ya que:

    0111

|   1010

 ----------

   1111

La XOR (^) inteligente regresara 1 si los bits son complementarios de otro modo regresa cero:

  x = 2;

  x = x ^ 10; // x sera 8 ya que:

    0010

 ^ 1010

 ----------

   1000

El complemento  (~) invierte los bits de la variable:

 x = 1;

 x = ~ x; // sera igual a 14 ya que:

  0001 ~  1110 

Rotar a la izquierda (<<) mueve los bits las posiciones indicadas despues del operador:

   x = 10;

   x = x <<>

              1010 

 <<  10 1000

Rotar a la Derecha (>>) mueve los bits las posiciones indicadas despues del operador:

 x = 10;

 x = x >> 3; // sera igual a 1 ya que:

             1010

      >>   0001 010

Sintaxis del Programa Parte III

Punteros

El uso de punteros en lenguaje C es muy común, en general los punteros sirven para mantener la dirección de una variable, los punteros son declarados de igual manera que las variables de programa solo que a estos les precede el símbolo asterisco (*), de tal manera que si queremos declarar un puntero de un entero sin signo tenemos:

  unsigned int *point; // este puntero sujetara la dirección de memoria de una variable entera sin signo.

Para asignar una dirección o un valor al puntero es necesario hacer uso del símbolo andperson (&) precediendo a la variable, por ejemplo:

 point = &k ; // El puntero point ahora posee la dirección de la variable k

Para asignar valores a k podemos usar el puntero:  *point = 200; con esta declaración la variable k tendrá como valor 10, lo que hubiese sido similar a declarar k = 200; también podemos pasar este valor a otras variables por ejemplo: i = *pointi ahora vale 200. Los arreglos también soportan el uso de punteros.

Estructuras

Las estructuras nos permiten llevar un control mas limpio en algunas variables, como por ejemplo las fechas, al  declarar una estructura el tamaño de bytes usados es equivalente al tamaño total de todos sus elementos y puede se obtenido dicho tamaño con la palabra reservda sizeof.

Para declarar una estructura de programa basta con usar la palabra reservada struct  seguida del nombre de la estructura, un ejemplo seria:

 struct time

{

   unsigned char year;

   unsigned char month;

   unsigned char day;

   undisgned char dweek;

   unsigned char hour;

   unsigned char mins;

}

 Ó también se puede nombrar la estructura al final por ejemplo:

struct 

{

   unsigned int year;

   unsigned char month;

   unsigned char day;

   undisgned char dweek;

   unsigned char hour;

   unsigned char mins;

time;

De igual forma que las variables podemos asignar valores a las variables individuales de la estructura, también podemos declarar las variables que hagan uso de la estructura por ejemplo:

  time fecha; // declaramos fecha como variable que contiene los elementos de la estructura

   ....

 fecha.year=2002;  // Asignamos valores a cada elemento

 fecha.mins=20;

Uniones

Las uniones son usadas para "traslapar" 2 variables y el espacio ocupado por las uniones esta dado por el tamaño de la variable mayor dentro de la unión, de esta manera si ser tiene un long y un entero dentro de la unión, el tamaño máximo es LONG. C18 soporta la unión de estructuras anónimas, es decir, una estructura sin nombre dentro de una unión.

Un ejemplo de una unión es el siguiente:

  union coord

   {

    unsigned int x;

    unsigned char y;

  }

De igual forma que las estructuras la unión puede ser nombrada al final:

  union 

  {

    unsigned int x;

    unsigned char y;

  }coord;

Para asignar una variable hacemos: coord k; . Un ejemplo que simplifica el uso de uniones es asignar un valor al elemento mayor de la unión por ejemplo:

   k.x = 0xAAFF;  // x valdra 0xAAFF, mientras que y por su tamaño sera 0xFF

 

lunes, 15 de diciembre de 2008

Sintaxis del Programa Parte II

Las Variables.

Existen diferentes tipos de Variables en C18, aunque la mayoría convive con las de ANSI C así que si estamos familiarizados con estas variables será más sencillo trabajar con C18. La siguiente tabla resume las variables que existen en C18:

Es importante saber que tipo de variable usaremos para consumir menos memoria del PIC. Entonces para declara una variable que solo toma valores entre 0 y 255 tendremos que declararla de la siguiente forma:

  unsigned char i;

Por ser equivalente en la mayoría al ANSI C, al declarar variables podemos hacer lo en una sola linea, incluso definiendo su valor inicial de algunas por ejemplo:

 unsigned char i, j , k=10;

Constantes.

Las constantes pueden ser definidas como globales o locales y se definen mediante el uso de la palabra reservada const precediendo al nombre de la variable, por ejemplo:

 const k=50;

Los valores de las variables y las constantes pueden ser definidos en los 3 sistemas numéricos que mencionamos anteriormente, decimal, binario y hexadecimal; para el sistema hexadecimal se debe usar el prefijo 0x  y para el sistema binario el prefijo 0b. Por lo que para declarar variables o constantes en C18 podemos hacerlo de la siguiente manera:

    unsigned char i;

           i = 0;

                   ......

           i = 0xFF

                  .......

          i = 0b00001010;

 

Arreglos de Variable.

Los arreglos sirven para crear vectores o matrices dentro de una variable, es decir, asignar índices individuales y cada uno de ellos puede tomar diferentes valores. Por ejemplo:

  unsigned char vec[4];

Creara una variable llamada vec  la cual contendrá cuatro índices de tamaño char dentro de ella, es decir podemos acceder a los índices de vec de la siguiente forma:

 vec[0]=1;

 vec[1]=0; 

 vec[2]=0;

 vec[3]=5;

O podemos definir los valores desde la declaración:

  unsigned char vec[4]={1,0,0,5};

Modificadores de las Variables.

Los modificadores son palabras que preceden la declaración de nuestras variables y sirven para especificar al compilador que tipo de flujo pueden llevar estas variables.

 Modificador Enum

Sirve para enumerar un arreglo de variable, por ejemplo:

 enum dweek{lun, mar, mier,jue,vie, sab,dom}

La variable los valores dentro de dweek toman un índice para este caso lun=0 mar=1 ... dom=6. También se pueden modificar los índices que tomaran por ejemplo:

 enum dweek{lun, mar, mier,jue=7,vie, sab,dom}

Para el ejemplo anterior lun=0, mar=1 mier=2, jue=7 vie=8 sab=9 dom=10

 Modificador Static

El modificador static  es usado para variables locales generalmente de funciones, y sirve para preservar el valor de la variable aun cunado hayan existido llamadas sucesivas a la función. Por ejemplo:

 static unsigned char  k;

 Modificador Extern

Cuando hacemos uso de la palabra reservada extern el compilador toma a estas variables como externas, es decir que pueden haber sido declaradas en cualquier parte del código de un modulo externo al código local. 

 extern data;

Con la sentencia anterior decimos que extern no esta definida en nuestro programa.

 Modificador Volatile

El uso del modificador Volatile es muy comun en rutinas ISR, ya que independientemente del flujo de programa la variable puede cambiar su valor repentinamente. En la siguiente sentecnia la variable IO es declarada como volatil.

 volatile char IO;

Sintaxis del Programa parte I

Como en todos los compiladores cada uno tiene sus sintaxis en cuanto a definición de sentencias, variables instrucciones etc. En los siguientes temas vamos a tratar a grosso modo  la sintaxis de C18.

Comentarios

Los comentarios son parte importante de un programa ya que nos ayudan a interpretar funciones o describen parte del proyecto. En C18 podemos definir una linea simple de comentario usando doble diagonal por ejemplo:

  // esto es un comentario y no necesita ser terminado

O también podemos definir un bloque de comentarios haciendo uso de diagonal-asterisco y necesita ser terminado con asterisco-diagonal. Por ejemplo:

  /* /////////////////////////////////////////////////

 //   TODO ESTO ES UN BLOQUE DE COMENTARIOS  //

 //////////////////////////////////////////////////*/

Cuando se usan los bloques de comentarios es necesario cerrarlos, ya que todo el código debajo de este bloque sin cerrar sera comentado.

Espacios en Blanco.

Los Espacios en blanco son usados para darle sentido y forma a nuestros programas y no afectan al desarrollo del mismo. Por ejemplo las siguientes sentencias son interpretadas de la misma manera por el compilador:

  int i; char j;

  int i;

 char j;

Terminación de las sentencias:

Para terminar una sentencia o declaración es necesario hacer uso del punto y coma (;), ya que si no se usa el compilador marcara un error en la sintaxis, así pues después de cualquier operación, llamada a función o declaración se debe poner punto y coma. Por ejemplo:

 int i; // declaramos una variable y terminamos la declaración

 i=0; // Asignamos un valor a i y terminamos la declaración

 i++; // incrementamos i y terminamos la sentencia

Terminación de Funciones:

Cuando se declara una función propia o procedimiento de programa es necesario iniciarlo y terminarlo para ello se hace uso de los corchetes ({}). Por ejemplo:

   void myfuncion(int a)

   

      a = a+2;

   }

   void main(void)

   {

     for (i=0; i<=4; i++)

     {

       c++;

     

        //sentencias 

  }

Nótese que esta regla aplica para main  también, es necesario llevar siempre  el par de corchetes para evitar errores de sintaxis.

Case Sensitive.

Desafortunadamente o afortunadamente (depende el enfoque) C18 es case sensitiveEsta frase significa que diferencia entre mayúsculas y minúsculas por lo que no es lo mismo escribir FOR, For, fOR, fOr o FoRademás que esta regla es extensiva para sentencias, variables y funciones.

De esta manera podemos declarar variables con el mismo nombre pero el compilador podría reconocerlas de manera diferente: int maria; char Maria; unsigned char mAria;