curso ccs en pdf

Upload: william-navas

Post on 08-Apr-2018

240 views

Category:

Documents


1 download

TRANSCRIPT

  • 8/7/2019 Curso Ccs en PDF

    1/69

    CCS - Comentarios

    Los comentarios son tiles para informar al que lee nuestro cdigo (o a

    nosotros mismos)el significado o funcionamiento de cada parte del programa.

    Todos los comentarios son ignorados por el compilador, por lo que no debes

    preocuparte por llenar la memoria del PIC.

    Un comentario puede ser colocado en cualquier parte del programa, excepto en

    medio de una palabra reservada, del nombre de una funcin o del nombre de

    una variable.

    Los comentarios pueden ocupar ms de una lnea de largo. Pueden utilizarsepara deshabilitar momentneamente un trozo de cdigo.

    Hay dos formas de introducir un comentario. La primera es la misma que en

    cualquier otro compilador de C:

    /* Esto es un comentario */

    Es decir, todo lo que haya escrito entre /* y */ ser tomado por el compilador

    como un comentario.

    La segunda manera es la siguiente:

    // Esto es un comentario

    En este caso, el comentario comienza en // y se extiende hasta el final de la

    lnea.

    CCS - Variables

    La programacin seria prcticamente imposible sin el uso de variables.

    Podemos hacernos una imagen mental de las variables consistente en una caja

    en la que podemos guardar algo. Esa caja es una de las muchas que

    disponemos, y tiene en su frente pegada una etiqueta con su nombre. Estas

    cajas tienen ciertas particularidades, que hace que solo se puedan guardar en

    ellas determinados tipos de objetos.

  • 8/7/2019 Curso Ccs en PDF

    2/69

    En esta analoga, cada caja es una variable, su contenido es el valor que

    adopta, y la etiqueta es el nombre de la variable. Como su nombre lo indica, y

    como veremos mas adelante, el contenido de una variable puede ser

    modificado a lo largo del programa.

    Tipos

    El lenguaje C proporciona cinco tipos bsico de datos, con cuatromodificadores posibles. Podemos utilizar variables de cualquiera de esos tipos.La tabla siguiente muestra los tipos disponibles:

    Tipo Ancho (Bits) Rango

    short 1 0 o 1

    short int 1 0 o 1

    int 8 0 a 255

    char 8 0 a 255

    unsigned 8 0 a 255

    unsigned int 8 0 a 255

    signed 8 -128 a 127

    signed int 8 -128 a 127

    long 16 0 a 65536

    long int 16 0 a 65536

    signed long 16 -32768 a 32767

    float 32 3.4E-38 a 3.4E+38

  • 8/7/2019 Curso Ccs en PDF

    3/69

    Si miras con atencin la tabla anterior, puedes ver que hay tipos que parecen

    estar repetidos. En realidad, ocurre que CCS permite una "forma corta" para

    escribir algunos de los tipos. Concretamente, podemos utilizar unsigned, short,

    o longen lugar de unsigned int, short int, o long int.

    Declaracin

    Las variables deben ser declaradas antes de ser utilizadas en el programa. El

    proceso de declaracin de variables le dice a CCS de que tipo son y como se

    llaman. Al igual las dems instrucciones CCS que veremos a lo largo de este

    tutorial, debe terminar con ;.

    La forma en que se declara una variable es la siguiente:

    tipo nombre_de_la_variable;

    Donde tipo es alguno de los enumerados en la tabla anterior. Veamos un

    ejemplo:

    int temperatura;

    Esa lnea permite a nuestro programa emplear la variable temperatura, que

    ser capaz de albergar cualquier valor comprendido entre 0 y 255.

    Asignacin de valores

    Asignar un valor a una variable es una tarea bien simple. Basta con hacer lo

    siguiente:

    nombre_de_variable = valor;

    donde nombre_de_variable es el nombre de la variable que contendr el

    valor. Al igual que todas las instrucciones de CCS, debe terminar con un ;

    (punto y coma).

  • 8/7/2019 Curso Ccs en PDF

    4/69

    Por ejemplo, supongamos que queremos asignar el valor "100" a la variable

    "count". Lo hacemos de la siguiente manera:

    count = 100;

    donde 100 es una constante.

    Podemos asignar un valor a una variable en el momento en que la declaramos.

    lo siguientes son algunos ejemplos de esto:

    int a = 0;

    Hace que la variable a sea del tipo entero, y le asigna el valor 0.

    signed long a = 125, b, c = -10;

    a,b y c son declaradas como long. a toma el valor de "125" y c "-10".

    Si la variable es de tipo char, la constante que se le asigna debe estar entre

    tildes, como en el siguiente ejemplo:

    char nombre = 'juan perez';

    Por ultimo, tambien podemo asignar a una variable el contenido de otra. En el

    siguiente ejemplo, el valor de i sera igual a 10.

    int i = 10;

    int j;

    j = 1;

    Variables Locales y Globales

    Si una variable se declara dentro de una funcin, ser "visible" solo dentro de

    sta:

  • 8/7/2019 Curso Ccs en PDF

    5/69

    funcion1 () {

    char letra;

    .

    .

    .

    . }

    En el ejemplo anterior, la variable tipo char llamada letra solo podr utilizarse

    dentro de la funcin funcion1 (). Si intentamos utilizarla fuera de ella, el

    compilador nos dar un error.

    Si declaramos una variable fuera de cualquier funcin, el alcance de esta sera

    global, lo que quiere decir que estar disponible en cualquier parte de nuestroprograma. Vemos un ejemplo de este ltimo caso.

    char letra;

    main() {

    .

    .

    .

    .}

    funcion1 () {

    .

    .

    .}

    La variable tipo char llamada letra podr utilizarse dentro de main() o de

    funcion1().

    Conversiones entre tipos

    CCS nos permite mezclar diferentes tipos de variables dentro de una misma

    expresin. Y existen un conjunto de reglas que nos permiten saber que de que

    tipo ser el resultado de la misma.

    Por ejemplo, el compilador convertir automticamente a int cualquier

    expresin que contenga variables char, short o int. Esta conversin solo tiene

    efecto mientras se realizan los clculos. Las variables en s mismas nocambian su tipo.

  • 8/7/2019 Curso Ccs en PDF

    6/69

    Las reglas de conversin de tipos hacen que el resultado de una operacin sea

    siempre el mismo que el de la variable ms larga que intervenga en ella.

    Sin embargo, podemos forzar a que el resultado sea de un tipo en particular, de

    la siguiente forma:

    (tipo) valor

    donde tipo es el tipo al que queremos que pertenezca valor. El siguiente

    ejemplo nos aclarar todo esto:

    int a = 250, b = 10;

    long c;

    c = a * b;

    Tal como explicamos, c no contendrel valor 2500 como podra parecer a

    simple vista, por que el tipo decno se modifica. CCS calculaa * b'y

    obtiene efectivamente el resultado 2500, pero c slo contendr los 8 bits

    menos significativos de ese resultado, es decir, el decimal 196.

    Si hubisemos hecho: int a = 250, b = 10;

    long c;

    c = (long) (a * b);

    el valor almacenado en c hubiese sido efectivamente 2500.

    CCS - Directivas para el compilador

    Llamadas en ingls "preprocessor directives", son comandos que interpreta el

    primer paso de la compilacin que lleva a cabo CCS.

    Las directivas ms comunes son #define e #include, pero deberas dar un

    vistazo a todas.

    #ASM / #ENDASM

  • 8/7/2019 Curso Ccs en PDF

    7/69

    Este par de instrucciones permite que utilicemos un bloque de instrucciones en

    assembler dentro de nuestro cdigo CCS. El siguiente es un ejemplo de uso

    tomado de la ayuda del CCS:

    int find_parity (int data) {

    int count;

    #ASM

    movlw 0x8

    movwf count

    movlw 0

    loop:

    xorwf data,w

    rrf data,f

    decfsz count,f

    goto loop

    movlw 1

    awdwf count,f

    movwf _return_

    #ENDASM}

    La variable predefinida _RETURN_ puede utilizarse para transferir un valor

    desde el cdigo ASM a CCS.

    Si en lugar de #ASM utilizamos #ASM ASIS, CCS no intentar efectuar

    cambios de bancos de memoria automticos para las variables que no pueden

    ser accedidas desde el banco actual. El cdigo assembler es utilizado "as-is"

    ("como es").

    #BIT

    Permite crear una nueva variable de un bit de tamao, que es colocada en la

    memoria del PIC en la posicin del byte x y el bit y. Esto es muy til para

    acceder de una manera sencilla a los registros. Por supuesto, estas variables

  • 8/7/2019 Curso Ccs en PDF

    8/69

    pueden ser empleadas de la misma manera que cualquier otra variable tipo

    short. El formato de #BIT es el siguiente:

    #BIT nombre = x.y

    Donde nombre es un nombre de variable CCS vlido, x es una constante o

    una variable CCS vlida e y es una constante de 0 a 7.

    Estos son algunos ejemplos de uso:

    #BIT T0IF = 0xb.2

    .

    ..T0IF = 0; // Limpia el flag de interrupcin del Timer 0

    int resultado;

    #BIT resultado_primer_bit = resultado.0

    .

    .

    .if (resultado_primer_bit)

    #BYTE

    Permite crear una nueva variable de un Byte de tamao, que es colocada en la

    memoria del PIC en la posicin del byte x. Esta es una herramienta muy til

    para acceder de una manera sencilla a los registros. Por supuesto, estas

    variables pueden ser empleadas de la misma manera que cualquier otra

    variable tipo int. El formato de #BYTE es el siguiente:

    #BYTE nombre = x

    Donde nombre es un nombre de variable CCS vlido, y x es una constante o

    una variable CCS vlida.

    Estos son algunos ejemplos de uso:

    #BYTE STATUS = 3

    #BYTE PORTB = 6

  • 8/7/2019 Curso Ccs en PDF

    9/69

    #DEFINE

    La instruccin #define tiene la siguiente forma:

    #DEFINE value

    es la etiqueta que usaremos en nuestro programa. Y value es el valor

    que estamos asignando a esta etiqueta. Las instrucciones #DEFINE no

    generan cdigo ASM, si no que el preprocesador realiza los reemplazos que

    ellas indican en el momento de la compilacin. El uso de #DEFINE permite

    construir programas ms ordenados y fciles de mantener.

    Veamos algunos ejemplos de #DEFINE

    #DEFINE TRUE 1

    Cada vez que en nuestro programa aparezca la etiqueta TRUE, el

    precompilador la reemplazar por 1

    #DEFINE pi 3.14159265359

    Cada vez que en nuestro programa aparezca la etiqueta pi, el precompilador la

    reemplazar por 3.14159265359

    #DEFINE MENOR_DE_EDAD (EDAD < 18)

    .

    .

    .

    .

    .if MENOR_DE_EDAD

    printf(JOVEN);

    El ejemplo anterior permite una mayor claridad en el programa. Por supuesto,

    no hay que abusar de #DEFINE, por que podemos obtener el efecto contrario,

    haciendo nuestros programas bastante difciles de comprender.

  • 8/7/2019 Curso Ccs en PDF

    10/69

    #DEFINE es una potente herramienta para la creacin de macroinstrucciones,

    ya que soporta el uso de variables. Veamos algunos ejemplos de esto:

    #DEFINE var(x,v) unsigned int x=v;

    var(a,1)

    var(b,2)

    var(c,3)

    Cuando el preprocesador se encuentra con el cdigo anterior, hace lo mismo

    que si hubisemos escrito lo siguiente:

    unsigned int a=1;

    unsigned int b=2;

    unsigned int c=3;

    Como puedes ver, #DEFINE puede hacer mucho por tus programas.

    #DEVICE

    Esta directiva informa al compilador que arquitectura de hardware utilizaremos,

    para que pueda generar cdigo apropiado para la cantidad de RAM, ROM y

    juego de instrucciones disponibles. Para los chips con ms de 256 bytes de

    RAM se puede seleccionar entre emplear punteros de 8 o 16 bits. Si deseamos

    emplear punteros de 16 bits basta con aadir *=16 a continuacin del nombre

    microcontrolador seleccionado.

    Veamos algunos ejemplos:

    #DEVICE PIC16C74 //PIC 16C74, punteros de 8 bits.

    #DEVICE PIC16C67 *=16 //PIC 16C67, punteros de 16 bits.

    Hay ms opciones que podemos agregar en las lneas #DEVICE:

    ADC=x : Determina el nmero de [bit]]s que devuelve la funcin

    read_adc().

  • 8/7/2019 Curso Ccs en PDF

    11/69

    #DEVICE PIC16F877 *=16 ADC=10 //PIC 1616F877, punteros de 16 bits y 10

    bits en el ADC.

    ICD=TRUE : Genera cdigo compatible con el ICD de

    [www.microchip.com Microchips]].

    #DEVICE PIC16F877 ICD=TRUE//PIC 1616F877, punteros de 8 bits y cdigo

    para ICD.

    WRITE_EEPROM=ASYNC :

    HIGH_INTS=TRUE : Define la prioridad de las interrupciones en los

    PIC18.

    #FUSE

    Permite modificar el valor de los fusesdel microcontrolador que estamos

    empleando. Los valores posibles dependen de cada microcontrolador en

    particular, y los valores posibles se cargan al utilizar #INCLUDE seguido del

    archivo correspondiente. La forma de #FUSE es la siguiente:

    #FUSE opciones

    Donde opciones es una lista de las opciones posibles separadas mediante

    comas. Antes de seguir, recuerda que puedes ver dentro del archivo con

    extensin .h correspondiente cuales son los valores posibles para ese

    microcontrolador. Estn al comienzo del archivo, en forma de comentarios.

    Algunos valores comunes son

    Tipo de oscilador: LP, XT, HS, RC

    Wach Dog Timer: WDT, NOWDT

    Proteccin de cdigo: PROTECT, NOPROTECT

    Power Up Timer: PUT, NOPUT

    Brown Out Reset: BROWNOUT, NOBROWNOUT

    #INCLUDE

  • 8/7/2019 Curso Ccs en PDF

    12/69

    Permite incluir en nuestro programa uno o mas archivos (conocidos como

    header file) que posean extensin .h. Estos archivos contienen informacin

    sobre funciones, sus argumentos, el nombre de los pines de un modelo

    determinado de PIC o cualquier otra cosa que usemos habitualmente en

    nuestros programas. Esto permite no tener que escribir un montn de cosas

    cada vez que comenzamos un programa nuevo: basta con incluir el .h

    correspondiente.

    La forma de utilizar esta instruccin es la siguiente:

    #INCLUDE

    Esto har que el contenido de se compile junto con nuestro

    programa. Por ejemplo:

    #INCLUDE

    hace que todas las especificaciones de nombres y registros del PIC16F877A se

    incluyan en nuestro programa. Esto permitir referirnos al pin 0 del PORTB del

    PIC mediante PIN_B0.

    Existe la posibilidad de utilizar #INCLUDE "archivo" en lugar de #INCLUDE

    . La diferencia es que si usamos "", el archivo se buscar primero

    en el directorio actual. Si empleamos , el archivo ser buscado primero en la

    ruta por defecto para los archivos .h.

    #INT_xxx

    #INT_xxx indica que la funcin que le sigue (en el cdigo fuente CCS) es una

    funcin de interrupcin. Estas funciones no deben tener parmetros. Por

    supuesto, no todos los PICs soportan todas las directivas disponibles:

    1. INT_AD Conversin A/D finalizada.

    2. I NT_ADOF Conversin A/D timeout.

    3. INT_BUSCOL Colisin en bus.

    4. INT_BUTTON Pushbutton.

    5. INT_CCP1 Unidad CCP1.

  • 8/7/2019 Curso Ccs en PDF

    13/69

    6. INT_CCP2 Unidad CCP2.

    7. INT_COMP Comparador.

    8. INT_EEPROM Escritura finalizada.

    9. INT_EXT Interrupcin externa.

    10.INT_EXT1 Interrupcin externa #1.

    11.INT_EXT2 Interrupcin externa #2.

    12.INT_I2C Interrupcin por I2C.

    13.INT_LCD Actividad en el LCD.

    14.INT_LOWVOLT Bajo voltaje detectado.

    15.INT_PSP Ingreso de datos en el Parallel Slave Port.

    16.INT_RB Cambios en el port B (B4-B7).

    17.INT_RC Cambios en el port C (C4-C7).

    18.INT_RDA Datos disponibles en RS-232.

    19.INT_RTCC Desbordamiento del Timer 0 (RTCC).

    20.INT_SSP Actividad en SPI o I2C.

    21.INT_TBE Buffer de transmisin RS-232 vaco.

    22.INT_TIMER0 Desbordamiento del Timer 0 (RTCC).

    23.INT_TIMER1 Desbordamiento del Timer 1.

    24.INT_TIMER2 Desbordamiento del Timer 2.

    25.INT_TIMER3 Desbordamiento del Timer 3.

    Ejemplo:

    #int_ad

    adc_handler () {

    adc_active=FALSE;

    }

    #int_rtcc noclear //"noclear" evita que se borre el flag correspondiente.

    isr () {

    ...

    }

  • 8/7/2019 Curso Ccs en PDF

    14/69

    CCS - Operadores

    En CCS los operadores cumplen un rol importante. Quizs C sea uno de los

    lenguajes que ms operadores tiene. Una expresin es una combinacin de

    operadores y operandos. En la mayora de los casos, los operadores de CCS

    siguen las mismas reglas que en lgebra, y se llaman de la misma manera.

    Operadores aritmticos

    CCS posee cinco operadores aritmticos:

    + (suma)

    - (substraccin) * (multiplicacin) / (divisin) % (mdulo)

    Los primeros cuatro operadores mencionados se pueden utilizar con cualquiertipo de dato. Estos son algunos ejemplos de como usarlos:

    a = b + c;a = b - c;a = b * c;

    a = b / c;a = -a; //Cambia el signo de "a".a = a + 1; //suma 1 al valor de "a".

    El operador % (mdulo) solo puede emplearse con enteros. Devuelve el restode una divisin de enteros. Veamos un par de ejemplos:

    int a = 10, b = 5, c;c = a % b; //"c" valdr cero.int a = 20, b = 3, c;c = a % b; //"c" valdr 2.

    Atajos

    CCS tambin provee atajos para utilizar los operadores aritmticos. Hayalgunas operaciones que se repiten a menudo cuando creamos nuestrosprogramas, y estos atajos ayudan a que podamos escribir nuestro cdigo msrpidamente. Los atajos provistos son los siguientes.

    a *= b es lo mismo que a = a * b

    a /= b es lo mismo que a = a / b a += b es lo mismo que a = a + b

  • 8/7/2019 Curso Ccs en PDF

    15/69

    a -= b es lo mismo que a = a - b a %= b es lo mismo que a = a * b

    Operadores Relacionales

    Los operadores relacionales comparan dos valores, y devuelven un valor lgicobasado en el resultado de la comparacin. Los operadores relacionalesdisponibles son los siguientes:

    > mayor que >= mayor que o igual a < menor que

  • 8/7/2019 Curso Ccs en PDF

    16/69

    > (desplazamiento a la derecha)

    Estas operaciones se llevan a cabo bit por bit. Veamos un ejemplo:

    Supongamos que a = 120 y b = 13.

    a & b = 8 a | b = 125 a ^ b = 117 ~ a = 135

    El porqu de estos resultados puede comprenderse mejor si se pasan losvalores de a y b a binario:

    a = 11111000

    b = 00001101

    luego

    01111000 AND 00001101 = 0000100001111000 OR 00001101 = 0111110101111000 XOR 00001101 = 01110101NOT 01111000 = 10000111

    Los operadores de desplazamiento "corren" el contenido de la variable a laderecha o a la izquierda, rellenando con ceros. Veamos algunos ejemplos:

    a = a >> 2 //"corre" el contenido de a dos lugares a la derecha

    Si a era igual a 120 ( 01111000 en binario) pasar a valer 30 (00011110 enbinario).

    a = a b a &= b es lo mismo que a = a & b a |= b es lo mismo que a = a | b

  • 8/7/2019 Curso Ccs en PDF

    17/69

    a ^= b es lo mismo que a = a ^ b

    Otros operadores

    Quedan por ver aun dos operadores ms:

    ++ Operador incremento -- Operador decremento

    Estos operadores permiten sumar (o restar) uno al valor de una variable. Loque generalmente haramos as:

    a = a + 1

    0 as:

    a = a - 1

    lo podemos hacer as:

    a++

    o as:

    a--

    el resultado sera el mismo, pero es mas corto de escribir, y mas fcil de utilizaren expresiones complejas.

    Precedencia de los operadores

    Al igual que ocurre en lgebra, en CCS los operadores se evalan en un ordendeterminado. La siguiente lista muestra este orden, ordenado de mayor amenor:

    ()

    signo +, signo -, ++, --, !, () *, /, % +, - = ==, != &&, || =, +=, -=, *=, /=, %=

  • 8/7/2019 Curso Ccs en PDF

    18/69

    CCS - Punteros

    Una de las caractersticas ms interesantes de las diferentes versiones de C

    son los punteros. Por supuesto, CCS permite el manejo de punteros, con lo

    que nuestros programas pueden aprovechar toda la potencia de esta

    herramienta.

    El presente artculo fue escrito por Pedro (PalitroqueZ), un amigo de uControl.

    Su direccin de correo electrnico es [email protected].

    Qu es un puntero?

    Un puntero es una variable cuya finalidad es almacenar nmeros ENTEROS

    POSITIVOS. Estos nmeros no son nmeros al azar, son direcciones de la

    memoria que posee el hardware del microcontrolador (memoria de programa o

    RAM).

    Para que pueden servir los punteros?

    Esta es la pregunta que puede alborotar a mas de un programador de C. Sirve

    para muchsimas cosas:

    Acceso a la memoria RAM del PIC.

    Ahorrar memoria RAM.

    Modificar ms de una variable dentro de una funcin (y por consiguiente

    devolver mas de un valor)

    En arreglos y cadenas strings (arrays, matrices) juega un papel

    importantsimo.

    Permite crear tablas con montones de datos (en los PIC que soporten

    acceso a la memoria de programa).

    En un ordenador se ampla el abanico de opciones.

    Ms abajo veremos detalladamente como hacer todo esto.

  • 8/7/2019 Curso Ccs en PDF

    19/69

    Como funcionan los punteros?

    Para entender el uso de estas variables especiales hay que comprender bien

    un concepto:

    Cuando se crea una variable en CCS (llamado registro en ensamblador), el

    compilador reserva un espacio de memoria cuyo tamao varia de acuerdo al

    tipo de dato.

    Como todo en el mundo electrnico/digital, est basado en 2 cosas:

    El registro: es la casilla donde se almacena el dato.

    La direccin del registro: es la posicin en la memoria donde est

    alojado el registro.

    as pues tenemos 2 elementos diferentes pero que se relacionan.

    Conociendo la direccin del registro o variable y pudindolo manejar nos da un

    poderosa herramienta para agilizar/simplificar nuestros programas.

    Como podemos acceder a la direccin de una variable?

    En CCS se hace a travs del operador &. Veamos un ejemplo:

    Ejemplo1:

    #include

    #use delay (clock=4000000)

    void main(){int t,k;

    t=5;

    k= &t;

    delay_cycles (1);

    }

    al simular en el MPLAB tenemos:

  • 8/7/2019 Curso Ccs en PDF

    20/69

    Cuando detenemos en delay_cycles(1) vemos que en k se guarda la direccin

    de la variable t, y que guarda t? guarda el nmero 5. todo se realiza usando

    memoria RAM el registro de propsito general GPR.

    Vamos a cambiar ligeramente el cdigo. Usemos 3 variables tipo entero (int):

    #include

    #use delay (clock=4000000)

    void main(){

    int k,l,m;

    int t,u,v;t=0xfa; u=0xfb; v=0xfc;

    k= &t; l= &u; m= &v;

    delay_cycles(1);

    }

    Se repite lo mismo, el resultado de las direcciones en k, l y m son contiguas.

    Pero... por que?

  • 8/7/2019 Curso Ccs en PDF

    21/69

    Para responder esta pregunta vamos a cambiar el cdigo otra vez, declarando

    los 3 tipos de registros conocidos, int, long y float:

    #include

    #use delay (clock=4000000)

    void main(){

    int k,l,m,n;

    int t;

    long u;

    float v;

    int z;

    t=0xfa; z=0xff; u=0xfffa; v=3.45000000;

    k= &t; l= &u; m= &v; n=&z;

    delay_cycles(1);

    }

    la simulacin:

    Observa que las direcciones de t, u y v saltan. Por que?

    Dependiendo del tipo de dato se consume >= 1 byte de memoria. En el caso de

    t es un entero, y los enteros ocupan 1 byte (0..255). u es un dato "entero

    largo", ocupa dos bytes (0..65535) v es un dato "coma flotante", con parte

    fraccionaria en el sistema decimal y toma 4 bytes de memoria (32 bits)

    en t tenemos una direccin que ocupa un byte [0xA]

    en u tenemos una direccin que ocupa 2 byte [0xB - 0xC]

    en v tenemos una direccin que ocupa 4 bytes [0xD - 0x10]

  • 8/7/2019 Curso Ccs en PDF

    22/69

    Probando punteros, primera parte

    Siempre que se declare una variable puntero, al momento de usarlo se debe

    especificar la direccin de apuntamiento de la variable normal, porque entonces

    no se puede guardar un dato sino sabemos donde lo vamos a guardar. (Es

    obvio pero es cierto)

    Esto quiere decir que se le debe pasar el nmero por valorde la direccin de la

    variable normal. Recordemos que:

    Pasar un dato por valor: se copia el dato de una variable a otra.

    Pasar un dato por referencia: se mueve/modifica el dato en la misma

    variable.

    Variable normal: la variable que normalmente usamos.

    Variable puntero: es la variable especial que estamos estudiando.

    Veamos un ejemplo sencillo usando punteros:

    #include

    #use delay (clock=4000000)

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

    void main (){

    int k; // variable normal

    int *p; // la variable puntero

    k=0xfa; // k

  • 8/7/2019 Curso Ccs en PDF

    23/69

    pero... no aparece nada enp!Por que?

    Es simple: porque no fijamos una direccin que apuntara p, y esto es muy

    importante saberlo, era lo que se deca al inicio de este artculo. Vamos a darle

    la direccin de k:

    #include

    #use delay(clock=4000000)

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

    void main(){

    int k; // variable normal

    int *p; // la variable puntero

    p=&k; // direccin de k copiada a p

    k=0xfa; // k

  • 8/7/2019 Curso Ccs en PDF

    24/69

    Y con esta lnea:

    *p=0x5; // k

  • 8/7/2019 Curso Ccs en PDF

    25/69

    j=0x11;

    k=0x22;

    //

    *p=0x5; // i i ocupa 1 byte.

    Entre p, j hay 2 bytes -> puntero p ocupa 2 bytes.

    Entre j, q hay 1 byte -> j ocupa 1 byte

    Entre q, k hay 2 bytes -> puntero q ocupa 2 bytes.

    Modificando el cdigo para que i sea del tipo float:

    #include

    #use delay(clock=4000000)

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

    void main(){

    float i; // variable normal

    float *p; // la variable puntero //

    long j;

    long *q;

    int k;

    //

    i=2.51; // i

  • 8/7/2019 Curso Ccs en PDF

    26/69

    p=&i; // direccin de i copiada a p

    q=&j; //

    *p=3.99; // i i ocupa 4 bytes.

    Entre p, j hay 2 bytes -> puntero p ocupa 2 bytes.

    Entre j, q hay 2 bytes -> j ocupa 2 bytes.

    Entre q, k hay 2 bytes -> puntero q ocupa 2 bytes.

    En ambos casos a pesar que cambiamos el tipo de declaracin de los

    punteros, se mantienen en 2 bytes, eso quiere decir que para el compilador el

    tamao de un puntero es de 2 bytes. No confundir con el tipo de datos a

    direccionar, pues eso es otra cosa.

    Vamos con otro ejemplo. Supongamos que i sea del tipo float (4 bytes) pero su

    apuntador lo declaramos como int (1 byte):

    #include

    #use delay(clock=4000000)

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

    void main(){

    float i; // variable normal

    int *p; // la variable puntero

    long j;long *q;

  • 8/7/2019 Curso Ccs en PDF

    27/69

    int k;

    //

    i=2.51; // i

  • 8/7/2019 Curso Ccs en PDF

    28/69

    float *p; // la variable puntero

    long j;

    long *q;

    int k;

    //

    i=2.51; // i

  • 8/7/2019 Curso Ccs en PDF

    29/69

    con 4 modos de seleccin: CCS2,CCS3,CCS4 y ANSI. Con CCS2 y CCS3 el

    tamao (size) del puntero es de 1 byte en partes de 14, 16 bits y con CCS4

    (modo por defecto) el size es de 2 bytes.

    Probando punteros, segunda parte

    Analizando nuevamente lo hablado referente al size de los punteros en CCS, y

    en un intento de explicar que el tipo de dato y el tamao del apuntado son 2

    cosas distintas, vamos hacer un ejemplo donde se ver claramente. Para ello

    vamos a usar una directiva llamada #locate, sobre la que la ayuda del

    compilador reza as:

    #LOCATE works like #BYTE however in addition it prevents C from using the

    rea

    bueno esto quiere decir que la variable normal la puedo alojar en cualquier

    direccin de la RAM (dentro de ciertos limites). Algo as como si en

    ensamblador pusiramos:

    variable_normal EQU 0xNNNN

    Esto nos servir porque sera como manipular el contenido de un puntero pero

    en tiempo de diseo

  • 8/7/2019 Curso Ccs en PDF

    30/69

    #include

    #use delay(clock=4000000)

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

    int dato=0xaa; // declaramos dato (GPR) y lo cargamos con 0xAA

    #locate dato = 0xff

    // le decimos al compilador que dato estar en la direccin 0xFF

    //del rea de registro de propsito general, traducido, en la RAM del PIC

    void main(){

    int *p; // declaramos un puntero como entero (igual que dato)

    int t; // otra variable normal

    p=&dato; // inicializamos al puntero

    *p=0xbb; // dato

  • 8/7/2019 Curso Ccs en PDF

    31/69

    Fjense que el puntero p ocupa 2 bytes a pesar que est declarado como int (1

    byte).

    Vamos a modificar este ejemplo pero usando float (4 bytes) y colocando el

    GPR en la direccin 0xAF

  • 8/7/2019 Curso Ccs en PDF

    32/69

    Observen que el puntero p se mantuvo en 2 bytes siendo ste declarado como

    float.

    Supongamos un ejemplo para el PIC18F4550, en el que tenemos una memoria

    de datos que llega hasta 0x7FF (Pg. 66 de su hoja de datos). Para que

    funcione 0x7FF debe ser el 4 byte para un float, entonces

    float dato=1.23456789;

    #locate dato = 0x7FB

    ...

  • 8/7/2019 Curso Ccs en PDF

    33/69

    Si que funcion. Pero, que pasa si asignamos el dato a 0x800?

    All vemos que el puntero se carg bien, pero el MPLAB-SIM delata el

    desbordamiento, Por que? Es que a partir de all no hay memoria de datos y

    las direcciones se deberan leer como puros 0x0 a pesar que compil bien,

    (similarmente en programas de computadoras pueden ocurrir los lazos infinitos

    popularmente llamado se colg la mquina)

    Punteros en funciones

    Todo lo que hagamos en CCS se hace a travs de funciones o procedimientos,

    desde el punto de vista matemtico una funcin se define as:

    Una funcin es una relacin entre dos variables numricas, habitualmente las

    denominamos x e y; a una de ellas la llamamos variable dependiente pues

    depende de los valores de la otra para su valor, suele ser la y; a la otra por

    tanto se la denomina variable independiente y suele ser la x. Pero adems,

    para que una relacin sea funcin, a cada valor de la variable independiente le

    corresponde uno o ningn valor de la variable dependiente, no le pueden

    corresponder dos o ms valores.

    Aplicndolo a la programacin, significa que podemos tener varios argumentos

    o parmetros de entrada, pero solo tendremos un dato de salida. Y eso no estodo, en C una funcin pasa los argumentos por valor. que quiere decir esto?

  • 8/7/2019 Curso Ccs en PDF

    34/69

    Que cuando llamemos a la funcin y le pasemos el dato como argumento, sta

    copiar ese dato en su propia funcin sin alterar la variable original. veamos un

    ejemplo:

    #include

    #use delay(clock=4000000)

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

    int mi_funcion(int argumento1, argumento2){

    delay_cycles (1);

    return (argumento1 + argumento2);

    }

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

    void main(){

    int k,l,resultado;

    k=5; L=2;

    resultado = mi_funcion(k,L);

    delay_cycles(1);

    }

    Noten que cuando llamo a mi_funcion, se copia el contenido de k ->

    argumento1 y L -> argumento2, luego hace la suma y regresa un dato con el

    resultado de la suma. k y L se quedan con el mismo valor anterior.

    y si queremos cambiar esas variables como se hace?

  • 8/7/2019 Curso Ccs en PDF

    35/69

    Bueno seguro que alguien llegar y colocar a k y L como globales y entonces

    as se puede modificar en cualquier lado. Pero si la variable es local, dentro de

    main (), no se puede modificar fuera de main ()...a menos que usemos

    punteros. y como se hara eso?

    Simple: se hara pasando el argumento a la funcin como referencia, haciendo

    referencia a la direccin, es decir lo que se pasar a la funcin es la direccin

    de k, L entonces all si se puede modificar a gusto. Un ejemplo:

    #include

    #use delay(clock=4000000)

    //*********************************int mi_funcion(int argumento1, argumento2, *la_k, *la_L){

    delay_cycles (1);

    *la_k=0xFF; *la_L=0xAF;

    return (argumento1 + argumento2);

    }

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

    void main(){

    int k,l,resultado;

    k=5; l=2;

    resultado = mi_funcion(k,l,&k,&l);

    delay_cycles (1);

    }

    Punteros en Arrays

    Como sabrn los arrays son arreglos de datos que van en direcciones

    consecutivas, es decir, uno detrs del otro. Un ejemplo de ello:

    char cadena[7]={'T','o','d','o','P','i','c'};

    Si lo probamos en un cdigo:

    #include

    #use delay(clock=4000000)

  • 8/7/2019 Curso Ccs en PDF

    36/69

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

    char cadena[7]={'T','o','d','o','P','i','c'};

    void main(){

    char c;

    int t;

    for(t=0;t

  • 8/7/2019 Curso Ccs en PDF

    37/69

    Se pueden usar punteros en el ejemplo anterior. Veamos como:

    Declarando un puntero como char:

    char c, *p;

    lo inicializamos (le damos la direccin del primer elemento del array):

    p=&cadena[0];

    luego hacemos un barrido de direcciones para tomar el contenido de cada

    elemento y guardarlo en c

    for (t=0;t

  • 8/7/2019 Curso Ccs en PDF

    38/69

    #include

    #use delay(clock=4000000)

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

    long cadena[7]={1000,2000,3000,4000,5000,6000,7000};

    void main(){

    long c, *p;

    int t;

    p=&cadena[0];

    for(t=0;t

  • 8/7/2019 Curso Ccs en PDF

    39/69

    Fjense que p queda inmutable, y lo que hace el programa es contenido[0] + t.

    Grave error!

    Arreglando el programa con *(p+t)

  • 8/7/2019 Curso Ccs en PDF

    40/69

    Con esto estamos garantizando que el puntero se mover de 2 bytes en 2

    bytes, es decir

    *(p+t) =

    0x5 + 0x2 (desplazamiento de 2 byte)-> dame el contenido de la direccin 0x5

    0x5 + 1x2 " -> dame el contenido de la direccin 0x7

    0x5 + 2x2 " -> dame el contenido de la direccin 0x9

    0x5 + 3x2 " -> dame el contenido de la direccin 0xA

    ...

  • 8/7/2019 Curso Ccs en PDF

    41/69

    Noten que la suma se realiza no intervalos de t sino en intervalos del ancho del

    tipo de dato. Pero...esto no es lo mismo que se hizo en el cdigo del inicio del

    artculo?

    O sea que c = cadena[t]; es igual a c = *(p + t) cuando p = &cadena[0]; ?

    Pues si, acabamos de ver un array al desnudo, como funciona en realidad, no

    es mas que un puntero escondido a nuestra vista. Solo que para hacer fcil la

    programacin el compilador lo acepta de esta manera. Si p es un puntero -> p

    = cadena (para el primer ndice del arreglo) es totalmente vlido, se acepta que

    cadena es un puntero constante, tambin se podra llamar un puntero nulo (ya

    que no se ve y tampoco se puede modificar).

    Ejemplos validos:

    cadena [0] = *cadena

    cadena [2] = *(cadena + 2)

    cadena = *(cadena + i)

    Nota: el operador () es el primero que atiende el compilador, antes que al resto.

    Acomodando el cdigo original, el que tena la cadena de caracteres:

    #include

    #use delay(clock=4000000)

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

    char cadena[7]={'T','o','d','o','P','i','c'};

    void main(){char c, *p;

    int t;

    p=cadena;

    for(t=0;t

  • 8/7/2019 Curso Ccs en PDF

    42/69

  • 8/7/2019 Curso Ccs en PDF

    43/69

    CCS - Funciones

    Las funciones son los bloques bsicos con los que construimos un programaen CCS. Adems de la funcin main() que veremos enseguida, un programaCCS tendr seguramente varias funciones ms, conteniendo cada una un

    bloque de instrucciones que realizan una tarea determinada.

    Funciones

    Las funciones tienen la siguiente forma:

    nombre_de_la_funcion() {instruccion;instruccion;.

    .instruccion; }

    Para evitar que surjan errores o avisos (warnings) al compilar nuestrosprogramas, debemos declarar las funciones antes de utilizarlas.

    Prototipos

    Existen dos formas de decirle al compilador CCS que tipo de valor devolvernuestra funcin. La forma general es la siguiente:

    tipo nombre_de_funcion();

    donde tipo es cualquiera de los tipos de variables soportados por CCS. Al igualque cualquier instruccin de CCS, la lnea debe termina con ; (punto y coma).

    El siguiente ejemplo declara la funcin ejemplo() que devuelve como resultadoun valor del tipo long:

    long ejemplo();

    Parmetros

    Adems de determinar el tipo de resultado que devolver la funcin, en elprototipo podemos especificar que parmetros recibir, y de que tipo sern. Laforma de hacerlo es la siguiente:

    tipo nombre_de_funcion(tipo var1, tipo var2, ..., tipo varN);

    La diferencia con el caso anterior es que se han incluido dentro de los () unaserie de nombres de variables (var1, var2, ..., varN), cada una asociado a un

    tipo en particular.

  • 8/7/2019 Curso Ccs en PDF

    44/69

    Supongamos que queremos crear una funcin que lleve a cabo la suma de dosde tipo int, que le son pasados como argumentos, y nos devuelva el resultadoen formato double. Deberamos escribir as su prototipo:

    double suma(int a, int b);

    donde a y b son los valores a sumar. El llamado a la funcin se puede hacer dela siguiente manera:

    int a, b;double resultado;a = 10;b = 250;resultado = suma (a, b);

    resultado contendr el valor "300".

    Return

    La forma en que se asigna en la funcin el valor que esta debe devolver esmediante la instruccin return.

    Vemoslo con el ejemplo de la funcin suma vista mas arriba. La funcinpodra ser como sigue:

    double suma(int a, int b){

    double auxiliar;auxiliar = (double) (a * b );return auxiliar;}

    Otra forma, mas corta, de escribir la misma funcin es la siguiente:

    double suma(int a, int b){return (double) a * b;}

    Void

    void significa que la funcin no devolver ningn parmetro. Supongamos quela funcin ejemplo() no debe regresar ningn valor luego de ser llamada. Suprototipo debera ser como sigue:

    void ejemplo();

    Adems, podemos usar void para indicar que la funcin no recibe parmetros:

    void ejemplo2(void);

  • 8/7/2019 Curso Ccs en PDF

    45/69

    en el ejemplo, la funcin ejemplo2() no recibe parmetros, ni devuelve ningnvalor.

    La funcin main()

    Como hemos visto, el lenguaje C permite la utilizacin de funciones. Pero hayuna funcin especial, llamada main () que obligatoriamente debe estarpresente, y es el punto de entrada a todo programa en C que escribamos.

    La funcin main () tiene la siguiente forma:

    main() {instruccion;instruccion;.

    .instruccion; }

    donde instruccion; puede ser cualquier instruccin vlida del CCS o unallamada a otra funcin.

    CCS - Uso de LCDs alfanumricos.

    En CCS no disponemos de instrucciones especficas para el manejo depantallas LCD. Sin embargo, nada impide que escribamos funciones que seancapaces de inicializar, escribir o borrar (e incluso leer) los datos de estaspantallas. El hecho de que la mayora de los mdulos LCD estn construidosen base al controlador Hitachi HD44780.

    LCD.C

    Para ponernos las cosas ms fciles, dentro de la carpeta "drivers" de CCS seencuentra un archivo llamado LCD.C, que si lo incluimos en nuestro proyecto,

    nos proveer de las funciones necesarias. Sin embargo, LCD.C tiene algunaslimitaciones: tal como est, solo funciona si conectamos nuestro LCD en elpuerto D (o B, con una modificacin menor).

    Para incluirlo en nuestro programa, basta con hacer lo siguiente:

    #INCLUDE "lcd.c"

    en cuanto al hardware,las lneas de datos deben conectarse de la siguientemanera:

    PORT.D0 -> enable PORT.D1 -> rs

  • 8/7/2019 Curso Ccs en PDF

    46/69

    PORT.D2 -> rw PORT.D4 -> D4 PORT.D5 -> D5 PORT.D6 -> D6 PORT.D7 -> D7

    Como puede verse, se trata de una comunicacin con solo 4 bits de datos. Msadelante veremos como modificar este archivo para que se pueda emplear conel LCD en otro puerto y/o con otra asignacin de pines. El siguiente es elcontenido del archivo LCD.C tal como es provisto por CCS.

    ///////////////////////////////////////////////////////////////////////////////////////////////////////// //// LCD.C //// //// Driver for common LCD modules //// //// //// lcd_init() Must be called before any other function. ////

    //// //// lcd_putc(c) Will display c on the next position of the LCD. //// //// The following have special meaning: //// //// \f Clear display //// //// \n Go to start of second line //// //// \b Move back one position //// //// //// lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1) //// //// //// lcd_getc(x,y) Returns character at position x,y on LCD //// //// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //// (C) Copyright 1996,2003 Custom Computer Services //////// This source code may only be used by licensed users of the CCS C //// //// compiler. This source code may only be distributed to other //////// licensed users of the CCS C compiler. No other use, reproduction //// //// or distribution is permitted without written permission. //// //// Derivative programs created using this software in object code //// //// form are not restricted in any way. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // As defined in the following structure the pin connection is as follows: // D0 enable // D1 rs // D2 rw // D4 D4 // D5 D5 // D6 D6 // D7 D7//// LCD pins D0-D3 are not used and PIC D3 is not used.//

    // Un-comment the following define to use port B// #define use_portb_lcd TRUE

  • 8/7/2019 Curso Ccs en PDF

    47/69

    ////struct lcd_pin_map { // This structure is overlayed

    BOOLEAN enable; // on to an I/O port to gainBOOLEAN rs; // access to the LCD pins.

    BOOLEAN rw; // The bits are allocated fromBOOLEAN unused; // low order up. ENABLE willint data : 4; // be pin B0.

    } lcd;//#if defined(__PCH__)#if defined use_portb_lcd

    #byte lcd = 0xF81 // This puts the entire structure#else

    #byte lcd = 0xF83 // This puts the entire structure#endif

    #else#if defined use_portb_lcd

    #byte lcd = 6 // on to port B (at address 6)#else

    #byte lcd = 8 // on to port D (at address 8)#endif#endif//#if defined use_portb_lcd

    #define set_tris_lcd(x) set_tris_b(x)#else

    #define set_tris_lcd(x) set_tris_d(x)#endif//#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines#define lcd_line_two 0x40 // LCD RAM address for the second line//BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type

  • 8/7/2019 Curso Ccs en PDF

    48/69

    delay_cycles(1);high = lcd.data;lcd.enable = 0;delay_cycles(1);lcd.enable = 1;

    delay_us(1);low = lcd.data;lcd.enable = 0;set_tris_lcd(LCD_WRITE);return( (high 4);lcd_send_nibble(n & 0xf);

    }//void lcd_init() {

    BYTE i;set_tris_lcd(LCD_WRITE);lcd.rs = 0;lcd.rw = 0;

    lcd.enable = 0;delay_ms(15);for(i=1;i

  • 8/7/2019 Curso Ccs en PDF

    49/69

    if(y!=1)address=lcd_line_two;

    elseaddress=0;

    address+=x-1;

    lcd_send_byte(0,0x80|address);}//void lcd_putc( char c) {

    switch (c) {case '\f' : lcd_send_byte(0,1);

    delay_ms(2);break;

    case '\n' : lcd_gotoxy(1,2); break;case '\b' : lcd_send_byte(0,0x10); break;default : lcd_send_byte(1,c); break;

    }}//char lcd_getc( BYTE x, BYTE y) {

    char value;lcd_gotoxy(x,y);while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is lowlcd.rs=1;value = lcd_read_byte();lcd.rs=0;return(value);

    }

    Funciones en LCD.C

    Hay cuatro funciones implementadas dentro de LCD.C:

    lcd_init()

    Esta funcin es la encargada de enviar los comandos de inicializacin

    necesarios al LCD. Es obligatorio ejecutar esta funcin antes de utilizar eldisplay para escribir sobre l. No recibe ni devuelve valores de ningn tipo. Suforma de uso es tan simple como:

    lcd_init ();

    y listo.

    lcd_putc()

    Esta seguramente ser la funcin que mas emplearemos. Es la que se encargade escribir nuestro mensaje en la pantalla. No devuelve valores, pero si

  • 8/7/2019 Curso Ccs en PDF

    50/69

    (obviamente) los recibe. La forma de uso es muy simple. Basta con llamarla,pansandole como parmetro una variable o constante tipo char, y la funcin seencargar de desplegar su contenido sobre el display.

    Lcd_putc ("uControl.com.ar");

    Produce la siguiente salida sobre el display:

    Por supuesto, no debemos olvidar de inicializar previamente el display.Adems, lcd_putc() reconoce los siguientes comandos que pueden ser

    enviados en el texto a mostrar:

    \f -> Borra la pantalla. \n -> Salta al comienzo de la segunda lnea. \b -> Retrocede una posicin.

    Esto quiere decir que si modificamos nuestro cdigo para que quede as:

    Lcd_putc ("uControl.com.ar\n LCD en CCS");

    obtendremos el siguiente texto en el LCD:

    Por ltimo, si queremos borrar el contenido de la pantalla, bastar con losiguiente:

    Lcd_putc ("\f");

    que dejar nuestro display completamente limpio:

  • 8/7/2019 Curso Ccs en PDF

    51/69

    lcd_gotoxy(x,y)

    Esta es la funcin que nos permite colocar el cursor en la parte que deseemosde la pantalla. Recibe dos parmetros, ambos de tipo byte. El primero de ellosindica la columna en la que aparecer el primer carcter del texto, y elsegundo se refiere a la fila en que lo har. El siguiente cdigo ejemplifica eluso de lcd_gotoxy(x,y):

    Lcd_putc ("uControl.com.ar");lcd_gotoxy (5,2); //salto a columna 4, fila 2Lcd_putc ( "LCD en CCS");

    hace lo siguiente:

    Importante: Tanto las filas como las columnas se cuentan a partir de 1.

    lcd_getc(x,y)

    Esta funcin recibe como parmetros la columna' y la fila (ambos de tipobyte ) de la que deseamos conocer el contenido, y nos devuelve uncharcon el contenido. Su uso no podra ser ms sencillo:

    char a;a = lcd_getc(5,2);

    Si el display conserva el texto de la imagen anterior, la variable a contendr elvalor "L".

    Importante: Tanto las filas como las columnas se cuentan a partir de 1.

    Modificando LCD.C

    Por supuesto, en la mayora de los casos la conexin entre el microcontroladory el display LCD no coincidir con la especificada en el archivo LCD.C provistopor CCS. Pero eso no quiere decir que debamos redisear nuestro proyecto, nique sea imposible modificar la configuracin de LCD.C. como puede verse,dentro del cdigo de LCD.C se define una estructura de datos que es laencargada de contener la distribucin de los pines a utilizar, junto a la funcinque desempear. Es el siguiente trozo de cdigo:

    struct lcd_pin_map { // This structure is overlayedBOOLEAN enable; // on to an I/O port to gainBOOLEAN rs; // access to the LCD pins.BOOLEAN rw; // The bits are allocated from

  • 8/7/2019 Curso Ccs en PDF

    52/69

    BOOLEAN unused; // low order up. ENABLE willint data : 4; // be pin B0.

    } lcd;

    Supongamos que tenemos un display conectado de la siguiente manera:

    PORT.B2 -> enable PORT.B3 -> rs PORT.B4 -> D4 PORT.B5 -> D5 PORT.B6 -> D6 PORT.B7 -> D7

    Notar que no estamos usando el pin RW del display, que estarpermanentemente conectado a GND. La estructura debera quedar as:

    struct lcd_pin_map {BOOLEAN unused1; // RB0BOOLEAN unused2; // RB1BOOLEAN enable; // RB2BOOLEAN rs; // RB3int data : 4; // RB4-RB7

    } lcd;

    Por supuesto, habrs notado que en lugar del puerto D estamos usando elpuerto B, as que hay que quitar el comentario a la lnea

    // #define use_portb_lcd TRUE

    para que quede as:

    #define use_portb_lcd TRUE //LCD conectado al puerto b.

    Y como no estamos usando la lnea RW del LCD, debemos quitar las dos treslneas de cdigo en la que se hace referencia a ella. El listado siguientecorresponde al archivo LCD.C con todas las modificaciones mencionadas, msalgunas modificaciones en los #INCLUDE del principio, que no tienen sentido

    mantener ya que al personalizar el archivo nunca se van a dar algunas de lascondiciones contempladas all. Tambin hemos quitado el cdigo de la funcinlcd_getc( x, y) ya que al estar RW conectado de forma permanente a GND,ser imposible leer caracteres del display.

    ///////////////////////////////////////////////////////////////////////////// LCD.C modificada por uControl.com.ar/////////////////////////////////////////////////////////////////////////// // B0

    // B1 // B2 E

  • 8/7/2019 Curso Ccs en PDF

    53/69

    // B3 RS // B4 D4 // B5 D5 // B6 D6 // B7 D7

    // (Sin 'RW')//// Funciones soportadas: // lcd_init() // lcd_gotoxy( BYTE col, BYTE fila) // lcd_putc( char c) // \f Clear display // \n Go to start of second line // \b Move back one position/////////////////////////////////////////////////////////////////////////////

    #define use_portb_lcd TRUE //LCD conectado al puerto b.//struct lcd_pin_map {

    BOOLEAN unused1; // RB0BOOLEAN unused2; // RB1BOOLEAN enable; // RB2BOOLEAN rs; // RB3int data : 4; // RB4-RB7

    } lcd;//#byte lcd = 0xF81 // Direccin de la estructura "lcd".#byte lcd = 6 // Direccin del puerto B.#define set_tris_lcd(x) set_tris_b(x)#define lcd_type 2 // Tipo de LCD: 0=5x7, 1=5x10, 2=2 lneas#define lcd_line_two 0x40 // Direccin de la LCD RAM para la 2da. lnea////Defino la cadena de inicializacin del LCD.BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type

  • 8/7/2019 Curso Ccs en PDF

    54/69

    delay_us(1);low = lcd.data;lcd.enable = 0;set_tris_lcd(LCD_WRITE);return( (high 4);lcd_send_nibble(n & 0xf);

    }//void lcd_init() {

    BYTE i;set_tris_lcd(LCD_WRITE);lcd.rs = 0;lcd.enable = 0;delay_ms(15);for(i=1;i

  • 8/7/2019 Curso Ccs en PDF

    55/69

    //void lcd_putc( char c) {

    switch (c) {case '\f' : lcd_send_byte(0,1);

    delay_ms(2);

    break;case '\n' : lcd_gotoxy(1,2); break;case '\b' : lcd_send_byte(0,0x10); break;default : lcd_send_byte(1,c); break;

    }}

    Libreria de grficos para GLCD K0108 en CCS

    El compilador CCS proporciona una librera capaz de dibujar primitivas sobrevarios modelos de displays LCD grficos o GLCD (por Graphic Liquid CristalDisplay). Hay versiones de esta librera para pantallas con diferentescontroladores embebidos, como el Samsung KS0108 o el Toshiba T6963.

    Pero a pesar de que pueden distribuirse libremente los trabajos que hagamoscon ellas, no pueden compartirse los programas que las contengan a menosque la persona que los recibe tambin sea un usuario registrado de CCS.

    Esto limita mucho su uso con fines educativos. De hecho, si quisisemos

    exponer aqu un programa que grafique algo en un GLCD, estaramos violandola licencia, ya que es muy posible que muchos de los lectores de uControl nohayan comprado el compilador.

    Es por ello que nos hemos decidido a escribir una librera propia, que usaremosde ahora en ms para nuestros proyectos.

    La librera GLCD_K0108

    Puedes descargar la libreria GLCD_K0108.C haciendo click aqu.

    En las siguientes secciones iremos explicando cada una de sus partes.

    IMPORTANTE: El trazado de lneas se basa en elAlgoritmo de Bresenham, ylas circunferencias se han resuelto mediante el "algoritmo del punto medio",que divide la circunferencia en 8 partes simtricas, evitando utilizar funcionescomo seno, coseno o potencias, que volveran muy lenta la tarea del trazado.

    GLCD_limpiar (color)

  • 8/7/2019 Curso Ccs en PDF

    56/69

    Esta es la funcin que "pinta" toda la pantalla con uno u otro color. Si recibecomo parmetro un "1", la pintar completamente de negro. Si recibe un "0", lalimpiar por completo.

    Por supuesto, su mayor utilidad es la segunda alternativa.

    Su funcionamiento tambin es muy sencillo, y se "apoya" en GLCD_enviaBYTE () para escribir en el GLCD. Recorre ambas mitades del GLCD, pginapor pgina, de arriba hacia abajo, escribiendo "0x00" o "0xFF" segn se hayaelegido pintar o borrar.

    (Hz clic sobre las imgenes para ampliarlas)

    En la primer imgen, utilizando GLCD_limpiar(1);, la pantalla se pintacompletamente de negro. En la segunda, mediante GLCD_limpiar(0);, se pintacompletamente de blanco. Podemos usar esta funcin para limpiarla pantalla.

    Puedes ver un ejemplo de uso de esta funcin aqu.

  • 8/7/2019 Curso Ccs en PDF

    57/69

    GLCD_inicializa (modo)

    Esta es la primera funcin de la librera que debe llamar nuestro programa.

    Se encarga de inicializar el GLCD, y el parmetro "modo" determina si estarencendido (si recibe un "1") o apagado (si recibe un "0").

    Puedes ver un ejemplo de uso de esta funcin aqu.

    GLCD_punto(x, y, color)

    Esta es la "primitiva grfica" indispensable. A partir de GLCD_punto(x, y, color)escribiremos todas las funciones restantes.

    Los parametros que recibe GLCD_punto(x, y, color) son:

    x: un byte, es la coordenada "x" (horizontal), con valores vlidos de 0 a127 (izquierda a derecha).

    y: un byte, es la coordenada "y" (vertical), con valores vlidos de 0 a 63(arriba a abajo)

    color: un bit, "0" = apagado, "1" = encendido.

    (Hz clic sobre la imgen para ampliarla)

    Puedes ver un ejemplo de uso de esta funcin aqu.

    GLCD_linea(x1, y1, x2, y2, color)

    La lnea tambin resulta indispensable a la hora de dibujar un grfico.

    Los parametros que recibe GLCD_linea(x1, y1, x2, y2, color) son:

  • 8/7/2019 Curso Ccs en PDF

    58/69

    x1: un byte, es la coordenada "x" (horizontal) del primer extremo de lalnea, con valores vlidos de 0 a 127 (izquierda a derecha).

    y1: un byte, es la coordenada "y" (vertical) del primer extremo de lalnea, con valores vlidos de 0 a 63 (arriba a abajo).

    x2: un byte, es la coordenada "x" (horizontal) del segundo extremo de la

    lnea, con valores vlidos de 0 a 127 (izquierda a derecha). y2: un byte, es la coordenada "y" (vertical) del segundo extremo de la

    lnea, con valores vlidos de 0 a 63 (arriba a abajo). color: un bit, "0" = lnea en blanco, "1" = lnea en negro.

    (Hz clic sobre las imgenes para ampliarlas)

    Puedes ver un ejemplo de uso de esta funcin aqu.

    GLCD_rectangulo(x1, y1, x2, y2, color)

    Los rectngulos de dibujan (internamente) mediante cuatro llamadas a lafuncin GLCD_linea.

    Los parametros que recibe GLCD_rectangulo(x1, y1, x2, y2, color) son:

  • 8/7/2019 Curso Ccs en PDF

    59/69

    x1: un byte, es la coordenada "x" (horizontal) de la esquina superiorizquierda del rectngulo, con valores vlidos de 0 a 127 (izquierda aderecha).

    y1: un byte, es la coordenada "y" (vertical) de la esquina superiorizquierda del rectngulo, con valores vlidos de 0 a 63 (arriba a abajo).

    x2: un byte, es la coordenada "x" (horizontal) de la esquina inferiorderecha del rectngulo, con valores vlidos de 0 a 127 (izquierda aderecha).

    y2: un byte, es la coordenada "y" (vertical) de la esquina inferior derechadel rectngulo, con valores vlidos de 0 a 63 (arriba a abajo).

    color: un bit, "0" = rectngulo en blanco, "1" = rectngulo en negro.

    (Hz clic sobre las imgenes para ampliarlas)

    Puedes ver un ejemplo de uso de esta funcin aqu.

    GLCD_caja(x1, y1, x2, y2, color)

    Las "cajas" son rectngulos pintados en su interior con el mismo color que elborde exterior. Tambin se dibujan (internamente) mediante llamadas a la

    funcin GLCD_linea.

  • 8/7/2019 Curso Ccs en PDF

    60/69

    Los parametros que recibe GLCD_caja(x1, y1, x2, y2, color) son:

    x1: un byte, es la coordenada "x" (horizontal) de la esquina superiorizquierda del rectngulo, con valores vlidos de 0 a 127 (izquierda aderecha).

    y1: un byte, es la coordenada "y" (vertical) de la esquina superiorizquierda del rectngulo, con valores vlidos de 0 a 63 (arriba a abajo).

    x2: un byte, es la coordenada "x" (horizontal) de la esquina inferiorderecha del rectngulo, con valores vlidos de 0 a 127 (izquierda aderecha).

    y2: un byte, es la coordenada "y" (vertical) de la esquina inferior derechadel rectngulo, con valores vlidos de 0 a 63 (arriba a abajo).

    color: un bit, "0" = caja en blanco, "1" = caja en negro.

    (Hz clic sobre las imgenes para ampliarlas)

    Puedes ver un ejemplo de uso de esta funcin aqu.

    GLCD_circulo(x1, y1, radio, color)

    Esta es la funcin que dibuja un circulo. El interior del circulo permanece delcolor del fono. Estrictamente hablando, se dibuja solo la circunferencia.

  • 8/7/2019 Curso Ccs en PDF

    61/69

    Los parametros que recibe GLCD_circulo(x1, y1, radio, color) son:

    x1: un byte, es la coordenada "x" (horizontal) del centro del circulo, convalores vlidos de 0 a 127 (izquierda a derecha).

    y1: un byte, es la coordenada "y" (vertical) del centro del circulo, con

    valores vlidos de 0 a 63 (arriba a abajo). radio: un byte, es el radio de la circunferencia (en pixeles). color: un bit, "0" = circulo en blanco, "1" = circulo en negro.

    (Hz clic sobre las imgenes para ampliarlas)

    Puedes ver un ejemplo de uso de esta funcin aqu.

    Definiciones, pines y otras yerbas

    Para que la libreria pueda ser adaptada al proyecto que tienes en mente,hemos colocado los siguientes "#define" al comienzo de la misma, paradeterminar que pin del PIC has conectado a cada pin del GLCD:

    //Pines a usar

  • 8/7/2019 Curso Ccs en PDF

    62/69

    #define GLCD_CS1 PIN_E2#define GLCD_CS2 PIN_E1#define GLCD_DI PIN_C3#define GLCD_RW PIN_C2#define GLCD_E PIN_C1

    #define GLCD_RESET PIN_E0

    Si tu circuito emplea pines diferentes a los del ejemplo para manejar el GLCD,debers cambiar los valores que sea necesario.

    El display est "partido" en dos mitades de 64x64 pixeles. Esto implica que almomento de escribir en el debemos seleccionar en cual de las dos mitades loestamos haciendo. Para ello dispone de dos lneas de control (ver el pinout delGLCD en la seccin correspondiente), llamadas CS1 y CS2. Asignaremos losvalores de 0 y 1 a "GLCD_lado_CS1" y "GLCD_lado_CS2", respectivamente.

    //Lados del GLCD#define GLCD_lado_CS1 0#define GLCD_lado_CS2 1

    Tambien hemos definido un BYTE que guardar el dato que leyamos desde elGLCD:

    BYTE GLCD_leeBYTE(int1 lado);

    GLCD-K0108 en el PIC SIMULATOR IDE

  • 8/7/2019 Curso Ccs en PDF

    63/69

    Veamos ahora las funciones internas bsicas de la librera:

    GLCD_enviaBYTE (lado, dato)

    Esta funcin enva un byte a uno u otro lado del display. Como mencionamosantes, debemos seleccionar previamente, mediante la activacin de CS1 oCS2, cual utilizaremos.

    El parmetro (tipo int1) "lado" es el que define a que mitad del GLCD ir a pararel "dato".

    El resto de la funcin no tiene ningn secreto. En ella, se realizan los siguientes

    pasos:

    Se pone el GLCD en "modo escritura", poniendo en bajo GLCD_RW. Se coloca el dato en el puerto D del PIC durante 1 microsegundo. Se habilita el GLCD, poniendo en alto GLCD_E durante 2

    microsegundos. Se deshabilita el GLCD, poniendo en bajo nuevamente GLCD_E Se vuelven a nivel bajo CS1 y CS2

    GLCD_leeBYTE (lado)

    Esta es la funcin que permite leer un byte desde el GLCD.

    Igual que la anterior, recibe como parmetro la informacin que le indica encual de las dos mitades est el dato a leer.

    Realiza los siguientes pasos:

    Se configura el puerto D como entrada. Se pone el GLCD en "modo lectura", poniendo en alto GLCD_RW. Se selecciona la mitad correspondiente, mediante CS1 y CS2. Se habilita el GLCD, poniendo en alto GLCD_E durante 2

    microsegundos. Se guarda el dato y se deshabilita el GLCD, poniendo en bajo

    nuevamente GLCD_E Se vuelven a nivel bajo CS1 y CS2

    La funcin devuelve un BYTE con el dato ledo.

    GLCD_letra (carcter, color, fuente)

    El presente artculo esta incompleto.

  • 8/7/2019 Curso Ccs en PDF

    64/69

    En ste momento estamos trabajando en l, y en poco tiempo estarterminado.

    El equipo de uControl.

    GLCD con controlador Samsung KS0108

    Por ahora, nuestra librera ofrece soporte para los GLCD de 128x64 pxeles,monocromticos, que tienen un controlador Samsung KS0108 (o compatibles).

    El que hemos usado en nuestras pruebas es el de la foto siguiente. Se trata deun ELWG12864-YYB-VN, con puntos negros sobre fondo verde, de la empresaWinstar.

    Este es el modelo de GLCD elegido para las pruebas.

  • 8/7/2019 Curso Ccs en PDF

    65/69

    IMPORTANTE: Si tu display no es exactamente este modelo, consulta su hojade datos para asegurarte que funcin cumple cada uno de sus pines.

    Restricciones legales de CCS

    Como decamos en la introduccin, dentro de las libreras incluidas en CCS seha incluido una especie de licencia. Concretamente, en el cdigo fuente dedichas librerias puede leerse algo como lo siguiente:

    ///////////////////////////////////////////////////////////////////////// //// (C) Copyright 1996, 2004 Custom Computer Services //////// This source code may only be used by licensed users of the CCS //////// C compiler. This source code may only be distributed to other //// //// licensed users of the CCS C compiler. No other use, //// //// reproduction or distribution is permitted without written ////

    //// permission. Derivative programs created using this software //// //// in object code form are not restricted in any way. /////////////////////////////////////////////////////////////////////////////

    Esto, traducido al espaol significa ms o menos lo siguiente:

    "Este cdigo fuente slo puede ser utilizado por usuarios con licencia delcompilador C CCS. Este cdigo fuente slo puede ser distribuido a otrosusuarios con licencia del compilador C CCS. No se permite ningn otro uso,reproduccin o distribucin sin el consentimiento escrito. Los programas

    derivados, creados utilizando este software, pueden distribuirse como cdigoobjeto sin limitantes."

    Descargas

    Puedes descargar la libreria GLCD_K0108.C haciendo click aqu.

  • 8/7/2019 Curso Ccs en PDF

    66/69

    CCS - Poniendo un poco de orden.

    Mantener ordenadas aquellas libreras que compartimos entre distintosproyectos, puede ser una tarea a veces complicada, sobre todo cuandodesconocemos mtodos eficaces para realizar este trabajo. Este problema

    existe desde hace muchos aos y los desarrolladores de compiladores para C,fueron incluyendo mecanismos eficientes para dar solucin a este problema.Las siguientes lneas nos ayudarn a sacar provecho de esas simples, peropoderosas herramientas.

    El uso de las libreras es fundamental para el desarrollo de proyectos en C.

    Sin embargo, cuando tenemos varios proyectos que comparten las mismas

    libreras, una gestin deficiente, puede llevarnos al caos.

    Donde reside el problema?

    En aquellas libreras que necesitamos reutilizar, y que por su naturaleza,tenemos que modificar para adaptarlas a nuestros proyectos. Un claro ejemplode este tipo de libreras es la Flex_LCD.c desarrollada por CCS, que nospermite utilizar los muy comunes LCDs de 2 lneas.

    Habitualmente, esta librera debe ser modificada para adaptarla a nuestrasnecesidades en cada proyecto. Esta situacin se presenta cuando nuestrosproyectos requieren el uso de distintos microcontroladores o cuando

    necesitamos determinados mdulos del microcontrolador, cuyos pines de E/S,han sido asignados al LCD dentro de Flex_LCD.c. De aqu en adelante,utilizaremos la librera Flex_LCD.c como modelo para el resto del artculo,pero todo lo expuesto es aplicable cualquier librera.

    Como se modifican estas libreras para su uso?

    Aqu es donde surge el caos entre los distintos proyectos que tenemos entremanos o que hemos realizado. Analicemos las tres alternativas, de uso msfrecuente:

    La forma usual e ineficaz.

    Tenemos una nica librera ubicada en el directorio de libreras (library), ycuando nos hace falta, la modificamos. Esta suele ser una prctica muyhabitual. Cada vez que empezamos un nuevo proyecto modificamos la libreray la adaptamos a la necesidad del momento.

    Pero: qu ocurre cuando debemos modificar y recompilar un proyecto hechocon anterioridad? Si los pines utilizados en el proyecto anterior y el actualcoinciden, no tendremos problema alguno. Sin embargo, es frecuente que no

    coincidan los pines asignados al LCD del antiguo proyecto con los del actual.

  • 8/7/2019 Curso Ccs en PDF

    67/69

    Por lo que si compilamos un proyecto antiguo, es muy probable que nofuncione correctamente.

    La solucin comn al problema anterior, es tener anotado en algn lugar laasignacin de pines para cada proyecto y modificar la librera antes de compilar

    cada uno. Como se pude ver, es un proceso tedioso que exige un alto grado deorden para mantener la funcionalidad de nuestros proyectos.

    El mtodo de la copia

    Una alternativa que puede solucionar el problema anterior, es tener una copiade la librera en el directorio de cada proyecto. Luego modificamos la copia,para ajustarla a la configuracin segn sea el caso. Esto permite que podamoscompilar cada proyecto una y otra vez, sin necesidad de modificar la librera, yaque cada proyecto tiene una copia adaptada segn sus necesidades.

    Es una solucin tambin bastante habitual, pero no idnea; qu ocurre sinecesitamos modificar la librera porque tenemos una nueva versin de lamisma? Tendremos que ir buscando por el laberinto de directorios de proyectoscada copia de la librera vieja y sustituirla por la nueva.

    Se puede argumentar que hoy en da con la velocidad de proceso y lasherramientas de bsqueda de las PC, este trabajo no ser en extremo tedioso.Pero aunque logrsemos encontrar y sustituir todas las copias en un cortoespacio de tiempo, tendremos otro problema aadido, y es que cada copia dela librera est personalizada para su proyecto. La situacin anterior nos

    obliga a reconfigurar la nueva versin de la copia, de acuerdo a laconfiguracin de cada proyecto, trabajo que hicimos la primera vez quecopiamos la librera hacia el directorio del proyecto.

    Utilizando las directivas del pre-procesador

    Esta es la forma correcta y eficaz de hacerlo. Este mtodo es el queadoptaremos y nos permitir manejar las libreras sin sufrir dolores de cabeza.Consiste en definir la asignacin de pines, en algn lugar fuera de la librera,bien en fichero aparte, o bien en el programa principal del proyecto. Cmo

    podemos modificar la asignacin de pines fuera de la librera? La forma dehacerlo es utilizando las directivas del pre-procesador.

    Las directivas del pre-procesador son un conjunto de instrucciones que seutilizan para indicarle al compilador, que debe hacer, ante determinadassituaciones. Aunque generalmente muchos programadores desconocen suutilidad con profundidad, estas directivas son una herramienta muy poderosapara crear variables, reservar memoria, definir constantes, utilizar macros eincluso indicarle al compilador que secciones de cdigo debe compilar yenlazar. En nuestro caso, utilizaremos las directivas del pre-procesador #ifndef #endif.

  • 8/7/2019 Curso Ccs en PDF

    68/69

    Cuando el pre-procesador se topa con la directiva #ifndef, comprueba si yaexiste el identificador , si ste no existiese, entonces crea uno conese nombre, lo agrega a su lista de identificadores y procesa el cdigo ubicadoentre #ifndef y #endif, en caso que el identificador [[]] exista, seignora todo el cdigo ubicado en el cuerpo de la llamada a la directiva.

    La tcnica descrita anteriormente es precisamente la que vamos a utilizar paragestionar de manera eficiente, el uso de nuestras libreras. Al revisar la seccinde Flex_LCD, donde se asignan los pines al microcontrolador, nos topamoscon el siguiente cdigo:

    #define LCD_DB4 PIN_B4#define LCD_DB5 PIN_B5#define LCD_DB6 PIN_B6#define LCD_DB7 PIN_B7#define LCD_RS PIN_C0

    #define LCD_RW PIN_C1#define LCD_E PIN_C2

    Ahora simplemente metemos esta seccin de cdigo en el cuerpo de unallamada a #ifndefcon nombre de identificador_FLEX_LCD, el cdigo resultantequedar de la siguiente forma:

    #ifndef _FLEX_LCD#define _FLEX_LCD#define LCD_DB4 PIN_B4#define LCD_DB5 PIN_B5#define LCD_DB6 PIN_B6#define LCD_DB7 PIN_B7#define LCD_RS PIN_C0#define LCD_RW PIN_C1#define LCD_E PIN_C2

    #endif

    Si no definimos nada en el programa principal o en su fichero de cabecera, elpre-procesador asignar a la LCD los pines segn el cdigo de la libreraFlex_LCD. Si queremos modificar la asignacin de pines para nuestro

    proyecto, escribiremos en el fichero principal de nuestro proyecto, o en sufichero de cabecera, el siguiente fragmento de cdigo:

    #define _FLEX_LCD#define LCD_DB4 PIN_C4#define LCD_DB5 PIN_C5#define LCD_DB6 PIN_C6#define LCD_DB7 PIN_C7#define LCD_RS PIN_A0#define LCD_RW PIN_A1#define LCD_E PIN_A2

    #include Flex_LCD.c

  • 8/7/2019 Curso Ccs en PDF

    69/69

    Esto hace que se asignen los pines del microcontrolador a la LCD tal y como seespecifica en nuestro programa principal y que la definicin de la librera seaignorada. Como puede verse, la librera ha sufrido un pequeo cambio que nosayudar a mantener gestionado su uso y nos facilitar la vida a partir de estemomento. Es muy importante que esta asignacin se haga antes de incluir la

    librera (#include Flex_LCD.c), ya que de no hacerlo as, el pre-procesadorasignar los pines segn la definicin que se hace dentro de la librera y seproducir un conflicto con la definicin realizada en el programa principal.

    Con este mtodo, solo tendremos una librera para todos nuestros proyectos yla personalizacin se realizar dentro de cada proyecto; sin que por ellotengamos que hacer copias o modificar el fichero original. Adems, la libreraestar perfectamente localizable dentro de su directorio, por lo que siobtuvisemos una nueva versin, bastar con actualizar y modificar una solacopia.

    Otra razn para utilizar esta forma de proceder, es la posibilidad de reconocerla dependencia entre los distintos archivos de nuestros proyectos o entredistintas libreras. Por ejemplo, si creamos una librera que utilice el displaycomo salida, podremos escribir en el cdigo de nuestra librera:

    #ifndef _FLEX_LCD#error Es necesario incluir la librera Flex_LCD

    #endif

    De esta forma enviamos un mensaje de error para avisar que es preciso incluiruna o varias libreras.

    programas de ejemplo