Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ESTRUCTURAS CONDICIONALES
Las condiciones son ingredientes comunes de un programa. Las condiciones
permiten ejecutar una o varias sentencias dependiendo de validez de una
expresión. En otras palabras, ‘Si se cumple la condición (...), se debe hacer
(...). De lo contrario, si la condición no se cumple, se debe hacer (...)’. Los
operandos condicionales if-else y switch se utilizan en las operaciones
condicionales. Una sentencia condicional puede ser seguida por una sola
sentencia o por un bloque de sentencias a ser ejecutadas.
break;
case constante2:
break;
...
default:
BUCLES
A menudo es necesario repetir una cierta operación un par de veces en el
programa. Un conjunto de comandos que se repiten es denominado un bucle
de programa. Cuántas veces se ejecutará, es decir cuánto tiempo el programa
se quedará en el bucle, depende de las condiciones de salir del bucle.
Bucle While
El bucle while se parece a lo siguiente:
while(expresión){
comandos
...
}
Bucle For
El bucle for se parece a lo siguiente:
for(expresión_inicial; expresión_de_condición; cambiar_expresión) {
operaciones
...
}
Bucle Do-while
El bucle do-while se parece a lo siguiente:
do
operación
while (cambiar_condición);
La expresión cambiar_condición se ejecuta al final del bucle, que significa que
operación se ejecuta como mínimo una vez sin reparar en que si la condición
es verdadera o falsa. Si el resultado es distinto de 0 (verdadero), el
procedimiento se repite. Todos los siguientes ejemplos son equivalentes. Esta
parte del código visualiza "hello" en un LCD 10 veces con un retardo de un
segundo. Note que en este ejemplo se utilizan funciones predefinidas, que se
encuentran en las librerías del compilador mikroC PRO for PIC. No obstante le
aconsejamos que no trate de entenderlas en detalle. Su comportamiento
general dentro del bucle se explica por medio de los comentarios.
i = 0; // Inicialización del contador
SENTENCIAS DE SALTO
SENTENCIA BREAK
A veces es necesario detener y salir de un bucle dentro de su cuerpo. La
sentencia break se puede utilizar dentro de cualquier bucle (while, for, do
while) y en las sentencias switch también. En éstas la sentencia break se
utiliza para salir de las sentencias switch si la condición case es verdadera. En
este ejemplo, “Esperar” está parpadeando en la pantalla LCD hasta que el
programa detecte un uno lógico en el pin 0 del puerto PORTA.
while(1){ // Bucle infinito
if(PORTA.F0 == 1) // Probar si el estado lógico del pin 0 del puerto
break; // PORTA es 1; si equivale, salir del bucle
Lcd_Out(1,3,"Esperar"); // Visualizar “Esperar” en el LCD
Delay_ms(1000); // Retardo de 1000 ms
Lcd_Cmd(_LCD_CLEAR); // Borrar LCD
Delay_ms(500); // Retardo de 500ms
}
SENTENCIA CONTINUE
La sentencia continue colocada dentro de un bucle se utiliza para saltar una
iteración. A diferencia de la sentencia break, el programa se queda dentro del
bucle y las iteraciones continúan.
// Si x=7, puede ocurrir una división por 0.
// continue se utiliza aquí para evitar esta situación.
x=1;
while (x<=10) {
if (x == 7) { // saltar x=7 para evitar división por 0
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,3,"Division by 0");
Delay_ms(1000);
x++;
continue; // Después de esta línea, saltar a la sentencia while con x=8
}
SENTENCIA GOTO
La sentencia goto le permite hacer un salto absoluto al otro punto en el
programa. Esta característica se debe utilizar con precaución ya que su
ejecución puede causar un salto incondicional sin hacer caso a todos los tipos
de limitaciones de anidación. El punto destino es identificado por una etiqueta,
utilizada como un argumento para la sentencia goto. Una etiqueta consiste en
un identificador válido seguido por un colon (:).
...
if(CO2_sensor) goto aire acondicionado; // Si se consta que el valor
... // de la variable CO2_sensor =1
// hacer salto a la línea de programa
// Aire acondicionado
...
Aire acondicionado: // Desde aquí sigue la parte del código que se
ejecutará
// en caso de una concentración de CO2 demasiado
alta
... // en el ambiente
Para leer o modificar un elemento de matriz del ejemplo anterior, basta con
introducir su índice encerrado entre corchetes:
/* Se supone que a ha sido declarado anteriormente como un entero */
7 7 19
PUNTEROS
Un puntero es una variable destinada a recibir una dirección. Un puntero
“apunta” a una localidad de memoria, referenciada por una dirección. En C, la
dirección de un objeto se puede obtener por medio un operador unitario &.
Para acceder al contenido de la memoria en una dirección específica (también
llamado objeto apuntado), se utiliza un operador de indirección (*).
'&n' es la dirección de la localidad de memoria 'n'. '*(&n)' es el contenido de la
dirección '(&n)', o sea de 'n'. Para declarar un puntero, se debe que especificar
el tipo de la variable apuntada:
tipo_de_variable *puntero;
Los punteros son muy útiles para manejar las matrices. En este caso, un
puntero se utilizará para apuntar al primer elemento de una matriz. Debido al
hecho de que es posible realizar operaciones básicas sobre los punteros
(aritmética de punteros), es fácil manejar los elementos de una matriz. Fíjese
en la diferencia entre ‘*v+1’ y ‘*(v+1)’ en el siguiente ejemplo:
short int voltio[3] = {0,5,10};
short int *v;
v = &(voltio[0]); // v contiene la dirección de voltio[0]
*(v+1) = 2; // voltio[1] = 2
voltio[2] = *v+1; // tab[2] = 1 (tab[0] + 1)
*(v+2) = *(v+1); // voltio[2] = 2
v++; // v contiene la dirección de voltio[1]
*v = 1; // voltio[1] = 1
Los punteros también pueden ser declarados con el prefijo ‘const’. En este caso, su valor no puede
ser modificado después de la inicialización, similar a una constante.
A diferencia de C, el mikroC no admite alojamiento dinámico.
ESTRUCTURAS
Ya hemos visto cómo agrupar los elementos dentro de matrices. No obstante,
al utilizar este método todos los elementos deben ser del mismo tipo. Al utilizar
estructuras, es posible agrupar diferentes tipos de variables bajo el mismo
nombre. Las variables dentro de una estructura se le denominan los miembros
de la estructura. Las estructuras de datos se declaran al utilizar la siguiente
sintaxis:
struct nombre_de_estructura {
tipo1_de_miembro1 miembro1;
tipo2_de_miembro2 miembro2;
tipo3_de_miembro3 miembro3;
..
};
Por supuesto, igual que al utilizar los punteros, todavía se le permite realizar
operaciones por medio de operadores y sentencias definidos en las partes
anteriores. Si está familiarizado con el lenguaje C, recuerde que mikroC no
admite la inicialización de los miembros de estructura por medio de las llaves.
Por ejemplo, ‘conjunto_1 ={15,‘m’};’ devuelve un error en mikroC.
FUNCIONES
Una función es una subrutina que contiene una lista de sentencias a realizar.
La idea principal es dividir un programa en varias partes utilizando estas
funciones para resolver el problema inicial con más facilidad. Además, las
funciones nos permiten utilizar las destrezas y el conocimiento de otros
programadores. Una función se ejecuta cada vez que se llame dentro de otra
función. En C, un programa contiene como mínimo una función, la función
main(), aunque el número de funciones es normalmente mayor. Al utilizar
funciones el código se hace más corto ya que es posible llamar una función
tantas veces como se necesite. En C, el código normalmente consiste en
muchas funciones. No obstante, en caso de que su programa sea muy corto y
simple, puede escribir todas las sentencias dentro de la función principal.
FUNCIÓN PRINCIPAL
La función principal main() es una función particular puesto que es la que se
ejecuta al iniciar el programa. Además, el programa termina una vez
completada la ejecución de esta función. El compilador reconoce
automáticamente esta función y no es posible llamarla por otra función. La
sintaxis de esta función es la siguiente:
void main (void) {
..
.
};
Esto significa que f es una función que recibe un número real x como
parámetro y devuelve 2*x-y. La misma función en C se parece a lo siguiente:
float f (float x, float y) // variables flotantes x y y se pueden utilizar en f
{
float r; // declarar r para almacenar el resultado
r = 2*x - y; // almacenar el resultado del cálculo en r
return r; // devolver el valor de r
}
Note que una función no necesita parámetros (función main() por ejemplo),
pero debe estar entre paréntesis. En caso contrario, el compilador
malinterpretaría la función. Para hacerlo más claro, puede sustituir el espacio
en blanco encerrado entre paréntesis por la palabra clave void: main (void).
VALOR DEVUELTO
Una función puede devolver un valor (esto no es obligatorio) por medio de la
palabra clave return. Al llegar a return, la función evalúa un valor (puede ser
una expresión) y lo devuelve a la línea de programa desde la que fue llamada.
return r; // Devolver el valor contenido en r
return (2*x - y); // Devolver el valor de la expresión 2*x-y
Una función no puede devolver más de un valor, pero puede devolver un
puntero o una estructura. Tenga cuidado al utilizar matrices y punteros. El
siguiente ejemplo es un error típico:
int *reverse(int *tab) // Esta función debe devolver una matriz r
{ // cuyo contenido está en orden inverso con
// respecto a la matriz tab
int r[DIM]; // Declaración de una nueva matriz denominada r
int i;
for(i=0;i<DIM;i++) // Bucle que copia el contenido de tab en r
r[i] = tab[DIM-1-i]; // al invertir el orden
Si la función no devuelve ningún valor, la palabra void debe ser utilizada como
un tipo de resultado en la declaración. En este caso, la sentencia return no
debe ser seguida por ninguna expresión. Puede ser omitida como en el
siguiente ejemplo:
void wait_1 (unsigned int a)
{
cnt ++; // Incremento de una variable global cnt
Delay_ms(a) ; // Ejecución de la función Delay_ms
} // Note que Delay_ms no devuelve nada
void main() {
int maximum, input[SIZE] = {5,10,3,12,0}; // Declaración de variables en la matriz
maximum = sort(input); // Llamar a función y asignarle el máximo
// valor a la variable maximum
}
En este ejemplo, por medio de una función se realizan dos operaciones: ordena
los miembros de la matriz por valor asdendente y devuelve el máximo valor.
Para utilizar una matriz en una función es necesario asignar la dirección a la
matriz (o a su primer miembro). Vea el siguiente ejemplo:
float método_1(int[]); // Declaración de prototipo de la función Método_1
float método_2(int*); // Declaración de prototipo de la función Método_2
void main()
{
double promedio1, promedio2; // Declaración de las variables promedio1
// y promedio2
int voltaje [NÚMERO_DE_MEDICIONES] = {7,8,3,5,6,1,9}; // Declaración de la
// matriz voltaje
promedio1 = método_1(&voltaje[0]); // Parámetro de la función es la dirección
// del primer miembro
promedio2 = método_2(voltaje); // Parámetro de la función es la dirección de
// la matriz
}
//××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
float método_1(int voltaje[]) // Inicio de la función método_1
{
int i, suma; // Declaración de las variables locales i y suma
return(suma/NÚMERO_DE_MEDICIONES);
}
//××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
float método_2 (int *voltaje) //Inicio de la función método_2
{
int i, suma; // Declaración de las variables locales i y suma
return(suma/NÚMERO_DE_MEDICIONES);
}
DIRECTIV
FUNCIONES
AS
Definiciones de macro
Inclusiones de archivos
Control de compilación
Ahora, vamos a presentar sólo las directivas del preprocesador utilizadas con más
frecuencia. Sin embargo, no es necesario saber todas ellas para programar
microcontroladores. Sólo tenga en cuenta que el preprocesador es una herramienta
muy poderosa para los programadores avanzados en C, especialmente para el control
de compilación.
Por medio de la directiva #undef es posible quitar una definición de nombre de macro.
Así se especifica que la substitución que se ha definido anteriormente ya no va ocurrir
en el siguiente código. Esto es útil cuando usted quiere restringir la definición sólo a
una parte particular del programa.
#undef TANQUE // Quitar la definición del macro VOLUMEN
INCLUSIÓN DE ARCHIVOS
La directiva de preprocesador #include copia un archivo específico en el código fuente.
El código incluido debe observar la sintaxis de C para ser compilado correctamente.
Hay dos formas de escribir estas directivas. En el primer ejemplo, sólo el nombre de
archivo se especifica, así que el preprocesador lo buscará dentro del archivo include.
En el segundo ejemplo, se especifica la ruta entera, así que el archivo estará
directamente incluido (este método es más rápido).
#include <nombre_de_archivo> // Se especifica sólo el nombre del archivo
#include "C:\Ruta\nombre_de_archivo.h" // Se especifica la localidad
// exacta del archivo