Está en la página 1de 44

Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

CURSO BASICO DE PROGRAMACION DE MICROCONTROLADORES


PIC EN LENGUAJE C

1. HERRAMIENTAS NECESARIAS PARA REALIZAR EL CURSO:

a. Compilador para PIC, en concreto el PCW compiler de la casa CCS

Te puedes bajar una versión de Evaluación


por 30 días desde aquí:

http://www.ccsinfo.com/ccsfreedemo.php

Después de rellenar el formulario te


descargas el programa de instalación y lo
instalas en tu ordenador como un programa
más de Windows, aunque tienes que tener en
cuenta que solo podrás programar un
pequeño conjunto de PIC de cada familia,
otro inconveniente es que tienes que estar
conectado a Internet para que te funcione si
no te aparecerá una ventanita poco amigable.

Otra limitación es que el tamaño del


programa no puede superar los 2K de
memoria, aunque para los ejemplos que vamos a hacer aquí te sobra.

b. Programa para Simulación: el PROTEUS de Labcenter Electronics

La versión de evaluación de Proteus te la


puedes descargar desde aquí:

http://www.labcenter.co.uk/download/prod
emo_download.cfm

Claro que tiene limitaciones, sino no sería una


demo, la principal es que no podemos guardar
nuestros trabajos y la segunda es que no lleva
incorporado muchas de las librerías dinámicas
necesarias para realizar la simulación de
algunos microcontroladores. Mira a ver si el
amigo que te dejo el compilador te puede
dejar también una licencia para este
magnífico Simulador.

1
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

2. MI PRIMER PROGRAMA EN C CON EL COMPILADOR PCW C


Vamos a crear nuestro primer ejemplo paso a paso: abrimos nuestro compilador y antes de crear un nuevo
programa, tal vez aparezca el último programa creado, si este es el caso, seleccionamos Close All del
primer icono para cerrar todos los programa anteriores; sólo entonces seleccionamos New->Source File
según se muestra en la figura de abajo:

Nos saldrá un cuadro de dialogo de guardar de Windows, donde le pondremos un nombre a nuestro
archivo y lo guardaremos. Tener cuidado de crear una nueva carpeta para cada proyecto que
hagamos; en el cual guardaremos el archivo.c del programa y el archivo.dsn del Proteus. Después
escribimos el código fuente que se muestra en la figura de abajo y guardamos el documento:

Comentario del programa:

En primer lugar nos encontramos con tres directivas del prepocesador, las identificaremos porque
empiezan por el símbolo (#):

• La primera de ellas es una directiva include su función es introducir un documento dentro de


otro. En la posición del programa donde se encuentra esta directiva, se incluirá el archivo indicado.
Se suele usar para incluir los archivos de cabecera (generalmente con extensión.h). En este caso

2
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

concreto se incluye el archivo <16F877A.h>,en este archivo se incluyen las definiciones de los
registros del PIC.

• #use delay (clock=4000000); directiva para el uso de retardos, entre paréntesis tenemos que
poner la frecuencia de reloj que vamos a utilizar.

• #use rs232 (baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8) esta directiva es para la


comunicación del PIC con otro dispositivo vía RS232, por ejemplo un ordenador, en ella se
encuentran definidas los prototipos de las funciones de entrada y salida como printf().

En segundo y último lugar se encuentra la función main. Este es el núcleo del programa, el que va
a incluir todos los pasos a seguir durante su ejecución. En nuestro primer ejemplo solo contiene
una sentencia que hace una llamada a la función printf(), esta función se encarga de mostrar un
mensaje por el dispositivo de salida RS-232.

El mensaje que muestra la función printf es el que recibe como parámetro (el texto entre
paréntesis). Dicho mensaje es delimitado por las comillas dobles, que indican el principio y el fin
de una cadena de texto.

a. Compilación del programa


Compilar significa traducir nuestro programa que ha sido en un lenguaje de alto nivel, a un
lenguaje que nuestro PIC pueda entender, en este caso a unos y ceros, lo que se puede expresar
mejor en lenguaje hexadecimal, es por eso que después de compilar se creará varios archivos,
entre ellos uno con extensión HEX. Para compilar seleccionamos la pestaña Compile y pulsamos
sobre Compile para construir todo.

Vemos que el archivo de salida no nos ha producido ningún error. Por tanto el proyecto se ha
generado correctamente. Y si vamos a la carpeta donde habíamos guardado nuestro primer
ejemplo, tenemos todos los archivos que nos ha creado el IDE:

3
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

De todos estos archivos los que mas nos interesa son los que están marcados en la figura de
arriba. El archivo Primer_Programa.hex es el que tenemos que utilizar para programar el PIC y el
que termina con extensión .cof lo utilizaremos para cargarlo en el simulador Proteus y poder
simular el programa paso a paso, entre otras posibilidades muy útiles a la hora de depurar nuestro
código.

b. Simulación con Proteus


Ya tenemos nuestro primer ejemplo generado y listo para
cargarlo en nuestro simulador Proteus. Vamos a ello:
Arrancamos nuestro simulador Proteus y pasamos a
colocar nuestros dispositivos en el área de trabajo.
Empezaremos colocando el PIC, para ello hacemos clic en
el botón que pone Pick Devices según se muestra en la
figura de alado:

En la ventana que nos aparece en el campo Keywords escribimos el nombre de nuestro PIC.

Una vez seleccionado


hacemos doble clic sobre él
para incorporarlo a nuestro
proyecto.

Vamos por el segundo y


último elemento que
necesitamos para simular
nuestro programa. Hay que
tener en cuenta que el

4
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

simulador es capaz de hacer funcionar nuestro circuito sin algunos elementos que serían
necesarios si decidimos montar nuestro circuito en una placa real (por ejemplo la alimentación del
PIC y el cristal de cuarzo).

El segundo elemento que necesitamos es


un Terminal Virtual que hará las veces de
monitor, para poder ver las salidas en
formato texto de nuestro PIC como si se
tratará del símbolo del sistema en un
ordenador de escritorio con el Windows
instalado. En la figura de alado se muestra
donde podemos incorporar dicho
instrumento.

Con esto ya tendremos los dos elementos


necesarios para simular nuestros
programas. La interconexión de los dos
dispositivos es muy sencilla según se
muestra en la figura de abajo, solo hay que
hacer clic con el puntero del ratón en
forma de lápiz entre los terminales que
queremos conexionar:

El pin del PIC que habíamos elegido como transmisión de datos en nuestro programa irá
conectado al terminal RXD de recepción de datos en el Terminal Virtual y viceversa. Una vez
terminado de colocar todos los componentes para la simulación, conviene grabar el archivo
poniéndole un nombre adecuado. Para nuestro caso lo llamaremos Programa1.dsn, luego de ello
solo nos queda cargar nuestro programa en el PIC para poder simularlo, para ello hacemos doble
clic sobre el PIC y nos aparecerá la ventana de la figura de abajo:

5
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Los valores que en un principio tenemos que introducir para que nuestra simulación funcione son
los que están señalados en la figura de arriba. En Program File pincharemos sobre la carpeta y
seleccionaremos el archivo con extensión .cof que se había creado al compilar nuestro programa,
si en vez de este seleccionamos el que tiene extensión .Hex funcionará igual pero no podremos
realizar la simulación paso a paso. El otro valor a tener en cuenta es que la frecuencia del reloj del
PIC debe coincidir con el valor que le habíamos puesto en el programa en nuestro caso 4 MHz.

Si ahora hacemos clic sobre el botón Play se nos abrirá una terminal al estilo
MSDOS donde nos mostrará la salida de nuestro programa:

Ahora si le damos al botón de simulación paso a paso podremos simular nuestro ejemplo paso a
paso desde cualquier momento o mejor si antes le damos STOP (para programa) y reanudamos la
simulación, peo esta vez presionando el botón STEP . Entonces nos aparecerá
la siguiente ventana donde podemos ver la ejecución del programa línea a línea o poner puntos de
interrupción en las partes del programa que nosotros queramos:

6
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Ejercicio de calentamiento:
Cambiar el PIC utilizado a PIC16F628A tanto en el compilador CCS como en el Simulador PROTEUS.

Hasta ahora podemos notar que nuestro programa tiene 2 partes:


- DIRECTIVAS
- FUNCION PRINCIPAL

Más adelante iremos agregando mas detalles muy interesantes.

3. VARIABLES Y TIPOS DE DATOS


¿Qué son las variables? pues sencillamente el poder identificar con un nombre una o varias posiciones de
memoria de la RAM de nuestro PIC y de esta manera el poder almacenar allí los datos que va a utilizar
nuestro programa. En C para poder utilizar una variable primeramente hay que declararla siguiendo la
siguiente sintaxis:

tipo nombre_variable [=valor];

Lo que va entre corchetes es porque es opcional es decir, las variables se pueden inicializar ó no al
declararlas. Ejemplo de variable declarada:
int i;

Ejemplo de variable declarada e inicializada:


int i=5;

En una misma línea se puede declarar más de una variable siguiendo el siguiente formato:
tipo nombre_variable1,nombre_variable2,....;

Hay que tener en cuenta que la línea tiene que acabar en punto y coma.
El tipo de datos es obligatorio ponerlo y le dice al compilador cuantas celdillas de memoria tiene que
reservar para almacenar el valor de la variable. Los tipos de datos pueden variar de un compilador a otro,
vamos a ver los tipos de datos que podemos usar con nuestro compilador CCS.

Los tipos de datos básicos que utiliza nuestro compilador son los siguientes:

7
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

¿Dónde se declaran las variables?


Las variables según el lugar en que las declaremos pueden ser de dos tipos: globales o locales.
• La variables globales se declaran fuera de las funciones y pueden ser utilizadas en cualquier
parte del programa y se destruyen al finalizar éste.
• Las variables locales se declaran en la función en que van a ser utilizadas. Sólo existen dentro
de la función en que se declara y se destruye al finalizar dicha función. Si una función va a usar
argumentos (DATOS), entonces debe declarar las variables que van a aceptar los valores de esos
argumentos. Estas variables son los parámetros formales de la función. Se comportan como cualquier
otra variable local de la función, creándose al entrar en la función y destruyéndose al salir. Cuando
veamos el tema de las funciones veremos ejemplos de estas variables.

Vamos a agregar algunas variables al programa anterior para poder entender mejor como es que se
utilizan. Agregar las siguientes líneas de modo que quede como se ve:

#include <16F628A.h> //cambiamos el pic a utilizar


#use delay(clock=4000000)
#use rs232 (baud=9600, parity=N, xmit=PIN_B2, rcv=PIN_B1)

short a=1;
int entero=255;
long largo=65535;
float flotante=3225.76;
char caracter='A';

void main()
{
printf("Hola Mundo, mi primer programa para PICS en Lenguaje C\r");
printf("variable short = %d\r", a);
printf("variable int = %u\r", entero);
printf("variable long = %lu\r", largo);
printf("variable float = %f\r", flotante);
printf("variable char = %c\r", caracter);
}

CONSIDERACIONES: Hay que intentar siempre utilizar el tipo de dato que menos memoria ocupe
dentro de los valores que pueda utilizar la variable. Si abusamos de los tipos grandes para almacenar
valores pequeños nos quedaremos sin memoria y en los programas grandes es un dato que tenemos
que tener en cuenta.

8
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

4. USO DEL LCD (DISPLAY DE CRISTAL LIQUIDO)


Ahora vamos a cambiar el dispositivo de salida del PIC. En lugar de usar el terminal virtual, vamos a utilizar
el LCD de 2x16 líneas, uno de los más utilizados en los proyectos electrónicos. Pero antes daremos algunas
especificaciones del mismo:

El LCD es usado para usado para representar caracteres alfanuméricos. Tiene una Memoria RAM de
pantalla (Display Data RAM: DDRAM) con un total de 80 posiciones. En los 8 bits se almacena el código del
carácter para un generador de caracteres ROM que dispone de 240 caracteres posibles y 8 posiciones
(dobles) para caracteres definibles por el usuario en una memoria CGRAM (caracteres gráficos).

Sólo son visibles 1 ó 2 líneas con 16 caracteres por línea. La DDRAM almacena el código de los caracteres
que están siendo visualizados o que se encuentran en posiciones no visibles debido a la posición de la
ventana de visualización.

Tiene un tamaño de 2 líneas * 40 bytes/línea = 80 bytes.


Direcciones no contiguas entre las líneas 1 y 2.

0x00 a 0x27: 40 caracteres de la línea 1.


0x40 a 0x67: 40 caracteres de la línea 2.

Localización en display virtual (x,y).

x: posición horizontal (de 1 a 40).


y: línea (1 ó 2).

9
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

La manera más sencilla de utilizar el LCD es utilizando un driver específico para ello proporcionado por
el mismo compilador CCS: el fichero lcd.c que define las funciones indicadas a continuación.

lcd_init ();

Debe llamarse antes que ninguna otra función del fichero lcd.c.
Tal y como aparece en el fichero, además de borrar el display, configura el LCD para trabajar como
sigue:

a) En formato de 4 bits, con dos líneas y con caracteres de 5*7 puntos.


b) Con display encendido, cursor apagado y sin parpadeo.
c) Con autoincremento del puntero de direcciones y sin desplazamiento del display real.

lcd_gotoxy (x , y);
Establece la posición del LCD a la que se debe acceder.
Recuérdese que la primera posición de la primera línea tiene coordenadas (1 , 1), y que la primera
posición de la segunda línea es la (1 , 2).

lcd_putc (dato);
Escribe dato en la posición a la que apunta el puntero de direcciones.
La variable dato es de tipo char, y se definen algunos caracteres especiales:

\f Borra el display
\n Se posiciona en el inicio de la segunda línea
\b Retrocede una posición

También pueden usarse las secuencias de escape disponibles para la función printf:

\r Retorno de carro
\t Tabulador
\' Comilla simple
\" Comillas dobles
\\ Barra invertida
\? Símbolo de interrogación
\0 Caracter nulo
\% Símbolo Tanto por ciento

10
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

lcd_getc (x , y);
Devuelve el carácter que ocupa la posición (x , y) del LCD.

Por defecto, este driver usa siete bits del puerto B para establecer la comunicación entre el LCD y el
microcontrolador.

B0 Enable B4 Bit de datos D4


B1 RS B5 Bit de datos D5
B2 R/W B6 Bit de datos D6
B3 - B7 Bit de datos D7

Para enviar caracteres al LCD se utiliza la función PRINTF según la siguiente sintaxis:

Printf (lcd_putc, cadena de caracteres, variables);

Cadena: Cadena de caracteres que puede formarse usando el contenido de una o más variables.
Variables: Variables incluidas en la cadena (separadas por comas).

Para indicar la posición y el tipo de las variables a incluir en la cadena, se usa el formato %wt, donde w
es opcional.

w: 1-9 Indica el número de caracteres a mostrar


(Opcional) 01-09 Indica el número de ceros a la izquierda
1.1-9.9 Indica cuántos decimales se han de mostrar
t: c Carácter e Flotante (formato exp)
s Cadena o carácter f Flotante
u Entero sin signo lu Entero largo sin signo
x ó X Entero hexadecimal lx ó lX Entero largo hexadecimal
d Entero con signo ld Entero largo con signo
% Simplemente un ‘%’

Algunos ejemplos:

printf(lcd_putc , ”Hola”);
printf(lcd_putc , ”Tecla %c pulsada %u veces” , key , cont );

Ejercicio:
Después de conocer un poco sobre el LCD, ahora vamos a desarrollar el siguiente ejercicio:
Displayar los mensajes anterios en el LCD. Para esto antes haremos los cambios necesarios en el PROTEUS.
Después de hacer los cambios, la pantalla debe quedar como sigue:

11
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Haremos los siguientes cambios en el programa:

#include <16F628A.h>
#use delay(clock=4000000)
//#use rs232 (baud=9600, parity=N, xmit=PIN_B2, rcv=PIN_B1)

#define use_portb_lcd TRUE //definir portb lcd


#include <lcd.c> //libreria manejo lcd

short a=1;
int entero=255;
long largo=65535;
float flotante=3225.76;
char caracter='A';

void main()
{
lcd_init(); //inicializa lcd

printf(lcd_putc,"Hola Mundo, mi primer programa para PICS en Lenguaje C\r");


printf(lcd_putc,"variable short = %d\r", a);
printf(lcd_putc,"variable int = %u\r", entero);
printf(lcd_putc,"variable long = %lu\r", largo);
printf(lcd_putc,"variable float = %f\r", flotante);
printf(lcd_putc,"variable char = %c\r", caracter);
}

5. MANEJO DE DATOS A NIVEL DE BITS Y BYTES. CAPTURA Y CONTROL DE DATOS

El compilador de CCS incorpora una serie de funciones integradas orientadas a trabajar con los puertos E/S.

output_low (pin*); Pone a 0 el pin especificado.


output_high (pin*); Pone a 1 el pin especificado.
output_bit (pin* , valor); Pone el pin especificado al valor indicado.
output_float (pin*); Define el pin como entrada, quedando a tensión flotante (simula salida en
drenador abierto)
output_a (valor); Saca el valor indicado (0-255) en el
output_b (valor); puerto correspondiente.
port_b_pullups (valor); Activa (valor=TRUE) o no (valor=FALSE) las resistencias de pull-up asociadas a
los pines definidos como entrada en PORTB.

set_tris_a (valor); Carga el registro de dirección de datos


set_tris_b (valor); con el valor indicado.

input (pin*); Devuelve el estado del pin señalado.


input_a ( ); Devuelve el valor presente en el puerto
input_b ( ); correspondiente.

Los parámetros de tipo pin* se corresponden con identificadores definidos en el 16F84a.h cuyo formato es
PIN_Xn (X es el puerto y n es el número de pin).

Ejercicio:
Cree una nueva carpeta con el nombre ENVIO DE DATOS. Dentro del mismo simule el siguiente programa para
ver el uso de envio de datos a nivel de bits y bytes:

12
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Escribir el siguiente programa:

#include <16f877a.h> //pic a utilizar


#use delay (clock=4000000)

//PROGRAMA PRINCIPAL:

void main(void)
{
output_b(0b10101010);
delay_ms(1000);
output_b(0b01010101);
delay_ms(1000);
}

6. OPERADORES LOGICOS Y OPERADORES MATEMATICOS

El lenguaje C define numerosos operadores mediante los cuales se construyen las expresiones
(combinación de operadores y operandos).

Operadores aritméticos
+ - * / % (resto de división de enteros)

Operadores incremento y decremento


x++ ó ++x x-- ó –x

Operadores relacionales
> >= < <= == !=

Operadores lógicos

&& || ! (Usados en los condicionales)

Operadores a nivel de bits


& | ^ ~ >> <<

AND OR XOR Comp1 Dcha Izda


a&b a|b a^b ~a a >> n a << n

13
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

En lenguaje C “profesional” es muy frecuentes usar abreviaturas.


Así, por ejemplo, es más habitual ver a += b; que a = a + b;

7. SENTENCIAS REPETITIVAS

Son aquellas que ejecutan un bloque de sentencias mientras se cumpla una expresión lógica. Este bloque
de sentencias que se ejecuta repetidas veces, se denomina bucle, y cada ejecución se denomina iteración.

a. Sentencia WHILE

La sentencia while permite la ejecución de un bloque de sentencias si se evalúa como verdadera una
expresión lógica. La expresión lógica aparece al principio del bloque de sentencias.

En la figura de abajo se muestra el Pseudocódigo, el diagrama de flujo y la sintaxis de la sentencia while.

El Pseudocódigo es una forma informal de representar la secuencia del programa, sin tener en cuenta
la sintaxis particular del lenguaje en que vayamos a programar y el diagrama de flujo es una
representación gráfica del Pseudocódigo.

Cuando vayamos a crear un programa el dibujar previamente un diagrama de flujo ó el Pseudocódigo


de la secuencia de nuestro programa puede ayudarnos en la tarea de programación, pero en ningún
caso es un paso obligatorio.
14
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

El bloque delimitado por las llaves puede reducirse a una sentencia, y en este caso se suprimen las llaves.
La expresión lógica debe estar delimitada por paréntesis. Cuando el programa llega a una sentencia while,
sigue los siguientes pasos.

• Evalúa la expresión.
• Si es falsa, continua la ejecución tras el bloque de sentencias.
• Si es verdadera entra en el bloque de sentencias asociado al while.
• Ejecuta dicho bloque de sentencias, evaluando de nuevo la expresión y actuando en consecuencia.

Si la primera evaluación resulta falsa, el bloque de sentencias no se ejecuta nunca.

b. Bucle for()

El bucle for permite indicar estos tres elementos en un solo lugar, al principio del bucle, facilitando así
la obtención de un código compacto, pero legible. Veamos cual es su sintaxis:

En un bucle for, el paréntesis que acompaña a la palabra reservada for generalmente contiene tres
expresiones: Expresión 1; inicializa la variable ó variables de control del bucle. Expresión 2; representa
la condición de continuación en el bucle. Expresión 3; modifica el valor de las variables de control en
cada iteración del bucle.

Los puntos y comas que separan cada expresión son obligatorios.

c. Bucle do-while()

A diferencia de los bucles for y while, que analizan la condición del bucle al principio del mismo, el
bucle do-while analiza la condición al final del bucle. Esto significa que el bucle do-while siempre se
ejecuta al menos una vez. La forma general del bucle do-while es la que se muestra en la figura de
abajo:
15
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

d. Sentencia IF

Vamos a empezar las sentencias condicionales, con la más simple de todas, la sentencia if. Si se evalúa
como cierta la expresión que hay entre paréntesis al principio de la sentencia if se ejecuta el bloque de
sentencias contenido entre las llaves y si se evalúa como falsa la condición, el programa se salta ese
bloque de instrucciones. En la figura de abajo tenéis la sintaxis de esta sentencia.

16
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Si sólo hay una sentencia se pueden suprimir las llaves, ejemplo:

if (x=1)

printf(“Sin llaves solo una sentencia asociada al if”);

e. Sentencia If…Else

Cuando el programa llega a una sentencia condicional del tipo If …Else, primero se evalúa una
expresión; si se cumple (es cierta) se ejecuta un bloque de sentencias y si es falsa se ejecuta otro
bloque.

En la figura de abajo se muestra la sintaxis de esta sentencia condicional.

d. Sentencia switch

La sentencia switch se compone de las siguientes palabras clave: switch, case, default y break. Lo que
hace está sentencia es comparar sucesivamente el valor de una expresión (dicha expresión tan solo puede
ser de tipo entero o de tipo carácter) con una lista de constantes enteras o de caracteres. Cuando la
expresión coincide con la constante, ejecuta las sentencias asociadas a ésta.

La estructura de la sentencia switch es la siguiente:

17
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

La sentencia break hace que el programa salte a la línea de código siguiente a la sentencia switch. Si se omite
se ejecutará el resto de casos case hasta encontrar el próximo break.

La sentencia default se ejecuta cuando no ha habido ninguna coincidencia. La parte default es opcional y, si no
aparece, no se lleva a cabo ninguna acción al fallar todas las pruebas y el programa seguirá a partir de la llave
que cierra la sentencia switch

Consideraciones a la hora de usar esta sentencia:

En una sentencia switch No puede haber dos sentencias case con el mismo valor de constante. Una
constante char se convierte automáticamente a sus valores enteros.

Switch difiere del if en que switch solo puede comprobar la igualdad mientras que if puede evaluar
expresiones relacionales o lógicas. Además cuando la comparación se basa en variables o se trabaja con
expresiones que devuelven float deberemos usar el if-else.

Hay que decir que la secuencia de sentencias en un case no es un bloque (no tiene porque ir entre llaves).
Por lo tanto no podríamos definir una variable local en él. Mientras que la estructura switch global sí que es
un bloque.

18
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

EJEMPLOS DE USO DE SENTENCIAS REPETITIVAS CON ENTRADAS Y SALIDAS DE DATOS:

EJEMPLO 1: Captura de Datos por el Puerto B y salida por el puerto A a través de Decodificador.
Objetivo del programa: El PIC simplemente captura los datos por el puerto B con el comando
input_b() y los envía por el puerto A con el comando output_a().

SIMULACION:

PROGRAMA:

#include <16f84a.h> //pic a utilizar


#use delay (clock=4000000) //Fosc=4Mhz
int numero;

//PROGRAMA
void main(void)
{
while(1)
{
numero = input_b();
output_a(numero);
}
}

EJERCICIO:
- Que la salida me muestre el doble del número ingresado.
- Que la salida me muestre la mitad del número ingresado.
- Que la salida me muestre el número ingresado mas 1.

EJEMPLO2: Temporizador simple


Objetivo del programa: El PIC generará un nivel alto en su salida por un tiempo determinado usando
el comando delay_ms() cada vez que una de sus entradas cambie de estado.

SIMULACION:

19
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

PROGRAMA:

#include <16f84a.h> //pic a utilizar


#use delay (clock=4000000) //Fosc=4Mhz

long tiempo=2500;

void main(void) //PROGRAMA


{
while(1)
{
if(!input(PIN_A0))
{
output_bit(PIN_B0,1);
delay_ms(tiempo);
output_bit(PIN_B0,0);
}
}
}

EJERCICIOS:
- Utilizar el comando output_high() y output_low() en lugar de output_bit()
- Que el temporizador se accione con flanco de subida (de 0 a 1)

EJEMPLO3: Manejo de un motor PAP Unipolar y Bipolar


Objetivo del programa: El PIC generará una secuencia de pulsos a su salida para hacer mover el motor
a una determinada velocidad.

SIMULACION:

U1 0
16 17
15
RA7/OSC1/CLKIN
RA6/OSC2/CLKOUT
RA0/AN0
RA1/AN1
18 0
1
4
RA5/MCLR
RA2/AN2/VREF
RA3/AN3/CMP1
2 0
3
RA4/T0CKI/CMP2
6
RB0/INT
7
RB1/RX/DT
8
RB2/TX/CK
9
RB3/CCP1
10 +88.8
RB4
11
RB5
12
RB6/T1OSO/T1CKI
13
RB7/T1OSI
PIC16F628A

PROGRAMA:
#include <16F628A.h>
#use delay(clock=4000000)

int retardo=10;

void main()
{
while(1)
{
while (input(PIN_A0))
{
output_b(0b00000001);
delay_ms(retardo);
output_b(0b00000010);
delay_ms(retardo);
output_b(0b00000100);
delay_ms(retardo);
output_b(0b00001000);
delay_ms(retardo);
}
20
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

while (input(PIN_A1))
{
output_b(0b00001000);
delay_ms(retardo);
output_b(0b00000100);
delay_ms(retardo);
output_b(0b00000010);
delay_ms(retardo);
output_b(0b00000001);
delay_ms(retardo);
}

}
}

EJERCICIOS:
- Cambiar el programa y la simulación para manejar un Motor PAP Bipolar

8. DISPLAY DE 7 SEGMENTOS
Los displays de 7 segmentos nos permiten mostrar información numérica y alfabética de forma muy eficaz,
con gran impacto visual y mucho más fácil de lo que puede parecer en un principio. Cada display de 7
segmentos está formado realmente por 8 leds, ya que además de cada una de las barritas que forman el
dígito numérico, hay un led adicional para el punto decimal. Cada segmento se suele nombrar con una
letra, según el siguiente diagrama:

En esta figura observamos que podemos encontrar dos configuraciones distintas de displays de 7
segmentos, que siendo idénticos externamente, son completamente distintos eléctricamente:
- Display de ánodo común: en este caso la parte común de los 8 leds es el ánodo, por lo que
habrá que alimentar el display de 7 segmentos con tensión positiva y encender cada segmento
tirando a masa su pin correspondiente.
- Display de cátodo común: en este caso la parte común de los 8 leds es el cátodo, por lo que
habrá que tirar a masa el punto común, y alimentar cada segmento con tensión por su pin
correspondiente.

EJEMPLO4: Visualizar la palabra “BETI”


Objetivo del programa: El PIC generará una secuencia de pulsos a su salida para hacer mover el motor a una
determinada velocidad.

SIMULACION:

21
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

PROGRAMA:
#include <16f84a.h> //pic a utilizar
#fuses XT,NOWDT,NOPROTECT,PUT //ordenes para el programador

void main(void)
{
int i; //contador de visualizacion BETI

do{ //bucle...
for(i=0;i<15;i++)
{ //bucle visualizacion beti
output_a(0b00001110);
output_b(0b01111100); //1º 7seg on B
delay_ms(10);
output_a(0b00001101);
output_b(0b01111001); //2º 7seg on E
delay_ms(10);
output_a(0b00001011);
output_b(0b01111000); //3º 7seg on T
delay_ms(10);
output_a(0b00000111);
output_b(0b00110000); //4º 7seg on I
delay_ms(10);
}

output_b(0b00000000); //todo...
output_a(0b0000);
delay_ms(500); //...apagado durante 0,5s
}while(TRUE); //...infinito
}

EJERCICIOS:
- Cambiar el texto por “HOLA”
- Intercalar los ambos textos alternadamente.

22
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

9. Funciones

Las funciones son los bloques constructivos fundamentales en C. Todas las sentencias deben encontrarse
dentro de funciones. Las funciones deben ser definidas antes de ser utilizadas.

tipo_dato nombre_func (tipo param1, tipo param2,…)


{
Cuerpo de la función (sentencias);
}

Las funciones pueden devolver un valor a la sentencia que las llama.

El tipo de dato devuelto se indica mediante tipo_dato. Si no se indica nada, se entiende que devuelve un
entero. Si no devuelve nada, debe incluirse una especificación tipo void.

La manera que tiene una función para devolver un valor es mediante la sentencia return.

return (expresión); return expresión;

La expresión debe proporcionar el mismo tipo de dato que el especificado en la función. Si no debe devolver
nada, se finaliza con return;

Cuando una función se encuentra con una sentencia return se vuelve a la rutina de llamada inmediatamente y
las sentencias posteriores a return no se ejecutan. Además de con las sentencia return, las funciones terminan
su ejecución y vuelven al lugar desde donde se les llamó cuando alcanzan la llave de cierre de función} tras
ejecutar la última sentencia de la misma.

Además de devolver valores, una función también puede recibir parámetros (denominados argumentos) según
se indicó en su definición.

Por ejemplo:

Los argumentos se pueden pasar a las funciones por valor o por referencia.

La llamada por valor copia el argumento de llamada en el parámetro formal de la función. No modifica su valor
en la función de partida. La llamada por referencia usa la dirección de la variable que se pasa a la función. Se
consigue usando punteros o arrays.
23
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

EJEMPLO 5: Usando una función simple de suma.


Objetivo del programa: Se trata de construir una función para sumar dos elementos y visualizarlos en uno o
displays.

SIMULACION:

PROGRAMA:

#include <16f84a.h> //pic a utilizar


#use delay (clock=4000000) //Fosc=4Mhz

int suma(int a,int b) //FUNCIONES


{
return(a+b);
}

void main(void) //PROGRAMA PRINCIPAL


{
int c;
c = suma(1,5);
output_b(c);
}

EJERCICIOS:
- Crear una función para hallar el volumen de un cilindro
- Mostrar la salida en una pantalla LCD de 2x16 lineas

EJEMPLO6: Contador con Display hasta 99


Objetivo del programa: El PIC generará una secuencia de conteo cada vez que se presione un pulsador en una
de sus entradas.

SIMULACION:

24
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

PROGRAMA:
#include <16f84a.h> //pic a utilizar
#use delay (clock=4000000) //Fosc=4Mhz

int tabBCD[10]={0b0000,0b0001,0b0010,0b0011,0b0100,0b0101,0b0110,0b0111,0b1000,0b1001};
int conta,delay=5;
int h_digit,m_digit,l_digit;
int a,b;

void vizu(void); //FUNCIONES


void int2bcd(int valor);

void main(void)
{
conta=0;
while(1)
{
if(!input(PIN_A0))
{
++conta;
int2bcd(conta);
a=m_digit;
b=l_digit;
while(!input(PIN_A0))
{
vizu();
}
}
vizu();
}
}

void vizu(void)
{
output_b(tabBCD[a]| 0b11100000);
delay_ms(delay);
output_b(tabBCD[b]| 0b11010000);
delay_ms(delay);
}

void int2bcd(int valor) // Funcion que convierte de Entero a 3 x BCD


{
h_digit = (int) valor / 100; // 1er Dígito o Centenas
valor - = h_digit * 100; // y se lo resto al valor
m_digit = (int) valor / 10; // 2do Dígito o Decenas
valor - = m_digit * 10; // y también se lo resto
l_digit = valor; // y por último solo me quedan las unidades
}

EJERCICIOS:
- Cambiar para que cuente de 3 en 3
- Situar las funciones secundarias antes que la función principal

10. USO DE UN TECLADO COMO ENTRADA DE DATOS

Muy utilizado para introducir información al microcontrolador. Los hay de varios tipos: de lámina flexible, de
efecto Hall, de efecto inductivo, de efecto capacitivo. Los más comunes son los de lámina flexible.

El problema de los rebotes. Debido al efecto muelle del pulsador, se producen oscilaciones en la señal tanto al
pulsar como al soltar la tecla.

25
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Teclados lineales
Muy sencillos, pero no permiten disponer de muchas teclas. De este modo, cuando el microcontrolador
detecte un “0” al final de la línea, se sabrá que se ha pulsado una tecla y, además, se sabrá cuál ha sido. Basta
con que el programa compruebe periódicamente el estado de las entradas a las que se ha conectado el
teclado.

Teclados matriciales
Varias teclas controladas con un número reducido de puertos E/S. La pulsación de una tecla se pone de
manifiesto en las entradas del microcontrolador conectadas al teclado.

En este ejemplo, se sabe que se ha pulsado una tecla de la tercera columna, pero no se sabe cuál. Se necesita
desarrollar algoritmos que permitan determinar cuál es la tecla que se ha pulsada.

26
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Conexión de teclados matriciales en los PIC.

El puerto B de los microcontroladores PIC está especialmente pensado para conectar un teclado matricial de
4x4 teclas.

La posibilidad de habilitar resistencias de pull-up reduce el número de componentes externos. La existencia de


una interrupción asociada a cambios en los bits RB<4:7> avisa de que se ha pulsado una tecla.

EJEMPLO 7: USO BASICO DE UN TECLADO DE 4X3


Objetivo del Programa: Cada vez que se presione una tecla, el display mostrará dicho número

SIMULACION:
+5v

U2
7 13
A QA
1 12
B QB
2 11
C QC
6 10
D QD
9
QE
3 15
LT QF
4 14
BI QG
5
LE/STB
4511

U1
16 17
OSC1/CLKIN RA0
15 18
OSC2/CLKOUT RA1
1
RA2
2
MCLR RA3
3
RA4/T0CKI

RB0/INT
6 R1 R2 R3 R4
7 220 220 220 220
RB1
8
RB2
9
RB3
10
RB4
11
RB5
12
RB6
RB7
13 D1 D2 D3 D4
LED-YELLOW
LED-YELLOW
LED-YELLOW
LED-YELLOW
PIC16F84A
1

A 1 2 3
B 4 5 6
C 7 8 9
D 0 #

PROGRAMA:

27
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

#include <16f84a.h> //pic a utilizar


#fuses XT,NOWDT,NOPROTECT,PUT //ordenes para el programador
#use delay (clock=4000000) //Fosc=4Mhz
#use fast_io(B)

char codigo; //VARIABLES

char explorar_teclado(); //DECLARACION DE LA FUNCION

void main(void) // PROGRAMA PRINCIPAL


{
set_tris_b(0b11110000);
output_b(0);
output_a(0);
port_b_pullups (true);
while(true) // bucle de trabajo
{
codigo=explorar_teclado(); // explora si se presiona pulsador en teclado
output_a(codigo); // y lo muestra por el puerto A
}
}
/******************************************************************************/
char explorar_teclado() // función que explora todo el teclado
{
output_b(0b11111110); // verifica columna 1
if(input(PIN_B4)==0)
return 1;
if(input(PIN_B5)==0)
return 2;
if(input(PIN_B6)==0)
return 3;
if(input(PIN_B7)==0)
return 12;

output_b(0b11111101); // verifica columna 2


if(input(PIN_B4)==0)
return 4;
if(input(PIN_B5)==0)
return 5;
if(input(PIN_B6)==0)
return 6;
if(input(PIN_B7)==0)
return 13;

output_b(0b11111011); // verifica columna 3


if(input(PIN_B4)==0)
return 7;
if(input(PIN_B5)==0)
return 8;
if(input(PIN_B6)==0)
return 9;
if(input(PIN_B7)==0)
return 14;

output_b(0b11110111); // verifica columna 4


if(input(PIN_B4)==0)
return 10;
if(input(PIN_B5)==0)
return 0;
if(input(PIN_B6)==0)
return 11;
if(input(PIN_B7)==0)
return 15;

28
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

EJEMPLO 8: USO DE UN TECLADO Y EL LCD USANDO LIBRERIAS


Objetivo del Programa: Mostrar en el LCD los números digitados.

SIMULACION:
LCD1
LM016L

VDD
VSS

VEE

RW
RS

D0
D1
D2
D3
D4
D5
D6
D7
E
1
2
3

4
5
6

7
8
9
10
11
12
13
14
U1
30
RD7/PSP7
29
RD6/PSP6
28
RD5/PSP5
27
RD4/PSP4
22
RD3/PSP3
21
RD2/PSP2
20
RD1/PSP1
19
RD0/PSP0
26
RC7/RX/DT
25
RC6/TX/CK
1 24
MCLR/Vpp/THV RC5/SDO
23
RC4/SDI/SDA
10 18
RE2/AN7/CS RC3/SCK/SCL
9 17
RE1/AN6/WR RC2/CCP1
8 16
RE0/AN5/RD RC1/T1OSI/CCP2
15
RC0/T1OSO/T1CKI
7
RA5/AN4/SS/C2OUT
6 40

3
RA4/T0CKI/C1OUT RB7/PGD
5 39
RA3/AN3/VREF+ RB6/PGC
4
3
RA2/AN2/VREF-/CVREF
RA1/AN1
RB5
RB4
38
37
A 1 2 3
2 36
RA0/AN0 RB3/PGM
35
RB2
14
13
OSC2/CLKOUT
OSC1/CLKIN
RB1
RB0/INT
34
33
B 4 5 6
PIC16F877A
C 7 8 9
D 0 #

PROGRAMA:
#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#define use_portb_kbd TRUE

#include <lcd.c>
#include <kbd.c>

void main() {
char k;

lcd_init();
kbd_init();
port_b_pullups(TRUE);

lcd_putc("\fListo...\n");

while (TRUE)
{
k=kbd_getc();
if(k!=0)
if(k=='*')
lcd_putc('\f');
else
lcd_putc(k);
}
}

29
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

11. USO DEL TEMPORIZADOR DEL PIC (TIMER )

Características generales del Temporizador TMR0.


Contador / Temporizador de 8 bits que se pueden leer y escribir. Prescaler de 8 bits programable por software.
Generación de interrupción al desbordarse de FFh a 00h. Se puede seleccionar el flanco activo si se usa reloj
externo.

Temporizador TMR0 / WDT


Registro OPTION_REG (81h)

bit 7 RBPU
bit 6 INTEDG
bit 5 T0CS: Selección del reloj a utilizar

0: Reloj interno (fCLK/4) 1: Reloj externo (RA4)

bit 4 T0SE: Selección del flanco activo del reloj externo

0: Flanco de subida 1: Flanco de bajada


bit 3 PSA: Asignación del prescaler

0: Asignado a TMR0 1: Asignado a WDT

bits 2:0 PS2:PS0: Prescaler

000: 1:2 para TMR0 / 1:1 para WDT.


001: 1:4 para TMR0/ 1:2 para WDT.
010: 1:8 para TMR0 / 1:4 para WDT.
011: 1:16 para TMR0 / 1:8 para WDT.
100: 1:32 para TMR0 / 1:16 para WDT.
101: 1:64 para TMR0 / 1:32 para WDT.
110: 1:128 para TMR0 / 1:64 para WDT.
111: 1:256 para TMR0 / 1:128 para WDT.

30
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

TMR0 / WDT en el compilador C de CCS

Configuración del módulo TMR0.

setup_timer_0 (modo);

modo:
RTCC_INTERNAL (OPTION_REG  00h)
RTCC_EXT_L_TO_H (OPTION_REG  20h)
RTCC_EXT_H_TO_L (OPTION_REG  30h)
RTCC_DIV_2 (OPTION_REG  00h)
RTCC_DIV_4 (OPTION_REG  01h)
RTCC_DIV_8 (OPTION_REG  02h)
RTCC_DIV_16 (OPTION_REG  03h)
RTCC_DIV_32 (OPTION_REG  04h)
RTCC_DIV_64 (OPTION_REG  05h)
RTCC_DIV_128 (OPTION_REG  06h)
RTCC_DIV_256 (OPTION_REG  07h)
Se pueden agrupar constantes de distintos grupos con |.

Configuración del módulo WDT.

setup_wdt (modo);

modo:
WDT_18MS (OPTION_REG  08h)
WDT_36MS (OPTION_REG  09h)
WDT_72MS (OPTION_REG  0Ah)
WDT_144MS (OPTION_REG  0Bh)
WDT_288MS (OPTION_REG  0Ch)
WDT_576MS (OPTION_REG  0Dh)
WDT_1152MS (OPTION_REG  0Eh)
WDT_2304MS (OPTION_REG  0Fh)

Para que el temporizador watchdog pueda llevar a cabo su misión es


necesario indicarlo así con la directiva #fuses.

#fuses [opciones], WDT [opciones] Watchdog activado


#fuses [opciones], NOWDT [opciones] Watchdog desactivado

Configuración de los módulos TMR0 y WDT (obsoleto).

Funciones implementadas en el compilador por compatibilidad con versiones anteriores. No se recomienda su


uso.
setup_counters (rtcc , prescaler);

rtcc:

RTCC_INTERNAL (OPTION_REG  00h)


RTCC_EXT_L_TO_H (OPTION_REG  20h)
RTCC_EXT_H_TO_L (OPTION_REG  30h)

prescaler:

31
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

RTCC_DIV_2 (OPTION_REG  00h)


... ...
RTCC_DIV_256 (OPTION_REG  07h)
WDT_18MS (OPTION_REG  08h)
WDT_36MS (OPTION_REG  09h)
WDT_72MS (OPTION_REG  0Ah)
WDT_144MS (OPTION_REG  0Bh)
WDT_288MS (OPTION_REG  0Ch)
WDT_576MS (OPTION_REG  0Dh)
WDT_1152MS (OPTION_REG  0Eh)
WDT_2304MS (OPTION_REG  0Fh)

Escritura en el módulo TMR0.

set_timer0 (valor);
Valor: Entero de 8 bits. (TMR0  valor)

Lectura del módulo TMR0.

Valor = get_timer0 ();


Valor: Entero de 8 bits. (valor  TMR0)

Puesta a cero del Watchdog.

restart_wdt ();
No precisa ningún parámetro. (Equivale a CLRWDT)

Ejercicio10_ejemplo1:

Reloj con el timer0:

//******************************************************************************
#include <16f84a.h> //pic a utilizar
#fuses XT,NOWDT,NOPROTECT,PUT //ordenes para el programador
#use delay (clock=4000000) //Fosc=4Mhz
#use standard_io(B)
#use standard_io(A)
//******************************************************************************
//Variables
//******************************************************************************
int tabBCD[10]={0b0000,0b0001,0b0010,0b0011,0b0100,0b0101,0b0110,0b0111,0b1000,0b1001};
int a,b,c,d;
int min,seg;
32
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

int h_digit,m_digit,l_digit;
int delay=5,conta;
//******************************************************************************
//Funciones
//******************************************************************************
void vizu(void);
void int2bcd(int valor);
//******************************************************************************
//LLAMADA FUNCION INTERRUPCION
//******************************************************************************
#INT_TIMER0
void interrupcion()
{
++conta;
if(conta==250)
{
conta=0;
++seg;
if(seg==60)
{
++min;
seg=0;
if(min==60)
{
min=0;
}
}
}

set_timer0(6); //reset TMR0


}
//******************************************************************************
///PROGRAMA
//******************************************************************************
void main(void)
{
setup_counters(RTCC_INTERNAL,RTCC_DIV_16); //configuracion interrupcion TMR0
set_timer0(6); //carga TMR0
disable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL); //activadas interrupciones
a=0,b=0,c=0,d=0;
while(1)
{
int2bcd(min);
a=m_digit;
b=l_digit;
int2bcd(seg);
c=m_digit;
d=l_digit;
vizu();
if(!input(PIN_A0))
{
enable_interrupts(INT_TIMER0);
}
else
{
disable_interrupts(INT_TIMER0);
}
}
}
/******************************************************************************/
void vizu(void)
{
output_b(tabBCD[a]| 0b11100000);
delay_ms(delay);
output_b(tabBCD[b]| 0b11010000);
delay_ms(delay);
output_b(tabBCD[c]| 0b10110000);
delay_ms(delay);
output_b(tabBCD[d]| 0b01110000);
delay_ms(delay);
33
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

}
/******************************************************************************/
/************************************************/
// Funcion que convierte de Entero a 3 x BCD
/************************************************/
void int2bcd(int valor)
{
h_digit = (int) valor / 100; // 1er Dígito o Centenas
valor -= h_digit * 100; // y se lo resto al valor
m_digit = (int) valor / 10; // 2do Dígito o Decenas
valor -= m_digit * 10; // y también se lo resto
l_digit = valor; // y por último solo me quedan las unidades
}
/******************************************************************************/

Ejercicio10_ejemplo2:

Contador con el Timer0:

//******************************************************************************
#include <16f84a.h> //pic a utilizar
#fuses XT,NOWDT,NOPROTECT,PUT //ordenes para el programador
#use delay (clock=4000000) //Fosc=4Mhz
#use standard_io(A)
#use standard_io(B)
//******************************************************************************
//Variables
//******************************************************************************
int tabBCD[10]={0b0000,0b0001,0b0010,0b0011,0b0100,0b0101,0b0110,0b0111,0b1000,0b1001};
int a,b,c,d;
int h_digit,m_digit,l_digit;
int delay=5,conta;
//******************************************************************************
//Funciones
//******************************************************************************
void vizu(void);
void int2bcd(int valor);
//******************************************************************************
///PROGRAMA
//******************************************************************************
void main(void)
{
setup_timer_0 (RTCC_EXT_H_TO_L );//configuracion interrupcion TMR0
setup_wdt (WDT_36MS );
set_timer0(0); //carga TMR0
disable_interrupts(INT_TIMER0);
disable_interrupts(GLOBAL); //activadas interrupciones
a=0,b=0,c=0,d=0;
while(1)
{
conta= get_timer0 ();
int2bcd(conta);
a=m_digit;
b=l_digit;

34
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

vizu();
}
}
/******************************************************************************/
void vizu(void)
{
output_b(tabBCD[a]| 0b11100000);
delay_ms(delay);
output_b(tabBCD[b]| 0b11010000);
delay_ms(delay);
output_b(tabBCD[c]| 0b10110000);
delay_ms(delay);
output_b(tabBCD[d]| 0b01110000);
delay_ms(delay);
}
/******************************************************************************/
/************************************************/
// Funcion que convierte de Entero a 3 x BCD
/************************************************/
void int2bcd(int valor)
{
h_digit = (int) valor / 100; // 1er Dígito o Centenas
valor -= h_digit * 100; // y se lo resto al valor
m_digit = (int) valor / 10; // 2do Dígito o Decenas
valor -= m_digit * 10; // y también se lo resto
l_digit = valor; // y por último solo me quedan las unidades
}
/******************************************************************************/

12. INTERRUPCIONES

En los 16F84a hay 14 fuentes posibles de interrupción.

En ese caso, el hardware interno del PIC ejecuta varias acciones.


1. Se pone GEIE a cero para no aceptar otra interrupción.
2. Se almacena la dirección de retorno en la pila.
3. El contador de programa se carga con la dirección 0x0004 (que es
la dirección común para todas las interrupci ones).

Cuando se da un evento en un determinado módulo, el flag asociado se pone a 1 y, si las máscaras global (GIE)
están habilitadas, se acepta la interrupción.
El programador debe asegurarse de que el código se encarga de identificar la fuente de la interrupción,
guardar y recuperar el contexto existente antes de producirse la interrupción y poner a cero el flag asociado a
la misma para permitir posteriores identificaciones.

Estas tareas quedan enormemente simplificadas usando directivas y funciones del lenguaje C del compilador
de CCS.

Las directivas #INT_xxxx

Indican que la función que aparece a continuación corresponde al


tratamiento de una interrupción (no tiene ni necesita parámetros).
En el caso de los PIC 16F84a hay 4 posibles directivas.

#INT_RTCC Desbordamiento de TMR0. (T0IF)


#INT_RB Cambio en los pines RB<4:7>. (RBIF)
#INT_EXT Flanco en pin RB0. (INTF)
#INT_EEPROM Escritura completa en EEPROM de datos. (EEIF)

La directiva #INT_DEFAULT

35
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Indica que la función que viene a continuación será llamada si se dispara una interrupción y ninguno de los
flags está activo.

La directiva #INT_GLOBAL

Indica que la función que va a continuación sustituye todas las acciones que inserta el compilador al aceptarse
una interrupción. Sólo se ejecuta lo que vaya en dicha función.

Ventajas de usar las directivas de interrupciones

El compilador genera el código necesario para saltar a la función que va tras esta directiva en el momento de
la interrupción.
Indica que la función que viene a continuación será llamada si se dispara una interrupción y ninguno de los
flags está activo.
También genera código para salvar al principio y restituir al final el contexto, y borrará el flag que se activó con
la interrupción.
El programador debe seguir encargándose de habilitar las interrupciones.

Funciones para gestión de interrupciones

El compilador C de CCS incluye algunas funciones integradas destinadas a manejar interrupciones.

enable_interrupts (nivel);

nivel es una constante definida en 16F84a.h y genera el código necesario para activar las máscaras necesarias.
Etiquetas de nivel definidas para el 16F84a:
GLOBAL
INT_RTCC
INT_RB
INT_EXT
INT_EEPROM

La mascara global (la que hace GIE=1) debe activarse de manera independiente. Las otras sólo activan la
máscara particular y el PEIE si es necesario.

disable_interrupts (nivel);

Hace la acción contraria a la función anterior, poniendo a 0 las máscaras relacionadas con la interrupción
indicada.
Existe también una función adicional destinada a configurar el flanco activo que genera la interrupción
externa (en RB0).

ext_int_edge (H_TO_L);

Selecciona flanco de bajada para activar el flag INTF.

ext_int_edge (L_TO_H);
Selecciona flanco de subida para activar el flag INTF.

#INT_EXT
ext_isr() {
......}

enable_interrupts (INT_EXT); // Activa máscara INTE


36
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

ext_int_edge (H_TO_L); // Flag INTF si flanco de bajada.


enable_interrupts (GLOBAL); // Habilita máscara global de int.

/* Si entra una interrupción por flanco de bajada en RB0, se irá a la función que aparece tras la directiva
#INT_EXT */

disable_interrupts (INT_EXT); // Desactiva interrupciones en RB0.


disable_interrupts (GLOBAL); // Desactiva todas las interrupciones.

Ejercicio11_ejemplo1:

Interrupción RB0:

//******************************************************************************
#include <16f84a.h> //pic a utilizar
#fuses XT,NOWDT,NOPROTECT,PUT //ordenes para el programador
#use delay (clock=4000000) //Fosc=4Mhz
#use standard_io(a)
#use standard_io(b)
//******************************************************************************
//VARIABLES GLOBALES
//******************************************************************************
int i=0; //contador para tabla BCD
int
tabBCD[10]={0b0000,0b0001,0b0010,0b0011,0b0100,0b0101,0b0110,0b0111,0b1000,0b1001};//BCD 0-
9
//******************************************************************************
//LLAMADA FUNCION INTERRUPCION
//******************************************************************************
#INT_EXT
void IntRB0()
{
i++; //incremento contador indice tabBCD
if(i>9) //¿se ha mostrado digito 9?
i=0; //SI -> restaura valor indice(para mostrar digito 0)
output_a(tabBCD[ i ]); //muestra por porta digito 7 segmentos
}
//******************************************************************************
//PROGRAMA
//******************************************************************************
void main(void)
{
enable_interrupts(int_ext); //activar interrupcion externa
ext_int_edge(L_TO_H); //configuracion:interrupcion cuando señal esta en alta
enable_interrupts(GLOBAL); //todas las interrupciones desactivadas

while(1){}
}
//*******************************************************************************

37
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Ejercicio11_ejemplo2:

Interrupción RBI:

//******************************************************************************
#include <16f84a.h> //pic a utilizar
#fuses XT,NOWDT,NOPROTECT,PUT //ordenes para el programador
#use delay (clock=4000000) //Fosc=4Mhz
#use standard_io(a)
#use standard_io(b)
//******************************************************************************
//VARIABLES
//******************************************************************************
int i=0; //contador para tabla BCD
int
tabBCD[10]={0b0000,0b0001,0b0010,0b0011,0b0100,0b0101,0b0110,0b0111,0b1000,0b1001};//BCD 0-
9
//******************************************************************************
//LLAMADA FUNCION INTERRUPCION
//******************************************************************************
#INT_RB
void IntPortB4_7( )
{
if(input(PIN_B7))
{
i++; //incremento contador indice tabBCD
if(i>9) //¿se ha mostrado digito 9?
i=0; //SI -> restaura valor indice(para mostrar digito 0)
output_a(tabBCD[ i ]); //muestra por porta digito 7 segmentos
}
/*if(!input(PIN_B7))
{
i++; //incremento contador indice tabBCD
if(i>9) //¿se ha mostrado digito 9?
i=0; //SI -> restaura valor indice(para mostrar digito 0)
output_a(tabBCD[ i ]); //muestra por porta digito 7 segmentos
}*/
}
//******************************************************************************
//PROGRAMA
//******************************************************************************
void main(void)
{
enable_interrupts(INT_RB); //activar interrupcion rb4:7
enable_interrupts(GLOBAL); //activar interrupciones

while(1){}
}
/******************************************************************************/

38
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

13. PUERTO SERIAL(RS-232)

Una manera de conectara dos dipositivos es mediante comunicaciones serie asíncronas. En ellas los bits de
datos se transmiten "en serie" (uno de trás de otro) y cada dispositivo realiza tiene su propio reloj.
Previamente se ha acordado que ambos dispositivos transmitirán datos a la misma velocidad.

En este cuaderno técnico se muestran los fundamentos de estas comunicaciones, los pines empleados y
ejemplos de circuitos para conectar el PC con un microcontrolador, además de mostrar los cables que se
pueden emplear.

Comunicaciones serie asíncronas

Los datos serie se encuentran encapsulados en tramas de la forma:

Primero se envía un bit de start, a continuación los bits de datos (primero el bit de mayor peso) y finalmente
los bits de STOP.

El número de bits de datos y de bits de Stop es uno de los parámetros configurables, así como el criterio de
paridad par o impar para la detección de errores. Normalmente, las comunicaciones serie tienen los
siguientes parámetros: 1 bit de Start, 8 bits de Datos, 1 bit de Stop y sin paridad.

En esta figura se puede ver un ejemplo de la transmisión del dato binario 10011010. La línea en reposo está a
nivel alto:

Norma RS232

La Norma RS-232 fue definida para conectar un ordenador a un modem. Además de transmitirse los datos de
una forma serie asíncrona son necesarias una serie de señales adicionales, que se definen en la norma. Las
tensiones empleadas están comprendidas entre +15/-15 voltios.

Conexión de un microcontrolador al puerto serie del PC

Para conectar el PC a un microcontrolador por el puerto serie se utilizan las señales Tx, Rx y GND. El PC utiliza
la norma RS232, por lo que los niveles de tensión de los pines entán comprendidos entre +15 y -15 voltios. Los
microcontroladores normalmente trabajan con niveles TTL (0-5v). Es necesario por tanto intercalar un circuito
que adapte los niveles:

39
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Uno de estos circuitos, que se utiliza mucho, es el MAX232.

El conector DB9 del PC

En los PCs hay conectores DB9 macho, de 9 pines, por el que se conectan los dispositivos al puerto serie. Los
conectores hembra que se enchufan tienen una colocación de pines diferente, de manera que se conectan el
pin 1 del macho con el pin 1 del hembra, el pin2 con el 2, etc...

La información asociada a cada uno de los pines es la siguiente:

Número de pin Señal


1 DCD (Data Carrier Detect)
2 RX
3 TX
4 DTR (Data Terminal Ready)
5 GND
6 DSR (Data Sheet Ready)
7 RTS (Request To Send)
8 CTS (Clear To Send)
9 RI (Ring Indicator)

El chip MAX 232

Este chip permite adaptar los niveles RS232 y TTL, permitendo conectar un PC con un microcontrolador. Sólo
es necesario este chip y 4 condensadores electrolíticos de 22 micro-faradios. El esquema es el siguiente:

40
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Ejercicio12_ejemplo1:

Transmisión:

/******************************************************************************/
#include <16f84a.h> //pic a utilizar
#fuses XT,NOWDT,NOPROTECT,PUT //ordenes para el programador
#use delay (clock=4000000) //Fosc=4Mhz
#use rs232(baud=9600, xmit=PIN_A0, rcv=PIN_A1, bits=8)
#use standard_io(A)
#use fast_io(B)
//******************************************************************************
//VARIABLES
//******************************************************************************
char codigo;
//******************************************************************************
//FUNCIONES
//******************************************************************************
char explorar_teclado();
//******************************************************************************
///PROGRAMA
//******************************************************************************
41
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

void main(void)
{
set_tris_b(0xf0);
output_b(0);
output_a(0);
codigo=0;
port_b_pullups (true);
printf("TECLADO: "); //mensaje por v.terminal
while(true) // bucle de trabajo
{
codigo=explorar_teclado(); // explora si se presiona pulsador en teclado y lo muestra
en el puerto A
if(codigo != 15)
{
printf("\b" ); //retrocede una posicion(borra ultima tecla)
printf("%c",codigo); //mensaje por v.terminal
}
}
}
/******************************************************************************/
char explorar_teclado() // función que explora todo el teclado
{
output_b(0xfe); // verifica columna 1
if(input(PIN_B4)==0)
return '1';
if(input(PIN_B5)==0)
return '2';
if(input(PIN_B6)==0)
return '3';
if(input(PIN_B7)==0)
return 'C';

output_b(0xfd); // verifica columna 2


if(input(PIN_B4)==0)
return '4';
if(input(PIN_B5)==0)
return '5';
if(input(PIN_B6)==0)
return '6';
if(input(PIN_B7)==0)
return 'D';

output_b(0xfb); // verifica columna 3


if(input(PIN_B4)==0)
return '7';
if(input(PIN_B5)==0)
return '8';
if(input(PIN_B6)==0)
return '9';
if(input(PIN_B7)==0)
return 'E';

output_b(0xf7); // verifica columna 4


if(input(PIN_B4)==0)
return 'A';
if(input(PIN_B5)==0)
return '0';
if(input(PIN_B6)==0)
return 'B';
if(input(PIN_B7)==0)
return 'F';

if(input_b()==0xf7)
return 15;
}
/******************************************************************************/

42
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Ejercicio12_ejemplo2:

Recepcion:

/******************************************************************************/
#include <16f84a.h> //pic a utilizar
#fuses XT,NOWDT,NOPROTECT,PUT //ordenes para el programador
#use delay (clock=4000000) //Fosc=4Mhz
#define use_portb_lcd TRUE //definir portb lcd
#include <lcd.c> //libreria manejo lcd
#use rs232(baud=9600, xmit=PIN_A0, rcv=PIN_A1, bits=8)
//******************************************************************************
//VARIABLES
//******************************************************************************
char codigo;
//******************************************************************************
///PROGRAMA
//******************************************************************************
void main(void)
{
lcd_init(); //inicializa lcd
while(1)
{
codigo=getc();
lcd_putc(codigo);
}
}
//******************************************************************************

43
Labelin Electronics EIRL PICS EN LENGUAJE C – GUIA RAPIDA E.M.P.

Este manual es de uso exclusivo para los cursos dictados por LABELIN ELECTRONICS EIRL.
Prohibida la Reproducción Total o Parcial.

Arequipa – 2011 – Perú.

44

También podría gustarte