Anda di halaman 1dari 79

2011

INTRODUCCION A LA
PROGRAMACION DE
MICROCONTROLADORES
PIC EN CCS C
Por John Caipa Roldan
Este material es una traduccin y actualizacin del libro original de Nigel Gardner
titulado "An introduction to programming the Microchip PIC in CCS C", copyright
Bluebird Electronics 2002.

Ing. John F. Caipa Roldan


Institucin Educativa Politcnico "AGS"
18/02/2011
Tabla de contenido
INTRODUCCION .................................................................................................................................. 4
PORQUE USAR C? ........................................................................................................................... 4
TERMINOLOGIA .............................................................................................................................. 5
RECOMENDACIONES EN LA ESCRITURA DE CODIGO C ................................................................... 7
1. FUNDAMENTOS DE C .................................................................................................................. 8
ESTRUCTURA DEL CODIGO C ........................................................................................................... 8
COMPONENTES DEL CODIGO C ....................................................................................................... 9
#PRAGMA ...................................................................................................................................... 10
MAIN() ........................................................................................................................................... 10
#INCLUDE ...................................................................................................................................... 10
FUNCION PRINTF ........................................................................................................................... 11
VARIABLES ..................................................................................................................................... 12
CONSTANTES ................................................................................................................................. 13
COMENTARIOS .............................................................................................................................. 14
FUNCIONES.................................................................................................................................... 14
COMPATIBILIDAD CON HARDWARE.............................................................................................. 15
PALABRAS CLAVES DE C................................................................................................................. 15
2. VARIABLES ................................................................................................................................ 17
TIPOS DE DATOS ............................................................................................................................ 17
DECLARACION DE VARIABLES........................................................................................................ 18
ASIGNACION DE VALORES A VARIABLES ....................................................................................... 20
ENUMERACION ............................................................................................................................. 21
TYPEDEF......................................................................................................................................... 22
CONVERSION DE TIPO ................................................................................................................... 23
CLASES DE ALMACENAMIENTO PARA VARIABLES ........................................................................ 23
3. FUNCIONES ............................................................................................................................... 25
FUNCIONES.................................................................................................................................... 25
FUNCION PROTOTIPO ................................................................................................................... 25
VOID .............................................................................................................................................. 27
USANDO LOS ARGUMENTOS DE UNA FUNCION ........................................................................... 27
USANDO FUNCIONES QUE RETORNAN VALORES ......................................................................... 28

1
DECLARACION CLASICA Y MODERNA DE FUNCIONES .................................................................. 30
PASANDO CADENAS CONSTANTES A FUNCIONES ........................................................................ 31
4. OPERADORES ............................................................................................................................ 32
OPERADORES ARITMETICOS ......................................................................................................... 32
OPERADORES RELACIONALES ....................................................................................................... 33
OPERADORES LOGICOS ................................................................................................................. 34
OPERADORES DE BIT A BIT ............................................................................................................ 34
OPERADORES INCREMENTALES Y DECREMENTALES .................................................................... 36
PRECEDENCIA DE OPERADORES .................................................................................................... 37
5. DECLARACIONES DE CONTROL DEL PROGRAMA ..................................................................... 39
DECLARACION if .......................................................................................................................... 39
DECLARACION if-else .............................................................................................................. 40
OPERADOR ? ................................................................................................................................. 42
DECLARACION for ....................................................................................................................... 42
DECLARACION while................................................................................................................... 43
DECLARACION do-while ........................................................................................................... 44
DECLARACIONES DE CONTROL ANIDADAS.................................................................................... 45
DECLARACION break................................................................................................................... 46
DECLARACION continue ........................................................................................................... 46
DECLARACION switch ................................................................................................................ 47
DECLARACION null(;) .............................................................................................................. 49
DECLARACION return ................................................................................................................ 50
6. ARREGLOS Y CADENAS ............................................................................................................. 51
ARREGLOS UNIDIMENSIONAL ...................................................................................................... 51
CADENA DE CARACTERES .............................................................................................................. 53
ARREGLOS MULTIDIMENSIONALES ............................................................................................... 54
INICIALIZANDO ARREGLOS ............................................................................................................ 55
ARREGLOS DE CADENAS ................................................................................................................ 56
FUNCIONES PARA MANIPULAR CADENAS .................................................................................... 56
7. PUNTEROS................................................................................................................................. 58
INTRODUCCION A LOS PUNTEROS ................................................................................................ 58

2
RESTRICCIONES PARA PUNTEROS ................................................................................................. 59
PUNTEROS Y ARREGLOS ................................................................................................................ 61
PASANDO PUNTEROS A FUNCIONES ............................................................................................. 62
8. ESTRUCTURAS Y UNIONES........................................................................................................ 64
INTRODUCCION A LAS ESTRUCTURAS ........................................................................................... 64
PUNTEROS A ESTRUCTURAS.......................................................................................................... 67
INTRODUCCION A LAS UNIONES ................................................................................................... 69
9. LENGUAJE C ESPECIFICO PARA PIC ........................................................................................... 71
ENTRADAS Y SALIDAS .................................................................................................................... 71
MEZCLANDO C Y ASSEMBLER ........................................................................................................ 73
MANIPULACION AVANZADA DE BIT .............................................................................................. 75
TEMPORIZADORES ........................................................................................................................ 76

3
INTRODUCCION

Un gran avance en la programacin de microcontroladores son las herramientas que utilizan el


lenguaje de alto nivel C como es el caso del compilador C de CCS. Con dicha herramienta
teniendo algo de conocimiento del lenguaje C facilita mucho el desarrollo de programas y
aplicaciones con microcontroladores, en este caso el PIC de Microchip. El lector de este material
aunque debe tener las bases de la programacin en el lenguaje Assembler y conocer las
caractersticas principales de los microcontroladores PIC no debe preocuparse, ya que el objetivo
de este material es presentar los fundamentos del lenguaje C apoyado en algunos ejemplos y
ejercicios, con la finalidad de que el lector tenga las bases necesarias para empezar su camino en
el desarrollo de aplicaciones con PIC utilizando el compilador C de CCS y el Simulador PROTEUS
de Labcenter Electrnics.

Para el desarrollo de los ejemplos y ejercicios que se muestran en el transcurso del libro se
recomienda sean compilados en Microsoft Visual C++ Express, el cual puede descargarse
gratuitamente de la pgina de Microsoft. El Microcontrolador empleado en este material es
el PIC16F84A de Microchip, adems los programas ejemplo que utilizan este
Microcontrolador se escribieron y compilaron en PIC C Compiler de CCS.

PORQUE USAR C?

El lenguaje C fue desarrollado en los laboratorios Bell a finales de los 60s por Dennis Ritchie y Brian
Kernighan. Una de las primeras plataformas para su implementacin fue PDP-11 que corra bajo el
ambiente UNIX. Desde su introduccin, este ha evolucionado, estandarizado y se ha establecido
en toda la industria de software como el lenguaje de programacin ms empleado.

C es un lenguaje portable desarrollado para tener mnimas modificaciones cuando se transfieran


programas de un computador a otro. Esto est bien cuando se trabaja con PCs y capas principales.
Pero los Microcontroladores y Microprocesadores son un caso diferente. El flujo del programa
principal bsicamente permanece sin cambios, pero las diferentes configuraciones de puertos y
control de perifricos son especficos para cada Microcontrolador. Un ejemplo de esto es que los
registros de puertos sobre un PIC son configurados 1=Input (entrada) 0=Output (salida), mientras
que en H8 son 0=Input (entrada) 1=Output (salida).

El uso del lenguaje C en las aplicaciones con Microcontroladores es debido a que provee
programas ms complejos con un desarrollo ms fcil y tiempo de diseo ms corto comparado
con el lenguaje Assembler, pero con el inconveniente que no es tan eficiente en lo relacionado
con memoria de programa.

4
TERMINOLOGIA

Comencemos con la terminologa bsica empleada en este contexto.

Microcontrolador Es un circuito integrado programable que contiene todos los componentes


necesarios para controlar el funcionamiento de una tarea determinada. El Microcontrolador
empleado en este libro es el PIC16F84A de Microchip (Fig. 1).

I/O Pin de conexin con el mundo exterior que puede ser configurado como entrada o salida. I/O
es necesario en la mayora de los casos para permitirle al Microcontrolador comunicarse, controlar
y leer informacin.

Software La informacin que el Microcontrolador necesita para operar o correr. Este tiene que
estar libre errores para una aplicacin exitosa. Puede ser escrito en una variedad de lenguajes
como C, Pascal o Assembler.

Hardware El Microcontrolador, memorias, perifricos, fuentes de voltaje, y todos los dems


componentes conectados a este para hacer que trabaje y se comunique con el mundo exterior.

Simulador Aplicacin en la que puede probar y depurar sus diseos de manera interactiva y
rpida evitando la programacin del dispositivo real, ejemplo: ISIS PROTEUS .

Programador Unidad que permite al programa ser cargado dentro de la memoria del
Microcontrolador. Estos vienen en diferentes formas, protocolos de comunicacin y precios,
ejemplos: PICSTART PLUS, PICKIT de Microchip.

Archivo Fuente Programa escrito en un lenguaje como Assembler o C que usted puede
entender. Este archivo tiene que procesarse antes de que el Microcontrolador lo reciba.

Compilador Paquete software que convierte al archivo fuente en un archivo objeto. El


compilador C que se utiliza en este material es PIC C Compiler de CCS.

Archivo Objeto Archivo que se produce despus de compilar el archivo fuente. La extensin es
.OBJ o .HEX, y es el archivo que necesita el Simulador y el Microcontrolador para funcionar.

5
(a)

(b)

Fig. 1. (a) Diagrama de pines PIC16F84A, (b) Diagrama de bloques PIC16F84A


Fuente: http://ww1.microchip.com/downloads/en/devicedoc/35007b.pdf

6
RECOMENDACIONES EN LA ESCRITURA DE CODIGO C

La escritura de un programa es como construir una casa, si la base es firme, el resto del cdigo
permanecer solido. Pero si la base es dbil, el cdigo perder su firmeza en algn punto. Las
siguientes recomendaciones tomadas del estndar C++ han sido adaptadas para el PIC.

Etiquetas Defnalas para que identifiquen su funcin


Los nombres de las etiquetas son el corazn de la programacin, as que defnalas
apropiadamente a su funcin y su uso en el programa.

Ejemplo: use ErrorCheck en vez de ERRORCHECK.

Corchetes o llaves selas de manera ordenada, ejemplo:

if (condicin)
{

}

Tabulacin e Indentacin
Use espaciado en lugar de tabulacin (8 espacios), recuerde que la configuracin de tabulacin de
un editor no es la misma en otro, haga el cdigo portable, utilice Indentacin para que su cdigo
luzca organizado.

Longitud de lnea
Mantenga una longitud de lnea de mximo 78 caracteres para mantener compatibilidad entre
monitor e impresora.

Formato de instruccin else if


Se puede incluir una instruccin else extra para decidir cualquier condicin no cubierta por las
instrucciones precedentes if, ejemplo:
if (condicion1)
{
}
else if (condicin2)
{
}
else
{
//decide cualquier condicin no cubierta anteriormente
}

Inicialice todas las variables


Coloque todas las variables en un valor conocido para prevenir condiciones aleatorias o flotantes.

Comentarios
Los comentarios permiten descifrar la historia que usted est escribiendo. Usted sabe como su
programa est funcionando hoy pero en dos semanas o dos aos podr recordar, o puede alguien
diferente entender su programa como lo tiene ahora?
Use comentarios para marcar reas donde hay que hacer alguna modificacin, errores a depurar o
complementos futuros de su cdigo.

7
1. FUNDAMENTOS DE C

Este captulo presenta algunos de los aspecto clave del lenguaje de programacin C. Se entregar
una vista rpida de cada aspecto. El objetivo es proporcionar al lector un conocimiento bsico de C
tal que puede comprender los ejemplos de los siguientes captulos.

ESTRUCTURA DEL CODIGO C

Todos los programas escritos en C contienen: directivas del preprocesador, declaraciones,


definiciones, expresiones, instrucciones y funciones.

Directivas del preprocesador


Una directiva es un comando del preprocesador de C (el cual es invocado automticamente como
el primer paso en la compilacin de un programa). Las directivas ms comunes son la directiva
#define, la cual substituye una etiqueta por un identificador especifico, y la directiva
#include, la cual incluye funciones de un archivo externo al programa actual.

Declaraciones
Una declaracin establece el nombre y atributos de las variables, funciones y tipos usados en el
programa. Las variables globales son declaradas fuera de las funciones y son visibles desde el final
de la declaracin hasta el final del archivo. Una variable local es declarada dentro de una funcin y
es visible desde el final de la declaracin hasta el final de la funcin.

Definiciones
Una definicin establece el contenido de una variable o funcin. Una definicin tambin asigna el
espacio de almacenaje necesario para las variables y funciones.

Expresiones
Una expresin es una combinacin de operadores y operandos que producen un nico valor

Instrucciones
Controlan el flujo y orden en la ejecucin del programa en un cdigo C.

Funciones
Una funcin es una coleccin de declaraciones, definiciones, expresiones e instrucciones que
desempean una tarea especfica. Los corchetes encierran el cuerpo de una funcin. Las funciones
no se pueden anidar en C.

Funcin main
Todos los programas hechos en C deben incluir una funcin llamada main donde la ejecucin del
programa comienza. Los corchetes que encierran la funcin main definen el comienzo y punto de
finalizacin del programa.

El siguiente ejemplo muestra la estructura general de un programa C escrito en Microsoft Visual


C++ Express, el cual puede descargarlo desde la web de Microsoft.

#include <stdio.h> /* directiva del preprocesador */


/* Incluye el encabezado estndar de C*/
#define PI 3.142 /* define una constante simblica */

8
float area; /* declaracin variable global */
int cuadrado (int r);

void main()
{ /* Comienza la funcin main */
int radio_alCuadrado; /* declaracin variable local */
int radio = 3; /*declaracin e inicializacin*/
radio_alCuadrado = cuadrado(radio); /*funcin de usuario*/
area = PI * radio_alCuadrado;
printf("El area es %6.4f unidades cuadradas\n",area);
getchar(); /* funcin de terminacin*/
} /*fin de la funcin main */
int cuadrado(int r) /* encabezado de la funcin*/
{
int r_alCuadrado;
r_alCuadrado = r * r;
return(r_alCuadrado);
}

COMPONENTES DEL CODIGO C

Todos los programas escritos en C contienen ciertos componentes esenciales tales como
instruccin y funciones. Las instrucciones son la parte del programa que realiza las operaciones.
Todos los programas en C contienen una o ms funciones. Las funciones son subrutinas, cada una
de las cuales contienen una o ms instrucciones y pueden ser llamada por otras partes del
programa. Cuando escribe programas con lneas en blanco, usar indentacin y comentarios mejora
la visualizacin, no solo para usted en el futuro, sino tambin para aquellas personas interesadas
en su trabajo. El siguiente ejemplo muestra algunas de las partes requeridas de un programa en C.

#include <stdio.h>
/* mi 1er codigo en C */
void main()
{
printf("Hola Mundo!");
getchar(); /* termina el programa oprimiendo ENTER */
}

La sentencia #include <stdio.h> le dice al compilador que incluya el archivo fuente


llamado stdio.h al programa.

La extensin .h pertenece a archivos de encabezado. Un archivo de encabezado contiene


informacin acerca de funciones estndar que est usando el programa como printf() y
getchar(). El archivo stdio.h (Standard Input and Output), contiene muchas de las
funciones de entrada y salida.

/* mi 1er cdigo en C */ es un comentario en C. Todos los comentarios estn


precedidos por un /* y terminan con un */. Los comentarios son ignorados por el compilador y
por consiguiente no afectan la velocidad ni el tamao del cdigo compilado.

Todos los programas escritos en C deben tener la funcin main(). Esta funcin es el punto de
entrada del programa. Todas las funciones tienen el mismo formato, el cual es el siguiente:

9
TipoFuncion NombreFuncion()
{
Cdigo;
}

Las instrucciones dentro de una funcin son ejecutadas secuencialmente, comenzando con el
corchete abierto y terminando con el corchete cerrado.
Los corchetes {} muestran el comienzo y el fin de bloques de cdigo en C.

Finalmente, printf("Hola Mundo"); representa una instruccin tpica en C. Casi todas las
instruccin en C terminan con punto y coma (;). El carcter final de lnea no es reconocido por C
como un terminador de lnea. En consecuencia, no hay restricciones sobre la posicin de las
instrucciones en una lnea ni del nmero de estas.

Todas las lneas tienen un punto y coma (;) al final para informar al compilador que ha alcanzado el
final de la instruccin. El error comn de no incluirlo es sealado como error en la lnea siguiente.
La excepcin a esta regla es con el comando if donde el punto y coma necesita estar al final de
la siguiente lnea, ejemplo:

if (EstoEsVerdad)
HagaEstaFuncion();

#PRAGMA

El comando pragma le informa al compilador que desempee una accin particular al momento
de realizar la compilacin como el PIC especifico usado en la aplicacin. Ejemplo:

#pragma device PIC16F84A

En CCS C el comando pragma es opcional, el siguiente comando es el que ms se utiliza:

#device PIC16F84A

MAIN()

Como ya se ha dicho anteriormente todo programa debe incluir una funcin main la cual puede
aparecer solo una vez en el programa. Ningn parmetro es necesario dentro de los parntesis
(). Como main est clasificada como funcin, todo el cdigo siguiente a esta funcin debe estar
dentro de un par de corchetes {}.

void main()
{
Cuerpo del programa
}

#INCLUDE

El archivo de encabezado, (denotado por la extensin .h) contiene informacin acerca libreras de
funciones tales como registros especiales de un PIC especfico, etc. Ejemplo:

#include <16F84A.h>

10
Esta informacin la utiliza el compilador para conectar detalles especficos de hardware y el
programa fuente. El siguiente ejemplo es hecho en el compilador C de CCS.

#include <16F84A.h> //definicion del PIC especifico


#include <ctype.h>
#fuses XT,NOWDT, PUT, NOPROTECT //palabra de configuracin
#use delay(clock=4000000) //frecuencia del oscilador
#use rs232(baud=9600,xmit=PIN_B0,rcv=PIN_B1)

void main()
{
Printf("Escriba caracteres:");
while(TRUE)
putc(toupper(getc())); //toupper convierte a maysculas
}

Las definiciones de PIN_B0 y PIN_B1 se encuentran en el archivo de encabezado 16F84A.h.


La funcin toupper() se encuentra en el archivo de encabezado ctype.h. Ambos archivos
deben estar en el programa para que el compilador tenga la informacin acerca de las funciones
que usted est usando.

Habr notado probablemente que la directiva #include no termina con punto y coma. La razn
para esto es que esta directiva no es una palabra clave de C, pero en cambio es una instruccin del
compilador. Todo el contenido de la librera incluida es insertado en el archivo fuente en la etapa
de compilacin.

FUNCION PRINTF

Es una funcin estndar contenida en el archivo de encabezado stdio.h. printf() le


permite al programa imprimir informacin en pantalla. El formato general para printf() es:

printf("Texto de control", Argumentos);

Texto de control es una cadena de caracteres entre comillas dobles. La cadena de


caracteres puede ser una combinacin de letras, nmeros y smbolos. Algunos smbolos especiales
de formato estn denotados con el smbolo %. Argumentos es una entrada opcional y puede
estar compuesto por constantes y variables que utilice el programa y que se quieren imprimir. Los
siguientes dos ejemplos muestran a printf() imprimiendo un mensaje e imprimiendo una
constante del programa.

printf("Hola Mundo!");
printf("Microchip es el #%d!",1);

%d da el formato para la constante que se est imprimiendo. La Tabla 1 muestra todos los
especificadores de formato de C y el tipo de datos que afectan.

11
Tabla 1. Especificadores de formato en C.
Especificador de formato Tipo de dato que afecta
%c Carcter sencillo
%uc Carcter sin signo
%s Cadena de caracteres
%d Enteros decimales con signo
%f Punto flotante (notacin decimal)
%e Punto flotante (notacin exponencial o cientfica)
%g Punto flotante (%f o %e, cualquiera en su formato
corto)
%u Enteros decimales sin signo
%x, %X Enteros hexadecimales sin signo
%p Apuntador
%o Enteros octales sin signo
l Prefijo usado con %d, %u, %x, %o para especificar
entero largo

NOTA: Un 0 (cero) seguido del smbolo % dentro de un formato de cadena obliga a imprimir los
ceros que estn al comienzo. El siguiente nmero especifica el tamao del campo a imprimir.
Ejemplo:

printf("El Hex del decimal 12 es %03x\n",12);

Imprime en pantalla lo siguiente:

El Hex del decimal 12 es 00c

Tabla 2. Caracteres especiales.


Smbolos Especiales
\n Lnea nueva \? Smbolo de
interrogacin
\t Tab horizontal \a Beep
\r Retorno de carro \b Backspace
\f Formfeed \0 Carcter nulo(null)
\ Comilla sencilla \v Tab vertical
\ Comilla doble \xhhh Inserta cdigo hex
hhh
\\ Backslash %% Signo de porcentaje

El formato de especificacin puede ser tambin as: %[flags][ancho][.presicion],


entonces retomando un ejemplo anterior:

printf("El area es %6.4f unidades cuadradas\n",area);

Esta instruccin imprime en pantalla el valor de area en un espacio con ancho de 6 y precisin
decimal de 4 posiciones.

VARIABLES

Una variable es un nombre que se le da a una localizacin especfica de memoria. Esta localizacin
de memoria puede guardar varios valores dependiendo de cmo haya sido declarada la variable.
En C, todas las variables deben declararse antes de ser usadas. Una declaracin de variables le

12
informa al compilador que tipo de variable est siendo usada. Todas las declaraciones de variables
son instrucciones en C y por consiguiente deben finalizar con un punto y coma.

Los cinco tipos bsicos de datos que soporta C son: char, int, float, double, void. El
formato general para declarar una variable es el siguiente:

TipoVariable NombreVariable;

Un ejemplo de declaracin de un variables es: char ch;. El compilador interpreta esta


instruccin como la definicin de la variable ch como tipo char (caracter o entero sin signo de 8
bits).

CONSTANTES

Una constante es un valor fijo que no puede ser alterado por el programa. Por ejemplo, 25 es una
constante. Las constantes enteras son especificadas sin ninguna componente fraccional como -100
o 40. Constantes en punto flotante requieren punto decimal seguido por su componente
fraccional. El nmero 456.75 es una constante en punto flotante. Los caracteres tambin son
constantes y deben estar encerradas por comillas sencillas como 'A' o '&'.

Cuando el compilador encuentra una constante en el programa, este decide qu tipo de constante
es. El compilador C podr, por defecto, acomodar la constante dentro del tipo de dato ms
pequeo que lo pueda contener. As que 15 es un tipo int, 64000 es un tipo long y 105020 es
un tipo int32.
Una constante es declarada usando la sentencia #define.

#define <etiqueta> valor

<etiqueta> define el nombre que usar a travs del programa, valor es el valor que se le
asignara a <etiqueta>. Ejemplos:

#define VERDADERO 1
#define pi 3.14159265359

Usted puede especificar el tipo de constante usando los siguientes sufijos:

F punto flotante FL long double


U unsigned L long

C le permite especificar constantes en los formatos hexadecimal y octal. Las constantes


hexadecimales deben tener el prefijo '0x'. Por ejemplo 0xA4 es una constante hexadecimal valida.
En adicin a las constantes numricas, C soporta constantes tipo string (cadena de caracteres).
Las cuales son una serie de caracteres encerrados entre comillas dobles.

Las constantes no son almacenadas en memoria, son resueltas en tiempo de compilacin. Para
guardar constantes en la memoria ROM del chip, use la palabra clave const en la declaracin de
una variable. Por ejemplo:

char const id[5]={"1234"};

13
Se estn usando cinco localizaciones de memoria para guardar la cadena porque esta debe
terminar con el carcter null (\0) como se explicar ms adelante.

COMENTARIOS

Los comentarios son empleados para documentar el significado y operacin del cdigo fuente.
Todos los comentarios son ignorados por el compilador. Un comentario puede ser puesto en
cualquier parte del programa excepto en la mitad de alguna instruccin, nombre de funcin o
nombre de variable. Los comentarios pueden abarcar muchas lneas y pueden ser usados para
remover temporalmente una lnea de cdigo. Finalmente, los comentarios no se pueden anidar.

Los comentarios tienen dos formatos. El primer formato es usado por todos los compiladores de C
y es el siguiente:

/* Este es un comentario */

El segundo formato es soportado por la mayora de compiladores y es el siguiente:

// Este es un comentario

FUNCIONES

Las funciones son los bloques de construccin bsicos de un programa en C. todos los programas
en C contienen al menos una funcin, main(). La mayora de los programas que usted escribe
contendr muchas funciones. El formato para un programa en C con muchas funciones es el
siguiente:

void main()
{
}
funcion1()
{
}
funcion2()
{
}

main() es la primera funcin llamada cuando el programa se est ejecutando. Las otras
funciones, funcion1() y funcion2(), pueden ser llamadas por cualquier otra funcin en el
programa.

Tradicionalmente main() no es llamada por ninguna otra funcin, sin embargo, no hay
restricciones en C con respecto a esto.

El siguiente es un ejemplo de dos funciones en C.

#include <stdio.h>

void main()
{
printf("Me ");

14
funcion1();
printf("C.");
}

funcion1()
{
printf("gusta programar en");
}

Una cuestin que hay que tener en cuenta al escribe sus propias funciones es que cuando el
corchete de cierre es alcanzado, el programa continuar ejecutndose una lnea despus del
punto en el cual la funcin ha sido originalmente llamada.

COMPATIBILIDAD CON HARDWARE

El compilador necesita saber acerca del hardware para que el cdigo pueda ser compilado
correctamente. Un programa tpico en el compilador C de CCS puede comenzar as:

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)

La primera lnea incluye las definiciones especficas del dispositivo tales como nombre de pines,
registros especiales, etc. La segunda lnea establece la palabra de configuracin del PIC, para este
caso se deja al oscilador de cristal como oscilador del dispositivo, se desactiva el Watch Dog Timer,
se habilita el Power-up Timer y se desactiva la proteccin de cdigo. La ltima lnea le informa al
compilador la velocidad del oscilador. Las siguientes lneas son otro ejemplo:

#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7) //config. RS232


#use i2c(master,scl=PIN_B6,sda=PIN_B7) //config. I2C

En adicin, las variables de C pueden ser creadas y mapeadas a registros del hardware. Estas
variables pueden ser bits o bytes. Despus que son definidas, pueden ser utilizadas en un
programa como cualquier otra variable. Ejemplo:

#bit carry=3.0
#byte portb=6
#byte intcon=11

PALABRAS CLAVES DE C

El estndar C ANSI define 32 palabras clave para usar en el lenguaje C. En C, ciertas palabras son
reservadas del compilador para definir tipos de datos y para su uso en loops (bucles o lazos). Todas
las palabras claves de C deben escribirse en minscula para que el compilador las reconozca.
Tpicamente, la mayora de los compiladores de C agregan varias palabras adicionales que toman
ventaja de la arquitectura del procesador.

La siguiente es una lista de las palabras claves de C:

15
auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while

Ejercicios

1. Escriba un programa en Microsoft Visual C++ Express que imprima en pantalla su


nombre, su documento de identidad y su email e lneas diferentes.
2. Escriba un programa en Microsoft Visual C++ Express que declare una variable tipo entera
llamada year. Esta variable debe entregar el valor del ao actual y luego, usando la
funcin printf(), mostrar el valor del ao en pantalla. El resultado de su programa
debe parecerse a lo siguiente:

El ao es 2011.

16
2. VARIABLES

Un aspecto importante del lenguaje C es como este almacena datos. Este captulo examinar ms
en detalle cmo se usan las variables en C para almacenar datos.

TIPOS DE DATOS

El lenguaje de programacin C soporta cinco tipos de datos bsicos (como se haba comentado en
el capitulo anterior) y cuatro tipos de modificadores. La Tabla 3 muestra la definicin de los tipos
de datos bsicos y el tipo de modificador.

Tabla 3. Tipos de datos y modificadores en C.


Tipo Significado Palabra clave
Carcter Dato carcter char
Entero Nmeros enteros con signo int
Flotante Nmeros con punto flotante float
Doble precisin Nmeros con punto flotante de doble precisin double
Vacio (void) Sin valor void
Con signo Nmeros positivos o negativos signed
Sin signo Solo nmeros positivos unsigned
Largo Duplica el tamao de un nmero long
corto Mitad del tamao de un nmero short

Cada tipo de dato representa un rango particular de nmeros, que pueden cambiar dependiendo
del modificador usado. La Tabla 4 muestra los posibles rangos de valores para algunos tipos de
datos bsicos y los modificadores en CCS C.

Tabla 4. Rangos de valores de los tipos de datos en CCS C.


Tipo Tamao bit Rango
short (int1) 1 0 a 1
int (int8) 8 0 a 255
long (int16) 16 0 a 65535
long long (int32) 32 0 a 4294967295
float (float32) 32 -1.5E45 a 3.4E38
char (unsigned int8) 8 0 a 255
void - Sin valor
signed int8 8 -128 a 127
signed int16 16 -32768 a 32767
signed int32 32 -2147483648 a 2147483647

NOTA: revisar la documentacin del compilador C para tipos de datos y rangos numricos
actualizados. Todos los tipos, excepto float, por defecto son unsigned.

C permite una notacin ms corta para los tipos unsigned int, short int, y long
int. Simplemente use las palabras unsigned, short o long sin la palabra int. Para realizar
las operaciones aritmticas de una forma sencillas para la CPU, C representa todos los nmeros
negativos en el formato complemento a 2. Para encontrar el complemento a 2 de un nmero
simplemente invierta todos los bits y sume 1 al resultado. Por ejemplo, para convertir el nmero
con signo +29 en complemento a 2 se procede as:

17
00011101= 29
11100010 se invierten todos los bits
+ 1 se suma 1
________
11100011= -29

Ejercicios

1. Escriba la siguiente declaracin de otra manera.


long int i;

2. Para entender la diferencia entre un nmero con signo y uno sin signo, escriba el siguiente
programa en Microsoft Visual C++ Express. El entero sin signo 35000 es representado por
-30536 en el formato entero con signo.

#include <stdio.h>

void main()
{
short int i; // entero con signo equiv. a signed int16 en CCS
unsigned short int u; // entero sin signo equiv. a int16 en CCS
u = 35000;
i = u;
printf("%d %u\n",i,u);
getchar();//detiene la ejecucin hasta oprimir ENTER
}

DECLARACION DE VARIABLES

Las variables pueden ser declaradas en dos lugares bsicos: dentro de una funcin o por fuera de
todas las funciones. Las variables son llamadas locales o globales respectivamente. Las variables
son declaradas de la siguiente forma:

TipoVariable NombreVariable;

Donde TipoVariable es uno de los tipos de datos validos en C y NombreVariable es el


nombre asignado a la variable. Las variables locales (declaradas dentro de una funcin) solo
pueden ser usadas por las instrucciones dentro de la funcin donde ha sido declarada.

El valor de una variable local no puede ser accesado por otras funciones por fuera de la funcin de
origen. La cosa ms importante a recordar acerca de las variables locales es que son creadas al
momento de entrar a la funcin y destruidas cuando la funcin ha finalizado. Las variables locales
deben declararse al comienzo de la funcin antes de las instrucciones.

Es aceptable para variables locales que estas tengan nombres iguales en diferentes funciones.
Considere el siguiente ejemplo.

#include <stdio.h>

void f2()
{
int cont;
for (cont=0; cont<10; cont++)

18
printf("%d \n",cont);
}
void f1()
{
int cont;
for (cont=0; cont<10; cont++)
f2();
}
int main()
{
f1();
getchar();
return 0;
}

Este programa imprime los nmeros del 0 al 9 en pantalla 10 veces. La operacin del programa no
es afectada por la variable cont que est definida en ambas funciones.

Las variables globales, por otra parte, pueden ser usadas por todas las funciones definidas en el
programa. Las variables globales deben ser declaradas antes que cualquier funcin que las vaya a
usar. Lo ms importante, las variables locales no son destruidas hasta que la ejecucin del
programa haya sido completada.

El siguiente ejemplo muestra como se emplean las variables globales.

#include <stdio.h>
int max;

void f1()
{
int i;
for (i=0; i<max; i++)
printf("%d ",i);
}

int main()
{
max = 10;
f1();
return 0;
}

En este ejemplo, ambas funciones main() y f1() hacen referencia a la variable max. La funcin
main() asigna un valor a max y la funcin f1() usa el valor de max para controlar el bucle del
for.

Ejercicios

1. Cules son las diferencias principales entre variables locales y variables globales?
2. Ambos tipos de variables podran compartir el mismo nombre en C?. Escriba el siguiente
programa.

#include <stdio.h>
int cont;

void f1()

19
{
int cont;
cont = 100;
printf("contador en f1(): %d\n ",cont);
}

int main()
{
cont = 10;
f1();
printf("contador en main(): %d\n ",cont);
return 0;
}

En la funcin main() la referencia a cont es una variable global. En la funcin f1() la variable
local cont domina sobre el uso de la variable global.

ASIGNACION DE VALORES A VARIABLES

Hasta el momento se ha discutido solo como declarar una variable en el programa y no realmente
como se asignan valores a esta. La asignacin de valores a variables es sencilla, as:

NombreVariable = valor;

Debido a que la asignacin de valores a variables se hace con una instruccin, se debe incluir el
punto y coma al final. Un ejemplo de cmo asignar el valor 100 a la variable tipo entera cont es:

cont = 100;

El valor 100 es una constante. Diferentes tipos de constantes existen en C. una constante tipo
carcter esta especificado porque debe estar encerrada en comillas sencillas, como 'M'. Todos los
nmeros enteros se emplean cuan se asignan valores a enteros. Nmeros en punto flotante deben
usar valores con punto decimal. Por ejemplo, para decirle a C que el valor 100 est en punto
flotante, use 100.0.

A una variable tambin se le puede asignar el valor que tiene otra variable diferente. El siguiente
programa ilustra esta asignacin.

void main()
{
int i;
int j;

i=0;
j=i;
}

Ejercicios

1. Escriba un programa en Microsoft Visual C++ Express que declare una variable tipo
entero llamada cont. De un valor de 100 a cont y use la funcin printf() para
imprimir el valor en pantalla. La salida debe lucir as:

100 es el valor de cont

20
2. Escriba un programa en Microsoft Visual C++ Express que declare tres variables, char,
float, y double con los nombres ch, f, y d. Asignar el valor 'R' a ch, 50.5 a f, y
156.007 a d. Imprima el valor de todas las variables en pantalla. La salida debe lucir como
la siguiente:

ch esta asignada con r


f esta asignada con 50.5
d esta asignada con 156.007

ENUMERACION

En C, es posible crear una lista de constantes enteras. Este tipo de declaracin es llamada
enumeracin. La lista de constantes creadas con enumeracin puede ser usada en cualquier lugar.
La forma general para crear una enumeracin es la siguiente:

enum nombre {lista de enumeracion} variable(s);

La lista de variables es opcional en la enumeracin. Las variables de enumeracin pueden


contener solo los valores que estn definidos en la lista de enumeracin. Por ejemplo, en la
instruccin:

enum TipoColor {rojo,verde,amarillo} color;

A la variable color solo se le pueden asignar los valores rojo, verde o amarillo (esto es,
color = rojo;).

El compilador asignara valores enteros a la lista de enumeracin comenzando con 0 en la primera


entrada. Cada entrada es una unidad ms grande que la anterior. Por consiguiente, en el ejemplo
anterior rojo es 0, verde es 1 y amarillo es 2. Estos valores por defecto pueden cambiarse
especificando un valor para la constante. El siguiente ejemplo ilustra la tcnica.

enum TipoColor {rojo,verde=9,amarillo} color;

Esta instruccin asigna 0 a rojo, 9 a verde y 10 a amarillo.

Una vez la enumeracin es definida, el nombre puede usarse para crear variables adicionales en
otros puntos del programa. Por ejemplo, la variable MiColor puede crearse con la enumeracin
TipoColor asi:

enum TipoColor MiColor;

La variable tambin puede probarse contra otro variable diferente:

if (color==fruta)
//haga esto

Esencialmente, enumeracin ayuda a documentar el cdigo. En lugar de asignar un valor a una


variable, una enumeracin puede usarse para distinguir el significado del valor.

21
Ejercicios

1. Crear una enumeracin con la familia de microcontroladores PIC16F8X.


2. Crear una enumeracin con la denominacin de la ms baja a la ms alta de la moneda
colombiana.
3. El siguiente fragmento de cdigo es correcto? Por qu?

enum {PIC16C51,PIC16C52,PIC16C53} dispositivo;


dispositivo = PIC16C52;
printf("el primer PIC es %s\n", dispositivo);

TYPEDEF

La declaracin typedef es usada para definir nuevos tipos de datos por medio de tipos
existentes. Su formato es el siguiente:

typedef NombreAnterior NombreNuevo

El nuevo nombre puede usarse para declarar variables. Por ejemplo, el siguiente programa usa el
nombre smallint para el tipo signed char.

#include <stdio.h>
typedef signed char smallint;
void main()
{
smallint i;
for(i=0;i<10;i++)
printf("%d ",i);
}

Cuando se usa typedef, usted debe recordar dos puntos clave: La declaracin typedef no
desactiva el nombre original o el tipo, en el ejemplo anterior signed char todava es un tipo
valido; varias declaraciones typedef pueden usarse para crear nuevos nombres para el mismo
tipo original.

Typedef es tpicamente usado por dos razones. La primera para crear un programa portable. Si
el programa que se est escribiendo va a ser usando en maquinas con enteros de 16-bits y de 32-
bits, usted querra asegurar que solo los enteros de 16-bits van a ser empleados. La segunda razn
para usar la declaracin typedef es para ayudarle a documentar su cdigo.

Ejercicios

1. Crear un nuevo nombre para el tipo unsigned long que se llame UL. Use este
typedef en un programa corto que declare una variable usando UL, asigne un valor a
est y muestre el valor en pantalla.

2. El siguiente fragmento de cdigo es correcto?

typedef int altura;


typedef altura largo;
typedef largo profundo;
profundo d;

22
CONVERSION DE TIPO

C le permite combinar diferentes tipos de datos en una sola expresin. Por ejemplo, el siguiente
ejemplo es un fragmento de cdigo valido:

char ch = '0';
int i = 15;
float f = 25.6

La combinacin de tipos de datos es gobernado por un conjunto estricto de reglas de conversin


que le informan al compilador como resolver las diferencias. La primera parte del conjunto de
reglas es una promocin de tipo. El compilador C automticamente promover un dato char o
short int en una expresin a un dato int cuando la expresin sea evaluada. Una promocin
de tipo solo es vlida durante la evaluacin de la expresin; la variable por s misma no se hace
fsicamente ms larga.

Ahora que la promocin de tipo automtica ha sido completada, el compilador C convertir todas
las variables en una expresin sobre el tipo de la variable ms larga. Esta tarea se completa sobre
una operacin por medio de operaciones bsica. El siguiente fragmento de cdigo muestra como
imprimir la porcin entera de un nmero en punto flotante:

float f;
f = 100.2;
printf("%d",(int)f);

El numero 100 se imprimir en pantalla al ejecutarse el cdigo. Si dos enteros de 8-bits son
multiplicados, el resultado ser un valor de 8-bits. Si el resultado es asignado a un tipo long, el
resultado todava seguir siendo un entero de 8-bits, debido a que la aritmtica es desarrollada
antes de que el resultado sea asignado a la nueva variable.

int a = 250, b = 10;


long c;
c = a * b;

El resultado ser 196 el cual es errneo. Entonces si necesita un valor tipo long como respuesta,
entonces al menos un valor necesita definirse inicialmente como long o escribir lo siguiente.

c = (long) a * b;

El resultado ser 2500 porque a primero ha sido convertido a tipo long antes que la
multiplicacin se haya completado.

CLASES DE ALMACENAMIENTO PARA VARIABLES

Cada variable y funcin en C tiene dos atributos, el tipo y clase de almacenamiento. El tipo ya ha
sido discutido como char, int, etc. Hay cuatro clases de almacenamiento: automtica, externa,
esttica y registro. Estas clases tienen los siguientes nombres en C:

auto extern static register

23
Auto
Las variables declaradas dentro de una funcin son por defecto auto, tal que.

{
char c;
int a,b,e;
}

Es lo mismo que:

{
auto char c;
auto int a,b,e;
}

Cuando un bloque de cdigo es introducido, el compilador asigna espacio RAM para las variables
declaradas. Las localizaciones RAM son utilizadas en ese bloque local de cdigo y puede ser
usado por otros bloques de cdigo.

Extern
La palabra clave extern declara una variable o una funcin y especfica que esta variable tiene
conexin externa. Esto significa que su nombre es visible en otros archivos diferentes en donde
fue definida. Extern no est definida en el compilador C de CCS.

Static
La clase static define variables globales activas que son inicializadas a cero, a menos que se
defina lo contrario.

void test()
{
char x,y,z;
static int cont = 4;
printf("cont = %d\n",++cont);
}

La variable cont es inicializada una vez, y despus se incrementa cada vez que la funcin test
es llamada.

Register
La clase register se origina de aplicaciones de sistemas donde esta puede ser usada para
reservar memoria de alta velocidad para variables usadas frecuentemente. Register no est
definida en el compilador C de CCS.

24
3. FUNCIONES

Las funciones son los bloques bsicos del lenguaje C. todas las instrucciones deben estar dentro de
funciones. En este captulo se discutir como pasar argumentos a funciones y como recibir un
argumento de una funcin.

FUNCIONES

En secciones anteriores, se estudiaron varios ejemplos de funciones siendo llamadas desde un


programa principal, por ejemplo:

void main()
{
f1();
}
int f1()
{
return 1;
}

En realidad, este programa producir un error. La razn es que la funcin f1() debe declararse o
definirse antes de usarse, tal como las variables. Si est empleando una funcin estndar de C, el
archivo de encabezado que incluye en el comienzo del programa ya ha informado al compilador
acerca de la funcin. Si est empleando una funcin que usted ha creado, hay dos caminos para
corregir este error. Una forma es usar funcin prototipo, que sern explicadas en la siguiente
seccin. La otra forma es reorganizar el programa de la siguiente manera:

int f1()
{
return 1;
}
void main()
{
f1();
}

El error ya no se genera porque la funcin f1() es definida antes que sea llamada en el main().

FUNCION PROTOTIPO

Hay dos mtodos empleados para informarle al compilador que tipo de valor retorna una funcin.
La forma general es la siguiente:

tipo NombreFuncion();

Por ejemplo, la declaracin en sum() podra decirle al compilador que la funcin sum() retorno
un entero. La segunda forma para informarle al compilador acerca del valor que retorna una
funcin es la funcin prototipo. Una funcin prototipo no solo entrega el valor a retornar de la
funcin, sino que tambin declara el nmero y tipo de los argumentos que la funcin acepta. El
prototipo debe corresponder con la declaracin de la funcin exactamente.

25
Los prototipos le ayudan a identificar errores en el programa reportando cualquier conversin
ilegal de tipos entre los argumentos que pasan a una funcin y en su declaracin. Adems reporta
si el nmero de argumentos enviados a una funcin no concuerdan con los especificados en la
declaracin de la funcin.

El formato general para una funcin prototipo es como se muestra a continuacin:

tipo NombreFuncion(tipo var1, tipo var2, tipo var3);

En el ejemplo anterior, el tipo de cada variable puede ser diferente. Un ejemplo de una funcin
prototipo se entrega en el siguiente programa. La funcin calcula el volumen definido por largo,
ancho y alto.

int volumen(int s1, int s2, int s3);

void main()
{
int vol;
vol = volumen(5,7,12);
printf("El volumen es: %d\n",vol);
}
int volumen(int s1, int s2, int s3)
{
return s1*s2*s3;
}

Note que return usa una expresin en lugar de una constante o variable.

La importancia de los prototipos no es significativa en programas cortos, como los que se han
realizado hasta ahora. Sin embargo, cuando el tamao de los programas crezca de unas pocas
lneas a cientos de stas, la importancia de los prototipos en la depuracin de errores ser
evidente.

Ejercicios

1. Para mostrar como los errores son capturados por el compilador, cambie el programa
anterior para mandar cuatro parmetros a la funcin volumen:

vol = volumen(5,7,12,15);

2. El siguiente programa es correcto? por qu?

double myfunc(void);

void main()
{
printf("%f\n",myfunc(10.2));
}
double myfunc(double num)
{
return num/2.0;
}

26
VOID

Se hace una excepcin cuando una funcin no tiene ningn parmetro de entrada ni de salida.
Esta funcin podra declararse como sigue:

void NombreFuncion(void)

Un ejemplo de esto podra ser:

double pi(void) //definicion de la funcion


{ //sin parametros de entrada
return 3.1415926536; //pero retorna el valor de pi
}
void main()
{
double pi_val;
pi_val = pi(); //llama el valor de pi
printf("pi= %f\n",pi_val);
}

USANDO LOS ARGUMENTOS DE UNA FUNCION

Un argumento de funcin es un valor que se le pasa a una funcin cuando se le hace un llamado.
C permite de ningn a varios argumentos en la declaracin de una funcin. El nmero de
argumentos que una funcin puede aceptar depende del compilador, pero el estndar C ANSI
especifica que una funcin debe ser capaz de aceptar al menos 31 argumentos.

Cuando una funcin es definida, deben ser declaradas variables especiales para recibir
parmetros. Estas variables especiales son definidas como parmetros formales. Los parmetros
son declarados entre los parntesis que siguen al nombre de la funcin. Por ejemplo, la funcin
que sigue calcula e imprime la suma de dos enteros que son enviados a la funcin cuando esta es
llamada.

void sum(int a, int b)


{
printf("%d\n",a+b);
}

Un ejemplo de cmo la funcin podra ser llamada en un programa es el siguiente:

void sum(int a, int b); //esto es una funcion prototipo

void main()
{
sum(1,10);
sum(15,6);
sum(100,25);
}
void sum(int a, int b)
{
printf("%d\n",a+b);
}

27
Cuando sum() es llamada, el compilador copiar el valor de cada argumento dentro de las
variables a y b. es importante recordar que los valores pasados a una funcin (1, 10, 15, 6,
100, 25) son llamadas argumentos y las variables a y b son los parmetros formales.

Las funciones pueden pasar argumentos en dos formas. La primera forma es nombrada como
llamado por valor (call by value). Este mtodo copia el valor de un argumento dentro de un
parmetro formal en una funcin. Cualquier cambio hecho a un parmetro formal no afecta el
valor original de la rutina de llamado. El segundo mtodo es nombrado como llamado por
referencia (call by reference). En este mtodo, la direccin del argumento es copiada dentro del
parmetro formal de una funcin. Dentro de esta funcin, el parmetro formal se usa para
acceder a la variable actual en la rutina de llamado. Esto significa que se pueden realizar cambios a
la variable usando el parmetro formal. Este mtodo se discutir en el captulo sobre apuntadores.
Por ahora, solo se usar el primer mtodo cuando se pasen argumentos a una funcin.

Ejercicios

1. Escriba una funcin que tome un argumento entero e imprima su valor en pantalla.
2. Cul es el error en el siguiente programa?

imprimirEsto(int num)
{
printf("%d\n",num);
}
void main()
{
imprimirEsto (156.7);
}

USANDO FUNCIONES QUE RETORNAN VALORES

Cualquier funcin en C puede retornar un valor a la rutina que realiza el llamado. Tpicamente, la
funcin es puesta al lado derecho del signo igual (=). El valor de retorno no necesariamente
necesita usarse en una instruccin asignada, pero puede usarse en una funcin printf(). El
formato general para informarle al compilador que una funcin retorna un valor es el siguiente:

tipo NombreFuncion(parmetros formales)


{
<instrucciones>
return valor;
}

Donde tipo especifica el tipo de dato del valor que retorna la funcin. Una funcin puede
retornar cualquier tipo de dato excepto un arreglo (array). Si no se especifica un tipo de dato,
entonces el compilador C asume que la funcin retorna un entero (int). Si su funcin no retorna
un valor, el estndar C ANSI especifica que la funcin debe retornar nada (void). Esto
explcitamente le informa al compilador que la funcin no retorna un valor. El siguiente ejemplo
muestra un uso tpico para una funcin que retorna un valor.

#include <stdio.h>
#include <math.h>

28
void main()
{
double result;
result = sqrt(16.0);
printf("%f\n",result);
}

Este programa hace un llamado a la funcin sqrt() la cual retorna un nmero en punto flotante.
Este nmero es asignado a la variable result. Note que el archivo encabezado math.h es
incluido debido a que contiene la informacin acerca sqrt() usada por el compilador.

Es importante que el tipo de dato que retorna la funcin sea el mismo tipo de dato de la variable a
la cual se le asignar el valor de retorno. Lo mismo se tiene que garantizar para los argumentos
que se entregan a la funcin.

Entonces, Cmo se debe retorna un valor desde una funcin? La forma general es la siguiente:

return NombreVariable;

Donde NombreVariable es una constante, variable o cualquier expresin valida en C que tenga
el mismo tipo de dato que el valor de retorno. El siguiente ejemplo muestra los dos tipos de
funciones.

int func();
int sum(int a, int b);

void main()
{
int num;
num = func();
printf("%d\n", num);
num = sum(5,127);
printf("%d\n",num);
}

int func()
{
return 6;
}
int sum(int a, int b)
{
int result;
result = a + b;
return result;
}

Una cosa importante para resaltar, es cuando una declaracin return es encontrada, la funcin
retorna inmediatamente a la rutina de llamado. Cualquier instruccin despus del return no
ser ejecutada. El valor retornado de una funcin no requiere ser asignado a una variable o usado
en alguna expresin, sin embargo, el valor se pierde de esta manera.

Ejercicio

1. Cul es el error en la siguiente funcin?

29
void main()
{
double result;
result = f1();
printf("%f\n",result);
}
int f1()
{
return 60;
}

DECLARACION CLASICA Y MODERNA DE FUNCIONES

La versin original de C usa un mtodo diferente para la declaracin de parmetros formales.


Esta forma, llamada la forma clsica, y es la siguiente:

tipo NombreFuncion(var1,var2,,varn)
tipo var1;
tipo var2;

tipo varn;
{
<instrucciones>
}

Note que la declaracin est dividida en dos partes. Solo los nombres de los parmetros son
incluidos dentro de los parntesis. Por fuera de los parntesis el tipo de datos y los nombres
de los parmetros formales son especificados.

La forma moderna, que se ha usado en ejemplos anteriores, es la siguiente:

tipo NombreFuncion(tipo var1,tipo var2,,tipo varn)

En este tipo de declaracin de funcin, tanto el tipo de dato como los nombres de los
parmetros formales son especificados dentro de los parntesis.

El estndar C ANSI permite ambos tipos de declaracin de funciones. El propsito es mantener


la compatibilidad con programas C antiguos donde hay literalmente millones de lneas de
cdigo. Si encuentra la forma clsica en un fragmento de cdigo, no tiene de que preocuparse;
su compilador C debe ser capaz de manejarlo. Como consejo, usted debera usar la forma
moderna cuando escriba su cdigo.

Ejercicios

1. Qu es una funcin prototipo y cules son los beneficios de usarla?

2. Convierta el siguiente programa de la forma clsica de declaracin de funciones a la


forma moderna.

void main(void)
{
printf("area = %d\n", area(10,15));

30
}
area(l,w)
int l,w;
{
return 1*w;
}

PASANDO CADENAS CONSTANTES A FUNCIONES

Debido a que los microcontroladores PIC tienen limitaciones en cuanto a acceso ROM, cadenas de
caracteres constantes (constant strings) no pueden ser pasadas a funciones de la manera
ordinaria.

El compilador C de CCS maneja esta situacin de una manera no estndar. Si una cadena de
caracteres es pasada a una funcin que permita solo un parmetro carcter, entones la funcin es
llamada para cada carcter en la cadena de caracteres. Por ejemplo:

void lcd_putc(char c)
{
. . . . .
}
lcd_putc("abcd");

Es lo mismo que:

lcd_putc("a");
lcd_putc("b");
lcd_putc("c");
lcd_putc("d");

31
4. OPERADORES

En C, las expresiones juegan un papel importante. La razn principal es que C define ms


operadores que la mayora de lenguajes. Una expresin es una combinacin de operadores y
operandos. En la mayora de los casos, los operadores C siguen las reglas del algebra y deben
parecerle familiares.

OPERADORES ARITMETICOS

El lenguaje C define cinco operadores aritmticos para la suma, resta, multiplicacin, divisin y
modulo.

+ suma
- resta
* multiplicacin
/ divisin
% modulo

Los operadores +,-,* y / pueden ser usados con cualquier tipo de dato. El operador modulo, %,
puede usarse solo con nmeros enteros. El operador modulo entrega residuo de una divisin
entre enteros. Por consiguiente, este operador no tiene significado cuando se aplica a nmeros en
punto flotante.

El operador puede usarse de dos formas, la primera siendo el operador de resta. La segunda
forma es para invertir el signo de un nmero. El siguiente ejemplo ilustra las dos formas de
manejar el signo menos:

a = a b; //resta
a = -a; //inversin de signo

Los operadores aritmticos pueden usarse con cualquier combinacin de constantes y/o variables.
Por ejemplo, la siguiente expresin es una instruccin valida en C.

result = cont 163;

C adems permite algunas abreviaturas cuando usa operadores aritmticos. Uno de los ejemplos
anteriores, a = a b; puede escribirse a-=b;. Este mtodo puede usarse con los operadores
+,-,* y /. El siguiente ejemplo muestra varias abreviaturas.

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


a/=b a=a/b
a+=b a=a+b
a-=b a=a-b
a%=b a=a%b
a<<=b a=a<<b
a>>=b a=a>>b
a&=b a=a&b
a|=b a=a|b
a^=b a=a^b

Tomando el cdigo C y comparndolo con su versin en Assembler se muestra a continuacin


como es lograda la funcin aritmtica dentro del PIC.

32
int a,b,c,;
a = b + c;
Se convierte en:
0007: MOVF b,W ;carga b
0008: ADDWF c,W ;suma c con b
0009: MOVWF a ;guarda en a

a = b - c;
Se convierte en:
0007: MOVF b,W ;carga b
0008: MOVWF a ;guarda en a
0009: MOVF c,W ;carga c
000A: SUBWF a,F ;resta c de a

Ejercicios

1. Escriba un programa en Microsoft Visual C++ Express que encuentre el residuo de 5/5,
5/4, 5/3, 5/2, y 5/1.
2. Escriba un programa en Microsoft Visual C++ Express que calcule el nmero de segundos
de un ao.

OPERADORES RELACIONALES

Los operadores relacionales en C comparan dos valores y devuelven un resultado verdadero o


falso basado en la comparacin. Los operadores relacionales son los siguientes:

> mayor que


>= mayor o igual que
< menor que
<= menor o igual que
== igual que
!= diferente que

Una cosa a resaltar acerca de los operadores relacionales es que el resultado de la comparacin es
siempre 0 o 1, aun cuando C defina verdad como cualquier valor diferente de cero. Falso siempre
es definido como cero.

Los siguientes ejemplos muestran algunas expresiones con operadores relacionales.

var > 15; //si var es menor o igual a 15, el resultado es 0 (falso)
var != 15; //si var es mayor o menor a 15, el resultado es 1 (verdadero)

Ejercicios

1. Reescriba la siguiente expresin usando un operador relacional diferente.

cont != 0;

2. Cundo la siguiente expresin es verdadera o falsa?

cont >= 35;

33
OPERADORES LOGICOS

Los operadores lgicos soportan las operaciones lgicas bsicas AND, OR, y NOT. De nuevo, estos
operadores retornan 0 para falso o 1 para verdadero. Los operadores lgicos y la tabla de verdad
para estas operaciones se muestran a continuacin:

AND OR NOT
p q p && q p || q !p
0 0 0 0 1
0 1 0 1 1
1 0 0 1 0
1 1 1 1 0

Los operadores lgicos y relacionales estn estrechamente acoplados cuando se evala una
expresin. Un ejemplo de juntar estos operadores es el siguiente:

cont>max || !(max==57) && var>=0

Otra parte de C que emplea los operadores relacionales y lgicos son las instrucciones de control
de programa que se estudiarn en el siguiente captulo.

Ejercicios

1. Reescriba la siguiente expresin usando cualquier combinacin de operadores relacionales


y lgicos.

cont == 0;
result <= 5;

2. Dado que C no entrega explcitamente una funcin OR exclusiva, escriba una funcin XOR
basada en la siguiente tabla de verdad.
p q XOR
0 0 0
0 1 1
1 0 1
1 1 0
OPERADORES DE BIT A BIT

C contiene seis operadores especiales que desarrollan operaciones bit a bit sobre nmeros. Estas
operaciones de bit pueden usarse solo sobre tipos de datos enteros y caracteres. El resultado de
usar cualquiera de estas operaciones es una operacin bit a bit de los operandos. Los operadores
de bit a bit son los siguientes:

& AND bit a bit


| OR bit a bit
^ XOR bit a bit
~ complemento a uno
>> desplazamiento hacia la derecha
<< desplazamiento hacia la izquierda

El formato general para el uso de los operadores de desplazamiento es el siguiente:

variable << expresin

34
variable >> expresin

El valor de expresin determina cuantos lugares hacia la izquierda o derecha variable es


desplazada. Cada desplazamiento hacia la izquierda causa que todos los bits de corran una
posicin de bit a la izquierda, y un cero es insertado sobre el lado derecho. El bit que es
desplazado fuera del final de variable se pierde.

La nica situacin a resaltar acerca del uso de los desplazamientos es que un desplazamiento hacia
la izquierda es equivalente a multiplicar un nmero por 2 y un desplazamiento hacia la derecha es
equivalente a dividir un nmero por 2. Los operadores de desplazamiento son casi siempre ms
rpidos que su equivalente operacin aritmtica debido a cmo trabaja la CPU.

Un ejemplo de todos los operadores bit a bit se muestra a continuacin.

AND OR
00000101 (5) 00000101 (5)
& 00000110 (6) | 00000110 (6)
------------ ------------
00000100 (4) 00000111 (7)

XOR NOT (complemento a uno)


00000101 (5) ~ 00000101 (5)
^ 00000110 (6) ------------
------------ 11111010 (250)
00000011 (3)

DESP IZQ. DESP DER.


00000101 (5) 00000101 (5)
<< 2 >> 2
------------ ------------
00010100 (20) 00000001 (1)

NOTA: no realice desplazamientos mas all de los bits que el operando posea, debido a que se
obtiene un resultado indefinido.

a = b | c;
Se convierte en:
0007: MOVF b,W ;carga b
0008: IORWF c,W ;opera b OR c
0009: MOVWF a ;guarda en a

a = b & c;
Se convierte en:
0007: MOVF b,W ;carga b
0008: ANDWF c,W ;opera b AND c
0009: MOVWF a ;guarda en a

a = b >> 3;
Se convierte en:
0007: MOVF b,W ;carga b
0008: MOVWF a ;guarda en a
0009: RRF a,F ;rota el contenido
000A: RRF a,F ;hacia la derecha
000B: RRF a,F ;tres veces
000C: MOVLW 1F ;enmascara el contenido
000D: ANDWF a,F ;del registro para a

j = ~a;

35
Se convierte en:
0007: MOVF a,W ;carga a
0008: MOVWF j ;guarda en j
0009: COMF j,F ;complementa j

Ejercicios

1. Escriba un programa que invierta los bits ms significativos (MSB) de un dato tipo signed
char.
2. Escriba un programa que imprima la representacin binaria de un nmero tipo char.

OPERADORES INCREMENTALES Y DECREMENTALES

Cmo podra usted incrementar o decrementar en una unidad una variable? Probablemente una
de dos formas le vendra a la mente. Tal vez las siguientes:

a = a + 1; o a = a - 1;

Una vez ms, los creadores de C han llegado con una notacin abreviada para incrementar o
decrementar un nmero. Los formatos generales son los siguientes:

a++; o ++a; para incrementar


a--; o --a; para decrementar

Cuando los signos ++ o -- preceden la variable, la variable es incrementada y despus el valor es


usado en una expresin. Cuando los signos ++ o -- van despus de la variable, el valor de la
variable se usa en la expresin y luego se incrementa.

int j, a = 3;
0007: MOVLW 03
0008: MOVWF a ;registro asignado a a

j = ++a;
0009: INCF a,F ;a = 4
000A: MOVF a,W ;carga a en w
000B: MOVWF j ;almacena w en j

j = a++;
000C: MOVF a,W ;carga el valor de a en w
000D: INCF a,F ;a = 5
000E: MOVWF j ;almacena w en j, j = 4

NOTA: no utilice la siguiente expresin.

a = a++;

Porque se genera el siguiente error en el cdigo generado:

MOVF a,W ;valor de a cargado en w


INCF a,F ;valor de a incrementado
MOVWF a ;el valor previo es recargado sobrescribiendo el
;valor incrementado

36
El siguiente ejemplo ilustra los dos usos.

#include <stdio.h>

void main(void)
{
int i,j;
i = 10;
j = i++;
printf("i = %d, j = %d\n",i,j);
i = 10;
j = ++i;
printf("i = %d, j = %d\n",i,j);
}

El primer printf() imprimir un 11 para i y un 10 para j. el segundo printf() imprimir


un 11 para ambos i y j.

Mezclando operadores

Escribiendo Se obtine
sum = a+b++ sum = a+b b = b+1
sum = a+b-- sum = a+b b = b-1
sum = a+ ++b b = b+1 sum = a+b
sum = a+ --b b = b-1 sum = a+b

Ejercicios

1. Reescriba los operadores de asignacin en el siguiente programa para incrementar o


decrementar las variables.

void main(void)
{
int a, b;
a = 1;
a = a+1;
b = a;
b = b-1;
printf("a=%d, b=%d\n", a,b);
}
2. Cules son los valores de a y b despus de que el siguiente segmento de cdigo se ha
ejecutado?

a = 0;
b = 0;
a = ++a + b++;
a++;
b++;
b = --a + ++b;

PRECEDENCIA DE OPERADORES

La precedencia se refiere al orden en el cual los operadores son procesados por el compilador C.
por ejemplo, si la expresin a+b*c se encontrar en su programa, Qu operacin ocurrira en
primer lugar, la suma o la multiplicacin? El lenguaje C mantiene precedencia para todos los
operadores. La siguiente lista muestra la precedencia desde la ms alta a la ms baja.

37
Prioridad Operador Ejemplo
1 () ++ -- (a+b)/c parentesis
2 sizeof & * + - ~ ! ++ -- a=-b mas/menos/NOT/complemento
incremento/decremento/sizeof
3 * / % a%b multi/dividir/modulo
4 + - a+b suma/resta
5 << >> a=b>>c Desp izg. o derecho
6 < > <= >= a>=b mayor/menor/igual que
7 == != a==b
8 & a=b&c AND bit a bit
9 ^ a=b^c XOR bit a bit
10 | a=b|c OR bit a bit
11 && a=b&&c AND lgico
12 || a=b||c OR lgico
13 = *= /= %= += -= <<= >>= $= a+=b asignacin
^= |=

Algunos de estos operadores todava no los hemos estudiado, pero no se preocupe, los
estudiaremos ms adelante. Los parntesis pueden usarse para fijar el orden especfico en el cual
las operaciones se lleven a cabo.

Un par de ejemplos del uso del parntesis para clarificar o cambiar la precedencia de una
declaracin son los siguientes:

10-2*5 = 0
(10-2)*5 = 40
cont*sum+88/val-19%cont
(cont*sum) + (88/val) (19%cont)

38
5. DECLARACIONES DE CONTROL DEL PROGRAMA

En este captulo aprender acerca de las instrucciones que C usa para controlar el flujo de
ejecucin en un programa. Adems aprender como los operadores relacionales y lgicos se usan
con estas declaraciones de control.

DECLARACION if

La declaracin if es una instruccin del tipo condicional. El bloque de cdigo asociado con la
instruccin if es ejecutado basado en el resultado de una condicin. Nuevamente, cualquier valor
diferente de cero es verdadero y cualquier valor cero es falso. El formato ms sencillo es el
siguiente:

if (expresion)
{
.
instruccones;
.
}

Los corchetes {} se usan para encerrar el boque de cdigo. Esto le informa al compilador que si la
expresin es verdadera, ejecute el cdigo dentro de los corchetes. Ejemplo:

if (cont < 0)
{
Cont = 0;
printf("cuenta descendente\n");
}
if (TestMode == 1)
{
... Haga esto
}

Otros operadores de comparacin usados en la instruccin if son los siguientes:

x == y x igual a y
x != y x es diferente a y
x > y x es mayor que y
x < y x es menor que y
x <= y x es menor o igual que y
x >= y x es mayor o igual que y
x && y AND lgica
x || y OR lgica

Un ejemplo de una de estas funciones convertida en Assembler es el siguiente:

int j, a = 3;
0007: MOVLW 03 ;carga a con 3
0008: MOVWF a
if (j == 2)
0009: MOVLW 02 ;carga w con 2
000A: SUBWF j,W ;testeo entre w y j
000B: BTFSS STATUS,Z ;si es cero salta
000C: GOTO 00F ;j no es igual a 2
{
j = a;

39
000D: MOVF a,W ;como es cero
000E: MOVWF j ;carga a en j
}
000F:

Ejercicios

1. Cules de las siguientes expresiones resultan en un valor verdadero?

a. 0
b. 1
c. -1
d. 5*5<25
e. 1==1
2. Escriba una funcin que le informe cuando un nmero sea par o impar. La funcin retorna
0 cuando el nmero sea par y 1 cuando el nmero sea impar.

DECLARACION if-else

Qu hara si se tienen dos bloques de cdigo que se ejecutan basados en el resultado de una
misma expresin? Si la expresin es verdadera, el primer bloque de cdigo se ejecuta, si la
expresin es falsa el segundo bloque de cdigo se ejecuta. Entonces, probablemente usted
empleara una declaracin if en combinacin con una declaracin else. El formato general para
la instruccin if-else es el siguiente:

if (expresion)
intruccion1;
else
intruccion2;

El formato para una declaracin if-else que use boques de cdigo (ms de una lnea) es el
siguiente:

if (expresion)
{
.
instruccones;
.
}
else
{
.
instruccones;
.
}

Tenga en cuenta que tanta la instruccin if como else pueden tener tantas instrucciones como
necesiten. Adems los corchetes pueden descartarse cuando solo haya una instruccin en
cualquiera de los dos casos. Un ejemplo de nica instruccin if-else es el siguiente:

if (num<0)
printf("Nmero negativo.\n");
else
printf("Nmero positivo.\n");

40
La adicin de la declaracin else proporciona dos opciones en la toma de decisiones. Pero qu
pasa si quiere combinar varias declaraciones if y else para realizar ms decisiones?
Coincidencia o no, C provee un mtodo con el cual usted puede combinar varios if con else
para suministrar diversos niveles de decisin. El formato general es el siguiente:

if (expresion1)
{
.
instruccones;
.
}
else if (expresion2)
{
.
instruccones;
.
}
else
{
.
instruccones;
.
}

Aqu se puede apreciar que se pueden evaluar las diferentes expresiones para elegir un bloque de
cdigo a ejecutar. Antes de explica ms acerca de este mtodo, aqu hay un ejemplo sencillo.

if(num == 1)
printf("lleva 1\n");
else if(num == 2)
printf("lleva 2\n");
else if(num == 3)
printf("lleva 3\n");
else
printf("no lleva nada\n");

NOTA: dentro de la declaracin if, hay que asegurar el correcto uso de los comparadores
sencillos y dobles, por ejemplo, los operadores sencillos &, = o | tiene el efecto de causar que la
funcin actu sobre la variable, opuesto a los operadores dobles &&, == o || que actan como
comparadores de la variable bajo prueba. Este es un error comn y no es fcil de encontrar en
cdigos extensos, debido a que el compilador no lo toma como error.

Ejercicios

1. El siguiente fragmento de cdigo es correcto?

if (cont>20)
printf("cont es mayor de 20");
count-- ;
}

2. Escriba un programa que imprima 1 peso, 5 pesos, 10 pesos, 20 pesos, 50 pesos o 100
pesos dependiendo del valor de una variable. Los nicos valores validos de la variable son
1, 5, 10, 20, 50 y 100.

41
OPERADOR ?

El operador ? es actualmente una expresin de la declaracin if-else. El formato es el


siguiente:

(expr1) ? (expr2) : (expr3);

Donde cada expr es una declaracin C vlida. Primero, se evala expr1. Si el resultado es
VERDADERO (recuerde este es cualquier valor diferente de cero), entonces se evala expr2. Pero
si el resultado es FALSO (cero), entonces se evala expr3. Lo siguiente es un ejemplo del
operador ?

int i,j;
i = j;
i ? j=0 : j=1; o j=i ? 0 : 1;

Puesto que i es 1 o diferente de cero, ser evaluada la expresin j=0. Distinto a la declaracin if
el operador ? retorna un valor. Por ejemplo:

i = (i<20) ? i+1 : 10;

Donde i se incrementar a menos que este sea igual o mayor a 20, entonces se le asignar el valor
10.

DECLARACION for

Uno de los tres bucles o lazos (loops) que suministra C es el lazo for. Si tiene una instruccin o un
conjunto de instrucciones que necesitan repetirse, con un lazo for puede fcilmente
implementar esto. El formato bsico para un lazo for es similar en todos los lenguajes, como
BASIC o Pascal. La forma ms comn de un lazo for es la siguiente:

for (inicializacin ; condicin de finalizacin ; incremento)


{
instrucciones;
}

La seccin inicializacin se emplea para entregarle un valor inicial a la variable de cuenta


en el lazo. Note que esta variable de cuenta debe ser declarada antes que el lazo for puede
usarla. Esta seccin del lazo for se ejecuta solo una vez. La seccin condicin de
finalizacin es evaluada antes de cada ejecucin del lazo. Normalmente esta seccin testea
la variable de cuenta del lazo en busca de una condicin VERDADERO o FALSO. Si la condicin
de finalizacin es verdadera el lazo se ejecuta. Si la condicin de finalizacin es
falsa el lazo termina su ejecucin y el programa sigue su flujo. La seccin incremento del lazo
for normalmente incrementa la variable de cuenta del lazo.

A continuacin se muestra un ejemplo de un lazo for.

void main(void)
{
int i;
for(i=0; i<10; i++)

42
printf("%d ",i);
printf("hecho");
}

Este programa imprimir los nmeros 0-9 en pantalla. El programa trabaja de la siguiente manera:
primero la variable de cuenta del lazo, i, es puesta a cero; la siguiente expresin i<10 se evala.
Si esta declaracin es verdadera la instruccin printf("%d ",i); es ejecutada. Cada vez
despus que la instruccin printf("%d ",i); se ejecuta, la variable de cuenta del lazo es
incrementada. Este proceso continua hasta que la expresin i<10 se convierte en falsa. En este
punto, el lazo for termina su ejecucin y la instruccin printf("hecho"); es ejecutada
dando fin al programa.

Como se afirmo anteriormente, la condicin de finalizacin es ejecutada en el comienzo de cada


iteracin del lazo. Por consiguiente, si el chequeo es falso desde el comienzo, el lazo for nunca
llegara a ejecutarse. Usted no est restringido a solo incrementos en la variable de cuenta. A
continuacin se muestran algunas variaciones sobre el lazo for.

for (num=100; num>0; num=num-1)


for (cont=0; cont<50; cont+=5)
for (cont=1; cont<10 && error==false; count++)

A continuacin se convierte un ejemplo en Assembler para verificar que sucede.

int h,a;
for (h=0;h!=10;h++)
0007: CLRF h ;borra h
0008: MOVLW 0A ;carga 10 en w
0009: SUBWF h,W ;resta w de h
000A: BTFSC STATUS,Z ;y testeo por cero
000B: GOTO 00F ;si i=10, sale del lazo
a++;
000C: INCF a,F ;incrementa a
000D: INCF h,F ;increment h
000E: GOTO 008 ;regresa
000F:

Ejercicios

1. Qu funcin cumplen las siguientes declaraciones for()?

for(i=1; ;i++)
for( ; ; )
for(num=1; num; num++)

2. Escriba un programa que imprima todos los mltiplos de un nmero.

DECLARACION while

Otro bucle en C es el lazo while. Cuando una expresin es verdadera, el lazo while repite una
declaracin o un bloque de cdigo. El formato general es el siguiente:

while (expresion)
instruccion;
o

43
while (expresion)
{
instrucciones;
}

Donde expresin es cualquier expresin valida en C. el valor de expresin es comprobado


antes de cada iteracin de la declaracin o bloque de cdigo. Esto significa que si expresin es
falsa la declaracin o bloque de cdigo no sern ejecutados. A continuacin se muestra un
ejemplo (hecho en el compilador C de CCS) de un lazo while:

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)
void main(void)
{
char ch;
printf("Escribe la letra q\n");
ch=getch();
while(ch!='q')
ch=getch();
printf("Escribiste la letra correcta!\n");
}

Habr notado que la primera declaracin pide un carcter desde el teclado. Luego la expresin es
evaluada. Siempre y cuando el valor de ch no sea igual a q, el programa continuar solicitando
otro carcter desde el teclado. Una vez una q se reciba, la funcin printf es ejecutado y el
programa termina.

Ejercicios

1. Qu funcin cumplen las siguientes declaraciones while?


a. while(i<10)
{
printf("%d ",i);
i++;
}
b. while(1)
printf("%d ",i++);

2. Escriba un programa que pida un carcter desde el teclado usando la declaracin


ch=getch(); e imprmalo en pantalla. Cuando se encuentre retorno de carro (Enter),
debe finalizar el programa.

DECLARACION do-while

El ultimo tipo de bucle en C es el lazo do. Este se puede combinar con la declaracin while de la
siguiente manera:

do
{
instrucciones;
}
while(expresion)

44
En este caso las instrucciones siempre se ejecutan antes que expresin es evaluada (al menos
una sola vez). El parmetro expresin puede ser cualquier expresin vlida en C. un ejemplo de
un lazo do-while se muestra a continuacin:

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)
void main(void)
{
char ch;
do
{
ch = getch();
}
while(ch != 'q');
printf("Escribiste la letra q!\n");
}
Este programa es equivalente al ejemplo estudiado en la seccin anterior.

Ejercicios

1. Reescriba los puntos a y b del ejercicio 1 de la seccin anterior usando el lazo do-while.
2. Reescriba el ejercicio 2 de la seccin anterior usando el lazo do-while.

DECLARACIONES DE CONTROL ANIDADAS

Cuando el cuerpo de un lazo contiene a otro, el segundo lazo se dice que esta anidado dentro del
primero. Cualquier bucle o lazo de C u otra declaracin de control pueden anidarse dentro de
cualquier otra. El estndar C ANSI especifica que los compiladores debe tener al menos 15 niveles
de anidado.

Un ejemplo de un lazo for anidado se muestra a continuacin:

i = 0;
while(i < 10)
{
for(j=0;j<10;j++)
printf("%d ",i*10+j);
i++;
}

Esta rutina imprime los nmeros de 00-99 en pantalla.

Ejercicio

1. Escriba un programa que obtenga un carcter desde el teclado (ch=getch();). Cada


vez que un carcter sea ledo, use su valor ASCII para imprimir un igual nmero de puntos
(.) en pantalla. Por ejemplo, si se lee la letra 'D' (con valor ASCII 68), su programa
imprime 68 puntos en pantalla. Cuando se lea la letra 'Q', el programa debe finalizar.

45
DECLARACION break

La declaracin break permite terminar cualquier lazo en cualquier punto dentro de su cuerpo.
Esta declaracin se desva de la terminacin normal de una expresin. Cuando la declaracin
break es encontrada en la ejecucin de un lazo, el programa salta a la siguiente lnea despus del
lazo. Por ejemplo:

void main(void)
{
int i;
for(i=0;i<50;i++)
{
printf("%d ",i);
if(i==15)
break;
}
}
Este programa imprime los nmeros 0-15 en pantalla. La declaracin break trabaja con todos los
lazos de C.

Ejercicios

1. Qu funcin cumple el siguiente lazo?


for(i=0;1;i++)
{
printf("Microchip es #1!");
if(getch()=='q')
break;
}
2. Escriba tres programas que usen los lazos de C, estos deben realizar una cuenta hasta que
se oprima una tecla. Puede usar la funcin kbhit() para detectar cuando una tecla ha
sido presionada. kbhit() retorna 1 cuando una tecla esta presionada y 0 en otro caso.
kbhit() requiere el archivo de encabezado conio.h.

DECLARACION continue

Vamos a asumir que cuando una cierta condicin ocurre en un lazo, usted quiere saltar al final del
lazo pero sin salir de este. C suministra la declaracin continue. Cuando el programa se
encuentra con esta declaracin, este salta todas las otras instrucciones entre continue y la
condicin de terminacin del lazo. Por ejemplo:

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)
void main(void)
{
int i;
for(i=0;i<100;i++)
{
continue;
printf("%d ",i);
}
}

46
Este lazo nunca ejecutar la declaracin printf(). Cada vez que continue es alcanzado, el
programa salta el printf() y evala la expresin i<100 despus de incrementar i.

Una declaracin continue puede causar que el programa vaya directamente a la condicin de
terminacin para los lazos while y do-while, un continue puede causar que se ejecute la
parte incremental de un lazo y que se evale la condicin de terminacin.

DECLARACION switch

La declaracin if es buena para seleccionar entre un par de alternativas, pero se vuelve


engorroso cuando existen muchas alternativas. De nuevo C cumple con la tarea al suministrarle la
declaracin switch. Esta declaracin es equivalente a tener mltiples declaraciones if-else.
La forma general para la declaracin switch es la siguiente:

switch (variable)
{
case constante1:
instrucciones;
break;
case constante2:
instrucciones;
break;
case constanteN:
instrucciones;
break;
default:
instrucciones;
}

La entrada variable es sucesivamente testeada contra una lista de enteros o caracteres


constantes. Cuando se encuentra una correspondencia, el cuerpo de la declaracin asociado con
esa constante se ejecuta hasta que un break es encontrado. Si ninguna constante corresponde,
las instrucciones asociadas con la declaracin default son ejecutadas. El default es opcional.
Un ejemplo de una declaracin switch se muestra a continuacin:

#include <stdio.h>

int main()
{
char ch;
for(;;)
{
ch = getchar();
if(ch=='x')
return 0;
switch(ch)
{
case '0':
printf("Domindo\n");
break;
case '1':
printf("Lunes\n");
break;
case '2':
printf("Martes\n");
break;

47
case '3':
printf("Miercoles\n");
break;
case '4':
printf("Jueves\n");
break;
case '5':
printf("Viernes\n");
break;
case '6':
printf("Sbado\n");
break;
default:
printf("Entrada Invalida\n");
}
}
}

Este ejemplo lee un nmero entre 0 y 6. Si el nmero esta fuera de este rango, el mensaje
Entrada Invalida se imprime. Valores dentro del rango se convierten en un da de la
semana.

El estndar ANSI declara que un compilador C debe soportar al menos 257 declaraciones case.
Dos declaraciones case no pueden tener el mismo valor dentro del mismo switch. Tambin las
declaraciones switch pueden anidarse, siempre y cuando los switch interiores no tengan
conflicto con valores de switch exteriores. Un compilador ANSI debe suministrar al menos 15
niveles de anidamiento para las declaraciones switch. A continuacin se muestra un ejemplo de
switches anidados.

switch (a)
{
case 1:
switch (b)
{
case 0:
printf("b es falso");
break;
case 1:
printf("b es verdadero");
break;
}
break;
case 2:
.
.

La declaracin break dentro de un switch tambin es opcional. Esto significa que dos
declaraciones case pueden compartir la mismo porcin de cdigo. Un ejemplo de esto se
muestra a continuacin.

void main(void)
{
int a=6,b=3;
char ch;
printf("S = Suma\n");
printf("R = Resta\n");
printf("M = Multiplicacion\n");
printf("D = Division\n");

48
printf("Escoja una Opcion:\n");
ch=getch();
switch (ch)
{
case 'R':
b=-b;
case 'S':
printf("\t\t%d",a+b);
break;
case 'M':
printf("\t\t%d",a*b);
break;
case 'D':
printf("\t\t%d",a/b);
break;
default:
printf("Opcion Incorrecta");
}
}

Ejercicios

1. Qu error tiene el siguiente segmento de cdigo?

float f;
switch(f)
{
case 10.05:
.
.
2. Use una declaracin switch para imprimir el valor de una moneda. El valor de la moneda
est contenido en la variable moneda. Las fases para describir las monedas son: de 20, de
50, de 100, de 200 y de 500.
3. Cules son las ventajas del uso de la declaracin switch sobre la declaracin if-
else?

DECLARACION null(;)

La declaracin null es una instruccin que contiene sola el smbolo punto y coma (;). Este puede
aparecer dondequiera que una declaracin sea esperada. Nada pasa cuando la declaracin null
es ejecutada, a diferencia de la instruccin NOP de Assembler, la cual introduce un ciclo de
retardo.

Declaraciones como do, for y while requieren que una instruccin ejecutable aparezca como el
cuerpo de la declaracin. La declaracin null satisface la sintaxis para esos casos.

for (i=0;i<10;linea[i++]=0)
;

En este ejemplo, la expresin del lazo for linea[i++]=0 inicializa los 10 primeros elementos
de linea a 0. La instruccin del cuerpo es un null, entonces no se requieren ms instrucciones.

49
DECLARACION return

La declaracin return termina la ejecucin de una funcin y retorna el control a la rutina que
hizo el llamado. Un valor puede retornarse a la funcin que realiza el llamado si es requerido pero
si este es omitido, el valor retornado es indefinido. Si no se incluye un return en la funcin, el
control es aun pasado a la funcin que hizo el llamado despus de ejecutar la ltima lnea de
cdigo. Si no se necesita retornar un valor, declare la funcin para ser del tipo void.

GetValue(c)
int c;
{
c++;
return c;
}
void GetNothing(c)
int c;
{
c++;
return;
}
void main()
{
int x;
x = GetValue();
GetNothing();
}

50
6. ARREGLOS Y CADENAS

En este captulo se discutirn los arreglos (array) y cadenas de caracteres (strings). Un arreglo es
simplemente una lista de variables relacionadas del mismo tipo de dato. Una cadena es definida
como un arreglo de caracteres, y tambin es conocido como el arreglo ms comn de una sola
dimensin (unidimensional).

ARREGLOS UNIDIMENSIONAL

Un arreglo es una lista de variables que son todas del mismo tipo de dato y que pueden
referenciarse a travs del mismo nombre. Una variable individual en un arreglo es llamada un
elemento del arreglo. Este es la manera sencilla de manejar grupos de datos relacionados.

La forma general para declarar un arreglo unidimensional (vector) es la siguiente:

tipo NombreArreglo [tamao];

Donde tipo es un tipo de dato vlido en C, NombreArreglo es el nombre del arreglo, y


tamao especifica cuantos elementos tiene el arreglo. Por ejemplo, si se quiere definir un arreglo
de 50 elementos se emplea la siguiente declaracin.

int altura[50];

Cuando se declara un arreglo, C define el primer elemento con un ndice 0. Si el arreglo tiene 50
elementos, el ltimo elemento tiene ndice 49. Usando el ejemplo anterior, digamos que quiero
indexar el elemento 25 del arreglo altura y asgnale un valor de 60. El siguiente ejemplo
muestra cmo hacer esto.

altura[24] = 60;

C almacena el arreglo unidimensional en posiciones de memoria contiguas. El primer elemento


est en la direccin ms baja. Si el siguiente segmento de cdigo es ejecutado.

int num[10];
int i;
for(i=0;i<10;i++)
0007: CLRF i ;borra i
0008: MOVLW 0A
0009: SUBWF i,W ;testea si i<10
000A: BTFSC STATUS,C
000B: GOTO 013 ;si no es as, deja la rutina
num[i] = i;
000C: MOVLW 0E ;carga el comienzo de num
000D: ADDWF i,W
000E: MOVWF 04
000F: MOVF i,W
0010: MOVWF 00
0011: INCF i,F
0012: GOTO 008
0013:

El arreglo num se ver as en memoria:

51
elemento 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7 8 9

Cualquier elemento del arreglo puede usarse en cualquier lugar donde usted quiera emplear una
variable o una constante. A continuacin se muestra otro ejemplo hecho en el compilador C de
CCS, en este simplemente se le asigna el cuadrado del ndice al elemento del arreglo, luego se
imprimen todos los elementos.

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)
void main(void)
{
int num[10];
int i;
for(i=0;i<10;i++)
num[i] = i * i;
for(i=0;i<10;i++)
printf("%d ",num[i]);
}

Qu pasa si se tiene un arreglo con diez elementos y usted accidentalmente escribe en el


onceavo elemento? C no tiene ninguna comprobacin de lmites de los ndices en arreglos. Por lo
tanto, se podra leer o escribir en un elemento no declarado en el arreglo. Sin embargo, esto por lo
general tendr resultados desastrosos. A menudo esto causar que el programa colapse y e
incluso a veces que el ordenador se bloquee.
C no le permite asignar los valores de un arreglo a otro simplemente usando una asignacin como
la siguiente:

int a[10], b[10];


.
.
a=b;

El ejemplo anterior es incorrecto. Si usted quiere copiar el contenido de un arreglo dentro de otro,
usted debe copiar cada elemento individual desde el primer arreglo dentro del segundo arreglo. El
siguiente ejemplo muestra como copiar el arreglo a[] dentro del b[] asumiendo que cada
arreglo tiene 20 elementos.

for(i=0;i<20;i++)
b[i] = a[i];

Ejercicios

1. El siguiente fragmento de cdigo es correcto?

int i;
char cont[10];
for(i=0;i<100;i++)
cont[i]=getch();

2. Escriba un programa que lea 10 caracteres desde el teclado usando getch(). El


programa reportar si cualquiera de estos caracteres concuerda con uno especfico.

52
CADENA DE CARACTERES

El arreglo unidimensional ms comn es la cadena de caracteres. C no tiene incorporado un tipo


de dato cadena (string). En lugar de esto, este soporta cadenas usando arreglos unidimensionales
de caracteres. Una cadena es definida con un 0. Si cada cadena debe terminar con un vacio,
entonces cuando se declare la cadena debe agregarse un elemento adicional. Este elemento
adicional almacenara el cero. Todas las cadenas constantes son automticamente terminadas en
cero por el compilador C. Puesto que estamos utilizando cadenas. Cmo se puede introducir una
cadena en el programa mediante el teclado? La funcin gets(str) leer los caracteres desde el
teclado hasta que un retorno de carro (Enter) es encontrado. La cadena de caracteres que ha sido
leda ser almacenada en el arreglo str declarado. Usted debe asegurar que el tamao del
arreglo sea ms grande o igual que el nmero de caracteres ledos desde el teclado incluyendo el
cero (null = \0).

A continuacin se muestra un ejemplo de cmo usar la funcin gets() en un programa.

#include <stdio.h>
void main(void)
{
char str[20];
int i;
printf("Escriba una cadena (<20 caracteres):\n");
gets(str);
for(i=0;str[i];i++)
printf("%c",str[i]);
printf("\n%s",str);
getchar();//termina el programa oprimiendo ENTER
}

En el ejemplo anterior se observa que la cadena puede imprimirse de dos maneras: como un
arreglo de caracteres usando %c o como una cadena usando %s.

Ejercicios

1. Cul es el error en el siguiente programa? La funcin strcpy() copia el segundo


argumento dentro del primero.

#include <string.h>
void main(void)
{
char str[10];
strcpy(str, "Microcontrolador");
printf(str);
}

2. Escriba un programa que lea una cadena de caracteres desde el teclado y los imprima en
orden inverso en pantalla.

53
ARREGLOS MULTIDIMENSIONALES

C no est limitado a los arreglos unidimensionales. Usted puede crear arreglos de dos o ms
dimensiones. Por ejemplo, para crear un arreglo entero llamado numero de dimensin 5x5,
puede hacerlo de la siguiente manera:

int numero[5][5]; //usa 25 posiciones de memoria

Dimensiones adicionales pueden hacerse simplemente aadiendo otro conjunto de parntesis


cuadrados. Por simplicidad, solo se trataran los arreglos de dos dimensiones (Matrices). La mejor
forma de representar un arreglo de dos dimensiones es por medio del formato fila/columna. Por
lo tanto, los arreglos de dos dimensiones son accesado una fila a la vez, de izquierda a derecha. La
Fig. 2 muestra una representacin grfica de un arreglo de 5x5.

Fig. 2. Arreglo de 5x5

Los arreglos de dos dimensiones se usan de la misma manera que se usan los arreglos
unidimensionales. Por ejemplo, el siguiente programa carga un arreglo de 5x4 con el producto de
los ndices, entonces imprime el contenido del arreglo en el formato fila/columna.

#include <stdio.h>
void main(void)
{
int arreglo[5][4];
int i,j;
for(i=0;i<5;i++)
for(j=0;j<4;j++)
arreglo[i][j]=i*j;
for(i=0;i<5;i++)
{
for(j=0;j<4;j++)
printf("%d ",arreglo[i][j]);
printf("\n");
}
getchar(); // termina el programa oprimiendo ENTER
}

La salida que genera este programa debe lucir como la siguiente:

0 0 0 0
0 1 2 3
0 2 4 6
0 3 6 9
0 4 8 12

54
Como se puede dar cuenta, cuando se usa un arreglo multidimensional al nmero de variables
necesarias para acceder a cada elemento individual del arreglo s incrementan. Debido a la
capacidad de memoria del PIC16F84A, arreglos de 100 o 10x10 no son posibles. Sin embargo, un
arreglo de 50 elementos podra implementarse o podra utilizar un Microcontrolador con ms
capacidad de memoria como por ejemplo el PIC16F877A.

Ejercicios

1. Escriba un programa que declare un arreglo de 3x3x3 y lo cargue con los nmeros del 1 al
27. Imprima el arreglo en pantalla.
2. Empleando el programa del ejercicio 1, imprima la suma de cada fila y de cada columna.

INICIALIZANDO ARREGLOS

Hasta el momento se ha estudiado como asignarle valores a elementos individuales de un arreglo.


C suministra un mtodo con el cual usted puede asignarle un valor inicial a un arreglo tal como se
hace para las variables. La forma general para un arreglo unidimensional se muestra a
continuacin:

tipo NombreArreglo[tamao] = {ListaValores};

El parmetro ListaValores es una lista de constantes separadas por comas que son
compatibles con el tipo de arreglo. La primera constante ser asignada al primer elemento del
arreglo, la segunda constante al segundo elemento y as. El siguiente ejemplo muestra como se
inicializa un arreglo tipo entero de 5 elementos.

int i[5] = {1,2,3,4,5};

El elemento i[0] tendr un valor de 1 y el elemento i[4] tendr un valor de 5.


Una cadena (arreglo de caracteres) puede inicializarse de dos formas. Primero, usted puede hacer
una lista de cada carcter individual como se muestra a continuacin:

char str[3] = {'a', 'b', 'c'};

El Segundo mtodo consiste en usar una cadena entre comillas, como se muestra a continuacin:

char nombre [5] = "John";

Abra notado que no se utilizan corchetes para encerar la cadena, debido a que no son necesarios
en este tipo de inicializacin debido a que las cadenas en C deben terminar con un vacio. El
compilador automticamente aade un vacio al final de "John".

Los arreglos multidimensionales se inicializan de la misma manera que los unidimensionales. Es


sencillo simular el formato fila/columna cuando define un arreglo de dos dimensiones. El
siguiente ejemplo muestra como inicializar un arreglo de 3x3.

int num[3][3]={ 1,2,3,


4,5,6,
7,8,9};

55
Ejercicios

1. la siguiente declaracin es correcta?

int cont[3] = 10,0, 5.6, 15.7;

2. Escriba un programa que defina una tabla con el valor al cuadrado y al cubo de un rango
de nmeros. Cada fila debe tener los nmeros, su valor al cuadrado y al cubo. Cree un
arreglo de 9x3 que mantenga esta informacin para los nmeros del 1 al 9. Debe
preguntarle al usuario por un nmero usando la funcin scanf("%d",&num);.
entonces imprime al nmero y su valor al cuadrado y al cubo.

ARREGLOS DE CADENAS

Arreglos de cadenas de caracteres son comunes en C. pueden declararse e inicializarse como


cualquier otro arreglo. Pero la manera en la cual usted usa el arreglo es un tanto diferente. Por
ejemplo, Qu define la siguiente declaracin?

char nombres[10][40];

Esta instruccin especifica que el arreglo nombres contiene 10 nombres, de hasta 40 caracteres
de largo cada uno (incluyendo el vacio). Para acceder a una cadena de esta tabla, hay que definir
solo el primer ndice. Por ejemplo, para imprimir el quinto nombre de este arreglo, puede usar el
siguiente comando.

printf("%s",nombres[4]);

Lo mismo pasa para arreglos con dimensiones mayores a dos. Por ejemplo, si el arreglo
animales se declarara de la siguiente manera:

char animales[5][4][80];

Para acceder a una cadena especifica, debe usar las dos primeras dimensiones. Por ejemplo, para
acceder a la segunda cadena de la tercera lista, se escribe animales[2][1].

Ejercicio

1. Escriba un programa que cree una tabla que contenga las palabras para los nmeros del 0
al 9. Permita que el usuario escriba un digito para que entonces su programa imprima en
pantalla la palabra respectiva. Para obtener un ndice dentro de la tabla, reste cero al
carcter tecleado.

FUNCIONES PARA MANIPULAR CADENAS

Las cadenas de caracteres pueden manipularse de diferentes maneras dentro de un programa. Un


ejemplo es copiando una cadena desde una fuente a un destino por medio de la funcin
strcpy(). Esta funcin permite a una cadena constante ser introducida en RAM.

56
#include <string.h> //la librera de funciones string
char cadena[10]; //define un arreglo string
.
.
strcpy (cadena, "Hi There");//disposicin de caracteres dentro del arreglo

Tenga en cuenta que apuntadores a ROM no son validos en las microcontroladores PIC por lo que
usted no puede pasar una cadena constante a ninguna de estas funciones. strlen("Hola") no
es vlida. A continuacin se presenta otro ejemplo.

#include <stdio.h>
#include <string.h>
void main()
{
char s1[10], s2[10];

strcpy(s1,"abc");
strcpy(s2,"def");
strcat(s1,s2);
printf("%u\n",strlen(s1)); //imprime el nmero 6
printf(s1); //imprime abcdef

if(strcmp(s1,s2)!=0)
printf("\n No son Iguales");
getchar();
}

Algunas funciones que manipulan cadenas estn disponibles a continuacin:

strcat Aade una cadena al final de otra


strchr Localiza un caracter en una cadena, buscando desde el principio
strrchr Localiza un caracter en una cadena, buscando desde el final
strcmp Compara dos cadenas numricamente ('a'!='A')
strncmp Compara los n primeros caracteres de dos cadenas numricamente
stricmp Compara dos cadenas ignorando su forma (mayus./minus.)
strncpy Copia los n primeros caracteres de una cadena en otra
strlen Devuelve la longitud de una cadena
strlwr Reemplaza letras maysculas con minsculas
strpbrk Encuentra la primera ocurrencia de algn caracter en dos arreglos
strstr Busca una cadena dentro de otra

NOTA: Asegrese de que el tamao de los arreglos de cadenas sean acordes con el tamao de las
cadenas que se manipulen.

57
7. PUNTEROS

Este captulo cubre un de los ms importantes y ms problemticos rasgos de C, el puntero. Un


puntero es bsicamente la direccin de un objeto en el programa.

INTRODUCCION A LOS PUNTEROS

Un puntero es una posicin de memoria (variable) que guarda la direccin de otra posicin de
memoria. Por ejemplo, si una variable puntero a contiene la direccin de la variable b, entonces a
apunta a b. si b es una variable que est en la posicin 100 de la memoria. Entonces a debera
contener el valor 100.
La forma general para declarar una variable puntero es la siguiente:

type *NombreVariable;

En un puntero type es uno de los tipos de datos validos en C. Este especifica el tipo de variables a
las cuales NombreVariable puede apuntar. Usted habr notado que NombreVariable va
precedido por un asterisco *. Este le informa al compilador que NombreVariable es una
variable puntero. Por ejemplo, la siguiente declaracin crea un puntero a un tipo entero.

int *ptr;

Los dos operadores especiales que estn asociados con los punteros son *, &. La direccin de una
variable puede ser accesada colocando antes de la variable el operador &. El operador * retorna
el valor de la direccin apuntada por la variable. Por ejemplo:

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)

void main(void)
{
int *a,b; //ms de 1 byte puede ser asignado a a
b = 6;
a = &b;
printf("%d",*a);
}

NOTA: por defecto, el compilador emplea 1 byte para punteros. Esto significa que solo las
posiciones de 0 hasta 255 pueden ser apuntadas. Para partes con una memoria ms extensa es
necesario usar un puntero de 2 bytes (16 bits). Para seleccionar un puntero de 16 bits, use la
siguiente directiva:
#device *=16

Sea consciente de que ms cdigo ROM se generara debido a que la aritmtica de 16 bits es
menos eficiente.

La primera instruccin declara dos variables: a, que es un puntero a entero y b, que es un entero.
La siguiente instruccin asigna el valor 6 a b. Lugo la direccin de b (&b) es asignada a la variable
puntero a. Esta lnea puede entenderse como la asignacin de a a la direccin de b. Finalmente, el

58
valor de b se imprime en pantalla usando el operador * con la variable puntero a. Esta lnea
puede imprimir el valor de la direccin apuntada por a. este proceso de referenciar un valor a
travs de un puntero es llamado direccionamiento indirecto. Un ejemplo grafico se muestra a
continuacin:

Direccin: 100 102 104 106


Variable: i j k ptr
Contenido: 3 5 -1 102

int i, j, k;
int *ptr;

Inicialmente, i es 3, &i es 100 (la direccin de i). Como ptr contiene el valor 102, *ptr es 5 (el
contenido de la direccin 102).
Es adems posible asignar un valor de posicin de memoria usando un puntero. Por ejemplo,
reestructuremos el programa anterior de la siguiente manera:

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)

void main(void)
{
int *a,b;
a = &b;
*a=6;
printf("%d",b);
}

En este programa, primero asignamos la direccin de la variable b en a, despus asignamos un


valor a b usando a. La lnea *a=6; puede entenderse como la asignacin del valor 6 a la posicin
de memoria apuntada por a. obviamente, el uso de punteros en los dos ejemplos anteriores no es
necesario pero ilustran los usos de los punteros.

Ejercicio

1. Escriba un programa en Microsoft Visual C++ Express donde con un lazo for realice una
cuenta de 0 a 9 e imprima los nmeros en pantalla. Imprima los nmeros empleando un
puntero.

RESTRICCIONES PARA PUNTEROS

En general, los punteros pueden tratarse como variables. Sin embargo, existen algunas pocas
reglas y excepciones que se deben tener en cuenta. En adicin de los operadores *, &, hay solo
otros cuatro operadores que se pueden aplicar a punteros: +, ++, -, --. Solo cantidades enteras
pueden sumarse o restarse de variables puntero.

Cuando es incrementada una variable puntero, este apunta a la siguiente posicin de memoria. Si
por ejemplo asumimos que la variable puntero p contiene la direccin 100, despus de que la
instruccin p++; se ejecuta, p tendr el valor 102 asumiendo que los enteros tienen un tamao
de 2 bytes. Si p hubiera sido un puntero tipo float, p contendra el valor 104 despus del

59
incremento asumiendo que los nmeros en punto flotante tienen un tamao de 4 bytes. El nico
puntero que aparece como se espera es el de tipo char, debido a que los caracteres tienen un
tamao de 1 byte.

Usted puede sumarle o restarle cualquier valor entero que quiera, a un puntero o desde un
puntero. Por ejemplo, la siguiente instruccin:

int *p;
.
p = p+200;

Causa que p apunte desde la posicin de memoria actual 200 posiciones ms adelante.

Es posible incrementa o decrementar tanto el puntero como el objeto al cual apunta. Debe ser
cuidadoso cuando incrementa o decrementa el objeto apuntado por el puntero. Qu cree usted
que haga la siguiente instruccin si el valor de p es 1 antes de que la instruccin se ejecute?

*p++;

Esta instruccin obtiene al valor apuntado por p, luego incrementa p. para incrementar el objeto
que es apuntada por un puntero, use la siguiente instruccin:

(*p)++;

El parntesis causa que el valor apuntado por p se incremente. Esto debido a la precedencia de *
versus ++.

Los punteros tambin pueden usarse en operaciones relacionales. Sin embargo, estos solo tienen
sentido si el puntero si los punteros estn relacionados los unos con los otros, por ejemplo, si
apuntan al mismo objeto.

Los punteros no se pueden crear en ROM. Por ejemplo, la siguiente instruccin es ilegal:

char const nombre[5] = "JOHN";


.
ptr=&nombre[0];

Esta es vlida sin el const, el cual pone el dato en ROM.

Ejercicios

1. Declare las siguientes variables y asigne sus direcciones a la variable puntero. Imprima el
valor de cada variable usando %p. Luego incremente cada puntero e imprima el valor de la
variable nuevamente. Cules son los tamaos de cada tipo de dato en su ordenador?

char *cp,ch;
int *ip,i;
float *fp,f;
double *dp,d;

2. Cul es el error en el siguiente fragmento de cdigo?

60
int *p,i;
p = &i;
p = p/2;

PUNTEROS Y ARREGLOS

En C, punteros y arreglos estn relacionados y son algunas veces intercambiables. Es la relacin


entre estos dos lo que hace el poder de C cada vez ms aparente.

Si usted emplea el nombre de un arreglo sin el ndice, entonces est usando un puntero que
direcciona al comienzo del arreglo. En el capitulo anterior, se uso la funcin gets(), con la cual
nosotros solo pasamos el nombre de la cadena. Lo que actualmente se pasa a una funcin, es un
puntero al primer elemento de la cadena. Nota importante: cuando un arreglo se entrega a una
funcin, solo un puntero que direcciona al primer elemento es entregado; estos no pueden
crearse para usarse con arreglos constantes o estructuras.

Debido a que el nombre de un arreglo sin un ndice es un puntero, puede asignar ese valor a otro
puntero. Esto te permitir acceder al arreglo usando la aritmtica puntero. Por ejemplo:

#include <stdio.h>
int a[5]={1,2,3,4,5};
void main(void)
{
int *p,i;
p=a;
for(i=0;i<5;i++)
printf("%d",*(p+i));
getchar();
}

Este es un programa claramente vlido en C. Abra notado que en la funcin printf() usamos
*(p+i), donde i es el ndice del arreglo. Adems se habr sorprendido del hecho de que
podemos colocar un ndice al puntero como si este fuera un arreglo. El siguiente programa
tambin es vlido.

#include <stdio.h>
int a[5]={1,2,3,4,5};
void main(void)
{
int *p,i;
p=a;
for(i=0;i<5;i++)
printf("%d",p[i]);
getchar();
}

Una cuestin a recordar es que un puntero solo podr indexarse cuando este apunte a un arreglo.
Debido a que los punteros a arreglos direccionan solo al primer elemento o base de la cadena, es
invalido incrementar el puntero. Por lo tanto, la instruccin p++; ser invalida utilizndola en el
programa anterior.

61
Ejercicios

1. El siguiente segmento de cdigo es correcto?

int cont[10];
.
cont = cont+2;

2. Qu valor imprime el siguiente segmento d cdigo?

int valor[5]={5,10,15,20,25};
int *p;
p = valor;
printf("%d",*p+3);

PASANDO PUNTEROS A FUNCIONES

En el captulo 3, hablamos acerca de las dos formas en las que los argumentos podan pasar a las
funciones, llamado por valor y llamado por referencia. El segundo mtodo pasa la direccin a la
funcin, o en otras palabras un puntero es pasado a la funcin. En este punto cualquier cambio
hecho a las variables empleando el puntero cambiara el valor de la variable desde la rutina de
llamado. Los punteros pueden pasarse a funciones al igual que otras variables. El siguiente
ejemplo muestra como pasar una cadena a una funcin usando punteros.

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)

void puts(char *p);


void main(void)
{
puts("Microchip es genial!");
}

void puts(char *p)


{
while(*p)
{
printf("%c",*p);
p++;
}
printf("\n");
}

En este ejemplo, el puntero p direcciona al primer caracter de la cadena, la letra M. La


instruccin while(*p) es testeada en bsqueda de la condicin vacio (null) al final de la cadena.
Cada vez que pasa a travs del lazo while, el carcter que es apuntado por p se imprime. Luego
p se incrementa para apuntar al siguiente caracter de la cadena. Otro ejemplo de pasar un
puntero a una funcin es el siguiente:

void IncBy10(int *n)


{
*n += 10;
}
void main(void)

62
{
int i=0;
IncBy10(i);
}

El ejemplo anterior puede reescribirse para mejorar la legibilidad, usando una clase especial de
parmetros de puntero llamado parmetro de referencia.

void Incby10(int & n)


{
n += 10;
}
void main(void)
{
int i=0;
Incby10(i);
}

Ambos ejemplos muestran como retornar un valor desde una funcin por medio de la lista de
parmetros.

Ejercicios

1. Escriba un programa que pase un valor tipo float a una funcin. Dentro de esta
funcin, el valor -1 se asigna al parmetro de la funcin. Despus que la funcin retorna al
main, imprime el valor de la variable float.
2. Escriba un programa que el puntero fl a una funcin. Dentro de la funcin, el valor -1 se
asigna a la variable. Despus que la funcin retorna al main, imprime el valor de la
variable.

63
8. ESTRUCTURAS Y UNIONES

Las estructuras y uniones representan dos de los ms importantes tipos de datos definidos por
usuario que tiene C. Las estructuras son un grupo de variables relacionadas que pueden tener
diferentes tipos de datos. Las uniones son un grupo de variables que comparten el mismo especio
de memoria.

INTRODUCCION A LAS ESTRUCTURAS

Una estructura es un grupo relacionado de elementos o tems que pueden ser accesados a travs
de un nombre comn. Cada tem dentro de una estructura tiene su propio tipo de dato, y pueden
ser diferentes entre ellos. C define las estructuras de la siguiente manera:

struct NombreEstructura
{
tipo elemento1;
tipo elemento2;
.
tipo elementoN;
} ListaVariables;

La palabra clave struct le informa al compilador que una estructura est por definirse. Dentro
de la estructura cada type es uno de los tipos de datos validos en C. estos tipos no tienen que ser
los mismos. NombreEstructura es el nombre con el cual vamos a identificar la estructura.
ListaVariables declara algunas variables que tienen un tipo de dato de la estructura.
ListaVariables es opcional. Cada uno de los elementos en la estructura es referenciado
comnmente como un campo o miembro. Nosotros nos referiremos a estos como miembros.

En general, la informacin almacenada en una estructura lgicamente debe estar relacionada. Por
ejemplo, usted podra emplear una estructura para guardar el nombre, direccin y nmero
telefnico de todos sus clientes o compaeros. El siguiente ejemplo es para una referencia
bibliogrfica en una biblioteca.

struct ReferenciaBib
{
char autor[40];
char titulo[40];
char editorial[40];
unsigned int pag;
unsigned char rev;
} tarjeta;

En este ejemplo, el nombre de la estructura es ReferenciaBib. Este no es el nombre de una


variable, solo el nombre de este tipo de estructura. La variable tarjeta es declarada como una
estructura del tipo ReferenciaBib.

Para acceder a cualquier miembro de la estructura, se debe especificar tanto el nombre de la


variable como el nombre del miembro. Estos nombres deben separase con un punto (.). Por
ejemplo, para acceder al miembro titulo de la estructura ReferenciaBib, usted debe usar
tarjeta.titulo donde tarjeta es el nombre de la variable y titulo es el miembro.

64
El operador es empleado para acceder a miembros de una estructura. Para imprimir el miembro
autor de la estructura ReferenciaBib, usted debe escribir lo siguiente:

printf("El autor es %s\n",tarjeta.autor);

En memoria la estructura ReferenciaBib se parece a lo siguiente:

autor 40 bytes
titulo 40 bytes
editorial 40 bytes
pag 2 bytes
rev 1 byte

Si usted quiere obtener la direccin del miembro pag de la estructura debe usar
&tarjeta.pag. Si quiere imprimir el nombre de la editorial, debe usar
printf("%s",tarjeta.editorial). Qu pasa si usted quiere acceder a un elemento
especifico del ttulo, por ejemplo la tercera letra de la cadena?, entonces debe usar:

Tarjeta.titulo[2];

El primer elemento del ttulo esta en 0, el segundo en 1 y, finalmente el tercero esta en 2. Una vez
usted ha definido una estructura, puede crear ms variables de estructura en cualquier lugar del
programa de la siguiente manera:

struct NombreEstructura ListaVariables;

Por ejemplo, si la estructura ReferenciaBib se definiera al comienzo del programa, usted


podra definir dos variables ms de la siguiente manera:

struct ReferenciaBib liro, lista;

C le permite declarar arreglos de estructuras de la misma manera que cualquier otro tipo de dato.
El siguiente ejemplo declara un arreglo de 50 elementos para la estructura ReferenciaBib.

struct ReferenciaBib grande[50];

Si usted quiere acceder a una estructura individual dentro del arreglo, debe indexar la variable
estructura (i.e grande[10]). Cmo puede acceder al miembro titulo del elemento 10 del
arreglo estructura grande?, de la siguiente manera:

Grande[9].titulo;

Las estructuras tambin pueden pasarse a funciones. Una funcin puede retornar una estructura
de la misma manera que cualquier otro tipo de dato. Tambin puede asignar valores de una
estructura a otra simplemente usando una asignacin. El siguiente fragmento es perfectamente
vlido:

struct temp
{
int a;
float b;
char c;

65
} var1,var2;

var1.a=37;
var2.b=53.65;
var2 = var1;

Despus que este fragmento de cdigo ejecuta la estructura, la variable var2 tendr el mismo
contenido de la variable var1.
El siguiente es un ejemplo de cmo inicializar una estructura.

struct ejemplo
{
char nombre[50];
char ch;
int i;
} var1[2]={"Rodger", 'Y',27,"Jack",'N',30};

NOTA: Cuando pasa una estructura a una funcin, toda la estructura pasa empleando el mtodo
llamado por valor. Por consiguiente, cualquier modificacin hecha a la estructura en la funcin no
afectara el valor de la estructura en la rutuna de llamado. El nmero de elementos tampoco
afecta la forma en la cual es pasada a una funcin.

Un ejemplo de estructura emplendola sobre un PIC para configurar una interfaz con LCD podra
ser el siguiente:

struct cont_pins
{
boolean en1; //habilita para todos los displays
boolean en2; //habilita para displays de 40x4
boolean rs; //selector de registro
int data:4;
} cont;
#byte cont = 8; //control sobre el puerto d

Este pone la estructura para cont_pins para luego ser manejada dentro del programa

NOTA: La notacin :4 en data indica que se van a utilizar 4 bits par ese elemento. En este caso
D0 ser en1, y D3-D6 sern los datos.

void LcdSendNibble(byte n)
{
cont.data=n; //dato actual
delay_cycles(1); //retardo
cont.en1=1; //pone la linea en1 en ALTO
delay_us(2); //retardo de tiempo
cont.en1=0; //pone la linea en1 en BAJO
}

Ejercicios

1. Escriba un programa que tenga una estructura con un variable carcter y una cadena de
40 caracteres. Lea un carcter desde el teclado y gurdelo en la primera variable usando
getch(). Lea una cadena y gurdela en la segunda variable usando gets(). Por ltimo
imprima los valores de cada miembro en pantalla.

66
2. En el siguiente fragmento de cdigo cual es el error?

struct tipo
{
int i;
long l;
char str[50];
} s;
.
.
i = 10;

PUNTEROS A ESTRUCTURAS

Algunas veces es til poder acceder a una estructura a travs de un puntero. Punteros a
estructuras son declarados de la misma manera que punteros a otros tipos de datos. Por ejemplo,
el siguiente fragmento de cdigo declara una variable del tipo estructura p y un puntero a
estructura q con el tipo de estructura temp.

struct temp
{
int i;
char ch;
} p,q;

Empleando esta definicin de la estructura temp, la instruccin q=&p es perfectamente valida.


Dado que q apunta a p, debe usar el operador flecha como se muestra a continuacin:

q->i=1;

Esta instruccin asigna el valor de 1 al nmero i de la variable p. Note que el operador flecha es
un signo menos seguido del signo mayor que sin ningn espacio entre estos.

Debido a que C pasa toda la estructura a una funcin, estructuras largas pueden reducir la
velocidad de ejecucin del programa debido a la gran cantidad de datos transferidos. Por esta
razn, es fcil pasar un apuntador a estructura a la funcin.

NOTA: Cuando se accese a un miembro de una estructura empleando una variable, use el punto.
Cuando accese a un miembro de una estructura empleando un puntero a estructura, usted debe
usar el operador flecha. El siguiente ejemplo muestra como un puntero a estructura debe
inicializase:

#include <16F84A.h>
#include <string.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=4000000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)

struct s_type
{
int i;
char str[40];
} s,*p;

67
void main(void)
{
p=&s;
s.i=10;
p->i=10;
strcpy(p->str,"Utilizo estructuras");
printf("%d %d %s",s.i,p->i,p->str);
}

Las dos lneas s.i=10 y p->i=10 son equivalentes.

Ejercicios

1. El siguiente segmento de cdigo es correcto?

struct s_type
{
int a;
int b;
} s, *p;
void main(void)
{
p=&s;
p.a=100;
}

2. Escriba un programa que cree un arreglo de estructuras de tamao 3 para las familias de
PIC bsicas. Necesitara cargar la estructura con un dispositivo PIC12, PIC16 Y PIC 18. El
usuario seleccionara la estructura a imprimir usando el teclado para entrar 1, 2, o 3. El
formato de la estructura ser el siguiente:

struct PIC
{
char nombre[20];
unsigned char progmem;
unsigned char datamem;
char rasgo[80];
};

ESTRUCTURAS ANIDADAS

Hasta ahora, usted solo ha visto que los miembros de una estructura son uno de los tipos de datos
de C. sin embargo, los miembros de las estructuras tambin pueden ser otras estructuras. A esto
se le llama estructuras anidadas. Por ejemplos:

#define NumerodePICS 25
struct PIC
{
char nombre[40];
unsigned char progmem;
unsigned char datamem;
char rasgo[40];
};
struct productos
{
struct PIC dispositivos[NumerodePICS];
char tipoEncapsulado[40];

68
float precio;
} lista1;

La estructura productos tiene tres elementos: un arreglo de la estructura PIC llamado


dispositivos, una cadena que tiene el tipo de encapsulado, y el precio. Estos elementos
pueden accesarse usando la variable lista1.

INTRODUCCION A LAS UNIONES

Una unin es definida como una posicin de memoria sencilla que es compartida por dos o ms
variables. Las variables que comparten la misma posicin de memoria pueden tener diferentes
tipos de datos. Sin embargo, solo podemos usar una variable a la vez. Una unin se parece mucho
a una estructura. La forma general de una unin es la siguiente:

union NombreUnion
{
tipo elemento1;
tipo elemento2;
.
.
tipo elementoN
} ListaVaribles;

Nuevamente, NombreUnion es el nombre que le damos a la unin y ListaVariables son las


variables que son del tipo unin NombreUnion. La diferencia entre uniones y estructuras es que
cada miembro de una unin comparte el mismo espacio. Por ejemplo, la siguiente unin contiene
tres miembros: un entero, un arreglo de caracteres, y un tipo double.

union u_type
{
int i;
char c[3];
double d;
} temp;

La manera en que una unin aparece en memoria se muestra a continuacin. Usaremos el


ejemplo anterior para ilustrar una unin. El entero emplea dos bytes, el arreglo utiliza tres bytes y
el tipo double emplea cuatro bytes.

-----------------------------tipo double----------------------------
----c[2]---- ----c[1]---- ----c[0]----
---------entero(int)---------
Elemento0 Elemento1 Elemento2 Elemento3

Accesar los miembros de la unin se realiza de la misma manera que como en las estructuras, se
emplea el punto (.). La instruccin temp.i accesa al miembro tipo entero de dos bytes. Si quiere
acceder a una unin a travs de un puntero, debe usar el operador flecha (->) como se hizo para
las estructuras.

Es importante notar que el tamao de la unin es establecido en tiempo de compilacin


acomodndolo al miembro ms grande de la unin. Asumiendo que los tipos double tienen cuatro
bytes de tamao, la unin temp tendr un tamao de cuatro bytes.

69
Un buen ejemplo de la aplicacin de las uniones es cuando un Microcontrolador de 8-bits tiene un
conversor A/D externo de de 12-bits conectado a un puerto serie. El Microcontrolador lee el A/D
en dos bytes. Entonces nosotros podramos configurar una unin que tenga dos unsigned
char y un signed short como miembros.

union muestra
{
unsigned char bytes[2];
signed short palabra;
}

Cuando quiera leer al A/D, leer dos bytes desde el A/D y los almacenara en el arreglo bytes.
Entonces, cuando quiera usar la muestra de 12-bits deber usar el miembro palabra para
acceder al nmero de 12-bits.

Ejercicios

1. Cules son las diferencias entre una estructura y una unin? Cules son las similitudes?
2. Escriba un programa que tenga una unin con un miembro long int y un arreglo de
caracteres de cuatro bytes. Su programa debe imprimir el miembro long int en
pantalla un byte a la vez.

70
9. LENGUAJE C ESPECIFICO PARA PIC

Habiendo estudiado las bases de C, es tiempo para continuar con las instrucciones, funciones y
operaciones relacionadas con el PIC. El compilador C de CCS tiene un extenso set de funciones
que ahorran tiempo, y aceleran el proceso de aprendizaje para los estudiantes y programadores
principiantes.

ENTRADAS Y SALIDAS

Los puertos de entrada/salida del PIC estn compuestos por dos registros: PORT y TRIS. Estos son
designados dependiendo de la disponibilidad de puertos del PIC en cuestin: PORTA, B, C, D, E y
TRISA, B, C, D, E. Un PIC de 8 pines tiene un solo registro GPIO y un TRIS para 6 lneas I/O. el
PIC16F84A posee 2 puertos (13 lneas I/O) por lo que tiene los siguientes registros: PORTA, PORTB,
TRISA, TRISB.

El puerto A tiene de 5 a 6 lneas dependiendo del PIC, las cuales pueden configurarse como
entradas o como salidas. Esto se hace por medio del registro TRISA, las entradas son configuradas
con un 1 y las salidas con un 0.

En Assembler para configurar individualmente los pines como entrada o salida se utilizan las
instrucciones BSF o BCF. Adems para leer el puerto se emplea la siguiente instruccin MOVF
PORTA,W.

NOTA: en dispositivos con conversores A/D, asegrese que el registro ADCON1 est configurado
correctamente, la configuracin I/O por defecto es ANALOGICO.

El compilador C puede interrumpir entradas y salidas de muchas maneras: fija, rpida, o estndar.
En el modo estndar, el registro TRIS es configurado antes de cada operacin I/O. esto aade
lneas a un programa y por lo tanto disminuye la velocidad, pero mejora la parte de seguridad del
cdigo asegurando que las lneas I/O estn siempre como se especificaron.

El modo I/O rpido habilita al usuario para configurar la direccin del puerto y este permanece as
hasta que sea redefinido. El compilador no aade lneas de cdigo para configurar la direccin del
puerto antes de cada operacin I/O.

El siguiente ejemplo configura el puerto B como entrada y luego lee su valor:

set_tris_b(0xff); //Puerto B como entrada


b_valor = portb; //lee puerto B

El enmascaramiento de bit se consigue fcilmente mediante la adicin de & y el patrn de la


mscara despus del nombre del puerto.

b_valor = portb & 0b00000011; //enmascara los bits no deseados

El valor almacenado en b_valor puede usarse para establecer un valor de retorno a una funcin.
Lo siguiente es el conjunto de una funcin empleada para leer algunos dip switches y establecer
una velocidad de transmisin (baudios) para una rutina comn.

71
byte bd_sw_get() //seleccin de velocidad de transmisin
{
byte b_rate;
b_rate = portb & 0b00000011; //enmascara los bits no deseados
switch(b_rate)
{
case 0: set_uart_speed(1200);
break;
case 1: set_uart_speed(2400);
break;
case 2: set_uart_speed(4800);
break;
case 3: set_uart_speed(9600);
break;
}
}

Cuando configuramos el puerto B, es aconsejable establecer las condiciones del puerto antes que
el registro TRIS. Esto previene que el puerto genere una condicin no requerida antes de que sea
configurado. Cuando configure los bits en el registro o puertos, trabaje en forma binaria, esto har
que su cdigo fuente sea ms fcil de escribir para usted y ms fcil de entender para otros.

La manipulacin de datos desde y hacia los puertos I/O se realiza de forma sencilla con el uso de
las numerosas funciones construidas. Sobre el nivel de bit se tienen las siguientes:

bit_set(variable, bit); //se emplea para poner en ALTO un bit


bit_clear(variable, bit); //se emplea para poner en BAJO un bit
bit_test(variable, bit); //se emplea para testear un bit

Las tres funciones anteriores pueden aplicarse sobre variables y I/O

b = input(pin); //obtiene el estado o valor de un pin


output_bit(pin, value); //pone un pin del puerto en un valor especifico
output_float(pin); //pone un pin como entrada o flotante
output_high(pin); //pone un pin de salida en ALTO
output_low(pin); //pone un pin de salida en BAJO

Sobre el puerto completo se emplean las siguientes instrucciones:

port_b_pullups(true/false);

Habilita o deshabilita las resistencias de pullup internas para el puerto B

set_tris_a(value);

Establece la combinacin de entradas y salidas para un puerto dado (ponga 1 para entradas y 0
para salidas). Esta funcin aplica para todos los puertos.
El registro de direccin de puerto (TRIS) es configurado cada vez que un puerto es accesado a
menos que las siguientes directivas del preprocesador se usen:

#use fast_io(port)

Deja el estado del puerto sin cambios a menos que se reconfigure

#use fixed_io(port_outputs=pin, pin)

72
Permanentemente configura el registro TRIS para el puerto

#use standard_io(port)

Por defecto para configurar el puerto cada vez que este se use.

MEZCLANDO C Y ASSEMBLER

Habr momentos en los cuales cdigo en Assembler ser requerido en nuestro programa escrito
en C. Buscando cdigo compacto, limitaciones en temporizaciones, o simplemente porque se
necesita alguna rutina especial. El siguiente ejemplo encuentra la paridad de un valor d pasado a
una rutina cuyo valor retornado es asignado a la variable a al momento de realizar el llamado.

BuscaParidad(byte d)
{
byte cont;
#asm
Movlw 8
Movwf cont
clrw
bucle:
xorwf d,w
rrf d,f
decfsz cont,f
goto bucle
movwf _return_
#endasm
}
void main(void)
{
byte a,d=7;
a=BuscaParidad(d);
}

Cuando se compila, el programa luce de la siguiente manera:

BuscaParidad(byte d)
{
byte cont;
#asm
0005: MOVLW 8
0006: MOVWF cont
0007: CLRW
0008: XORWF 27,W
0009: RRF 27,F
000A: DECFSZ 28,F
000B: GOTO 008
#endasm
000C: MOVWF 21
000E: GOTO 016
}
void main(void)
{
0011: MOVLW 07
0012: MOVWF 26
byte a,d=7;
a=BuscaParidad(d);

73
0013: MOVF 26,W
0014: MOVWF 27
0015: GOTO 005
0016: MOVF 21,W
0017: MOVWF 25
}

Set de instrucciones para el PIC16F84A

Las 35 instrucciones fundamentalmente se dividen en tres tipos. Esta divisin viene dada por el
tipo de datos con los que trabajan:
Instrucciones orientadas a los registros o bytes (byte-oriented operations).
Instrucciones orientadas a los bits (bit-oriented operations).
Operaciones con literales y de control (literal and control operations).

Las 35 instrucciones mnemnicos de la gama media de Microchip las encontraremos resumidas


en las siguientes tablas. w es el registro acumulador, f representa un registro cualquiera y C, DC, Z
los flags (banderas) del registro STATUS.

Tabla 5. Instrucciones orientadas a registros


Instrucciones orientadas a registros
MNEMNICO
DESCRIPCIN CDIGO OP BANDERAS NCIC NOTAS
OPERANDOS
ADDWF f,d w + f d 00 0111 dfff ffff C, DC, Z 1 1,2
ANDWF f,d w AND f d 00 0101 dfff ffff Z 1 1,2
CLRF f 00 h f 00 0001 1fff ffff Z 1 2
CLRW - 00 h w 00 0001 0xxx xxxx Z 1 -
COMF f,d Complemento de f d 00 1001 dfff ffff Z 1 1,2
DECF f,d f - 1 d 00 0011 dfff ffff Z 1 1,2
DECFSZ f,d f - 1 d (si es 0 salta) 00 1011 dfff ffff Ninguna 1(2) 1,2,3
INCF f,d f + 1 d 00 1010 dfff ffff Z 1 1,2
INCFSZ f,d f + 1 d (si es 0 salta) 00 1111 dfff ffff Ninguna 1(2) 1,2,3
IORWF f,d w OR f d 00 0100 dfff ffff Z 1 1,2
MOVF f,d f d 00 1000 dfff ffff Z 1 1,2
MOVWF f w f 00 0000 1fff ffff Ninguna 1 -
NOP - No operacin 00 0000 0xx0 0000 Ninguna 1 -
RLF f,d Rota f izq por carry d 00 1101 dfff ffff C 1 1,2
RRF f,d Rota f dcha por carry d 00 1100 dfff ffff C 1 1,2
SUBWF f,d f - w d 00 0010 dfff ffff C,DC,Z 1 1,2
SWAPF f,d Intercambia nibbles de f d 00 1110 dfff ffff Ninguna 1 1,2
XORWF f,d w XOR f d 00 0110 dfff ffff Z 1 1,2
Fuente: http://perso.wanadoo.es/pictob/instrucciones.htm

74
Tabla 6. Instrucciones orientadas a bit
Instrucciones orientadas a bit
MNEMNICO
DESCRIPCIN CDIGO OP BANDERAS NCIC NOTAS
OPERANDOS
BCF f,b Pone a 0 bit b de registro f 01 00bb bfff ffff Ninguna 1 1,2
BSF f,b Pone a 1 bit b de registro f 01 01bb bfff ffff Ninguna 1 1,2
BTFSC f,b Salto si bit b de reg. f es 0 01 10bb bfff ffff Ninguna 1(2) 3
BTFSS f,b Salto si bit b de reg. f es 1 01 11bb bfff ffff Ninguna 1(2) 3
Fuente: http://perso.wanadoo.es/pictob/instrucciones.htm

Tabla 7. Instrucciones con literales y de control


Instrucciones con literales y de control
MNEMNICO
DESCRIPCIN CDIGO OP BANDERAS NCIC NOTAS
OPERANDOS
ADDLW k w + k w 11 111x kkkk kkkk C,DC,Z 1 -
ANDLW k w AND k w 11 1001 kkkk kkkk Z 1 -
CALL k Llamada a subrutina k 10 0kkk kkkk kkkk Ninguna 2 -
CLRWDT - Borra temporizador del WDT 00 0000 0110 0100 TO,PD 1 -
GOTO k Ir a direccin k 10 1kkk kkkk kkkk Ninguna 2 -
IORLW k w OR k w 11 1000 kkkk kkkk Z 1 -
MOVLW k k w 11 00xx kkkk kkkk Ninguna 1 -
RETFIE - Retorno de una interrupcin 00 0000 0000 1001 Ninguna 2 -
RETLW k Retorno con k en w 11 01xx kkkk kkkk Ninguna 2 -
RETURN - Retorno de una subrutina 00 0000 0000 1000 Ninguna 2 -
SLEEP - Modo Standby 00 0000 0110 0011 TO, PD 1 -
SUBLW k k - w w 11 110x kkkk kkkk C,DC,Z 1 -
XORLW k w XOR k w 11 1010 kkkk kkkk Z 1 -
Fuente: http://perso.wanadoo.es/pictob/instrucciones.htm

MANIPULACION AVANZADA DE BIT

El compilador C de CCS posee un nmero de funciones enfocadas a la manipulacin de bit que se


necesitan comnmente en los programas con PIC.
bit_set, bit_clear, y bit_test simplemente ponen en ALTO o BAJO un bit de una
variable o testean el estado de un solo bit. La numeracin de los bits se realiza dejando el bit
menos significativo (la primera posicin de derecha a izquierda) como 0 y el bit ms significativo
como 7.

Shift_left y shift_right desplazan una posicin de bit a travs de cualquier nmero de


bytes. En adicin, estas nos permiten especificar el valor del bit para colocarlo en la posicin
vacante. Estas funciones devuelven los valores 0 o 1 representando los bits desplazados. Note que,

75
estas funciones consideran el byte menos significativo en memoria como LSB. El segundo
parmetro es el nmero de bytes y el ltimo parmetro es el nuevo bit. Ejemplo:

int x[3] = {0b10010001, 0b00011100, 0b10000001};


short bb; //el primer msb de x es: 10000001,00011100,10010001
bb = shift_left(x,sizeof(x),0);
// el primer msb de x es: 00000010,00111001,00100010
//bb es 1
bb = shift_left(x,sizeof(x),1);
// el primer msb de x es: 00000100,01110010,01000101
//bb es 0

NOTA: El primer parmetro es un puntero. En este caso, debido a que x es un arreglo el


identificador sin ndice es un puntero. Si se usara una simple variable o estructura, se debe aadir
el operador &. Por ejemplo:

long y;
struct { int a,b,c} z;
shitf_left(&y,2,0);
shitf_right(&z,3,0);

rotate_left y rotate_right trabajan muy parecido a las funciones de desplazamiento de


arriba con la diferencia de que el bit desplazado que sale por uno de los lados es insertado por el
otro lado. Por ejemplo:

int x[3] = {0b10010001, 0b00011100, 0b10000001};


//el primer msb de x es: 10000001, 00011100, 10010001
rotate_left(x,sizeof(x));
//el primer msb de x es: 00000010, 00111001, 00100011

La funcin swap intercambia los 4 bits ms significativos con los 4 bits menos significativos de un
byte. Por ejemplo:

int x;
x = 0b10010110;
swap(x); //x es ahora 01101001

TEMPORIZADORES

Todas las gamas de PICs tienen un temporizador (timer) de 8-bits y adems algunos PICs tienen
dos temporizadores avanzados. Las capacidades se presentan a continuacin:

rtcc (timer0) = 8Bit.

Se puede incrementar con el reloj interno o con una fuente externa


Aplicando un preescaler se puede retrasar su incremento
Cuando timer0 se desborda de 255 a 0, una interrupcin puede generarse

timer1 = 16Bit.

Se puede incrementar con el reloj interno o con una fuente externa


Aplicando un preescaler se puede retrasar su incremento
Cuando timer1 se desborda de 65635 a 0, una interrupcin puede generarse

76
En el modo captura, la cuenta del timer1 puede guardarse en otro registro cuando el
estado de un pin de entrada cambia, una interrupcin puede generarse
En el modo captura, un pin de salida cambia su estado cuando la cuenta alcanza un valor
preestablecido, y una interrupcin puede generarse
Este temporizador se emplea como parte de la generacin de PWM (Modulacin por
anchura de pulsos)

timer2 = 8Bit.

Se puede incrementar con el reloj interno o con una fuente externa


Aplicando un preescaler se puede retrasar su incremento
Cuando timer2 se desborda de 255 a 0, una interrupcin puede generarse
La interrupcin puede retrasarse aplicando un post-escaler, con lo que requiere un cierto
nmero de desbordamientos antes que la interrupcin ocurra
Este temporizador se emplea como parte de la generacin de PWM

En el siguiente ejemplo se usa rtcc (timer0) para temporizar cuanto tiempo dura un pulso en
estado ALTO.

#include <16F84A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=1024000)
#use RS232 (Baud=9600, xmit=pin_a3, RCV=pin_a4)

void main(void) {
int time;
setup_counters(rtcc_internal, rtcc_div_256);
//incrementa 1024000/4*256 veces por segundo
//o cada milisegundo
while(input(PIN_B0)); //espera por estado ALTO
set_rtcc(0);
while(!input(PIN_B0)); //espera por estado BAJO
time = get_rtcc();
printf("tiempo en ALTO = %u ms.",time);
}

El siguiente ejemplo emplea el timer1 en el modo captura para temporizar cuanto tiempo le toma
al pin C2 cambiar al estado ALTO despus de que el pin B0

#include <16F877A.h>
#fuses XT,NOWDT, PUT, NOPROTECT
#use delay(clock=8000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#bit capture_1 = 0x0c.2 //registro pir1
//bit 2 = la captura se ha realizado
void main(void)
{
long time;
setup_timer_1(t1_internal | t1_div_by_2);
//incrementa cada 1 us
setup_ccp1(ccp_capture_re);
//configura CCP1 para captura en flanco subida
capture_1=0;
set_timer1(0);
output_high(PIN_B0);
while(!capture_1);

77
time = ccp_1;
printf("Tiempo de reaccion = %1u us.",time);
}

COMVERSION A/D

Los conversores A/D de

Pag117

78