1
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.
Autor: Wilmer Planchez Febrero, 2013.
2
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.
Autor: Wilmer Planchez Febrero, 2013.
3
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.
Autor: Wilmer Planchez Febrero, 2013.
4
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
Autor: Wilmer Planchez Febrero, 2013.
5
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. Autor: Wilmer Planchez Febrero, 2013.
6
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
Autor: Wilmer Planchez Febrero, 2013.
7
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(){ Sentencias;
// Inicio Función Principal // 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 Autor: Wilmer Planchez Febrero, 2013.
8
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.
Autor: Wilmer Planchez Febrero, 2013.
9
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;
Autor: Wilmer Planchez Febrero, 2013.
10
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)
Autor: Wilmer Planchez Febrero, 2013.
11
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;
Autor: Wilmer Planchez Febrero, 2013.
12
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.
Autor: Wilmer Planchez Febrero, 2013.
13
5.2 RELACIONALES.
5.3 LÓGICOS.
5.4 DE BITS.
Autor: Wilmer Planchez Febrero, 2013.
14
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();
Autor: Wilmer Planchez Febrero, 2013.
15
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();
Autor: Wilmer Planchez Febrero, 2013.
16
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*/
Autor: Wilmer Planchez Febrero, 2013.
17
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)){ Sentencias;
//Operación AND: Se deben cumplir //Las 2 condiciones*/
} Autor: Wilmer Planchez Febrero, 2013.
18
O también: If((B1 == 0)||(C==1)){ Sentencias;
// Operación Or: Se debe cumplir // 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; }
Autor: Wilmer Planchez Febrero, 2013.
19
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
Autor: Wilmer Planchez Febrero, 2013.
20
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.
Autor: Wilmer Planchez Febrero, 2013.
21
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. Autor: Wilmer Planchez Febrero, 2013.
22
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){
Autor: Wilmer Planchez Febrero, 2013.
23
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++; }
Autor: Wilmer Planchez Febrero, 2013.
24
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; Autor: Wilmer Planchez Febrero, 2013.
25
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ó.
Autor: Wilmer Planchez Febrero, 2013.
26
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
Autor: Wilmer Planchez Febrero, 2013.
27
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
Autor: Wilmer Planchez Febrero, 2013.
28
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
Autor: Wilmer Planchez Febrero, 2013.
29
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, LEDGREEN. 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
Autor: Wilmer Planchez Febrero, 2013.
30
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.
Autor: Wilmer Planchez Febrero, 2013.
31
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.
Autor: Wilmer Planchez Febrero, 2013.
32
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 â&#x20AC;&#x153;Hola Mundoâ&#x20AC;? de los microcontroladores. Autor: Wilmer Planchez Febrero, 2013.
33
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.
Autor: Wilmer Planchez Febrero, 2013.
34
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
Autor: Wilmer Planchez Febrero, 2013.
35
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
Autor: Wilmer Planchez Febrero, 2013.
36
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, LEDRED, 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 Autor: Wilmer Planchez Febrero, 2013.
37
output_b(0b00000000); while(1){ output_b(0b00100001);
// Apaga todos los Pines del puerto B // Bucle infinito // 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-BARGRAPHGREEN (Barra de 10 Leds verdes), CRISTAL, CAP (22pf).
Figura 11-2
Autor: Wilmer Planchez Febrero, 2013.
38
// 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); while(1){ for(i=0;i<=255;i++){
} }
// Apaga todos los Pines del puerto B // Bucle infinito // 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
Autor: Wilmer Planchez Febrero, 2013.
39
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:
Autor: Wilmer Planchez Febrero, 2013.
40
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.
Autor: Wilmer Planchez Febrero, 2013.
41
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
Autor: Wilmer Planchez Febrero, 2013.
42
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
Autor: Wilmer Planchez Febrero, 2013.
43
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), LEDGREEN , 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 Autor: Wilmer Planchez Febrero, 2013.
44
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
Autor: Wilmer Planchez Febrero, 2013.
45
// 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 Autor: Wilmer Planchez Febrero, 2013.
46
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-BARGRAPHGREEN (Barra de 10 Leds verdes), 74LS138, CRISTAL, CAP (22pf).
Autor: Wilmer Planchez Febrero, 2013.
47
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); Autor: Wilmer Planchez Febrero, 2013.
48
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. Autor: Wilmer Planchez Febrero, 2013.
49
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.
Autor: Wilmer Planchez Febrero, 2013.