Está en la página 1de 16

INCOELECTRONICA S.A.S.

¿CÓMO PROGRAMAR UN MICROCONTROLADOR CON PIC C?

ESCRITO POR

CAMILO ANDRÉS FELIPE CASTRO VARÓN

INGENIERO ELECTRÓNICO

Correo electrónico: incoelectronica@gmail.com

Twitter: @incoelectronica

Página en Facebook: http://www.facebook.com/INCOELECTRONICA

Página oficial: https://sites.google.com/site/incoelectronicasas/

Página en Youtube: http://www.youtube.com/user/INCOELECTRONICA

Este artículo se basa en distintas fuentes de información, las cuales fueron citadas
correspondientemente, la redacción y edición es total responsabilidad del autor. El objetivo de
este documento es únicamente académico, si se desea ampliar información no dude en
escribirnos en nuestra página oficial, correo o alguna de las redes sociales en las que nos
encontramos adscritos. De antemano gracias por preferirnos.
¿CÓMO PROGRAMAR UN MICROCONTROLADOR CON PIC C?

PIC C es una herramienta que permite programar un microcontrolador por medio de lenguaje C, a
diferencia del lenguaje máquina o ensamblador (ASM) que se maneja por defecto, este hace los
programas más fáciles de escribir, analizar y comprender. PIC C ha sido desarrollado por PIC CMU,
y cuenta con una gran cantidad de librerías o drivers que permiten optimizar los programas en el
momento de manejar dispositivos externos, tales como pantallas LCD, memorias, conversores, etc.
Queremos destacar que el orden de este mini-tuto se basó principalmente en el libro Compilador
C CCS y simulador Proteus para Microcontroladores PIC, de Eduardo García.

Tal como se puede observar en la figura 1, el espacio de trabajo del programa consta de las
siguientes partes:

Figura 1. Espacio de trabajo de PIC C.

Fuente. Autor.

El lenguaje C es un tipo de programación que pese a ser uno de los más básicos en esta área, sigue
siendo una gran herramienta en el momento de crear diferentes rutinas para un
microcontrolador. Este lenguaje básicamente es un sistema de decisiones, por ello realizar un
diagrama de flujo antes de escribirlo es de gran ayuda (para más información visitar el enlace que
acompaña la figura 2).
Figura 2. Ejemplo de un diagrama de flujo.

Fuente. http://www.comolohago.cl/2009/06/16/como-hacer-un-diagrama-de-flujo/.

ESTRUCTURA DE UN PROGRAMA EN C

Un programa en PIC C se puede hacer de dos formas distintas, ya sea creando un proyecto o
simplemente escribiendo el código completo directamente en un archivo con extensión ".C" (más
adelante se tratará este tema), cualquiera que sea el caso que se vaya a usar, la estructura es
prácticamente la misma:

#include <16f876.h> --
#fuses XT,NOWDT,PUT,NOWRT |
#use delay(clock=4000000) |-------Directivas
#use fast_io(B) |
int1 cambio=0; |
#INT_EXT --

ext_isr() --
{ |
output_toggle(PIN_B7); |-------Función o funciones secundarias
} --

void main() --
{ |
set_tris_b(0x01); //Configura el Port B |
|______________| |_______________| |
| | |
Instrucciones Comentarios |
|
output_low(PIN_B7); |
port_b_pullups(TRUE); |-------Función principal
enable_interrupts(int_ext); |
ext_int_edge(L_TO_H); |
enable_interrupts(GLOBAL); |
while(1) |
{ |
} |
} --
 Las directivas dan los parámetros de control que le indican al compilador las herramientas
que el programa va a necesitar para ejecutarse adecuadamente.
 Las funciones son las rutinas que el microcontrolador ejecutará según se programe. La
función principal es la columna vertebral del programa y es la primera en ejecutarse según
su diseño, hará las llamadas correspondientes tanto a las librerías como a las funciones
secundarias. Las funciones secundarias, son aquellas subrutinas en las que se apoya la
función principal para su correcto funcionamiento, principalmente se usa para no repetir
la escritura de un código una y otra vez o por simple orden.
 Las instrucciones son el código a escribir y a compilar.
 Los comentarios se usan para aclarar ciertos aspectos de las instrucciones, es bastante útil
para recordar la estructurar y el funcionamiento de un programa hecho anteriormente o
por un tercero.

OPERADORES Y EXPRESIONES COMPATIBLES CON PIC C

No todas las funciones de lenguaje C están disponibles para la programación de


microcontroladores, por esta razón se darán a conocer los comandos disponibles y los exclusivos
para PIC C.

 Constantes: Estos son las constantes que acepta PIC C.

Tipos de datos
Definición Tipo de dato al que corresponde
123 Decimal
0123 Octal
0x123 Hexadecimal
0b011011 Binario
‘x’ Carácter
‘\010’ Carácter Octal
‘\xA5’ Carácter hexadecimal
Constantes definidas por sufijo
Definición Sufijo Tipo de dato al que corresponde
Int8 127U Entero de 8 bit
Long 80UL Variable de 8 bytes
Signed INT16 80L Entero de 16 bits con signo
Float 80F Valor de ponto flotante de 32 bits
Char Con comillas simples ‘C’ Carácter
Caracteres especiales
Definición Efecto
\n Retorno de línea
\r Retorno de carro
\t Tabulación
\b Backspace
 Tipos de datos: PIC C acepta los siguientes los siguientes tipos de datos.

Tipo Tamaño Rango Descripción


Int1
1 bit 0a1 Entero 1 bit
Short
Int
8 bit 0 a 255 Entero de 8 bit
Int8
Int16
16 bit 0 a 65535 Entero de 16 bit
Long
Int32 32 bit 0 a 4294967295 Entero de 32 bit
Float 32 bit ±1.175x10-38 a ±3.402x1038 Coma flotante
Char 8 bit 0 a 255 Carácter
Void - - Sin valor
Signed Int8 8 bit -128 a 127 Entero con signo
Signed Int16 16 bit -32768 a 32767 Entero largo con signo
Signed Int32 32 bit -231 a +(231-1) Entero 32 bit con signo

 Variables: La definición de las variables dentro del programa es la misma para todas:

[Tipo de variable] [Nombre de la variable]= [Valor inicial de la variable]

o El tipo de variable se refiere a las definiciones descritas en el punto anterior.


o El nombre de la variable es aquella con que el programador la identificará, esta
puede tomar cualquier valor con la condición de que no se usen espacios ni
tampoco las letras se salgan del teclado americano o los caracteres especiales, por
ejemplo, no se permite el uso de “ñ”, y si se desea definir una variable con más de
una palabra se puede escribir usando la raya al piso “nombre_de_la_variable”.
o El valor inicial de la variable puede ser cualquiera que esté dentro de los límites
del tipo de variable a usar, por ejemplo no se puede dar un valor de 260 a una
variable tipo byte. Aunque no es obligatorio darle valor a las variables, es
preferible dárselos para asegurar que el programa inicie con los valores que
queremos, existe un pequeño problema que al programar un microcontrolador sin
borrarlo primero, el número de registro que se le asigne a la variable que
acabamos de definir tenga un valor aún, esto puede provocar malestares que en el
momento de hacer las pruebas en físico, no se encuentre el error, tenga esto en
cuenta.

La única diferencia de las variables está en la posición dentro del programa en la que se
escriban, según sea esta, son de tipo global o local:

o Variables de tipo local: Aplican dentro de la función en las que sean definidas.
void main()
{
byte variable_local
}

o Variables de tipo global: Aplican para todo el programa, se pueden citar dentro de
la función principal como también en las secundarias.

byte variable_global
void función_secundaria()
{
variable_global++;
}
void main()
{
while(1)
{
función_secundaria();
}
}

Las variables se pueden definir AUTO, las cuales son aquellas que no se necesitan definir,
STATIC, variables locales que pasan a ser globales, y EXTERN, variables compiladas varias
veces.

 Operadores y expresiones: Las operaciones son aquellas usadas para cumplir con la tarea
lógica de nuestro programa ya sean sumas o restas aritméticas o lógicas, mientras que las
expresiones cumplen con la misma tarea, con la diferencia que no necesita escribir toda la
ecuación para que el programa lo entienda, por ejemplo:

o Operación => i=i+1


o Expresión => i++

Ambos tienen el mismo efecto sobre el registro “i” lo único que difieren es en la escritura
de la instrucción, como bien se puede apreciar mientras que el primer caso tiene cinco
caracteres el segundo tiene 3; aunque la diferencia no sea mucha, al momento de escribir
ecuaciones o algoritmos más y más complejos se empieza a ver la diferencia. En el
siguiente cuadro se dará a conocer los operadores y expresiones más comunes:
OPERADOR
Tipo de operador Definición Operador Descripción
+= Asignación de suma.
-= Asignación de resta.
*= Asignación de multiplicación.
/= Asignación de división
%= Asignación de resto de división.
Asignación de desplazamiento a
<<=
la izquierda.
Representan
Operadores Asignación de desplazamiento a
operaciones de formas >>=
de asignación la derecha.
más cortas.
&= Asignación de AND de bits
|= Asignación de OR de bits.
Asignación de OR exclusivo de
^^=
bits.
~= Asignación de negación de bits.
++ Asignación de incremento.
-- Asignación de decremento.
+ Suma.
- Resta.
Son las operaciones * Multiplicación.
Operadores
básicas encontradas en / División.
aritméticos
matemáticas. - Cambio de signo.
Módulo, resta de una división
%
entera.
< Menor que...
> Mayor que…
Comparan y dan un
Operadores <= Menor o igual que…
resultado: 1 verdadero,
relacionales >= Mayor o igual que…
0 falso.
== Igual que…
!= Distinto a…
Comparan cada registro ! Negado lógico (NOT).
Operadores lógicos y realizan la operación && Y lógico (AND).
correspondiente. || O lógico (OR).
Hacen la misma tarea de ~ Negado de bits (NOT).
Operadores de los operadores lógicos a & Y lógico de bits (AND).
manejos de bits nivel de bit y solo ^^ O lógico exclusivo de bits (XOR).
variables de tipo entero. | O lógico de bits (OR).
Operadores de Son capaces de mover >> Desplazamiento a la derecha.
desplazamiento de las posiciones de los bits
bits de un registro. << Desplazamiento a la izquierda.
Capaces de apuntar y & Directo
Operadores de
tomar el valor de un * Indirecto
dirección
puntero. -> Puntero a estructura
 Funciones: son las encargadas de separar el programa en segmentos de códigos, como ya
se había mencionado anteriormente, existe la función principal complementada de una o
más secundarias con el fin de ahorrar líneas repetidas de instrucciones. Al igual que las
variables se deben de definir al comenzar el programa y se pueden separar en librerías o
ficheros si se desea, con la extensión “.h” o “.c”.
 Declaraciones de control: Estas declaraciones se encargan de controlar el proceso del
programa:
Sentencia Descripción Diagrama de flujo Ejemplo de
código
if(A==5)
{
Decisión 1;
Ayuda a la toma de }
If – else else
decisiones.
{
Decisión 2;
}

Mientras se cumpla while(A==5)


{
While una condición repite Proceso;
el proceso. }

Mientras se cumpla do
{
una condición realiza
Do – While Proceso;
el proceso, al menos }
una vez. while(true)

Repite un caso for(A=0;A>=5;A++)


{
For tantas veces como Proceso;
se necesite. }

Toma un caso de
múltiples switch (A)
{
posibilidades.
Case 1: Proceso 1;
break;
Case 2: Proceso 2;
Switch – Case break;

Case 3: Proceso 3;
break;
}

Return Devuelve los datos a las funciones.


Break Permite Salir de un bucle.
Goto Realiza un salto incondicional.
 Comentarios: Ayudan a aclarar ciertos aspectos del programa, son muy útiles en dos casos
específicos, el primero cuando se quiere retomar un programa que se tiene en espera
durante mucho tiempo (suele pasar con algunos proyectos que necesitan echarle una
repasada a algunos temas o aprender otros nuevos), y cuando se le va a dar a un tercero,
en este caso si se acompaña de un diagrama de flujo este último no se sentirá tan perdido;
no tienen ningún efecto sobre el programa. Los comentarios se pueden escribir de dos
maneras:

o Los de una sola línea: El comentario empieza con dos barras diagonales “//” y se
escribe lo que se desea. Por ejemplo:

INT Variable=0 // Se define una variable tipo INT

o Los de dos o más líneas: Usualmente para hacer extensas especificaciones del
programa, en este caso se usa un barra diagonal junto a un asterisco, al comienzo
y al final pero, en distinto orden así:

/* Este programa se encargará de controlar el movimiento


de un motor paso a paso, tenga en cuenta los transistores
en los pines de salida para evitar dañar el PIC. */

 Directivas: También conocidas como directivas de pre-procesamiento, usualmente


empiezan con el símbolo “#” sin las comillas; se usan para indicarle y definirle al
microcontrolador las tareas y registros que debe tener en cuenta para comenzar sus
rutinas de manera adecuada y óptima, existe un gran número de estas y para no citarlas
todas se mencionarán las más comunes, para mayor información recomendamos el libro
de Eduardo García y el manual de usuario del compilador PCW de CCS (lo puede encontrar
en nuestra página oficial):

o #device chip, define el micro a usar, por ejemplo:

#device 16F877A

o #fuses options, permite quemar los fusibles del microcontrolador que se van a
usar en el momento de la programación, por ejemplo:

#fuses XT, NOPROTECT, NODEBUG

o #include “Archivo”, incluye en el programa y la compilación ciertos ficheros o


librerías, es muy útil para incluir la librería del PIC a usar o de diferentes
periféricos, esto evita definir una serie de parámetros que ya están definidas en
estos ficheros:
#include “16F877A.h”

o #use delay (clock=velocidad), define la base de tiempo en los que se basará el


programa para definir la cantidad de ciclos de máquina que requiere alguna
instrucción para ejecutarse de la manera más adecuada:

#use delay (clock=4000000)

o #ASM y #ENDASM, permite insertar código ensamblador a un programa en C,


aunque no acepta todos las instrucciones que pueda disponer el PIC, si tiene los
más importantes (recomendamos nuevamente el manual de CCS). Bastante útil a
quienes apenas comienzan a migrar:

#asm
Movlw 0x8
Movwf portb
#endasm

PRIMER PROGRAMA

Anteriormente se había mencionado dos maneras de realizar un programa en PIC C, una por el
PROJECT WIZARD y otra escribiendo todo el código en un documento con la extensión “.C”, ambos
casos son útiles, el primero lo recomendamos a los principiantes, una vez se tenga dominio en los
conceptos de PIC C pasar al segundo caso, este es bastante útil en el momento de necesitar el
programa disponible en la nube o en algún medio extraíble, ya que este permite compilarse en
equipos en donde no se haya hecho el programa.

Para hacer el mini-tuto más didáctico se decidió enseñar ambos ejemplos por medio de videos,
expuestos en nuestra página en youtube, aquí dejamos los enlaces:

Creación de un programa en C para microcontrolador PIC a través del PROJECT WIZARD:

http://youtu.be/b-Q_kUv7aCw

Creación de un programa en C para microcontrolador PIC desde un archivo de extensión “.c”:

http://youtu.be/lvK81htVrhs

Ya vistos estos videos se tiene idea de lo que se va realizar a continuación, independientemente


del método adoptado para crear y compilar el programa, este último efectuará una tarea sencilla:
un contador de 0 a 999 iniciado al oprimir un pulsador, una vez termine el conteo volverá a su
posición inicial esperando a que se vuelva a repetir el proceso.
Figura 3. Diagrama de flujo del programa ejemplo.

Fuente. Autores.

Para compilar el programa se adoptará el método de un archivo con extensión “.c”, esto para que
se pueda descargar el archivo desde nuestra página web y pueda compilarse ahí mismo, como se
demostró en el otro video, el método que se usa tendrá el mismo resultado, difiere únicamente en
unas pocas líneas:
#include <16F877A.h>
#fuses XT,NOWDT
#use delay(clock = 4000000)
#include <lcd.c>
#byte porta=0x05
#byte portd=0x08
#byte trisa=0x85
#byte trisd=0x88
#byte adcon1=0x9f
char secu[10]={'0','1','2','3','4','5','6','7','8','9'};

void main()
{
byte uni,dec,cen;
adcon1=0x07;
trisa=0x01;
trisd=0x00;
lcd_init();
lcd_putc('\f');
while(true)
{
if(bit_test(porta,0)==1)
{
lcd_gotoxy(1,1);
printf(lcd_putc,"Contador ON ");
for(cen=0;cen<10;cen++)
{
for(dec=0;dec<10;dec++)
{
for(uni=0;uni<10;uni++)
{
lcd_gotoxy(16,2);
lcd_putc(secu[uni]);
lcd_gotoxy(15,2);
lcd_putc(secu[dec]);
lcd_gotoxy(14,2);
lcd_putc(secu[cen]);
delay_ms(100);
}
}
}
}
else
{
lcd_gotoxy(1,1);
printf(lcd_putc,"Contador en cero");
lcd_gotoxy(14,2);
printf(lcd_putc,"000");
}
}
}

Lo primero que puede observar es la ausencia de los comentarios en los que se han insistido
anteriormente, esto debido a que se explicará paso a paso el funcionamiento del programa y de
cada instrucción, tenga en cuenta la estructura del programa, pues es fundamental para que se
pueda compilar el programa, si no queda claro este aspecto no dude en contactarnos, con gusto
aclararemos cualquier pregunta:

#include <16F877A.h>: Esta instrucción ya se había explicado anteriormente, con esta se incluye la
librería que contiene los datos básicos para el manejo del microcontrolador, en este caso el
PIC16F877A, al programa.

#fuses XT,NOWDT: En este punto se configuran los fusibles del PIC, para el caso solamente se le
indica al microcontrolador que la velocidad máxima será de 4MHz proveniente de un cristal de
cuarzo y que no se hará uso del perro guardián o watchdog.

#use delay(clock = 4000000): Aquí se configura la base de tiempo del PIC, muchos se preguntarán
el porqué es necesaria esta instrucción, esto se debe a que PIC C genera una serie de ciclos de
máquina para hacer funcionar el microcontrolador, pero debido a que estos ciclos son
inversamente proporcionales a la frecuencia de reloj inducida al PIC (Ciclo de máquina = 4/Fosc),
no se puede poner deliberadamente x cantidad de ciclos, o sino el lenguaje C no se podría usar
para programar estos dispositivos.

#include <lcd.c>: Aunque es la misma instrucción mencionada tres puntos atrás, esta incluye otra
librería la del manejo del display LCD, así como esta se pueden incluir tantas librerías como se
necesiten sin importar si es propia o de un tercero.

#byte porta=0x05: Esta es la primera instrucción de una serie igual, esta se usa para definir
variables de tipo byte en una posición de memoria específica, ¿qué tiene de especial?,
básicamente porque define una variable importante en la posición de memoria 05h del
microcontrolador, véase la página 19 del datasheet del PIC, al igual que las instrucciones similares
siguientes.

char secu[10]={'0','1','2','3','4','5','6','7','8','9'}: Bueno este tipo de instrucción es algo avanzada,


pero no es nada del otro mundo, esta estructura define matrices, para el caso es una simple matriz
de 1x10 (una fila, diez columnas), la primera parte “char” indica que todos los datos introducidos
son de tipo carácter o char (los cuales son los que únicos que entiende, por así decirlo, el LCD); en
cuanto a “secu” es el nombre dada a la matriz, este es el referente para citarla posteriormente;
[10] es la extensión de la matriz, si se necesita más de una fila la definición es por medio de dos
números separados por corchetes cuadrados así [y][x]; y finalmente siguen los datos, estos son
separados por comas, en este caso en particular se encierran entre comillas sencillas, para indicar
que son tipo char, convirtiendo el carácter a su formato ASCII de manera transparente.

void main(): Esta es la función principal, es decir la columna vertebrar de tu programa, no importa
cuántas instrucciones y funciones se le pongan encima, C siempre comenzará por acá. Recuerden
que seguida de la función van los corchetes {}, entre estos se encierran las líneas de comandos que
la rutina ha de ejecutar.

byte uni,dec,cen: Una sencilla línea de definición de variables, en este caso tres tipo byte,
recuerden que debido a la estructura, antes de cualquier cosa dentro de una función van las
definiciones de las variables, este punto es crítico cuando se crea el proyecto por el PROJECT
WIZARD, se debe fijar que encima de las líneas creadas automáticamente en la función principal
(dentro del void) se definan las variables, de lo contrario PIC C mostrará error.

Las líneas venideras como la referente al ADCON y los TRISx demuestran la versatilidad de PIC C,
pues permite definir variables tan elementales del PIC como estas y configurarlas tal cual se haría
en ASM, y sin la necesidad de usar los comandos específicos de este lenguaje (#ASM… #ENDASM).
Posteriormente se usarán los métodos definidos específicamente para C, como el uso de
apuntadores, sin embargo, este método es más práctico en casos específicos.

lcd_init(): Esta instrucción es propia de la librería de la pantalla LCD, es usada para inicializar este
elemento, siempre se usa en las primeras líneas de la función principal.

lcd_putc('\f'): Esta línea se usa para limpiar el LCD de cualquier registro que le haya quedado de un
uso anterior, también es usada para imprimir datos o líneas de datos en el LCD.

while(true): Esta declaración genera un ciclo infinito, es decir, repite una misma rutina una y otra y
otra vez, con el fin de que el microcontrolador siempre ejecute una tarea en específico y no se
bloquee.

if(bit_test(porta,0)==1): Esta otra declaración es usada para testear o revisar el estado del pin A0
del microcontrolador, esto se puede ver por medio de su estructura; el if es la declaración de
decisión es decir, si se cumple con la condición dada entre los paréntesis se ejecuta la tarea de lo
contrario se ignora; bit_test es el encargado de revisar el pin referenciado dentro de los paréntesis
siguientes; (porta,0) referencia el pin del microcontrolador a revisar, primero se le dice que puerto
o variable debe tomar y después de la coma se pone el pin o bit a testear, y en conjunto nos dice
que el objetivo es el pin A0, de igual forma se pueden testear bits de variables definidas por el
usuario; finalmente la condición “==1” se refiere al estado en el que se debe encontrar el pin para
que se pueda ejecutar la declaración. En otras palabras, esta instrucción se puede leer: Si el pin A0
del microcontrolador está en uno haga…

lcd_gotoxy(1,1): Su objetivo es posicionar el cursor del LCD en el lugar designado por los números
entre los paréntesis, el primero posiciona el cursor en la columna y el segundo en la fila (y,x).

printf(lcd_putc,"Contador ON "): Imprime la serie de caracteres escritas entre las comillas en la


pantalla LCD.

for(cen=0;cen<10;cen++): esta es una declaración de conteo desde cero hasta 9, y cada cambio
queda registrado en la variable cen.

lcd_putc(secu[uni]): Imprime en el LCD el carácter de la matriz secu de la posición designada por el


valor de la variable uni. Es decir, si uni tiene el valor de 3, el programa mostrará el carácter de la
posición 3, que para este caso es el valor ASCII de 3; se debe tener en cuenta que si el valor de uni
apunta a una posición inexistente en la matriz el programa se bloquea completamente.
delay_ms(100): Genera un retraso de 100 milisegundos, el tiempo es determinado por el número
entre paréntesis y el acrónimo ms, también se puede usar microsegundos usando us así delay_us.
Estos tiempos no son completamente exactos pues varían según el programa, por ende si se
desean tiempos exactos se debe acudir a los Timer que posea el PIC.

else: es la otra parte de la declaración if, y se encarga de cubrir las otras posibilidades que no hace
las instrucciones dentro del if.

Esperamos que con esta detallada explicación de las instrucciones usadas en el programa ejemplo
sean de ayuda y se pueda comprender la programación en PIC C.

Finalmente y como un bonus dejamos un video tutorial para compilar programas de PIC C en el
programa oficial de Microchip:

http://youtu.be/xIozjzoKZh4

Estos son los parámetros más básicos de PIC C, en los documentos descritos en las referencias, se
puede conseguir mayor información, sin embargo la principal herramienta es la curiosidad,
cualquier duda, comentario u observación que tengan no duden en dirigirse a nuestro correo
electrónico y redes sociales, aunque no seamos los mayores expertos, también podemos aprender
con ustedes, muchas gracias por leer nuestro artículo.

REFERENCIAS

http://es.wikipedia.org/wiki/C_(lenguaje_de_programaci%C3%B3n)

http://www.aquihayapuntes.com/indice-programacion-pic-en-c.html

Compilador C CCS y simulador Proteus para Microcontroladores PIC, de Eduardo García

Manual de usuario del compilador PCW de CCS

http://ww1.microchip.com/downloads/en/DeviceDoc/39582b.pdf

También podría gustarte