Fundamentos de Programación 1
Fundamentos de Programación 1
0412-5620807 [email protected]
PROGRAMACIÓN EN LENGUAJE C
Este material pretende proporcionar o potenciar conocimientos acerca de las formas y aplicaciones
de las estructuras básicas de programación en Lenguaje C bajo el entorno MPLAB y el compilador
XC8, no de sustituir un libro de texto. Sin embargo, la destreza que pueda adquirir el lector de este
material se incrementa considerablemente en la cantidad de tiempo de compromiso intelectual que
el lector pueda dedicarle a la práctica de las estrategias de programación directamente en la
computadora.
USO DE COMENTARIOS
Los Comentarios permiten la documentación del código (especificar para qué sirve cada línea de
programa). Puede seleccionarse un bloque comenzando por /* y finalizando el bloque con */ o
agregando // al principio de la línea para volverla comentario hasta su final. Por ejemplo, los
comentarios se colocan de acuerdo a la siguiente sintaxis:
/* Este es un comentario de todo lo que se encuentre entre los caracteres */
// Este también es un comentario pero solo hasta el final de la línea
VARIABLES
Página 1 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
información almacenada en la variable (o sea, cuánto vale). Entonces, cuando se quiere hacer
referencia o buscar la información contenida en la variable, se puede preguntar por la casa o por la
dirección donde se encuentra ubicada la casa. Estas dos maneras de hacer referencia a una variable
se denominan Direccionamiento Directo (haciendo referencia directamente al nombre de la
variable) o Direccionamiento Indirecto (haciendo referencia a la dirección de memoria donde se
encuentra ubicada la variable.
Un µC asigna cierta cantidad de espacio de memoria RAM a una variable en dependencia al tipo de
variable que se desea crear. Por ejemplo, un caso muy común es disponer de un µC que posee
espacios de memoria de 8 bits (1 byte c/u), entonces para almacenar una variable de tipo “char”
utiliza un espacio completo de su memoria, pero si desea almacenar variables de tipo “int” o “float”
debe disponer de 2 espacios y 4 espacios de su memoria, respectivamente. El espacio que ocupa
cada tipo de variable en la memoria de un µC se puede visualizar en la siguiente tabla (8 bits
equivalen a 1 byte):
Hay que resaltar que cada variable ocupa una posición en la memoria, o sea que dos variables no
ocupan una misma posición, como en la figura anterior donde una variable ‘A’ tipo “char” ocupa
media posición en la memoria de un µC de 16 bits y los otros 8 bits no son aprovechados. Imagine el
caso donde dos variables diferentes (A y B) de tipo “char” compartan la misma posición de memoria
ya que ocupan cada una medio espacio: entonces cuando se haga el direccionamiento indirecto no
se sabría cual valor se está devolviendo, el valor de A o B. De hecho, el programa creerá que en
realidad es una sola variable de tipo “int” que ocupa toda la posición, y no dos variables “char” que
comparten la posición.
Página 2 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
Si en una operación aritmética se involucran variables del mismo tipo, entonces el resultado será
una variable del mismo tipo. Por el contrario, si variables de diferentes tipos son usadas en una
misma operación aritmética, el resultado debe ser almacenado en una variable de igual o mayor
capacidad que la variable con mayor capacidad en la operación. Por ejemplo, si se suma una variable
tipo “char” con una variable tipo “int” y la variable donde se almacena el resultado es de tipo “int” o
“float”, el resultado de la operación será de tipo “int” o “float” sin problemas porque estos formatos
tienen mayor capacidad. Sin embargo, existen casos donde el resultado de un cálculo se pretende
almacenar en una variable cuya capacidad es inferior a la capacidad de la variable involucrada en el
cálculo, entonces el resultado de la operación se ajusta al tipo de la variable resultado.
bit < char < int < long < float < double
Por ejemplo, si se desea almacenar el valor 3,14 en una variable tipo “char” o “int”, entonces se
almacenará únicamente el valor 3, ya que este tipo de variables no tiene la capacidad de almacenar
decimales, como una variable tipo “float”, por ejemplo. Otro caso sería almacenar un valor como
2019 en una variable tipo “unsigned char” cuyo formato solo puede almacenar números hasta 255.
Debido a que 2019 excede la capacidad de la variable donde se desea almacenar, el resultado sería
que se almacena el valor 234, que lógicamente no es lo que se esperaba.
Para realizar operaciones aritméticas entre variables se emplean los operadores comúnmente
usados y otros operadores especiales creados para el Lenguaje C. Estos operadores debe colocarse
en la ecuación entre dos variables, dos constantes o una variable y una constante. Es importante
mencionar que para que un cálculo aritmético que involucra solo variables de tipo “char” o “int” o
constantes enteras resulte un número decimal para asignarlo a una variable de tipo “float”, hay que
incorporar alguna constante que tenga un punto decimal, para que el lenguaje pueda interpretar
que el resultado que se quiere es decimal. En caso contrario, el valor resultante no será el esperado.
Página 3 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
OPERADORES RELACIONALES
Se usan en las proposiciones de control de los ciclos y las estructuras condicionales. Se incorporan
para comparar variables entre sí o variables con constantes. En ocasiones se olvida colocar “doble
igual” para comparar la igualdad entre dos expresiones, por lo que el compilador avisa como
warning que es posible que falte un igual; ya que es una comparación y no asignación.
== Es igual a a == 6 Si a es igual a 6
No es igual a (es
!= a != b Si a es diferente de b
diferente)
Los operadores lógicos se usan para comprobar proposiciones. Un cero (0) indica que la condición
no se cumple o es falsa y un uno (1) indica que la condición se cumple o es verdadera. Según sea su
uso, el resultado de la operación lógica “&&” u “||” será verdadera o falsa en correspondencia con las
respectivas tablas de verda. El operador lógico “!” simplemente niega la condición lógica.
OPERADORES BITWISE
Página 4 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
Los operadores bitwise se utilizan para hacer operaciones lógicas entre los bits de las variables
usadas como operandos. Es común hacer operaciones bitwise entre los bits de una variable y los
bits de una constante. Por ejemplo, se puede emplear & 0xF0 para seleccionar el nibble alto de una
variable o se puede emplear & 0x0F para seleccionar el nibble bajo de una variable. Hay que resaltar
que estos operadores se usan sobre bits, no sobre proposiciones, o sea que & es diferente a && y | es
diferente a ||.
Otra forma práctica de usar un operador bitwise es rotar los bits de una variable a la derecha
usando >> o a la izquierda usando <<. Cada vez que se rota un bit a la derecha es equivalente a
realizar sobre la variable una división por 2, o sea que la expresión A>>4 es equivalente a A/16, o
A/24. Por el contrario, cada vez que se rota un bit a la izquierda es equivalente a realizar sobre la
variable una multiplicación por 2, o sea que la expresión A<<3 es equivalente a A*8, o A*23.
Página 5 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
Página 6 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
while(1)
{
// Instrucciones a ejecutar
} // fin del ciclo infinito
} // fin del cuerpo principal
NOCIONES INICIALES:
Si la estructura de operación posee solo una acción a ejecutar, se puede colocar esta acción
entre llaves o no. En caso de querer ejecutar más de una acción, deben colocarse llaves para
indicar dónde comienza y termina la estructura.
Las condiciones (o proposiciones) son de tipo BOOLEANO, o sea, solo pueden adoptar dos
valores: 0=falso o 1=verdadero. Si el valor es 1 o verdadero se cumplirá la condición y las
instrucciones dentro de la estructura se ejecutarán, en caso que la condición sea 0 o falsa no
se ejecutarán las acciones de la estructura y el programa saltará a la próxima instrucción.
El operador && aplica la conjunción entre dos condiciones y el operador || aplica la
disyunción entre dos condiciones. Es posible combinar dos o más condiciones o
proposiciones con estos operadores.
Una condición correcta se realiza cuando se emplean dos operandos y un operador. Los
operandos pueden ser variables o números y los operadores ==, !=, <, <=, >, >=, por ejemplo:
Var1==123, Var>2, 89!=Contador, ADC==ADC_ANTERIOR. En este lenguaje se usan los
operandos a los extremos y el operador lógico en medio de los operandos.
ESTRUCTURA CONDICIONAL if
TOPOLOGÍA: if (condición)
USO: Se utiliza en casos donde se requiere realizar una acción en dependencia del valor de la
variable que establece la condición. Se recomienda usar esa estructura cuando la variable de la
condición presenta solo dos alternativas, tal como el estado de un pulsador o botón (0: no
presionado y 1: presionado), un sensor on-off de nivel (0: activo y 1: no activo). En caso contrario se
debe implementar una estructura con if anidados.
/* si el pulsador se presiona por lo menos una vez se enciende el led LED indefinidamente porque
no existe una instrucción que lo apague, o sea, LED = 0**/
Página 7 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
/* si el pulsador se presiona por lo menos una vez se enciende el led LED indefinidamente porque
no existe una instrucción que lo apague, o sea, LED = 0**/
/**** solo cuando el pulsador está presionado enciende el led LED *****/
EJEMPLO 5: Cuando se deben chequear dos condiciones pero no se quiere utilizar && se pueden
usar if anidados, o sea, un if dentro de otro if:
Es igual utilizar:
Página 8 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
Es igual utilizar:
TOPOLOGÍA:
switch(variable)
{
case 0: { /*acciones a realizar*/ break; }
case 1: { /*acciones a realizar*/ break; }
USO: Se utiliza en casos donde se requiere la variable a discriminar adquiere más de dos valores. La
variable puede tomar “n” valores y la opción “default” especifica que hacer en los casos no
contemplados. Note que cada caso tiene sus propias llaves y su propio break, ya que con una sola
Página 9 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
instrucción y el break se convierten en dos acciones y debe implementar llaves. La instrucción break
se coloca para indicarle al compilador que aborte la estructura switch una vez que ejecute las
acciones propias del caso. En el siguiente ejemplo la estructura switch verifica el valor de la variable
CONT y ejecuta las acciones dependiendo de lo contemplado en la coincidencia de caso.
EJEMPLO 1:
switch(CONT)
{
case 0: { LED1 = 0; LED2 = 0; break; }
case 1: { LED1 = 1; LED2 = 0; break; }
case 2: { LED1 = 1; LED2 = 0; break; }
default: { LED1 = 1; LED2 = 1; break; }
}
Esta estructura se utiliza para acortar las líneas de programación y visualizar eficientemente los
casos. En lugar de un switch, se podría usar esta secuencia de if:
if (CONT==0)
{ LED1 = 0; LED2 = 0; }
if (CONT==1)
{LED1 = 1; LED2 = 1; }
if (CONT==2)
{LED1 = 0; LED2 = 1; }
if (CONT>=3)
{LED1 = 1; LED2 = 1;}
switch(MENU)
{
case 0: {
if (INC)
{ NUM1++; __delay_ms(250); }
if (DEC)
{ NUM1--; __delay_ms(250); }
break;
}
case 1: {
if (!OK)
NUM = 255;
else
{ AUX = NUM; __delay_ms(250); }
break;
}
}
Página 10 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
if(5<=CONT)&&(CONT <10))
switch(CONT)
{
case 5: { PORTA = CONT; break;}
case 6: { PORTB = CONT; break;}
case 7: { LED_ROJO = 1; break;}
case 8: { LED_VERD = 1; break;}
case 9: {continue; break;}
}
else
{
PORTA = 0;
PORTB = 0;
LED_ROJO = 0;
LED_VERD = 0;
}
TOPOLOGÍA:
for(Valor_Inicial; Condición; Forma)
{
//Acciones a ejecutar
}
USO: Se utiliza en casos donde se conoce la cantidad de veces que se desea ejecutar una acción. La
cantidad de veces que se repetirá este ciclo depende del valor de una variable entera (unsigned char
o unsigned int) Posee 3 parámetros:
1. Valor_Inicial: Por ejemplo, I=0 especifica que la variable que controla el ciclo es “I” y su
valor inicial es 0 en este caso.
2. Condición: Por ejemplo, I<7 especifica que el ciclo se repetirá siempre que la variable “I” sea
menor a 7 en este caso.
3. Forma: Indica la manera como se modificará la variable que controla el ciclo. Por ejemplo,
I++ indica que la variable se incrementará en una unidad cada vez que se repita el ciclo. En
caso que la Forma sea I—2 especifica que la variable que controla el ciclo “I” reducirá su
valor en 2 unidades cada vez que se repita el ciclo.
Página 11 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
EJEMPLO 1: Al Puerto C del µC se le asigna el valor de la variable “I” que controla el ciclo. Se
desea repetir el ciclo 200 veces, partiendo de cero y que la variable se incremente de uno en
uno.
for (I=0;I<200;I++)
PORTB = I;
EJEMPLO 2: Se desea encender 30 veces y apagar 30 veces un diodo led conectado al µC y que
encienda y apague cada 5 segundos.
EJEMPLO 4: Se desea enviar uno a uno los valores de una variable unsigned char llamada “A”
(comenzando por el último valor) a través del pin 7 del puerto B del µC.
EJEMPLO 4: Se desea enviar uno a uno los valores de una cadena de valores unsigned char
llamada “CAD” a través del puerto C del µC comenzando por el primero.
Página 12 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
TOPOLOGÍA:
while(Condición)
{
//Acciones a ejecutar
}
USO: Se utiliza en casos donde no se conoce la cantidad de veces que se repetirá el ciclo. El ciclo se
repite solo si se cumple la condición.
EJEMPLO 2: Encender y apagar un diodo led cada segundo indefinidamente hasta que se toque
un pulsador ‘PULL’.
Página 13 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
EJEMPLO 4: Chequear si se activan los pulsadores INC y DEC para incrementar o decrementar la
variable MENU. Aborte el ciclo en caso que el pulsador OK se active.
while(!OK)
{
if (INC) MENU++; // si se activa INC se incrementa MENU
if (DEC) MENU--; // si se activa DEC se decrementa MENU
}
EJEMPLO 5: Diseñar el equivalente a la estructura del ciclo for(I=0;I<10;I++) usando ciclo while.
Para diseñar el equivalente es necesario crear la variable “I” para mantener la condición e
inicializarla antes de entrar al ciclo.
1. Diseñe un programa para un microcontrolador PIC12F510 que use el cristal interno a 4MHz. Se
desea configurar todos los pines de salida excepto GP3 (consulte el datasheets para comprender por
qué). Se desea encender y apagar un diodo led color amarillo conectado a GP0 cada segundo.
2. Sin usar condicionales, diseñe un programa para un microcontrolador PIC12F510 que use el cristal
interno a 4MHz, configurando todos los pines de salida excepto GP3 (consulte el datasheets para
comprender por qué). Se desea:
a. Encender y apagar un diodo led color amarillo conectado a GP0 cada segundo.
b. Encender y apagar un diod led color rojo conectado a GP1 cada medio segundo.
3. Usando condicionales, diseñe un programa para un microcontrolador PIC12F510 que use el cristal
interno a 4MHz, configurando todos los pines de salida excepto GP3 (consulte el datasheets para
comprender por qué). Se desea:
a. Encender y apagar un diodo led color amarillo conectado a GP0 cada segundo.
b. Encender y apagar un diod led color rojo conectado a GP1 cada medio segundo.
Página 14 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
5. En base al diseño anterior, se desea hacer un programa que encienda todos los diodos led cuando se
presionen por lo menos dos pulsadores (no importa cuáles sean) y se apaguen cuando se dejen de
presionar, o sea, los diodos se encienden cuando se presiona P1 y P2, o P1 y P3, o P1 y P4, y así con
todas las demás combinaciones.
6. En base al diagrama eléctrico del ejercicio 4, se desea que usted diseñe un programa que encienda
indefinidamente todos los diodos led cuando se presione P1 y P3, pero se apaguen indefinidamente
cuando se presione P2 y P4.
7. En base al diagrama eléctrico del ejercicio 4, se desea que usted diseñe un programa que:
Encienda el led verde cuando se presione P1 o P2.
Encienda el led rojo cuando se presione P1 o P3.
Encienda el led amarillo cuando se presione P2 o P4.
Encienda el led azul cuando se presione P3 o P4.
Cuando se dejan de presionar los pulsadores se apagan los leds encendidos.
8. En base al diagrama eléctrico del ejercicio 4, se desea que usted diseñe un programa que encienda el
diodo verde cuando se presione P1 y se apague cuando se vuelva a presionar, emulando un flip flop
tipo T.
9. En base al diagrama eléctrico del ejercicio 4, se desea que usted diseñe un programa que encienda
los diodos consecutivamente cuando se presiona el pulsador P3, o sea, se enciende el diodo verde si
se presiona P3 una vez, pero enciende el diodo rojo si se presiona nuevamente, y así con todos los
diodos restantes. Cuando llega al final se apagan todos los diodos para volver a comenzar con el
verde. Use la estructura de programación if.
10. En base al diagrama eléctrico del ejercicio 4, se desea que usted diseñe un programa que encienda
los diodos consecutivamente cuando se presiona el pulsador P3, o sea, se enciende el diodo verde si
se presiona P3 una vez, pero apaga el diodo verde y enciende el diodo rojo si se presiona
nuevamente (apaga uno antes de encender el próximo), y así con todos los diodos restantes. Cuando
llega al final se apagan todos los diodos para volver a comenzar con el verde. Use la estructura de
programación if.
11. En base al diagrama eléctrico del ejercicio 4, se desea que usted diseñe un programa que encienda
los diodos consecutivamente cuando se presiona el pulsador P3, o sea, se enciende el diodo verde si
se presiona P3 una vez, pero apaga el diodo verde y enciende el diodo rojo si se presiona
nuevamente, y así con todos los diodos restantes. Cuando llega al final vuelve a comenzar con el
verde. Use la estructura de programación switch.
12. Resuelva los ejemplos del material de apoyo y los ejercicios propuestos del tema de lógica
combinacional y mapas de Karnaugh mediante el uso de un PIC16F873A, un cristal de 8MHz,
capacitores de 22pF, pulsadores o interruptores simulando las condiciones de entrada y diodos led
simulando los dispositivos de salida. Use únicamente las estructuras condicionales if o switch
además del ciclo infinito.
Página 15 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
14. Según el diagrama eléctrico del ejercicio 13, se requiere diseñar un programa usando la estructura
repetitiva “for” que muestre en la barra gráfica conectada en el puerto B el valor binario de un
contador que comience en cien y se decremente de dos en dos hasta 50.
15. Según el diagrama eléctrico del ejercicio 13, se requiere diseñar un programa que encienda los
segmentos pares de la barra gráfica conectada en el puerto B si el valor de un contador que
comienza en 15 y termina en 30 es par, y que encienda los segmentos impares de la barra si el valor
del contador es impar.
16. Según el diagrama eléctrico del ejercicio 13, se requiere diseñar un programa que muestre en el
primer segmento de la barra gráfica conectada en el puerto B sólo el último bit del contador que
comienza en 1 y termina en 10 cada segundo.
17. Según el diagrama eléctrico del ejercicio 13, se requiere diseñar un programa que muestre en el
primer segmento de la barra gráfica conectada en el puerto B los últimos 4 bits que componen un
contador que comienza en 1 y termina en 10 cada segundo, comenzando de derecha a izquierda, o
sea, sí el contador es cinco (0b00000101 en binario) se debe encender el segmento un segundo (1),
apagarse un segundo(viene 0), encenderse un segundo (viene 1) y apagarse un segundo (0). Use un
ciclo “for” dentro de otro ciclo “for”: el ciclo más externo para controlar el contador y el ciclo más
interno para mostrar los bits.
18. Repita el ejercicio anterior pero mostrando todos los bits del contador de izquierda a derecha.
Sugerencia: use un ciclo “for” antes sólo para invertir una copia del contador y luego mostrarla.
20. Repita el ejercicio anterior (sin el 74LS48) usando la estructura condicional switch dentro de un
ciclo for para visualizar letras, o sea, se muestra la letra “A” o “a” cuando el contador sea 0, “B” o “b”
cuando el contador sea 1 y así sucesivamente hasta 9.
Página 16 de 17
Dr. Julio J. Mendoza H.
0412-5620807 [email protected]
22. Rediseñe los programas anteriores para cambiar las estructuras “for” por “while”.
23. Se requiere visualizar en un display 7 segmentos el valor de un número equivalente al valor de una
tecla presionada (teclado telefónico). Use un PIC18F4550 y su cristal interno a 20MHz, y un display
7 segmentos ánodo común. El valor se debe mostrar sólo 3 segundos en el display.
Página 17 de 17