Aprendiendo a programar Microcontroladores PIC en Lenguaje C con CCS

Los compiladores de lenguaje C hoy son ampliamente utilizados para la creación de programas con microcontroladores PIC. El compilador que mejor soluciona las necesidades del programador enmascarando el hardware y simplificando la implementación de una aplicación es el fabricado por la compañía CCS. Por Andrés Raúl Bruno Saravia

Entrega Nº 2.
En nuestra entrega anterior aprendimos a crear un proyecto dentro del MPLAB para escribir nuestro primer código en lenguaje C, hoy crearemos nuestro primer código y aprenderemos la función que cumplen sus elementos principales .

Creando Nuestro Primer Código
Ya que hemos aprendido a crear nuestro primer proyecto, escribiremos nuestro primer código, el cual adicionaremos a nuestro proyecto. Para ello nos moveremos con el Mouse hasta el ícono de New File y haremos clic sobre el mismo:

//esperamos 500 ms output_low(PIN_B0). y muchas veces querer comenzar con un código demasiado elaborado es complejo. En esta cabecera encontraremos instrucciones dirigidas al compilador y no al microcontrolador.h> #use delay(osc=4000000) //configura fusibles de configuración #fuses XT //Oscilador a cristal standar #fuses NOWDT //sin WatchDog Timer #fuses NOPROTECT //sin proteccion de memoria de programa #fuses NOPUT //sin PowerUp Timer #fuses NOBROWNOUT //sin brownout #fuses NOLVP //sin programación en baja tensión //rutina principal void main(void) { //abrimos la función principal Setup_adc_ports(NO_ANALOGS).h> nos permite decirle al compilador para que microcontrolador hemos escrito el código. //prendemos RB0 delay_ms(500).Y se desplegará una nueva ventana en la cual escribiremos el código de nuestro programa. Las directivas se diferencian de las instrucciones en que: • • Siempre se encuentran en la cabecera del programa Todas comienzan con el símbolo del numeral # En nuestro caso estas son las directivas: #include<16f887. //esperamos 500 ms } //cerramos el bucle //cerramos la función principal } Este código lo hemos escrito en lo que se conoce en la jerga técnica como “codigo en C nativo” ya que usamos las funciones de control de entrada / salida de CCS El código inicia siempre en lo que se conoce como “cabecera”. simplemente haremos titilar un LED con un tiempo de flashing de 500ms. Por ser este nuestro primer programa. . dichas instrucciones se denominan “directivas”. //borramos RB0 delay_ms(500).//configuramos los puertos digitales while(1) //creamos un bucle infinito { //abrimos el bucle output_high(PIN_B0).h> #use delay(crystal=4000000) //configura fusibles de configuración #fuses XT //Oscilador a cristal standar #fuses NOWDT //sin WatchDog Timer #fuses NOPROTECT //sin proteccion de memoria de programa #fuses NOPUT //sin PowerUp Timer #fuses NOBROWNOUT //sin brownout #fuses NOLVP //sin programación en baja tensión La directiva : #include<16f887. es decir el principio. #include<16f887. La idea es introducirnos de a poco.

o accionar los osciladores internos cuando el microcontrolador los trae. etc. El orden de las directivas es crucial ya que siempre primero debemos indicarle al compilador cual es el PIC que estamos usando y luego cual es la frecuencia del oscilador. Posteriormente podemos agregar el resto de directivas. Este parámetro se denomina MIPS (Millones de Instrucciones por Segundo) y se obtiene dividiendo la frecuencia de entrada por cuatro. La directiva puede tener distintas formas ya que amolda la configuración interna a la frecuencia que le indicamos. definición de variables y constantes.HS. se le informa al compilador que el fusible en cuestión está desactivado. En líneas generales podemos decir que anteponiendo la palabra NO al fusible de configuración (así se llama al seteo de las propiedades). clock=16000000) Le indica al compilador que tenemos un cristal externo de 4Mhz. MIPS = fosc/4 La directiva #fuse xx nos permite activar o desactivar las características del nucleo. Por otra parte para activar o desactivar los distintos fusibles se puede realizar en varias líneas (como en el ejemplo) o se pueden activar y desactivar en una sola línea separando cada fusible con comas: #fuse NOWDT.NOLVP.NOPUT. ya que las mismas suelen cambiar entre versiones del compilador o tipos de microcontroladores. que resetea el microcontrolador ante un fallo de la alimentación. que reseta al microcontrolador ante un cuelgue del mismo. y que la misma necesita saber la frecuencia del oscilador.Seguidamente con la directiva #use delay(crystal=4000000) le indicamos a que frecuencia esta funcionando nuestro oscilador. clock=16000000) Sin embargo esta directiva debe usarse con precaución ya que el clock que definimos nunca debe sobrepasar la máxima velocidad de procesamiento del PIC que se esté usando. Así esta directiva nos permite activar multiplicadores y divisores internos. y que la frecuencia que llega a la CPU es de 16Mhz.NOMCLR. Si esto no se respeta podemos tener errores en el proceso de compilación sobre todo cuando usamos alguna función propia del compilador (llamadas funciones embebidas) para manejar algún periférico.NOPROTECT. por ejemplo: #use delay(crystal=4000000. Esto será visto en nuestras próximas lecciones. Otro ejemplo pero usando el reloj interno es el siguiente: #use delay(internal=8000000. mientras que colocando solo el nombre activamos la propiedad. Y prototipo de funciones. Las etiquetas usadas para activar o desactivar la propiedad. están incluidas en el archivo de cabecera y deben ser consultadas siempre. por lo tanto el compilador configurará correctamente el PLL de la CPU para alcanzar los 32Mhz.NOBROWNOUT La cabecera además puede incorporar redefinición de nombres de pines. el Brown Out Detect. . el tipo de oscilador. como ser el circuito de Watch Dog Timer.

Dicho nombre no puede ser distinto.Finalizada la cabecera. a ellas se les puede pasar valores de variables para que las procesen. de lo contrario el compilador nos indicará un error.//configuramos los puertos digitales while(1) //creamos un bucle infinito { //abrimos el bucle output_high(PIN_B0). La función main es una función especial ya que no puede recibir ningún valor. En nuestro caso nuestro código es bastante sencillo: void main(void) { //abrimos la función principal setup_adc_ports(NO_ANALOGS). continúa el código. Entre estas dos llaves se encuentran las sentencias y las estructuras lógicas. //borramos RB0 delay_ms(500). En el lenguaje C las rutinas se denominan funciones. Debe observarse que cada línea la hemos decalado (separado del origen) por medio del TABULADOR. sin embargo las funciones tiene una característica extra. //prendemos RB0 delay_ms(500). Básicamente actúan como las funciones matemáticas. las cuales forman el bloque de dicha función. todo programa debe tener una función main. Esto significa que hemos usado todas las funciones embebidas (incluidas dentro) del compilador para simplificar la escritura del código y que nos ahorran mucho tiempo. Dicho bloque inicia con una llave { y finaliza con otra llave } . es decir que no devuelve ningún valor (primer void) ni puede recibir ningún valor. el cual esta encerrado entre paréntesis). Por lo tanto observe que va acompañada por dos palabras void lo cual en el lenguaje C significa vacío. ni tampoco puede devolver uno. La función encierra una serie de sentencias. esto es una buena práctica para poder advertir a simple vista cuales sentencias son las que estas anidadas dentro de cada bloque del programa principal. La primera línea o sentencia le indica al compilador que debe desactivar todos los puertos analógicos del PIC y que debe configurarlos como puertos digitales: setup_adc_ports(NO_ANALOGS). y son capaces de devolvernos los resultados de dichos procesos. Todo programa C siempre inicia en la función principal. la cual se denomina main. que es el que se traducirá en instrucciones al microcontrolador luego del proceso de compilación. . //esperamos 500 ms } //cerramos el bucle //cerramos la función principal } Todo programa siempre inicia en una rutina principal. //esperamos 500 ms output_low(PIN_B0). (segundo void. como lo hacen las rutinas. Las funciones son un conjunto de sentencias u ordenes que realizan una operación determinada. void main(void) { Nuestro código } Nuestro código lo hemos escrito en formato “CCS nativo”.

si la condición no se cumple. Es decir que las sentencias encerradas dentro del bloque while (limitado por las llaves{}). se encargan de poner en uno o en cero un puerto. En nuestro caso hemos forzado la condición 1. se ejecutará. y esto se simboliza con el número 1. En nuestro caso es el RB0.h). NO LA IDENTIFICARÁ. Observe que hemos escrito entre paréntesis NO_ANALOGS lo cual le dice al compilador que no hay puertos analógicos. y que se encarga básicamente de setear que puertos van a trabajar como analógicos y que puertos van a trabajar como digitales. al cual CCS lo denomina dentro del archivo de cabecera del microcontrolador como PIN_B0. se ejecutaran por siempre. Debe observarse también que las sentencias siempre terminan con un punto y coma. Estas son funciones de salida de datos. caso contrario no se ejecutará ninguna sentencia que se encuentre dentro del while. . Es importante resaltar que las etiquetas siempre van en mayusculas. PIN_C6. si una condición se cumple.Usamos la función embebida setup_adc_ports. y así sucesivamente. La siguiente sentencia de nuestro código es una instrucción estructural: while El while es una instrucción condicional la cual determina la ejecución de una o mas instrucciones en tanto y en cuanto se cumpla una condición. Entre paréntesis le indicamos el PIN a encender o apagar. es falsa y se simboliza con el número 0. con lo cual el while se ejecutará eternamente. mientras que las instrucciones se escriben en minúscula. lo que este dentro del bloque del mismo. la cual se encierra entre paréntesis. y al RC6. Es muy importante que se respete el orden mayúscula-minúscula pues el compilador es sensible a ello. por el contrario. la cual esta embebida en el compilador. Observe que dentro del while usamos también funciones embebidas: output_high(PIN_B0). siempre que la condición de verdadera. En un while. se dice que es verdadera. el cual la misma función se encarga de configurar como salida. no debe hacerlo el programador. Si escribimos una instrucción con mayúscula. Por ejemplo el RA0 CCS lo llama PIN_A0. y es el que ha adoptado CCS. es práctico para los programadores NO ELECTRÓNICOS. output_low(PIN_B0). Este formato si bien parece en principio raro porque no se adapta al usado en el data sheet. La función configura los bits PCFG o ANSEL dependiendo con que PIC estemos trabajando y lo realiza de forma automática. En programación. Esta etiqueta la obtenemos del archivo de cabecera del procesador (16f887. Otra de las sentencias usadas es delay_ms(500).

. La exactitud de la función delay depende de que hayamos definido correctamente la frecuencia de clock..La cual es una función de tiempo que nos permite crear un tiempo de espera en milisegundos.. . en las próximas entregas iremos descubriendo paso a paso las utilidades de la programación en lenguaje C y del entorno CCS. esto es todo por ahora . De esta forma hemos hecho falshear un LED en nuestro primer código.. Continuará . Bueno. También existe el delay_us que nos permite crear un delay de microsegundos..