tecmikro logo
Programación de microcontroladores PIC en mikroC PRO
Email: tecmikro@gmail.com   Cel. 098 743 8877   Telf. 243 0352 Quito-Ecuador


Programación de PIC en C con el compilador mikroC PRO

 

A continuación se presentan los conceptos fundamentales más importantes, necesarios para emprender exitosamente el aprendizaje de programación de microcontroladores PIC en C, utilizando el conocido compilador mikroC PRO.

La programación en el compilador mikroC PRO se basa en PROYECTOS. Cada proyecto está conformado por un conjunto de archivos interrelacionados entre sí. Para crear un programa primero se debe crear un Proyecto (básicamente se debe seleccionar el microcontrolador, la frecuencia de operación y establecer los bits de configuración); a continuación se procede a escribir las instrucciones del programa en lenguaje C (código fuente); y por último se genera el código de máquina .HEX (código ejecutable) que será almacenado en la memoria de programa del microcontrolador.

En este artículo se explican los detalles de la programación de microcontroladores PIC en lenguaje C, es decir la sintaxis (cómo se deben escribir las instrucciones) y el uso de las instrucciones con ejemplos prácticos. Se recomienda al lector que estudie y repase estas líneas con paciencia y dedicación ya que constituyen la piedra angular sobre la cual descansa la programación de microcontroladores; el dominio de estos conceptos le permitirán a usted convertirse en un experto en la programación de microcontroladores PIC.

Estructura básica de un programa en mikroC PRO (sin funciones)

Todos los programas (código fuente) de microcontroladores PIC en C tienen una estructura básica, a partir de la cual se desarrolla cualquier aplicación del usuario:

//Nombre_de_programa.c
//Descripción del programa. 
//Autor: Ing. Penagos R.
//Declaración de variables
...
//Función principal
void main( ){
//Instrucciones del programa.
...
}

En el código anterior se debe entender lo siguiente:

Los 7 elementos básicos de la programación de PIC en C

La programación de PIC en C se puede comprender mejor si se estudian sus elementos básicos; una vez que se dominen estos elementos se podrá dar solución a la gran mayoría de problemas de programación. El propósito de la mayoría de los programas es resolver un problema. Los programas resuelven los problemas por medio de la manipulación de información o datos. Normalmente los programas se caracterizan por permitir el ingreso de información, tener uno o varios lugares de almacenamiento de dicha información, contar con las instrucciones para manipular estos datos y obtener algún resultado del programa que sea útil para el usuario. También, las instrucciones se pueden organizar de tal forma que algunas de ellas se ejecuten sólo cuando una condición específica (o conjunto de condiciones) sea verdadera, otras instrucciones se repitan un cierto número de veces y otras pueden ser agrupadas en bloques que se ejecutan en diferentes partes de un programa.
Lo anterior constituye una breve descripción de los siete elementos básicos de la programación: entrada de datos, tipos de datos, operaciones, salida, ejecución condicional, lazos y funciones. Una vez que se dominan estos elementos se puede afirmar que se conocen los fundamentos de la programación, con lo cual ya es posible desarrollar una gran cantidad de aplicaciones de diversa índole.

Instrucciones básicas de PIC en C

1.- Instrucción de asignación (=)
Permite asignar a una variable un valor constante, el contenido de otra variable o el resultado de una expresión matemática. La asignación va de derecha a izquierda. Por ejemplo,

suma=0; //El valor 0 se almacena en la variable suma.
x0=x1; //El contenido de la variable x1 se almacena en la variable x0.
dx=(b-a)/n; //El resultado de la expresión matemática se almacena en la variable dx.

2.- Instrucción de entrada de datos (variable=PORTx)
Permite el ingreso de uno o más datos a través de los pines del microcontrolador y almacenarlos en una o más variables. Por ejemplo,

variable=PORTA; //Los bits del puerto A se almacenan en la variable.

El siguiente es un caso especial utilizado en la programación de microcontroladores PIC en C:

PORTB=PORTA; //Los bits del puerto A se envían hacia los pines del puerto B.

También se puede leer el estado individual de cada bit de un puerto:

variable=RB3_bit; //Lee el estado del pin RB3 y lo guarda en la variable.

3.- Instrucción de salida de datos (PORTx=dato)
Permite el envío de datos, el contenido de una variable o el resultado de una expresión matemática hacia los pines de un puerto. Por ejemplo,

PORTA=0x00; //Todos los pines del puerto A se ponen en 0.
PORTB=variable; Los bits de la variable son enviados hacia los pines del puerto B.
PORTB=PORTA+65; //El valor del puerto A más 65 se envía hacia el puerto B.

Como caso especial, se pueden enviar bits individuales a cada uno de los pines de un puerto:

RB0_bit=0; //El pin RB0 se pone en 0.

4.- Instrucción de decisión (if...else)
Permite la ejecución de las instrucciones1 si la condición es verdadera, de lo contrario se ejecutan las instrucciones2. Las llaves { } no son necesarias cuando hay una sola instrucción.

if (condición){
 instrucciones1;
}
else{
 instrucciones2;
}

Ejemplo 1:
Si el contenido de la variable codigo es igual al contenido de la variable clave, se ejecutan las primeras cuatro instrucciones; de lo contrario se ejecutan únicamente los dos últimas instrucciones.

if (codigo==clave){
 intentos=0;
 RA7_bit=1;
 Delay_1sec( );
 RA7_bit=0;
}
 else{
 intentos++;
 Delay_ms(200);
}

Ejemplo 2:
Instrucción de decisión sin else. Esta es una variante muy utilizada cuando se desea condicionar la ejecución de un grupo de instrucciones.
Las dos instrucciones se ejecutarán únicamente si la variable contador es igual a 2, de lo contrario la ejecución continúa a partir de la línea //Aquí.

if (contador==2){
 RB6_bit=~RB6_bit;
 contador=0;
}
//Aquí.

Ejemplo 3:
Similar al caso anterior pero con una sola instrucción. Si la variable horas es igual a 24 se reinicia esta variable con un valor de cero.

if (horas==24) horas=0;

Nota 1: Las condiciones se obtienen por medio de los operadores de relación y los operadores lógicos.

Nota 2: Operadores de relación:

>    Mayor que
>=   Mayor o igual que
<    Menor que
<=   Menor o igual que
==   Igual a (nótese la diferencia con el operador de asignación =)
!=   No es igual a

Nota 3: Operadores lógicos:

&&   Y
||   O

5.- Instrucción de ciclo controlado por una variable (for)
Permite ejecutar un grupo de instrucciones de manera repetitiva, una determinada cantidad de veces.

for (número de veces){
 instrucciones;
}

Ejemplo 1:
La variable i tiene un valor inicial de 7 (i=7) y un valor final de 1 (i>=1). Esta variable va disminuyendo de 1 en 1 (i--). Por lo tanto las dos instrucciones se ejecutarán en 7 ocasiones. La primera vez cuando i=7, la segunda cuando i=6, la tercera cuando i=5 y así sucesivamente hasta la séptima vez cuando i=1. Luego la ejecución continúa a partir de la línea //Aquí.

for (i=7; i>=1; i--){
 PORTB=PORTB<<1;
 Delay_ms(500);
}
//Aquí.

Ejemplo 2:
El valor inicial de la variable es 1 y su valor final es 3. La variable i se va incrementando de 1 en 1 (i++). Por lo tanto la instrucción se ejecuta tres veces, lo que da como resultado un retardo de 3 segundos. Luego la ejecución continúa a partir de la línea //Aquí.

for (i=1; i<=3; i++)
 Delay_1sec( );
//Aquí.

6.- Instrucción iterativa condicional (while)
Permite ejecutar un grupo de instrucciones de manera repetitiva, mientras una condición sea verdadera. Primero se revisa la condición para determinar su valor de verdad (verdadero o falso) y luego se ejecutan las instrucciones.

while (condición){
 instrucciones;
}

Ejemplo 1:
La ejecución del programa permanece indefinidamente en esta línea mientras el bit IOFS del registro OSCCON sea igual a cero. Como caso particular no se ejecuta ninguna instrucción (la cual debería estar antes del punto y coma).

while (OSSCON.IOFS==0) ;

Ejemplo 2:
Ejemplo de un lazo infinito. En mikroC PRO, cualquier valor numérico diferente a cero se considera VERDADERO, y un valor numérico igual a cero se considera FALSO.
Al valor numérico del puerto A se le suma el valor 65, el resultado se envía hacia los pines del puerto B. Este proceso se repite continua e indefinidamente, debido a que la condición siempre es verdadera (1).

while (1)
 PORTB=PORTA+65;

Ejemplo 3:
Las cuatro instrucciones encerradas por { } se ejecutarán indefinidamente mientras el valor del bit RB0 sea igual a 0.

while (RB0_bit==0){
 RB1_bit=1;
 Delay_ms(500);
 RB1_bit=0;
 Delay_ms(200);
}

7.- Instrucción hacer-mientras (do...while)
Permite ejecutar un grupo de instrucciones de manera repetitiva, mientras una condición sea verdadera. Es similar a la instrucción while, con la diferencia de que primero se ejecutan las instrucciones y luego se revisa la condición.

do{
 instrucciones;
}
while (condición);

Ejemplo 1:
La variable kp tiene un valor inicial de cero. La instrucción kp=Keypad_Key_Click( ); se ejecuta y luego se revisa la condición (!kp).Mientras kp sea igual a cero (FALSO) la condición será VERDADERA (!kp), debido al operador de negación ! que cambia el valor de verdad a su estado contrario. Como resultado se tendrá un lazo infinito mientras la variable kp siga en cero. Cuando la variable kp cambie de valor como consecuencia de la pulsación de una tecla, la condición será FALSA y la ejecución continuará en la línea //Aquí.

kp=0;
do
 kp=Keypad_Key_Click( );
while (!kp);
//Aquí.

Ejemplo 2:
Las cuatro instrucciones dentro de { } se ejecutarán indefinidamente mientras la variable tecla sea diferente a 1.

do{
 ingreso( );
 raiz( );
 pn_1( );
 seg_grado( );
}
while (tecla != 1);

Nota: A diferencia de la instrucción while, en la instrucción do...while las instrucciones se ejecutan por lo menos una vez.

8.- Instrucción de selección múltiple (switch)
Permite la ejecución de un grupo de instrucciones de varios grupos posibles, dependiendo del valor de una variable.

switch (variable){
 case 1: instrucciones1;
         break;

 case 2: instrucciones2;
         break;

 case 3: instrucciones3;
         break;

 …

 default: instrucciones;
}

Si la variable es igual a 1 se ejecutan únicamente las instrucciones1, si es igual a 2 se ejecutan únicamente las instrucciones2 y así sucesivamente. Si la variable no es igual a ninguno de los casos (case) se ejecutan las instrucciones por defecto (default).

Ejemplo 1:
Esta es una función numérica que da como resultado un número hexadecimal dependiendo del valor que tenga la variable digit. Si digit es igual a 0 la función devuelve (return) el valor 0x3F. Si digit es igual a 1, la función devuelve el valor 0x06, y así sucesivamente. Este ejemplo es una variante de la instrucción switch, donde no aparece el elemento default.

char Bin2_7seg(char digit){
 switch (digit){
  case 0: return 0x3F; 
  case 1: return 0x06; 
  case 2: return 0x5B;
  case 3: return 0x4F;
  case 4: return 0x66;
 }
}

Funciones
Una función es una agrupación de instrucciones para formar una nueva instrucción creada por el programador (usuario). Empleando funciones, la solución total de un determinado problema se divide en varios subproblemas, cada uno de los cuales es resuelto por medio de una función particular, aplicando de esta manera la conocida máxima Divide y vencerás.
Las funciones constituyen una de las características fundamentales de mikroC PRO, pues todo programa bien escrito hace uso de ellas. Para poder utilizar una función se deben cumplir los dos siguientes pasos:

1.-Declaración de la función.- Consiste en indicar el tipo, nombre y parámetros de la función:

tipo nombre ( parámetro1, parámetro2, ...);

2.-Definición de la función.- Consiste en indicar las instrucciones que forman parte de dicha función:

tipo nombre ( parámetro1, parámetro2, ...){
 instrucciones;
}

Estructura básica de un programa en mikroC PRO (con funciones)
Todos los programas (código fuente) en mikroC PRO tienen una estructura básica, a partir de la cual se desarrolla cualquier aplicación del usuario:

//Nombre_de_programa.c
//Descripción del programa. 
//Autor: Ing. Penagos R.
//***************************Declaración de funciones (prototipos)**************************
...
//******************************Fin de declaración de funciones*****************************

//==================================Declaración de variables================================ 
...
//===============================Fin de declaración de variables============================

//**********************************Función principal******************************** 
void main( ){
  //Instrucciones del programa.
  ...
}
//********************************Fin de función principal***************************

//================================Definición de funciones============================ 

función1{ 
 instrucciones1;
}

función2{ 
 instrucciones2;
}
//============================Fin de definición de funciones==========================

Nota 1: Los tipos de funciones más empleadas son numéricas char y nulas void. Las primeras retornan return o devuelven como resultado un número, mientras que las segundas simplemente ejecutan un grupo de instrucciones.

Ejemplo 1:
Este ejemplo se puede encontrar en el capítulo II, Puertos Digitales, del libro. La función es numérica char, su nombre es Bin2_7seg y tiene un parámetro digit de tipo char.
La función se utiliza como si fuera una instrucción cualquiera, tomando en cuenta el tipo de función y su(s) parámetro(s). En este ejemplo se tiene PORTB=Bin2_7seg(PORTA). Esto significa que la variable PORTA remplaza a la variable digit. Por lo tanto si PORTA es igual a 0, la función devuelve el valor 0x3F que será enviado al puerto B. Si PORTA es igual a 1, la función devuelve 0x06 que será enviado al puerto B, y así sucesivamente.

//7seg1.c
//Se utiliza la función Bin2_7seg que transforma un número binario a su
//equivalente en 7 segmentos.

char Bin2_7seg(char digit); //Prototipo de la función. 

void main(){ 
OSCCON=0x40; //Oscilador interno a 1MHz.
while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
PORTA=0x00;  //Inicialización.
PORTB=0x00;
ANSEL=0x00;  //Pines AN<6:0> como E/S digital.
TRISB=0x00;  //Puerto B como salida.
while (1) PORTB=Bin2_7seg(PORTA);
}

char Bin2_7seg(char digit){  //Definición de la función. 
 switch (digit){
   case 0: return 0x3F;  //0x3F es el código 7-segmentos del 0.
   case 1: return 0x06;  //0x06 es el código 7-segmentos del 1.
   case 2: return 0x5B;
   case 3: return 0x4F;
   case 4: return 0x66;
   case 5: return 0x6D;
   case 6: return 0x7D;
   case 7: return 0x07;
   case 8: return 0x7F;
   case 9: return 0x67;
 }
}

Ejemplo 2: Trabajo simplificado con funciones.

Variante del ejemplo anterior, en el que se hace únicamente la definición de la función (sin declaración). Se debe hacer antes de la función principal, de lo contrario se producirán errores de compilación por tratar de usar una función desconocida. Este método de uso de funciones es muy popular ya que simplifica notablemente la escritura de los programas asi como su mantenimiento.

//7seg1.c
//Se utiliza la función Bin2_7seg que transforma un número binario a su
//equivalente en 7 segmentos.

char Bin2_7seg(char digit){  //Definición de la función. 
 switch (digit){
   case 0: return 0x3F;  //0x3F es el código 7-segmentos del 0.
   case 1: return 0x06;  //0x06 es el código 7-segmentos del 1.
   case 2: return 0x5B;
   case 3: return 0x4F;
   case 4: return 0x66;
   case 5: return 0x6D;
   case 6: return 0x7D;
   case 7: return 0x07;
   case 8: return 0x7F;
   case 9: return 0x67;
 }
}

void main(){ 
OSCCON=0x40; //Oscilador interno a 1MHz.
while (OSCCON.IOFS==0);//Esperar mientras el oscilador está inestable.
PORTA=0x00;  //Inicialización.
PORTB=0x00;
ANSEL=0x00;  //Pines AN<6:0> como E/S digital.
TRISB=0x00;  //Puerto B como salida.
while (1) PORTB=Bin2_7seg(PORTA);
}

      

Detalles importantes de mikroC PRO para tener en cuenta
En la programación de PIC en C existen pequeños detalles que se deben tener muy en cuenta y que permitirán que los programas realizados cumplan las tareas para los cuales fueron diseñados. Con respecto a los comentarios, se puede decir que son importantes aunque no son necesarios. Su importancia radica en que ofrecen una mayor facilidad para entender el código y realizar su mantenimiento (esto es especialmente cierto cuando ha pasado el tiempo y necesitamos realizar alguna modificación).

Los tipos de datos más utilizados se muestran en la tabla 1.5.

Programación de pic en c: Tipos de datos en mikroc pro
Tabla 1.5 Tipos de datos más comunes en mikroC PRO


El tipo float es para números con punto decimal, mientras que los demás tipos son para números enteros.
La EJECUCIÓN DE UNA INSTRUCCIÓN consiste en la realización de las operaciones especificadas en esa instrucción. De la ejecución se encarga la CPU (unidad central de proceso) del microcontrolador PIC.


eBook en formato PDF "Cómo programar microcontroladores PIC"

Guía básica para programar microcontroladores PIC en mikroC PRO. Disponible en formato PDF. A la venta por tan sólo US$12.00

¡Cómpralo ya!