1
Autor: Wilmer Planchez Febrero, 2013.
1.- ESTRUCTURA DE UN PROGRAMA EN C
Todo programa en C orientado a microcontroladores cumple con la siguiente estructura:
1.1.- CABECERA.
En la cabecera se incluyen características importantes para el manejo del PIC,
las cuales son:
- Código del microcontrolador.
- Configuración de Fusibles.
- Frecuencia de oscilación.
- Renombramiento de pines.
1.1.1.- CÓDIGO DEL MICROCONTROLADOR.
Para incluir el microcontrolador con el cual se va a trabajar se debe hacer uso de
la directiva #include.
Archivos (conocidos como header File) que posean extensión .h. Estos archivos
contienen información sobre funciones sus argumentos, el nombre de los pines de un
modelo determinado de PIC o cualquier otra herramienta que con frecuencia en nuestros
programas.
2
Autor: Wilmer Planchez Febrero, 2013.
Sintaxis:
#include <archivo>
Ejemplo #1:
#include <16f84A.h>
Donde “<16f84A.h>” es el microcontrolador que queremos utilizar. Por convención,
se utiliza la extensión .h para los archivos de cabecera. Algunos de los
microcontroladores más usados y comunes en el mercado son:
- PIC 12F629 (8 Pines).
- PIC 16F628A (16 Pines).
- PIC 16F873A (28 Pines).
- PIC 16F877A (40 Pines).
- PIC 18F4550 (40 Pines).
1.1.2.- CONFIGURACIÓN DE FUSIBLES.
Los fusibles son características, que posee cada microcontrolador y varían de un
modelo a otro. Todos los microcontroladores tienen 2 tipos de configuraciones
comunes, y que son indispensables que aparezcan, las cuales son:
- Tipo de oscilador.
- Configuracion del Wathcdog.
1.1.2.1.- TIPOS DE OSCILADOR:
a) LP: Oscilador LP (Low Power). Se usa cuando el PIC va a trabajar con un
cristal de baja potencia. (Fosc < 200 Khz).
b) XT: Oscilador XT. Debe utilizarse cuando el PIC Trabajará con un cristal o
resonador de frecuencias iguales o menores a 4Mhz. (Fosc <= 4Mhz).
c) HS: Oscilador HS (High Speed). Para cristales o resonadores con frecuencias
mayores a 10Mhz. (Fosc >10Mhz)
d) RC: Oscilador RC (Resistor/Capacitor). Se usa cuando el PIC va a operar con
un circuito RC.
3
Autor: Wilmer Planchez Febrero, 2013.
1.1.2.2.- CONFIGURACIÓN WATCHDOG.
¿Qué es el Watchdog?
El Watchdog (“Perro Guardian”) o WDT es un temporizador que una vez
alcanzado su tiempo límite puede provocar un reset en el PIC. El Watchdog cuenta cada
ciertos pulsos de reloj en un determinado tiempo, esperando algún evento generado por
el programa, si este evento no ocurre el Watchdog se activa y hace que todo empiece de
nuevo debido a que el programa a realizado una acción no prevista.
Para activar o desactivar el Watchdog se usan las siguientes sentencias:
NOWDT: No Watch Dog Timer. Deshabilitación del Watchdog.
WDT: Watch Dog Timer. Habilitación del Watchdog.
Las sentencias para indicar el tipo de oscilador y la configuración del Watchdog
se escriben en una sola línea, escribiendo la directiva #fuses.
#fuses: Permite modificar el Valor de los fusibles del microcontrolador que
estamos utilizando. Los valores posibles dependen de cada microcontrolador en
particular.
Sintaxis:
#fuses Opciones
Opciones es una lista de las opciones posibles separadas mediante comas. Algunos
valores comunes son:
Tipo de oscilador: LP, XT, HS, RC.
WatchDog Timer: WDT, NOWDT.
Protección de código: PROTECT, NOPROTECT.
4
Autor: Wilmer Planchez Febrero, 2013.
Ejemplo #2:
#fuses XT,NOWDT
Indica que el tipo de oscilador utilizado es del tipo XT (Fosc <= 4Mhz) y el
Watchdog está deshabilitado.
1.1.3.- FRECUENCIA DE OSCILACIÓN.
Las instrucciones en el microcontrolador necesitan de un ciclo de máquina para
ejecutarse y este depende de la frecuencia de oscilación del cristal externo, o una fuente
de reloj interna. Se recomienda usar Cristales o resonadores para tener precisión, es muy
útil cuando se desea trabajar con más de un microcontrolador y se desea que estén
sincronizados.
1 Ciclo de Maquina = 4 Ciclos de reloj
Tcm = 4 / Fosc = 4 * Tosc
Donde:
Tcm : Ciclo de máquina.
Fosc: Frecuencia de oscilación del cristal, resonador, o circuito RC.
Tosc: Periodo de oscilación del cristal , resonador, o circuito RC.
Ejemplo #3:
Calcular el ciclo de máquina para una frecuencia de oscilación de 4Mhz.
Fosc = 4Mhz
Tosc = 1 / 4Mhz = 0,25us = 0,26 x 10-6 segundos
Tcm = 4 * 0,25us = 1us
Cada instrucción en el microcontrolador se ejecutará en 1us.
Para incluir la frecuencia de oscilación con la que se va a trabajar se usa la
directiva #use delay. Esta directiva indica al compilador la frecuencia del procesador, en
ciclos por segundo, a la vez que habilita el uso de las funciones delay_ms() y
5
Autor: Wilmer Planchez Febrero, 2013.
delay_us(), las cuales se usan para hacer retardos en milisegundos y microsegundos
respectivamente.
Sintaxis:
#use delay (clock= Frecuencia)
Ejemplo #3:
#use delay (clock=4000000)
En este caso se indica que la frecuencia de oscilación con la que se va a trabajar es de
4Mhz.
1.1.3.1.- FUNCIONES DE RETARDOS
DELAY_MS(time)
Esta función realiza retardos del valor especificado en time. Dicho valor de
tiempo es milisegundos y el rango es 0 – 65535.
Ejemplo #4a:
delay_ms(1000); //retardo de 1 segundo
DELAY_US(time)
Esta función realiza retardos del valor especificado en time. Dicho valor de
tiempo es microsegundos y el rango es 0 – 65535.
Ejemplo #4b:
delay_us(50); //retardo de 50 microsegundos
1.1.4.- RENOMBRAMIENTO DE PINES.
Para el renombramiento de pines se usa la directiva #define. La instrucción #define
tiene la siguiente forma:
#define <Label> value
<Label> es la etiqueta que usaremos en nuestro programa. Y value es el valor que
estamos asignando a la etiqueta.
6
Autor: Wilmer Planchez Febrero, 2013.
Sintaxis: (Cambiar el nombre de un pin)
#define Nombre pin_xn
Donde:
x: Letra que indica el puerto
n: Número de pin (0 a 7)
Ejemplo #5:
#define led1 pin_b0 // El pin B0 ahora se llama Led1
1.2.- PROGRAMAS O FUNCIONES.
Las funciones son un conjunto de instrucciones. Pueden existir muchas
funciones las cuales deben ser definidas antes de ser usadas, siempre existirá una
función principal llamada main(). La función principal Siempre debe existir, e indica el
punto en el que comenzara a funcionar el programa.
1.3.- INSTRUCCIONES
Las instrucciones o sentencias indican como se debe comportar el PIC, este
realizará solo aquello que se le indique.
1.4.- COMENTARIOS
Los comentarios facilitan la comprensión del programa, describiendo el
funcionamiento de cada línea de código. Los comentarios son ignorados cuando se
compila el código. Existen dos formas de hacer comentarios:
1.4.1.- COMENTARIOS DE UNA LINEA
Para escribir comentarios que ocupen una sola line se hace uso del doble Slash (//)
Ejemplo #6:
// Este comentario ocupa una sola línea
7
Autor: Wilmer Planchez Febrero, 2013.
1.4.2.- COMENTARIOS QUE OCUPAN MÁS DE UNA LINEA.
Los comentarios que ocupan más de una línea se escriben de la siguiente manera:
/* Linea de comentario 1
Linea de comentario N */
/*: Indica que se inicia el comentario
*/: Cierre del comentario
Ejemplo #7: Estructura de un programa en C.
#include <16f84A.h> //Microcontrolador a utilizar
#fuses xt,nowdt //Oscilación del cristal <= 4mhz
//Whatchdog desactivado
#use delay (clock=4000000) //Frecuencia del cristal de 4Mhz
void main(){ // Inicio Función Principal
Sentencias; // Instrucciones. Estructuras de control
} // Fin de la Función Principal
Seguramente se estará preguntando el significado de “void”, las llaves { }, y para que
sirve el punto y coma (;).
Void es una palabra reservada en lenguaje C. En nuestro caso tenemos lo siguiente:
void main() quiere decir que la función main() no devolverá parámetros o
valores. Más Adelante se explicaran en detalle aspectos importantes sobre las funciones.
USO DE LAS LLAVES {. . .}
C es un lenguaje estructurado o modular en el que un programa está formado por
“bloques”. Los elementos que componen un bloque deben estar relacionados entre sí.
Lo que indica que lo encerramos entre llaves.
{ // INICIO DEL BLOQUE
} // FINAL DEL BLOQUE
8
Autor: Wilmer Planchez Febrero, 2013.
USO DEL PUNTO Y COMA (;)
El punto y coma indica el final de una sentencia en C. En el Ejemplo #7
generalizamos las instrucciones escribiendo:
Sentencia 1;
Sentencia 2;
O también se pudo haber escrito:
Sentencia 1; Sentencia 2;
Ambas formas son validas, el final de una sentencia y el inicio de la otra son
indicados con el punto y coma (;).
2. DATOS. TIPOS DE DATOS
Un dato es toda información que almacena el ordenador.
2.1 TIPOS DE DATOS
En cualquier lenguaje de programación siempre existirán 4 tipos de datos
fundamentales, estos son:
i) Numéricos.
ii) Reales.
iii) Alfanuméricos.
a. Letras.
b. Números.
c. Caracteres especiales.
d. Una mezcla de todo lo anterior.
iv) Booleanos. Solo pueden tener 2 valores, verdadero o falso.
El compilador CCS C acepta los siguientes tipos de datos.
9
Autor: Wilmer Planchez Febrero, 2013.
3.- CONSTANTES
4.- VARIABLES.
Las variables son zonas de la memoria RAM que se utilizan para almacenar datos; se
deben declarar antes de ser utilizadas; para ello se debe indicar el nombre y el tipo de
dato que se manejará.
Sintaxis:
Tipo_Dato Nombre_variable;
Ejemplo #8:
int Numero;
Float Voltaje;
10
Autor: Wilmer Planchez Febrero, 2013.
Al declarar las variables se le pueden asignar valores iniciales, de no hacerlo, estas
tendrán un valor por defecto igual a cero (0).
int Valor = 25;
Float Presion = 4.5;
Podría darse el caso, en el cual se declaren variables del mismo tipo, el lenguaje C nos
brinda una forma elegante de hacerlo.
Int Numero_1, Numero_2 , Valor = 25;
Float Voltaje, Presion = 4.5;
4.1.- IDENTIFICADORES.
Los identificadores o nombres de variables pueden estar formados por letras números o
guion bajo ( _ ) y deben comenzar por letra o guion bajo. No deben tener espacios. El
guión bajo es el único carácter especial permitido para asignar el nombre de una
variable o función, no se permite la letra “ñ” ni las letras acentuadas. Lenguaje C
diferencia entre mayúsculas y minúsculas, esto quiere decir que una variable llamada
“Numero” será diferente de una llamada “numero”.
A continuación unos ejemplos de Nombres no válidos para las variables.
Ejemplos #9:
Int 2Caras; // Empieza por un numero (Error)
Float Primer Numero; // Contiene un espacio (Error)
Int16 Año; // La letra “ñ” (Error)
Long Más_Personas; // Tiene una vocal acentuada (Error)
11
Autor: Wilmer Planchez Febrero, 2013.
5.- OPERADORES
5.1- ASIGNACIÓN.
5.1- ARITMÉTICOS.
5.1.1- INCREMENTO Y DECREMENTO.
Sintaxis:
Forma 1: Notación normal.
A = A + 1;
A = A – 1;
12
Autor: Wilmer Planchez Febrero, 2013.
Forma 2: Notación compacta.
A++;
A--;
En resumen:
A++ es lo mismo que A = A + 1.
A-- es lo mismo que A = A - 1.
5.1.1.1- Postincremento.
B = A++;
Se asigna a B el valor de A y se incrementa el valor de A tras asignar su valor. Por lo
tanto si A = 1, entonces:
B=1; // Se asigna el valor de A (B = A = 1)
A=2; // Se incrementa el valor de A
5.1.1.2- Preincremento.
B = ++A;
Primero se incrementa el valor de A y después asigna su valor. Por lo tanto si A = 1,
entonces:
A = 2; // Se incrementa el valor de A
B = 2; // Se asigna el valor de A (B = A = 2)
El Predecremento y el Postdecremento funcionan de la misma manera.
13
Autor: Wilmer Planchez Febrero, 2013.
5.2 RELACIONALES.
5.3 LÓGICOS.
5.4 DE BITS.
14
Autor: Wilmer Planchez Febrero, 2013.
6.- FUNCIONES.
Las funciones tienen la siguiente forma:
Nombre_funcion() { // Cuerpo de la función
Instrucción 1;
Instrucción 2;
.
.
Instrucción n;
}
Las funciones terminan y regresan automáticamente al procedimiento que las llamó
cuando se encuentra la ultima llave}.Se deben declarar las funciones antes de utilizarlas
de igual manera como se hace con las variables.
6.1.- PROTOTIPOS DE FUNCIONES
Un prototipo es una declaración de una función. Consiste en una presentación de la
función con la misma estructura que la definición, pero sin cuerpo y termina con un “;”.
El prototipo le indicara al compilador el tipo de datos que la función regresara y el tipo
de parámetros que la función espera.
Sintaxis:
Tipo_Funcion nombre_funcion();
Donde “Tipo” es cualquiera de los tipos de variables soportados en CCS.
Ejemplo #10:
Long Ejemplo();
15
Autor: Wilmer Planchez Febrero, 2013.
6.2.- PARÁMETROS.
Además de determinar el tipo de resultado que devolverá la función, en el prototipo
podemos especificar que parámetros recibirá. Y de que tipo serán. La forma de hacerlo
es la siguiente:
Tipo_Funcion nombre funcion(Tipo variable1,Tipo variable2,…);
6.3.- DEFINICION DE UNA FUNCIÓN.
Luego de haber indicado el prototipo de la funcion, esta debe ser definida luego de la
función principal. Una función con parámetros podría ser la siguiente:
double Division(float x,float y){ // Cuerpo de la funcion
double Resultado;
x = 10;
y = 250;
resultado = x/y;
return resultado /* la función retorna el valor de
de la variable resultado*/
}
6.4.- VOID
Significa que la función no devolverá ningún parámetro. Supongamos que la función
Ejemplo_x() no debe regresar ningún valor luego de ser llamada. Su prototipo debería
ser como sigue:
void Funcion_1();
Además, podemos usar void para indicar que la función no recibe parámetros, ni
devuelve ningún valor.
void Funcion_2(void);
ó
void Funcion_2();
16
Autor: Wilmer Planchez Febrero, 2013.
6.5.- LLAMADA DE UNA FUNCIÓN.
Cuando un programa llama a una función, la ejecución del programa se trasfiere a dicha
función el programa retorna a la sentencia posterior a la llamada cuando se acaba la
función.
Sintaxis:
Nombre(Parámetros); /* Los parámetros son opcionales
Dependen de la función*/
Nombre es el identificador con el que es definida la función a la que queremos llamar.
Parámetros es la lista de valores que se asigna a cada parámetro de la función(en caso
de que tenga, estos se separan por comas).
Ejemplo #11:
Tiempo(); /*Llamada de la función Tiempo la cual no recibe
Parámetros*/
17
Autor: Wilmer Planchez Febrero, 2013.
7.- ESTRUCTURAS DE CONTROL.
Las estructuras de control se utilizan para tomar decisiones, realizar tareas repetitivas o
de bucle; son la base de cualquier lenguaje de programación, por lo tanto, su dominio es
fundamental. El inicio y el cierre de las estructuras de control se indica haciendo uso de
las llaves { }, de forma idéntica como se hace con las funciones. Las estructuras o
declaraciones de control que admite CCS son:
If - Else.
While.
Do-While
For.
Switch - Case.
Continue-Break-Goto.
7.1.- ESTRUCTURAS ALTERNATIVAS.
7.1.1.- IF: (“Si. . . entonces. . .”).
Con esta estructura se pueden tomar decisiones.
Sintaxis:
If(Condición){ // Inicio de la estructura IF
Sentencias;
} // Fin del IF
Ejemplo #12:
If(B1 == 0){ // Si B1 es igual a 0 entonces . . .
B2 = 10;
B3 = 5;
}
Haciendo uso de los operadores lógicos podemos escribir cosas como:
If((B1 == 0)&&(C==1)){ //Operación AND: Se deben cumplir
Sentencias; //Las 2 condiciones*/
}
18
Autor: Wilmer Planchez Febrero, 2013.
O también:
If((B1 == 0)||(C==1)){ // Operación Or: Se debe cumplir
Sentencias; // Alguna de las 2 condiciones
}
7.1.2.- ELSE : (“En Caso contrario . . .”)
Esta estructura se usa siempre con un if la cual indica que si la condición del if no es
verdadera entonces se ejecutan las sentencias del bloque else.
Sintaxis:
If(Condición){ // Inicio de la la estructura IF
Sentencias;
}// Fin del IF
Else{ // Inicio de la la estructura Else
Mas_Sentencias;
}// Fin del else
Ejemplo #13:
If(A == 1){ // Si A es igual a 1 entonces . . .
B = 2;
C = 7;
}
Else{ En caso contrario: A no es igual a 1 entonces . . .
B = 0;
C = 0;
}
19
Autor: Wilmer Planchez Febrero, 2013.
7.1.2.- ELSE IF.
Se pueden enlazar los if usando else para decir, si no se cumple esta condición, ve si se
puede ejecutar esta otra.
Sintaxis:
If(Condición){ // Inicio de la la estructura IF
Sentencias;
}// Fin del IF
Else if(Condición){ // Inicio del Else If
Sentencias;
} // Fin Else If
Else{ // Ninguna de las condiciones se cumple.
Sentencias;
} // Fin del else
20
Autor: Wilmer Planchez Febrero, 2013.
7.1.1.- SWITCH – CASE.
Si queremos preguntar por varias condiciones, sería muy pesado tener que hacerlo con
muchos if seguidos.
Sintaxis:
switch(Variable){
Case valor1:
Sentencias;
break;
Case valor2:
Sentencias;
break;
Case valor3:
Sentencias;
break;
default:
Sentencias;
}
Donde Variable es la variable por la cual vamos a preguntar, valor1, valor2 y valor3
son los posibles valores de las variables. La palabra reservada break indica que cuando
el compilador ejecute esa línea, se saldrá automáticamente de la estructura switch, de no
escribir esa sentencia, el programa seguirá preguntando por el resto de las condiciones y
ejecutando las instrucciones hasta que finalice la estructura, se cumpla una condición , o
se encuentre con la instrucción break.
La sentencia default es opcional (no es necesario colocarla) y es la opción que se
ejecutará si ninguno de los valores coincide, por lo tanto default, es la opción que se
ejecutara por defecto.
21
Autor: Wilmer Planchez Febrero, 2013.
Ejemplo #14:
switch(X){
Case 5:
Y = 1;
break;
Case 10:
Y = 2;
break;
Case 15:
Y = 3;
break;
default:
break;
}
7.2.- ESTRUCTURAS REPETITIVAS.
7.2.1.- FOR.
For se usa para repetir sentencias un número determinado de veces.
Sintaxis:
For(inicialización ; condición de finalización ; inc. ó dec.){
Sentencias;
}
Inicialización es una variable que definirá el punto desde el cual comenzará a
incrementarse la estructura. La condición de finalización, indica hasta donde se
ejecutará el bucle. Por último, la expresión de incremento o decremento modifica la
variable de control después de ejecutar el bucle.
Si se ejecuta la siguiente expresión se consigue un bucle sin fin.
22
Autor: Wilmer Planchez Febrero, 2013.
For( ; ; ){
Sentencias;
}
Ejemplo #15:
For(i=0;i<=15;i++){
Printf(“%u”,i); /* Imprime en pantalla los números del 0 al 15.*/
}
7.2.2.- WHILE / DO-WHILE.
WHILE se utiliza para repetir sentencias, hasta que una determinada condición se
cumple.
Sintaxis:
while(condición){
Sentencias;
}
La condición se evalúa y la sentencia se ejecuta mientras la expresión sea verdadera,
cuando es falsa se sale del While. Si la expresión es verdadera desde un principio, el
bucle While no ejecuta las sentencias ni una sola vez.
DO-WHILE se diferencia del WHILE y del FOR en la condición de finalización, la
cual se evalúa al final del bucle, por lo que las sentencias se ejecutan al menos una vez.
Sintaxis:
}do
Sentencias;
}while(condición);
Si se ejecuta la siguiente expresión se consigue un bucle sin fin.
while(1){
23
Autor: Wilmer Planchez Febrero, 2013.
Sentencias;
}
ó
}do
Sentencias;
}while(1);
Ejemplo #16:
while(i<=9){
j=4;
K=0;
}
Ejemplo #17:
}do
j=4;
K=0;
}while(i<=9);
Un bucle WHILE puede comportarse como un bucle FOR, la forma de lograrlo es la
siguiente.
i=0;
while(i<=9){
sentencias;
i++;
}
24
Autor: Wilmer Planchez Febrero, 2013.
Lo anterior es equivalente a escribir:
for(i=0;i<=9;i++){
sentencias;
}
7.3.- OTROS.
7.3.1.- BREAK.
Podemos salir de un bucle antes de tiempo con la orden BREAK.
Ejemplo #18:
For(i=0;i<=10;i++){
If(i == 4){
break; // Sale del bucle
}
}
7.3.1.- CONTINUE.
Podemos saltar alguna repetición de un bucle con la orden CONTINUE.
For(i=0;i<=10;i++){
If(i == 4){
Continue; /* El bucle se salta el numero 4
Y continua la ejecución del bucle*/
}
}
7.3.1.- GOTO: (“Ir a...”)
GOTO permite hacer saltos incondicionales, asignando una etiqueta en algún lugar del
código, y cuando se desee regresar al lugar de la etiqueta se hace uso del GOTO la
siguiente manera:
Inicio: // Etiqueta
Goto inicio;
25
Autor: Wilmer Planchez Febrero, 2013.
Se debe evitar el uso del GOTO en lo posible, ya que genera malos hábitos de
programación, se recomienda su uso, cuando se tengan un anidamiento de estructuras
repetitivas, de donde es difícil salir con una sola instrucción como BREAK. El siguiente
ejemplo muestra un caso en el que es muy útil usar GOTO.
Ejemplo#19:
for(i=1;i<=100;i++){ // Inicio del For1
for(j=0;j<=50;j++){ // Inicio del For2
for(K=0;K<=9;K++){ // Inicio del For3
if(Z==1){ // Inicio del If
goto Seguir;
} // Fin del If
} // Fin del For3
} // Fin del For2
} // Fin del For1
Seguir:
Sentencias;
En las estructuras anidadas, el bucle mas interno es el que primero termina, en este caso
el bucle mas interno es el For3, para poder salir de la estructura se debe salir primero del
bucle For3, luego del For2 y finalmente del For1 que es el principal, obviamente con
escribir la sentencia break en el bucle for3 solo se conseguiría salir de este, y quedar
atrapado en los otros 2 bucles, y es aquí donde la sentencia GOTO se torna realmente
útil ya que nos redirige a la zona deseada de nuestro código de un solo salto.
NOTA: Jamás se debe usar un GOTO dentro de una función hacia un punto fuera de
esta, ya que toda función debe retornar, para continuar su ejecución desde el lugar de
donde se llamó.
26
Autor: Wilmer Planchez Febrero, 2013.
8.- DIRECTIVAS DE MANIPULACION DE PUERTOS.
El compilador CCS posee funciones predefinidas para trabajar con puertos, y pines
específicos del microcontrolador.
Funciones Para el manejo de puertos:
output_X(valor): Saca por el puerto un valor de 8 bits (0 – 255).
input_X( ): Función para la lectura del puerto correspondiente.
set_tris_X(valor): Carga el registro TRISx con un valor de 8 bits, en esta
función se indican las entradas y las salidas del puerto. Indicando las entradas con 1 y
las salidas del puerto con 0.
Donde la X es la inicial del puerto correspondiente (A, B, C , D, E).
Funciones Para el manejo de pines.
output_low(pin*): Coloca el estado lógico del pin a 0.
output_high(pin*): Coloca el estado lógico del pin a 1.
output_bit(pin*,Valor): Pin al valor especifico. (Valor puede ser 0 o 1).
output_toggle(pin*): Complementa el valor del pin.
input(pin*) : Lee el valor del pin.
Las funciones input_x() y output_x() dependen de la directiva #USE *_IO que este
activa. Las directivas mas utilizadas son:
#USE FAST_IO(PUERTO)
Con la función output_x() se saca un valor de 8 bit por el puerto indicado y con la
función input_x() se lee el valor del puerto. La directiva no modifica el registro TRIS
correspondiente.
#USE STANDARD_IO(PUERTO)
Con la función output_x() el compilador se asegura de que el terminal, o terminales
correspondientes, sean de salida mediante la modificación del registro TRIS
27
Autor: Wilmer Planchez Febrero, 2013.
correspondiente. Con la función input_x() ocurre lo mismo pero asegurando el terminal
como entrada.
9.- DISEÑO DE CIRCUITOS CON ISIS DE PROTEUS.
Proteus es un poderoso software de simulación y diseño electrónico, de la compañía
Labcenter Electronics. El ISIS permite la simulación de las familias de
microcontroladores mas conocidas como la: 12F (Gama baja), 16F (Gama media), 18F
(Gama alta). Proteus puede simular una gran cantidad de dispositivos digitales y
analógicos. En la siguiente imagen se puede apreciar la apariencia del entorno de trabajo
de ISIS:
Figura 9-1
28
Autor: Wilmer Planchez Febrero, 2013.
9.1.- CARACTERISTICAS BÁSICAS PARA SIMULAR.
Se debe identificar la paleta de dispositivos, que está a la izquierda de la pantalla, en
esta paleta el diseñador debe identificar el botón P como se muestra en la imagen.
Figura 9-2
Al presionar el botón P, el programa abre una nueva ventana que permite la búsqueda
de dispositivos por medio de la referencia comercial, o bajo la clasificación que el
mismo ISIS tiene.
Figura 9-2
29
Autor: Wilmer Planchez Febrero, 2013.
El programa genera una lista en la parte derecha de la ventana con los dispositivos
relacionados con la solicitud del usuario. Para seleccionar un dispositivo de esta lista se
da doble clic sobre cada uno de los numerales de la lista. Para comenzar busque los
siguientes dispositivos: PIC16F877A, RES(220ohm), CAP(22pf), CRYSTAL, LED-
GREEN. El cristal no es necesario en la simulación, pero es recomendable su uso en el
montaje en físico.
Figura 9-3
El paso siguiente es buscar los terminales de GROUND (tierra) y POWER (Vcc). La
terminal de Vcc tiene una diferencia de potencial por defecto de 5v. Para colocar estas
terminales en le área de trabajo se presionan los ítems en la paleta de terminales y
posteriormente en el área de trabajo, después de esta acción en el área de trabajo se
debe ver lo siguiente:
Figura 9-4
30
Autor: Wilmer Planchez Febrero, 2013.
El siguiente paso es unir los componentes en el área de trabajo, para esto se debe
presionar el botón COMPONENT MODE (El símbolo es un amplificador operacional
amarillo) de la paleta de herramientas a la izquierda. Para unir los dispositivos en el
área de trabajo se sigue el mismo procedimiento de las terminales, al finalizar se debe
tener la siguiente vista:
Figura 9-5. El circuito más simple con un Microcontrolador.
10.- CREACION DE UN PROYECTO CON CCS.
1) Crear una carpeta donde se guardara el programa y el esquema electrónico diseñado en Proteus.
2) Abrir el compilador CCS.
Figura 10-1. Entorno de Trabajo de CCS.
31
Autor: Wilmer Planchez Febrero, 2013.
3) En la barra de herramientas dar clic a la pestaña Proyect.
Figura 10-2
4) Click en New/Source File.
Figura 10-3. Creación de un nuevo proyecto.
32
Autor: Wilmer Planchez Febrero, 2013.
5) En la carpeta creada escribir el nombre del Programa. Se recomienda que el
programa tenga el mismo nombre de la carpeta.
Figura 10-4
6) Finalmente Guardar.
Figura 10-5. Proyecto creado listo para Programar.
Con nuestro proyecto creado procedemos a escribir nuestro primer Programa, el “Hola
Mundo” de los microcontroladores.
33
Autor: Wilmer Planchez Febrero, 2013.
Ejemplo#20: Programa que encienda y apague un led durante un tiempo indefinido. El
Parpadeo debe durar 1 segundo. (500ms encendido y 500ms apagado).
// Program_00_Apagar_Encender_Led
#include <16f877A.h>
#fuses xt,nowdt
#use delay (clock=4000000)
#use fast_io(b)
#define led1 pin_b1 // El pin B1 ahora se llamará led1
void main(){ // Funcion Principal
set_tris_b(0b00000000); // Config. del puerto B como Salida
output_b(0b00000000); // Apaga todos los Pines del puerto B
while(1){ // Bucle infinito
output_bit(led1,1); // Enciende el Led
delay_ms(500); // Espera 500ms
output_bit(led1,0); // Apaga el Led
delay_ms(500); // Espera 500ms
} // Fin del While
} // Fin de la función principal
7) Para compilar el programa en la barra de herramientas seleccione La pestaña
Compile y luego la opción Compile.
Figura 10-6. Compilación.
34
Autor: Wilmer Planchez Febrero, 2013.
Si la compilación fue exitosa deberá aparecer una imagen como la siguiente.
Figura 10-7. Compilación Exitosa.
En la compilación se generan archivos con diferentes extensiones, utilizaremos los
archivos de extensión *.HEX y *.COF, los cuales se pueden utilizar para trabajar con el
entorno PROTEUS.
8) Dar doble clic en el microcontrolador para abrir la ventana de edición.
Figura 10-8
35
Autor: Wilmer Planchez Febrero, 2013.
7) En el item Processor Clock Frequency se debe colocar la frecuencia de reloj
especificada en la programación, para nuestro caso será de 4Mhz.(Figura 10-8).
8) Incluir el archivo de trabajo en el ítem Program File dando clic al símbolo de
la carpeta. (Figura 10-8).
´
Figura 10-9
9) Seleccionar el archivo de extensión *.HEX o *.COF.
10) Ahora se puede proceder a la simulación del circuito empleando la barra de
simulación. Esta opción se compone de la opción MARCHA, PASO A PASO,
PAUSA y PARADA.
Figura 10-10
36
Autor: Wilmer Planchez Febrero, 2013.
11.- PROYECTOS CON LEDS
Ejemplo#21: Se desea programar un semáforo, de 2 intersecciones que cumpla la
siguiente función: La luz roja del semáforo 1 y la luz verde deben activarse por 9
segundos, luego se debe activar la luz amarilla del semáforo 2 por 3 segundos mientras
la luz roja del otro semáforo sigue activa, debe completarse el ciclo para ambos
semáforos.
Componentes ISIS: PIC16F877A, RX8 (Pack de 8 resistencias), LED-GREEN, LED-
RED, LED-YELLOW, CRISTAL, CAP (22pf).
Figura 11-1. Semáforo De 2 Intersecciones con leds.
// Program_01_Semaforo
#include <16f877A.h>
#fuses xt,nowdt
#use delay (clock=4000000)
#use fast_io(b)
void main(){ // Funcion Principal
set_tris_b(0b00000000); // Config. del puerto B como Salida
37
Autor: Wilmer Planchez Febrero, 2013.
output_b(0b00000000); // Apaga todos los Pines del puerto B
while(1){ // Bucle infinito
output_b(0b00100001); // Rojo_1 = ON / Verde_2 = ON
delay_ms(9000);
output_b(0b00010001); // Rojo_1 = ON / Amarillo_2 = ON
delay_ms(3000);
output_b(0b00001100); // Verde_1 = ON / Rojo_2 = ON
delay_ms(9000);
output_b(0b00001010); // Amarillo_1 = ON / Rojo_2 = ON
delay_ms(3000);
} // Fin del While
} // Fin de la funcion Principal
Ejemplo#22: Diseñar un contador binario de 8 bits que cuente de 0 a 255, al llegar a 255 la cuenta debe reiniciarse. Entre un cambio y otro debe haber un retarde de 300 milisegundos.
Componentes ISIS: PIC16F877A, RX8 (Pack de 8 resistencias), LED-BARGRAPH-
GREEN (Barra de 10 Leds verdes), CRISTAL, CAP (22pf).
Figura 11-2
38
Autor: Wilmer Planchez Febrero, 2013.
// Program_02_Contador_8_Bits
#include <16f877A.h>
#fuses xt,nowdt
#use delay (clock=4000000)
#use fast_io(b)
void main(){ // Funcion Principal
set_tris_b(0b00000000); // Config. del puerto B como Salida
output_b(0b00000000); // Apaga todos los Pines del puerto B
while(1){ // Bucle infinito
for(i=0;i<=255;i++){ // Bucle for de 0 a 255
output_b(i); // saca Por el Pto.B el valor de i
delay_ms(300); // Retardo de 300milisegundos
} // Fin del Bucle For
} // Fin del While
} // Fin de la funcion Principal
39
Autor: Wilmer Planchez Febrero, 2013.
Ejemplo#23: Diseñar un programa que sea capaz de desplazar un bit desde el LSB de un puerto al MSB (de derecha a izquierda) al llegar al MSB este debe realizar un desplazamiento en sentido contrario (De izquierda a derecha), el proceso debe repetirse infinitamente. Mostrar las salidas con leds. Se utilizará el esquema electrónico del Ejercicio #22 (Ver Figura 11-2).
// Program_03_Desplazamiento
#include <16f877A.h>
#fuses xt,nowdt
#use delay (clock=4000000)
#use fast_io(b)
int i,j=1;
void main(){ // Funcion Principal
set_tris_b(0b00000000);
output_b(0b00000000);
delay_ms(500);
while(1){
for(i=1;i<=7;i++){ // Desplazamiento a la Izquierda
output_b(j); // Saca por el pto B el valor de j
j <<= 1; // <<= indica desplazamiento a la izq.
delay_ms(500);
} // Fin del For de despl. A la izquierda
for(i=1;i<=7;i++){ //Desplazamiento a la Derecha
output_b(j);
j >>= 1; // >>= indica desplazamiento a la Derecha
delay_ms(500);
} // Fin del For de despl. A la derecha
} // Fin del While
} // Fin del main
Al ejecutarse el programa es necesario que el bit menos significativo del puerto este activado. Se han declarado 2 variables:
40
Autor: Wilmer Planchez Febrero, 2013.
int i,j=1;
i: se utiliza para indicar la cantidad de veces que se va a desplazar el valor de j (j=1) desde el LSB hasta el MSB, en este caso se desplazara 7 veces (como se indica en el bucle For) hasta llegar a su objetivo, para luego regresar a su punto de origen.
j: es la variable que ira tomando los valores que vamos a sacar por el puerto B.
for(i=1;i<=7;i++){ // Desplazamiento a la Izquierda
output_b(j); // Saca por el pto B el valor de j
j <<= 1; // <<= indica desplazamiento a la izq.
delay_ms(500);
}
En el bucle For indicamos la cantidad de veces que se desplazará el valor de j, que por defecto es 1 (00000001 binario) es decir tendremos 7 posibles valores de j al comenzar el desplazamiento.
00000010 (binario) = 2 (decimal)
00000100 (binario) = 4 (decimal)
00001000 (binario) = 8 (decimal)
00010000 (binario) = 16(decimal)
00100000 (binario) = 32 (decimal)
01000000 (binario) = 64(decimal)
10000000 (binario) = 128 (decimal)
Podemos darnos cuenta que el desplazamiento a la izquierda no es más que una multiplicación por 2, es decir en realidad lo que se ejecuta es lo siguiente:
j = j*2;
Quiere decir que el valor que se tenga en j justo en ese instante, se va a multiplicar por 2, esto se traduce en el desplazamiento de un bit a la izquierda (cuando se saca el valor por el puerto), y se asigna ese nuevo valor a la variable.
El desplazamiento a la derecha es una división entre 2.
j = j/2;
Como ejercicio reemplace j <<= 1 por j = j*2 y j >>= 1 por j = j/2, y observe lo que sucede.
41
Autor: Wilmer Planchez Febrero, 2013.
Ejemplo#24: usando las 8 salidas de un puerto generar una secuencia, similar a las luces de una discoteca, al inicio deben estar en estado alto el bit 0 y el bit 7 del puerto, se desea que estos bits se desplacen hacia su extremo opuesto correspondiente, generando un efecto de cruce cuando pasan por el centro, el proceso debe repetirse indefinidamente. Mostrar las salidas con leds. Se utilizará el esquema electrónico del Ejercicio #22 (Ver Figura 11-2).
// Program_04_Luces_Para_Discoteca
#include <16f877A.h>
#fuses xt,nowdt
#use delay (clock=4000000)
#use fast_io(b)
Int Tiempo = 100; // Argumento de la función delay_ms(Valor)
void main(){ // Inicio de la funcion principal
set_tris_b(0b00000000); // Config. Del pto.B como salida
output_b(0b00000000); // Saca un cero por los pines del pto.B
while(1){ // Bucle infinito
output_b(0b10000001);
delay_ms(Tiempo);
output_b(0b01000010);
delay_ms(Tiempo);
output_b(0b00100100);
delay_ms(Tiempo);
output_b(0b00011000);
delay_ms(Tiempo);
output_b(0b00100100);
delay_ms(Tiempo);
output_b(0b01000010);
delay_ms(Tiempo);
} // Fin del bucle infinito
} // Fin de la función principal
42
Autor: Wilmer Planchez Febrero, 2013.
Este programa muestra otra de las posibilidades que nos ofrece la función delay_ms(valor), donde valor podría ser una constante(como se había trabajado en los programas anteriores), o puede ser una variable, la cual podría cambiar su valor en cualquier momento, permitiendo generar temporizaciones de diferente duración.
La razón por la cual se usa como argumento una variable es sencilla, simplemente para poder variar la temporización de la secuencia, sin modificar muchas líneas de código. Para este ejemplo el cambio entre una secuencia y otra es de 100ms, pero supongamos que deseamos una temporización de 50ms, en lugar de escribir delay_ms(50); 6 veces basta con modificar el valor de int Tiempo = 50; que es la variable para controlar la temporización, permitiéndonos ganar tiempo valioso, sin hacer que programar secuencias con la misma duración sea tedioso.
12.- PROYECTOS CON PULSADORES
Los pulsadores permiten al microcontrolador comunicarse con el mundo exterior, estos mandan valores digitales al PIC permitiendo tomar decisiones en base a ellos. Existen 2 tipos de conexiones para los pulsadores Pull-Up y Pull- Down.
Pull-Up: Siempre está en 1 lógico (5V), y cuando se presiona el pulsador este cambia su estado mandando un cero lógico (0V).
Pull-Down: Siempre está en 0 lógico (0V), y cuando se presiona el pulsador este cambia su estado mandando un 1 lógico (V).
Figura 12-1
43
Autor: Wilmer Planchez Febrero, 2013.
Ejemplo#25: Se desea encender un led durante 1 segundo al presionar un pulsador, al pasar este tiempo el led debe apagarse, hasta que se vuelva a presionar el pulsador.
Componentes ISIS: PIC16F877A, BUTTON (Pulsador), RES(220ohm), LED-
GREEN , CRISTAL, CAP (22pf).
Figura 12-2
// Program_05_Pulsador_Led
#include <16f877A.h>
#fuses xt,nowdt
#use delay (clock=4000000)
#use fast_io(b)
#define Led pin_b1 // El Pin B1 se llamara Led
#define Pulsador pin_b0 // El Pin B0 se llamara Pulsador
void main(){ // Funcion principal
set_tris_b(0b00000001); // Config del pin B0 como entrada
// y el resto de lo pines como salida
output_b(0b00000000);
while(1){ // Bucle infinito
if (input(Pulsador)==0){ // Si se presiona el pulsador
output_bit(Led,1); // Ecender Led
44
Autor: Wilmer Planchez Febrero, 2013.
delay_ms(1000); // retardo de un segundo
output_bit(Led,0); // Apagar Led
} // Fin del If
} // Fin del bucle infinito
} // Fin de la funcion principal
En el esquema electrónico se hace uso de un pulsador del tipo Pull - up por lo tanto al ser presionado su estado lógico cambia de uno a cero, razón por la cual se pregunta por cero en el if y no por uno.
if (input(Pulsador)==0){ // Si el pulsador es Pull-up
if (input(Pulsador)==1){ // Si el pulsador es Pull-Down
Ejemplo#26: Diseñar un programa que permita controlar 3 salidas con un pulsador se debe alternar el funcionamiento de las 3 salidas activando 1 a la vez de forma secuencial es decir, activar la salida 1 luego la 2 y finalmente la 3, el ciclo debe repetirse.
Componentes ISIS: PIC16F877A, BUTTON (Pulsador), RES(220ohm), LED--GREEN , CRISTAL, CAP (22pf).
Figura 12-3
45
Autor: Wilmer Planchez Febrero, 2013.
// Program_06_1Pulsador_3Salidas
#include <16f877a.h>
#fuses xt,nowdt
#use delay (clock=4000000)
#use fast_io(b)
#define Pulsador pin_b0
int Flag=1;
void main(){
set_tris_b(0b00000001); output_b(0b00000000);
while(1){
if (input(Pulsador)==0){
delay_ms(250); // Retardo anti-rebote
switch(Flag){
case 1:
output_b(0b00000010); // Activo el pin B1
Flag++; // Incremento la badera
break;
case 2:
output_b(0b00000100); // Activo el pin B2
Flag++; // Incremento la badera
break;
case 3:
output_b(0b00001000); // Activo el pin B3
Flag = 1 ;
break;
} // Fin del Switch
} //Fin del If
} // Fin del While
} // Fin de la funcion Principal
46
Autor: Wilmer Planchez Febrero, 2013.
En este programa se hace uso de la estructura Switch la cual nos permite preguntar por los posibles valores que podría tener una variable, y en función de estos, generar acciones, en este caso hemos asociado al pulsador una variable de nombre Flag (Bandera), que será la variable por la cual vamos a preguntar cada vez que se pulse el botón.
Para las siguientes sentencias:
case 1:
output_b(0b00000010); // Activo el pin B1
Flag++; // Incremento la badera
break;
En este caso estamos preguntando si la variable es igual a uno (Flag = 1, notese que inicialmente cuando se declaro la variable Flag, se le asigno el valor de 1), de cumplirse esta condición entonces se activa la primera salida ubicada en el pin B1, luego se incrementa la variable en uno (Flag = 2), de forma tal, que cuando se presione el pulsador nuevamente, el programa sepa cuál es el siguiente caso , y que salida debe activar. Con la sentencia break salimos inmediatamente de la estructura switch, de no colocarse, el programa seguiría preguntando por cada una de las condiciones hasta llegar al final de la estructura, haciendo más lenta la ejecución del programa.
case 3:
output_b(0b00001000); // Activo el pin B3
Flag = 1;
break;
Cuando se ha activado la salida 3 en el pin B3 se necesita que cuando se presione el pulsador se active la salida 1, para lograr esto colocamos nuevamente la variable a su valor inicial (Flag = 1).
Ejemplo#27: Diseñar un Programa que permita controlar 8 salidas con 3 pines del microcontrolador, utilice un decodificador 74LS138, las salidas deben activarse una a una cada vez que se pulse un botón.
Componentes ISIS: PIC16F877A, RX8 (Pack de 8 resistencias), LED-BARGRAPH-
GREEN (Barra de 10 Leds verdes), 74LS138, CRISTAL, CAP (22pf).
47
Autor: Wilmer Planchez Febrero, 2013.
Figura 12-4
// Program_07_PIC_y_Decodificador
#include <16f877a.h>
#fuses xt,nowdt
#use delay (clock=4000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
//Redefinicion de Puertos
#define Pulsador pin_a0
//Definicion de variables
int valor;
void main(){
set_tris_b(0b00000000); // Conf. Del puerto B como salida
set_tris_a(0b00000001); // Conf Del pin A0 como entrada
set_tris_c(0b00000000); // Conf. Del puerto C como salida
output_b(0b00000000);
output_c(0b00000000);
48
Autor: Wilmer Planchez Febrero, 2013.
while(1){
if (input(Pulsador)== 0){ // Si se presiono el pulsador
output_c(0b00000001) // Actica el enable del 74LS138
delay_ms(250); // retarde de 250ms
if(valor>7){ // si valor es mayor que 7
valor=0; //Coloca a cero la variable
}
output_b(valor); // saca por el puerto B el contenido Valor
valor++; // Incrementa la variable
} // Fin del If
} // Fin del bucle infinito
} // Fin de la funcion principal
El decodificador 74LS138 es un demultiplexor que con 3 pines nos permite controlar 8 salidas, este es capaz de activar una de las 8 salidas dependiendo de la combinación binaria en sus entradas, si desea conocer mejor el funcionamiento de este circuito integrado consulte su hoja de datos (Datasheet).
Inicialmente el decodificador esta desactivado, el Enable en el pin c0 está en estado bajo, cuando se presiona el pulsador este es habilitado y se activa la salida correspondiente.
La condición:
if(valor>7){
valor=0;
}
Indica que si la variable es mayor que 7 entonces, esta volverá a su valor inicial. De 0 a 7 se tendrán 8 posibles valores (Ya que controlaremos 8 salidas), esa es la razón por la cual se pregunta por 7 y no por otro número.
output_b(valor);
valor++;
Se ejecuta siempre y cuando se presione el pulsador, en este caso saca el valor de la variable por el puerto y luego incrementa su valor.
49
Autor: Wilmer Planchez Febrero, 2013.
PROYECTOS PROPUESTOS CON LEDS.
1. Encienda un led conectado en el pin RB0 durante 1 segundo, luego apáguelo por 500ms. El proceso debe repetirse 4 veces, luego el led debe permanecer apagado.
2. Encienda 2 leds conectados en RB0 y RB1 alternamente, es decir mientras un led esta encendido el otro permanece apagado. Los tiempos de transición son de 500ms, entre encendido y apagado. El proceso debe continuar indefinidamente.
3. Genere 5 parpadeos de un led con intervalos de 400ms, luego haga 2 parpadeos de 1 segundo con un segundo led, luego haga que los 2 leds parpadeen 3 veces, repita el proceso indefinidamente.
PROYECTOS PROPUESTOS CON PULSADORES.
4. Haga un proyecto en el que al presionar un botón este encienda un led intermitente de 8 repeticiones de 100ms.Luego el led permanezca apagado, y el programa vuelve a sensar el pulsador.
5. Con un pulsador haga que 8 leds conectados en el puerto B, se enciendan, de derecha a izquierda uno a la vez, empezando de RB0 a RB7, al final este ultimo permanece encendido, con otro pulsador haga que los leds se desplacen uno a uno hacia la derecha, es decir, de RB7 que fue el ultimo y que está actualmente encendido se desplace hasta RB0 las pausas son de 200ms.