100% encontró este documento útil (1 voto)
132 vistas333 páginas

Prácticas de Microcontroladores PIC para Mecánica

Cargado por

edgar
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
100% encontró este documento útil (1 voto)
132 vistas333 páginas

Prácticas de Microcontroladores PIC para Mecánica

Cargado por

edgar
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

PRACTICAS CON MICROCONTROLADORES

PIC Y ELECTRONICA PARA LA GENTE DE


MECANICA

UN LIBRO DE ELECTRONICA Y MICROCONTROLADORES PARA LA GENTE


QUE NO SABE ELECTRONICA NI PROGRAMAR MICROCONTROLADORES
=>85 Programas en PIC C, explicados con sus montajes<=
Edgar A. Morales N.

INTRODUCCION.

1
Este libro no es para alguien que quiera convertirse en un experto en
microcontroladores, ni en electrónica, pero si es para todo aquel que teniendo los
conocimientos básicos en electricidad y algo de programación quiera incursionar en la
mecatrónica (lo más básico de la robótica), y desee aprender a controlar de manera
sencilla y con un mínimo de componentes electrónicos y programación ciertos
procesos sencillos que nos encontramos en el mundo de la mecánica, la construcción,
entre otros.

Por ejemplo aquí encontrará como construir y programar un circuito para controlar las
revoluciones por minuto (RPM) de un motor DC y recibir un reporte en su pc a
distancia y según las RPM detectadas tomar una acción programada que puede ser
encender una luz de un determinado color, etc.

También aprenderá a trabajar con pantallas LCD, displays 7 segmentos, a programar


microcontroladores, a construir el programador JDM, y conocerá un grupo de circuitos
TTL de gran utilidad y más.

En este libro se abordarán en general cuatro (4) temas únicamente, con ellos espero
poder llenar las expectativas que me gustaría cubrir en el libro.

Visión estereoscópica.
Saber programar es como ver por un solo ojo.
Saber diseñar en electrónica y en mecánica es como ver por un solo ojo.
Saber ambas es como ver por los dos ojos, pués ya solo piensas en construir artefactos
con todas esas propiedades unidas, aparatos programables, aparatos que tienen cierta
independencia de los operadores, aparatos inteligentes…

Caracas 11/11/2011

1.) El microcontrolador.

2.) La programación del microcontrolador.

3.) La electrónica necesaria.

4.) Aplicaciones.

2
TEMAS A TRATAR

Que es un microcontrolador.
El entorno del microcontrolador.
Lo mínimo necesario para que el microcontrolador funcione.
La programación del microcontrolador.
El programador JDM.
El Pic Programmer.
Transmisión de datos en serie y el puerto COM1 de las PC.
El código decimal y el código binario.
El lenguaje C para microcontroladores.
Lista de comandos del PIC C (Usados en este manual).
El convertidor analógico a digital.
El modulador de ancho de pulsos y el capturador.
Los temporizadores.
Comunicación serial entre el pic y una pc o entre dos microcontroladores.
Comandos que funcionan en grupo.
Funciones de interrupción.
Lista de errores.
La electrónica necesaria (componentes extras interesantes TTL).
La electrónica digital.
La electrónica analógica.
La electrónica de potencia.
Los componentes electrónicos útiles para ciertos diseños.
Diagramas de pinado de los microcontroladores en español.
Diagrama del pic16f84a y sus principales características.
Diagrama del pic16f876 y sus principales características.
Diagrama del pic16f877 y sus principales características.

Programas y circuitos de ejemplos útiles y explicados con el circuito lógico, montaje y


lista de componentes.

3
¿QUE ES UN MICROCONTROLADOR?.

Lo primero que pienso que se debe decir de un microcontrolador es: ¿que és?, y no es
más que un circuito integrado programable, así de simple, es un circuito al que
podemos programar (grabarle un programa en la memoria que tiene adentro para eso)
para que cumpla una cierta o ciertas tareas.

Un microcontrolador contiene memoria ram, memoria rom, un microprocesador,


puertos de salida, puertos de entrada y otros circuitos, tal como si fuera una
computadora en miniatura sin monitor, ni teclado, ni ratón; pero que cumple con una(s)
función(es) programada(s).

Y se comporta igual que una computadora, en la memoria rom se graba el programa que
va a ejecutar, en la memoria ram se manejan los datos y valores en transito que necesita
el programa en su funcionamiento, por los puertos de entrada se puede introducir
información que afectará el funcionamiento del programa o algún tipo de dato, por el
puerto de salida el microcontrolador envía información o pulsos para actuadores
externos, pantallas, luces, motores, etc.

Por supuesto que para que funcione necesita ser alimentado con energía eléctrica (0 y
+5Volt).

Así tenemos que un microcontrolador es un circuito integrado programable al cual


podemos cargarle un programa en su memoria para que él lo ejecute y se comporte de la
forma esperada (esto, si el programa está bien hecho).

Ahora:

Siempre que una persona va a una tienda de aparatos y se compra un aparato, por
ejemplo una radio, lo primero que este debe hacer antes de usarlo es leer el manual de
dicho radio, no sólo para saber usarlo, sino para evitar dañarlo, así también conocer las
limitaciones, las ventajas, los rangos de operación para luego no arrepentirse de haberlo
comprado, y de ser posible debería leerse el manual del radio antes de pagarlo para
asegurarse que ese radio se ajusta a sus necesidades.

Así, de esa manera como lo expliqué con el radio mencionado en el párrafo anterior, es
como se debe proceder con los microcontroladores, pués antes de comprarlo usted
debería consultar en la Internet o algún manual si este microcontrolador se ajusta a las
necesidades que tiene el sistema que usted está por diseñar, construir y programar.

Los datos más importantes a tener en cuenta de un microcontrolador para aplicaciones


sencillas que una persona debe tener en cuenta son:

1) Número de pines disponibles para trabajar como puertas de entrada o salida,


para saber si esa cantidad de pines le alcanza a su sistema o si le sobran muchas.

4
2) Cantidad de memoria para cargar el programa (rom), debido a que un programa
muy largo no podrá grabarse en una memoria pequeña, así también la cantidad
de memoria ram.
3) Si posee convertidor analógico digital, para aplicaciones de medida directa de
temperaturas, presiones, humedad, entre otros fenómenos físicos que se miden
en la naturaleza de forma analógica.
4) Si posee contadores de pulsos, por si se desea contar eventos o medir
revoluciones.
5) Si posee generador de ancho de pulsos para controlar la velocidad de un motor
DC o controlar la intensidad de iluminación de lámparas, o la cantidad de
corriente introducida a una resistencia de calentamiento, etc.
6) Si posee circuitos para comunicaciones en forma serial u otra forma. para
monitorear bien el programa o los datos que está manejando.
7) Si posee oscilador interno para hacer más sencilla la instalación.

Por otra parte es recomendable que se consiga el diagrama de los pines del
microcontrolador que piensa usar, para que observe la distribución de los puertos, las
entradas analógicas, la entrada de pulsos, pines de alimentación, pines de programación,
pines para colocación del cristal resonador, etc.

Nota: Todo eso es más sencillo de lo que parece, de hecho, en las aplicaciones sencillas
de lo que uno se preocupa es del numero de pines disponibles para trabajar.
(Generalmente la memoria alcanza).

EL ENTORNO INMEDIATO DEL MICROCONTROLADOR

Considero que el entorno de un microcontrolador es todo aquello que necesita tener


conectado para su funcionamiento básico, así, aunque usted sólo quisiera utilizar el
microcontrolador para encender un led (luz) en un tiempo determinado, necesita una
cantidad básica de elementos y/o circuitos.

Lo mínimo debe tener para que un microcontrolador funcione.

Lo primero que obviamente necesita es una fuente de alimentación de corriente continua


de 5 voltios y recomendable por lo menos 0.5 amperes, también necesita (para muchos
microcontroladores) un cristal resonador con frecuencia menor a 20000000 (20mega)
Hertz, una resistencia de 10000 (10k) ohmios, y dos condensadores de 15 pico faradios.

Esto es lo mínimo que se necesita para que un microcontrolador trabaje y ejecute un


determinado programa, con la salvedad que este circuito (el anterior) aún no tiene
ningún componente o circuito que nos permita apreciar el funcionamiento del
microcontrolador.

Ahora, para poder apreciar el funcionamiento de un microcontrolador necesitamos


conectarle algo más que el sistema básico, necesitamos conectarle diodos emisores de
luz (led), pantallas de de cristal líquido (LCD), display 7 segmentos, pulsadores,
amplificadores operacionales, transistores para elevar la potencia de salida y activar

5
relés, o activar motores, y/o una serie de elementos y componentes electrónicos que no
sólo nos permitan apreciar que está ejecutándose un programa, sino verificar que su
funcionamiento es el correcto.

Además de todo lo anterior, necesitamos dos programas de computadora, y un circuito


de grabación (un programador) para grabar el programa en la memoria del
microcontrolador.

Uno de los programas se usa para crear el código fuente del programa (o sea el código
del programa que nosotros hacemos con nuestro intelecto typeando en la computadora)
que va a ser ejecutado por el microcontrolador, y que al ser compilado con este software
lo va a convertir en un programa con extensión programa.hex, en hexadecimal que es el
código que el microcontrolador entiende y puede ejecutar. (en este libro usaremos el
lenguaje de programación para microcontroladores PIC C, pero existen otros como
assembler, mikro pascal, pic Basic, etc).

El otro programa se necesita para poder grabar este programa.hex ya compilado en


código hexadecimal en la memoria del microcontrolador donde se almacena el
programa a ejecutar, en nuestro caso usaremos el Picprogrammer (es gratis en la
Internet), pero también está el icprog que funciona igualito y también se consigue gratis
en la Internet.

Además, necesitamos un circuito grabador o programador de microcontroladores, para


nuestro caso y como conozco los costos de éstos programadores les voy a dar el plano
de un programador conocido como el JDM, que és de muy bajo costo y funciona con los
microcontroladores que vamos a usar en este libro.

PLANO DEL PROGRAMADOR JDM

6
En el plano anterior, COM1 es el puerto de comunicación serial que normalmente
tienen las computadoras por la parte de atrás, (quiero informarles que no he podido
programar los microcontroladores con los puertos seriales de las laptop debido a que
sus voltajes no se adaptan a las necesidades y requerimientos para grabar los
microcontroladores, pero las de escritorio nunca me han fallado), de este puerto
(COM1) usamos los pines 3,7,4,8,5 y de los microcontroladores usamos los pines VPP,
B6,B7, alimentación + y alimentación – .

Nota:
En el pic 16F84 (de 18 pines) los pines se distribuyen de forma diferente a los pic
16F876 (de 28 pines), pic 16F877 (de 40 pines) y pic 16F887(de 40 pines).
Normalmente en los microcontroladores con 28 pines o más, el pin VPP es el PIN_1,
el pin Clock es el penúltimo (PIN_27 en 16f876 y PIN_39 en 16f877 y16f887) y el pin
de la data es el último pin (PIN_28 en 16f876 y PIN_40 en 16f877 y 16f887), la
alimentación positiva y negativa la consigue en el diagrama del pinado de cada PIC.

Ejemplo de conexión entre la computadora y el pic 16f876 usando el programador.


JDM

Nota: En la computadora el terminal es macho, la hembra es el terminal del


programador JDM, recuerde que viéndolos de frente el macho cuenta sus pines de
izquierda a derecha y la hembra de derecha a izquierda, muchos conectores tienen sus
pines numerados.

7
El PICPgm programmer

El PICPgm programmer es un programa de computadora que se usa para grabar el


programa que ya está compilado en código hexadecimal en la memoria de programa del
microcontrolador, la secuencia a seguir es la siguiente:
Una vez que ya hemos hecho un programa en (código fuente- PIC C en nuestro caso)
algún lenguaje para programar microcontroladores, lo siguiente que hacemos es
compilarlo para que este leguaje nos genere el programa en código hexadecimal,
ejemplo “programa.hex”, luego de tener este archivo llamamos al programa grabador y
proseguimos a grabarlo en la memoria del microcontrolador.

Este es el icono del programa grabador.


Haga doble click sobre el icono.

Aparecerá la siguiente ventana,

Una vez que esta ventana esté presente en la pantalla de la computadora debemos
configurar este programa para que nos funcione adecuadamente.
El siguiente paso es hacer doble click en la opción.

8
Hardware selection/configuration

Y aparecerá la siguiente ventana.

Ahora abra el menú Programmer Selection y seleccione la opción


JDM Programmer

9
Ahora cliquee en el menú Programmer Connection seleccione en port com1

Es importante que los valores de pin configuration se mantengan iguales a los


siguientes para que funcione adecuadamente.

10
Pin configuration
Funtion pin
MCLR/Vpp 3
PGM/Vdd 0
Clock 7
Data Out 4
Data In 8

Tal como se ve en la gráfica siguiente

Y volver a la ventana principal

Verifique que en la esquina inferior izquierda aparezca el programador


JDM Programmer
Verifique que en la esquina inferior derecha aparezca en puerto COM1.

11
Nota:
Tenga en cuenta que al cliquear en el recuadro Browse usted deberá buscar el
directorio en donde se encuentran grabados los archivos.hex, estos normalmente se
graban en el directorio C\ARCHIVOS DE PROGRAMA\PIC C, pero usted los puede
guardar en cualquier directorio que quiera con “SAVE AS”, se le recomienda que
antes de tratar de grabar el programa en el microcontrolador, tenga el microcontrolador
ya conectado al programador JDM y se dirija a el menú Command y ejecutar el
Autodetect PIC, para que el PICPgm lo detecte y lo presente en Device
Information, tenga en cuenta que si el programa no reconoce al microcontrolador, no
lo grabará (verifique que esté bien montado).

Una vez que usted ha configurado el PICPgm y lo ha ejecutado, aparecerá la pantalla


PICPgm Development Programmer, y si ya tiene cargado el programa.hex en la
memoria de la computadora y ha sido detectado el microcontrolador, proceda a
grabarlo, cliqueando el icono que tiene un chip con un rayo amarillo.

Observe en la línea en blanco al lado del recuadro Browse


G:\proli\p11.HEX (Este es el programa que se cargará en el PIC), y además en Device
Information que está reconocido el microcontrolador PIC16F84A, y que tiene 2K de
memoria flash y 64 bytes de EEPROM

Y una vez que la grabación ha sido exitosa debe aparecer la siguiente ventana

12
.

Nota:
El programa anterior tiene más alternativas de uso, y no es que éstas no sean
importantes, pero en este tema lo que me interesa es que usted aprenda a usarlo para
grabar su programa compilado en la memoria del microcontrolador, que es el objetivo
de este libro. Lo que usted quiera aprender aparte de configurar el programador JDM
para usarlo grabando sus programas corre por su cuenta.

Este programa lo puedes bajar de forma gratuita de la dirección


http://members.aon.at/electronics/pic/picpgm/download.html

13
El puerto de comunicación serial COM1 en las computadoras.

El puerto de comunicación serial es un puerto DB9 (conector de 9 pines macho) que


usualmente tienen las computadoras es su parte posterior, algunas tienen dos puertos
(COM1 y COM2), pero por lo general es uno solo.

Este conector se usa para establecer comunicación en forma serial, comunicación serial
quiere decir que los datos se transmiten uno detrás del otro, y solo cuando se ha
transmitido el último pulso de un dato se sabrá que dato és.

En uso normal este puerto de comunicaciones envía la data por el pin nro. 3 y recibe los
datos por el pin nro. 2 , además tiene la tierra lógica en el pin 5 y otros pines para
indicar que se está listo para enviar o recibir datos, para indicar que hay repique y para
dar una señal de pulsos eléctricos o clock.

Como se transmite una información en forma serial?


Una de las formas de transmitir información en forma serial es usando dos hilos, por
uno de ellos enviamos pulsos a una velocidad constante, y por el otro también enviamos
pulsos, pero estos pulsos son para formar datos, cada ocho pulsos se forma un dato (una
letra o un símbolo) que unido con las otras letras forman palabras y estas palabras
forman mensajes.

Ejemplo hipotético.
Se va a enviar la palabra HOLA usando grupos de tres pulsos por dos hilos de forma
similar como lo haría una computadora en forma serial

Código A = 1 1 1 tres lecturas de pulsos en voltage alto 5 voltios


H = 0 0 0 tres lecturas de pulsos en voltage bajo 0 voltios
L = 0 0 1 dos lecturas en bajo y una en alto
O= 1 0 0 una lectura en alto y dos en bajo
Además nos quedarían 1 0 1 sin código y 010 sin código

Analicemos esta gráfica de transmisión en serie de la palabra HOLA. Mediante 12


pulsos, uno cada segundo.

14
1) La línea A es la gráfica de un generador de pulsos que da una pulsación cada
segundo, durante 12 segundos.
2) Tenga en cuenta que las lecturas se hacen justo cuando la gráfica A está en la
parte alta de un pulso, entonces cuando esto ocurre (el pulso en la gráfica A), se
toma el valor de la gráfica B como un 0 si la gráfica B está a 0V, y como un 1 si
la gráfica B está en 5V.
3) De esta manera, lo importante es que la gráfica B esté en el voltaje conveniente
cuando ocurran los pulsos para formar los códigos de las letras.
4) Observe que en el primer pulso de la gráfica A, la gráfica de B está en 0Volt.
pero en el cuarto pulso de la gráfica A, la gráfica B está en 5Volt.
5) Los códigos posibles 000 – 001 – 010 – 011 – 100 – 101 – 110 - 111
6) Luego separando los 12 pulsos 000100001111 en grupos de tres (3) tenemos
000 100 001 111
7) Buscamos en nuestra codificación lo que significa cada serie de tres en tres (3 en
3) y obtenemos que 000 es H, 100 es O, 001 es L y 111 es A, con lo que
formamos la palabra HOLA.

Porqué es importante saber esto?, porque cuando programamos los microcontroladores


la información (el programa) se la introducimos de forma similar a lo explicado antes,
en los microcontroladores PICs, el PIN_B7 hace las veces de la línea B, en PIN_B6
hace las veces de la línea A, y además hay que decirle que se le va a programar, y eso
lo hacemos cuando le ponemos 12Voltios en el pin VPP (Voltaje Para Programarlo, es
de 12 voltios), lo que sucede, es que la velocidad de transmisión de los datos es muy
superior a un pulso por segundo, lo normal son 9600 pulsos por un segundo.

Una nota aparte: Es decirles que cuando configuramos el software para usar un
programador JDM, este cambia las funciones tradicionales de los pines del COM1 y lo
reprograma para poder usar los 12Voltios del pin 3 como excitador para programar, los
datos son transmitidos por el pin 4 y los pulsos por el pin 7.

15
SISTEMAS DE NUMERACIÓN

El código decimal y el código binario.


(Este tema es necesario –créamelo- si no lo fuera, no me diera la tarea de explicárselo)

Todos conocemos y usamos normalmente el sistema de numeración decimal, ahora:


Que és, el sistema de numeración decimal o código decimal?.
Se llama código de numeración decimal a la forma de representar cantidades utilizando
diez (10) símbolos (por eso se llama decimal), estos símbolos son 0, 1, 2, 3, 4, 5, 6, 7,
8 y 9. y el que cada símbolo tenga el mismo nombre que la cantidad que representa es
algo que nos ayudó cuando éramos niños a conocer los números y las cantidades, pero
que ahora la realidad es que cualquiera puede representar cualquier cantidad usando el
código que le guste más (a las máquinas solo les gusta en código binario)

El código más sencillo de todos es el código unitario (un solo símbolo), pues con el
representamos las cantidades directamente repitiendo el símbolo cuantas veces sea la
misma cantidad.
Por ejemplo:

Código Código
Decimal Unitario
1 1
2 11
3 111
4 1111
5 11111
6 111111
7 1111111
8 11111111
9 111111111
10 1111111111
11 11111111111

y así sucesivamente, pero imagínese representar un millón en código unitario, y además


este código no tiene representación del cero.

El código que sigue es el código binario, en este código usamos dos símbolos para
representar las cantidades, como en todos los sistemas de numeración, la ciencia
consiste en:

1ro) Representar las cantidades que se puedan formar con un solo símbolo (un digito).
2do) Representar las cantidades que se puedan formar con dos símbolos comenzando
por una unidad más alta que la última cantidad representada con un dígito (antes un
dígito, ahora usando dos dígitos)

16
3ro) Representar las cantidades que se puedan formar con tres símbolos empezando
por una unidad más alta a la última anterior (dos dígitos).

Representación de cantidades desde cero, hasta quince en códigos decimal y binario


DECIMAL BINARIO DECIMAL BINARIO
0 0 1 1
2 10 3 11
4 100 5 101
6 110 7 111
8 1000 9 1001
10 1010 11 1011
12 1100 13 1101
14 1110 15 1111

Así podemos representar la cantidad que deseemos, sabiendo como organizar los
dígitos tenemos la posibilidad cierta de codificar cualquier cantidad, así la cantidad de
un millón se escribe en código binario
Decimal Binario
1000000 = 111101000010010000000

Esta explicación tiene sentido, porque la electrónica digital solo tiene dos estados,
apagado o estado 0 y encendido o estado 1, así, si un microcontrolador le da una
respuesta numérica en un puerto de pines, se la dará en código binario que es el código
con el que él se puede expresar, cuando usted vea una respuesta representada en código
decimal es porque hay una circuitería que se la está convirtiendo para que usted la
entienda y reconozca, pero las máquinas calculadoras y las computadoras y toda la
electrónica digital no conoce otro lenguaje que no sea el del código binario.

Además del código unitario, el código binario y el código decimal (el que usamos
normalmente) también está el código hexadecimal (16 símbolos) y el octal (8 símbolos),
que son muy utilizados en la programación de los microcontroladores; pero me las
arreglaré para explicar todo con solo estos dos códigos, el binario y el decimal

Ahora:

1) Para convertir un número binario en decimal.


Copiamos el número, digamos el 10011001 (este tiene 8 digitos), luego
enumeramos sus dígitos desde el 0 hasta 7 y de izquierda a derecha, entonces
tenemos: (para un número con 8 dígitos)

Posición de cada digito 7 6 5 4 3 2 1 0


Valor en código binario 1 0 0 1 1 0 0 1

17
Luego en las posiciones donde haya un 1 en el número binario lo hacemos potencia de
2 y los demás los descartamos, en este caso las posiciones que tienen 1 en el código
binario son 7, 4, 3 y 0, y procedemos a calcular el valor en decimal.

128 + 16 + 8 + 1 = 153

Ahora para convertir el número 152 de decimal a código binario.

Como puede observar son puras divisiones entre 2, hasta que el último cociente nos de
cero, luego tomamos todos los restos o residuos y los ordenamos empezando por el
último resto hacia la derecha.

10011000 binario = 152 decimal

EL PIC C

El Software PIC C para hacer programas para microcontroladores.


En la dirección http://www.ccsinfo.com/compdemo.php se consigue una versión
gratuita demostrativa, con la que se puede iniciar en la programación, y además realizar
todos los programas.

Una vez ya instalado el PIC C en la computadora, antes de comenzar a ponernos a


escribir código de programas, debemos informarnos de ciertas cosas que son
importantes, aunque quizás poco las utilicemos.

1) El programa PIC C al instalarse se almacena en el directorio c:\archivos de


programa\PICC
2) En ese directorio conseguiremos lo siguiente.
2.1) Varios subdirectorios entre los que están.
2.2) DIRECTORIO :Data sheets: En este directorio conseguirás gran
cantidad de información en formato PDF acerca de los
microcontroladores PICs, y otra información adicional, además un
manual de referencia del PICC en ingles.
2.3) DIRECTORIO : Devices: En este directorio están los archivos que
tienen la información que requiere PIC C de cada microcontrolador, para
poder saber con que cuenta el microcontrolador para determinar si puede
realizar ciertas tareas puestas en el programa, por ejemplo si tiene

18
suficiente memoria, además si tratamos de compilar un programa para un
microcontrolador que no aparece en este directorio nos dará error, ya que
el PICC no sabe a que atenerse, cuando esto suceda usted debe ejecutar
el programa CHIPEDIT cuyo icono está en el directorio de PICC y
agregar este PIC para que tenga su archivo de referencia.H y poder
trabajar con él.(más adelante se dará una mejor explicación de esto)
2.4) DIRECTORIO: Drivers: En este directorio se encuentra una cantidad de
librerías para ser usadas, pero primero debe aprender a usarlas, para
ello puede abrir cada librería y leer en ella para que sirve y además puede
ver su código C y hacerse una mejor idea de cómo y para que usarla.
2.5) DIRECTORIO: Example: Este directorio tiene una serie de ejemplos de
programas en PIC C, que siempre son buenos para tener una referencia
de cómo se hizo alguna parte de un programa, como se definió un cuerpo
o algunas variables, como se usa algún comando o grupo de comandos.

2.6) EL ICONO CSS: Nota: Para hacer un programa y compilarlo no


necesitamos tener el ambiente del PIC C, este lo podemos usar con un
editor de textos para crear el código y luego compilarlo, para ello
podemos usar el ícono Ccsc, que al ejecutarlo aparece una ventanita en la
que colocamos el nombre del programa que queremos compilar, y este
será compilado si no tiene errores, la ventaja del ambiente de PICC es
notable, pero también lo podemos hacer sin este ambiente.
2.7) EL ICONO : CHIPEDIT: que se usa cuando queremos agregar un
microcontrolador que no tiene archivo.h en el directorio DEVICES.
NOTA:
Sucede que un día compré un microcontrolador, y cuando fui a compilar
un programa que había hecho para trabajar con él, el PIC C no lo
compiló, al buscar en la causa me informé que este no estaba en la lista
de PICS del directorio DEVICES, entonces ejecuté al programa
CHIPEDIT

y apareció la siguiente ventana.

19
En esta ventana debes seleccionar un PIC (de esos que ahí aparecen) que sea lo más
parecido en cuanto a número de pines (patillas) memoria, etc. a el PIC que quieres
agregar, para ello debes buscar en los archivos de datos de los dos (el que no aparece y
el que está en la lista para compararlos) PICs usando la Internet o manuales, una vez
que sabes cual de los que están en la ventana es el más parecido, debes cliquear en
+COPY

+COPY

Y aparecerá está ventana, ahí debes copiar el nombre exacto del pic que quieres agregar,
(Ejemplo: PIC16F887)

Por ejemplo NOMBRE DEL PIC

20
Presionar en la opción OK
Y deberá aparecer esta ventana, ahí podrás verificar las caracterícsticas del PIC, y ahora
presionas la opción SAVE, y listo, ya está agregado el pic.
(Note que en está ventana se presentan las características del PIC, si usted tiene la hoja
de datos puede ajustarla, sino que al menos sea parecida )

Verifica que el archivo que te aparezca en el directorio DEVICES tenga el nombre del
PIC con extensión H, ejemplo PIC16F887.H, si no tiene esta extensión (H) no
funcionará, pues a veces aparece como .TXT, si esto te sucede solo cámbiale la
extensión de .TXT POR .H y caso resuelto, también puedes conseguir este archivo
de otro PIC C que tenga la referencia de este microcontrolador.H y grabarla en el tu
directorio DEVICES y caso resuelto.

21
2.8) ICONO SIOW: Que es un icono que sirve para monitorear el puerto de
comunicaciones serial.

NOTAS SOBRE EL LENGUAJE C PARA MICROCONTROLADORES PIC C

Antes que todo, debo decir que para aprovechar este libro al máximo debes tener el
lenguaje C para microcontroladores de la empresa CCS, de este puedes bajar una
versión demo de la Internet, http://www.ccsinfo.com/compdemo.php, y una vez
instalado puedes hacer tus programas, recuerda que las versiones demo tienen una fecha
de vencimiento que comienza a contar a partir del día de su instalación y son 30 días
nada más, así que si quieres más tiempo deberás reinstalarlo o estar pendiente de
cambiarle la fecha a tu computadora y mantenerte en una fecha cercana al día de la
instalación , no dejes que se te pase esta fecha, incluso puedes hacer un programa en
lenguaje C o en Pascal o en Basic, etc. y colocarlo en el autoexec.bat que ajuste la fecha
por ti cada vez que enciendas tu computadora.

(Programar en lenguaje C para microcontroladores es sencillo y entretenido, además le


da la satisfacción de automatizar muchas actividades que en principio será aprendizaje,
luego será entretenimiento y finalmente será para resolver problemas de ingeniería con
suma sencillez, rapidez y bajo costo, (esta es una herramienta que en manos de la gente
que hace mecánica y con un poco de imaginación logra maravillas)

En este libro no pretenderé que les voy a enseñar todo lo extenso de este lenguaje de
programación tan importante y poderoso, pero si les enseñaré los lineamientos que uso
para programar los microcontroladores y muchas de las cosas que se pueden hacer con
él, y los PICs

Como primero y esto es por todos conocido, és que todo aquel que alguna vez en su
vida se ha visto en la necesidad de programar computadoras, independientemente del
lenguaje que haya usado, siempre de alguna manera ha sabido de la existencia del
lenguaje C, en alguna de sus tantas versiones, C, turbo C, C+, C++, ANSI C, etc.

22
LINEAMIENTOS EN EL LENGUAJE C PARA MICROCONTROLADORES
(PIC C)

1) Todo programa en PIC C debe tener su encabezado, en el que se le informa al


lenguaje ciertas directivas, (entre estas directivas hay unas que son muy
importantes y si no lo hace bien, el programa no compilará), además tenga
mucho cuidado con la ortografía (sintaxis) de las palabras, por ejemplo escriba
PROTECT y no PROTEC, esa T que le falta a la segunda palabra al final es
un error casi invisible y puede causar retardos.

2) Si usted va a usar librerías debe llamarlas y además debe saber usarlas, saber
para que le sirven y donde están localizadas. (Una librería es otro programa,
también en C que ya está hecho y que pretendemos usar acoplado al que vamos
a hacer o estamos haciendo)

3) Toda variable se debe declarar (bien sea global y sea local) antes de ser usada.

4) En lenguaje C los programas pueden ser modulares o por cuerpos y esto nos da
tremendas ventajas.

5) Se deben configurar todos los puertos (es lo más recomendable).

6) Se debe informar de antemano cuando se va a usar el convertidor


analógico/digital y además informar la cantidad de bits (la precisión) con la
que va a trabajar el convertidor.

7) Se debe informar de antemano cuando se va a establecer comunicación serial,


así como la velocidad de esta comunicación, el pin de transmisión de los datos
y el pin de recepción de los datos.

8) Se debe informar la velocidad exacta del cristal resonante que se va a usar


conectado al microcontrolador, (esto es muy importante para producir retardos
exactos y para establecer comunicación en forma serial con la velocidad en
baudios adecuada). “Baudios es una velocidad de comunicación serial,
baudio = 1 es una señal por segundo y baudios = 9600 es 9600 señales por
segundo”

EL PIC C (Lenguaje C para microcontroladores)

Este libro está basado en el lenguaje PIC C de la casa CCS, qua una vez instalado en su
computadora, lo puede usar para hacer sus programas, compilarlos y luego con el uso
del PICpgm Programmer y el Programador JDM podrá grabarlos en la memoria de
programa del microcontrolador, el que luego podrá ponerlo a funcionar para verificar si
lo que programó, es lo que hace el microcontrolador.

23
Para ejecutar el programa PIC C debe cliquear en el ícono.

Luego le aparecerá toda la pantalla de color gris con el menú de barra horizontal
siguiente

Cliquee en la opción file y luego el new.

Ahora le aparecerá la siguiente ventana, ahí deberá colocarle el nombre al programa que
está por hacer, y también deberá ubicar el directorio donde lo va a guardar. En este
ejemplo el programa se llama programa y se va a guardar en el directorio proli. Luego
cliquee en guardar.

24
Ahora toda la pantalla se pondrá de color blanco, esto le indica que está lista para que
comience a programar. (lo que los programadores llaman echar código).

Estos son todos los menús desplegados de PIC C, en este libro no se explicarán todas
las opciones de todos los menús, pero sí todos los necesarios e importantes para
nuestros programas.

25
El diagrama del microcontrolador es importante tenerlo a mano cuando vamos a hacer
un programa, para saber que tenemos y con que contamos.

26
Ahora vamos crear el primer programa, en este programa lo importante es que
aprenda la importancia del encabezado.

Información del primer programa:

1ra linea:
#include <16f84a.h>
Siempre se coloca en la primera línea la palabra #include y entre los símbolos
<16f84a.h>, el modelo del pic con extensión h, esto le dice al PIC C que busque en el
directorio devices las características electrónicas de ese microcontrolador para saber si
se ajusta a lo que se requiere en el programa.

Nota: recuerde que el subdirectorio devices está en el directorio del PIC C, que es donde
está instalado el PIC C, y en él están todos los archivos.h con las características
electrónicas que necesita tener a mano PIC C para programarlos. (El PICC siempre
sabe donde buscar sus archivos .h).

2da línea:
#fuses hs,nowdt,noprotect,put
En esta segunda línea se le dice al PIC C que se va a trabajar con ciertas directivas.

27
Nota1: Las directivas se separan con coma (,) y es indiferente si las copia en
mayúscula o en minúscula.
#fuses Le indica al PIC C que lo que viene después en esa misma línea son directivas a
tener en cuenta al compilar el programa.
Nota2: Una directiva es una característica como el tipo de oscilador, protección del
programa,etc.

hs: Le indica a PIC C que al microcontrolador se le va a conectar un cristal resonador


de cuarzo alta velocidad, es decir frecuencia superior de 3000000Hz

nowdt: En electrónica digital existe un circuito llamado “circuito de perro guardián”, y


este circuito es como una especie de vigilante que cuando detecta que algo anda mal
detiene el funcionamiento del sistema, o si este está detenido sin explicaciçon lo hace
andar, en ingles es Watch Dog Timer, y sus siglas son WDT para indicar que cierto
sistema está protegido por este circuito, lo que sucede es que en nuestro caso no lo
necesitamos, porque lo que nos interesa es que nuestro programa funcione, por eso no lo
usaremos, entonces NODWT indica que no queremos funcionando este circuito de
perro guardián.

noprotect: Muchas veces cuando diseñamos un sistema con microcontrolador, tenemos


que correr el riesgo de presentar el prototipo a extraños (Por alguna razón), y quizás la
clave del éxito está justamente en el programa que está grabado en la memoria del
microcontrolador, entonces utilizamos la opción Protect, con esta opción no podrán
copiarse el programa aunque se roben el prototipo, pues al tratar de leer el programa del
microcontrolador para copiarlo en otros microcontroladores no podrán, y lo que
lograrán hacer será borrarlo o dañar el microcontrolador.(por ahora no necesitamos
tener en secreto los programas).
Nota: Sepa que copiar un circuito puede ser extremadamente facil, a veces basta con
fotografiarlo y nada más.

put : Esto significa power up time, que en nuestro idioma quiere decir, que el
microcontrolador no debe comenzar a ejecutar el programa hasta que esté estabilizado
energéticamente (eléctricamente) el microcontrolador, sin embargo esta estabilización
tarda mucho menos de una décima de segundo, es decir put < (1/10)segundo.

3ra línea:
use delay (clock=8000000)
Como ya en la segunda línea le habíamos dicho que íbamos a usar un cristal resonador
de alta velocidad, entonces también tenemos que decirle de cuanto es exactamente la
velocidad (frecuencia de oscilación) del cristal resonador.
Nota: Estos cristales resonadores de cuarzo vienen encapsulados en una cubierta de
metal en la mayoría de los modelos, y en su cobertura tienen grabada la velocidad de
oscilación o frecuencia en Megahertz , ejemplo
8.000Mhz quiere decir 8000000 hertz. (No quiero decir que si pone una velocidad
diferente a la dice el encapsulado del cristal no funcione, la verdad es que si funciona;
pero tendrá problemas con los retardos y con la comunicación serial porque en la
actualidad el PIC C no tiene como saber la velocidad del cristal resonador y deberá
confiar en usted, y usted debe verificar esta velocidad en el cristal mismo).

28
En la 4ta línea: No tenemos nada, pero esto es solo porque este programa es didáctico y
se hace para separar visualmente las partes del programa, pero sepa que esto no es
necesario si se está claro en lo que se quiere hacer y se conoce el lenguaje, cuando se
compile estos espacios ni existen.

El lenguaje C es un lenguaje en el que los programas pueden tener muchos cuerpos,


módulos o subprogramas, pero siempre como quiera que sea, deben tener un cuerpo
principal, si nuestro programa no tiene sino un solo cuerpo, este necesariamente será el
cuerpo principal del programa, que en lenguaje C se llama main() o void main() y
esto quiere decir que este es el cuerpo principal del programa o quizás el único cuerpo
del programa, “en nuestro caso es el único cuerpo”.
Ahora: ¿Donde empieza y donde termina un cuerpo de programa?, o una sección que
queremos delimitar en nuestro programa, sepa desde ahora y no olvide nunca que los
cuerpos y sectores de programas que queremos delimitar en lenguaje C los hacemos con
llaves { }.

void main() { principio del cuerpo del programa


- -----
- -----
Etc
Fin del cuerpo del programa }

5ta línea: Tenemos la declaración del inicio del cuerpo principal del programa y en la
6ta línea tenemos la llave { que delimita el comienzo.

void main ()
{
Como lo expuse en los lineamientos de la programación en C, siempre que necesitemos
una variable, antes la tenemos que declarar, claro!, en este programa éstas variables que
declaré int a,b; (enteras sin decimales a y b) y float c;d; (valores con decimales c y
d), y aunque no se usan para nada (en este programa de ejemplo) y no hacía falta
declararlas en absoluto, preferí hacerlo porque ahora necesito explicarles como se
manejan las variables en lenguaje C.
Siempre que estemos programando, e independientemente de lo que hagamos, por lo
general vamos a necesitar variables, si evaluamos funciones necesitamos variables, para
hacer cálculos necesitamos variables, etc, ahora al lenguaje C debemos decirle, no solo
los nombres de las variables que vamos a usar, sino, cual tipo de variable: entera, con
decimales, si el valor es grande o muy grande, si es un carácter, si es una palabra o
cadena de caracteres, etc.

En lenguaje C hay una serie de variables a declarar que tiene para trabajar, éstas son:
tipo ejemplo rango
Entera pequeña int int a,b,c; 0 hasta 255
Entera mediana int16 int16 d,e; 0 hasta 65535
Entera grande int32 int32 f,g,h; 4294967295
Con decimales float float i,j,k; -1.75e-30 ->3.3e38
Caracteres char char l,m,n; un caracter

29
Cuando se desea declarar una matriz o un vector de variables se debe indicar la
dimensión del vector o matriz con el tipo de variable de la siguiente forma.

Variable entera pequeña de subindice a en un vector de 100 elementos


Int a[100]; la dimensión (cantidad de variables) entre corchetes.

Variable entera grande de subindice b en una matriz de 20 X 30


Int b[20][30];

Nota: Las líneas de comando que no encierran un grupo de acciones a repetir siempre
terminan en punto y coma (;), y las líneas de comando que ejecutan un grupo de
acciones que se delimitan con llaves no llevan punto y coma (;) al final. (de cualquier
manera verá muchos ejemplos que le aclararán esto).

Así, de esta manera en las líneas 7ma y 8va tenemos declaraciones de


int a,b; variables enteras pequeñas.
float c,d variables grandes con decimales.

En la línea 9na tampoco hay nada.

Líneas 10ma y 11va.

Como ya sabe, en la 1ra línea de programa declaramos que estamos trabajando con un
microcontrolador 16F84A, y una de las características de este microcontrolador es que
tiene dos puertos o puertas (como quieras), el puerto A tiene 5 pines y el puerto B tiene
8 pines, ahora debemos decirle al leguaje PIC C como queremos que trabaje cada pin
(uno por uno) de cada puerto, esto ocurre porque cada uno de los pines puede hacer
solo una de varias tareas que puede realizar, “pero solo una”, no he sabido que en un
programa, un pin que se configura como pin de salida también trabaje como entrada,
(en un mismo programa) cada pin puede realizar una sola tarea, además, si podemos e
hiciéramos que realizara más de una tarea, esto nos traería como consecuencia tener que
realizar circuitos que nos alternara externamente la conexión cuando va a ser entrada y
cuando va a ser salida y la idea del microcontrolador es precisamente ahorrarnos esto.

Ahora, nosotros podemos comunicarnos con el lenguaje C en varios sistemas de


numeración, el PIC C los entiende todos; pero nosotros solo le vamos a hablar en
decimal porque es el que entendemos mejor y en binario cuando esto nos convenga, y
entonces cuando yo le quiero dar cantidades o valores en decimal se las doy de forma
simple y directa, es decir, sin decirle en que sistema está porque él sabe que yo siempre
hablo en decimal; pero cuando necesite hablarle en binario entonces a la cantidad le
tengo que colocar adelante la contraseña 0b y el automáticamente ya sabe que ese valor
está dado en binario.

Bien, a nosotros nos conviene que cada vez que le hablemos de valores de salida por los
puertos del microcontroldor, le hablemos en binario, y que cada vez que le hablemos de
configurar los puertos también en lo hagamos en binario, porque así sé por los
diagramas de pines de los microcontroladores cuantos pines tiene en cada puerto y así

30
me ahorro en tener que hacer conversiones para saber si un pin de determinada puerta
va a ser salida o entrada.

Entonces para que un pin de un puerto trabaje como entrada le doy el valor de 1 y este
de paso se parece a la letra i de in entrada en ingles, y que cuando quiera que un
determinado pin de un puerto trabaje como salida le doy el valor de 0, y este de paso se
parece a la letra O de Out salida en ingles, y las palabras set_tris que es el comando
de configuración para configurar los puertos y la letra (a) que le sigue, indica cual es el
puerto configurado, entonces tenemos.

set_tris_a(0b11111); Esto quiere decir que configuré los 5 pines del


puerto a como entradas.
set_tris_b(0b00000000); Esto quiere decir que configuré los 8 pines del
puerto b como salidas.

Sabiendo esto, podemos configurar cualquier puerto como queramos que este trabaje.
Nota: Mi persona normalmente usa el puerto a, solo como entradas, pero esto es algo
particular.

Ejemplos:

set_tris_a(01010); pines a4, a2, a0 como salidas y pines a3 y a1 como entradas.

set_tris_b(0b11110000); pines b7,b6,b5,b4 como entradas y pines b3,b2,b1


y b0 como salidas.

Set_tris_c(0b11000011); pines b7,b6 como entradas, b5,b4,b3,b2 como


salidas, b1,b0 como entradas.

Set_tris_d(0b00111100); pines b7,b6 como salidas, b5,b4,b3,b2 como


entradas, pines b1,b0 salidas.

Nota: Es importante siempre tener a mano el diagrama de pines del microcontrolador


para configurarlo, pues los pines no solo son entradas y salidad digitales, pueden ser
entradas analógicas, pueden sen entradas de contadores timer, en el puerto E de PIC
16F887 los pines son diferentes, etc.

Línea 12: Linea en blanco –no hace nada-

Línea 13va.
En esta línea tiene lo único que realmente podemos apreciar que hace el
microcontrolador con el programa que le pusimos. (encender un led).
output_high(pin_b0);

Línea 14va.
Cierre de la llave, fin del cuerpo de programa.
}

31
Nota:
El comando output_high es el que pone la salida alta en el (pin_b0); es así de
sencillo, output_high es salida alta, o sea, el voltaje alto que puede dar, y (pin_b0) entre
paréntesis le dice el pin al que tiene que poner en salida de voltaje alto del puerto B, y
en la línea 14va la llave cerrada indica que este es el fin del cuerpo principal y por ende
fin del programa.

Una vez echo todo el código del programa en C, ahora debemos compilarlo, si tiene
errores, este no compilará, y aparecerá en la parte baja de la pantalla en mensaje de error
que le indica el tipo de error.

Ejemplo:

Que le indica que archivo 16f897.h de ese microcontrolador no está en el directorio ahí
señalado.

Ejemplo:

Que le indica que tiene un error de sintaxis en el encabezado.

Si no tiene errores, aparecerá esta ventana por unos segundos.

32
Nota: fíjese en la primera línea.
Project: d:\programas\887..c que es el directorio donde deberá buscar el archivo
887.hex el cual es el archivo que deberá grabar en la memoria de su microcontrolador.
(Nota: 887..c es el nombre que le puse al programa, no se confunda con el código de un
microcontrolador).

Hasta aquí su primer programa, ahora deberá proceder a llamar a el programa software
que se necesita para grabarlo en el microcontrolador (ejemplo picpgm programmer),
cargarlo como se explicó en la sección de cómo grabar el programa en la memoria del
microcontrolador e instalar el microcontrolador como indica el siguiente esquema.
Nota: Este programa lo único que hace es encender un led en el pin b0, pero puede
probar que en los demás pines A0, A1, A2, A3, A4, B1, B2, B3, B4, B5, B6 Y B7 no se
enciende si conecta el led en cada uno de ellos.

1) Haga el programa (póngale un nombre),


2) Compílelo,
3)Llame al PIGpgm Programmer.

4)Cárguelo (use BROWSE para ubicarlo dende esté).


5) Ponga el microcontrolador en el programador JDM.
6) Conecte el programador al COM1 de la computadora.
7) Cliquee al ícono del rayo amarillo.
(Si todo está bien, apareceré la vantana de color verde)

33
Circuito como se debe instalar el microcontrolador para ver el funcionamiento de este
programa, se recomienda colocar una resistencia de 220 ohm entre el led y el pin 6 del
microcontrolador y dos condensadores de 15 pf entre los pines del cristal y negativo.
Nota: Muchas veces el microcontrolador funciona sin los condensadores de 15 pF.

Bueno, hasta aquí es el encabezado y el cuerpo de este programa, pero hay más
directivas que indican otras situaciones.
Las directivas posibles son
. Para osciladores. lp xt hs rc
. Para circuito de perro guardián. wdt nowdt
. Para la protección del codigo. project, noprotect
. Para esperar estabilizar el sistema. put, noput
.Para detener el programa en caso de caida de voltaje. Brownout, nobrownout.
Brownout es una directiva que al usarla mantiene una vigilancia en cuanto a la
alimentación del microcontrolador, y cuando el voltaje cae por debajo de el voltaje
correspondiente se detiene el funcionamiento del programa.

lp es también un cristal resonador de cuarzo, pero esta es de baja velocidad, máximo


hasta 3.0Mhz.
rc es un circuito oscilador de resistencia condensador.
Nota: Solo podrá colocar como máximo una de las alternativas, por categoría.

34
Ahora observen este encabezado de un programa más complejo

#include <16f877.h>
#fuses hs,nowdt,noprotect,put.browout,nolvp
#device adc=10
#use delay (clock=20000000)
#use rs232(baud=9600, xmit=pinc6, rcv=pinc7)
#use fast_io(b)

nolvp: Es para programación en bajo voltaje, (es una forma especial de programar los
microcontroladores).

#device adc=10 se usa para activar el convertidor analógico digital con 10 bits de
precisión, (10 bits de precisión en decimal quiere decir que el rango que vamos a
establecer tendrá 1024 divisiones).

#use rs232(baud=9600,xmit=pinc6,rcv=pinc7) Esta línea se usa para comunicarle al


PIC C que debe preparar el microcontrolador para tener comunicación serial usando el
protocolo rs232, con una velocidad de 9600 baudios, con emisión de datos por el
PIN_C6 y recepción de datos por el PIN_C7.

#use fast_io(b) Le dice a PIC C que se quiere trabajar con el puerto b a alta velocidad.

Nota: He leído en la bibliografía que sólo con los pines c6 y c7 se puede transmitir y
recibir información a alta velocidad, de resto se puede usar casi cualquier par de pines.
(yo pienso que la velocidad de 9600 todavía no es una velocidad alta).

NOTA:
Ahora lo recomendable es que se repase todas las veces que necesite todo lo explicado
hasta ahora, principalmente lo que tiene que ver con el encabezado, ya que es algo que
casi hay que aprendérselo de memoria y no lleva mucho de lógica, ni es algo largo,
pero si, es muy importante. Desde aquí en adelante me dedicaré a explicar los
comandos, uno a uno “ para que sirve, como lo aplico o como lo cálculo, que cuidados
debo tener”, programar y verificar el funcionamiento, como conectar el circuito.

Esta es una lista incompleta de comandos del lenguaje PIC C, pero con esta cantidad se
pueden hacer muchas aplicaciones útiles y prácticas.

Nota: En este libro no se explicarán todos los comandos que existen en este lenguaje,
además que existen varias formas para que diferentes programas hagan lo mismo, solo
me limitaré a realizar la mayoría de las tareas de una solo forma (trataré que sea la
forma más sencilla, simple y entendible) para evitar confusiones, procuraré no usar
comandos reducidos pues estos no se entienden a simple vista, luego que usted entienda
esto, la forma más simple, puede buscarse cualquier libro de lenguaje C y ahí
conseguirá como resumir ciertas tareas y partes de programas, pero que solo los
expertos lo entienden al verlo, ya que para el lenguaje humano, ese código resumido no
tiene sentido a simple vista.

35
Ejemplo x=x+y es entendible a simple vista, pero x+=y no hay forma que lo entienda
sin haberme antes leído la teoría de esta programación resumida, y no es la idea de este
libro.

Lista de operadores que se están en este libro. (hay más pero me limitaré solo a éstas)

+ suma

- resta

* multiplicación

/ división

= igualdad para asignar un valor a una variable ( x=5 )

== igualdad; pero para comparar si dos variables valen igual


“si (a = = c) entonces valen lo mismo”

> mayor que


< menor que
>= mayor o igual que
<= menor o igual que
!= diferente a

Cada uno de los operadores siguientes necesita una explicación corta, debido a que
son operaciones lógicas.

Toda cantidad tiene una representación (con símbolos alfanúmericos) que casi
siempre es diferente, dependiendo del sistema de numeración con el que la
escribamos, en estos casos trabajamos en código binario debido a que estas sentencias
lógicas trabajan con los bits (en binario) de las cantidades.

& es la operación lógica AND o Y en español, y trabaja de la siguiente forma.(Uno


solo& se usa para comparar bits)
Si todas las variables o constantes que se relacionan con este símbolo son 1 entonces
el resultado es 1, pero si al menos una sola vale 0, el resultado es 0.

Ejemplo:

0b1 & 0b1 = 0b1; 0b0 & 0b0 = 0b0, 0b1 & 0b0 = 0b0 0b0 & 0b1 = 0b0; (No
olvide que 0b significa que esa cantidad está en binario)

Ahora usando múltiples bits (cada bit se relaciona con el bit del mismo lugar en la otra
cantidad teniendo en cuenta que se empieza por la izquierda, y si falta se rellena con
ceros.)

36
0b11100 & 0b00111 = 0b00100 debido a que solo el dígito del centro es 1 en las
dos cantidades.

9 & 7 = 0b1001 & 0b0111 = 0b0001 debido a que solo el 1er digito es igual a 1 en
ambas cantidades.

&& Se usa para evaluar si dos condiciones se cumplen al mismo tiempo (No para
comparar bits sino situaciones).

&& es la operación lógica AND o Y que compara dos situaciones.

Si (X >5) && (Y > 10) entonces los dos son mayores que 5. si cumplen
Si (X<5) && (Y>10) entonces solo uno es mayor que 5. no cumplen
| es la operación OR o O en español y compara dos cantidades o el valor de dos
variables bit a bit y cuando al menos una es 1 el resultado es 1 y si ambas son iguales a
0 entonces el resultado es 0.

0b0 | 0b0 =0b0 ; 0b0 | 0b1 =0b1, 0b1 | 0b0 =0b1; 0b1 | 0b1=0b1; donde haya un 1
la respuesta es 1

0b111000 | 0b000001 = 0b111001;

9 | 5 = 0b1001 | 0b0101 = 0b1101;


Nota: esa linea vertical es el signo alt 124 (En código ASCII).

|| compara varias situaciones y si al menos una se cumple es resultado es 1

Si (A>2) || (B>2) cualquiera es mayor que 2 si cumplen.


Si (A>2) || (B=1) entonces, ya hay una mayor que 2 si cumplen.
Si (A=1) || (B=1) entonces, no hay una mayor que 2 no cumplen

El siguiente comando funciona para cualquier cantidad, pero debido a que los puertos
que más tienen bits (son B, C y D) tienen 8 bits, y el número más grande que se puede
escribir con ellos es 255, es decir el número 11111111 en binario, solo me referiré a
cantidades hasta 255 que es la cantidad más alta que puedes representar en un puerto de
8 bits con todos los pines en alto

Nota: Este operador se consigue fácilmente con el código ASCII 124


Presione la tecla (ALT) y sin soltarla 1, 2, 4 y suéltela.

>> significa desplazamiento de bits hacia la derecha.

Así, si a = 49 en decimal, entonces en binario a=0b00110001 debido a que siempre


escribimos estos números con 8 bits para entendernos mejor con las computadoras.

Luego si aplicamos la operación b = (a>>2), esto quiere decir que se deben eliminar
los dos bits más hacia la derecha, y se corren los otros 6 bits dos lugares a la derecha y
los que falten se rellenan de 0 (ceros)

37
Si a = (0b00110001) y b = (a>>2)  b=(0b00001100) y se pierden el 1 y el 0 que
estaban más hacia la derecha)

Si a = (49) y b = (a>>2)  b=(12) si colocamos los valores en código decimal,


ocurre lo mismo, pero sería muy difícil explicarlo debido a que la operación se realiza
en código binario.

Nota: Debido a que los puertos B, C, D, y en general los puertos tienen 8 bits (8
cablecitos o pines de salida y/o entrada)

Ejemplo c=255 en binario c=0b11111111 siempre se escribe con 8 bits,


d = (c>>5) entonces d = (0b00000111), se perdieron cinco unos y fueron
reemplazados por ceros.

<< significa desplazamiento de bits hacia la izquierda

Ejemplo e = 129 (en decimal) ; e=(0b10000001) en binario


f = (e<<4)  f = (0b00010000), se corrió 4 lugares hacia la izquierda, el primer 1
se perdió.

~ Significa complemento a, en binario el complemento de 1 es 0 y el complemento de


0 es 1. o sea 1 = ~0 y 0 = ~1.

Entonces si a = (00011000)  ~a = (11100111), cambian todos los valores.


Si procedieramos a hacer lo mismo pero presentando las cantidades en decimal, bastaría
con restarle a 255 es cantidad.
Ejemplo: ~100 =255-100 = 155 ó 0b11111111-0b01100100=0b10011011

% es el operador de residuo o resto, así 20/3 =6 y el resto es 2

a =20%3 =2  a=2

El operador o exclusivo (exor) ^ significa (uno solo) que en la relación entre dos
cantidades binarias si los bits que están en el mismo lugar son iguales el resultado es 0
y si son diferentes el resultado es 1, es como decir (O es uno, o es el otro; pero ni
ninguno ni los dos, es como preguntar si son diferentes)

1^1=0 ; 0^0=0 ; 1^ 0=1 ; 0 ^ 1=1

(0b11001100) ^ (0b01010101) = (0b10011001)

38
LISTA DE COMANDOS Y DE DIRECTIVAS A EXPLICAR

#define Realciona dos argumentos, uno reemplaza al otro.


#include < > Para incluir programas o datos de microcontroladores.
#device adc=10 Para declarar el uso de modulos CCP o convertidor A/D
#use delay (clock=x ) Para indicar la frecuencia x del cristal resonador.
#use rs232 (baud=9600, xmit=pin_c6, rcv=pin_c7) Declara el uso de
comunicación serial por los pines pin_c6 y pin_c7.
#use fast_io(t) Pone a trabajar a un puerto t en alta velocidad.
a=getc(); Para esperar entrada de datos por el puerto serial.
putc(x); Para enviar un carácter por el puerto de comunicación serial.
puts(“cadena”); Para enviar palabras por el puerto de comunicación serial.
pirntf(lcd_data,” literales %var “, variable); Para imprimir textos en
pantallas.
a=kbhit(); Captación de un carácter en el puerto serial.
x=input_Z(); Lectura de entrada por Z, Z es un puerto A,B,C,D,E.
output_bit(b5,1); Poner en estado 1 al pin_b5.
output_high(pin_c2); Poner en estado 1 al pin_c2.
output_low(pin_b7); Poner en estado 0 al pin_b7.
port_b_pullups(1); Activa resistencias de protección del puerto B.
port_b_pullups(0); Desactiva resistencias de protección del puerto B.
set_tris_x(0bzzzzzzzz) x es el puerto y z (1/0) entrada o salida.
delay_ms(pausa) Retardo: pausa es la cantidad de milisegundos.
delay_us(pausa) Retardo: pausa es la cantidad de microsegundos.
enable_interrupts(int_xxx) habilita una función de interrupción.
disable_interrupts(int_xxx) inhabilita una función de interrupción.
ext_int_edge(l_to_h) ext_int_edge(h_to_l) (señal de flanco).
x=get_rtcc(); x=get_timer0(); Lectura del valor del timer0.
x=get_timer1(); Lectura del timer1.
x=get_timer2(); Lectura del timer2.
setup_timer_0(rtcc_ext_l_to_h); Configura la lectra de flanco subida.
setup_timer_0(rtcc_ext_h_to_l); Configura la lectura de flanco bajada.
set_rtcc(k); k es el valor que se le asigna al timer0 (precarga).
set_timer1(k); k es el valor que se le asigna al timer1 (precarga).
set_timer2(k); k es el valor que se le asigna al timer2 (precarga).
set_timer_1(t1_external); Configuración del timer1.
set_timer_2(t2_div_by_1,255,1); Configuración del timer2.

x=abs(y); Cálculo del valor absoluto de y


x=acos(y); Cálculo del arco coseseno de y
x=asin(y); Cálculo del arco seno de y.
x=atan(y); Cálculo del arco tangente de y
x=atoi(cadena); Convierte una cadena de números en su valor núerico.
x=atol(cadena); Convierte una cadena de números en su valor númerico.
x=atof(cade.na); Convierte una cadena de números en su valor númerico.
x=ceil(y); Cálcula el mayor entero de y.

39
x=exp(y); potencia de 10 x=10^y.
x=floor(y); Calcula el menor entero de y.
x=log(y); Calcula el logaritmo natural de y.
x=log10(y); Cálcula el logaritmo decimal de y.
x=sqrt(y); Cálcula la raiz cuadrada de y.
setup_adc_ports(puertos analógicos); Configura los puertos analógicos.
setup_adc(adc_clok_div_32); Determina un tiempo para la conversión.
set_adc_channel(x); Determina pin x de lectura analógico.
y=read_adc(); Carga en y, el valor de la lectura del convertidor A/D.
setup_ccp1(capture_re); Configura la lectura de flanco en subida del CCP1.
setup_ccp1(capture_fe); Configura la lectura de flanco en bajada del CCP1.
setup_ccp2(capture_re); Configura la lectura de flanco en subida del CCP2.
setup_ccp2(capture_fe); Configura la lectura de flanco en bajada del CCP2.
setup_ccp1(ccp_pwm); Configura el mdulador CCP1 para ancho de pulso.
setup_ccp2(ccp_pwm); Configura el modulador CCP2 para ancho de pulso.
bit_clear(x,g); Pone el pin g de la variable x en 0.
bir_set(x,k); Pone el pin k de la variable x en 1.
rotate_left (x,3); Rotación de los bits 3 lugares hacia la izquierda.
rotate righ (x,1); Rotación de los bist 1 lugar hacia la derecha.
shift _left (x,3); Desplazamiento de 3 bits a la izquierda es igual a <<.
shift_right(x,7) Desplazamiento de 7 bits a la derecha es igual a >>.
swap(x); Intercambio de los nibles de x.
Funciones de interrupción.
#int_ccp1
#int_ccp2
#int_ext
#int_ext1
#int_ext2
#int_rb
#int_rc
#int_rtcc
#int_timer2
#int_timer3

If(x = =1) { }; else { }; Evaluación de una condición ejecute .

While (x= =0) { }; Mientras se cumpla una condición ejecute.

Do { } while (x = =1); Haga {} mientras x sea igual a 1.

Ejecuta una acción dependiendo del valor de var.


Switch (var)
{
Case 0:
Break ;
Case 1:
Break ;
Case 2:
Break ; }

40
En todo caso, si quiere tener la lista completa de comandos y directivas acceda al menú
help, Built in functions, operators, statements, etc, en la sección index del menú Help
toda la lista con una breve explicación en ingles.

Ahora algunos detalles del PCW Compiler

41
Menú File

New: Se usa para comenzar un programa nuevo. (Un programa que aún no existe)

Open: Se usa para abrir un programa que ya está hecho o al menos ya lo ha comenzado,
para modificarlo o continuarlo.

Reopen: Se usa igual que open, pero este muestra los últimos programas hechos.

Save: Sirve para grabar el programa en el directorio original.

Save as: Se usa para grabar el programa en un directorio específico.

Close: Se usa para cerrar un programa.

Close all: A veces en una misma pantalla se tienen varios programas independientes, o
que trabajan en conjunto como librerías, este los cierra a todos a la vez.

Print: Se usa para imprimir el código del programa sobre papel con una impresora.

Exit: Para salir del PIC C

Menú Project

42
New: Hay programas que realmente son un grupo de programas, y que a su vez
trabajan con ciertos archivos, bases de datos, etc, a esto se le llama Project (Proyecto).
Y este es el comando para comenzar uno.

Open: Se usa para continuar un proyecto.

Nota: Hay muchas opciones que el promedio de la gente que usa computadores ya las
conoce y sabe usar debido a que están en los menús de los diferentes programas bajo
ambiente windos, así que las opciones cuya explicación sea obvia las omitiré para no
engrosar este libro,

Menú Edit

Undo: Se usa cuando se comete un error a sabiendas que se ha cometido o por


accidente, con él podemos retroceder ese último paso y salvarnos de tener que revisar
todo el código.

Copy from file: Se usa para insertar parte de un código cuando estamos escribiendo un
programa y sabemos que esa parte o rutina la tenemos hecha en un programa que ya está
guardado, entonces lo podemos importar y pegarlo en el código del que tenemos en
pantalla.

Paste to a file: Lo usamos cuando queremos pegar una parte de un programa que
tenemos en pantalla en otro que está en el disco duro.

43
Menú Compile

Compile : Lo usamos para compilar el programa que tenemos en pantalla.

Menú View

Nota: este menú tiene opciones importantes y que son muy útiles cuando se está
programando.

Data sheet: Nos muestra la hoja de datos PDF del microcontrolador que tenemos
puesto en la primera línea de programa #include <código del pic> que es muy
importante tenerla a mano para conocer sus características, inclusive el diagrama del
pinado, también aparece el acceso al manual de referencia del PIC C donde aparecen las
explicaciones de como usar los comandos (en ingles).

44
Valid #fuses: Nos muestra las directivas válidas para el microcontrolador que aparece
señalado en la primera línea del programa #incluye <código de microcontrolador>.

Valid interrupts: En PIC C existen unas funciones llamadas funciones de interrupción,


éstas son subrutinas independientes del cuerpo principal del programa, y que son
llamadas por la ocurrencia del algún evento, por ejemplo un pulso en un pin
determinado, cuando esto sucede el programa salta directamente a una subrutina
específica, la ejecuta y luego vuelve al sitio desde donde salto, salvo que en la rutina
haya un anidamiento u ocurra otro salto o otra subrutina.

45
Las demás opciones, si bien son importantes, creo que no las utilizaremos al menos en
este primer libro, pero sería bueno que buscarán algo de información sobre ellas como
parte su cultura técnica.

Comandos explicados con ejemplos dentro de programas.


Nota: En cada programa se explicarán sólo los comandos que no hayan sido explicados
con anterioridad en otro programa o subrutina, si se consigue algún comando no
explicado es porque debe estar en un programa anterior.

#define a 8
#define es una directiva llamada macro, que asigna o relaciona dos entidades, en este
caso #define x 8, es asignarle a la letra x el valor de 8.
Nota: El código de los programas estará escrito en negrita, la explicación que aparece a
la derecha === > No forma parte del programa (no la copie).

Ejemplo en un programa:

#incluye <16F84A.h> Informa a PIC C cual es el microcontrolador.


#fuses hs,nowdt,put Inflorma el tipo de oscilador, perro gaundian
y establilización de sistema
#use delay (clock=4000000) Establece la velocidad del cristal oscilador
#define x 8 Establece la relación entre x y 8 (x=8)

void main() Indica cuerpo principal del programa


{ Llave inicio del cuerpo del programa
Int a; Declaración de la variable a
a = 5 + x; Operación de sumar
} Llave de final del programa

En este caso y a pesar de que no podemos ver ningún resultado en algún circuito, el
sumar 5+x es lo mismo que sumar 5 + 8, debido a que definimos a la letra x como el
numero 8.

46
Programa ejemplo.
Nota: output_high(pin_b0); Comando que enciende un led en pin_b0

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)

#define a output_high(pin_b0)
#define b output_high(pin_b1)
#define c output_high(pin_b2)

void main()
{
a;
b;
c;
}

En este caso, y así como en el primer programa sólo se encendió un led en el pin _ b0,
ahora encendimos tres (3) leds, uno en pin _ b0, otro en pin_b1 y otro en pin_b2,
porque cuando definimos (a) como output_high(pin_b0) y colocamos a; en la línea de
programa, el PIC C la reconoce como el comando con el que se definió y así lo ejecuta,
entonces enciende un led en el pin 0 del puerto B (pin_b0), de la misma manera que lo
hará con pin_b1 y pin_b2, en este caso los tres led encienden consecutivamente, pero a
una velocidad tal que pareciera que encendieran al mismo tiempo, ya que la diferencia
de tiempo es de unos microsegundos (imperceptible para el humano).

De esta manera podemos ejecutar mechas veces un comando u operación que


previamente definimos solo con llamar a una letra.

47
Programa ejemplo.

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)

#define a output_high(pin_b0) Comando que enciende el pin_b0


#define b output_low(pin_b0) Comando que apaga el pin_b0

void main()
{
a;
b;
a;
b;
a;
b;
}

Nota: Use el circuito anterior


El programa anterior enciende y apaga un led en el pin_b0 tan rápido, que es muy difícil
que lo note, apenas se dará cuenta que la intensidad de iluminación es baja, pero no lo
verá apagarse.
delay_ms(milisegundos);
delay_us(microsegundos);
delay es un comando que se usa para detener o causar u determinado retardo y
paralización en la ejecución de un programa, delay_ms(1000); causará una parada de
1000 milisegundos, o sea un segundo en la ejecución de un programa cuando se llega a
esta línea del programa, de la misma manera actuará delay_us(1000); pero este causará
un retardo de 1000 microsegundos que es lo mismo que 1 milisegundo.

Programa ejemplo.

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)

Void main()
{
output_high(pin_b0);
delay_ms(1000); Paralización por 1 segundo del programa.
output_high(pin_b1);
delay_ms(500) Paralización por ½ segundo del programa.
output_high(pin_b2);
}

Este programa encenderá el led del pin_b0, luego 1.0 segundo después encenderá el
pin_b1 y 0.5 segundo más tarde el pin_b2.

48
Use el circuito anterior

output_low(pin_puertonumero);

Si encendemos algo con un programa, también podemos apagarlo con el mismo


programa, después de una determinada cantidad de tiempo, así en este programa
encenderemos los leds y luego los apagaremos, el comando
output_low(pin_puertonumero); nos sirve para poner un pin en voltaje bajo (0 Voltios).

Se encienden los tres leds por 5.0 segundos y luego se apagan los todos.

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
Void main()
{
output_high(pin_b0);
output_high(pin_b1);
output_high(pin_b2);
delay_ms(5000);
output_low(pin_b0);
output_low(pin_b1);
output_low(pin_b2);
}

Se encienden los tres leds uno por uno cada 1 segundo y luego se apagan los tres uno
por uno cada 1 segundo.

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
Void main()
{
delay_ms(1000);
output_high(pin_b0);
delay_ms(1000);
output_high(pin_b1);
delay_ms(1000);
output_high(pin_b2);
delay_ms(1000);
output_low(pin_b0);
delay_ms(1000);
output_low(pin_b1);
delay_ms(1000);

49
output_low(pin_b2);
}
El circuito se mantiene, con el fin de solo reformar el programa y ejecutarlo
Comandos y sentencias.

for ( ; ; ) { };

while (condición) { };

do { }; while (condición)

Los comandos de repetición de un lazo se pueden hacer de tres maneras.

1) Lazo infinito: es cuando la condición que se establece no va a cambiar bajo


ninguna circunstancia, por ejemplo en valor del número 1 while (1).
2) Lazo finito: es cuando la condición que se establece puede cambiar durante la
ejecución del lazo repetitivo, por ejemplo cuando se va incrementando el valor
de a hasta llegar a un valor mayor a 100 White (a<=100).
3) Lazo infinito: Cuando se establece un contador sin parámetros.

En el primer y tercer caso el programa nunca deja de ejecutarse, y para interrumpirlo


tendrá que hacerlo desde el exterior: (quitando la energía), y en el segundo caso cuando
el valor de a supere el valor de 100, este lazo terminará su ejecución y pasará a la rutina
siguiente o terminará el programa.

Programa ejemplo.

Enciende y apaga cada seg.(un led se mantiene encendido 1 seg., se apaga y al pasar
otro segundo y se enciende el siguiente led en el puerto b).

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
Void main()
{
While (1)
{
output_high(pin_b0);
delay_ms(1000);
output_low(pin_b0);
delay_ms(1000);
output_high(pin_b1);
delay_ms(1000);
output_low(pin_b1);
delay_ms(1000);
output_high(pin_b2);
delay_ms(1000);
output_low(pin_b2);
delay_ms(1000);

50
output_high(pin_b3);
delay_ms(1000);
output_low(pin_b3);
delay_ms(1000);
output_high(pin_b4);
delay_ms(1000);
output_low(pin_b4);
delay_ms(1000);
output_high(pin_b5);
delay_ms(1000);
output_low(pin_b5);
delay_ms(1000);
output_high(pin_b6);
delay_ms(1000);
output_low(pin_b6);
delay_ms(1000);
output_high(pin_b7);
delay_ms(1000);
output_low(pin_b7);
delay_ms(1000);
}
}

Nota: se recomienda ponerle una resistencia de 220 ohm a cada led, pero si no lo pone y
solo hace pruebas de minutos no se dañará el led.

Hasta ahora hemos visto comandos para controlar la salida de un solo pin de algún
puerto, pero también están los comandos que trabajan con el puerto completo, y en vez
de tener que repetir 8 veces la misma línea para encender 8 leds, lo hacemos con una
sola línea, claro está, todo depende de la necesidad del programa y la idea que se quiera
llevar a cabo.

Nota: No olvide todo lo que se explicó en un aparte anterior con respecto al código
binario y al código decimal.

51
-Los comandos para controlar la salida de un puerto entero no interfieren con los
comandos para controlar la salida de un pin particular del mismo puerto, ya que la que
prevalece es la última que se ejecutó, es decir si usted por comando de puerto entero
hace que se enciendan todos los pines y luego con un comando de pin solitario apaga
uno solo, este se apagará y permanecerá apagado hasta que otro comando le cambie la
condición de estado.

output_x(0bcodigo binario);
output_x(código decimal );

Al PIC C cuando le queremos dar un valor para que lo ponga como señales de voltaje
alto (1 en digital significa 5 voltios en analógico en un pin de un puerto) en un puerto,
se lo tenemos que dar en alguno de los varios códigos numéricos que este lenguaje
entiende, pero los códigos numéricos que nos interesan son a) código decimal, b) código
binario, ahora lo que necesitamos es tener una tabla en donde aparezca la conversión o
la equivalencia entre los dos. De cualquier manera hay un método para convertir cada
uno en el otro. - explicado en la Pág. 19.-

Entonces, si queremos que un puerto se encienda por completo lo único que tenemos
que hacer es ejecutar uno de los siguientes comandos
Nota: 255 en decimal es 0b11111111 en binario “255 = 0b11111111”, sin embargo si
yo se le doy al PIC C directo sin decirle en que código está, este lo asumirá
directamente en decimal, pero si se lo quiero dar en binario, obligatoriamente se lo
tengo que informar de antemano pegado con el numero prefijo 0b

Ejemplos:

Encienda todo el puerto b en decimal: output_b(255);


Encienda todo el puerto b en binario: output_b(0b11111111);

Esto es útil saberlo, ya que unas veces quisiéramos controlar el puerto y ver lo más
parecido posibles el valor que entregamos y lo que se enciende y se apaga en el puerto
(usamos binario), pero otras veces si lo que queremos es enviar una cantidad en decimal
digito por digito para que sea leída por algún componente o circuito conectado al puerto
entonces usamos decimal.

52
Ejemplo: Encender en el puerto b.
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
set_tris_a(0b11111); == > configura todo el puerto a como entradas
set_tris_b(0b00000000); == > configura todo el puerto b como salidas

output_b(0); ===== > apaga todo el puerto b en decimal


delay_ms(1000); ===== > retardo de 1 segundo
output_b(255); ===== > enciende todo el puerto b en decimal
delay_ms(1000);
output_b(0b00000000); ===== > apaga todo el puerto b en binario
delay_ms(1000);
output_b(0b11111111); ===== > enciende todo el puerto b en binario
delay_ms(1000);
output_b(15); == > enciende la mitad del puerto b (nible bajo)*
delay_ms(1000);
output_b(0b11110000); === > enciende el nible alto y apaga el bajo pto b
}

Nota: como los puertos generalmente tienen 8 bits, estos se pueden separar en dos
mitades de 4 bits, la parte baja bits 0,1,2,3 y parte alta bits 4,5,6,7. y estos son llamados
nible bajo y nible alto.

Cuando trabajamos con microcontroladores, muchas veces la salida que tenemos que
dar por un puerto depende de la entrada o lectura de datos que tengamos en el
programa, sin embargo puede ocurrir que debamos esperar un cierto tiempo después de
recibida parte de una información para poder tomar alguna acción, es entonces cuando
no podemos cambiar los estados de los pines de algún puerto a cada centésima de
segundo (sería un locura para muchos procesos químicos o mecánicos), pero; si
necesitamos tener la información todo el tiempo a la vista y almacenada en una variable
que está controlando un puerto de 8 bits, y que en un pin nos controle una válvula, otro
pin el paso de corriente a una resistencia térmica, con otro la refrigeración, con otro un
motor que agite una mezcla, etc., y también poder chequear cual es el estado de alguno

53
(un BIT o pin) de esos procesos que este puerto controla, entonces, en esa situación es
cuando necesitamos mantener toda la información en una variable que podamos
manipular, y según se vaya desarrollando un proceso poner a 0 o poner a 1 un
determinado BIT (pin) de esta variable, la que digamos que cada 5 o 10 minutos se tome
la acción de ponerla en el puerto de salida controlando o monitoreando el proceso,
ahora, para situaciones como está necesitamos los siguientes comandos.

bit_set(variable,pin);
bit_clear(variable,pin);
bit_test(variable,pin);

bit_set(x,2);
Lo usamos para poner a 1 el bit nro. 3 (el bit nro. 2 es el 3ro, no olvide que se
enumeran desde el 0) de la variable x en su código binario, así, si X=16 en binario
X=0b00010000 y ejecutamos este comando ocurrirá lo siguiente

X= 00010000 antes X=16 ó X=0b00010000


Bit_set(x,2)
X= 00010100 después X= 20 ó X=0b00010100

Nota: Si el bit nro. 2 hubiera estado antes en 1, su condición no cambiaría ya que no se


puede encender lo que ya está encendido.

bit_clear(x,3);
Lo usamos de la misma forma que bit_set(x,2) pero ente apaga el bit 3 si está encendido
antes de aplicar el comando.

X= 00011100 antes X=28 ó X=0b00011100


Bit_clear(x,3)
X= 00010100 después X= 20 ó X=0b00010100

z = bit_test(x,2);
Lo usamos para conocer el estado de un determinado bit de una variable, en este caso el
3er bit de la variable X;

x=15 ò x=0b00001111

a) z= bit_test(x,2); ==== > z será igual a 1

b) z= bit_test(x,5); ==== > z será igual a 0

output_bit(pin_pd,v); salida del valor de v por el pin d del puerto p.


(v solo puede valer 0 o 1, d vale entre 0 y 7 y p un puerto a,b,c,d).
output_bit(pin_b0,1); se pone a nivel alto en pin_b0.

54
Programa ejemplo:

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=8000000)
void main()
{
Int x;
Int y;

set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000); ===== > normalmente apago el puerto que
configuro como salida.
x=0b11110000;
output_b(x);
delay_ms(1000);
bit_clear(x,7); ====== > ahora x=(0b01110000)
output_b(x);
delay_ms(1000);
bit_set(x,0); ====== > ahora x=(0b01110001)
output_b(x);
delay_ms(1000);
y=bit_test(x,0); ====== > ahora y=1
output_bit(pin_b0,y); ====== > salida del valor de y por el pinb0 (0)
delay_ms(1000);
y=bit_test(x,3); ====== > ahora y=0
output_bit(pin_b0,y); ====== > salida del valor de y por el pinb0 (1)
}
Nota: output_b(x); Es la salida por el puerto del valor x, este valor irremediablemente se
mostrará en binario porque es salida por los pin de B.

rotate_left(variable,rotación)
rotate_right(varable,rotación)

55
Existen situaciones en las que quisiéramos rotar los valores de los bits dentro de una
variable, por ejemplo si tenemos un solo led y queremos conocer el estado de todos los
bits, no nos queda más remedio que mover el led a cada uno de los pines de un puerto, o
mover los valores de los bits de la variable en un mismo puerto manteniendo el led
colocado en un pin fijo.

Ejemplo:

x=0b00011000
rotate_right(x,1) ahora x=(0b00001100) los bits se corrieron un lugar
hacia la derecha y el primer bit0 de la derecha se
colocó en el bit7 a la izquierda.
Rotate_right(x,3) ahora x=(0b10000001) los bits se corrieron tres
Lugares a la derecha, como ellos se mueven
como una cadena, el 1er 1 dió la vuelta y el 2do 1
se quedó en el último lugar.

El comando rotate_xxxx no permite la perdida de bits, los valores de los bits que salen
por la izquierda reingresan por la derecha, y los que salen por la derecha, reingresan por
la izquierda, con este comando, con un solo led colocado en cualquier pin de un puerto
y haciendo 8 rotaciones de 1 bit cada una, podemos inspeccionar el valor de todos los
bits de una variable de 8 bits, y al final queda en la variable o puerto el mismo valor.
Programa ejemplo.

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
int a,b,c;
a=(0b00000001);
b=0;
c=0;

while (1)
{
while (b<9) === > Lazo hasta que b=9.
{
output_b(a);
delay_ms(500);
rotate_left(a,1); ==== > Rotación de un lugar a la izquierda cada 0.5 seg.
b=b+1; ====> Incremento de b.
c=0;
}

56
while (c<9) === > lazo hasta que c=9.
{
output_b(a);
delay_ms(500); ====> rotación un lugar a la derecha cada 0.5 seg
rotate_right(a,1);
c=c+1;
b=0;
}
}
}

Nota: b=0 y b=0b00000000 es lo mismo.


a=1 y a=0b00000001 es lo mismo.
x=2 y x=0b00000010 es lo mismo.

Al igual que rotate_right y rotate_left, también existen dos comandos que funcionan
de la misma forma, pero que estos no retornan los valores que salen por un lado
reintroduciéndolos por el otro (sale por la derecha reingresa por izquiera y viceversa),
estos comandos son shift_left(variable,desplazamiento de bits a la izquierda)
shift_right(variable,desplazamiento de bits a la derecha),
se pueden usar para limpiar los bits de una variable, dejarlos en cero o para mover un
bit a un lugar específico.

Ejemplo de parte de un programa que desplaza los bits.


Cuando comenzamos a desplazar los bits de una variable, bien sea a la izquierda
shift_left(var,despl) o a la derecha shift_righ(var,despl.), éstos bits que se desplazan son
reemplazados por ceros, hasta que llega el momento en el que solo tenemos ceros en los
bits de la variable; pero si comezaramos a realizar el proceso inverso, (luego del
shift_left hacer shift_righ) los 1 unos que se salieron por alguno de los lados, se pierden
y solo retornarán 0.

x=(0b11111111);
shift_left(x,1); ahora x=(0b11111110);
shift_left(x,1); ahora x=(0b11111100);
shift_left(x,1); ahora x=(0b11111000);
shift_left(x,3); ahora x=(0b11000000);
shift_left(x,2); ahora x=(0b00000000); Se perdieron todos los 1.
shift_right(x,4); ahora x=(0b00000000);

57
Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);

x=(0b11111111);
output_b(x); ===== > salida por el puerto b de x
delay_ms(2500); ===== > pausa de 2.5 seg
shift_left(x,1); ahora x=(0b11111110); corrió un lugar a la izquierda
output_b(x);
delay_ms(500);
shift_left(x,1); ahora x=(0b11111100); corrió otro lugar a la izquierda
output_b(x);
delay_ms(500);
shift_left(x,1); ahora x=(0b11111000); corrió otro lugar a la izquierda
output_b(x);
delay_ms(500);
shift_left(x,3); ahora x=(0b11000000); corrió tres lugares a la izquierda
output_b(x);
delay_ms(500);
shift_left(x,2); ahora x=(0b00000000); últimos dos lugares a la izq.
output_b(x);
delay_ms(500); }
-------------------------------------------------------------------------------------
Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
x=(0b11111111);
output_b(x); ===== > salida por el puerto b de x
delay_ms(2500); ===== > pausa de 2.5 seg.
shift_right(x,1); ahora x=(0b01111111); desplazamiento a la
output_b(x); derecha de un bit
delay_ms(500);
shift_right(x,1); ahora x=(0b00111111); desplazamiento a la
output_b(x); derecha de otro bit
delay_ms(500);
shift_right(x,1); ahora x=(0b00011111); desplazamiento a la

58
output_b(x); derecha de otro bit
delay_ms(500);
shift_right(x,3); ahora x=(0b00000011); desplazamiento a la
output_b(x); derecha de tres bits
delay_ms(500);
shift_right(x,2); ahora x=(0b00000000); desplazamiento a la
output_b(x); derecha de dos bits
delay_ms(500);
}

El mismo programa que el anterior pero con desplazamiento a la derecha.

El comando desplazamiento de bits, bien sea a la derecha o a la izquierda tiene su


versión en comando reducido, pero este ya fue explicado, por eso aquí solo expondré el
programa, funciona igual a los comandos shift_left(x,2); es igual que x =(x<<2); a la
izquierda
shift_right(x,3) es igual que x =(x>>3); a la derecha

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);

x=(0b11111111);
output_b(x); ===== > salida por el puerto b de x
delay_ms(2500); ===== > pausa de 2.5 seg.
x = (x>>1); ahora x=(0b01111111);

59
output_b(x);
delay_ms(500);
x = (x>>1); ahora x=(0b00111111);
output_b(x);
delay_ms(500);
x = (x>>1); ahora x=(0b00011111);
output_b(x);
delay_ms(500);
x = (x>>3); ahora x=(0b00000011);
output_b(x);
delay_ms(500);
x = (x>>2); ahora x=(0b00000000);
output_b(x);
delay_ms(500);
}

El comando swap(x); intercambio de nibles.


Los puertos (B, C, D) tienen 8 bits (pins de conexión con el exterior), el puerto (A) tiene
5 o 6 bits dependiendo del microcontrolador y el puerto E tiene 3 bits, ahora en los
puertos que tienen 8 bits, éstos bits se separan en dos partes, los bits de baja o nible
bajo compuesto por los bits 0, 1, 2, 3 y los bits de alta o nible alto compuesto por los
bits 4, 5, 6 y 7.
En infinidad de casos, bien sea en programas o en operaciones de transferencia de datos,
necesitamos enviar todo el contenido de un puerto (digamos 8 canales) por una
conexión que solo tiene 4 canales, entonces nos vemos en la necesidad de enviar la
información en dos mitades, pero con el problema de que solo hay comunicación por
los canales 0,1,2,3, entonces usamos el comando de intercambio de nibles, es decir,
intercambiamos los valores de los bits según la siguiente tabla.

El bit 0 pasa a ser el bit 4 y el bit 4 pasa a ser el bit 0 bit0  bit4
El bit 1 pasa a ser el bit 5 y el bit 5 pasa a ser el bit 1 bit1  bit5
El bit 2 pasa a ser el bit 6 y el bit 6 pasa a ser el bit 2 bit2  bit6
El bit 3 pasa a ser el bit 7 y el bit 7 pasa a ser el bit 3 bit3  bit7

Y así en una segunda transmisión enviamos la información del segundo nible (nible
alto).
Ahora y a pesar de que cualquier programador puede hacer esto sin ninguna dificulta,
existe un comando que hace esto de forma directa por nosotros y no tenemos que hacer
ningún programa, el comando swap(x);

Ejemplo.
x=(0b11110000);
swap(x); ===== > ahora x =(0b00001111);
swap(x); ===== > ahora x vuelve a ser (0b11110000);

Nota aclaratoria: (cuidado) Tenga en cuenta que esta operación también se le puede
aplicar a números en sistema decimal (entre 0 y 255) y si lo hace el valor del la cantidad
cambiará, por ejemplo.

60
X=0b00001111 o sea, 15 en decimal.
swap X, ahora X = 0b11110000, o sea 240 en decimal.

X=0b00000001 o sea 1 en decimal.


Swap X, ahora X=00010000, o sea 16 en decimal.

Nota:
Nunca pierda la noción que los números y las cantidades pueden ser a la vista iguales
pero las cantidades que representan no lo son.

Ejemplo:
* 11 es once en decimal; pero 11 tres en binario (0b11).

• 11 es once en decimal y 1011 también es once pero en binario.(0b1011).


Si de programación se trata, perdamos la costumbre que las cantidades sólo se escriben
en decimal y pensemos en los otros sistemas de numeración.

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int x;
x=(0b11110000);
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
delay_ms(2000);
while (1)
{ ======= > Lazo infinito
output_b(x);
delay_ms(1000);
x=swap(x); ====== > se mantiene intercambiando los nibles
}
}

61
Insisto: Pruebe el circuito sin los condensadores, si le funciona; ahórrese ese trabajo.(es
solo para hacer las pruebas).
El contador For (x=0; x<=100; x=x+incremento)
En muchos casos, tanto en programación normal, como en programación de
microcontroladores, etc, necesitamos darle a una variable un valor que vaya
aumentando o disminuyendo a una razón fija y preestablecida hasta un valor límite de
nuestra necesidad, para estos casos tenemos el contador:
For (x=0; x<=100; x=x+incremento) para ir en aumento.
For (x=100; x>=0; x=x-decremento) para ir disminuyendo.

Ejemplo: Este programa cuenta desde 0 hasta 255 con un retardo de 0.3 segundos y lo
presenta en el puerto b (recuerde que en el puerto B, lo verá en código binario).

Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);

for (x=0; x<=255; x=x+1)


{
output_b(x);
delay_ms(300);
}
}
Conteo creciente
-------------------------------------------------------------------------------

62
Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);

for (x=255; x>=0; x=x-1)


{
output_b(x);
delay_ms(300);
}
}

Conteo decreciente

switch (variable);
En muchos casos en programación necesitamos que el microcontrolador tome acciones
diferentes para valores deferentes de una misma variable, y bastaría simplemente con
utilizar condicionales (if (expresión)) para ejecutar una acción dependiendo del valor de
entrada, sin embargo y para evitar hacer más código de lo necesario, tenemos un
comando que discrimina el proceso a seguir dependiendo del valor de la variable de
entrada.

Ejemplo:
Este programa encenderá un led diferente cada vez, dependiendo del valor de y, el cual
variará entro 0 y 7. Para ello declararemos un contador de variable y, y cuando el valor
de y no esté entre las variables esperadas entonces encenderá todo el puerto, para ello
está la opción default: (entrada por defecto) la cual es opcional.

63
Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int y;

set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);

for (y=0; y<=12; y=y+1)


switch (y)
{
case 1: output_b(1);
delay_ms(1000);
break;
case 2: output_b(2);
delay_ms(1000);
break;
case 3: output_b(4);
delay_ms(1000);
break;
case 4: output_b(8);
delay_ms(1000);
break;
case 5: output_b(16);
delay_ms(1000);
break;
case 6: output_b(32);
delay_ms(1000);
break;
case 6: output_b(64);
delay_ms(1000);
break;
case 7: output_b(128);
delay_ms(1000);
break;
default : output_b(0);
break;
default : output_b(255);
delay_ms(1000);
break;
}

64
El mismo programa pero codificando las salidas en código binario y sin la opción
default (por defecto)
Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int y;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
for (y=0; y<=10; y=y+1)
switch (y)
{
case 1: output_b(0b00000001);
delay_ms(1000);
break;
case 2: output_b(0b00000010);
delay_ms(1000);
break;
case 3: output_b(00000100);
delay_ms(1000);
break;
case 4: output_b(0b00001000);
delay_ms(1000);
break;
case 5: output_b(0b00010000);
delay_ms(1000);
break;
case 6: output_b(0b00100000);
delay_ms(1000);
break;
case 6: output_b(0b01000000);
delay_ms(1000);
break;
case 7: output_b(0b10000000);
delay_ms(1000);
break;
case 0: output_b(0b00000000);
dealy_ms(1000);
break;
}

65
Circuito recomendado para los programas anteriores.

Ya es hora de aprender a trabajar con entradas de pulsos, o de datos, por un pin


específico o por un puerto completo, etc, en fin a introducir información de cualquier
tipo desde afuera del microcontrolador usando sus los pines como canal de
comunicación.

Nosotros cada vez que usamos una computadora para cualquier actividad, la manejamos
introduciéndole información por el teclado (no siempre; pero casi siempre), y ella nos
envía información por el monitor, la impresora, emitiendo sonidos, etc, bueno, en los
microcontroladores el teclado es cualquier puerto que configuremos como puerto de
entrada, para ello basta con darle la información de configuración en una línea del
programa set_tris_puerto(0b11111111); en donde puerto puede ser a, b, c, d, e, etc.

Al igual que para controlar las salidas (pines,) nosotros podemos controlar el leer un
pin específico o leer todo el puerto en un solo paso, todo depende del programa y la su
necesidad, para ello colocamos en el circuito de los pines de entrada una combinación
en paralelo de resistencia y pulsador de la siguiente manera: (En este caso en el puerto
a).

Vea el diagrama de instalación del microcontrolador para poder darle entrada de pulsos
por sus pines del puerto A, hága esta instalación o montaje que desde ahora en adelante
vamos a trabajar con este circuito.

66
Nota: Este diagrama es eléctricamente igual al anterior, pero a los pines 17, 18, 1, 2 y 3
se le debe colocar una resistencia de 100000 (100k) ohmios conectados al negativo (0
voltios) y un swiche pulsador conectado a positivo (5 voltios). La resistencia sirve para
que esa entrada no esté flotante mientras no se está usando el swiche, sino que tenga
algo de corriente que la estabilice en polaridad opuesta a la señal que le vamos a dar.
(Nota: las uniones están engrosadas para evitar confusiones.)

Sin embargo en algunos microcontroladores este trabajo de colocar resistencias para


limitar la corriente de entrada a los pines y protegerlos de una sobre corriente ya está
hecho dentro del mismo chip, lo que hay que hacer es activar la protección, colocando
en una línea del programa el comando port_b_pullups(1); para activar las resistencias
de protección y port_b_pullups(0); para desactivarlas.
Nota: la letra b indica el puerto en el que se va a activar la protección, tengo entendido
que casi todos los pics las tienen en el puerto b, y deberá verificar en el manual del
microcontrolador si la posee en los demás puertos.

Input(pin_pd);
a=input(pin_a0); y a=!input(pin_a0);
El comando input(pin_a0); o a=!input(pin_a0); es un comando para hacer lectura por el
pin_a0 del puerto A, la diferencia está en si la resistencia se coloca a polaridad negativa
y el pulsador a polaridad positiva y viceversa, (yo uso normalmente el puerto A como
puerto de entrada, por eso en casi todos los programas su configuración es
set_tris_a(0b111111), pero esto es indiferente, cualquier pin del cualquier puerto puede
ser un pin de entrada), lo que se debe tener pendiente para que esto funcione bien es que
hay que estabilizar el pin a el voltaje opuesto a la señal de entrada con una resistencia
alta, yo he usado resistencias de 100k y me funciona bien.

El siguiente programa enciende un led en el puerto b cuando se presiona el swiche del


puerto a correspondiente a ese pin, es decir si presionas en swiche del pin_a0 se
enciende el led del pin_b0, si presiones el pin_a1 se encenderá entonces el led del
pin_b1, así hasta el pin_b5.

67
Nota: las variables se llamarán a0, a1, a2, a3 y a4, y esto no tiene nada que ver con que
se vayan a usar en los pines que tienen el mismo nombre, pin_a0, pin_a1, pin_a2,
pin_a3 y pin_a4, lo hago para tener una mejor guia de trabajo en el programa.

Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
Int1 a0,a1,a2,a3,a4; ==== > Las variables declaradas con int1 solo
set_tris_a(0b11111); admiten dos valores 0 ó 1
set_tris_b(0b00000000);
output_b(0b00000000);
while (1) Bucle infinito.
{
a0=(pin_a0); ======= > Lee el valor del pin_a0 y lo asigna a la
a1=(pin_a1); variable a0
a2=(pin_a2);
a3=(pin_a3);
a4=(pin_a4);
output_bit(pin_b0,a0); ====== > Saca el valor de la lectura del pin_a0
output_bit(pin_b1,a1); por el pin_b0
output_bit(pin_b2,a2);
output_bit(pin_b3,a3);
output_bit(pin_b4,a4); } }
Así de esta manera el valor que está en la entrada de los pines del puerto A, se reflejará
en los pines del puerto B.
Nota: La función que hace este programa se puede hacer de una manera más corta,
(menos código usando ciertas estrategias del lenguaje C; pero es más difícil de explicar,
esto así es sencillo y se ve a simple vista el funcionamiento).

Esquema de circuito recomendado para esta práctica.


Use el circuti anterior

Lectura de un puerto completo.


Cuando queremos leer data (valores numéricos) por un solo pin, lo más que podemos
leer son dos valores, 0 o 1 (2 posibles estados), sin embargo muchas veces existen
situaciones en las que necesitamos conocer una situación entre muchas, digamos que
para un puerto de 8 bits las posibilidades son 256, y para dos puertos trabajando en
conjunto a 8 bits 8bits + 8bits =16 bits son 65535 posibles estados, entonces es cuando
lo que necesitamos es leer un puerto completo, para esto tenemos.
variable = input_x(); donde x puede ser A,B,C,D,E, cualquier puerto.
En el programa siguiente, oprima uno o varios swiches al mismo tiempo y verifique
que los swiches que presiona hacen encender al led correspondiente del puerto b.

68
Programa ejemplo:

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
Int A;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);

while (1)
{
A=input_a(); ==== > Nota: la variable A no tiene nada que ver con el
puerto de lectura a.
output_b(A); ===== > Muestra por el puerto b, el valor de A, que a su
} vez el leído en el puerto a.
}

El condicional if(expresión).

Condicional if (condición cumplida) { } llaves de subrutina positivas


Else (condición no cumplida) { } llaves de subrutina negativa
If no es un comando, pero es un evaluador de una condición de tal manera que si esta se
cumple, el permitirá la ejecución de una subrutina dentro de un programa, y si no se
cumple, él podrá direccionar a otra subrutina o permitir que el programa siga su curso
normal hasta el final.
Los evaluadores de condiciones se pueden emplear con las variables y directamente con
los pines de los puertos, así, si un pin de cualquier puerto está conectado a un pulsador,
cuando este pulsador se oprime se cumple una condición (condición de oprimido)
entonces se ejecutará una subrutina, luego al soltarlo se deja de cumplir esa condición y
el programa vuelve a seguirse ejecutando sin pasar por esa subrutina.
Ejemplo de programa con el evaluador de condición if () {} else {}.
Mientra se presione el pin_a0 se enciende el pin_b0, cuando se deje de presionar el
pin_a0 entonces se encenderá el pin_b1.”no se enrede, recuerde que las llaves delimitan
el principio y el fin de los cuerpos, las subrutinas y del cuerpo principal.”

Programa ejemplo.

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);

69
while (1)
{
if (input(pin_a0))
{ ======= > llave de inicio de bloque
output_high(pin_b0);
} ======= > llave de fin de bloque
else
{
output_high(pin_b1);
}
}
}

En este programa al presionar un pin, se enciende otro pin, pero tenga en su conciencia
que dentro de ese par de llaves {-} puede meter de todo lo que se le ocurra, incluso
llamar librerías (otros programas), y desde allí todo lo que su imaginación y su dominio
de la programación le permita, que cuando se compile todo quedará cargado en el
mismo archivo.hex
También podemos usar los evaluadores de condición con cualquier varible, bien sea una
leída por puerto de entrada o una generada dentro del programa con un contador,
convertidor analógico digital, etc.

Ejemplo: El programa siguiente enciende el pin_b0 si (100 < a <200) de otra forma
enciendo el pin_b1.
Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
Int a,b,c;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
while (1)
{
a=input_a();
If ((a>100) && (a<200)) ====== > si (100 < a <200)
{ ======= > llave de inicio de bloque
Output_high(pin_b0);
} ======= > llave de fin de bloque
else
{
Output_high(pin_b1); ====== > si (a<100 y a>200)
} } }
Use el circuito anterior

70
output_toggle(pin_pd); cambio de estado.
a= ~a; complemento a 1.
El comado de cambio de estado es de lo más sencillo, y teniendo en cuenta que “hacer
un cambio de estado y hacer un complemento a 1 es algo muy parecido”, voy a
explicarlo así,
Hacer un cambio de estado es cambiar de 0 a 1 ó de 1 a 0 el estado de un pin.
Hacer un complemento a 1 es hacer un cambio de estado a todos los pines de una
variable o de un puerto, de tal manera que hacer un complemento a 1 es hacer un
cambio de estado múltiple.

El siguiente programa produce en el pin_b0 un cambio de estado y luego en el puerto b


un complemento a 1 (cambia todos los valores de los pin de b).

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int x;
x=(0b11110000);
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
a=(0b11110000);
delay_ms(1000);
while (1)
{ ======= > Lazo infinito.
output_toggle(pin_b0);
delay_ms(1000);
output_b(~a); ======= > Cambia el estado de los pines de b.
delay_ms(1000);
x=swap(x); ====== > Se mantiene intercambiando los nibles.
}
}

71
UNA PARADA EN LA ELECTRÓNICA
Lo ideal de las aplicaciones de los microcontroladores es el monitoreo y el control de
procesos, independientemente de lo que se haga, bien sea seguridad, procesos de
fabricación, procesos de control, cálculos o simples juegos para la diversión, los
usuarios quieren ver el estado en el que se encuentra a cada momento (tiempo real) el
sistema que depende de sus decisiones y/o acciones, por eso, pienso que ha llegado la
hora de dejar de ver lucecitas de colores y comenzar a ver números (dígitos), los
números de control y/o de cálculos que se realizan en el microcontrolador y a los cuales
aún en este libro no hemos tenido acceso, salvo en código binario (que no manejamos
en la vida rutinaria como ver la hora, pagar una cuenta, dar un número telefónico,etc)
así que ahora vamos a entender el funcionamiento de los displays de 7 segmentos y las
pantallas LCD, además, según se nos vaya acrecentando la curiosidad y la necesidad, la
utilización de componentes discretos (transistores, reguladores, sensores de todo tipo y
otros) y componentes integrados (memorias, codificadores, decodificadores, contadores,
manejadores (drivers), convertidores y todo lo que haga falta para sentir que de verdad
tenemos el control electrónico de un sistema).
Nota: Tener el control electrónico no es solo manejarlo a voluntad, es también poder
cambiar el diseño para mejorarlo, hacerlo más económico, ampliar sus aplicaciones y
cambiar el programa que lo controla todas las veces que se quiera, etc.

Conceptos que son necesarios manejar para entender funcionamiento de un sistema


electrónico digital que funciona con un programa de computadora.

Un microprocesador es un dispositivo electrónico digital que controla un sistema


completo, procesa datos, saca cuentas, compara valores, ejecuta proramas,etc.
Para poder controlar el sistema necesita tener ciertos parámetros de funcionamiento y
varios amigos (circuitos) que le ayudan.
Sus amigos son, las memorias, la unidad lógico-aritmética (con lo que saca las cuentas)
y un grupo de conexiones con su alrededor.
La memorias que son sus amigas tienen la información (datos o programas) que el
microcontrolador o microprocesador requiere para gerenciar, pero a más información,
más memoria y a más memoria, necesidad de más espacio para guardar, y cada espacio
tiene un único lugar donde almacena determinada información.
Ahora, el microprocesador para pedir una información debe decirle a la memoria el
lugar exacto donde está guerdada la información que necesita, lo que pasa es que el
siempre necesita millones de unidades de información y para ello se necesitan muchas
conexiones (un puño de cablecitos), ahora, este puño de cablecitos por el que se le dice
a la memoria los lugares donde están las unidades de información se llama bus de
direcciones, ahora bien cada lugar de esos en donde hay una unidad de información se
localiza con un número (entre ellos se comunican en código binario, pero es un número
como los decimales, y es único como si fuera su número de teléfono(no deberían existir
dos líneas telefónicas con el mismo número) entonces en una memoria de un mega hay
un mega de unidades de información y hay un mega de lugares de resguardo de
unidades de información y por ende un mega de números para localizar cada unidad de
información en su resguardo, y como ya sabemos, la electrónica digital se maneja con
código binario, así que cada cablecito del bus de direcciones de donde se almacena la
información es un bit de los números en código binario con los que se ubica la
información.

72
Ahora, la información también debe circular por cablecitos; pero cuantos cablecitos,
(normalmente 8 cablecitos), a este grupito de cablecitos se le llama bus de datos, y
cuando son 8 cablecitos se dice que los datos se componen de palabras de 8 bits.

En este caso se le llama palabra a la cantidad de cablecitos que se usan para transmitir la
información de los datos, dato por dato, si los datos están formados por ocho cablecitos
u ocho bits, entonces se dide que los datos están formados por palabras de 8 bits
(cablecitos), de esta manera si las palabras son ocho bits lo más que podemos tener es
256 datos diferentes.

Simulacro en frío de un microprocesador y una memoria.


Cuando se enciende un sistema con microprocesador, este comienza a poner
inmediatamente números en código binario en el bus de direcciones (lo hace a una
velocidad impresionante) para buscar todas las unidades de información que necesita,
éstos números de direcciones en código binario pasan por ese puño de cablecitos
(recuerden: un cablecito es un bit) y llegan a la memoria, la memoria tienen adentro de
ella un circuito que se llama decodificador de direcciones y a cada número binario que
lee de ese puño de cablecitos (unos encendidos otros apagados cambiando
constantemente a velocidades de millones de veces por segundo) le tienen su lugar
específico para cada combinación de encendidos y apagados, y en esa unidad de
memoria hay un dato grabado que también está en código binario, este dato la memoria
lo pone en el bus de datos y es leído inmediatamente por el microprocesador y este una
vez que lee la unidad de información (dato) cambia el número en binario en el bus de
direcciones para pedir el dato siguiente y así se mantiene trabajando.

Claro está que al diagrama anterior le falta mucho componente electrónico, pero ilustra
lo que quería mostrar.

Ahora, los sistemas digitales tienen más de dos buses (grupos de cablecitos dedicados a
una tarea específica), ya sabemos que tienen el bus de datos y el de direcciones, pero
también tienen un bus llamado bus de control y se emplea para estar interconectado en
todo momento con en mundo exterior esperando un llamado para responder en el

73
momento que pueda o en el acto, según sea el llamado, además de lo obvio como la
alimentación, la conexiones con el cristal oscilador, etc.

También es importante saber que cuando a los sistemas se le colocan varios bancos de
memoria, el microprocesador tiene unos pines para selecionar de cual memoria quiere
leer en un momento, y que la memoria tiene un pin (pin de habilitación) por el cual ella
se activa y que cuando el microprocesador la activa ella comienza a poner sus datos a
disposición en el bus de datos según la dirección que este le mande.

Entonces tenemos bus de datos, bus de control, bus de direcciones, alimentación, pin de
habilitación, y más, pero por ahora con esto es suficiente.

Diagrama de un microprocesador

Rojo bus de direcciones: Azul bus de datos Bus de control

Bus de direcciones y bus de datos son el mismo en los pines 9 al 16, para este
microprocesador, hay otros que los tienen totalmente separados.

En muchos casos, y así de la misma manera como un microprocesador que tiene varios
bancos de memoria selecciona solo uno para leer la información de él o escribir en ella,
así de esa misma manera cuando un sistema esta diseñado para que el bus de
direcciones también sirva de bus de datos, el microprocesador decide con una señal de
un pin, si un bus en ese momento va a ser usado por una memoria, como bus de
dirección o como bus de datos, pero solo una utilidad en un tiempo, y así se ahorra
conductores y espacio, pero se tiene que hacer mejores y más complejos programas
desde el punto de vista lógico, entonces un microprocesador tiene que decidir de cual
memoria quiere leer, si el bus va a usarse como bus de datos o direcciones, y administra
todo el sistema, así como en el diagrama del microprocesador Intel 8088, tiene parte del
bus de direcciones usado como bus de datos. (direcciones 20 bits y datos de 8 bits)

74
Nota:
En electrónica cuando un bus (grupo de cablecitos) tiene más de una función a realizar
se le dice que ese bus está multiplexado, o sea se usa para diferentes tareas que no se
pueden mezclar.
Entonces en resumidas cuantas, bus de direcciones es el grupo de cablecitos por donde
el microprocesador indica cuales datos requiere, bus de datos es el grupo de cablecitos
por donde se reciben y envían esos datos, bus de control es el grupo de cablecitos para
que el operador del programa puede tener algún control sobre el funcionamiento de todo
el sistema, y la alimentación por donde se le pone la energía para que todo funcione, y
pin de habilitación es un cablecito que cuando tiene corriente positiva le impide a una
memoria funcionar, es como si la durmiera, y cuando tiene corriente negativa la
despierta y la pone activa.
Así que desde ahora en adelante no tiene que dudar lo que es cuando lea las
expresiones bus de datos, bus de direcciones, bus de control y pin de habilitación.

EL DISPLAY 7SEGMENTOS.
Si yo tomara 7 lámparas en forma de tubo, y las ordenara de tal manera que formaran el
número 8, como se muestra en la figura abajo, podría escribir cualquier número entro el
0 y el nueve, encendiendo unas lámparas y apagando otras.

Así de esta manera si quisiera escribir el número 1 solo encendería las Lámparas B y C,
y el número 5 encendería las lámparas A,F,G,C,D lo único que tengo que hacer es
conectar la alimentación a cada lámpara cuando la necesite.
Ahora como seguro ya saben, los leds son emisores de luz con alimentación polarizada,
es decir, solo encienden si le colocamos la alimentación de una forma, positivo de
alimentación con positivo del led y negativo de alimentación con negativo del led, si lo
coloca de la forma alternativa no encenderá, entonces imagine que sí esta lámpara la
construye con puros leds, ¿que opciones tiene para hacer las conexiones de
alimentación?.

1) Colocar todos los terminales negativos de los leds juntos y los positivos por
separados, así cuando desee encender dos leds solo tengo que alimentar los
positivos de estos leds y dejar los demás positivos flotantes (no conectarlos), y
solo encenderán los alimentados. (esta conexión se llama de cátodo común) o
sea todos los negativos pegados.
2) colocar todos los terminales positivos de los leds juntos y los negativos por
separados, así cuando desee encender tres leds solo tengo que alimentar los
negativos de estos leds y dejar los demás positivos flotantes (no conectarlos), y

75
solo encenderán los alimentados. (esta conexión se llama de ánodo común) o sea
todos los positivos pegados.

Bueno, cuando compré sus displays 7 segmentos pregúntele al vendedor si estos son
ánodo común o cátodo común y además cual es el voltaje, (eso si el display no trae esta
información grabada en un costado).

Esto es importante a la hora de hacer el diseño, pues cuando se compran los


manejadores de voltaje para ciertos displays, éstos también vienen de ánodo común o
cátodo común, algunos circuitos manejadores envían los dos voltajes, por ejemplo en
alto +5v y en bajo -5v, pero otros envían solo +5 y 0v, o -5v y cero, y si nos
equivocamos no nos sirven.

Ahora vamos a conectar y a poner a funcionar un display 7 segmentos, infórmese si es


cátodo común o ánodo común, si no lo sabe, o si no sabe nada de él display tome lápiz y
papel y haga lo siguiente:

1ro. Móntelo en el protoboard y observe en que posición quedan conectados cada uno
de sus pines.
2d0. consiga una fuente de 5voltios y a uno de sus terminales conéctele una resistencia
de unos 500ohm. (eso es muy fácil teniendo un protoboard).
3ro. Conecte el terminal positivo de la fuente al primer pin del display.
4to. Tome el otro terminal de la fuente (negativo) y comience a conectarlo a cada uno
de los demás pines del display, si no prende ningún segmento entonces intercambie las
posiciones de negativo y positivo y vuelva ha tantear con los demás pines.
5to. Ya algún segmento ha debido encender, cuando encienda algún segmento tenga
casí por seguro que el pin donde tanteó es en pin de alimentación común, déje ese cable
ahí fijo y ahora comience a mover el que antes estaba fijo y observará como cambia de
iluminación entre los segmentos.
Tome el lápiz y el papel y anote en que posición enciende cada segmento, use el
diagrama como guía de los nombre A, B, C, D, E, F, G y punto.

76
Normalmente el pin central tanto de un lado como del otro es el pin de alimentación
común, pero tiene que verificar y si la disposición de los pines no es igual debe hacer
este trabajo.(recuerde mantener la resistencia en el pin de alimentación común, si el
display enciende muy débil cambie la resistencia por una menor o póngale otra de igual
valor en paralelo).

Ahora vamos a trabajar con el display 7seg y el microcontrolador.

Usaremos el puerto B del microcontrolador para encender los segmentos y el punto del
display, y los pines de puerto a para darle las instrucciones de que hacer según se
presione un pulsador conectado a algún pin.

MANEJO DEL DISPLAY 7SEGMENTOS


Primer programa para manejar un display 7segmentos.

Haga que el microcontrolador le diga en el display que pin del puerto A está
presionando.
Nota: No presione más de un botón al mismo tiempo.(El programa no está hacho para
protegerse de errores)

Lo primero que tenemos que hacer en diseñar nuestro propio código de señales entre el
microcontrolador y el display.

Entonces:
Para encender el 0 debemos iluminar los segmentos A B C D E F.
Para encender el 1 “ “ “ B C
Para encender el 2 A BD E G
3 A B C D G
4 BC FG
5 ACDFG
6 CDEFG
7 ABC
8 ABCDEFG
9 ABCFG

Ahora debemos convertir nuestro código en números que me den los segmentos
indicados.

Entonces el segmento A va a ser el pin B0


B B1
C B2
D B3
E B4
F B5
G B6

77
Ahora interconecte su display y su microcontrolador así.
(Este es un display catodo común), por eso conectamos el negativo del display
7segmentos a el negativo del microcontrolador.

Ejemplo: Si quiero encender el número 4, sus pines conectados a los segmentos. 4


=F, G, A, B = B0, B1, B5 y B6 = 0B01100011.
O sea que output_b(0B01100011); muestra el número 4 en el display.

Para hacer este programa hay muchas alternativas, pero mi estrategia será de lo más
sencillo, enviar al puerto la señal en binario sabiendo código de cada número (ejemplo:
para hacer el 8 enciendo todos los leds enviando puros 1 8=01111111 ya que el último
está desconectado.)
El problema es que el puerto a solo tiene 5 entradas, por lo tanto solo veremos los
números desde el 0 hasta el 4.

0= 00111111 1=00000110 2=01101011 3=01001111 4=01100011


5=01101101 6=01111100 7=00000111 8=01111111 9=01100111

Programa ejemplo.
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int a;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
while (1)
{
If (input(pin_a0)) output_b(0b00111111);
If (input(pin_a1)) output_b(0b00000110);
If (input(pin_a2)) output_b(0b01011011);
If (input(pin_a3)) output_b(0b01001111);
If (input(pin_a4)) output_b(0b01100110);
a=input_a();
if (a==0) output_b(0b00000000); } }

78
Nota: recuerde que donde quiera que tenga un 1 como salida, ese pin se pondrá en salida
alta (5Volt), y si tiene 0 como salida se pondrá en salida baja (0Volt).

En el siguiente programa vamos a hacer 5 corridas, una por cada pin del puerto a,
A0 corrida ascendente del 0 al 9
A1 corrida descendente del 9 al 0
A2 corrida ascendente sólo los números pares
A3 corrida ascendente sólo números impares
A4 corrida ida y vuelta

Programa ejemplo.

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int a;
set_tris_a(0b11111);
set_tris_b(0b00000000);
while (1)
{
If (input(pin_a0))
{
output_b(0b00111111);
delay_ms(300);
output_b(0b00000110);
delay_ms(300);
output_b(0b01101011);
delay_ms(300);
output_b(0b01001111);
delay_ms(300);
output_b(0b01100110);
delay_ms(300);
output_b(0b01101101);
delay_ms(300);
output_b(0b01111100);
delay_ms(300);
output_b(0b00000111);
delay_ms(300);
output_b(0b01111111);
delay_ms(300);
output_b(0b01100111);
delay_ms(300);
}

If (input(pin_a1))

79
{
output_b(0b01100111);
delay_ms(300);
output_b(0b01111111);
delay_ms(300);
output_b(0b00000111);
delay_ms(300);
output_b(0b01111100);
delay_ms(300);
output_b(0b01101101);
delay_ms(300);
output_b(0b01100110);
delay_ms(300);
output_b(0b01001111);
delay_ms(300);
output_b(0b01101011);
delay_ms(300);
output_b(0b00000110);
delay_ms(300);
output_b(0b00111111);
delay_ms(300);
}

If (input(pin_a2))
{
output_b(0b01100111);
delay_ms(300);
output_b(0b00000111);
delay_ms(300); output_b(0b01101101);
delay_ms(300);
output_b(0b01001111);
delay_ms(300);
output_b(0b00000110);
delay_ms(300);
}

If (input(pin_a3))
{
output_b(0b01111111);
delay_ms(300);
output_b(0b01111100);
delay_ms(300);
output_b(0b01100110);
delay_ms(300);
output_b(0b01101011);
delay_ms(300);
output_b(0b00111111);
delay_ms(300);
}
If (input(pin_a4))

80
{
output_b(0b00111111);
delay_ms(300);
output_b(0b00000110);
delay_ms(300);
output_b(0b01101011);
delay_ms(300);
output_b(0b01001111);
delay_ms(300);
output_b(0b01100110);
delay_ms(300);
output_b(0b01101101);
delay_ms(300);
output_b(0b01111100);
delay_ms(300);
output_b(0b00000111);
delay_ms(300);
output_b(0b01111111);
delay_ms(300);
output_b(0b01100111);
delay_ms(300);
output_b(0b01100111);
delay_ms(300);
output_b(0b01111111);
delay_ms(300);
output_b(0b00000111);
delay_ms(300);
output_b(0b01111100);
delay_ms(300);
output_b(0b01101101);
delay_ms(300);
output_b(0b01100110);
delay_ms(300);
output_b(0b01001111);
delay_ms(300);
output_b(0b01101011);
delay_ms(300);
output_b(0b00000110);
delay_ms(300);
output_b(0b00111111);
delay_ms(300);
}
}

El mismo programa pero con menos código


La estrategia de este está en saber que los valores binarios que sacamos por el puerto B
los podemos usar de igual forma pero en decimal, así sabiendo que en binario para
encender los 7 segmentos necesitamos enviar 7 pines en voltaje alto y que este numero
es Ob01111111 y en decimal es 127 entonces solo pasamos los valores a decimal.

81
Nota: recuerde que el prefijo ob significa que ese valor está codificado en código
binario, al lado derecho estarán las misma cantidades en decimal
(0b00111111); =63 (0b00000110);=6 (0b01101011);=107
(0b01001111); =79 (0b01100110);102 (0b01101101);109
(0b01111100);= 31 (0b00000111);7 (0b01111111);127
(0b01100111);103

Luego a estos valores los definimos con algún nombre de forma que los podamos llamar
con facilidad e igual con el retardo.

A medida que se vaya familiarizándose con la sintaxis y las diferentes estrategias del
código del lenguaje C, le será fácil hacer los programas cortos y sencillos.

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
#define a0 output_b(63)
#define a1 output_b(6)
#define a2 output_b(107)
#define a3 output_b(79)
#define a4 output_b(102)
#define a5 output_b(109)
#define a6 output_b(31)
#define a7 output_b(7)
#define a8 output_b(127)
#define a9 output_b(103)
#define retardo delay_ms(300)
void main()
{
set_tris_a(0b11111);
set_tris_b(0b00000000);
while (1)
{
If (input(pin_a0)) {
a0; retardo;
a1; retardo;
a2; retardo;
a3; retardo;
a4; retardo;
a5; retardo;
a6; retardo;
a7; retardo;
a8; retardo;
a9; retardo; }
If (input(pin_a1)) {
a9; retardo;
a8; retardo;
a7; retardo;

82
a6; retardo;
a5; retardo;
a4; retardo;
a3; retardo;
a2; retardo;
a1; retardo;
a0; retardo; }
If (input(pin_a2)) {
a0; retardo;
a2; retardo;
a4; retardo;
a6; retardo;
a8; retardo; }
If (input(pin_a3)) {
a1; retardo;
a3; retardo;
a5; retardo;
a7; retardo;
a9; retardo; }
If (input(pin_a4)) {
a0; retardo;
a1; retardo;
a2; retardo;
a3; retardo;
a4; retardo;
a5; retardo;
a6; retardo;
a7; retardo;
a8; retardo;
a9; retardo;
a8; retardo;
a7; retardo;
a6; retardo;
a5; retardo;
a4; retardo;
a3; retardo;
a2; retardo;
a1; retardo;
a0; retardo; }
} }

Es más sencillo, menos código, pero tienes que saber usar el #define,

LOS DECODIFICADORES 7447, 7448 Y 7449.

Espero que tanto con el programa como con la explicación anterior esté en capacidad de
instalar y poner en marcha cualquier display 7segmentos, ahora les voy a presentar a un
codificador que nos ahorrará mucho trabajo, en este punto debo aclarar que todo lo que
nos ahorre trabajo tiene su costo en dinero, es decir para yo ahorrarme parte del trabajo

83
de codificar el programa necesito usar un circuito integrado llamado decodificador de
código binario a display de 7segmentos, estos decodificadores son el SN74LS47(ánodo
común) y el SN74LS48 (cátodo común) son circuitos TTL, y nos dan mucha utilidad
pero tienen un costo.

Los circuitos TTL SN74LS47 y SN74LS48 o como los llaman 7447 y 7448 son
decodificadores que convierten un número binario de 4 bits en un número decimal en
7segmentos para alimentar el display, la diferencia es que el 7447 está diseñado para
displays de ánodo común y el 7448 para displays de cátodo común, pero su lógica es la
misma.

Ahora con estos circuitos nos ahorramos cierta cantidad de trabajo al no tener que crear
un código para poder realizar la conversión y hacer funcionar el display, sino que le
enviamos en código binario al 7447 o 7448 y listo, observe el ejemplo.
Nota “No se pregunte porque les enseñé lo anterior si esta manera es más fácil, ya que
todo es cuestión de gusto y de costo”

84
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int a;
set_tris_a(0b11111);
set_tris_b(0b00000000);
while (1)
{
for(a=0; a<=9;a++) ======= > es una forma de incrementar el contador
{
Output_b(a);
delay_ms(300);
}}}

Nota: En lenguaje C, escribir a=a+1 es lo mismo que escribir a++.


Este programa muestra en el display los números del 0 al 9 en lazo infinito, observe
todo el ahorro de trabajo solo por usar un chip más. (por supuesto, si va a fabricar
millones de circuitos, “mejor ahórrese el chip”

ESTRATEGIAS EN ELECTRÓNICA
En electrónica como en programación, y en general en el diseño, un problema de
ingeniería, tiene en la mayoría de los casos varias posibles soluciones, y según sean los
criterios de evaluación de las posibles soluciones, se adoptará una, las más elegante, la
más económica, la más rápida, etc y en electrónica con toda la diversidad de
componentes que hay es posible que una estrategia de resolver una situación no se
parezca en nada a las demás, sin embargo es posible que cualquiera sirva.
A más componentes electrónicos conozcamos, más rápido resolveremos.

Planteamiento del siguiente problema.


Como puedo hacer un contador de 2 dígitos con 2 displays usando un solo PIC16F84A,
los que quiera de 7448 y solo el puerto b.

Respuesta 1 (buena): Usando el nible bajo del puerto b con un 7448 y un display, y
usando el nible alto del puerto b con otro 7448 y otro display.

85
Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int a, u,d,s;
set_tris_a(0b11111);
set_tris_b(0b00000000);
while (1)
{
for(a=0; a<=99;a++)
{
d=floor(a/10); ==== > floor(v); calcula en menor entero de v (la decena)
u=a-10*d; ==== > Se calcula la unidad
swap(d); ===> Intercambia los nibles
s=u | d; === > operación or (o en español)
output_b(s);
delay_ms(300);
}}}

Lógica del programa:


Digamos que en el contador la variable a va por el número 74

Para calcular el digito de las decenas


Entonces d = parte entera (74/10) = parte entera de 7.4 = 7 =d, ahora como este es un
número que lo máximo que llega es a 9 y lo máximo que ocupa es a 4 bits, lo paso al
nible alto, con el comando swap.

Para calcular el digito de las unidades


Entonces u = 74 – d*10 = 74 – 70 = 4 =u
Entonces tengo d =7 =(0b00000111) y u=4 =(0b00000100), ahora: como ya tengo el
número 7 en el nible alto, solo debo colocar el 4 en el nible bajo: -¿como lo hago?,
usando el operador lógico or |, al tener la decena en una varible en el nible alto, y la
unidad en otra variable en el nible bajo, al hacer la operación s= d or u => s= d | u en la
variable s me quedan ambos, decena y unidad en los nibles bajo y alto.

Nota: Cuando intercambié los nibles de la variable d (d es la decena y debe estar en el


nible alto).
swap d, y se convierte de (0b00000111) en (01110000) y así me queda el nible bajo
para colocar ahí la unidad del número 74, o sea el 4 y así cuando necesite los dos nibles
en una misma variable entonces aplico el operador OR (ALT124) | ya que sé, que el
nible alto está vacío

u = (0b00000100)
d = (0b01110000)
-----------------------------
S = (0b01110100)

86
Y tengo los dos nibles, u en nible bajo y d en nible alto, que al salir por el puerto B van
a los decodificadores 7448 y estos controlan los displays mostrando los dos dígitos del
conteo.

Respuesta 2(buena) usando solo el nible bajo del puerto b para los dígitos con dos 7448
y alternando la señal de activación de los dos displays con el nible alto del puerto b, (de
hecho se pueden controlar así hasta cuatro displays, recuerden que estos dispositivos
trabajan a una velocidad tan alta que pueden alternar los displays y no lo notamos)

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
int a,u,d;
set_tris_a(0b11111);
set_tris_b(0b00000000);
while (1)
{
for(a=0; a<=99;a++)
{
d=floor(a/10); ==== > floor(v); calcula en menor entero de v la decena.
u=a-10*d; ==== > Se cálcula la unidad.
output_low(pin_b7); === > Activa el display decena.
output_high(pin_b6); === > Desactiva el display unidad.
output_b(u);
output_low(pin_b6); === > Activa el display unidad.
output_high(pin_b7); === > Desactiva el display decena.
output_b(d);
}}}
Respuesta 3(buena) teniendo en cuenta que los displays son de 7segmentos, por lo tanto
se necesitan 7 pines de control para los 7 segmentos, y como el puerto B tiene 8 pines
esto quiere decir que del puerto B se usarán 7 pines (uno para cada segmento) y uno
quedará libre y sin usar , ahora ese pin que queda libre lo puedo usar como selector del
display al activar usando un display ánodo común y un display cátodo común y usando
ese pin como alimentación de los dos displays.( al encender un display se apaga el otro)

87
Respuesta 4 (buena) Usando un 7447 y un 7448, un display ánodo común y otro cátodo
común conectados ambos al nible bajo (en paralelo) y usando dos de los pines sobrantes
del nible alto para controlar en encendido y apagado de los dos displays.

Todas son soluciones para el mismo problema, todas son factibles técnicamente, 4
soluciones con 4 arquitecturas diferentes y por supuesto 4 programas diferentes.

LAS PANTALLAS LCD DE CRISTAL LÍQUIDO (cómo funcionan).

El código ASCII:
Existe un código llamado el código ASCII, en este código están (si no todos, la gran
mayoría) los símbolos, números y letras que conocemos en nuestro lenguaje escrito, y
además en este código cada símbolo, número y letra tiene un código númerico asignado
(la cédula de identidad de cada símbolo), de tal manera que si yo llamo a la letra A

88
(mayúscula) por su código tendría que llamarla 65 que es su código ASCII, y si llamara
a la letra a (minúscula) entonces la llamaría 97, de esta manera cualquiera podría
escribir mensajes y libros en puro código ASCII, (tenga en cuenta que todo lo que se
almacena en una computadora (en su interior) se hace en código ASCII y además esos
valores escritos en binario).

Ahora, las pantallas de cristal líquido tienen un bus de datos (un grupo de cablecitos en
los que se pone información en código binario), un bus de control (un grupo de
cablecitos por los que le decimos con un pulso -o bien que escriba algo, o bien que
haga algo “pero este hága no es escribir sino borrarse, prenderse, apagarse, etc), además
de la alimentación y el contraste y algunas tienen luz de fondo, pero esto es preferible
de control manual y no requiere conectarse a microcontrolador.

Como la hago funcionar:


Primero que todo, “El diagrama”: La pantalla tiene 14 cablecitos numerados, y cada
cablecito tiene una función que hacer.

Conecta la pantalla de la siguiente manera, ver diagrama de conexión.


Los pines 1, 3, 5 y 14 al negativo de la fuente
El pin 2 al positivo +5 voltios
El pin 13 con una resistencia en serie de 1000 ohm(1k) a 0 volt
El pin 4 con una resistencia en serie de 10000 ohm a 0V y un swiche con resistencia en
serie de 1000 ohm a +5volt.
El pin 6 igual que el pin 4
Los pines 7, 8, 9, 10, 11 y 12 conéctelos mezclados, unos a 0Volt y otros a 5Volt.

89
Una vez conectada la pantalla de esta manera, puede usted manipularla hasta cierto
punto, entonces:
1ro.) Coloque un código cualquiera en los terminales, algunos pines a 5volt, y otros en
0volt.
2do.) ahora de pulsos en p2 (El pulsador que está en el pin 6 de la pantalla).

En los pines del bus de datos de la pantalla (pines desde el pin_7 al pin_14) se pone un
código en binario, unos pines en 0volt y otros en 5volt, y según sea esa combinación,
usted le está dando un código en binario a la pantalla, y con el pulsador P2 la pantalla lo
asume y toma una de dos posibles acciones, 1ro (si el pin 4 está a 0volt “P1 no
presionado”) presenta el carácter correspondiente a ese código ASCII, 2do (si el pin 4
está a 5volt “P1 presionado”) ejecuta una acción como, borrarse, apagarse, encenderse,
ubicar un carácter en un lugar específico, etc.

Explicación genérica de funcionamiento de la pantalla:


Una pantalla LCD en general funciona de la siguiente manera (una vez conectada y
alimentada), para manejarla tiene 10 pines, 8 pines son el bus de datos (los pines del 7
al 14), son los pines donde se colocará un código ASCII en binario, es decir unos
cablecitos estarán puestos a 0volt y otros a 5volt, si todos están puestos a 0volt el código
ASCII que le está introduciendo será 0 (cero), ya que se escribió cero en código binario,
si el 1er cablecito está puesto a 5volt y los demás a 0volt el código ASCII es 1, si los 4
primeros (pin_7, pin_8, pim_9, pin_10) están a 5volt y los 4 últimos a 0volt el código es
15 y así sucesivamente. (Nota: El código ASCII es un código que le puso a todos los
carácteres que usamos para escribir un número asignado y el código binario es una
forma de expresar cantidades con solo unos y ceros, ningún de los códigos tiene que ver
con el otro, son dos temas separados “consulte código ASCII en la internet”), ahora
quedan 2 cablecios el pin 4 (un pin puede tener 2 estados, está conectado a 0volt –bajo o
0-, o está conectado a 5volt -alto), en el pin 4 es donde se decide si le va a dar a la
pantalla letras u ordenes, cuando el pin 4 está puesto a negativo (la da letras) todos los
valores que se le pongan en el bus de datos son asumidos como códigos de letras
(ASCII), y si el pin 4 está puesto a 5volt (le da ordenes) todos los valores que se pongan
en el bus de datos serán asumidos como ordenes, y el pin 6 es el pin por el que dándole
un pulso la pantalla ejecuta la acción, por ejemplo presenta una letra o se borra.

90
Por ejemplo (tenga la pantalla conectada)
Nota: Recuerde que el prefijo 0b no forma parte del código, sino es para advertirles que
ese valor está escrito en código binario.

1) Nota: No olvide que el bus de datos son solo los pines del 7 al 14, y cuando me
refiera al bus de datos son esos pines. (ojo con eso)
2) En el bus de datos ponga el número 12 en binario (0b00001100) el pin 9 y pin10
de la pantalla a 5volt y todos los demás a 0volt.
3) El pin 4 lo conectas a 5volt. (para darle una orden)
3) En el pin 6 das un pulso (con el código 12, la orden es encenderse)
4) En el bus de datos colocas el número 1 en binario (0b00000001), el pin 7 a 5volt
y los demás a 0volt.
5) En el pin 6 das un pulso (con el código 1 la orden es borrarse)
6) Ahora en el bus de datos pones el numero 65 en binario (0b01000001), el pin 7
y pin 13 a 5volt y los demás a 0volt.
7) El pin 4 lo pones a 0volt (para darle letras o caracteres).
8) En el pin 6 das un pulso 0volt -> 5volt ->0volt
9) Por cada pulso que des debe aparecer una letra A en la pantalla.

Conociendo el código ASCII puedes escribir lo que quieras, busca en la Internet la tabla
de códigos ASCII que es de mucha utilidad-

Nota: Haga esto hasta que la pantalla le funcione, es importante que entienda su
funcionamiento independientemente de que cuando esté conectada al microcontrolador
sea este el que mediante un programa escriba, borre y ejecute cada acción que ella
realizará.

Como manejar la pantalla LCD con el microcontrolador y el PIC C.

Antes debe entender como funcionan las librería y los cuerpos de programa en PIC C,
(Esto es una ventaja considerable del lenguaje de las computadoras).
Nota importante para que no se confunda: Los términos: cuerpo, subprograma, rutina,
subrutina, bloque de programa (bloque), son lo mismo, un pedazo de un programa que
se hizo de forma aparte pero que se ejecute con todos los demás bloques o cuando se le
llame.

El lenguaje C, tiene la característica de que sus programas pueden hacerse en varios


bloques o cuerpos, y luego desde cualquier línea de un bloque se puede llamar a
ejecutar cualquier otro bloque o cuerpo, y después de ejecutado (ese bloque que se
llamó) el programa regresará por si solo a seguir en la línea siguiente donde hubo el
llamado al bloque o dió el salto.

En lenguaje C la palabra void significa que lo que viene después es un cuerpo o bloque,
se usa para hacer pedazos de programas a los cuales se les asigna un nombre.

Ejemplo: void rutina1() { }, Quiere decir que ese es un subprograma que se llama
rutina1, y que el código está comprendido entre las llaves.

En lenguaje C, el inicio y fin de un bloque o cuerpo se delimitan con llaves

91
Inicio {, y final }, entonces luego del void rutina1() debe seguir una llave abierta y al
final una llave cerrada.

Programa ejemplo:
void rutina1(variable)
{
desarrollo del
subprograma
}

Ejemplo de programa hecho en varios cuerpos, los cuales son llamados desde el cuerpo
principal del programa.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)

Void cero (int a)


{
For (a=1; a<=10; a++)
{
output_b(0b00111111);
delay_ms(3000);
output_b(0);
delay_ms(200);
} }

Void uno(int a)
{
For (a=1; a<=10; a++)
{
Output_b(0b00000110);
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
} }

Void dos(int a)
{
For (a=1; a<=10; a++)
{
Output_b(0b01011011);
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
} }

92
Void tres(int a)
{
For (a=1; a<=10; a++)
{
Output_b(0b01001111);
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
} }

Void cuatro(int a)
{
For (a=1; a<=10; a++)
{
Output_b(0b01100110);
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
} }

Void main ()
{
int a;
set_tris_a(0b11111);
set_tris_b(0b00000000);

While (1)
{
If(input(pin_a0)) cero (a);
If(input(pin_a1)) uno (a);
If(input(pin_a2)) dos (a);
If(input(pin_a3)) tres (a);
If(input(pin_a4)) cuatro (a);
}
}

Nota: Observe que es importante estar pendiente de las llaves, pués una llave mal
colocada puede dar algún tipo de error.

93
Circuito recomendado para el programa anterior.

El programa anterior está hecho en seis cuerpos, el cuerpo principal siempre se va al


final de todos los demás cuerpos (secundarios), pero es importante que sepa que el
código de un cuerpo (el bloque de sub-programa) siempre debe aparecer en el código
del programa antes de ser llamado, de otra manera el lenguaje PIC C dará un error al
llamar un cuerpo que no ha visto durante la corrida.

El programa anterior muestra titilando un dígito (entre el 0 y el 4) en un display


conectado al puerto b, siempre que se presione un pulsador colocado en alguno de los
pines del puerto a.

Nota: Los cuerpos tienen como nombre un número, entre paréntesis van declaradas las
variables (En este caso solo hay una variable de nombre a como un número entero sin
decimales) que se usa en la subrutina.

94
LIBRERIAS EN PIC C
Creación y uso de las librerías en Pic C.

En lenguaje PIC C y en general en lenguaje C, una librería es un programa escrito en


lenguaje C; pero sin encabezado, es decir: es solo el cuerpo.

Ejemplo:

void cuerpo_a ( declaración de variables)


{
Código;
}

void cuerpo_b ( declaración de variables)


{
Código;
}

void cuerpo_c ( declaración de variables)


{
Código;
}

Las variables que se declaran son las que se van a usar dentro de cada bloque,
subprograma o cuerpo.

Y debe ser guardado con extensión.c, no lo compile recuerde que este va a ser una parte
de algún programa, use Save As y guárdelo en algún subdirectorio donde pueda ser
ubicado.

Una vez bien codificado y guardado el subprograma.c cada vez que usted necesite esa
rutina puede invocarla colocando como línea final del encabezado el código #include
<subprograma.c>, recuerde que si el subprograma está en un directorio específico, debe
direccionar la búsqueda al directorio donde está grabado.

Programa ejemplo:
Está parte del código debe ser guardada (ejemplo) en el directorio librería, con
extención.C “suponga que la llama milibrería.c”

Void cero (int a)


{ For (a=1; a<=10; a++)
{ Output_b(0b00111111);
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
}}
Void uno(int a)
{ For (a=1; a<=10; a++)
{ Output_b(0b00000110);

95
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
}}
Void dos(int a)
{ For (a=1; a<=10; a++)
{ Output_b(0b01011011);
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
}}
Void tres(int a)
{ For (a=1; a<=10; a++)
{Output_b(0b01001111);
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
}}
Void cuatro(int a)
{ For (a=1; a<=10; a++)
{Output_b(0b01100110);
Delay_ms(3000);
Output_b(0);
Delay_ms(200);
}}

Escriba este código tal como está, y almacénelo en el disco duro, -NO TRATE DE
COMPILARLO-, solo guárdelo con el nombre milibreria.c

Una vez codificado y guardado sin errores de sintaxis ni errores lógicos puede acceder
a él desde cualquier otro programa llamándolo como se hace en el siguiente programa.

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <milibrería.c> ====== > Llamado de la librería para que sea
Incluida en el código de este programa.
Void main ()
{
int a;
set_tris_a(0b11111);
set_tris_b(0b00000000);

96
While (1)
{
If(input(pin_a0)) cero (a);
If(input(pin_a1)) uno (a);
If(input(pin_a2)) dos (a);
If(input(pin_a3)) tres (a);
If(input(pin_a4)) cuatro (a);
}}

Nota: Este programa funciona exactamente igual al anterior en el cual todo el código
está en el mismo programa sin llamar a la librería, porque lo que en este programa es
una librería, en el anterior es parte de su código, solo que lo invoca y lo compila cuando
él es compilado, por ende el circuito es el mismo.

Esta explicación se hace necesaria porque para controlar la pantalla LCD, lo ideal es
hacerlo con una librería que la controla, (un subprograma que controla la pantalla), y al
invocar a esta librería en todos los programas en que necesitemos mostrar información,
estaremos en la posibilidad de ver esa información en una pantalla LCD, y de esta
manera nos olvidamos de hacer código cada vez que necesitemos usar una pantalla LCD
y solo invocamos a milibrería.c.

Nota: En la librería que sigue, si queremos usar los comandos en ingles use estos
comandos:
Lcd_init(); => Inicializa la pantalla (enciende la pantalla)
Lcd_clear(); => Borra la pantalla y lleva el cursor al principio de la línea
Printf(lcd_data,”texto literal %tipo de variable “,variable); => Para imprimir el
texto que queremos ver y las variables con datos numéricos.
Lcd_cmd(192); => Para poner el texto en la línea de abajo para pantallas de 2 lineas

Este es el código del sub-programa o bloque que le permite manejar la pantalla, cópielo
y almacénelo con algún nombre.c y guárdelo en un directorio donde le pueda acceder.

void lcd_out(int code, int flag)


{
output_x((code & 0xf0) | (input_x() & 0x0f));
if (flag==0)
output_high(rs);
else
output_low(rs);
delay_cycles(10);
output_high(stb);
delay_cycles(20);
output_low(stb);
}
void lcd_data(int asci)
{
lcd_out(asci,0);

97
lcd_out(asci<<4,0);
delay_us(50);
}
void lcd_cmd(int cmd)
{
lcd_out(cmd,1);
lcd_out(cmd<<4,1);
delay_ms(2);
}

void lcd_clear()
{
lcd_cmd(0x01);
delay_ms(15);
}
void lcd_init()
{
set_tris_x(mode);
delay_ms(15);
lcd_out(0X30,1);
delay_ms(5);
lcd_out(0x30,1);
delay_ms(1);
lcd_out(0x30,1);
delay_ms(1);
lcd_out(0x20,1);
delay_ms(1);
lcd_cmd(0x2e);
lcd_cmd(0x08);
lcd_cmd(0x0d);
lcd_cmd(0x06);
lcd_cmd(0x02);
}

Grabe o guarde este programa como pantallai.c, para saber que esta usa los comandos
en ingles.

Librería con comandos en español.


Inicializar(); Inicializa la pantalla (enciende la pantalla).
Borrar(); Borra la pantalla.
Printf(texto,”texto literal %tipo de variable”, variable); Imprime texto literal y los
valores de las variables.
Comando(192); Para cambiar a la línea de abajo en pantalla de 2 líneas

98
void lcd_out(int code, int flag)
{
output_x((code & 0xf0) | (input_x() & 0x0f));
if (flag==0)
output_high(rs);
else
output_low(rs);
delay_cycles(10);
output_high(stb);
delay_cycles(20);
output_low(stb);
}
void texto(int ascii)
{
lcd_out(asci,0);
lcd_out(asci<<4,0);
delay_us(50); }
void comando(int cmd)
{
lcd_out(cmd,1);
lcd_out(cmd<<4,1);
delay_ms(2);
}

void borrar()
{
lcd_cmd(0x01);
delay_ms(15);
}

void inicializar()
{
set_tris_x(mode);
delay_ms(15);
lcd_out(0X30,1);
delay_ms(5);
lcd_out(0x30,1);
delay_ms(1);
lcd_out(0x30,1);
delay_ms(1);
lcd_out(0x20,1);
delay_ms(1);
lcd_cmd(0x2e);
lcd_cmd(0x08);
lcd_cmd(0x0d);
lcd_cmd(0x06);
lcd_cmd(0x02);
}

99
Grabe o guarde este programa como pantallae.c, para saber que esta usa los comandos
en español.

Ahora codifique este bloque de programa y el anterior y guárdelos para que lo use desde
ahora en adelante, recuerde que estos bloques son para controlar la pantalla LCD.

Para usar cada una de estas librerías no solo necesita invocarla, también debe darle al
microcontrolador ciertas directivas para la operación de la pantalla, éstas son muy
sencillas aprendáselas lo mejor posible.

Con este encabezado conectamos la pantalla al puerto B del microcontrolador, si


cambiamos la letra B por C o D entonces conectamos la pantalla al puerto C o D. (Mi
costumbre es conectarla al puerto B)

#define mode 0
#define set_tris_x set_tris_b
#defne input_x input_b
#define output_x out_put_b
#define RS pin_b2
#define STB pin_b3
#include <pantallai.c>

¿Como conectar la pantalla al puerto B?.


Nota: Las pantallas LCD pueden trabajar con bus de datos de 8 bits o de 4 bits según
sea su interés, la diferencia está en que, cuando trabaja a 8bits los códigos de las letras
los recibe en un solo paso, y cuando trabaja a 4 bits, recibe los código en dos partes de
4bits cada uno, nible bajo y nible alto y luego ella los une en su interno y obtiene así un
código de 8 bits.

Conecte de esta manera la pantalla al PIC 16F84A y haga el siguiete programa.

Monte el siguiente circuito, para poner a prueba la pantalla con los siguientes
programas.

100
Programa ejemplo que escribe en la pantalla LCD usando la librería que tiene los
comandos en ingles.

Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)

#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define stb pin_b2
#define rs pin_b3
#include <pantallai.c>

Void main ()
{
Int32 a;
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
printf(lcd_data,"pantalla inicializada");
While (1)
{
a=a+1;
lcd_cmd(192);
printf(lcd_data," contando los segundos %lu ",a);
delay_ms(1000);
}}

101
Cópie el programa, compílelo y haga funcionar la pantalla, esto es muy importante, ya
que muchas de las aplicaciones que se van a realizar de ahora en adelante se van a
monitorear en la pantalla y algunas en displays 7segmentos.

En esta sección vamos a sacar cuentas y ver los resultados por pantalla, será como
hacer una calculadora.

Operadores.
Sumar +, Restar -, Multiplicar *, Dividir /, Residuo %, Menor que <,
Mayor que >, Menor o igual que <=, Mayor o igual que >=, Negación !,
Igual comparativamente ==, Diferente a !=, Complemento de ~, Función Y &&,
Función O ||,

Funciones.
Valor absoluto abs(var), Coseno de ángulo cos(ang); Seno de ángulo Sin(ang),
Tangente de ángulo tan(ang), Arcocoseno de x acos(x), arcoseno de x asin(x),
Arcotangente de x atan(x), Menor entero de x.y floor(x.y), Mayor entero de x.y
ceil(x.y), Exponencial e^x exp(x), Logaritmo natural de x log(x), Logaritmo decimal
de x log10(x), Raíz cuadrada de x sqrt(x),.

Desde ahora en adelante, siempre que necesitemos usar la pantalla, el encabezado e


inicio del programa será el siguiente. (la librería debe tener el nombre pantallai.c y debe
estar grabada en un directorio donde C lo ubique en el momento de compilar el
programa.

Los siguientes programas son muy sencillos, pero solo sirven para ilustrar como utilizar
los operadores

1ro). Para sumar dos valores


Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)

#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define RS pin_b2
#define STB pin_b3
#include <pantallai.c>

void main ()
{
int x,y,z;
set_tris_a(0b11111);
set_tris_b(0b00000000);

102
lcd_init();
lcd_clear();
x=11;
y=23;
z=x+y;
printf(lcd_data," la suma de los valores");
lcd_cmd(192);
printf(lcd_data,"%u + %u = %u ",x,y,z);
}

Explicación del código del programa:


En rojo, está escrito las definiciones necesarias para manejar la pantalla con la librería
pantallai.c.
En gris, el llamado a la librería pantallai.c que es la subrutina que opera la pantalla
directamente.
En azul, el comando que inicializa la pantalla.
En verde, el comando que borra la pantalla.
En violeta, el comando que escribe en la linea superior de la pantalla.
En naranja, el comando que hace que se escriba en la línea inferior de la panatalla.
En marrón, el comando para escribir en la pantalla, con la variante que este presenta la
cuenta y no el texto, para ello la notación %u le indica a PIC C que ese %u debe ser
sustituido por una cantidad que está después de las comillas “, .

Nota: observe que hay tres (3) veces la notación %u, y hay tres (3) variables después de
las comillas, x, y, z, y estas se asocian de la siguiente manera:
printf(lcd_data,"%u + %u = %u ",x,y,z);
Donde está el primer %u, se coloca el valor de la primera variable que aparece después
de las comillas, en este caso será el valor de x, segundo %u será sustituido por el valor
de y, y el tercer %u por el valor de z.

2do). Para restar dos valores.


Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b3
#define RS pin_b2
#include <pantallai.c>
void main ()
{
int x,y,z;
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();

103
lcd_clear();
x=11;
y=23;
z=y-x;
printf(lcd_data," la resta de los valores");
lcd_cmd(192);
printf(lcd_data,"%u - %u = %u ",y,x,z);
}

----------------------------------------------------------------------------
3ro.) Para multiplicar dos valores

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b3
#define RS pin_b2
#include <pantallai.c>
void main ()
{
int x,y,z;
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
x=11;
y=23;
z=x*y;
printf(lcd_data," la multipliciación de los valores");
lcd_cmd(192);
printf(lcd_data,"%u * %u = %u ",x,y,z);
}

--------------------------------------------------------------------------

4to.) Para dividir dos valores.


Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b3
#define RS pin_b2

104
#include <pantallai.c>
void main ()
{
int x,y;
float z;
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
x=50;
y=23;
z=x/y;
printf(lcd_data," la division de los valores");
lcd_cmd(192);
printf(lcd_data,"%u + %u = %2.2f ",x,y,z);
}

Nota: Para todos los programas anteriores se recomienda el circuito

El siguiente programa mostrará la tabla de sumar, si se presiona un pulsador conectado


al pin A0, y la tabla de multiplicar, si se presiona el pulsador conectado al pin A1,
luego, una vez estando adentro de algura de las tablas, con el pin A0 se cambiará la
tabla del número entre 0 y 9 según sea la tabla deseada, y con pin a3 cambia la
multiplicación, luego con el pin A1 se sale de esa tabla y se regresa al menú principal.

Nota: El siguiente programa se hará en subrutinas separadas, algo que me parece que no
deben dejar de tener en mente a la hora de hacer programas largos (mucho código).

105
Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b3
#define RS pin_b2
#include <pantallai.c>

void sumar() {
Int16 a,b,c,d,e;
d=0; b=1;
lcd_init();
lcd_clear();
printf(lcd_data,"Tabla de SUMAR");
while (d==0) {
lcd_cmd(192);
printf(lcd_data,"Tabla del %lu ",b);
if(input(pin_a0)) { b=b+1;delay_ms(200);}
if (b>9) b=1;
if (input(pin_a1)) d=1; }
lcd_clear();
printf(lcd_data,"Tabla del %lu ",b);
while (d==1) {
For (c=0; c<=10;c++) {
lcd_cmd(192);
e=b+c;
printf(lcd_data," %lu + %lu = %lu ", c,b,e);
while (e==0)
{ if (input(pin_a3)) e=1; }
e=0;
delay_ms(200);
if (c==10) d=2; } } }

void multiplicar() {
Int16 a,b,c,d,e;
d=0; b=1;
lcd_init();
lcd_clear();
printf(lcd_data,"Tabla de multiplicar");
while (d==0) {
lcd_cmd(192);
printf(lcd_data,"Tabla del %lu ",b);
if(input(pin_a0)) b=b+1;delay_ms(200);
if (input(pin_a1)) d==1; }
d=0;
lcd_clear();

106
printf(lcd_data,"Tabla del %lu ",b);
while (d==0) {
For (c=0; c<=10;c++) {
lcd_cmd(192);
e=c*b;
printf(lcd_data," %lu * %lu = %lu ", c,b,e);
while (e==0)
{ if (input(pin_a3)) e=1; }
e=0;
delay_ms(200);
if (c==10) d=1;} } }
void main () {
lcd_init();
lcd_clear();
printf(lcd_data,"Tabla de + pulse A0");
lcd_cmd(192);
printf(lcd_data,"Tabla de * pulse A1");
while (1) {
set_tris_a(0b11111);
set_tris_b(0b00000000);
If (input(pin_a0)) sumar();
If (input(pin_a2)) multiplicar(); }}

Circuito recomendado para el pregrama anterior.

Nota: Cuando traté compilar este programa me apareció el siguiente error en pantalla.

107
Lo que me dice que el PIC C no consigue el programa pant1.c en los directorios

Asegúrese de que el pant1.c (o el programa que tenga para manejar la pantalla) esté en
un directorio donde lo pueda conseguir PIC C, en mi caso estába en
#include <C:\pantallai.c>
y problema resuelto.

Programa para operar dos números entre 0 y 9, suma, resta, multiplicación, división,
con el pulsador conectado al pin_a0 aumenta el valor de los operandos, con el pulsador
conectado a pin_a1 cambia del primer operando para seleccionar el segundo operando,
luego otra vez con pin_a0 aumenta el valor del segundo operando y con el pulsador del
pin_a1 sale de ese bloque y entra a el bloque de selección de la operación +, -, / y *.
Secuencia:
1) Coloca el primer número a operar, cuando el programa arranca le pone el
número 0, pero presionando el pulsador del pin_a0, se puede aumentar hasta 9.
2) Presionar el pulsador conectado al pin_a1, para cambiar a seleccionar el 2do.
número.
3) Otra vez aparece el 0, pero presionando pin_a1 se puede aumentar hasta 9.
4) Ahora el programa necesita saber que operación quiere efectuar entre +, -, *, /.
5) Ahora en la pantalla se le informa que pulsador debe presionar según la
operación que desee realizar y la pantalla le mostrará el resultado.

Programa ejemplo para realizar cálculos básicos entre 0 y 9.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b2
#define RS pin_b3
#include <pantallai.c>

108
void sumar(int16 a,b)
{
int16 c;
char e; e='+';
c=a+b; }

void restar(int16 a,b)


{int16 c;
char e; e='-';
c=a-b; }

void multiplicar(int16 a,b)


{int16 c;
char e; e='*';
c=a*b; }

void dividir(int16 a,b)


{float c;
char e; e='/';
c=a/b; }

void main()
{
Int16 a,b,c,d,e;
lcd_init();
lcd_clear();
printf(lcd_data,"Operar 2 números");
while (1)
{

while (d==0)
{
printf(lcd_data,"valor1 = %lu ",a);
If (input(pin_a0)) a=a+1; delay_ms(200);
If (input(pin_a1)) d=1;
if(a>10) a=0;
}
d=0;
while (d==0)
{
printf(lcd_data,"valor2 = %lu ",b);
If (input(pin_a0)) b=b+1; delay_ms(200);
If (input(pin_a1)) d=1;
if(a>10) a=0;
}
d=0;
lcd_clear();

while (d==0)
{

109
lcd_clear();
printf(lcd_data,"+ A0, - A1, * A2, / A3" );
If (input(pin_a0)) sumar(a,b); d=1;
If (input(pin_a1)) restar(a,b);d=1;
If (input(pin_a2)) multiplicar(a,b); d=1;
If (input(pin_a3)) dividir(a,b);d=1;
}
lcd_cmd(192);
printf(lcd_data," %lu %c %lu = %lu ",a,e,b,c);
}
}

Programa calcular el residuo en una división. 50%23= 4


50/23=2.173 == > 50-2X23 = 50-46 = 4, (El residuo es 4).
Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b2
#define RS pin_b3
#include <pant.c>

void main ()
{
int x,y,z;
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
x=50;
y=23;
z=x%y;
printf(lcd_data," la suma de los valores");
lcd_cmd(192);
printf(lcd_data,"%u + %u = %u ",x,y,z);
}

Para sumar, restar y multiplicar un grupo de valores, : Para cambiar la operación,


cambié el operador en las lineas indicadas con color rojo.
Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0

110
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b2
#define RS pin_b3
#include <pant.c>
void main ()
{
Int16 x,y,z;
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();
lcd_clear();

for (x=0; x<=20; x++)


for (y=0; y<=20; y++)
{
z=x+y;
printf(lcd_data," la suma de los valores");
lcd_cmd(192);
printf(lcd_data,"%lu + %lu = %lu ",x,y,z);
delay_ms(1000);
lcd_clear(); } }

Nota: Cada línea del programa ya se ha explicado en otros programas ejemplos, por eso
en muchos programas no tiene sentido seguir redundando en explicar lo mismo una y
otra vez, solo me limitaré a explicar lo que en los programas anteriores no se ha
explicado y que en realidad necesite aclaratoria y/o una explicación, de cualquier
manera en la última sección del libro están muchos programas explicados con detalle,
en cuanto a su lógica y sintaxis.

Para comparar dos valores


Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b2
#define RS pin_b3
#include <pant.c>
void main ()
{
Int32 x,y,z;
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();

111
lcd_clear();
x=5; y=2; z=8;
printf(lcd_data," el mayor de los valores ");
lcd_cmd(192);
if ((x>z) && (x>y)) printf(lcd_data,” es %lu “,x);
if ((y>z) && (y>x)) printf(lcd_data,” es %lu “,y);
if ((z>y) && (z>x)) printf(lcd_data,” es %lu “,z);
}

En el programa anterior si lo desea puede cambiar los valores de las constantes (color
rojo) por los que quiera, (siempre que no tengan decimales ya que las variables se
declararon enteras sin decimales) y volver a correr el programa para verificar que su
lógica está buena, el programa solo muestra cual es el mayor de los valores. (es algo
muy sencillo pero didactico).

En el siguiente programa vamos a realizar unos cálculos muy sencillos, pero el lenguale
C, no los puede realizar si no se le indica que debe usar las rutinas del lenguaje C para
ello, por lo tanta debemos colocar en el encabezado la siguiente línea.
#include <math.h>
Lo que hace que C incluya toda una serie de funciones matemáticas.
Además debo aclarar que en todos los lenguajes que he trabajado los valores de los
ángulos siempre son asumidos por las computadoras en radianes, es decir sin(1) es
sin(1 radian) que es lo mismo que sin(57.3 grados), por lo tanto para trabajar en grados
que es lo habitual que se enseña en Venezuela necesito dividir al ángulo entre 57.3 por
lo que me queda teniendo como ángulo el valor de X.
Sin(X / 57.3) y el valor se le puede dar en grados directamente

Ahora las funciones valor absoluto, coseno, seno, tangente, menor entero, mayor
entero, exponencial, logaritmo natural y logaritmo decimal.

Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b3
#define RS pin_b2
#include <pantallai.c>
#include <math.h> == > para habilitar las funciones matemáticas y poder usarlas
void main ()
{
int16 a,b,d,e;
int16 g,h,i,j; === > declaración de variables enteras
float f;
float p,q,r,s,t,u,c,v; == > declaración de variables con decimales
set_tris_a(0b11111);

112
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
a=45/57.3; == > para convertir los radianes en grados (rad/57.3)=grados
b=60/57.3; c=-22; d=11.55; e=1000;
v=sqrt(e); == > cálcula la raiz cuadrada de e
p=sin(a); == > cálculo del seno (a)
q=cos(b); == > cálculo del caseno (a)
r=tan(a); == > cálculo de la tangente(a)
g=abs(c); == > cálculo del valor absoluto de c |c|
h=floor(d); == > cálculo del menor entero de d (d sin decimales)
i=ceil(d); ==> cálculo del valor mayor entero de d
f=exp(3); == > cálculo del exponencial de 3 e^3
t=log(c); == > cálculo del logaritmo natural (neperiano) de c
u=log10(1000); == > cálculo del logaritmo decimal d c
printf(lcd_data,"sen cos tan men");
lcd_cmd(192); == > para que imprima en la parte baja de la pantalla.
printf(lcd_data,"%2.2f %2.2f %2.2f %lu",p,q,r,h);
delay_ms(2000);
printf(lcd_data,"abs may exp log");
lcd_cmd(192);
printf(lcd_data,"%lu %lu %2.2f %2.2f, 2.2f",g,i,f,t,u);
delay_ms(2000);
}

Nota: printf(lcd_data,”%2.2f %2.2f %2.2f %lu”,p,q,r,h); se explica así:


Printf (lcd_data,” para imprimir lo que le sigue después de las comillas (“), %2.2f le
indica que la variable que va en ese lugar tiene hasta dos dígitos enteros y dos
decimales, %lu le dice que esa es una variable entera positiva y las variables en ese
orden son p, q, r y h

Nota: Hay un comando, while(input(pin_a0)) que me permite ejecutar una subrutina


mientras tenga presionada una tecla (En este caso un pulsador colocado en el pin_a0) , y
en este caso lo que hará, será incrementar un valor al presionar el pin_a0 y
decrementarlo al presionar el pin_a1.

Use el mismo circuito anterior para probar el programa.


Programa ejemplo
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define STB pin_b3
#define RS pin_b2
#include <pantallai.c>

113
void main ()
{
Int16 x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
printf(lcd_data,”prueba del pulsador”,);
while(1)
while(input(pin_a0))
{
delay_ms(100);
x=x+1;
lcd_cmd(192);
printf(lcd_data,” valor %lu “,x);
}
while(input(pin_a1))
{
delay_ms(100);
x=x-1;
lcd_cmd(192);
printf(lcd_data,” valor %lu “,x); } }

Tenga en cuenta que hay dos versiones del mismo comando while(input(pin_ax)) y
while(!input(pin_ax)), la diferencia está en que el primero lleva la resistencia
conectada a positivo y el pulsador a negativo y en otro la resistencia a negativo y el
pulsador a positivo, y funcionan de la misma forma.
Hay otras operaciones matemáticas las cuales no programaré, pero que las explicaré,
y=asin(x) para calcular el arcoseno, y=acos(x) para calcular el arcocoseno y el
y=atan(x) para calcular el arcotangente.

Dentro de un programa coloque esas funciones en una linea para calcular su valor,
recuerde que el resultado lo obtendrá en radianes, así, que si lo quiere en grados debe
multiplicar el resultado por 57.3. teóricamente ya sabe como mostrarlo en pantalla

A=(asin(x))*57.3; resultado en grados


B=(acos(x))*57.3;
C=(atan(x))*57.3;

114
LOS CIRCUTIOS INTEGRADOS DIGITALES TTL.

Los circuitos integrados TTL nos brindan tremenda ayuda a la hora de evitarnos muchas
líneas de código, todos estos circuitos tienen códigos cuyos números comienzan por
xx74xxyyy donde las x son letras y las y son números, aquí les voy a dar una lista de
circuitos integrados TTL de los muchos que existen y de gran utilidad.

7447 y 7448, son decodificadores que convierten una señal de cuatro bits codificadas en
un valor binario pasandolas a decimal en forma de 7segmentos, por los pines 7, 1, 2 ,6
le introducimos un código binario entre 0 (0b0000) y 9 (0b1001) y por los pines 13, 12,
11, 10, 9, 15 y 14 nos da las señales para ponérselas a un display 7segmentos y nos
mostrará el número en decimal.

7414 es un inversor con disparador de smith, es muy util debido a que con el podemos
estabilizar una señal e invertirla, y si no queremos invertirla la podemos invertir 2 veces
o sea conectamos la salida del primer inversor a la entrada del que le sigue al lado y
obtenemos una señal igual a la que entregamos al primer inversor pero estable.

7490 y 7493 son contadores de pulsos, que por supuesto dan el resultado en código
binario, y que al conectar estas salidas a la entrada de un 7448 o 7447 y estas a un
display podemos ver el número de veces que se ha pulsado el 7490 o el 7493 en su
entrada.

115
También hay circuitos que
cuentan ascendente y descendente (74190 , 74191 y 74193 entros otros).

Ahora necesitamos un circuito que nos genere los pulsos, y mejor aún si podemos
controlar la velocidad de los pulsos (su frecuencia).
El circuito integrado 555 o NE555, SE555, SA555 etc, como se conocen normalmente,
que tiene ciertas variantes, este circuito es muy util para producir pulsos de onda
cuadrada, en la internet aparece un manual en PDF de como confugurarlo para una serie
de señales diferentes, pero a nosotros nos interesa solo la señal de onda cuadrada,
Nota: Donde aparece el circulo no se conectan, es un error de dibujo.

116
Circuito contador de los pulsos generados por el 555, el condensador es de 1
microfaradio, la resistencia R1 es de 1000 omh y R2 es de 100000 omh.

Por supuesto que el anterior es un plano en parte lógico y en parte tal como se vería en
la realidad, porque es obvio que se debe alimentar a 7490, 7448 y al display.

Existen circuitos llamados decodificadores, demultiplexores o selectores, estos circuitos


son muy útiles debido a que nos permiten activar solo un circuito de entre varios que
están conectados en paralelo y trabajar con él sin alterar a los demás.

Analizaremos el 74LS154 al que usaremos como un selector.

117
La lógica de este circuito es muy sencilla, a pesar de la cantidad de pines que tiene, pués
realmente nosotros usamos 4, las demás funcionan solas.

Cuando está alimentado el 74LS154 en todo momento tendrá solo una de sus salidas en
estado negativo (esta es la seleccionada según la codificación del valor puesto en las
entradas), y las demás estarán en estado positivo, mientras los pines 18 y 19 deben estar
conectados a negativo, las entradas 23, 22, 21, 20 son las entradas por donde se
codificará el pin de salida que se desea poner en voltaje bajo, de este manera, si
ponemos el bit0 en alto, el bit1 en alto, el bit2 en bajo y el bit3 en bajo, la combinación
es 0011 (tres en binario), se pondrá en voltage bajo el pin nro. 4, los demás estarán en
voltage alto, de esta manera podemos seleccionar un dispositivo para su activación y los
demás quedan inactivos.

118
Nota: recuerde que voltage alto es 3 o más voltios y voltage bajo es 0 o muy pocos
voltios.

El 74XX374, es un circuito flip-flop tipo D, este tiene unas características especiales,


pero nosotros lo veremos como una memoria de un solo dato, esto para ciertas
aplicaciones es muy util, ya que lo que queremos es que solo nos almacene un dato, la
vantaja de esta memoria de un solo dato, es que el dato se recibe por unos pines
(entrada) y se entrega por otros pines (salida), lo que nos permite dar aplicaciones
directas que no tienen las memorias convencionales en las cuales los pines de entrada y
de salida son por lo general los mismos pines.

Ahora, ¿como funciona este circuito?, es sencillo, tiene 20 pines, 2 son alimentación +
y -, 8 son data de entrada, 8 son data de salida, uno es habilitación (para que responda
cuando se le mande) y el que falta es el lector de pulsos (lo llaman clock), una vez
alimentado y conectado el pin 1 de habilitación a corriente negativa, colocamos un dato
en los pines de entrada unos a 0 voltios y otros a 3 voltios, en los pines de salida
conectamos unos leds, y cuando le damos un pulso al pin 11 (lector de pulsos)
inmediatamente los pines de la salida ponen identicamente igual a los de la entrada, si
entrada D1 está en bajo, entonces salida Q1 se pone en bajo, a partir del momento del
pulso, no antes, y asi ocurre con los demás pines, la salida es una copia de la entrada
cuando se le da el pulso al pin_11, asi pueden estar cambiando permanentemente los
valores a la entrada y cuando quiero pasar un valor específico, solo le doy un pulso al
lector en el momento preciso para atrapar ese valor y pasarlo a la salida, este efecto es
demasiado util para cuando quiero mantener ciertos valores a la vista, pues podemos
usar el 74XX374 como un driver de displays 7segmentos.

Monte el siguiente circuito

119
Una vez que haya montado el circuito, ponga algunos apagadores a 5 voltios y deje
otros abiertos, cada vez que presione el pulsador de carga, se encenderán los leds cuya
entrada están a 5 volt. y apagarán los demás, cambie la combinación y vuelva a
presionar hasta que este claro de todo lo que está pasando.

Si en este circuito sustituimos los leds por un display 7segmentos y el pulsador de carga
por una conexión a un PIC, que cada vez que sea necesario dar un pulso, podríamos
almacenar ese dato automaticamente sin más que un simple programa.

Nota: Haga el mismo circuito, pero en vez de usar un TTL SN74LS374, use el
SN74LS574, que es el mismo integrado; pero con todas las entradas por un mismo lado
y las todas salidas por el otro costado, es un poco más sencillo de hacer el montaje en
protoboard, pero su lógica es igual.

En la sección que sigue, vamos a construir un contador, puede ser un contador de pulsos
o un cronómetro, lo importante es que se va a mostrar el valor que obtengamos en
diaplays 7segmentos, y además vamos a diseñar varios contadors con dos criterios.

Como ya nos hemos dado cuenta, en electronica digital tenemos circuitos capaces de
darnos muchos pulsos por segundo (frecuencia), pero cuantos pulsos por segundos
estamos capacitados para ver, y aún más, cuantos podemos contar, sabías que
dificilmente puedas observar una luz prenderse y apagarse si esta lo hace más de 25
veces por segundo, porque la retención de luz que queda en el ojo tarda más de lo que
esta luz se apaga y vualve a encender, y que valiéndonos de esto podemos tener varias
luces prendiendo y apagando alternadamente a una alta velocidad y nosotros las vemos
encendidas permanentemente.

Claro, este circuito es perfecto cuando necesitamos encender una cuantas luces,
digamos tres, máximo cuatro, pues por cada luz extra sería menos tiempo que
permanece encendia y más tiempo apagada, es decir con 2 luces cada una tendría 1/2 del

120
tiempo encendida, con 3 luces tendría 1/3 del tiempo encendida, con 10 luces solo 1/10
del tiempo encendida, y así de esta manera, pero que sucede si yo quiero hacer un
programa que envié los datos una sola vez y el resto que se mantenga haciendo
cualquier otra cosa hasta que esos datos cambien, sucede que nunca vería nada porque
la señal sería tan rápida que no la vemos, entonces es cuando se hace muy utíl usar un
74LS374 o un 74LS574 o un equivalente.

En los siguientes dos programas, hay aplicaciones y circuitos, en los cuales hay dos
formas de hacer lo mismo, pero una usa el 74LS374 y la otra no lo usa.

Observe cuidadosamente el circuito anterior y note lo siguiente.


1) Todos los segmentos de los displays están conectados en paralelo.
2) Todas las alimentaciones de los displays son independientes y están conectadas
a los pines de salida del puerto A.

Por lo tanto, si yo colocara un valor 7segmentos en el puerto B del microcontrolador y


activara la alimentación del primer display (usando el pin del puerto A que alimenta ese
display) este valor se verá en este display, luego al activar (cambiar la salida del pin_a0
al pin_a1) la alimentación del segundo display este también se verá en el segundo
display, (se observará el mismo número dos veces), pero valiéndome de la gran
velocidad del microcontrolador puediera poner un valor en el puerto B y activar la
alimentación del primer display, y luego desconectar la alimentación del primer display
y poner otro valor en el mismo puerto B y activar la alimentación del segundo display y
así ver otro valor, y si realizara esta tarea 200 veces en un segundo estaría viendo dos
números diferentes utilizando la misma salida del puerto B pero al alimentar
alternadamente los displays cambiando el valor del puerto B vería dos números
diferentes.

Si hacemos este proceso igual para los cinco displays entonces podríamos ver un
número de cinco dígitos diferentes usando un solo puerto de salida y alternando las
alimentaciones de los 5 displays.

Tenga en cuenta que usamos un display de catodo común, lo que quiere decir que este
display encenderá cuando enviemos voltage positivo por los pines del puerto B (hacia

121
los segmentos) y voltage negativo por los pines del puerto A. (el pin común para todos
los segmentos) un pin negativo y 7 positivos, si la salida del pin de puerto A no es
negativo nada encenderá.

Programa ejemplo.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>
void main ()
{
Int16 x;
Int a,b,c,d,e,f;
set_tris_a(0b00000);
set_tris_b(0b00000000);

while(1)
{
x=x+1;
a=floor(x/10000);
b=floor((x-10000*a)/1000);
c=floor((x-10000*a-1000*b)/100);
d=floor((x-10000*a-1000*b-100*c)/10);
e=x-10000*a-1000*b-100*c-10*d;
output_a(0b11111);
output_b(0b00000000);

if (a==0) a=63;
if(a==1) a=6;
if(a==2) a=91;
if(a==3) a=95;
if(a==4) a=102;
if(a==5) a=109;
if(a==6) a=124;
if(a==7) a=7;
if(a==8) a=127;
if(a=9) a=103;

if (b==0) b=63;
if(b==1) b=6;
if(b==2) b=91;
if(b==3) b=95;
if(b==4) b=102;
if(b==5) b=109;
if(b==6) b=124;
if(b==7) b=7;
if(b==8) b=127;
if(b=9) b=103;

122
if (c==0) c=63;
if(c==1) c=6;
if(c==2) c=91;
if(c==3) c=95;
if(c==4) c=102;
if(c==5) c=109;
if(c==6) c=124;
if(c==7) c=7;
if(c==8) c=127;
if(c=9) c=103;
if (d==0) d=63;
if(d==1) d=6;
if(d==2) d=91;
if(d==3) d=95;
if(d==4) d=102;
if(d==5) d=109;
if(d==6) d=124;
if(d==7) d=7;
if(d==8) d=127;
if(d=9) d=103;

if (e==0) e=63;
if(e==1) e=6;
if(e==2) e=91;
if(e==3) e=95;
if(e==4) e=102;
if(e==5) e=109;
if(e==6) e=124;
if(e==7) e=7;
if(e==8) e=127;
if(e=9) e=103;

for (f=0;f<=100;f++)
{
output_a(0b11111);
output_b(a);
output_a(0b01111); delay_ms(10);
output_a(0b11111);
output_b(b);
output_a(0b10111); delay_ms(10);
output_a(0b11111);
output_b(c);
output_a(0b11011); delay_ms(10);
output_a(0b11111);
output_b(d);
output_a(0b11101); delay_ms(10);
output_a(0b11111);
output_b(e);
output_a(0b11110); delay_ms(10);

123
}
}
}

En el programa anterior debo dar la siguiente explicación según ciertas partes del
programa.

x=x+1;
a=floor(x/10000);
b=floor((x-10000*a)/1000);
c=floor((x-10000*a-1000*b)/100);
d=floor((x-10000*a-1000*b-100*c)/10);
e=x-10000*a-1000*b-100*c-10*d;

#include <math.h> Lo usamos en la cabecera porque necesitamos habilitar la funcion


matematicas de menor entero floor(x);.

x=x+1; Es el incremento de la variable x, que es el valor que se va a descomponer en


digitos para poder ser mostrada en los displays 7segmentos.

a=floor(x/10000); El comando floor(valor.dcimales) le quita los decimales a un


número positivo y solo nos deja el valor entero, al dividir un número de 5digitos entre
10000 nos de un numero de un digito y cuatro decimles que al extraerle el entero nos
libramos de los decimales.

b=floor((x-10000*a)/1000); Luego si al número de 5 digitos le restamos el anterior


cálculado y multiplicado por 10000 nos queda un número de 4 digitos y le aplicamos la
misma para extraer su mayor digito (sin decimales).

c=floor((x-10000*a-1000*b)/100); le aplico la misma que a los 2 anteriores.

d=floor((x-10000*a-1000*b-100*c)/10); Igual a los anteriores.

e=x-10000*a-1000*b-100*c-10*d; y aquí obtengo el último dígito,

output_a(0b11111); Pongo todo el puerto A en positivo para que no encienda ningún


digito. (recuerde que estos display sin catodo común)
output_b(0); Apago todos los pines del puerto B.(los segmentos).

Ahora ya tengo todos los digitos sueltos y asignados en las variables a, b, c, d y e,


además tengo apagados todos los segmentos y los digitos.

124
Conversión para ver los valores en los displays

if (a==0) a=63;
if(a==1) a=6;
if(a==2) a=91;
if(a==3) a=95;
if(a==4) a=102;
if(a==5) a=109;
if(a==6) a=124;
if(a==7) a=7;
if(a==8) a=127;
if(a=9) a=103;

Nota: Cuando el valor de a es 0 (cero), los pines que hacen que se enciendan los leds
para poder observar el cero en un display 7segmentos son los pines b0, b1, b2, b3, b4 y
b5, lo que da un número binario 0b00111111 que en decimal es 63, por eso se hace la
equivalencia entre el valor del número (0) y el que produce la representación en el
display 7segmentos (63), también se podría usar el número en binario como
a=(0b00111111).

Otra explicación de lo mismo.

Este paso es una conversión sencilla de entender se si hace de la siguiente manera.


1) Solo la voy a explicar la converción de los números 1 y 8, por qué?, porque 1 es
el digito que enciende menos segmentos (solo dos, el segmento B y el segmento
C) y 8 porque es el que enciende más segmentos (todos los segmentos, desde A,
hasta G). Nota: recuerde la configuración de un display 7segmentos.
2) Ahora, el puerto B tiene 8 pines de los cuales vamos a usar 7 para encender
totalmente un display.
3) Así que asignamos (conectamos) a cada pin del puerto B un segmento
especifico, pin_B0 con en segmento A, pin_B1 con el segmento B, pin_B2 con
el segmento C y así sucesivamente hasta pin_B7 con segmento G.
4) Ahora si queremos visualizar el numero 8 tenemos que enviar voltaje alto a los 7
segmentos, es decir, por los 7 primeros pines del puerto B y así se encenderán
los segmentos que muestran el numero 8.

5) Si quiero visualizar el número 1, solo tengo que enviar voltaje a los segmentos B
y C, y estos están conectados a los pines 1 y 2 del puerto B, así que solo envío
voltaje a los pines 1 y 2, pero enviar voltaje a los pines 1 y 2, es hacer esto
output_b(0b00000110); y este es el número 6 en binario, o sea que la
conversión para ver el número 1 en el display enviando voltaje por el puerto B
equivale a enviar el número 6 y así enciendo los segmentos B y C, por eso es
que se convierte el número 1 del digito en 6 para salida por el puerto B, y el
número 8 de digito en el número 127 de salida por el puerto B. Porque si mando
el número 8 (0b00001000) directamente sin hacer esta conversión por el puerto
B solo encenderé el segmento más bajo el que llaman piso en las direcciones de
correo electrónico y eso no se parece a un 8.

125
Claro, toda esta conversión me la puedo evitar si uso un circuto integrado TTL 7448,
7447 o 7449 dependiendo del display que convierte los valores directamente de binario
a 7segmentos, pero esto se trata a veces más de echar código y saltarse los circuitos y
otras de saltarse el código y agarrarse de los circuitos.

Ahora vamos a hacer lo mismo, pero con otro circuito y otro programa, por supuesto
que son parecidos. (A más circuitos auxiliares, menos código de programa).

El circuito arriba se explica de la siguiente manera:

1) Generamos números de 8 digitos en el microcontrolador


2) Usando algún metodo como el del programa anterior lo separamos en dígitos
independientes (8 digitos).
3) Sacamos esos valores digito por digito por los primeros 4 pines del puerto A
(Para números menores a diez con 4bits es más que suficiente).
4) Esos valores que salen en código binario por el puerto A, los introducimos en el
decodificador 7448 o 7449 que nos los convierte en señales para introducir
directamente en los displays 7segmentos.
5) Pero antes los metemos en el 74xx374 o 74xx574 para memorizarlos y luego, si
los pasamos a los displays.
6) Con los pines que me quedan libres, 8 del puerto B puedo producir el
almacenamiento de los 8 digitos en los 8 IC 74XX374 y visualizarlos en los
displays.
7) Por el diagrama puedo ver que la secuencia será de menor a mayor B0, B1, B2,
B3, B4, B5, B6 y B7, el valor B0 es de más bajo valor (las unidades).

Nota: las alimentaciones de los IC TTL, el microcontrolador y los displays es algo


obvio, y el pin que queda libre en el 74XX374 es porque este IC trabaja con 8 bits y el
display con 7 bits.

Programa ejemplo del contador de ocho dígitos

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>
void main ()
{
Int32 x;

126
Int16 y,z;
Int a,b,c,d,e,f,g,h,i,j,k;
set_tris_a(0b00000);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);
while(1)
{
delay_ms(100);
x=x+1;
y=floor(x/1000);
z=x-1000*y;
a=floor(y/1000);
b=floor((y-1000*a)/100);
c=floor((y-1000*a-100*b)/10);
d=floor(y-1000*a-100*b-10*c);
f=floor(z/1000);
g=floor((z-1000*f)/100);
h=floor((z-1000*f-100*g)/10);
i=z-1000*f-100*g-10*h;
output_b(i);
output_high(pin_b0);
output_low(pin_b0);
output_b(h);
output_high(pin_b1);
output_low(pin_b1);
output_b(g);
output_high(pin_b2);
output_low(pin_b2);
output_b(f);
output_high(pin_b3);
output_low(pin_b3);
output_b(d);
output_high(pin_b4);
output_low(pin_b4);
output_b(c);
output_high(pin_b5);
output_low(pin_b5);
output_b(b);
output_high(pin_b6);
output_low(pin_b6);
output_b(a);
output_high(pin_b7);
output_low(pin_b7);
}}

Es obvio, no solo que este programa es más corto y más facil de hacer, sino que cuenta
hasta el número 99 999 999 mientras que el otro cuenta hasta el 99 999, le coloqué un
delay_ms(100); para evitar que avanzara demasiado rápido, no necesita estar

127
refrescando la señal de los digitos para que el ojo humano los pueda verlos, además si el
programa se detiene al menos sigo viendo los digitos en donde quedó la cuenta, pero es
más costoso por los flip-flop tipo D.

Una explicación de algunas partes del código del programa.

x=x+1;
y=floor(x/1000);
z=x-10000*y;

Aquí primero divido el número de 8 digitos en dos partes (variables), de 4 digitos, una
variable y y una variable z . Para facilitarme en volverlo puros dígitos por separados

La visualización del primer dígito


output_a(i);
output_high(pin_b0);
output_low(pin_b0);

Primero extraigo el valor de a que es el primer dígito, (recuerde que este va


directamente a un 7447 ó 7448, que lo convierte en código de 7segmentos directamente,
y la salida de esta va a la entrada de un TTL 74374 ó 74574 (memoria de un dato),
luego de un pulso se queda atrapado en la salida del TTL y pasa el display de forma fija.

output_high(pin_B0) y output_low(pin_B0) dan en el pin_B0 un pulso que se mete en


el primer TTL flip-flop-D y carga el valor del primer digito en el primer display, y asi
sucesivamente, lo que tengo que cambiar es el pin donde voy a dar el pulso y el valor
del digito, una tarea que se repite 8 veces en cada corrida.

Nota: si yo defino una matriz de variables y les asigno los valores de los digitos y los
pines, hago aún más corto el programa, pero ahora me interesa que entiendas un poco
más la parte electrónica y la lógica digital que la programación.

Nota: Si en vez de enviar directamente los pulsos de carga del pic a los TTL flip-flops-
D los intoduzco en un par de decodificadores/selectores 74LS154 en vez de tener un
numero de 9 digitos podría tener uno de 32 digitos y si hago un arreglo en cascada no sé
hasta que cantidad de dígitos podría alcanzar, pero por lo bajito serían 256 digitos.
(verífiquelo y si ud tiene una buena imaginación seguro esta cifra se queda pequeña).

Hasta ahora he trabajado con el PIC 16F84A, que como se han dado cuenta, sirve para
bastante, sin embargo ya lo vamos a dejar atrás, no porque se haya llegado a su límite,
porque el límite de un microcontrolador está principalmente en la imaginación y
después en su conocimiento tanto del mismo microcontrolador y del dominio del
lenguaje con el que cada quien lo programe, y por favor no nos basemos en la capacidad
del PIC en cuanto a su memoria RAM, ROM, FLASH; PINES, de hecho la proxima
aplicación que voy a montar también se puede hacer con el 16F84A, pero como
inmediatamente después voy a pasar a una que este no la posee entonces prefiero dar el
cambio desde ya.

128
AVANCE DEL MICROCONTROLADOR PIC16F84A AL PIC16F876A

Ahora vamos a pasar de grado, vamos pasar al PIC 16F876 o PIC 16F876A, lo
principal que salta a la vista de este microcontrolador es que tiene 28 pines (10 más que
el anterior), pero pienso que eso no es realmente el avance, es como pasar de un carro
regulado de 5 personas y motor 4 cilindros simple a uno de 9 puestos, con motor 8
cilindros y además aire acondicionado y radio, y después vendrán las camionestas
rusticas de lujo.

Que tiene este microcontrolador por encima del anterior además de los pines, yo no sé
exactamente todo lo que tiene por encima, pero lo que sé que tiene es suficiente para
decir que es un avance.

Nota: Nunca desprecie un microcontrolador porque este le parezca pequeño en su


tamaño, recuerde que este tiene gran cantidad de aplicaciones, y tiene lo mismo que
tienen los grandes: tiene microprocesador, unidad lógico aritmética, memorias y
puertos de salida y entrada, además tenga en cuenta que cuando el hombre llegó a la
luna, lo hizo con una computadora que hoy día es comparable a una con un
microprocesador 386, lo principal es el conocimiento del lenguaje de programación,
la imaginación, la tenacidad ante los problemas y mucha práctica en cuanto a hacer
programas, por simples que sean o complejos, estos nos ayudan a perfeccionarnos en
esta área del conocimiento tecnológico.

REPASO DE ALGUNAS COSAS IMPORTANTES

Pinado del microcontrolador PIC16F876A.

1) Un microcontrolador es un circuito integrado que tiene una cierta cantidad de


pines (patas), de las cuales unas tienen una función fija, es decir solo sirven para

129
una y solo una cosa, por ejemplo la alimentación, y tienen otros pines que no
sirven para nada, hasta que el microcontrolador está programado, parece un
chiste, pero es así, hay pines en los cuales se puede observar por ejemplo:
RA3/AN3/VREF+, el pin Nro. 5 tiene tres alternativas, pero ninguna de ellas
estará en funcionamiento si el PIC no ha sido programado y además
especificado que función tendrá dicho pin_xx, y además tenga bien claro que un
pin después de programado solo ejecutará una función, no piense que en una
misma aplicación el pin Nro 5 una rato será RA3, otro rato será AN3 y otro será
VREF+.
2) En muchos casos es necesario hacer una declaración en el encabezado del
programa para poder poner a funcionar ciertas tareas que el microcontrolador
realiza.

PIC16F876 / PIC 16F876A, 28 PINES

A partir de este momento vamos a trabajar con el PIC16F876 o el PIC16F876A, es


indiferente, ahora necesito explicar ciertas conceptos antes de entrar en los programas
y aplicaciones para este microcontrolador.

EL CONVERTIDOR ANALÓGICO A DIGITAL

Primero: ¿Qué es un convertidor analogico digital?.

Lo más simple que pudiera decir es que es algo que convierte un valor de analógico a
digital, es !obvio!, la mejor explicación es que cuando tenemos una magnitud en físico,
esta magnitud la podemos expresar en números, por ejemplo, cuando nos montamos en
un peso tradicional tipo balanza, o se mueven unas agujas sobre una escala de números,
o se mueve un circulo graduado detrás de una linea de referencia y somos nosotros los
que tenemos que leer y dar cierta interpretción del valor númerico que estamos leyendo.
Sin embargo cuando en vez de pesarnos o colocamos un peso sobre una balanza, está
nos da el valor del peso directamente con números en una pantalla sin la necesidad de
que nosotros tengamos que interpretar alguna lectura, entonces estamos frente a un
convertidor analógico a digital.

Ahora, cuando nosotros vamos a crear o a aplicar un convertidor analógico a digital


tenemos que tener en cuenta los siguientes parametros.
a-) Con que lectura física este convertidor nos tiene que mostrar cero (0),
b-) Con que lectura física nos tiene que mostrar el máximo (100%),
c-) Entre lectura y lectura cual es la diferencia.

Explicación: Cuando vamos a construir un convertidor analógico a digital, lo primero


que necesitamos es un transductor (un aparatico) que nos convierta cualquier estímulo
fisico o magnitud fisica en una señal electrica, o que al menos influya sobre una
corriente eléctrica alterándola de alguna forma que nosotros podamos medir, (voltaje
y/o corriente), por ejemplo, un micrófono de membrana es un transductor que convierte

130
el sonido en señales eléctricas, pero un micórofono de carbón es un transductor que
cambia su resistencia al paso de la electricidad con el sonido, lo cual los hace diferentes;
pero que sirven para lo mismo, (capturar sonido y transmitirlo en forma de señales
electricas).

Ahora si usamos un micrófono de membrana y lo sometemos a una cierta cantidad de


ruido, digamos 80 decibeles y medimos la corriente que se produce en la salida de sus
hilos de cobre de la bobina y esta nos da (por deicr algo) 1 miliamperio, podemos decir
con certeza que cuando este micrófono está producuiendo en su bobina una corriente de
1 miliamperio entonces está en un lugar con un nivel de ruido muy proximo a los 80
decibeles.

Ahora cambiemos de micrófono, usemos un micrófono de carbón, conectémoslo a una


corriente de 100 miliamperios y con un voltage en los extremos de sus conexiones de
10 voltios (por decir algún valor), y pongámoslo en el sitio donde anteriormente estaba
el de membrana y observamos que la corriente subió al doble, 200 miliamperios, y que
el voltaje en sus términales cayo a la mitad, 5 voltios, entonces podemos afirmar que
este micrófono cuando está sometido a un nivel de ruido de 80 decibeles cambia su
resistencia a la mitad.

Los casos anteriores son dos casos de transductores, uno produce impulsos ante un
estímulo y otro cambia sus propiedades electricas ante el mismo estímulo, pero lo
importante es que ambos reccionan ante estumilos o megnitudes físicas y producen un
efecto electrico que podemos usar para convertirlo en información y trabajar con ella.

Ahora, una vez que ya tenemos el efecto electrico, (bien sea crear una corriente o influir
sobre el paso de otra corriente), solo tenemos que poder medirla y ponerle los
parametros que queremos.
Entonces un transductor es un dispositivo que convierte un estimulo o magnitud física
en una señal electrica (corriente, votaje, resistencia, magnetismo, etc) y la cual a partir
de ese momento ya depende de nosotros con el microcontrolador poder manejar y
aprovechar, y un covertidor analógico a digital es un dispositivo que mide una señal
eléctrica y nos la muestra en dígitos (numeritos) en una pantalla.

Ejemplo: Supongamos que el transductor que tenemos nos convierte un estímulo en


voltaje, ¿qué és lo que tenemos que averiguar de este voltaje?, (XXXX), cual es la
relación que hay entre el estímulo que se está recibiendo y el voltaje que se está
produciendo en el transductor, de tal manera que yo le pueda poner números para tener
la cantidad de estimulo que se está recibiendo en números.

Veamos con el siguiente ejemplo:


Tengo un transductor que cambia su resistencia con la temperatura, a más caliente esté
el ambiente, su resistencia será mayor, ¿entonces que hago?, le coloco un voltage en sus
estremos con un voltímetro y un termometro pegado, los tres en paralelo y veo en el
voltímetro cuanto voltage hay en sus extremos, y anoto la temperatura y el voltaje,
luego lo caliento un poquito, y vuelvo a anotar temperatura y voltage, lo caliento otro
poquito y anoto, y así hasta que tengo la rata de variación de voltage en los extremos de
la conexion del transductor con respecto a la temperatura, luego con estos datos tomo
mi transductor y lo conecto a mi microcontrolador (tenga en cuenta que debe ponerle el
mismo voltage para que se comporte igual) y esos datos los pongo en el programa que

131
lo controla y hago que me muestre las lecturas en una pantalla y tengo un termómetro
dígital, esto suena facil y es facil pero trabajoso.

Ahora ¿Como le pongo los parametros a un convertidor analógico digital que ya está
construido en un chip? (circuito integrado).

Como los convertidoes analógicos a digitales lo que hacen es leer voltajes (por lo
general), ellos tienen una serie de pines con sus funciones específicas.

Explicación de como funciona este ADC0804 convertidor analógico digital.

Pin 1: /CS Es el pin que hace que este chip se active, (recuerde que aunque el chip
esté encendido si no está seleccionado como activado no funciona), el que
aparezca con una barra sobre la CS indica que se activa cuando este pin está
conectado a negativo, y si está a 5 voltios está congelado (no funciona)

Pin 2: /RD Es el pin que envía el valor del dato ya convertido en digital a los pines
de salida, (recuerde que esté dato se presenta en codigo binario)

Pin 3: /WR Es el pin que hace que se realice la conversión del valor que el
convertidor tiene en su entrada analógica, (este pin debe durar al menos 0.25
milisegundos en negativo para que se realice la conversión, ya que realizar este
trabajo lleva su tiempo)

Pin 5: Este pin no es controlado por nosotros, pues el se pone (por si solo) a
voltage alto (3~5 volt) para indicar que está haciendo la conversión en ese momento,
y cuando termina de hacer la conversión se vuelve a poner a nivel bajo (0 volt).

Pines 6 y 7 Vin+ y Vin-: son los pines por donde voy a conectar los terminales de
mi transductor, o sea el voltaje a convertir en valor digital. (tenga en cuenta que el
rango de trabajo de este voltage de entrada es desde 0volt a 5volt ó de 0Volt a 2.5
volt.

Nota: El convertidor analógico digital puede tener cualquier rango de entrada para
convertir en digital, ahora como sé en que voltage de conversión está trabajando en
cualquier momento. Facil!, si el pin 9 Vref/2 de voltage de referencia no esta
conectado (está suelto o flotante) el voltage positivo de referencia máximo de
entrada es de 2.5 voltios (la mitad de su alimentación) y si está conectado a un
voltaje cualquiera mayor que 0volt y menor o igual 5volt. (0< entrada <=5volt),
es entonces ese el voltage que el convertidor reconoce como máximo.

132
Porqué esto es importante dominarlo: Porque el convertidor le dará un valor
máximo con el voltaje maximo de entrada y minimo con el voltaje mínimo de
entrada.
En otras palabras, si un convertidor analógico a digital trabaja entre 5 y 10 voltios,
nos dará lecturas de 0% hasta que tenga una entrada superior a 5Volt., y nos dará
lecturas de 100% cuando tenga en su entrada voltajes iguales o superiores a 10
voltios, asumiendo como 0% el mínimo valor de salida y 100% el máximo valor de
salida.
Explicación detallada de rango de entrada y valor de salida.
1) Observe que el ADC0804 tiene 8 bits de salida pines 18, 17, 16, 15, 14, 13, 12 y
11, lo que dice que con esos 8 bits se puede escribir en binario desde 0 (todos
apagados) hasta 255 ( todos prendidos).
2) Supongamos que yo conecto el pin de voltaje de referencia (pin 9 Vref/2) lo
conecto a 5volt. Por lo tanto el rango de entrada que yo decidí está entre 0 volt y
5 volt. Entonces si yo conecto a los pines 6 y 7 (entradas analógicas) 0 voltios la
salida que veo en los pines de salida es 0 (todos los pines de salida apagados), y
si conecto 5 voltios a los pines 6 y 7, entonces el valor que me presenta el
convertidor a su salida es 255 (todos lo pines encendidos) pero es obvio que no
tengo 255 volt puesto a la entrada, entonces que hago, busco por cuanto tengo de
dividir a 255 para que me de 5 (a la salida) y este número és 51, entonces yo en
mi programa controlador coloco que el valor obtenido de la conversión me lo
divida entre 51 y obtengo a la salida el valor en digital entre 0volt y 5volt igual a
la entrada entre 0volt y 5volt , ademas si divido 5volt/51 = 0.098, lo que quiere
decir que tengo una apreciación menor que 0.01 voltios.

Los pines 19 y 4 puede conectarlos con una resistencia de 10K mientras el pin 4
está conectado a negativo através de un condensador de 150Pf

AGND es la tierra del circuito analógico y DGND en la tierra del circuito digital y
el negativo normal del circuto.(tenga en cuenta que el circuito de donde obtiene el
voltage analógico puede ser externo al circuito digital donde tiene el convertidor.

Ahora, también existe la posibilidad de tener a este circuito convirtiendo


constantemente el valor presente en su entrada analógica a digital.

133
El siguiente circuito mantiene al convertidor analógico a digital trabajando en la
conversión constantemente, pero tenga en cuenta que si el voltaje a la entrada
cambia muy rápido, podría darse que el valor en la salida digital sea diferente al de
la entrada analógica, (claro estamos hablando de tiempo alrededor de 0.25
milisegundos), esto podría parecer rídiculo pero hay fenómenos en los que se podría
tener que saber la variación de temperatura a tiempos más cortos.

CIRCUITO QUE PERMITE TENER EL ADC0804 TRABAJANDO


PERMANENTEMENTE

Bueno, ahora sepa que los PIC 16F876 tienen incorporado un convertidor analógico
digital, que los pines de entrada del valor analógico están en el puerto A, que en el
PIN_A3 se coloca el voltage de referencia positivo VREF+ (optativo) y en el PIN_A2
el voltaje de referencia negativo (optativo), y que si no coloca nada como referencia, la
referencia es la alimentación de 0 a 5volt, observe en el diagrama de pines, que en los
pines del puerto A aparece las opción ANO, AN1, AN2, etc, indicando que estos pines
pueden ser usados como entradas convertidoras analógicos a digitales, (no olvide que si
va a usar un pin como convertidor analógico digital debe declararlo en el encabzado con
la línea #device adc=N, donde N es la cantidad de bits con la que desea trabajar en la
conversión, si es 10 (lo normal), entonces tendrá 2^10=1024 divisiones entre el valor
más bajo y el valor más alto de la conversión, si como en el ejemplo trabaja con 0 a 5
voltios, tendrá una apreciacion de 5/1024 = 0.00488 voltios de apreciación.

NOTA: El PIC no le va a dar salida binaria, ésta la puede observar en decimal


directamente en la pantalla LCD o displays .

134
EL MODULADOR DE ANCHO DE PULSOS

El Modulador de ancho de pulsos.

Un modulador de ancho de pulso es un oscilador de onda rectangular (que pudiera


ser cuadrada cuando trabaja al 50%) al que le puedo controlar su ciclo de trabajo.
Ciclo de trabajo: Una persona tiene un clclo de trabajo de 1/3 (33.33..%) porque de
las 24 horas del día trabaja 8 horas y descanza 16 horas. Entonces el ciclo de trabajo
es la porción del ciclo (de una oscilación completa) que está en voltaje alto, por lo
tanto cuando el tiempo que esta onda rectangular dura lo mismo en su voltaje alto
(5Volt) y voltaje bajo (0volt) está al 50% o tiene onda cuadrada, pero este es un caso
particular.

Con los microcontroladores yo puedo facilmente controlar la forma de la onda,


desde ciclo de trabajo al 100% (no hay onda sino que está todo el tiempo en voltaje
alto) hasta 0%, (todo el tiempo en voltaje 0), entre esos dos estados hay hasta
1024 posibilidades, desde 0 -1024 hasta 1024-0, cuando use 512-512 estará con un
ciclo de 50%.

Estos moduladores de ancho de pulso se usan para controlar desde la cantidad de


iluminación que entrega un foco de luz, hasta la velocidad de un motor DC, etc., ya
que con ellos podemos controlar la cantidad de energía que le entragamos a un
dispositivo que trabaja con energía eléctrica.

Claro tambien podemos controlar el tiempo del ciclo completo, es decir, si quiero
que un motor dc trabaje con el 50% de la energía disponible en la línea y lo
energizo durante una hora y lo desenergizo durante la que sigue, le estoy entregando
la mitad de la energía que pudiera recibir en dos horas, pero este ciclo de 2 horas no
me sirve para nada ya que el motor alcanzaría su máxima velocidad en unos
segundos y los restantes se mantendría a esa velocidad, y luego en pocos segundos
se detendría y se mantendría así durante el tiempo restante de esa hora detenido, lo

135
conveniente sería tener ciclos de unos 0.01 segundo, es decir, que si el ciclo
completo dura 0.01 seg a 50% de carga duraría 0.005 seg en alto y 0.005 seg en
bajo, tiempo lo suficientemente corto como para que ni el mismo motor se de
cuenta que lo están encendiendo y apagando 100 veces en un segundo.
Más adelante encontrará un programa para controlar bastante bien la velocidad de
un motor DC (rps, rpm o rpcs).

AJUSTE DE UNA SEÑAL ANALÓGICA

Cuando estamos recibiendo una señal que debe ser tratada (trabajada), no siempre
está nos llega de la forma más adecuada para procesarla, por ejemplo: Si estamos en
un concierto y nos toca estar muy lejos de los músicos no apreciaríamos su música
de no ser por los amplificadres y altavoces, entonces la señal de los instrumentos y
las voces fueron tratadas, no solo amplificadas, también se les modifica el tono
según sea el recinto donde estén cantando, de la misma manera si necesitamos
observar algo en la superficie del sol necesitamos disminuir la intensidad de su luz
con algo para poder observar su superficie, de lo contrario nos incandilamos.

Pero no solo las señales se amplifican, disminuyen o cambia su tono, hay muchos
casos en los que hay que tratarlas para depurarlas de ruidos que las distosionan,
invierten etc.(esto generalmente ocurre en comunicaciones a largas distancias, bien
sea con ondas o con cables de hilos de cobre etc), afortunadamente a nosotros no
nos toca depurarlas debido a que las señales que vamos a ajustar son señales en las
que lo que nos interesa es solo el cambio del valor del voltaje que se produce en un
transductor, y por lo general solo debemos ajustarla con un amplificador
operacional, usando una resistencia variable hasta que obtengamos el rango en el
valor deseado.

Un amplificador operacional es un dispositivo que generalmente se usa para ajustar


señales según un patrón que deseemos.

136
El pin 4 es la alimentación positiva y el pin 11 es la alimentación negativa, R1 es la
resistencia de atenuación de entrada inversora, R2 es una resistencia de atenuación a
masa.

A la izquierda el símbolo del amplificador operacional, a la derecha el circuito


integrado LM324 que contiene 4 amplificadores operacionales que usaremos para
ajustar algunas señales, y en la parte inferior el circuito con sus resistencias de
atenuación de la señal.

LOS AMPLIFICADORES OPERACIONALES

Explicación breve con esquemas y configuraciones externas.

Un amplificador operacional en un dispositivo de amplificación de muy alta


ganancia, el cual tiene multiples formas de usarse y configurarse.
El símbolo de un amplificador operacional es el siguiente:

Los Terminales son: V+: Entrada no inversora. V-: Entrada Inversora


Vout: Salida Vs+: Alimentación positiva Vs-: Alimentación negativa.
Normalmente los pines de alimentación son omitidos en los diagramas eléctricos por
razones de simplicidad de los esquemas
.
Configuración de Lazo Abierto:
Si no existe realimentación, la salida del AO (amplificador operacional) será la resta
de sus 2 entradas multiplicada por un factor (factor de amplificación). Este factor suele
ser del orden de 100000 (que se considera infinito en cálculos con el componente ideal).
Por lo tanto si la diferencia entre las 2 tensiones es de 1mV la salida debería de ser
100V. Pero debido a la limitación que supone no poder entregar más tensión de la que
hay en la alimentación, el AO (amplificador operacional) estará saturado si se da este
caso. Si la tensión más alta es la aplicada a la terminal positiva la salida será la que

137
corresponde a la alimentación Vs+, mientras que si la tensión más alta es la de la
terminal negativa la salida será la alimentación Vs-
Configuración de Lazo Cerrado:
(Es la que pretenderemos usar por su simplicidad)
Se conoce como lazo cerrado a la retroalimentación en un circuito. Aquí se supondrá
realimentación negativa. Para conocer el funcionamiento de esta configuración se parte
de las tensiones en las 2 entradas exactamente iguales, se supone que la tensión en la
terminal positiva sube y por lo tanto la tensión en la salida también se eleva. Como
existe la realimentación entre la salida y la entrada de terminal negativa, la tensión en
esta terminal también se eleva, por tanto la diferencia entre las 2 entradas se reduce,
disminuyéndose también la salida este proceso pronto se estabiliza y se tiene que la
salida es la necesaria para mantener las 2 entradas, idealmente con el mismo valor.

Siempre que hay realimentación negativa se aplican estas 2 aproximaciones para


analizar el circuito:
V+ = V- I+ = I - = 0

Alimentación:

El amplificador operacional puede ser polarizado, tanto con tensiones simples


(tensión positiva +5volt. y tensión cero 0volt.) como con tensiones simétricas (tensión
positiva +5volt. y tensión negativa -5volt.), si utilizamos tensiones simples, a la salida
no podremos conseguir valores menores de 0V. El valor de estas tensiones no suele ser
fijo, dando los fabricantes un margen entre un máximo y un mínimo, no teniendo
ninguna consecuencia en el funcionamiento del amplificador el valor de tensión que se
escoja, únicamente las tensiones de salida nunca superaran las tensiones de
alimentación.

Bueno, en todo caso no se preocupe si cree que es algo complicado por los diagramas,
cuando usemos el Amplificador Operacional se dará cuenta que lo que se va a hacer es
muy sencillo, de hecho usaremos uno solo (AO) y los otros tres quedarán sin
conectarse.

138
En el diagrama: Rojo alimentación positiva.
Azul alimentación negativa.
Violeta señal de entrada al amplificador.
Verde señal de salida amplificada.

EL CAPTURADOR

El capturador es un pin del grupo de los pines CCP, CCP significa Capturador,
Comparador, Pulsador (modulador de ancho de pulsos), en el caso de configurar a
CCPx, (con x= 1, 2, 3, 4, 5, 6) como capturador de un pulso, también debemos decirle a
que flanco debe responder:

Flanco de subida: Cuando la entrada cambia de negativo a pisitivo.


Flanco de bajada: Cuando la entrada cambia de positivo a negativo.
Cada 4 pulsos o cada 16 pulsos.

Setup_ccp1(ccp_capture_re) flanco de subida


Setup_ccp1(ccp_capture_fe) flanco de bajada
Setup_ccp1(ccp_captura_div_4) cada 4 pulsos
Setup_ccp1(ccp_capture_div_16) cada 16 pulsos

En el PIC16F876 los pines para captura de un flanco de pulso y de modulación de


ancho de pulso son los pines 12 y 13, el PIC16F84 no posee esta propiedad.

139
Los temporizadores y contadores son elementos dentro de los microcontroladores que: o
bien cuentan pulsos en los pines de los timers (contadores) o bien internamente
contabilizan tiempos o retardos.

Para nuestro caso los usaremos principalmente como contadores de eventos externos
que producen pulsos y los introducimos en los pines de entrada de los timers.

Recuadro rojo timer 0 clock in (pin (6) entrada de pulso del contador 0)
Recuadro azul timer 1 clock in (pin (11) entrada de pulso del contador 1)

COMUNICACIÓN EN FORMA SERIAL CON EL PROTOCOLO RS232

Nota: Protocolo es la forma y condiciones o secuencia de actos que deben cumplirse


para realizar una actividad determinada, en este caso es la secuencia de actos y normas a
realizarse para establecer la comunicación entre dos o más aparatos que se quieren
comunicar, transmitiendo sus informaciones o datos en serie, es decir un dato tras otro.

La comunicación entre microcontroladores y/o computadores se puede llevar a cabo de


dos formas, en forma serial o en forma paralela, pero la forma serial del prótocolo
RS232 es la más ampliamente usada debido a su versatilidad, pocos cables y mayores
distancias, no es que la paralela y otras no se usen, de hecho en las impresoras de puerto
paralelo ésta es la comunicación que se usa, pero cuando requerimos simplicidad a la
hora de construir cables y cubrir distancias de hasta más de 10 metros podemos usar la
comunicación serial RS232.
Además hay otras formas de comunicación, pero sólo me concentraré en la
comunicación serial RS232, y unicamente de ser necesario usaré y explicaré otra.

En la mayoría de microcontroladores está colocada toda la circuitería necesaria para la


comunicación en forma serial con el protocolo RS232, ya en un tema anterior expliqué
como funciona la comunicación serial (datos transmitidos en serie –uno tras otro hasta
completar el mensaje)

140
En los microcontroladores PIC se puede configurar casi cualquier pin como pin de
salida, pin de entrada o como pin conexión de comunicación serial RS232, sin embargo
son los pines C6 y C7 los indicados para trabajar esta comunicación a alta velocidad, al
igual que cuando vamos a usar el convertidor analógico digital, debemos participar en el
encabezado del programa la configuración de la comunicación serial RS232 de la
siguiente forma:

#use rs232 (baud=9600, xmit=pin_c6, rcv=pin_c7)

De esta forma le informamos al PIC C que usaremos comunicación en forma serial,


usando el protocolo RS232 con transmisión de datos por el pin_c6 y con recepción de
datos por el pin_c7.

Si necesito transmitir esta información a distancias mayores de 20 mts hasta 1200 mts,
podemos usar un convertidor de protocolo RS232 a protocolo RS485, que es un simple
conector con tres hilos de cobre.

Es importante saber que existen otros protocolos de comunicaciones que se puede usar
con los microcontroladores, pero hasta ahora nos basaremos en el rs232 por su
versatilidad y facil operación.

Hasta aquí todo lo que tenía que ver con el repaso e información de ciertas
características del PIC16F876 y PIC16F876A.

Notas:
1) Recuerde que los pines del microcontrolador no sirven para nada antes de que
este esté debidamente programado.

141
2) Observe que hay pines con varias funciones, pero que de esas varias funciones,
una y solo una funcionará, ¿cual?: La función que usted programó para ese pin.
(no asuma que el PIC C le declarará algo por defecto, hágalo ud. mismo)
3) Siempre que vaya a usar un pin como entrada, declárelo en todas pertes donde lo
nombre como entrada, porque puede seceder que en la configuraciçon de puerto
lo ponga como salida y luego en la configuración analógica lo configure como
entrada.

El PINADO del microcontrolador PIC16F876 y PIC16F876A.

Pin 1:
MCLR: Master clear. Cuando este pin está puesto a negativo se resetea (puesta a 0) el
microcontrolador, por eso se debe mantener conectado con una una resistencia de 10K
ohm al positivo de la alimentación.
VPP: Cuando vamos a proceder a grabarle un programa (programarlo) al
microcontrolador, por este pin debemos conectarle un voltaje de +12volt. con el fin de
que este entre en modo programación.

PIN 2:

142
RA0: Es un pin de entrada o salida digital, mientras que no se declare que va a
funcionar como entrada del convertidor analógico digital.
AN0: Cuando se declara en el encabezado del programa que vamos a utilizar el
convertidor analógico digital, este es el pin AN0 (puerta de entrada analógica 0), es
donde se conectará la salida de un transductor para digitalizar su valor.

PIN3: Igual que PIN2


RA1: Entrada o salida digital.
AN1: Entrada analógica 1

PIN 4:
RA2: Entrada o salida digital.
AN2: Entrada analógica 2.
VREF-: Voltaje de referencia negativo.

Cuando usamos el convertidor analógico digital en un determinado pin, por ese


determinado pin introducimos un voltaje, ahora, este voltaje necesita dos (2) referencias
de voltajes para saber en que proporción está con respecto al rango de trabajo. Bien a)
Si yo no declaro voltajes de referencia el microcontrolador asumirá que son sus voltajes
de alimentación (normalmente entre 0volt y +5 volt), pero yo puedo decirle al
microcontrolador que trabaje con unos voltajes de referencia particulares, los cuales son
introducidos por los pines PIN 4 VREF- y PIN 5 VREF+, solo cuando en la línea de
configuración declare que usaré estos voltajes de referencia:

Ejemplo:

Setup_adc(an0_an1_vref-_vref+_an4_an5);
En la línea enterior se declaró a los pines A0, A1, A4, A5 como entradas analógicas y a
los pines A2 como voltaje de referencia negativo y A3 como voltaje de referencia
positivo.

Hay muchas maneras de configurar los pines de entrada analógicas, pero tenga en
cuenta que siempre que coloque el término VREF+ será el pin A3 la referencia positiva
y VREF- será el pin A2 la referencia negativa.
Ejemplos:
Setup_ADC(ANO_AN1_AN2_AN4_VREF+); VREF+siempre es PIN_A3
RA5 queda como pin de entrada o salida digital.

En otras palabras, los pines que desee tener como entradas analógicas debe declararlos
ANx_ donde x es el número del pin y el guión de piso es para separarlo del siguiente,
en este PIC tiene hasta 6 entradas analógicas.

PIN 5 (explicación igual al PIN 4)

PIN 6:
RA4: Entrada o salida digital.
T0CKi: Timer 0 clock in --contador0 de eventos , entrada de pulsos, este es el pin por
el cual introducimos pulsos para que sean procesados por el contador 0, es importante
informar que este pin da una salida digital con menos corriente que las demás, por eso al
colocarle un led este apenas enciende ante una salida alta, esto se puede deber a que

143
este pin tiene un disparador de smith (smith triger de entrada) que es muy util ya que
sirve para detectar pequeñas variaciones de voltaje como entrada que en otros pines
quizas no sean detectadas.

PIN 7:
RA5: Entrada o salida digital.
AN4: Entrada analógica 4
/SS: Slave select :Cuando se establece una comunicación serial sincronizada entre dos
aparatos, uno de los dos elementos participantes debe poner los pulsos de sincronización
para establecer la comunicación, cuando esta comunicación se inicia si este pin está
puesto a bajo nivel, los pulsos de sincronización los debe poner el otro aparato, bien sea
otro microcontrolador o computador.

PIN 8:
Alimentación negativa

PIN 9 y PIN 10:


En estos pines es donde se debe colocar el elemento resonador, bien sea un cristal o un
circuito oscilador.

PIN 11:
RC0: Bit 0 de la entrada o salida digital de la puerta C
T1OSo: Salida del oscilador del timer 1, por este pin salen (una vez configurado) los
pulsos del timer 1.
T1Cki: timer 1 clock in-- Por este pin se pueden introducir pulsos para que sean
procesados por el timer 1 (contador 1)

PIN 12:
RC1: Bit 1 de la entrada o salida digital de la puerta C.
T1Osi: Entrada del oscilador para el contador 1 (timer 1) .
CCP2: CCP significa captura, o comparación, o modulador de pulsos, todo depende de
lo que haya configurado y programado para este pin.

PIN 13:
RC2 y CCP1: Igual que pin 12.

PIN 14:
RC3 igual que RC1
SCK/SCL: Es el sincronizador de entrada o salida de los modos de comunicación serial
SPI e I^2 C

PIN 15:
RC4: igual a que RC1
SDI/SDA: Pin de entrada de datos de los modos de comunicación SPI e I^2C

PIN 16
RC5: Igual que RC1
SDO: Transmisor de datos del modo SPI

144
PIN 17:
RC6: igual que RC1
TX: Pin de transmisión de la data en el modo serial RS232
CK: Pin de pulsos sincronización de una comunicación de transmisión de datos.

PIN 18:
RC7: Igual a RC1
RX: Pin por el cual se reciben los datos en comunicación serial RS232
DT: Pin de pulsos de sincronización de una comunicación serial para recepción de
datos.

PIN 19 y Pin 20:


VSS: Pin de alimentación negativa. 0voltios.
VDD : Pin de alimentación positiva +5 voltios.

PIN 21:
RB0: Bit 0 entrada o salida digital del puerto B
INT: En los microcontroladores existen unas funciones llamadas funciones de
interrupción, las que explicaré más adelante, sin embargo es bueno decir que Int está en
un pin en el cual cuando se introduce un pulso, el microcontrolador deja lo que este
haciendo (salta de su rutina principal) y se va a ejecutar una subrutina exterior y luego
regresa, Nota: independientemente de donde este la ejecución de un programa al sentir
el llamado de una función de interrupción, este salta a esa función y luego regresa a su
lugar desde donde saltó.

PIN 22, PIN 23, PIN25, PIN 26


RB1, RB2, RB4 y RB5 son entradas o salidas digitales bit 1, bit 2, bit4 y bit 5 del
puerto B.

PIN 24:
RB3: Entrada o salida digital bit 3 del puerto B.
PGM: Pin para la actiivación del estado de programación cuando se le introduce +5volt

PIN 27:
RB6: Entrada o salida digital bit 6 del puerto B
PGC: Entrada de los pulsos (clock) durante el proceso de programación.

PIN 28:
RB7: Entrada o salida digital bit 7 del puerto B
PGD: Entrada de la data del programa durante el proceso de programación.

145
EL TRANSDUCTOR LM35 (SENSOR TÉRMICO)

En esta sección voy a explicar como trabajar con el transductor LM35, que es un sensor
de precisión de temperatura en grados centigrados, también se consigue el LM335 que
es una versión más económica pero que funciona bien para comenzar con los
transductores.

El LM35 es un circuito integrado sensor de precisión de temperatura en grados


centigrados, cuya salida de voltaje es linealmente proporcional a la temperatura medida,
su rango de funcionamiento está entre los -55 ºC y los 150 ºC y su alimentación está
entre los 4 y 30 voltios.
Se instala según el siguiente diagrama.

En el diagrama superior se observa como alimentar al sensor LM35 y el pin de salida


del sensor, el cual nos da un voltaje proporcional a la temperatura a la que está siendo
sometido, en el diagrama inferior derecho el pinado del PIC16F876 y en el diagrama
inferior izquierdo como se debería conectar en una forma ideal con el PIC por la entrada
analógica AN1.

Por supuesto que al diagrama anterior le faltan componentes para que se pueda observar
su funcionamiento, pero esta es la instalación básica de como se deben conectar el
LM35 y el PIC16F876 para trabajar con la temperatura que está afectando al sensor.

146
Antes de pasar a un diagrama definitivo de conexiones entre el sensor, el PIC y la
pantalla LCD, primero debemos hacer el programa con el que va a trabajar el
microcontrolador para determinar la temperatura del sensor y pasarlo a la pantalla LCD.

1) Recuerde el diagrama de conexión entre la pantalla y el microcontrolador (para


el PIC16F876 es igual en el puerto B).
2) Tenga en cuenta que ahora debe dar la directiva en el encabezado del
programa para utilizar el convertidor analógico digital del microcontrolador
3) Tenga presente como debe conectar el sensor al microcontrolador.
4) Haga el programa, almacénelo en el microcontrolador y pongalo en marcha.

Encabezado de un programa en el que se usaré el convertidor analógico digital y la


pantalla LCD.

En este encabezado lo único nuevo es #device adc=10 , y lo que esta línea significa es
que se va a utilizar el dispositivo convertidor analógico digital el cual trabajará con 10
bits en código binario, que en decimal es 1024 divisiones entre la menor lectura y la
mayor lectura.

Nota: Si el rango de medida está entre 10ºC y 50 ºC y trabajo con adc=10, tengo 1024
divisiones entre 10 y 50, entonces (50-10)/1024=0.039 lo que quiere decir que mi
sensor captará variaciones de 0.039 ºC (bastante preciso)

Algo importante es tener a mano la hoja de las características del sensor o transductor,
debido a que es importante conocer sus parámetros de funcionamiento, por ejemplo
saber que el LM35 da una variación de 0.01 voltios por cada 1ºC que la temperatura,

147
que tendrá en su salida 0.00 Volt cuando la temperatura del medio ambiente es -55 ºC, y
que su rango de funcionamiento está entre los -55 y 150 ºC

Análisis:
Si su rango de trabajo (LM35) está entre -55 y 150 ºC tienen un margen de 205 º, 155-
-55 = 155+55=210º
Si aumenta 10mv/ºC entonces, cuando el sensor está a -55 ºC dará en su salida 0 mV, y
cuando está a 150 ºC dará en su salida 205*10mv = 2050mv = 2.05 voltios.
Lo que quiere decir, que lo ideal sería que los voltajes de referencia en mi convertidor
analógico digital deberían ser VREF-= 0.00v y VREF+=2.05V, (para que el rango de
salida del sensor sea igual al rango de entrada del convertidor), así de esta manera con
los dos rangos igualados, cuando la salida del sensor es mínima, la entrada del
convertidor también es mínima, y cuando la salida del sensor es máxima, la entrada del
convertidor también es máxima. Ahora, supongamos que me las arreglo para tener
estós voltajes de referencia, aún así, cuando mi convertidor lea 0.00volt me dará a la
salida un valor de 0ºC (perfecto) pero cuando lea 2.05 voltios me dará el valor 1024ºC.
(porqué?), por que ese és el máximo valor que el convertidor da cuando su entrada es
máxima.
Explico:
El convertidor tiene un rango de entrada entre 0 y 2.05, y un rango de salida, entre 0 y
1024, o sea para entrada ( mínima) 0.00volt, salida (mínima)0, y para entrada (máxima)
2.05volt, salida (máxima) 1024.
Entonces lo que tenemos que hacer en plantearnos una función líneal que nos relacione
X de 0 a 1024 con Y de -55 a 150.

Lo que quiere decir que 1024/205 =4.995 aprox. 5


O sea que por cada grado (ºC) de temperatura que aumente (Y) mi valor (X) aumenta en
5 unidades, es decir, que la función es: Y= (X/5) -55 , y esta es la conversión que
debemos tener en nuestra fórmula adentro del programa en el microcontrolador, cuando
los voltajes de referencia sean VREF- 0.00 volt y VREF+ 2.05 voltios, donde Y es la
temperatura y X es la lectura que da el convertidor.

Nota: Que secede cuando no puedo calibrar exactamente los voltajes de referencia, y
además no conozco bien las características de mi transductor.
(¡que eso es lo que siempre ocurre!).

Primero (El sensor)


1ro.) Energice su sensor y colóquele un voltimetro entre su salida y el negativo, lea el
voltaje, anótelo junto con la temeratura ambiente.
2d0) Caliente un poco de agua, sumerja el termómetro y una parte del sensor, no moje
los contactos electricos. Lea la temperatura y el voltaje y anote.
3ro) caliente el algua y haga igual que con el agua fría.
4to) divida las variaciones de voltaje entre las variaciones de temperatura y tendrá dos
ratas de variación ( voltios/ºC), saque el promedio y uselo como rata de variación
volt/ºC.

Segundo (el convertidor analógico digital del microcontrolador)


1ro.) Haga todas las conexiones que necesite, alimentación, pantalla, cristal, etc.

148
2do.) Prográmelo para que le muestre en la pantalla el valor ya convertido de analógico
a digital de la entrada por su pin de lectura analógica, (no use voltajes de referencia
externos, use los que vienen por defecto).
3ro.) Conecte al pin de lectura analógica a la alimentación negativa y vea en la pantalla
que lectura tiene (debería tener 0), si no tiene 0 réstele ese valor a la variable leida en el
programa para obtener 0, y luego deconecte el pin del negativo.(Nota: tenga en cuenta
cuantos bits uso en la declaración del encabezado, por lo general se usa #device
adc=10. lo que da una lectura máxima de 1024.
4to.) Mida el voltaje de una batería (pila AA o AAA), con el multimetro y anótelo,
ahora conectela con el negativo al negativo del microcontrolador y el positivo a la
entrada de lectura analógica, lea en valor, ahora plantee la siguiente regla de tres

Voltaje de la pila ------ lectura en pantalla


X --------------------- 1024
(1024*voltaje de la pila) / (lectura en pantalla)= VREF+
VREF+ es el máximo valor de entrada que soporta el convertidor A/D, con el que
debería presentar la pantalla el valor 1024 (máxima lectura)

Ahora resulta que tenemos dos rangos diferentes, el de nuestro sensor (desde x hasta y)
y el de entrada al convertidor A/D (desde a hasta b), (aquí lo importante es que el
máximo valor del sensor nunca esté por encima del máximo valor de entrada del
convertidor y que el mínimo valor del sensor tampoco esté por debajo del mínimo del
convertidor.
O sea x(sensor) >= a(convertidor) Y y(sensor) <= b convertidor.
En palabras, el rango del sensor (el que manda la señal) debe estar dentro del rango del
convertidor (el que recibe la señal). Para garantizar el resultado.
Si esto no se cumple entonces debe tratar la señal con amplificadores operacionales para
ajustarla, no trate que sea igual al rango de entrada sino a que quede adentro de ese
rango.

Una vez que ha logrado esto, haga algunas mediciones y anote según la temperatura del
sensor que lectura le da la pantalla, halle la función correspondiente y listo.
La función correspondiente es la relación que hay entre la lectura de la pantalla y la
temperatura que sse está midiendo con el sensor, con dos lecturas se haya esa relación.

Ejemplo:
15 ºC (termómetro) muestra 354 en pantalla
24 ºC (termómetro) muestra 741 en pantalla

24-15 = 9 (amplitud del rango) 741-354 = 387 (amplitud del rango)

387 / 9 = 43, cada 43 unidades que se incremente en la variable que se presenta en la


pantalla debe haber una variación de 1ºC. en el sensor, siempre y cuando la lectura de
la variable sea 354 cuando en el sensor hay 15ªC y la lectura sea 741 cuando en el
sensor hay 24ªC, entonces la relación 354/43=8.23, 8.23 es el valor que mostrará la
pantalla cuando la lectura en el termometro de de 15ªC, pero 8.23 no es la temperatura,
entonces debemos calcular un factor de corrección FC=temp. en termometro – 8.23, y
esto es 15-8.23=6.76 , entonces para tener una lectura adecuada en la pantalla
conextada al microcontrolador debemos implementar esta relación.

149
Temperatura = (x/43)+6.76 para 354 < x <741 donde x es el valor de la variable
calculada por el convertidor analógico digital.

Claro, lo mejor sería hacer medidas a 0ºC y 100ºC y realizar la misma operación

Programa ejemplo para medir y presentar la temperatura con un sensor LM35.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#device adc=10
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantal1ai.c>
void main() {
Int16 a;
float d;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
output_b(0b00000000);
output_c(0b00000000);
setup_adc_ports(ra0_analog);
setup_adc(adc_clock_div_32);
while (1)
{ set_adc_channel (0);
delay_ms(100);
a=read_adc();
d=((a/1024)*205)-55;
printf(lcd_data,"temperatura = %2.2f ",d);
}}

150
Circuito para el programa anterior.

Se me hace necesario explicar ciertas líneas del programa.

3ra línea: Es la línea del encabezado donde se declara que se va a utilizar el convertidor
analógico digital con un rango de 10 bits = 1024 divisiones entre el menor valor y el
mayor valor.

20va linea: set_adc_ports(ra0_analog), es donde se le dice a PIC C cual o cuales son


los pines por los que se necesita una entrada analógica, en este caso sólo usaré RA0 (El
pin 0 del puerto A “solo el puerto A tiene entradas analógicas y para el PIC16F876 son
los pines A0, A1, A3).
Nota: Existen varias opciones de seleccionar los pines de entrada analógica.
Ejemplo:

Setup_adc_ports(ra0_analog);
setup_adc_ports(ra0_ra1_ra3_analog);
setup_adc_ports(all_analog);
setup_adc_ports( RA0_RA1_ANALOG_RA3_REF );

21va línea: set_adc(adc_clock_div_32); Todo proceso necesita un tiempo para que sea
realizado, en este caso para hacer la lectura por el pin y para hacer la conversión, y este
tiempo está dado por esta línea, y aunque hay otros tiempos de trabajo más cortos, és
este el que mejor garantiza que que el tiempo alcance para realizar la lectura y la
conversión de este proceso.

23va línea: set_adc_channel (0):Cuando vamos a realizar una lectura por un pin
configurado como entrada analógica y debido a que el microcontrolador solo puede
realizar la conversión de un pin a la vez, necesitamos informarle al PIC C cual va a ser
ese pin, primero porque puedo tener configurado varios pines con entradas analógicas y

151
segundo porque si el pin que estoy selecionando no está configurado como entrada el
programa dará un error en la compilación.

24va línea: delay_ms(100), además de los tiempos de conversión de la data y selección


del pin, también hace falta un tiempo de estabilización eléctrica, este tiempo se le pone
con un delay_ms(10) “suficiente”; después de la selección del canal de entrada (pin), en
mi caso usé 100mSeg para aprovecharlo también como estabilizador de la presentación
por pantalla, (para que no parpadée cuando los cambios de temperatura sean
constantes).

25va línea: a=read_adc(); En esta línea es donde le asignamos el valor de la lectura del
convertidor analógico digital a una variable (a), esta variable es una variable entera (sin
decimales) debido a que el convertidor solo dá valores en un rango definido y en
números enteros, para nuestro caso con adc=10 bits tenemos 1024 posibilidades.

26va línea: d=((a/1024)*205)-55; Esta fórmula es muy importante que la entienda:


1r0.) d es una variable declarada float, lo que quiere decir variable con decimales, esto
es así en este caso porque tenemos lecturas de temperaturas que rara vez serán números
redondos.
2do.) (a/1024) . Esta división es necesaria porque la escala de valores que me va a dar el
convertidor analógico digital está entre 0 y 1024, lo que quiere decir que cuando en el
pin de entrada analógica el valor sea el mínimo (ejemplo 0.00volt), el valor de a =0 y
cuando en el pin de entrada el valor analógico sea máximo (ejemplo 5.00volt), el valor
de a=1024, luego si yo divido a a / 1024 en esa división tendré la proporción del valor
con respecto al maxímo que puedo tener como entrada, así, si a = 1024 esto me quiere
decir que estoy recibiendo el 100% del valor de entrada máxima y que por lo tanto la
salida por pantalla también debe ser el 100% del valor cuya proporción es 1, teniendo
como 1 el 100% de la posible entrada.
3ro.) *205, lo multiplico por 205 porque es la amplitud del rango de trabajo del sensor
es entre -55 y 150, lo que da 150+55=205 .
4to.) -55 se le resta 55 para llevarlo al punto en el que cuando el voltaje en el
transductor sea cero (0) la temperatura presentada sea -55ºC.

El siguiente programa es el mismo anterior, pero con la variante que cuando la


temperatura esté por debajo de 50ºC emitirá una señal de alarma por el pin_C0, cuando
la señal este entre 50 y 60 ºC emitirá una señal por el pin_C1 indicando que está dentro
del rango, y cuando la temperatura esté por encima de 60ºC emitirá una señal de alarma
por el pin_C2, siempre que la lectura de entrada analógica se haga por el pin_A0, lo
mismo aplicará para la lectura analógica por el pin_A2 pero con los pines pin_C3,
pin_C4 y pin_C5, además cuando las dos temperaturas estén en el mismo intervalo, se
emitira una señal por el pin_C6 y cuando estén en intervalos diferentes por el pin_C7.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#device adc=10
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b

152
#define rs pin_b3
#define stb pin_b2
#include <pant1.c>
void main() {
Int16 a,b,x,y;
float d,e;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
output_b(0b00000000);
output_c(0b00000000);
setup_adc_ports(ra0_ra1_ra3_analog);
setup_adc(adc_clock_div_32);
while (1)
{
set_adc_channel (0);
delay_ms(20);
a=read_adc();
d=((a/1024)*205)-55;
if (d<50) x=1;
if ((d>=50 && d<=60)) x=2;
if (d>60) x=3;
printf(lcd_data,"temperatura1 = %2.2f ",d);
set_adc_channel (1);
delay_ms(10);
b=read_adc();
e=((b/1024)*205)-55;
if (e<50) y=1;
if ((e>=50 && e<=60)) y=2;
if (e>60) y=3;
lcd_cmd(192);
printf(lcd_data,"temperatura2 = %2.2f ",e);
delay_ms(200);
output_c(0b00000000);
if (x==1) output_high (pin_c0);
if(x==2) output_high(pin_c1);
if (x==3) output_high(pin_c2);
if (y==1) output_high (pin_c3);
if(y==2) output_high(pin_c4);
if (y==3) output_high(pin_c5);
if (x==y) output_high(pin_c6); else output_high(pin_c7);
}}

Circuito recomendado para este programa:

153
Diodos azules 1N914, resistencias en leds 220 ohm.

LOS OPTOACOPLADORES

Antes de enrtrar al siguiente programa debo explicar lo que es un optoacoplador.

Los esquemas anteriores corresponden a dos tipos de optoacopladores comercialmente


populares, arriba a la derecha está el optoacoplador encapsulado, que comunmente se
usa para separar electricamente dos circuitos; pero mantenerlos inteconectados a través
de señales de luz, estos se usan principalmente para proteger la parte de control logico
que trabaja a bajo voltaje (entre 3 y 5 voltios) de la parte de potencia, la que podría
trabajar a varios cientos de voltios.

El esquema eléctrico de la parte superior y su imagen como lo conseguimos en las


tiendas es del tipo encapsulado, este se caracteriza porque no es afectado por la luz de
sus alrededores.

154
El esquema inferior es el optoacoplador abierto o de ranura, con una abertura por la cual
pasa un haz de luz que el mismo produce de un lado y que capta del otro lado, este se
usa para poder detectar el paso de algún elemento opaco movil que pasa por esa ranura
al interrumpir el haz de luz. Nota: No todo material sirve para interrumpir ciertos hazes
(rayos infrarojos), por ejemplo hay luces en la gama infraroja para los cuales ciertos
plásticos son invisibles y lo atraviesan sin dificultad, y una persona inexperta pudiera
pensar que el optoacoplador está malo, para probarlo use objetos metálicos (una
moneda), luego pruebe con el material que piensa usar como interceptor.

El siguente programa es un contador de revoluciones, RPS y RPM, que es muy util


para determinar la velocidad exacta de un motor en tiempo real, para ello usaré un
motor de corriente continua al que le conectaré varios voltajes en diferentes momentos,
un optoacoplador de ranura y un circulo con un agujero o una helice, con el objetivo de
hacer pasar la helice o el circulo por dentro de la ranura de manera que interrumpa el
rayo infrarojo para determinar la velocidad RPM y RPS del motor.

Programa ejemplo.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>
void main() {
Int32 rps,rpm,rpx;
float a,b;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
lcd_init();
lcd_clear();
setup_timer_0(rtcc_ext_l_to_h);
enable_interrupts(int_timer0);
enable_interrupts(global);
while (1) {
output_low(pin_a4);
set_timer0(0);
output_high(pin_a4);
delay_ms(1000);
output_low(pin_a4);
rpx=get_timer0();
rpm=rpx*60;
rps=rpx;
lcd_clear();
printf(lcd_data,"RPM = %5lu ",rpm);

155
lcd_cmd(192);
printf(lcd_data,"RPS = %5lu ",rps);
delay_ms(100);
} }

Circuito recomendado para el programa anterior.

Elementos necesarios.
Un motor dc 5 voltios.
Un optoacoplador de ranura.
Una helice circular perforada con un agujero.
Una pantalla LCD.
Un PIC16F876.
Un cristal resonador 8000000 hertz.
Dos resistencias de 200 y una de 10000 ohm.
Una fuente de 5 volt dc y al menos 0.5 amp.

EL CONVERTIDOR DE DIGITAL A ANALÓGICO.

Un convertidor digital a analógico es lo inverso que el analógico a digital, a este se le


introduce un valor en código binario por los pines de entrada y este envía la proporción
de voltaje máximo de salida según una relación lineal, suponga la siguiente situación
hipótetica pero sencilla:

1ro.) El convertidor tiene 8 pines de entrada, lo que me indica que el rango de valores
en el que trabaja (la entrada) está desde 0 (cero) hasta 255.
2do.) El convertidor va a tener como voltajes de referencia para dar salida entre 0 volt y
255 voltios, y que su alimentación le permita poner a la salida hasta 255 voltios.

Entonces para este caso, el voltaje que me dará a la salida el convertidor será igual al
valor en código binario que le introduzca por los pines de entrada, lo que quiere decir
que si a la entrada todos los pines son 0, la salida será 0 volt, y que si a la entrada todos
los pines están en alto, entonces su salida será 255 volt.
Claro, si el valor a la entrada es 127 (0b11111110) en binario, su salida será también
127 volt, pero se cálcula de la siguiente manera.

156
Volt de salida = (valor entrada / valor máximo) * voltaje máximo de salida.

Volt de salida: Es el voltaje que entregará el convertidor en los pines de salida.

Valor de entrada: Es el valor (número en código binario), que le ponemos en los pines
de entrada digital al convertidor.

Valor máximo: Es el valor máximo que podemos escribir en la entrada digital del
convertidor. (todos los pines de entrada puestos a voltaje alto (1)), para nuestro caso con
8 pines de entrada será 0b11111111 o 255 en decimal.

Voltaje máximo de salida: Es el mayor voltaje que podemos obtener del convertidor,
estos datos están indicados en el manual del convertidor según su fabricante.

Nota: En todo caso siga la siguiente regla.

Voltaje a la salida = Valor a la entrada (esto es en binario)


Voltaje máximo a la salida Valor máximo que se puede poner a la entrada.

Si la entrada tiene 7 pines es 128


Si la entrada tiene 8 pines es 255
Si la entrada tiene 9 pines es 512
Si la entrada tiene 10 pines es 1024.
Etc.

Es una lástima que los microcontroladores (al menos con los que vamos a trabajar en
este libro) no contengan convertidores digitales a analógico, pero de cualquier forma lo
vamos a usar como un circuito auxiliar más en la electrónica que vamos a trabajar.
Ver diagrama de convertidor digital a analógico.

157
En el siguiente programa vamos a utilizar el convertidor digital a analógico DAC0800,
Para indicarnos con una intensidad de iluminación en una relación directamente
proporcional a la velocidad de un motor (a más rápido gire el motor, más intensidad
luz), partiendo de medir sus RPS, el mismo programa se calibrará determinando la
máxima velocidad y tomándola para calcular la relación entre velocidad máxima
velocidad actual, por el puerto C se obtendrá un valor digital que se introducirá en el
convertidor digital a analógico y la salida de este al bombillo que cambiará su
intensidad de ilumación según las RPS mostradas en la pantalla LCD. (más rápido más
luz)

Programa ejemplo.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b3
#define stb pin_b2
#include <pantallai.c>
void main() {
Int32 rps,mrps,rel,x;
mrps=1, rel=1;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
lcd_init();
lcd_clear();
setup_timer_0(rtcc_ext_l_to_h);
while (1) {
output_low(pin_a4);
set_timer0(0);
output_high(pin_a4);
delay_ms(1000);
output_low(pin_a4);
rps=get_timer0();
lcd_clear();
printf(lcd_data,"RPS = %5lu ",rps);
if (rel>rps) mrps=rel;
rel=rps
x=(rps/mrps)*255
output_c(x);
delay_ms(100);
} }

Circuito recomendado para el programa anterior.

158
Nota: Para alcanzar la velocidad máxima para la calibración, es necesario llevar la
resistencia variable al máximo que es el punto de mayor velocidad del motor ya que es
el punto donde recibe la mayor cantidad de energía.
Usar dos alimentaciones, una para el motor y la otra para todo lo demás.

Al programa anterior se le debe la explicación de algunas líneas:

setup_timer_0(rtcc_ext_l_to_h);
La anterior línea es la configuración del contador 0 (timer_0), para el PIC C, el término
timer0 o rtcc es lo mismo y le da la misma interpretación, así que cuando se presenta el
modo de funcionamiento (lo que está dentro de los parentesis) rtcc_ext_l_to_h le dice
a PIC C que el timer0 se incementará por un pulso dado desde el exterior _ ext cuando
el pulso pase de un estado bajo _l (0volt) a un estado alto _h, “un flanco de subida”.
Nota: El timer0 tiene su entrada por el pin nro. 6 o el pin_a4, donde está un disparador
de smith para facilitar la lectura de un pulso que le aplique.

159
EL MODULADOR DE ANCHO DE PULSO

Lo que falta explicar del modulador de ancho de pulso, es como implementarlo en PIC
C, porque lo demás ya fue expuesto anteriormente.

Para aplicar el generador de ancho de pulso:


1ro.) Debido a que el ancho del pulso está determinado por una cantidad de bits, y estos
bits se declaran con la expresión #device adc=10 para 10 bites en el encabezado, lo
primero que tenemos que hacer es colocar esa expresión en el encabezado. Con esto ya
sabemos que el ciclo de trabajo está entre 0 y 1024.
2d0.) Luego de haber declarado la cantidad de bits con la que se va a trabajar, tenemos
que configurar a ccp1 o a ccp2 como modulador de ancho de pulsos con el comando .
setup_ccp1(ccp_pwm);
3ro.) Tenemos que definir la base de tiempo del ciclo de trabajo y descanzo del pulso
alto + pulso bajo configurando al timer_2.
Nota: La base de tiempo del timer_2 es la que usa el generador de ancho de pulsos para
trabajar.
Setup_timer_2(t2_div_by_1,255,1); (recomendable)
4to.) Tenemos que darle al ciclo de trabajo un valor, set_pwm1_duty(cdt); como en
este caso estamos trabajando con 10bits porque así lo configuramos en el encabezado
del programa (#device adc=10), el valor que debemos darle a cdt deberá estar entre 0 y
1024, con 512 estaremos trabajando al 50% del ciclo de trabajo.
setup_pwm1_duty(512);
Nota: El ciclo de trabajo no tiene porque ser constante, este valor puede provenir de una
formula determinada por el programador o de una tabla con condiciones.

Ejemplo de una sección de un programa con ciclo de trabajo que depende del valor del
ciclo equivalente a 25%, 50%, 75% y 100%:

setup_ccp1(ccp_pwm);
setup_timer_2(t2_div_by_1,255,1);
if (x==0) c=256;
if(x==1) c=512;
if(x==2) c=768;
if(x==4) c=1024;
set_pwm1_duty(c);

160
Ejemplo de programa con el cual se controla el ciclo de trabajo del generador de ancho
de pulso controlado con un pulsador conectado a los pines del puerto A:

Programa ejemplo.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#device adc=10
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>
void main()
{ Int16 a,b,c; float ct;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
lcd_init();
lcd_clear();
setup_ccp1(ccp_pwm);
setup_timer_2(t2_div_by_1,255,1);
while (1) {
if (input(pin_a0)) c=0;
if (input(pin_a1)) c=200;
if (input(pin_a2)) c=400;
if (input(pin_a3)) c=512;
if (input(pin_a4)) c=800;
if (input(pin_a5)) c=1020;
set_pwm1_duty(c); ct=((c/1024)*100);
printf(lcd_data," %% de ciclo trabajo = %2.1f", ct) }}

Nota: Use el siguiente circutio para probar programa.

161
El siguiente programa buscará un equilibrio en la temperatura de un sensor, aumentando
la velocidad de un ventilador con motor dc cuando aumente la temperatura en el sensor
y disminuyéndola cuando la temperatura disminuya.

Problema: construir un circuito con en microcontrolador PIC16F876 el cual según un


programa cuando se le acerque una fuente de calor a un sensor térmico, este encienda y
aumente las rpm de un motor de un ventilador para enfriar el sensor.

162
EL TRANSISTOR

Un comentario valedero:
Porque, si a una persona que trabaja en el área de la electrónica se le pregunta ¿qué es
un engranaje?, esta persona como mínimo dira que es una reuda dentada, o si le
preguntan ¿que es una viga o una columna?, también dará una explicación aunque sea
vaga, pero al menos tiene una idea bien clara a dar a cada una de esas preguntas, sin
embargo si a un mecánico (técnico o ingeniero) o a un costructor (arquitecto, ingeniero
o técnico) se le pregunta ¿que es un trasistor?, por lo menos el 90% (y me quedo corto)
no tiene nada que decir, solo sabe que existe, pero no tiene idea de como funciona, y es
que la cultura que tenemos en cuanto a la electrónica es tan pobre, que en muchos casos
personas estudiadas en el área de mecánica ni siquiera está segura de que és voltaje o
deferencia de pontencial y aún menos segura de que es corriente o amperios, y ahí en lo

163
más básico de la electrónica (potencial y corriente) empiezan los problemas para
dominar esta área de la tecnología.

No obstante la explicación que voy a dar aquí es la mínima necesaria para entender un
poco estos conceptos, por analogía con la mecánica, alguien dirá que no tiene nada que
ver unas cosas con las otras, pero ya que los mecánicos menejamos muy bién ciertos
conceptos en mecánica de los fluidos y éstos son aplicables a la electronica y
electricidad entonces me valeré de ellos.

Diferencia de potencial:
De la misma manera que los fluidos llámese agua, aceite, etc. son impulsados por una
diferencia de presión a fluir (moverse) por dentro de las tuberÍas, de la misma manera
los electrones son impulsados a moverse por los conductores (cables) por una diferencia
de potencial eléctrico (voltios), así de esta manera si en una tubería hay mucha presión
hasta que esta se llegue a romper, así mismo si en un cable hay demasiada diferencia de
potencial estos electrones causarían tanto recalentamiento al pasar por el cable que lo
funden (se quema), entonces una diferencia de potancial lo podemos comparar con una
diferencia de presión y a las moleculas de agua con los electrones.
Si en una tubería hay demasiada presión está estalla y el agua sale espelida para todas
partes.
Si en el extremo de un conductor hay un potencial electrico muy alto con respecto a sus
alrededores, entonces lo que salta es un rayo o chispazo, que no son más que los
electrones saltando espelidos a lugares de mucho menos potencial electrico, ejemplo:
los rayos, que son descargas electricas naturales que ocurren cuando la atmosfera se
carga con un potencial muy alto y se descarga hacia la tierra.

La corriente eléctrica:
De la misma manera que medimos el caudal del agua que pasa por una tubería en litros
por segundo o alguna medida equivalente (según el diametro de la tuberia), de la misma
manera medimos la cantidad de electrones que pasan por segundo por un cable. Con la
diferecia que el agua fluye a diferentes velocidades y los electrones a la misma
velocidad independientemente del calibre (grueso) del cable, sin embargo esta medida
de la cantidad de electrones que pasan por una sección de un cable por cada segundo es
llamada amperes. (Esto tiene su demenuzamiento para entenderlo más facilmente).
1ro.) Todos sabemos que los principales responsables de la energía electrica son los
electrones en movimiento.
2do.) Que los electrones se mueven en cantidades enormes, pero que cada uno de ellos
hace su pequeño aporte de energía en el grupo.
3ro.) El pequeño aporte de energía que aporta un electrón es de 1.602 x 10 ^ -19
coulombs
4to.) Y que 1 coulomb es la energía que poseen 6.25 x 10 ^18 electrones en
movimiento. Así de esta manera cuando decimos que por un cable está pasando una
corriente = 1 amper, estamos diciendo que están pasando ---------- 6250 000 000 000
000 000 electrones por cada segundo, lo que en carga (cantidad de energía aportada por
todos los electrones) 1 coulomb/seg. O sea si un cuerpo tiene una carga de un coulomb
es que tiene 6.25 x 10 ^18 electrones de más (está cargado negativamente).
Lo que voy a explicar aquí del transistor es algo muy superficial, pero que es lo que nos
va a servir para usarlo en nuestros montajes.
Bueno, como decía antes del comentario, un transistor es un dispositivo que funciona
con energía eléctrica, tiene 3 patas (se les llama pines a la patas de los circuitos

164
integrados), y cada una de esas patas tiene su nombre y su función específica.

Modelos de transistores Tipos Esquema eléctrico

Los transistores tienen tres pines (patas), las cuales son Base (B), Emisor (E) y
Colector (C), de los cuales existen de varios tipos según su fabricación, pero nosotros
aquí solo nos interesaremos por los transistores de unión bipolar, y de los cuales hay
dos tipos NPN y PNP.

Como funciona el transistor.


Como ya explique, el voltaje no es más que una diferencia de potencial energético (que
se aplica) entre 2 terminales, como el transistor tiene 3 patas, entonces entre estas patas
(tomadas de 2 en 2) se aplican diferentes voltajes,
Así tenemos que entre el pin base y el pin emisor aplicamos un voltaje, al que llamamos
voltaje base-emisor

Entre los pines Base y Colector aplicamos otro voltaje, al que llamamos voltaje base-
colector

165
Y entre los pines Emisor y Colector aplicamos otro voltaje, al que llamamos, voltaje
emisor-colector.

Dependiendo de la configuración que deseemos hacer, se aplican solo dos de estos


voltajes.

Ahora, como nosotros queremos usar el transistor para amplificar potencia, es decir yo
le aplico al transistor la pequeña potencia que puedo obtener del microcontrolador, con
el objetivo de poder controlar una potencia mucho mayor, y asi tener el control
(digamos) de 100 voltios utilizando para controlar esos 100 voltios, los 5 voltios de la
salida de un pin del microcontrolador.

Entonces deciamos que el transistor tiene 3 posibles configuraciones (básicas):


a) Base común.
b) Emisor común.
c) Colector común
De las cuales la que mejor nos sirve, es la configuración de emisor común.
¿Que significa emisor común?:
Los amplificadores que conocemos y manejamos en la vida diaria son los
amplificadores de los equipos de sonido, y así los conectamos para que hagan su
función de amplificar.

Pero que pasaría si al verlo por dentro nos conseguimos que hay una conexión que no
pasa por ningún circuito, sino que así como entra sale, sin que se le haga nada a la señal
que por esa conxión le introducimos.

166
Entonces podemos decir este amplificador tiene una configuración de negativo común,
ya que este negativo es tanto entrada como salida, pero que gracias a la caparazón no lo
podemos apreciar.

Bueno de igual manera funcionan las configuraciones del transistor,. En base común
nos dice que la base funciona tanto de entrada como salida, en emisor común, el emisor
es tanto entrada como salida e igual al colector común.

Ahora, hagamos una analogía entre una situación meánica y el transistor como
amplificador

La situación es la siguiente:
Tengo dos tuberías, una roja de 1” de diámetro y una azuloscuro de 10” de diámetro,
cada una tiene una válvula de ¼ de giro, la válvula violeta controla el caudal de la
tubería azuloscuro, y la válvula verde controla el caudal de la tubería roja, a la válvula
violeta le pega directamente el chorro de agua que sale de la tuberia roja, pero el resorte
naranja le impide mantenerse abierta, así que cuando el agua azulclara no tiene mucha
velocidad o no sale, la valvula violeta se mantinen cerrada, pero a medida que sale más
agua azulclara se abre la valvula violeta y por el tubo azul oscuro pasa una cantidad de
agua 1000 veces superior a la que sale de la tubería roja, de esta manera cuando abro la
valvula verde y permito que salga 1 lts/seg, estoy abligando a la valvula violeta a dejar
pasar 1000 lts/seg. y así se mantiene esa relación, entonces con un caudal de agua
pequeño que puedo controlar el caudal de agua mayor por la otra tubería.

Así funciona el transistor como amplificador, en la configuración emisor común existen


dos voltajes.

167
El voltaje emisor-base que es 5voltios y el voltaje emisor-colector que es 100 voltios, de
tal manera que:
Cuando entre la base y el emisor están los 5 voltios completos, el voltaje entre el emisor
y el colector pasa completo y se le aplica a la carga los 100 voltios, y cuando el voltaje
que está entre el emisor y la base es 2.5voltios entonces por la conexión emisor-base
solo pasan 50voltios, esto sucede así porque el transistor funciona como una valvula
electrónica, la cual se abre a medida que le aplicas más voltaje a la conexión de control,
hasta su límite
Nota: Para aplicar y usar un transistor como amplificador es necesario tener su hoja de
datos y sus curvas características.
Por ejemplo el transistor xxxyyy
Voltaje emisor-colector 100V, esto quiere decir que lo máximo que aguanta este
transistor entre sus pines emisor y colector son 100volt, si ud se exede lo más probable
es que lo queme.
Voltaje emisor-base 5V, esto quiere decir que lo que necesita para controlar todo el
voltaje (hasta max 100V) de la salida del transistor son 5 voltios, si aplica más voltios
ahí, a partir de 5 voltios no tendrá ningún cambio a la salia, hasta que lo queme por
exceso de voltaje en esos pines.
Para nuestras aplicaciones con entender esto basta, ya que los transistores que vamos a
usar son pocos y funcionan y se instalan de igual forma, lo único es que la
configuración de las patas no siempre es igual, por eso siempre necesita la hoja de
datos para saber cual pata es el emisor, cual la base y cual el colector.

Como se instala un transistor para usarlo como amplificador.

Así cuando aplico 5 voltios en la conexión azul, se aplican los 12 voltios en la conexión
roja y se enciende el motor DC que está conectado en esa línea.

168
Estas son algunas de las características del transistor NPN TIP122,
Pero hay machas más, se le recomienda buscar en la internet TIP122 pdf y observe sus
características básicas.

La tabla anterior nos da la información MAXIMUM RATINGS que quiere decir valores
máximos que soporta.

Colector-Emiter Voltage, Vceo para el TIP122 es 100 Vdc, es decir soporta entre los
pines colector y emisor hasta 100 voltios DC. Y como es un trasistor NPN el positivo de
los 100 voltios se conecta al colector.

Colector-Base Voltage, Vcb para el TIP122 es de 100 Vdc, es decir soporta entre los
pines colector y base hasta 100 voltios DC.

Emiter-Base voltage Veb este es el voltaje entre la base y el emisor, para el TIP122
son 5.0 voltios DC. y como es del tipo NPN el positivo de los 5 voltios se conecta a la
base.

También informa que en el pin colector soporta picos de corriente haste 5 amperes.

169
También informa que la corriente en la base es de 120 miliamperes con corriente DC.
Entre otras características.

Normalmente la hoja de datos de los transistores también tienen unas gráficas de sus
comportamientos electricos, su geometría y dimensiones etc.
Ultimo detalle, existe otro dispositivo electrónico que es más facil de explicar que el
transistor, este es el diodo rectificador, este es un dispositivo de dos terminales (dos
paticas) y el cual solo deja pasar corriente electrica en un sentido, esto queire decir
graficamente:

En la simbología del diodo la linea que está en la punta de la flecha es la banda gris que
tiene en un extremo el diodo.

Nota: Un diodo solo deja pasar la corriente cuando se polariza directamente, esto quiere
decir que por el extremo donde está la banda gris se le coloca el polo negativo de la
corriente y por el otro extremo (negro) se le coloca el polo positivo, si lo conecta de
forma contraria no habrá paso de corriente y por lo tanto no funcionará lo que conecte
en ese circuito, de igual manera se le hace al emisor del transistor, como el transistor
que vamos a usar es NPN, esto quiere decir que el emisor es negativo, la base es
positiva y el colector es negativo. Eso es lo que significa NPN, y siempre se sobre-
entiende que en los diagramas electrónicos 1ro. va el emisor, 2do. la base y 3ro. el
colector.

Una explicación aclaratoria para los transistores:


Tenemos que ver al transistor como un amplificador que tiene entrada y salida, con la
condición de que para nuestra configuración de emisor común, la conexión emisor-base
es la entrada, y la conexión emisor-colector es la salida, ahora, como el transistor
TIP122 es NPN (EBC), esto quiere decir que el emisor es negativo y que para
polarizarlo directamente se le colocará el negativo de la señal de entrada en el emisor
(negativo) y el positivo de la señal de entrada en la base del transistor (positivo), ahora
como la señal de salida amplificada está entre los pines emisor-colector, y como el
colector tambien es negativo, y a la sección de salida siempre se le debe polarizar
inversamente, entonces al colector le colocamos la señal positiva de la fuerza (el alto
voltaje) de amplificación y al emisor la señal negativa de la fuerza de amplificación,
sabiendo que en este circuito en serie debe estar lo que se llama la carga, o sea para
nuestro caso un motor DC o un bombillo, etc.
Observe el diagrama:
Circuito recomendado para el montaje de control de generación de ancho de pulso con
un transistor NPN TIP122

170
Nota: la línea naranja es una fuente de energía de 15 voltios extra.
LA COMUNICACIÓN ENTRE LOS MICROCONTROLADORES

Muchas veces en nuestros microcontroladores necesitamos mantener algún tipo de


comunicación, supongamos que tenemos en algún sistema 5 microcontroladores
monitoriando 5 secciones de un proceso complejo o largo, 1 supervisa temperaturas en
varias partes, 2 supervisa la velocidad de rotación de los motores, 3 supervisa el tiempo
de cocción de materia prima, 4 supervisa el peso de las cantidades a mezclar, cada uno
siguiendo un programa determinado para su función, y el 5 microcontrolador recibe
todos los datos de todos los microcontroladres y chequea que todos esté en orden.

¿Como hacemos esto?


Para hacer esto necesitamos implementar ciertos parametros.
1ro.) Todos deben hablar el mismo idioma (protocolo de comunicación) y a la misma
velocidad.
2do.) Uno y solo un microcontrolador determina quien emite y quien recibe
información.
3ro.) Todos deben estar interconectados debidamente, de manera que no acurran
colisiones de información en las conexiones.
4t0.) Tenga cuidado con las velocidades de los cristales resonadores, coloque la
velocidad exacta del cristal en el encabezado de cada programa de cada uno de los
microcontroladores, recuerde que esa es la referencia para sincronizar la velocidad de
comunicación.

Lo primero que necesito saber es:


¿Como hago para que un microcontrolador envie información por un pin específico?.
Lo primero que tenemos que definir es el protocolo de comunicación a usar. Este
protocolo será el RS232, y lo declaramos y configuramos en el encabezado del
programa de la siguiente manera.

#use rs232(baud=9600, xmit=PIN_c2,rcv=PIN_c3)

Con esta línea definimos los siguientes parametros.


1ro.) Definimos que el protocolo de comunicación es el RS232
2d0.) Definimos la velocidad de comunicación a 9600 baudios.

171
3ro) Definimos que el pin_c2 se usará para tranmitir información
4to.) Definimos que el pin_c3 se usará para recibir información.

Con esto ya tenemos definido todo lo que necesitamos para enviar y recibir
información, ahora nos falta como hacerlo.

El PIC C tiene comandos que una vez que están definidos los parametros anteriores, ya
de forma automática envia la información por el pin de envío hacia el exterior.

Por ejemplo:

puts(“Este escrito va para la linea de transmisión”);

Envía la frase que está entre comillas por el pin de transmisión de datos para que lo
reciba algún aparato o microcontrolador que esté conectado a esta linea.

Esta sección de comunicación entre microcontroladores o entre microcontroladores y


computadoras es realmente sencillo, solo hay que tener en cuenta la línea de
configuración en el encabezado del programa y tener presente los pines que se van a
usar como medios de comunicación,.

Ejemplo:
Escriba un programa en el que un microcontrolador sea usado para medir una
temperatura, se la transmita a una computadora y la presenta en la pantalla LCD..

Programa ejemplo.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#device adc=10
#use delay (clock=8000000)
#use rs232(baud=9600, xmit=pin_c6,rcv=pin_c7)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pant1.c>
void main()
{ Int16 a,b,c; float ct;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
lcd_init();
lcd_clear();
setup_adc_ports(ra0_analog);
setup_adc(adc_clock_div_32);
while (1) {
set_adc_channel(0);

172
delay_ms(1000);
a=read_adc();
printf(lcd_data,”La temperatura es %lu “,a);
puts (”La temperatura es “,);
putc(a);
} }

Interconecte la computadora y el microcontrolador con un cable con las siguientes


características.

Nota: No olvide ejecutar un programa de monitoreo para el puerto serial COM1 de la


computadora al conectar el circuito, o use el que trae PIC C que está en: C:\Archivos
de programa\PIC C, ejecútelo y observe en la pantalla de la computadora los datos
enviados, si el microcontrolador envía los datos pero estos parecen incoherentes es que
los está enviando invertidos, entonces solo coloque un inversor en el pin_C6 para que
los datos lleguen en la forma que se espera. (Ver el siguiente diagrama).

173
El 74LS14 o 7414 es un circuito TTL inversor, lo único que hace es que, si recibe por el
pin 1,3,5, positivo (+) entrega por el pin2,4,6 negativo (-) y viceversa.

Para recibir datos provenientes por la linea de transmisión de datos, se usan los
comandos x=getc( ) o x= kbhit( ), la diferencia está en que x=getc() detiene el
programa hasta que llega un caracter por la linea de comunicación y x=kbhit()
mantiene el programa funcionando y cuando llega un caracter este es leido.

El programa siguiente recibe datos por la línea de comunicaciones (pin_c7), lo presenta


en la pantalla LCD y lo reenvía por le línea de comunicación serial pin_c6.

Programa ejemplo.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#use delay (clock=8000000)
#use rs232(baud=9600, xmit=pin_c6,rcv=pin_c7)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pant1.c>
void main() {
char e;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);

174
lcd_init();
lcd_clear();
while (1) {
e=kbhit();
printf(lcd_data, “ entrada %c “,e);
puts ( e );
} }

COMANDOS QUE FUNCIONAN EN GRUPO

En PIC C existen comandos que por si solos no harían nada y deben estar en grupo con
otros para poder realizar una tarea completa, por ejemplo, la acción de leer una
temperatura pareciera que se pudiera hacer con un comando que dijera algo como “LEA
LA TEMPERATURA EN EL PIN_XY”, sin embargo esto no ocurre así, pues para
realizar una tarea como esta hay que configurar al microcontrolador para de active el
convertidor analógico digital, hay que decirle antes de la lectura por cual pin_xy debe
leer, hay que esperar para estabilizar la lectura, hay que darle un tiempo para que el
microcontrolador realice la conversión, en el siguiente ejemplo se coloreran las lineas
que son impresindibles para que el microcontrolador realice la tarea de leer una
temperatura.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#device adc=10
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pant1.c>
void main() {
Int16 a;
float d;
set_tris_a(0b111111);

175
set_tris_b(0b00000000);
set_tris_c(0b00000000);
output_b(0b00000000);
output_c(0b00000000);
setup_adc_ports(ra0_analog);
setup_adc(adc_clock_div_32);
while (1)
{
set_adc_channel (0);
delay_ms(100);
a=read_adc();
d=((a/1024)*205)-55;
printf(lcd_data,"temperatura = %2.2f ",d);
}}
Son en total 6 líneas de programa para leer por un canal (pin_a0), lo que se supone es
una señal de un tranductor para una temperatura, y aún falta la fórmula de conversión
del dato leido en la unidades útiles (grados centigrados, kelvin) y la presentación por
pantalla, éstas líneas ya fueron explicadas en este mismo programa hace una cuantas
páginas atrás, pero es bueno que tenga en cuenta que éstas líneas funcionan en conjunto,
si alguna línea falta, el objetivo falla.

Explicación.
#device adc=10 Declara la necesidad del convertidor A/D

setup_adc_ports(ra0_analog); Declara los puertos para lectura analogica.


setup_adc(adc_clock_div_32); Determina el tiempo para la conversión.
set_adc_channel (0); Determina el canal de lectura.
delay_ms(100); Detiene el sistema para que se estabilice
v=read_adc(); Asigna a v el valor de la lectura en pin_a0

Segundo ejemplo de comandos en grupo


#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#device adc=10
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pant1.c>
void main()
{ Int16 a,b,c; float ct;
set_tris_a(0b111111);
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
setup_ccp1(ccp_pwm);
setup_timer_2(t2_div_by_1,255,1);

176
while (1) {
if (input(pin_a0)); c=0;
if (input(pin_a3)) c=512;
if (input(pin_a5)) c=1020;
set_pwm1_duty(c); ct=((c/1024)*100);
printf(lcd_data," %% de ciclo trabajo = %2.1f", ct) }}

Explicación.
#device adc=10 Declara la necesidad del convertidor A/D
setup_ccp1(ccp_pwm); Configura al pin_c2 como PWM
setup_timer_2(t2_div_by_1,255,1); Determina el tiempo de señal
set_pwm1_duty(valor); Asigna la proporción de trabajo (0-1024)
Nota: ct es el % de trabajo cálculado a partir de c.

PWM = Modulador de ancho de pulso.


El tiempo de señal es el tiempo que dura una modulación completa.
La proporción de trabajo es cuanta proporción entre 0 /1024 (mínimo) y 1024/1024
( máximo) durará la parte de la modulación en voltaje alto.
Nota: 0/1024 es no suministrar energía, 512/1024 es suministrar 50% de la energía y
1024/1024 es suministrar toda la energía.

177
Tercer ejemplo de comandos en grupo.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>
void main() {
Int32 rps,mrps,rel,x;
mrps=1, rel=1;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
lcd_init();
lcd_clear();
setup_timer_0(rtcc_ext_l_to_h);
while (1) {
output_low(pin_a4);
set_timer0(0);
output_high(pin_a4);
delay_ms(1000);
output_low(pin_a4);
rps=get_timer0();
lcd_clear();
printf(lcd_data,"RPS = %5lu ",rps);
if (rel>rps) mrps=rel;
rel=rps
x=(rps/mrps)*100
output_c(x);
delay_ms(100);
} }

El programa anterior se hizo para contar las RPS de un motor,


mrps= máximas revoluciones por minuto que tiene el motor.
rel = relativo;es la máxima velocidad detectada.
rps = revoluciones por segundo
Por el puerto c sale el valor de la velocidad, 100 es velocidad máxima que se representa
en esta puerto, por eso es que se multiplica x*100.
x es la relación entre las velocidades, si x=100 es la máxima velocidad.

178
Circuito para el programa anterior.

En PIC C cuando activamos el contador 0 (TIMER0) y lo configuramos para que reciba


pulsos externos, esta entrada de lactura de pulsos puede estar encendida o apagada,
cuando está encendida, este pin detectará pulsos aún cuando el programa esté detenido
por alguna razón, y cuando está apagada este pin no detectará pulsos.
Ahora, ¿como enciendo la lectura de pulsos del contador 0? (TIMER0), resp: poniendo
el pin_a4 en alto (1) “output_high(pin_a4);”, observe en el pinado del PIC16F876
que la entrada de pulsos del contador 0 (TIMER0) está en el pin_a4.

Explicación: Cuando tengo el timer0 del microcontrolador configurado para que detecte
pulsos externos y tengo el pin de lectura (T0CLKi=pin_a4)) encendido (pin_a4 en alto),
este contará los pulsos que reciba por el pin_a4, que es la entrada de conteo de pulsos
para el timer0, este pin contará todos los pulsos que detecte, independientemente si el
programa está detenido o esta corriendo normalmente, y cuando está apagado
(pin_a4=0) no detectará pulsos. Lo bueno es que esta cantidad de pulsos contados por
el timer0 lo puedo extraer para usarlo en para algo (para lo que me sirva), ahora ¿como
le extraigo este valor al contador0?. Resp: usando el comando valor =get_timer0( ),
con este comando le asigno a la variable valor la cantidad de pulsos que ha contado el
timer0, si por otras razones necesito, en vez de extraerle la cantidad de pulsos contados
por timer0 más bien asignarle una cantidad, entonces el comando es set_timer0(valor);
y con este comando le asigno al timer0 un valor cualquiera, (siempre que sea un número
entero positivo y no mayor de 255.

setup_timer_0(rtcc_ext_l_to_h); Configura el timer0 con entrada


externa y flanco ascendente

output_low(pin_a4); Apaga en pin de lectura.


set_timer0(0); Pone el timero0 en 0 (cero.)
output_high(pin_a4); Enciende el lector de pulsos.
delay_ms(1000); Detiene el programa pero sigue
detectando y contando pulsos.
output_low(pin_a4); Apaga el pin de lectura

179
rps=get_timer0(); Se le asigna a la variable rps el
valor leido del timer0.

Nota: La explicación dada del timer0 también es válida para el timer1 y timer2, pero el
timer2 no tiene pin externo para lectura de pulsos.
Nota: El timer2 puede tener varias aplicaciones, pero en este libro solo se va a usar para
determinar el tiempo del ancho total del pulso para el modulador de pulsos.

FUNCIONES CCP

Los microcontroladores poseen módulos CCP (Captura, Compara o Pulsa), estos


módulos trabajan directamente con el timer1 (contador 1) y timer2 contador 2, para
esto hay que activar el timer1
setup_timer_1(T1_internal);
y/o el timer2
setup_timer_2(T2_div_by_1,255,1);

Ahora:
¿Que es lo que se captura y cuando?:

¿Que es lo que se captura y cuando?:


Resp: Se captura (más bien se toma) el valor del timer1 y se le asigna a CCP1 o CCP2
depende de donde donde se reciba el pulso y luego este valor se le puede pasar a una
variable, cuando en el pin CCP1 o CCP2 ocurre un evento esperado (un pulso) según sa
haya configurado.
¿Porqué se hace así?, Porque con el pulso en el pin CCP1 o CCP2 el valor del timer1 se
carga instantaneamente en el CCP, mientras que si asignamos el valor del timer1 a una
variable en el transcurso del programa este valor depende de la ubicación línea del
programa donde está, así que de esta forma la asignación del timer1 a la variable
pueder dar valores con un diferencial relativemente grande.

Eventos posibles a configurar en los pines CCP para que lo anterior ocurra.

a) Hay un pulso eléctrico que pasa de bajo a alto (flanco ascendente):


setup_ccp1(ccp_capture_fe);
b) Hay un pulso eléctrico que pasa de alto a bajo (flanco descendente):
setup_ccp1(ccp_capture_re);
c) Después de haber ocurrido 4 pulsos de bajo a alto.
setup_ccp1(ccp_captura_div_4);
d) Después de haber ocurrido 16 pulso de bajo a alto.
setup_ccp1(ccp_capture_div_16);

Explicación:
Se puede (ejemplo) usar los módulos CCP como cronometros de eventos o entre
eventos, por ejemplo: medir cuanto dura un pulso electrico, para ello como ya se dijo,
estos modulos CCP trabajan con el timer1, así por ejemplo cuando en el pin CCP1

180
ocurre un pulso ascendente se inicia el contador timer1 y cuando ocurre el pulso
descendente en el pin CCP1 este tiempo se mide.

Nota: tenga en cuenta que este debe ser un pulso de duración de tiempo muy corto,
centesimas o milesimas de segundo, no cometa el error de pensar que va a utilizar esto
para medir minutos u horas, recurde que los microcontroladores son dispositivos muy
rápidos.

Programa ejemplo para medir el tiempo de un pulso.

#include <16f876.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pant1.c>

int x;
int16 t;
#int_ccp1
void ccp1_int() {
If (x==0) {setup_ccp1(ccp_capture_fe); x=2;}
If(x==1) {setup_ccp1(ccp_capture_re); x=3;}}
void main () {
x=0;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b11111111);
setup_timer_1(t1_internal);
setup_ccp1(ccp_capture_re);
while (1) {
if (x==2) { set_timer1(0); x=1}
if (x==3) {
t=ccp_1;
printf(lcd_data," El tiempo del pulso es %6lu ",t);
x=0; delay_ms(1000);
}}}

181
Explicación del programa anterior:

1ro.) Las siguientes líneas son una subrutina que se activa cuando en el pin del
CCP_1 ocurre un cambio de estado, bien sea el paso de 0 a 1 o el paso de 1 a 0, esto
quiere decir que se va a meter por el pin 13 del microcontrolador 16F876 (que es el
pin CCP1) un pulso, como todos saben un pulso es el cambio de estado en un
terminal electrico que pasa de 0 a 1 a 0 , o de 1 a 0 a 1 , y vuelve a su estado
anterior.

#int_ccp1
void ccp1_int() {
If (x==0) {setup_ccp1(ccp_capture_fe); x=2;}
If (x==1) {setup_ccp1(ccp_capture_re); x=3;}}

Cuando ocurre el cambio de 0 a 1 el programa salta de su secuencia y se va a


ejecutar esta rutina que es una función de interrupción.

2do.) Como ya se sabe, cuando el programa arranca 1ro. Lee el encabezado y


todas las directivas y luego se va directo al cuerpo principal (void main) y es desde
este cuerpo que se puede llamar cualquier otro cuerpo o subrutina.

3ro.) Ahora el cuerpo principal:


void main () {
x=0;
setup_timer_1(t1_internal);
setup_ccp1(ccp_capture_re);
1ro.) Asigna x=0.
2d0.) Configura el timer_1, le declara que use las oscilaciones internas.
3ro.) Configura la entrada de activación con flanco ascendente (re).

4to.) Luego entra en un bucle infinito.


while (1) {
if (x==2) { set_timer1(0); x=1;}
if (x==3) { t=ccp_1;
printf(lcd_data," El tiempo del pulso es %6lu ",t);
x=0; } } }

Como el programa se inicia con x=0 y con flanco ascendente, hasta que en el pin
CCP_1 no haya un flanco ascendente no ocurre nada.
Ahora, cuando ocurre un flanco ascendente el programa salta a la rutina, y con x=0
cambia a flanco de descendente y asigna x=2, luego regresa al bucle infinito con
x=2, pone el timer1 en 0 y a x=1.

Ahora después de un flanco ascendente obligatoriamente viene un flanco


descendente y el programa vuelve a saltar a la rutina, pero con x=1, en la rutina se
vuelve a poner a flanco ascendente y asigna a x=3 y vuelve al bucle infinito.
Ahora en el bucle infinito con x=3 , se le asigna a t = valor que se contó en el timer1
extrayéndolo de t=ccp_1, luego se presenta este valor en la pantalla LCD y se
vuelve a asignar x=0, y vuelve a empezar todo.

182
Nota: El valor que obtenga de t dependerá de la frecuencia de oscilación y de cuanto
tarde el microcontrolador en ejecutarse toda la rutina del programa en microsegundos,
así que primero para calibrar el tiempo haga un generador de pulsos de 1 milisegundo
con otro microcontrolador e introduzca la señal por el pin CCP_1 del microcontrolador
que quiere calibrar y halle la relación para determinar la constante por la que tiene que
multiplicar a t.
Nota: En modo captura cuando ocurre un flanco, inmediatamente se carga el CCPx con
el valor de timer1, y este valor se mantine en CCPx, ahi está fijo hasta que ocurra otra
vez el mismo flanco.

Ejemplo:
Suponga que construyó su pulsador de 1 milisegundo, e introdujo el pulso por el pin
CCP_1 y que este le muestra en pantalla el número 24520 (o sea t=24520) ,
entonces t=t/24.520 y esto le hace t=1000 milisegundos. (no es exacto pero es una
buena aproximación).

Circuito recomendado para el programa anterior.


Nota: El circuito del NE555 es solo para calibrar, luego se debe retirar

El circuito del NE555 es un simple oscilador muy popular entre los técnicos en
electrónica, (facil de construir su montaje y económico).

¿Qué es lo que se compara y cuando?

Resp: Se compara el valor en tiempo real del timer1 con un valor que le asignemos a
alguno de los CCP.
Esto se hace de esta manera, porque así se nos garantiza que cuando ocurra la igualdad
entre el valor asignado al CCP y el timer1, el microcontrolador ejecutará la acción que
debe tomar en el momento preciso.

Ahora que modos de comparación hay y como se confuguran:

setup_ccp1(ccp_compare_set_on_match);

183
Con esta configuración, en el momento que ocurra la igualdad entre el timer1 y el
CCP1, el pin CCP1 se pondrá en voltaje alto si está en voltaje bajo, o se mantendrá en
alto si antes ya lo estaba.
Nota: El valor de CCP1 (CCP_1=valor) se lo asigno en una línea de programa
cualquiera (CCP_1 = 300); y recuerde que el timer1 se incrementa por si solo de forma
automática, comenzando desde un valor predeterminado set_timer1(valor), o cero (0).

setup_ccp1(ccp_compare_clr_on_match);
Con esta configuración, en el momento que ocurra la igualdad entre el timer1 y el
CCP1, el pin CCP1 se pondrá en voltaje bajo si está en voltaje alto, o se mantendrá en
bajo si antes ya lo estaba.

Programa ejemplo

#include <16f876.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>
int i,r;
#int_ccp2
Void ccp2_int() {
if (i==0) setup_ccp2 (ccp_compare_set_on_match);
if (i!=0) setup_ccp2 (ccp_compare_clr_on_match);
set_timer_1(0); r=0 }
void main () {
disable_interrupts(global);
setup_timer_1(t1_internal);
setup_ccp2(ccp_compare_set_on_match);
ccp_2=100000; i=1;
enable_interrupts(int_ccp2);
enable_interrupts(global);
lcd_init()
lcd_clear();
printf(lcd_data,” CCP2 oscilador”);
while(1){
if (i==0) i=1; else i=0;
r=1;
while (r!=0){ } }

El programa anterior es simplemente un oscilador cuya salida está en el pin CCP2, y


cada vez que el timer1 alcanza el valor de 100000 cambia su estado entre apagado y
encendido.

Explicación del programa.

184
En este programa cada vez que el timer1 alcanza el valor 100000 se iguala con el valor
que se le ha precargado a CCP2 (timer1==CCP2), y cada vez que esto sucede el
programa deja su rutina principal (que en ese momento se encuentra en un bucle infinito
y salta a la sub-rutina #int_ccp2, y sucede lo siguiente:
1ro.) Tengamos en cuenta que cuando el programa pasa por toda la rutina principal el
CCP_2 se carga con el valor de 100000, y que la variable i se carga con el valor de 1
entonces tenemos CCP_2=100000 e i=1.
2d0.) Entonces al entrar a la sub-rutina hace una evaluación, y si ( i==0) configura el
pin CCP2 para que cuando CCP_2==100000 encienda un led que esté en ese pin
conectado, y si (i==1) entonces configura el CCP2 para que cuando (CCP_2=100000)
apague el led. Lo que quiere decir que la sub-rutina lo que hace es cambiar la condición
de la salida para que el led oscile.
3r0.) Observe que al final de la rutina principal hay dos bucles infinitos anidados, el
bucle externo alterna el valor de i entre 0 y 1, y el segundo bucle es solo para consumir
tiempo mientras se llega a la igualdad entre CCP y timer1.
Nota: El bucle interno se termina cuado la corrida del programa regresa de la sub-rutina
#int_ccp2 porque allá se le cambió el valor a r y se le hace (r==0), para que salga de
ese bucle (el interno) y regrese al bucle externo para alternar el valor de i, y el de r=1,
se hace (r!=0) para que vuelva a caer en bucle infinito (el más interno):Nota recuerde
que != significa diferente.
Circuito recomendado para el programa anterior

185
FUNCIONES DE INTERRUPCIÓN.

Las funciones de interrupción tienen una traducción en el leguaje de los programadores.


Sub-rutinas a las que se llega mediante un evento, que puede ser externo al
microcontrolador (un pulso en un pin) o interno (una comparación entre un contador y
un registro)
Todo aquel que ha programado en algún lenguaje sabe bien lo que es una subrutina, y
también sabe que para que un programa entre en una subrutina se debe cumplir
alguna(s) condición(es), y en este libro cuando se explicó como programar en lenguaje
C, se explicó que los programas en este lenguaje se podían hacer en cuerpos
independientes, y que estos cuerpos pueden realizar y realizan tareas independientes de
todos los demás cuerpos, y además que para ejecutar un cuerpo de estos simplemente
hay que llamarlo desde el cuerpo principal del programa o desde otro cuerpo.

Estas, a las que llaman funciones de interrupción no son más que cuerpos (subrutinas)
que se ejecutan cuando ocurre algún evento.

¿Cuáles eventos?
1) Que en un pin se de un pulso con flanco ascendente o descendente.
2) Que un contador y un registro se igualen.
3) Que haya un cambio en alguno de los pines (nible superior) de alguno de los
puertos.
4) Que se transmita o reciba un dato por un pin.
5) Que ocurra un desbordamiento en un contador.
6) Que haya actividad en el puerto paralelo.

Y otras más.
Ya en los programas inmediatamente anteriores usé las funciones de interrupción
#int_ccp1 y #int_ccp2.

Las funciones de interrupción que voy a exponer son las siguientes:


Nota: Un evento es un flanco de un pulso.

#INT_EXT Que se ejecuta cuando ocurre un evento en el pin_b0.

#INT_RTCC Que se ejecuta cuando ocurre un evento en el pin T0CLKin.

#INT_TIMER1 Que se ejecuta cuando se desborda el timer1.

#INT_TIMER2 Que se ejecuta cuando se desborda el timer2.

#INT_CCPx Según la configuración: (x puede ser 1 0 2)


1.-) Con un flanco (subida o bajada)
2.-) Con cada 4 flancos de subida.
3.-) Con cada 16 flancos de subida.
4.-) Con una comparación entre CCP y TIMER1.

186
Nota: Hay muchos otros eventos con los cuales se puede ejecutar una sub-rutina
ligada a una función de interrupción, pero en este libro solo explicaré las antes
mencionadas.

Lo primero que pienso que se debe saber de una función de interrupción, después de
haber explicado lo anterior es lo siguiente:

Cual función necesito usar, para que me sirve y cuales son sus parámetros:

1ro.) Con cual de los pines del microcontrolador está relacionada.


2do.) Que debo o como debo hacer para usarla.
3ro.) Que hace esta función.
4to.) Como configurarla.
5t0.) Como habilitarla.

Nota: Se les llama función de interrupción, pero esto no es una función como
normalmente la conocemos en matemática (para la gente que ha estudiado
ingeniería o tecnología), realmente lo que hace es saltar desde alguna parte de un
programa en ejecución a un cuerpo (sub-rutina) o módulo y luego de ejecutar ese
sub-programa regresa a continuar ejecutando el programa desde donde saltó.

Esta explicación es válida para todas las funciones de interrupción.

Función de interrupción #INT_EXT

La función de interrupción #INT_EXT, está (por decirlo de alguna forma)


conectada al PIN_B0, observe los diagramas de pinados.

¿Con cual de los pines del microcontrolador está relacionada?


Resp.: Lo que quiere decir INT en el mismo PIN_ RB0 en los diagramas es que: es
en ese pin donde debe ocurrir el evento que disparará el salto a la subrutina que

187
corresponde con esta función #INT_EXT, es evidente que este pin debe estar
configurado como entrada en la línea SET_TRIS_B(0bxxxxxxx1).

¿Que debo o como debo hacer para usarla?.


Resp.: Para usarla se debe colocar antes del cuerpo principal del programa y
después del encabezado la siguiente señalización, que indicará a PIC C a donde
saltar.

#INT_EXT
Void nombre () { }

¿Que hace esta función?.


Esta función hace todo lo que se le programe, es una sub-rutina como cualquiera,
solo que esta está condicionada a ejecutarse con un evento externo que suceda en el
pin RB0/INT.

Ejemplo:
#int_ext
void inext()
{
output_high(pin_c0);
output_low(pin_c1);
delay_ms(1000);
output_d(0b11000011);
output_a(0b10101);
}

¿Cómo se configura?
La configuración de esta función, al igual que todas las funciones que tienen que ver
con pulsos eléctricos es realmente sencilla:

Lo primero que hay que decir de un pulso eléctrico (periódico) es que está compuesto
de cuatro fases. (observe el diagrama).

Rojo: voltaje bajo


Azul: Flanco de subida (intervalo de tiempo para pasar a voltaje alto.)
Violeta: Voltaje alto.

188
Verde: flanco de bajada (intervalo de tiempo para pasar a voltaje bajo).
Nota: En la gráfica se aprecia que el tiempo de voltaje alto y bajo son 10
milisegundos y que los flancos duran 1 milisegundo.

Ahora, para configurar la interrupción #INT_EXT, aparte de la línea que indica que
esta interrupción se va a usar y donde está ubicado el cuerpo (sub-programa),
también hay que decirle con cual flanco del pulso debe saltar a la función
interrupción.

ext_int_edge(0,l_to_h);

Esta línea debe estar en alguna parte del cuerpo principal del programa, y se
interpreta de la siguiente forma:

ext_int_edge. Flanco para la interrupción externa


(0,l_to_h) Informa que es la interrupción externa 0, flanco de
bajo a alto (low to high) “Flanco de subida”
O

ext_int_edge. Flanco para la interrupción externa


(1,h_to_l) Informa que es la interrupción externa 1, flanco de
alto a bajo (high to low) “Flanco de bajada”

En microcontroladores avanzados hay hasta 5 o más interrupciones externas.

¿Cómo habilitarla?.
La habilitación de la función de interrupción se hace con dos líneas de programa que
originalmente deben estar en el cuerpo principal, pero que luego de esto se puede
colocar copia de las mismas en sub-rutinas para cambiar la activación del tipo de
flanco o deshabilitarlas.

enable_interrupts(int_ext) Habilita la interrupción.

enable_interrupts(global) (global) Informa a PIC C que


esté pendiente de cualquier
interrupción de cualquier función.

189
Programa ejemplo:

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>

#int_ext
void nombre () {
printf(lcd_data,"Ha ocurrido un evento en INT_EXT");
output_high(pin_b1);
delay_ms(2000);
lcd_clear(); }

void main ()
{
set_tris_a(0b11111);
set_tris_b(0b00000001);
lcd_init();
lcd_clear();

ext_int_edge(0,l_to_h);
enable_interrupts(int_ext);
enable_interrupts(global);

while (1)
{
output_low(pin_b1);
}
}

El programa anterior tiene una sola finalidad, presentar en la pantalla LCD un


mensaje que dice Ha ocurrido un evento en INT_EXT y encender un led conectado
al pin_b1 durante 2 segundos cuando en el pin RBO/INT se detecta un flanco de
subida.

190
Circuito recomendado para el programa anterior.

Función de interrupción #INT_RTCC.

Nota: En PIC C las expresiones RTCC y TIMER0 significan exactamente lo


mismo.

El timer0 también es otra función de interrupción, pero esta a diferencia de


INT_EXT se puede configurar para que salte a la sub-rutina una vez cada cierta
cantidad de eventos captados en el pin correspondiente, esa cantidad de eventos es
configurada por el programador, y para ello se debe valer de una precarga en el
valor del timer0 set_timer0(precarga) y un numero llamado prescaler.
Ahora: ¿Que es el prescaler?: Es un número que nos indica cada cuantos pulsos se
tomara uno y solo uno en cuenta para incrementar el valor del timer0.

Como ya sabemos, el timer0 trabaja como contador o temporizador, y cuando se


emplea como una función de interrupción y contador podemos hacer lo siguiente
para configurarlo.
En los contadores de eventos se pueden configurar situaciones simultáneas para
adaptar el contador a nuestras necesidades.

Por ejemplo:

Nota: Tenga en cuenta que los contadores no son infinitos, que ellos tienen una
capacidad máxima de conteo, es decir cuentan hasta un número y vuelven a cero (0)
para comenzar de nuevo, y que cuando llegan a su máximo se dice que se
desbordan.

¿Cómo configurar un contador para que cuente hasta un valor exacto?.

1ro.) Debemos saber hasta cuanto cuenta el contador:


Todos los timer cuentan hasta 255 (8 bits), excepto el timer1 que
cuenta hasta 65535 (16 bits)
2do.) Para agrupar las condiciones de conteo se usa el símbolo de barra

191
vertical | ( su código ASCII es 124).
3ro.) No ponga condiciones que no se puedan cumplir simultáneamente.

Ejemplos de configuración de los timer

-Para que cuente eventos (pulsos) de 1 en 1 hasta 255 con captación por el
pin_T0CLKin, (es el mismo PIN_A4) en el flanco de subida.
setup_timer_0(rtcc_ext_l_to_h);

rtcc (es timer0), ext (pulsos externos), l_to_h (flanco de subida)

- Para que cuente 100 eventos por el pin T0CLKin en el flanco de bajada

set_timer0(155);
setup_timer_0(rtcc_ext_h_to_l);

Explicación: Como el timer0 cuenta hasta 255 y solo quiero contar 100 eventos
antes del salto, precargo el contador timer0 con 155, así comenzara a contar desde
el nro. 156, y como 255 – 155 =100, entonces cada 100 conteos se desbordará.

Para que cuente 300 eventos en el flanco de subida.


set_timer0(105);
setup_timer_0(rtcc_ext_l_tio_h | rtcc_div_2);

Explicación: Como el timer0 está precargado con 105, entonces al contar desde 106
hasta 255 estará haciendo 150 conteos y además como los pulsos se están dividiendo
por 2, toma en cuenta 1 por cada 2 (uno si, uno no), lo que lo obliga a desbordarse
después de hacer 300 conteos.

Nota: Con un poco de imaginación se puede poner a contar casi a cualquier número,
por ejemplo todos los números entre 1 y 255 si se precarga el timer0 con la resta.
Ejemplo: Contar hasta 111 eventos, se precarga con (255-111=144) 
set_timer0(144);

Los prescaler que se pueden usar son 2, 4, 8, 16, 32, 64, 128 y 256.

Los prescaler nos dan la división por la cual se están dividiendo los eventos (pulsos)
para ser tomados en cuenta (se cuenta 1 cada tantos pulsos), así con un prescaler de
256, y si el conteo no se precarga al timer0 (cuenta desde 0 hasta 255) se desbordará
en el conteo 256*256-1=65525, que es el desbordamiento del timer1. En otras
palabras lo más lejos que puede llegar el timer0 es hasta el normal del timer1.

Pinado en donde se muestra la ubicación de la entrada del timer0

192
Programa ejemplo:

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>

#int_timer0
void nombre () {
printf(lcd_data,"Han ocurrido 255*16 “);
lcd_cmd(192);
printf(lcd_data,”eventos en timer0");
output_high(pin_b1);
delay_ms(2000);
lcd_clear(); }

void main ()
{
set_tris_a(0b11111);
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
setup_timer_0(rtcc_ext_l_to_h | rtcc_div_16);
enable_interrupts(int_timer0);
enable_interrupts(global);
while (1)
{
output_low(pin_b1);
}
}

193
Este programa cuenta 4095 eventos en el pin timer0 y da el salto a la sub-rutina que
muestra en mensaje, observe que 4095 es la cuenta de 255*16-1=4095.

Circuito recomendado para el programa anterior.

Nota: Las funciones de interrupción CCP1 y CCP2 ya fueron explicadas en el tema de


Captura, Comparación y Modulación de pulsos.

194
Ultimo tema en lo que se refiere a la programación.

Existen dos comandos en PIC C que se usan para encerrar una rutina que está hecha en
assembler y ponerla a correr junto con el programa que hagamos en PIC C : Estos
comandos son:

#ASM
ADD A
MOV.D W0,W4
MAC W4,W5,A
MOV.D ACCAH:ACCAL, W0
MOV.B W1, 0x1352
#ENDASM

y se usan para introducir una parte de un programa que esté hecho en assembler dentro
de una programa hecho en PIC C, ahora: porque és esto es importante: Porque hay
cualquier cantidad de programitas en assembler (sub-rutinas) hechos para realizar
muchas tareas básicas en publicaciones y en la Internet que nos sirven para agilizar
cualquier programa que estemos haciendo. De esta manera solo tenemos que copiar
antes de la sub-rutina #asm (sub-rutina) #endasm, también podemos valernos de una
función interrupción para usar una sub-rutina en assembler con estos comandos.
Ver ejemplo

Programa ejemplo

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>
#int_timer0
void nombre () {
printf(lcd_data,"Han ocurrido 255*16 “);
lcd_cmd(192);
printf(lcd_data,”eventos en timer0");
output_high(pin_b1);
delay_ms(2000);
lcd_clear(); }
void main ()
{
#asm
movlw 8
movlw 0
#endasm
set_tris_a(0b11111);

195
set_tris_b(0b00000000);
lcd_init();
lcd_clear();
setup_timer_0(rtcc_ext_l_to_h | rtcc_div_16);
enable_interrupts(int_timer0);
enable_interrupts(global);
while (1)
{
output_low(pin_b1);
}
}

Las líneas que están en assembler no hacen nada dentro del programa, pero sirven de
ejemplo para ilustrar como poner una rutina en assembler dentro del PIC C.

LOS PRINCIPALES ERRORES QUE COMETEN LOS PRINCIPIANTES EN


PIC C.

Nota: Toda a aquella persona que alguna vez a programado, sabe que los leguajes solo
detectan errores de sintaxis del lenguaje y matemáticos como la división por cero, y de
confusión entre tipos de variables, los errores de programas en los que la sintaxis está
buena, pero las fórmulas matemáticas están malas no las detecta ningún lenguaje, por
eso hay que probar los programas con datos conocidos y sus respuestas para cerciorarse
de que se está en lo correcto.

El primer error que normalmente se comete es el siguiente.

Este error es el típico al principio, cuando se tiene una de las palabras de directivas en
la línea #fuses mal escrita, revíselas y verifique todas las letras de las palabras y la
separación por comas (,).
También aparece cuando tienen algún error (palabra mal escrita) en alguna de las líneas
de directivas del encabezado que comienzan con el carácter #.

Este error aparece cuando se intenta compilar un programa en un microcontrolador que


no lo puede ejecutar, ejemplo: configurar en convertidor analógico digital en un
PIC16F84

Este error le indica que ese microcontrolador no está incluido en la base de datos de
microcontroladores en
C:\Archivos de programa\PICC\Devices
o que tiene mal escrito el nobre del microcontrolador con la extención .H

196
Al final de toda línea de comandos debe haber un ; que indica la separación entre una
orden y otra.
Nota: Cuando se requiere realizar un bucle FOR o evaluar una condición IF no se
coloca el ;
Ejemplo: for (i=0;i<100;i=i+1) y if (x==0)
Y se encierra entre llaves { } el sub-programa que debe ser ejecutado bajo ese bucle o
esa condición.

Estos errores ocurren cuando se llama a un cuerpo de programa (una sub-rutina) que no
existe, porque; o no existe, o tiene mal escrito el nombre, o porque se está tratando de
utilizar una variable que no está declarada.

Este error aparece cuando se está confundiendo dos tipos de variables, o está tratando de
asignar un valor con decimales a una variable entera (esta es sin decimales o viceversa),
también ocurre cuando entre variables enteras se trata de trabajar a una variable de
formato int con formato de int16.

Todos los errores anteriores son errores de falta de algún signo, las llaves y los
paréntesis deben estar en parejas {}, ( ), no deben faltar (punto y coma); después de un
comando.

Error de división por cero (x/0);

Cuando trate de trabajar con alguna función matemática


(ejemplo y=sin(x) )
y le aparezca este error, es porque no ha llamado a la librería de operaciones
matemáticas #include <math.h> en el encabezado del programa.

Nota: En la Internet hay varios manuales en PDF en español y en ingles, en los que hay
una gran cantidad de errores y otras informaciones importantes.
Busque manual de usuario del compilador pcw de ccs pdf.

197
LA ELECTRÓNICA MÍNIMA NECESARIA PARA COMENZAR.

Los componentes electrónicos mínimos necesarios para iniciarse en el área de la


programación de los microcontroladores son:

1 Microcontrolador (recomendable) PIC16F84 0 PIC16F876.


6 Pulsadores.
8 Leds.
1 Cristal resonador de 8 000 000 herz.
1 Fuente de voltaje DC 5.0 Volt y 1 amp. o más amperaje.
1 Regleta o protaboard.
1 Pantalla LCD de 16 caracteres y 2 líneas.
1 Programador JDM (construirlo)
(Componentes para construir el programador JDM)
2 Resistencias de 10 000 ohm.
1 Transistor 2N3904
1 Condensador de 16V/50uF
1 Diodo zener 1N4733
1 Conector DB9 hembra con sus tapas
1 Cable de 5 conductores de 1.5 mts.
4 mts de cable multipar cortado en pedazos de entre 3 cms y 20 cms para hacer las
conexiones en el protoboard.

El Software programador que lo puede descargar gratis el la sig. dirección

El software para crear el código fuente y compilador u otro.

Con la lista anterior de materiales y el software se tiene más que suficiente para
inicializarse en la programación de los microcontroladores, al principio del libro está el
plano y la explicación de cómo construir el programador JDM, muy económico y
efectivo, esto es porque muchos estudiantes de áreas diferentes a la electrónica o
sistemas quisieran iniciarse en la programación de los microcontroladores, pero lo

198
piensan porque el costo de los programadores comerciales, que aún los más económicos
es alto, y estos estudiantes ya tienen bastante con los costos de sus carreras.

Este manual está dirigido a estudiantes de mecánica, bien sea tecnología o ingeniería,
pero sé que muchos otros, como los estudiantes de construcción civil, química,
hidrometeotrología, etc. también lo aprovecharán al máximo, este manual es de lo más
sencillo, todos los programas tienen un nivel de dificultad aceptable porque la
intención es que se inicien sin tropiezos, y que puedan resolver alguna situación
sencilla sin tener que recurrir a especialistas.

Se aconseja que analice todos los programas por sencillos que sean y que traten de
resolver la misma situación con algún programa parecido, también que haga todos los
montajes que puedan (que no son muchos), además cada uno sirve para varios
programas y muchos otros que usted mismo cree.

También hay programas de situaciones reales de mecánica, como medir RPM, RPS,
temperaturas, como controlar temperaturas, como medir tiempos realmente pequeños y
presentar los datos en pantallas, displays 7segmentos o transmitirlos por una línea de
comunicación serial incluso a largas distancias, como pasar del control de motores de 5
voltios a motores de 500 voltios, entender el uso de los convertidores de analógico a
digital y de digital a analógico Etc.

LA ELECTRÓNICA ANALÓGICA

La electrónica analógica es la electrónica en la que las señales que se trabajan y


procesan son señales analógicas, ahora: ¿Cuáles son las señales analógicas?, son todas
aquellas señales en las que lo importante es su magnitud cambiante, bien sea voltaje o
corriente, y que la información que ellas transmiten está relacionada con su magnitud
variable permanentemente, las gráficas de éstas señales generalmente son sinosoidales,
pero también pueden ser exponenciales o parabólicas.

Los principales componentes electrónicos que se usan en la electrónica analógica son:


La resistencia, El condensador, La bobina, El transistor, El diodo, El transformador,
El diodo emisor de luz, El amplificador, los transductores y los transformadores.

Con estos componentes se puede construir cualquier cantidad de circuitos para


diferentes usos y objetivos (osciladores, receptores, transmisores,etc), pero rara vez
tendrán su propio control o regulación, no tienen capacidad de programación.

No obstante, esta es la electrónica original, donde empezó todo, y todas las señales
electromagnéticas de radiación son analógicas.

LA ELECTRÓNICA DIGITAL.

199
La electrónica digital es la electrónica de las señales digitales, ahora: ¿Cuáles son las
señales digitales?, la señales digitales son aquellas señales en las que lo que importa es
solo su polaridad, es decir la señal es positiva, o es negativa, y para decidir si es positiva
o negativa se pone como regla la siguiente condición: Toda aquella señal cuyo voltaje
sea menor a 2.5 voltios es negativa o vale 0, y toda aquella señal cuyo voltaje sea mayor
a 3.5 voltios es positiva o vale 1, si una señal está entre 2.5 volt. y 3.5 volt. está
indefinida y dependerá del tratamiento que se le de o el diseño del circuito que la
procese como las tomará, pero lo normal es que estas señales o estén por debajo de 2.5
volt o por encima de 3.5 volt..

Ahora bien, estas señales son usadas para transmitir información de dos maneras
posibles: a) Se transmite información de forma serial, lo que quiere decir que se
transmite en una serie de pulsos por un mismo conductor y que el componente que los
recibe puede interpretarlos, b) En forma paralela, es decir se transmite la información
usando una grupo de conductores (normalmente 8 cables) y por cada conductor se
transmite un pulso, los ocho cables transmiten simultáneamente para formar un número
en código binario que tiene una interpretación acordada también por el elemento
electrónico que las recibe.
Esta electrónica es la electrónica de todas las máquinas que procesan información
computacional hoy día, todas las calculadoras, las computadoras y todo aparato que
soporta un programa para trabajar lo hace en base a la electrónica digital, en base a esto,
el principal elemento de toda esta electrónica es el microprocesador, los que cada día
son más avanzados y potentes (decir que un microprocesador es más potente que otro;
quiere decir que tiene mayor capacidad de procesamiento de información tanto en
cantidad como en velocidad).

En esto se basa la idea de este libro, utilizar los microcontroladores para poder procesar
información que obtendremos del medio en el que están instalados utilizando todo tipo
de sensores, transductores y convertidores, para controlar voltajes y corrientes para
poder cambiar la situación de trabajo de algún proceso, más calor, más revoluciones,
informar una situación, dar señales de alerta, etc.

Los componentes en la electrónica digital son tantos que no alcanzaría un libro para
mencionarlos con sus características, pero entre los de más utilidad están (aparte de los
microprocesadores) las memorias de todo tipo, los convertidores A/D y D/A,
codificadores, acopladores, pantallas, todo tipo de compuertas, osciladores, etc.

En la electrónica digital existen unas serie de componentes en circuitos electrónicos


integrados que bien vale la pena estudiar y entender el funcionamiento, estos circuitos
son los llamados TTL, CMOS, DTL, RTL, HTL y tener algún manual de estos a la
mano, ya que estos elementos nos brindan una gran cantidad de soluciones a problemas
sin la necesidad de ni-siquiera pensar, solo hay que saber que existen y aplicarlos, yo
personalmente recomiendo los TTL (llamados 74XXYYY )y los CMOS (llamados
40XXYYY), los que en la Internet tienen manuales bien completos de motorola.

LA ELECTRÓNICA DE POTENCIA:

200
La electrónica de potencia es la electrónica responsable de la aplicación de los
elementos de estado sólido para el control de la potencia eléctrica, los elementos de
control son circuitos que trabajan con voltajes muy bajos, estos circuitos integrados,
procesadores, microcontroladores son los que generan las señales para el control de los
dispositivos que consumen grandes potencias (motores trifásicos, sistemas de
iluminación, etc).

Los dispositivos responsables de la conmutación del paso de estas cantidades de energía


eléctrica tanto voltaje como corriente son los llamados semiconductores de potencia, la
tecnología de los semiconductores está desarrollando dispositivos de control de potencia
como los TBJ, MOSFET, SIT, SCR, TRIAC y otros, y las aplicaciones de los
microprocesadores y microcontroladores y la electrónica digital para el control y
automatización de procesos en los que se manejan altos voltajes y corrientes es cada vez
mayor, por ejemplo en el control de los ascensores se está haciendo con sistemas cuyo
elemento central es un microprocesador, bien sea a través de una computadora, un PLC
o un microcontrolador, lo que permite programar y reprogramar el funcionamiento del
ascensor sin la necesidad de cambiar ningún componente, de ahí los llamados
ascensores inteligentes (o sistemas inteligentes) que cumplen con un programa de
funcionamiento específico para cada día de la semana incluso horas pico, con el
objetivo de ahorrar energía.

COMPONENTES ELECTRÓNICOS ÚTILES PARA DOSEÑOS Y


APLICACIONES.

Tres compuertas AND (Y) de tres entradas 7411

Su funcionamiento es el siguiente:
Cuando en las entradas E1, E2 Y E3 hay un voltaje alto (mayor de 3 voltios), en la
salida se presenta un voltaje alto, pero si solo en alguna de las entradas (cualquiera) hay
un voltaje bajo entonces la salida será voltaje bajo. (Estos circuitos TTL cuyos códigos
siempre tienen el número 74, ejemplo: SN74LS11 se alimentan en la esquina superior
izquierda con 5voltios y en la esquina inferior derecha con 0 voltios).

Para esto se utiliza una tabla llamada: la tabla de la verdad, y funciona de la siguiente
forma:

TABLA DE LA VERDAD

201
E1 E2 E3 SALIDA
0 0 0 0 En la tabla a la izquierda se observa
0 0 1 0 que si cualquiera de las entradas E es
0 1 0 0 0 (voltaje bajo) la salida es también
1 0 0 0 de voltaje bajo, y solo cuando todas
0 1 1 0 las entradas son de voltaje alto, la salida
1 0 1 0 tiene voltaje alto. Este es el concepto
1 1 0 0 de compuerta Y (AND), solo hay salida alta
1 1 1 1 cuando están en alto todas las entradas.

Cuatro compuertas NAND (Y inverso) de 2 entradas 7400

En este circuito, si cualquiera de sus entradas es bajo (0) la salida es alto (1), de resto la
salida es bajo (0).
TABLA DE LA VERDAD DEL TTL 7400
E1 E2 SALIDA
0 0 1
0 1 1
1 0 1
1 1 0

Seis inversores de señal (Entrada = Salida inversa), 7414

Este circuito invierte la señal que tenga a la entrada, si la entrada es positiva, su salida
es negativa y viceversa.

E SALIDA
0 1
1 0

Cuatro compuertas O (OR) 7432

202
En este circuito, si cualquiera de sus entradas es alto (1), la salida es alto (1), y solo
cuando todas sus entradas son bajo (0) la salida es bajo (0).

Tres compuertas O Inversa (NOR) de tres entradas. 7427

En este circuito, si cualquiera de sus entradas es alto (1), la salida es bajo (0), de resto
es alto (1).

Compuertas Y (AND)
Compuerta Y de 4 entradas Compuerta Y inversa de 8 entradas

Decodificador de entrada en código binario y salida en un pin decimal

203
En los pines A,B,C,D se coloca un valor en binario, suponga A, B a 0volt, y B,C a 5
volt. entonces se activará en pin 4 que corresponde al número 3, que es como se escribe
3 en binario 0011.

Codificador con entrada en binario y salida para alimentar un display 7segmentos de


ánodo común. 7447

Compuerta EXOR

En este circuito si las entradas son iguales, la salida es voltaje bajo, si las entradas son
diferentes, la salida es voltaje alto.
Circuito selector, con entrada en binario 4 bits y salida en decimal 16 pines

204
En este circuito colocamos un número en binario a la entrada y este responderá
activando (poniendo en voltaje bajo (0)) solo ese pin a su salida.

Excitador de línea unidireccional con selección de paso s/n.

Excitador de línea bidireccional con selección de paso.

Aquí lo importante es que tenga una referencia de la existencia de ciertos circuitos, y


que sepa que existen muchísimos más, y que cuando necesita hacer algún diseño,
primero revise la lista de componentes y luego se ponga a diseñar, teniendo criterios
como, lo económico, la simplicidad, la disponibilidad de los IC, y lo principal,
imaginación y domínio de tema.

205
TABLA DE COMPONENTES ELECTRONICOS

CIRCUITOS TTL (Lógica transistor-transistor)

206
207
208
209
COMPONENTES CMOS 40XXXX

210
AMPLIFICADORES OPERACIONALES Y COMPARADORES

211
CIRCUITO INTEGRADOS PARA COMUNICACIONES

ARREGLOS DISCRETOS

Nota: Los arreglos discretos son: un grupo de resistencias, o un grupo de transistores, o


un grupo de diodos y otros componentes que se fabrican en un circuito integrado para
facilitar su aplicación en un diseño electrónico.

212
CIRCUITO LINEALES Y OTROS

REGULADORES DE VOLTAJE

213
TRANSISTORES

214
Nota importante: Todos y cada uno de los componentes electrónicos que aparecen en las
tablas anteriores tienen su manual de características en PDF, que lo podemos conseguir
en la Internet o en manuales de componentes electrónicos que se venden
comercialmente, esta es simplemente una lista en la que aparece el código del
componente y una breve descripción , para aplicarlos en un diseño de un circuito
particular se recomienda buscar su manual en el que aparecen los parámetros de trabajo
y sus curvas características, aplicación típica y algún ejemplo.

Se recomienda buscar algunos componentes en la Internet y observar sus propiedades


eléctricas, su geometría, aplicación típica, curvas características y hasta su costo.
Nota: Una curva característica de un componente es la gráfica que se obtiene de
aplicarle voltaje y observar su desempeño en diferentes condiciones de instalación, su
consumo de corriente, calentamiento, etc., cada gráfica es generada al menos con un par
de estos parámetros y se les llaman curvas características.

215
CARACTERISTICAS TECNICAS DEL

PIC16F84

Encapsulado de 18 pines.

Microcontrolador de 8 bits
.
La arquitectura de la CPU es del tipo HARVARD.

Tiene un set de instrucciones de 35 palabras de 14 bits.

Todas las instrucciones se ejecutan en un ciclo máquina, excepto las instrucciones de


salto de linea que se ejecutan en dos ciclos máquina.

Velocidad de operación
DC Hasta 20 Mghz de frecuencia en el cristal resonador.
DC Duración de ciclos máquina de 200 nano segundos
PIC16F84A-04 Cristal resonador 4Mghz.
PIC16F84A-20 Cristal resonador 20Mghz.

Memoria del tipo FLASH de 1024 instruciones.


Memoria RAM de datos de 68 bytes.

Tiene 15 registros de funciones especiales.

La pila tiene 8 niveles de anidamiento (profundidad).

Tiene 4 posibilidades de interrupción, configurables por software.


1) Interrupción por entrada externa RB0/INT_EXT
2) Por desbordamiento del timer0.
3) Por algún cambio en por los bits 4,5,6,7 del puerto B.
4) Por escritura en la memoria EEPROM.

216
Características de los periféricos incorporados.

Puerto A: 5 líneas, configurables como entradas o salidas.


RA0, RA1, RA2, RA3 Entradas o salidas digitales.
RA4/T0CKi multiplexada entre salida o entrada digital o entrada externa
para el contador TIMER0.

Puerto B: 8 líneas, configurables como entradas o salidas.


RB0,RB1,RB2,RB3,RB4,RB5,RB6,RB7 entradas o salidas
Digitales y RB0/INT multiplexada entre salida o
digital y entrada de interrupción externa.

Su consumo es de 25 mA por pin cuando está como entrada.


Proporciona 20 mA cuando trabaja como salida y esta en alto.

El TIMER0 es un contador de 8 bits, con división de frecuencia programable en el


prescaler.

OTRAS CARACTERISTICAS.

La memoria FLASH soporta hasta 10000 ciclos de borrado/escritura.

La memoria EEPROM soporta hasta 10 000 000 de ciclos de borrado/escritura.


Con retención mayor a 40 años.

Se puede programar con transmisión de datos en forma serial con solo dos pines
instalado en el circuito de trabajo. (ICSP).

217
Contiene circuito de perro guardián con oscilador incorporado RC de alta
confiabilidad.

Protección de código del programa.

Modo de funcionamiento de bajo consumo.

Tipo de oscilador seleccionable por software en el programa.

Tensión de alimentación de 3.5 a 5.5 Volt.

Tensión VPP (programación) de 12 a 14 Volt.

Potencia de disipación máxima 800Mw

218
CARACTERISTICAS TECNICAS DEL

PIC16F876

CARACTERISTICAS PRINCIPALES DEL PIC16F876

219
TABLA DE LAS FUNCIONES DE LOS PINES DEL PIC16F876 Y PIC 16F876A

220
221
Conexión con los condensadores para la estabilidad de la señal del oscilador de cristal.

Diagrama de las dimensiones geométricas del PIC16F876

222
223
224
CARACTERISTICAS TECNICAS DEL

PIC16F877

225
226
227
DIAGRAMA DE LOS PINES DEL PIC16F877

228
229
230
231
232
233
234
235
236
237
238
TABLA DEL PINADO DEL PIC16F877

239
240
CARACTERÍSTICAS GEOMÉTRICAS

SECCIÓN DE PROGRAMAS DIDACTICOS

241
Desde aquí en adelante, antes de tratar de entender y analizar un programa, primero
estúdiese lo mejor que pueda sin demorar mucho la circuitería a la que se le va a aplicar
ese programa, tenga en cuenta que el circuito y el programa van juntos, el circuito no se
entiende sin el programa, y el programa no tiene sentido sin el circuito, hay que tenerlos
a los dos presentes en el cerebro al mismo tiempo para lograr el mejor éxito en el área
de diseño digital y su programación.

Haga este montaje, que este circuito se va a usar para varios programas, en principio
habrá ciertos elementos que no se van a usar, pero conforme vaya avanzando en los
programas, se van usando esos componentes hasta su totalidad.

Programa ejemplo 1. El encendido de un led


#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
void main () {
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);
output_b(0b00000001);
}
Este programa es de lo más simple. Solo enciende un led que esté conectado al pin B0.
Explicación línea por línea.

1ra. Se le informa a PIC C cual es el microcontrolador que se va a programar


#include <16f84a.h>

242
2da Se dan las directivas:
#fuses indicador de que lo que viene son directivas.
hs Para cristal resonador de frecuencia mayor a 3.6 Giga hertz
nowdt Para no activar el circuito de perro guardián.
noprotect Para informar que no queremos proteger el código del programa.
put Para informar que el programa debe arrancar cuando el sistema esté
eléctricamente estabilizado.

3ra Se le informa a PIC C la frecuencia del cristal que vamos a colocar.


#use delay (clock=8000000)

4ta. Se inicializa el cuerpo principal del programa.


void main () { “la llave abierta indica el principio del cuerpo de programa.

5ta. Se configura el puerto A como un puerto con todos los pines como entradas.
set_tris_a(0b11111);
Nota: En este libro se configuran todos los puertos en código binario para facilitar y
ver a simple vista la función de cada pin, así cuando el pin es 0 está como salida, y
cuando es 1 está como estrada. Hay quienes les gusta el código hexadecimal, y lo
harían así set_tris_a(0h1F); pero como 0h1F =0 b11111. da lo mismo.

6ta. Se configura el puerto B con todos los pines como salida.


Set_tris_b(0b00000000);

7ma. Se ordena apagar todo el puerto A (realmente esto no hace falta porque es un
puerto de entrada y no va a mandar señales, pero es para visualizar solamente).

8va. Ser ordena apagar todo el puerto B, esta es para asegurar que en el puerto no
hay ninguna señal por alguna causa desconocida.

9na Envía una señal de 5 voltios por el pin B0, y 0 voltios por los demás pines.

10ma Cierre de llave indicando final del programa.


Programa ejemplo 2. Encendido y apagado del mismo led de forma indefinida.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
void main () {
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
while (1) {
output_b(0b00000000);
delay_ms(500);
output_b(0b00000001);
delay_ms(500);
}
}

243
El programa anterior nro. 2 , es el mismo programa nro. 1, con la variante que este
enciende y apaga el led que está conectado al pin_B0 durante 0.5 segundos, (0.5seg.
apagado, 0.5seg. encendido).

Solo explicaré las líneas en negrita, ya que las demás fueron explicadas en el programa
nro. 1.

While (1) { La sentencia while (una condición){ inicializa un bucle que se mantiene
en su ciclo mientras la condición que está adentro de los paréntesis se esté cumpliendo,
ahora, cuando adentro de los paréntesis colocamos un valor constante, esta es una
condición que siempre se va a cumplir, por lo tanto se hace un bucle infinito.
Nota: hay varias maneras de hacer un bucle infinito, pero esta es obvia, note que los
paréntesis verdes encierran justo el bloque que se repetirá infinitamente.

} Paréntesis que cierra el ciclo del while (1)

Nota: Las sentencias que inicializan ciclos no llevan punto y coma (;) al final de la
línea.

delay_ms(500); Sentencia de retardo o paralización de la corrida del programa por


500 milisegundos (0.5 segundos)
Nota: Recuerde que esto (un delay exacto) se cumple cuando la frecuencia del cristal
resonador instalado en el circuito es la misma que está puesta en el encabezado del
programa, si la velocidad del cristal es el doble que la puesta en el encabezado entonces
los segundos duran la mitad de lo que espera.

Programa ejemplo 3. Alternancia entre dos leds

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)

void main () {
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
while (1) {
output_b(0b00000010);
delay_ms(500);
output_b(0b00000001);
delay_ms(500);
}
}

El programa nro. 3 es igual al programa nro 2, con la variante que este, en vez de apagar
y encender el mismo led, cuando apaga pin_b0, enciende pin_b1 y cuando enciende
pin_b0, apaga pin_b1, y así se mantiene.

244
Nota: Recuerde que la sentencia output_b(0bXXXXXXXX); envía señales de voltaje
al puerto B, y que donde X vale 0, la señal es 0volt. , y donde la señal es 1, la señal vale
5volt.

Programa ejemplo 4 encendido y apagado de todo el puerto.


#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)

void main () {
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
while (1) {
output_b(0b00000000);
delay_ms(500);
output_b(0b11111111);
delay_ms(500);
}
}

Programa ejemplo 5.1 El efecto desplazamiento.


#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
void main () {
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
while (1) {
output_b(0b00000001);delay_ms(300);
output_b(0b00000010);delay_ms(300);
output_b(0b00000100);delay_ms(300);
output_b(0b00001000);delay_ms(300);
output_b(0b00010000);delay_ms(300);
output_b(0b00100000);delay_ms(300);
output_b(0b01000000);delay_ms(300);
output_b(0b10000000);delay_ms(300);
}}
Este programa es una corrida de luces utilizando los leds conectados al puerto B, es
simple, cada salida por el puerto B enciende un led por 300 milisegundos (luz) y apaga
las demás.
Nota:En una misma línea se puede colocar varias sentencias separadas por ;
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
void main () {
int a; a=0;
set_tris_a(0b11111);
set_tris_b(0b00000000);

245
output_a(0b00000);
if (input(pin_a0)) a=1;
while (a==1) {
output_b(0b00000001);delay_ms(300);
output_b(0b00000010);delay_ms(300);
output_b(0b00000100);delay_ms(300);
output_b(0b00001000);delay_ms(300);
output_b(0b00010000);delay_ms(300);
output_b(0b00100000);delay_ms(300);
output_b(0b01000000);delay_ms(300);
output_b(0b10000000);delay_ms(300);
a=0; } } // Programa igual al anterior, pero hace la misma corrida al presionar un
pulsador conectado al pin_a0
Programa ejemplo 5.2 El efecto desplazamiento usando un ciclo infinito y una fórmula
matemática para recrearlo.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int va,vb;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);
va=0;
while (1) {
va=va+1;
if (va==8) va=0;
vb=pow(2,va);
output_b(vb);
delay_ms(300);
}
}

El programa 5.2 hace exactamente lo mismo que el programa 5.1, pero utilizando otro
camino:

1ro. Tiene que saber que la función POW(X,Y) es la función potencia, que es igual a
decir X elevada a la pontencia Y . vb=pow(2,va);
Y
X
2do. Que para poder usar cualquier función matemática, es necesario incluir la librería
de funciones matemáticas dentro del programa.
#include <math.h>

246
3ro. Que toda variable que se use Adentro del programa, se debe declarar antes de
usarla. int va,vb;

Explicación.

#include <math.h> Es la inclusión de la librería de funciones matemáticas en el


programa, para poder realizar mucho más que las operaciones básicas. (+ - * /)

Int va,vb; Declaración de las variables va y vb como variables enteras (números sin
dcimales), ya que no necesito decimales para hacer esa tarea.

va=0; Inicialización de la variable va con valor 0 . Nota: las variables pueden tener
cualquier nombre excepto las palabras reservadas por PIC C.

va=va+1; Incrementación de la variable va en una unidad.

Nota: En el lenguaje C existen dos símbolos con significado diferente.


= este es un igual para asignar valores, o para igualar el valor de la derecha del signo
al que está a la izquierda del signo a=8;

= = (dos iguales seguidos) esto es un igual de comparación, es para evaluar una


condición, if (x==8){ } quiere decir si x es igual a 8 entonces haga todo lo que está
entre las llaves

If(va==8) va=0; si el valor de va es igual a 8, entonces haga va=0, :


Sucede que el mayor valor que puedo representar en el puerto B con un solo bit (un
solo led) es el 128, y este es 2 elevado a la 7.
7
2
Por eso es que en la línea if (va==8) va=0; se hace que cuando va llegue a 8, lo
devuelvan a 0.

vb= pow(2,va);
Tenga en cuenta que los valores que se pueden representar con un solo bit o que
enciende un solo led son los siguientes:
1 = 2^0, 2 = 2^1, 4 =2^2, 8 =2^3, 16 =2 ^4 32 =2^5, 64 =2^6 y -- 128 = 2^7,
(para un puerto de 8 bits), por eso es que se aplica la fórmula de la potencia de 2
elevado a la va === > vb= pow(2,va);

Cuando se quiere enviar un número a cualquier puerto, siempre se le tiene que decir en
que código se le va a presentar para que este lo sepa, pero cuando el valor está en
código decimal no hace falta decírselo, si se le envía un valor sin decirle el formato 0b
para código binario, o 0h para código hexadecimal, etc, solo cuando la cantidad es en
números decimales (normales 25, 33, 121,etc) PIC C lo asume que ese valor está en
decimal, claro está que en el puerto de salida no hay sino una sola forma de
representarlo con sus pines (sólo en código binario).
output_b(vb); coloque en el puerto_B, el valor de vb que fue calculado con la fórmula
de la potencia vb=2^va;

247
---------------------------------------------------------------------------------------------------------

Programa ejemplo 6.1 Efecto ida y vuelta (No necesita explicación) Una corrida ida y
vuelta de la luz, indefinidamente.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)

void main () {
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
while (1) {
output_b(0b00000001); delay_ms(300);
output_b(0b00000010); delay_ms(300);
output_b(0b00000100); delay_ms(300);
output_b(0b00001000); delay_ms(300);
output_b(0b00010000); delay_ms(300);
output_b(0b00100000); delay_ms(300);
output_b(0b01000000); delay_ms(300);
output_b(0b10000000); delay_ms(300);
output_b(0b01000000); delay_ms(300);
output_b(0b00100000); delay_ms(300);
output_b(0b00010000); delay_ms(300);
output_b(0b00001000); delay_ms(300);
output_b(0b00000100); delay_ms(300);
output_b(0b00000010); delay_ms(300);
output_b(0b00000001); delay_ms(300);
output_b(0b00000000); delay_ms(300); } }

En este programa se colocó en cada línea dentro del ciclo infinito el led que debe
encender y su retardo (permanencia encendido), para que se observe con una mirada
descendente y ascendente el efecto del programa.

Programa ejemplo 6.2 Efecto ida y vuelta usando contadores o bucles de ciclo con un
número determinado de iteraciones.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int va,vb;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);

248
va=0;
while (1) {
for (va=0;va<=8;va=va+1) {
vb=pow(2,va);
output_b(vb);
delay_ms(300); }

for (va=7;va<=0;va=va-1) {
vb=pow(2,va);
output_b(vb);
delay_ms(300); }
}}
En este programa solo tengo que explicar el bucle con contador for( ; ;)
Existe una forma de controlar exactamente la cantidad de ciclos que hace un bucle, esto
se puede hacer con el comando:
for(i=0;i<=100;1=i+1){ }; Para hacer que la variable i se incremente desde 0 hasta 100
y todo lo que está adentro de las llaves se ejecutará 100veces, claro está que si dentro de
las llaves está la variable i, está valdrá un valor diferente en cada ciclo, es decir valdrá
una unidad de incremento por cada ciclo hasta que llegue a 100 que es el final del ciclo.

Lo mismo aplica para for(i=100;i>=0;i=i-1) { } pero en este caso i comienza el ciclo


valiendo 100 y termina valiendo 0. (decreciente).
Nota: Si usamos este contador sin parámetros for( ; ; ) lo hacemos infinito.
Programa ejemplo 7. El efecto dominó

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int va,vb,vc;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);
va=0; vc=0;
while (1) {
output_b(0b00000000);
for (va=0;va<=8;va=va+1) {
vb=pow(2,va);
vc=vc+vb;
output_b(vc);
delay_ms(300); }
for (va=7;va<=0;va=va-1) {
vb=pow(2,va);
vc=vc-vb; // Nota: En los paréntesis, es importante entender//
output_b(vc); // que ellos deben encerrar solo su bloque //
delay_ms(300); } } }

249
El efecto dominó consiste en imponer una condición a un solo elemento de un grupo,
luego este elemento le pasa la condición a un segundo elemento sin perder esa
condición, el segundo a un tercero hasta que se acaban los elementos.
En este caso, la condición la impone el programador y los elementos son los leds, y
consiste en ir encendiendo esos leds conectados el puerto B, uno a uno hasta que todos
queden encendidos y luego apagarlos de la misma forma, para este caso la situación está
en conseguir una función que vaya sumando los valores que se presentan en el puerto
B.
La idea consiste en conseguir el valor que enciende el primer led, y envíarlo al puerto B,
luego el valor que enciende el segundo led, sumarlo con el primer valor (el que
encendió el primer led) y esta suma enviársela al puerto B, y así hasta el último led,
esta fórmula es
Vb= 2 elevado a la Va (Vb = 2^Va) con Va tomando valores entre 0 y 7 incluidos.
Vc = Vc + Vb : a Vc le mantenemos su valor (Vc) y le sumamos en actual de Vb

Programa ejemplo 8.1 El efecto rebote sin perdida de energía

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int va,vb,t;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);
va=0; t=0;
while (1) {
output_b(0b00000000);
for (va=0;va<=8;va=va+1) {
vb=pow(2,va);
output_b(vb);
t=(va+1)*50;
delay_ms(t); }
for (va=8;va<=0;va=va-1) {
vb=pow(2,va);
output_b(vb);
t=(va+1)*50;
delay_ms(t); }
} }

250
El efecto rebote sin pérdida de energía consiste en producir el movimiento de una luz,
con la condición de que: cada vez el tiempo de encendido de cada led dure menos que el
anterior, produciendo una simulación parecida a una caída libre que aumenta su
velocidad hasta chocar con el piso, y rebotando disminuyendo su velocidad en el
ascenso, hasta detenerse (Esto se repetirá indefinidamente debido a que la altura del
rebote será la altura de la caída original, es decir con 100% de recuperación en el
rebote)

Programa ejemplo 8.2 El efecto rebote con perdida de energía.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int va,vb,t,n;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);
va=0; t=0;
while (1) {
output_b(0b00000000);
for (n=8;n<=0; n=n-1) {
for (va=0;va<=n;va=va+1) {
vb=pow(2,va);
output_b(vb);
t=(va+1)*50;
delay_ms(t); }
for (va=n;va<=0;va=va-1) {
vb=pow(2,va);
output_b(vb);
t=(va+1)*50;
delay_ms(t); }}}}
El programa 8.2 es el mismo programa 8.1, pero reduciendo el margen de cada ciclo
interno de los contadores rojo y azul con en el contador verde, debido a que, el mayor
de cada ciclo interno comienza en el valor asignado por el más externo (verde)

For (x=10; x>=0; x=x-1) {


For (y=0; y<=x; y=y+1) { }
For(z=x; z >=0; z=z-1) { } }

Nota: He alineado en orientación vertical y coloreado las llaves didácticamente, estas no


necesitan estar alineadas ni coloreadas.

251
Programa ejemplo 8.3 Efecto dominó con efecto rebote.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int va,vb,vc;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);
va=0; vc=0;
while (1) {
output_b(0b00000000);
for (va=0;va<=8;va=va+1) {
vb=pow(2,va);
vc=vc+vb;
output_b(vc);
delay_ms(75*va); }

for (va=7;va<=0;va=va-1) {
vb=pow(2,va);
vc=vc-vb;
output_b(vc);
delay_ms(75*va); } } }

Este programa es la combinación de los efectos ya explicados, simplemente al efecto


dominó se le puso un tiempo de retrazo variable aprovechando que cambia su valor en
cada iteración.

252
Programa ejemplo 9. El contador binario

Este programa es tan sencillo, que debió ser , sino el primero, el segundo.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);

while (1) {
for (x=0; x<=255; x=x+1) {
output_b(x);
delay_ms(500);
output_b(0);
delay_ms(200); }}}

El programa anterior envía al puerto B el valor del conteo de la variable x, lo retiene por
500 milisegundos, luego apaga el puerto por 200 milisegundos y presenta el siguiente
valor, observe que es un contador en código binario, así que cuando observe que hay un
solo led encendido ese valor es automáticamente una potencia exacta de dos 2^x.

253
Para los siguientes programas haga el siguiente montaje, el display 7segmentos es de
cátodo común.

Programa ejemplo 10. Manejo de un display 7segmentos.

Explicación antes del programa:

Ahora en el diagrama del montaje del PIC16F84A y el display se pueden observar las
conexiones entre ambos, y que la correspondencia es
A=> 1, B=>2, C=>4, D=>8, E=>16, F=>32 y G=>64.

254
De esta manera para calcular escribir los números del 0 al 9 los calculo así.

Naturalmente, si por el puerto B enviamos el número 0, no encenderá ninguno de los


segmentos.

Programa ejemplo 10.1 Una corrida de los números desde el 0 hasta el 9. y las letras
A, C, E y F.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_a(0b00000);
output_b(0b00000000);

while (1) {
delay_ms(2000);
output_b(0); delay_ms(500);
output_b(63); delay_ms(500);
output_b(6); delay_ms(500);
output_b(91); delay_ms(500);
output_b(79); delay_ms(500);
output_b(102); delay_ms(500);
output_b(109); delay_ms(500);

255
output_b(124); delay_ms(500);
output_b(7); delay_ms(500);
output_b(127); delay_ms(500);
output_b(103); delay_ms(500);
output_b(119); delay_ms(500);
output_b(57); delay_ms(500);
output_b(121); delay_ms(500);
output_b(113); delay_ms(500);
}}

En este programa se hace una presentación en un display 7segmentos, con un retardo de


0.5 segundos.

Nota: También pudieramos realizar la misma tarea enviando al pueto B las señales en
código binario. Por ejemplo para encender el número 1 envíamos
output_b(0b00000110) que es igual a output_b(6) ya que 6=0b00000110
Programa ejemplo 10.1 Una corrida de números desde el 0 hasta el 9 usando el
decodificador de binario a 7segmentos SN74LS49

Nota: Los circuitos integrados TTL 7446, 7447, 7448, 7449 tienen la misma función y
lógica, todos son para decodificar cantidades decimales pasándolas de código binario a
decimal 7segmentos, pero tienen variantes en cuanto a la activación de la salida, si es
cátodo común o ánodo común, en este ejemplo emplearé el SN74LS49 porque
sinceramente es el más sencillo de aplicar y además es para trabajar con displays de
cátodo común, lo que quiere decir que enviará señales positivas por sus pines de salida,
y como el display que voy a usar es cátodo común entonces se complementan como
equipo sin necesidad de hacer ningún ajuste.

Haga el siguiente montaje, para el programa ejemplo 10.2

Explicación.

256
El programa 10.2 hace exactamente lo mismo que el programa 10.1, sin embargo es
mucho más corto, esto se debe a que toda la conversión necesaria para presentar los
números que en el programa 10.1 la hacíamos con código, pero en el programa 10.2 la
hace el decodificador SN74LS49, nos ahorramos trabajo; pero tiene su costo.

Programa ejemplo 10.3 Contador de dos digitos.

Circuito para el programa 10.3

Para el programa 11, es necesario una explicación del funcionamiento del circuito
integrado TTL SN74LS574, es un FLIP-FLOP tipo D y funciona de la siguiente
manera.

257
Los circuitos integrados TTL FLIP-FLOP tipo D trabajan todos con la misma función y
lógica, (SN74LS374, 7474, 74174, 74574, etc) en los pines nombrados con la letra D
(son las entradas) se coloca una información, por ejemplo los pines pares en nivel bajo
y los pines impares en nivel alto, (01010101), en los pines que tienen la letra Q no hay
información (00000000), todos están en nivel bajo, pero cuando se le da un pulso
eléctrico en el PIN_CP, se copia (o se pasa) la data que está en los pines de las entradas
(D) a los pines de salidas (Q), y esta data permanece ahí mientras esté alimentado el
circuito FLIP-FLOP indefinidamente e independientemente de que cambie la data en las
entradas, hasta que haya otro pulso en el PIN_CP lo que vuelve a copiar la data que está
en las entradas D a las salidas Q.

Ahora, valiéndonos de esta propiedad, vamos a diseñar un circuito digital y el programa


para construir un cronómetro de 8 dígitos, para ello vamos a usar los siguientes
circuitos, (para realizar la práctica no necesita tener 8 circuitos 74574 y 8 displays, con
que tenga tres ya cumple con la lógica y la idea de esta tarea)

1 PIC17F84A
1 SN74LS49
8 SN74LS574
8 Displays 7segmentos

258
El circuito arriba es el circuito para construir el cronómetro de 8 dígitos, la idea de este
circuito es:

1ro. El número que voy a enviar hasta 8 cifras lo convierto en dígitos separados con
alguna técnica numérica o fórmula matemática

2do. Por el puerto A envío los datos correspondientes a cada uno de los dígitos desde
el 1ro hasta el 8vo. (uno por uno) al decodificador.

3do. Con el decodificador de binario a decimal 7segmentos SN74LS49 lo convierto de


formato binario que es como lo entrega el microcontrolador a formato para display
7segmentos que ese es su trabajo.

4to. Tomo esa decodificación que viene del SN74LS49 y la pongo en el bus de datos
(son las líneas negras) que los lleva a todos los FLIP-FLOP tipo D, los que me servirán
como memoria para retenerlo y pasarlo a un display

5t0. Cada vez que el microcontrolador me envíe un dato, éste pasa de forma automática
al decodificador, y del decodificador al bus de datos, una vez que está en el bus de datos
y sabiendo a cual digito pertenece, con el puerto B doy un pulso en el PIN_CP de ese
FLIP-FLOP tipo D y el dato se presenta en el display correspondiente.

Y así funciona: Imagínese la situación:

1.1 El número que se ha generado por el conteo es el 12345678.

1.2 El programa descompone el número en 1, 2, 3, 4, 5, 6, 7 y 8 (8 dígitos)

1.3 El programa toma el número 1 y lo envía por el puerto A en binario.

1.4 El puerto A está conectado a la entrada del decodificador SN74LS49.

1.5 El decodificador toma ese valor y lo convierte en código 7segmentos y los pone en
el bus de entrada de los ocho FLIP-FLOP tipo D.

1.6 Ahora el microcontrolador manda un pulso por su PIN_B0. (1er dígito)

1.7 El FLIP-FLOP número 1 al recibir ese pulso carga ese valor y lo muestra en el
display. (Se repite todo pero esta vez el pulso es para FF 2)

2.3 El programa toma el número 2 y lo envía por el puerto A (Igual a 1.3).


2.4 (igual a 1.4)
2.5 (igual a 1.5)
2.6
2.7
3.3
3.4 . . . . . hasta 3.7 y regresa a 1.1 para el siguiente número generado.

259
Sepa que esta tarea la hace el microcontrolador cientos de veces en un segundo, por eso
no notamos la secuencia y nos parece instantanea.

Nota: Se le llama bus a un grupo de líneas o conductores (cablecitos) que trabajan


juntos transportando entre todos un dato compuesto por varios bits, en nuestro caso el
dato es de 7 bits (7 cablecitos) para los FLIP-FLOPs.

Circuito completo del cronómetro. Observe como se repite los FLIP-FLOP y los
displays, ( por lo menos trate de montar 3 conjuntos flip-flop display)

260
Programa del contador de 8 digitos

1 #include <16f84a.h>
2 #fuses hs,nowdt,noprotect,put
3 #use delay (clock=8000000)
4 #include <math.h>
5
6 void main () {
7 int16 x,z;
8 int a[9];
9 int i;
10 float y;
11 set_tris_a(0b00000);
12 set_tris_b(0b00000000);
13 output_a(0b00000);
14 output_b(0b00000000);
15 x=0;
16 while (1) {
17 x=x+1;
18 y= x/10000;
19 y=floor(y);
20 z=x-10000*y;
21
22 a[1]=floor(y/1000);
23 a[2]=floor((y-1000*a[1])/100);
24 a[3]=floor((y-1000*a[1]-100*a[2])/10);
25 a[4]=y-1000*a[1]-100*a[2]-10*a[3];
26
27 a[5]=floor(z/1000);
28 a[6]=floor((z-1000*a[5])/100);
29 a[7]=floor((z-1000*a[5]-100*a[6])/10);
30 a[8]=z-1000*a[5]-100*a[6]-10*a[7];
31
32 for (i=1;i<=8;i=i+1) {
33 output_a(a[i]);
34 output_b(pow(2,(i-1)));
35 output_b(0); }}}

Las líneas se numeraron para facilitar la explicación

261
Explicación.
Línea 7: int16 x,z; Declaración de las variables x y z como variables que tomaran
valores mayores a 255 pero menores a 65536 .

Línea 8: int a[9]; Definición de un arreglo de variables que van desde a[0] hasta a[8] :
Todas serán variables enteras sin decimales y compondrán los dígitos independientes
que se presentarán en los displays

Línea 9: int i; Definición de una variable entera i (va a ser usada como contador)

Línea 10: float y; Definición de una variable con decimales, porque su valor depende
de una división inexacta.

Ahora: Como se convierte un número de cuatro cifras en dígitos independientes.

Ejemplo: Como convertir el numero 8643 en dígitos separados.


Nota: La parte entera de un número es el valor del mismo número sin decimales, y se
denota con corchetes.
Parte entera de 3.1415 = 3 ó [3.1415] = 3
X= 9743 como convertirlo en los dígitos separados 9, 7, 4, 3

A = [9743/1000] = [9.743] = 9

B= [ (9743-A*1000) / 100 ]
B= [ (9743-9*1000) / 100 ] = [ (9743-9000) / 100 ] = [ (743) / 100 ] =

[ (743) / 100 ] = [7.43] = 7

C= [ (9743 – A*1000 –B*100)/10]


C= [(9743-9000-700)/10] = [ 43/10 ] = [4.3] = 4

D = 9743 – A*1000 – B*100 – C*10 = 9743 – 9000 – 700 – 40 = 3

A=9, B=7, C=4, D=3.


Este es el proceso que se usó para convertir el número del contador x de 8 cifras en 8
dígitos, primero se separó en dos números de 4 cifras y luego cada uno en dígitos.
Nota: En PIC C la función parte entera es FLOOR(3.14) = 3
Nota: No confundir a[x] que es una variable de un grupo de variables con sub-indice,
con la función parte entera: Una es la notación de PIC C y la otra es la notación de la
matemática tradicional de clase en pizarrón.

En las líneas 18, 19 y 20 se convierte el número x de 8 cifras en y de 4 cifras y z de 4


cifras.
Nota: El valor de x no siempre será de 8 cifras, pero como el valor de x, se va
incrementando, a partir de un momento se convertirá de 8 cifras, así que de entrada se
trabajará como si siempre fuera de 8 cifras, y al leer los displays descartamos los ceros
(0) a la izquierda. Así tenemos y de 4 cifras y z de 4 cifras.
En las líneas 22, 23, 24 y 25, se convierte el valor de x en cuatro dígitos
A, B, C, D
En las líneas 27, 28, 29 y 30, se convierte el valor de x en cuatro dígitos

262
E, F, G, H
En las líneas 32, 33, 34 y 35 se envían los dígitos uno por uno y se ponen en los FLIP-
FLOP y por ende en los displays

i es el contador.

a[ i ] es el grupo de variables con sub-indice i que contiene los dígitos a presentar a[1],
a[2]….a [8]

Línea 33: output_a( a[i] ); pone en el puerto A el valor del digito a[i], el cual pasa
directamente a la entrada del decodificador SN74LS574, y de la salida de este
decodificador a los FLIP-FLOP

Nota de la línea 34: POW(2,(i-1)) =

Por qué se usa (i-1), porque los exponentes tienen que ir desde 0 hasta 7, pero los sub-
indices van desde 1 hasta 8, entonces:
exponente = sub-indice -1.

Recuerde que i se cuenta desde 1 hasta 8


Output_b(2,(i-1)) es 2^0=1 => 1er digito del puerto B, PIN_B0
2^1=2 => 2do digito del puerto B, PIN_B1
2^2=4 => 3do digito del puerto B, PIN_B2
2^3=8 => 4to digito del puerto B, PIN_B3
2^4=16 => 5to digito del puerto B, PIN_B4
2^5=32 => 6to digito del puerto B, PIN_B5
2^6=64 => 7do digito del puerto B, PIN_B6
2^7=128 =>8do digito del puerto B, PIN_B7
Nota: El programa y circuito anterior con mínimas modificaciones los vamos a utilizar
como un cronómetro o como contador de eventos externos.
El IC TTL SN74LS154:

El circuito integrado 74154 es un decodificador de binario a posición decimal, es lo que


se llama un selector, por su entrada se le introduce un número en código binario, y este
responde activando una salida que corresponda con el valor que se le introduce.
Este circuito tiene 4 entradas para valores en código binario y 16 salidas, de las que se
activa solo la que corresponde con el valor binario de la entrada.

263
Ejemplo: A B C

Verde entradas en nivel alto, violeta salida.


En el ejemplo A, la entrada es 0b1110, que en decimal es 14, la salida activada es la
número 14.
En el ejemplo B, la entrada es 0001, que en decimal es 1, la salida activada es la
número1.
En el ejemplo C, la entrada es 0110, que en decimal es 6, la salida activada es la 6.
Nota: En este IC TTL 74154, la salida activada se pone en voltaje bajo (0volt) todas las
demás salidas permanecen en voltaje alto hasta que se cambie el valor en la entrada.
Ahora: diseñe un circuito para hacer un contador con 15 dígitos usando los
componentes que ya conoce incluyendo el 74154.

El Par Darlington:

El par Darlington o transistor darlington es un dispositivo que nos permite controlar un


voltaje relativamente alto y cierta cantidad de corriente con la salida de los pines de un
microcontrolador, esto es muy útil para los casos en los que necesitamos encender
motores dc de hasta 12 voltios, activar reles, etc.

Afortunadamente estos transistores vienen incorporados en circuitos integrados y lo


único que tenemos que hacer es conectar la salida del microcontrolador a la entrada del
IC (par darlington) y tomar en la salida de este los 12 voltios que necesitamos para la
aplicación.

También están los integrados ULN28xxx, que son muy parecidos pero con un par
darlington más.

264
Nota: Estos circuitos tienen salida negativa , lo que quiere decir que cuando se aplica
una entrada, se activa su salida en voltaje negativo, el positivo de la alimentación
también es positivo común para todas las salidas.

Desde aquí en adelante vamos a interferir en el funcionamiento de los programas, así


que consígase unos pulsadores, de lo contrario va a tener que simularlos con cables.

Generalmente los programas no funcionan tan solos, en muchos casos necesitan de un


pulso de arranque, un pulso de parada, etc.

Programa ejemplo 11. Haga un programa que informe cual o cuales botones tiene
presionados como entrada el microcontrolador.

Programa ejemplo 11.1


#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
void main () {
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
while (1) {
if (input(pin_a0)) output_high(pin_b0); else output_low(pin_b0);
if (input(pin_a1)) output_high(pin_b1); else output_low(pin_b1);
if (input(pin_a2)) output_high(pin_b2); else output_low(pin_b2);
if (input(pin_a3)) output_high(pin_b3); else output_low(pin_b3);
if (input(pin_a4)) output_high(pin_b4); else output_low(pin_b4);
}}
------------------------------------------------------------------------------
Programa ejemplo 11.2
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>

void main () {
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);

265
while (1) {
x=input_a();
output_b(x);
}}

Explicación.

Como quiera que sea, solo hay dos formas de introducir datos en un programa mientras
este se está en ejecutando.

1ro. Presionando botones que estén conectados a los pines de entrada.


2do. Enviando la información por un puerto serial.

Ahora, cuando introducimos datos presionando botones tenemos dos alternativas.

1ro. Que el programa determine botón por botón cuales están presionados y cuales no lo
están.
2do. Que el programa lea el puerto de entrada todo de una sola vez y determine que
valor está puesto en el según los estados de las entradas conectadas.
3ro. Que el programa haga las dos tareas 1ro y 2do simultáneamente, todo depende de
lo que tenga en mente el diseñador digital y el programador del sistema que
generalmente son la misma persona.

Existen varias formas de leer las entradas por los pines.

1ro. x=input(pin_a0); De esta manera x tendrá el valor de la entrada del pin_a0 y el


programa tomará este valor para trabajar.

Nota importante: Cuando los pines se configuran como entradas, si no están conectados
a alguna de las dos alimentaciones (positiva o negativa) mediante una resistencia de
protección (yo uso 100k y funciona) están en cierto grado indeterminadas de: a que
señal deben obedecer (+ o -), así que hay que hacer una cierta discriminación en cuanto
a las entradas (positivas o negativas en cuanto al software) y la conexión eléctrica que
se les debe hacer (en cuanto a hardware).
Entonces tenemos realmente para las entradas de pines independientes dos tipos.

Tipo a) X= ( !input(pin_a0)); para entradas positivas.


Tipo b) X=( input(pin_a0)); para entradas negativas.

Observe que la diferencia es solamente el símbolo ! que indica una negación, así que
lo único que hay que hacer es lo siguiente, cuando usamos la entrada para un pin
solitario tipo a, conectamos ese pin a positivo mediante una resistencia de 100k, y si es
tipo b la conectamos a negativo igualito. (ver diagrama)
Ver diagrama explicativo.

266
Tipo a Tipo b

Por otra parte cuando se desea leer todo el puerto de una sola vez, entonces es
recomendable que se conecten todas las entradas a negativo con una resistencia alta
(r>10k ohm) al negativo de la alimentación del Microcontr.

X= input_a(); Asigna a X el valor leido en el puerto A


X= input_b(); Asigna a X el valor leido en el puerto B
X= input_c(); Asigna a X el valor leido en el puerto C
X= input_d(); Asigna a X el valor leido en el puerto D
X= input_e(); Asigna a X el valor leido en el puerto E

En el programa 11.1 sólo con explicar una línea se entiende todo lo demás.

if (input(pin_a0)) output_high(pin_b0); else output_low(pin_b0);

If(input(pin_a0)) Se traduce “si se tiene presionado el pulsador conectado a pin_a0”

output_high(pin_b0); Ponga el pin_b0 en alto “si se cumple esa condición”

else output_low(pin_b0); Ponga el pin_b0 en bajo “si no se cumple esa condición”

---------------------------------------------------------------------------------------------------

En el programa 11.2 lo único que se hace es leer todo el puerto A de una sola vez y
poner el valor leído como salida en el puerto B.

x=input_a();
output_b(x);

x=input_a(); Le asigna a x el valor leído en el puerto A.

output_b(x): Saca por el puerto B, el valor de x que fue leído del puerto A.

Circuito recomendado para los programas 11.1 y 11.2

267
EL MOTOR PASO A PASO UNIPOLAR

Lo primero que hay que explicar (para el que no lo sabe) es: ¿Que és un motor paso a
paso?.

Para no entrar en detalles electrónicos, un motor paso a paso es un motor cuyo eje gira
de forma gradual, y el que lo controla no sólo puede controlar la velocidad de giro y el
sentido del giro, sino también el ángulo que va a girar y detenerse con alta precisión.

Como se logra que el motor paso a paso haga lo que uno quiere.
1ro.) Un motor paso a paso unipolar tiene 5 o 6 cables para su alimentación.
2do.) Esos cables corresponden a 4 bobinas, y se organizas de la siguiente manera.

De esta manera tengo un motor con 5 cables, uno de los cables lleva alimentación fija,
los otros 4 cables se alimentan alternadamente 1 a la vez y así al ir rotando la
alimentación en esos 4 cables el motor gira en un sentido, y si cambio el sentido de la
rotación de la alimentación de los 4 cables el motor gira en el otro sentido.

La velocidad del motor depende de la velocidad con la que alterne la alimentación de


las diferentes bobinas.

268
Nota: Cuando se alimenta solo una bobina del motor paso a paso, el rotor del motor se
orienta hacia donde está la bobina energizada y ahí se queda estático, hasta que se
alimenta la bobina que sigue, entonces el rotor se orienta hacia es bobina (gira 1.8
grados), ese movimiento de estar parado hacia una bobina y luego pasar a estar
orientado a la siguiente y detenerse es lo que se llama un paso.
Ahora: ¿Cuanto es el giro de una paso?: Eso depende del motor, pero los conozco de
1.8º, lo que quiere decir que una vuelta entera son 200 pasos.
Programa ejemplo 12. Control de un motor paso a paso

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>
void main () {
int x,y,z,a;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
while (1) {
if (input(pin_a1)) a=1;
if (input(pin_a2)) a=2;
if (input(pin_a3)) a=3;
if (input(pin_a4)) a=4;
while (a==1){
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200);}}
while (a==2){
for (x=3;x<=0;x=x-1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200);}}
while (a==3){
for (z=0;z<=50;z=z+1){
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200);}}
for (z=0;z<=50;z=z+1){
for (x=3;x<=0;x=x-1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200);}}}
while (a==4){
for (z=0;z<=50;z=z+1){

269
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(1000);
if (input(pin_a0)) a=0; }}}}}

Programa 12 coloreado para explicarlo

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>
void main () {
int x,y,z,a;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
while (1) {
if (input(pin_a1)) a=1;
if (input(pin_a2)) a=2;
if (input(pin_a3)) a=3;
if (input(pin_a4)) a=4;
while (a==1) {
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200); }}
while (a==2) {
for (x=3;x<=0;x=x-1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200); }}
while (a==3) {
for (z=0;z<=50;z=z+1) {
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200); }}
for (z=0;z<=50;z=z+1) {
for (x=3;x<=0;x=x-1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200); } } }
while (a==4) {
for (z=0;z<=50;z=z+1) {

270
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(1000);
if (input(pin_a0)) a=0; }}} } }

La manera como organicé el programa 12, le parecerá un carnaval y un desorden, pero


nada más lejos de la verdad, lo organicé así para que pueda apreciar los distintos
bloques (un bloque definido por cada color), donde abre y cierra cada llave, cada una
con su correspondiente, cada una está más o menos alineada verticalmente con su
correspondiente y poseen el mismo color.

Explicación:
El primer bloque Azul oscuro.
Este es el encabezamiento, en donde se especifica el microcontrolador, las directivas del
tipo de oscilador, protección del código, estabilización, velocidad del cristal oscilador, y
la inclusión de la librería <math.h> que la necesitamos para hacer el cálculo de la
potencia 2^x, que la necesitamos calcular para dar la salida alta de un solo pin en el
puerto B.

El segundo bloque Negro.


Este es el bloque de inicialización del programa, se declaran las variables a usar x,y,z,a,
se configuran los puertos, A como puerto de entrada y B como puerto de salida, además
se ordena apagar todo el puerto B. (no hace falta, pero se hace por seguridad).

El tercer bloque Marrón Claro


Se inicializa el bucle infinito, while (1) { y se colocan las líneas de comando de lectura
de los pines a1, a2, a3 y a4.
if (input(pin_a1)) a=1;

Nota: No confunda pin_a1 con a=1, a es una variable declarada e igualada a 1 y


pin_a1 es el segundo pin del puerto A.

Como se interpreta la línea de comando en español hablado.

SI SE PRESIONA EL PULSADOR QUE ESTÁ CONECTADO AL PIN_A1,


ENTONCES SE LE ASIGNA A LA VARIABLE a EL VALOR DE 1.

Esas cuatro líneas marrones están dedicadas para que cuando se presione alguno de los
pulsadores conectados al puerto A, le asigne a la variable a un valor distinto (un valor
para cada pulsador), pin_a0 no está asignado en ese bloque, porque se usará para salir
de la sub-rutina al asignarle a la variable a el valor de 0. Para que salga de los bloques y
regrese al cuerpo principal presionar pin_a0.

271
Cuarto bloque Rojo
Cuando se presiona el pulsador pin_a1, a la variable a se le asigna el valor de 1, y esta
es la condición necesaria para que el programa corra dentro de este bloque rojo, y ahí se
mantendrá hasta que se le cambie el valor a la variable a, ¿Cómo se le cambia el valor a
a estando en el bloque rojo, presionando el pin_a0, al presionar el pin_a0 se le vuelve a
asignar a la variable a el valor 0 y al no cumplirse esa condición de a=1 el programa se
sale del bloque rojo.

while (a==1) {
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200); }}

for (x=0;x<=3;x=x+1)
Ahora, el contador x se mueve desde 0 a 3, porque al elevar 2^0 =1, 2^1=2, 2^2=4 y
2^3=8, y estos son los valores que se sacan por el puerto B que me ponen uno y solo un
pin en alto en el puerto, y este pin está conectado integrado ULN2803 que da la
potencia para mover el motor paso a paso.

Además, este bloque cumple con una rutina que solo pone en el puerto los valores 1, 2,
3, 4, 1, 2, 3, 4…. Para hacer girar el motor paso a paso hasta que se presione el pulsador
pin_a0 y saque al programa de ese bucle.

La fórmula y=pow(2,x) es la evaluación de la potencia de 2 entre 0 y 3.

delay_ms(200) es porque el motor necesita un tiempo de retardo para mover su rotor


hasta la bobina energizada.

if (input(pin_a0)) a=0; Es el comando que está esperando a que se presione el pin_a0


para cambiarle el valor a a y salirse del bucle.

output_b(y); Es el comando de salida del valor de y por el puerto B.

El bloque Azul Claro

A este bucle se entra presionando el pulsador del pin_a2 que hace a a=2.
El bloque azul claro, hace exactamente lo mismo que el bloque rojo, pero pone a girar el
motor en sentido contrario, porque su contador cuenta en regresivo, 3, 2, 1, 0, 3 ,2, 1, 0

while (a==2) {
for (x=3;x>=0;x=x-1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200); }}

272
for (x=3;x<=0;x=x-1) El contador va en regresivo desde 3 hasta 0

todo lo demás funciona igual.

Los bloques Verdes.


A estos bucles se entra presionando el pulsador pin_a3, que hace a a=3.
Como dije cuando hice la explicación del funcionamiento de los motores paso a paso,
si estos tienen un paso de 1.8º, entonces necesitan 200 pasos para dar exactamente una
vuelta, 360/1.8=200.
Ahora bien con un conteo desde 0 hasta 3 le estoy dando cuatro pulsos y el motor está
girando 4 pasos, pero necesito 200 pasos para dar la vuelta, entonces lo que hago es
repetir el ciclo entre 0 y 3 una cantidad de 50 veces, ya que 4 pasos * 50 = 200 pasos.

while (a==3) {
for (z=0;z<=50;z=z+1) {
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200); }}
for (z=0;z<=50;z=z+1) {
for (x=3;x<=0;x=x-1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(200); } } }

for (z=0;z<=50;z=z+1) {
for (x=0;x<=3;x=x+1) {

Repetir 50 veces los números desde el 0 al 3 es lo mismo que contar desde el 0 hasta el
200, para completar los 200 pasos de una vuelta entera.

El bloque está repetido salvo porque en un ciclo cuenta hacia delante y en el otros hacia
atrás para cambiar el sentido de giro del motor.

Este bucle hace que el motor de una vuelta en sentido positivo, y una vuelta en sentido
negativo, y así se mantiene hasta que se presiona el pulsador pin_a0.

El último bloque Marrón.


A este bucle se entra presionando el pulsador pin_a4, que hace a a=4.

273
Después de todo lo expuesto, bucle no necesita mayor explicación, solo que este hace
girar al motor una vuelta entera (360º) lo detiene por 1 segundo, lo hace dar otra vuelta,
lo detiene y sigue el ciclo, hasta que presiónenla pulsador del pin_a0.

while (a==4) {
for (z=0;z<=50;z=z+1) {
for (x=0;x<=3;x=x+1) {
y=pow(2,x);
output_b(y);
if (input(pin_a0)) a=0;
delay_ms(1000);
if (input(pin_a0)) a=0; }}}

delay_ms(1000); retardo de 1 segundo.

Observe la disposición de las llaves que delimitan los cuerpos principal , el bucle
infinito y los cuerpos azul, verde y marrón.

void main () {
int x,y,z,a;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0b00000000);
while (1) {
if (input(pin_a1)) a=1;
if (input(pin_a2)) a=2;
if (input(pin_a3)) a=3;
if (input(pin_a4)) a=4;
while(a==1) { { } }
while(a==2) { { } }
while (a==3) {
{{}}
{{}}
}
while (a==4) {
{{}}
{{}}
}
}
}

274
Circuito recomendado para el programa 12

Programa ejemplo 13. Un programa hecho en con diferentes cuerpos.


El siguiente programa hará una serie de conteos en diferentes secuencias y cada
secuencia estará programada en un cuerpo por fuera del cuerpo principal void main().

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>
void adelante () {
int x;
for (x=0;x<=9;x=x+1){
output_b(x);
delay_ms(1000);}}
void atras () {
int x;
for (x=9;x<=0;x=x-1){
output_b(x);
delay_ms(1000);}}
void saltop () {
int x;
for (x=0;x<=8;x=x+2){
output_b(x);
delay_ms(1000);}}
void salton () {
int x;
for (x=9;x<=1;x=x-2){
output_b(x);
delay_ms(1000);}}
void idvu () {
int x;
for (x=0;x<=9;x=x+1){
output_b(x);

275
delay_ms(1000); }
for (x=9;x<=0;x=x-1){
output_b(x);
delay_ms(1000);} }
void main () {
int x;
set_tris_a(0b11111);
set_tris_b(0b00000000);
while (1) {
if (input(pin_a0)) adelante:
if (input(pin_a1)) atras:
if (input(pin_a2)) saltop:
if (input(pin_a3)) salton:
if (input(pin_a4)) idvu:
}}

El programa anterior, está hecho 6 cuerpos:

void adelante ( ) { } Conteo hacia delante 0 ==> 9.

void atrás ( ) { } Conteo hacia atrás. 9 ==> 0

void saltop ( ) { } Conteo de 2 en 2 hacia delante.

void salton () { } Conteo de 2 en 2 hacia atrás.

void idvu () { } Conteo ida y vuelta 0=>9 y 9=>0.

void main () { } Cuerpo principal.

Lo importante en este tema de hacer un programa en cuerpos independientes, es:

1ro.) Todo cuerpo independiente se debe poner antes del cuerpo principal (void main()
{ }) en el programa, para que este, esté reconocido cuando se llegue al cuerpo principal
-que debería ser siempre el último-.

2do.) Se recomienda que todo cuerpo sea llamado desde el cuerpo principal, ya que
cuando un cuerpo A llama a otro cuerpo B, el cuerpo B debe estar en orden antes que el
cuerpo A.

3ro.) Para llamar a un cuerpo, simplemente se coloca en una línea del programa el
nombre del cuerpo seguido de cuerpo();

4to.) Para hacer un cuerpo, simplemente se coloca la palabra void, seguida del nombre
del cuerpo con los paréntesis, el uso de los paréntesis tiene que ver con el trabajo de
variables externas al cuerpo, pero, si no necesitamos usar variables externas basta con
poner los paréntesis solamente y entre llaves el código del programa de ese cuerpo.
void cuerpo() { código programa }

276
Circuito recomendado para el programa 13

Circuito para el programa ejemplo 14.

277
El programa ejemplo 14, es una adaptación del programa ejemplo 13, para un conteo
con 2 dígitos, además los pulsadores fueron cambiados a los pines B4, B5, B6, B7 Y
A4, para facilitarme y usar el programa anterior.

Nota: Si se quisiera presentar dos dígitos usando solo un puerto de 8 bits, me facilito la
parte del contador, pero necesito hacer la conversión de un número de 8 bits a dos
números de 4 bits.

Explicación: Entre los tantos códigos numéricos o sistemas de numeración que son muy
usados en electrónica digital, está el código decimal codificado en binario, conocido por
sus iniciales en ingles BCD, y consiste en que las cantidades se escriben en sistema
decimal, pero cada dígito usando código binario, por lo tanto y a pesar de que estos
números binarios se escriben con 4 bits, no llegan hasta la cantidad diez y seis que en
binario es 1111, y en decimal es 16, sino que se llega hasta nueve que en binario es
1001 y en decimal es 9.

Tabla ejemplo usando 8 bits de un puerto (se usan 4 bit por digito decimal)
BCD significa “cantidad escrita en decimal pero codificada en binario”
En decimal En binario En BCD o decimal EN BCD pero
------------ ------------ Codificado en binario unidos (lo normal)
75 01001011 0111 0101 01110101
88 01011000 1000 1000 10001000
32 00100000 0011 0010 00110010
0 00000000 0000 0000 00000000
80 01010000 1000 0000 10000000
8 00001000 0000 1000 00001000

Es obvio que la mayor cantidad que se puede representar con dos dígitos en BCD es
noventa y nueve en DECIMAL 99 y BDC 10011001.

Nota: Si bien es cierto que con un puerto de 8 bits se puede contar hasta el número 255
y con el mismo puerto pero en BCD hasta 99, también es cierto que puedo usar
cualquier otro elemento externo para extender la capacidad, como el selector 74154, el
flipflop tipo D como memoria de un byte 74574 o 74374, además tengo el
decodificador de binario a decimal 7segmentos 7449, 7448, etc.
Nota importante: En la medida que usted conozca mayor cantidad de componentes en la
electrónica digital, en esa medida resolverá rápidamente o más rápidamente una
situación lógica-digital.
-----Pregunta tonta: ¿Como se pasa de un número binario a BCD?.
-----Resp: Se pasa de binario a decimal, se separan los dígitos y cada digito se pasa a
binario. 11001 => 25 =>2 y 5 => 0010 y 0101 => 00100101.
Programa ejemplo 15. Un contador de RPS

Un contador de RPS es un dispositivo que puede contar cuantas revoluciones da un


motor por segundo y lo presenta en una pantalla.

278
El programa es realmente simple.

1ro) Configuramos el contador 0 (timer0) para que cuente eventos externos.


Setup_timer_0(rtcc_ext_l_to_h);
Enable_interrupts(int_timer0);
Enable_interrupts(global);
Nota: Aún después de haberlo configurado, el timer0 (contador 0) no comienza a contar
eventos hasta que se habilita el pin_a4 (que és el pin de entrada de pulsos del contador
timer0), y para habilitarlo se le manda una señal de voltaje alto output_high(pin_a4)
entonces queda habilitado contando todos los pulsos que reciba; luego para que deje de
contar, se le envía una señal de voltaje bajo output_low(pin_a4); y termina de contar.

2d0) Conectamos un sensor (opto-acoplador, sensor magnético,etc) como entrada al


pin_a4, que es donde está ubicada la entrada del contador timer0. (observe el plano del
circuito)

3ro) Extraemos (tomamos) el valor contado por el timer0 y lo asignamos a una variable.
Ejemplo rps=get_timer0();

4t0) Descomponemos ese número en 4 dígitos y lo enviamos a los displays.

rps=(get_timer0()); rps toma del valor de timer0()


d4=floor(rps/1000); extracción del 4t0 dígito
d3=floor((rps-1000*d4)/100); extracción del 3er dígito
d2=floor((rps-1000*d4-100*d3)/10); extracción del 2do dígito
d1=rps-1000*d4-100*d3-10*d2; extracción del 1er dígito
output_b(d4); Puesta en el puerto del 4to dígito
output_high(pin_b7); Flanco de subida del pulso
output_low(pin_b7); Flanco de bajada del pulso

Nota: El digito 4t0 se carga en el 4to display con un pulso dado en el pin_b7, debido a
que es este pin el que está conectado al pin_11 (CP) de carga del FLIP-FLOP tipo D, el
digito 3 con un pulso en el pin_b6, el dígito 2 con un pulso en el pin_b5 y el dígito 1ro
con un pulso en el pin_b4.
Nota: Recuerde que un pulso es completo, cuando tiene subida y bajada del voltaje.

Programa ejemplo 15
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>
void main() {
int16 rps;
int d1,d2,d3,d4;
set_tris_a(0b11111);
set_tris_b(0b00000000);
setup_timer_0(rtcc_ext_l_to_h);
enable_interrupts(int_timer0);
enable_interrupts(global);
output_b(0b00000000);

279
while (1){
output_low(pin_a4);
set_timer0(0);
output_high(pin_a4);
delay_ms(1000);
rps=(get_timer0());
d4=floor(rps/1000);
d3=floor((rps-1000*d4)/100);
d2=floor((rps-1000*d4-100*d3)/10);
d1=rps-1000*d4-100*d3-10*d2;
output_b(d4);
output_high(pin_b7);
output_low(pin_b7);
output_b(d3);
output_high(pin_b6);
output_low(pin_b6);
output_b(d2);
output_high(pin_b5);
output_low(pin_b5);
output_b(d1);
output_high(pin_b4);
output_low(pin_b4);
}}

Nota: En el circuito para este programa, los cruces entre líneas que no tengan indicación
de hacer contacto eléctrico, no hacen contacto

280
Circuito para el programa ejemplo 15.

281
Programa ejemplo 16:
Situación hipotética pero que se ajusta a la realidad.

Suponga que usted tiene una máquina que tiene dos mecanismos gemelos, es decir que a
pesar de que los mecanismos son exactamente iguales, cada uno trabaja
independientemente del otro, y que el motor trabaja según un programa computarizado,
por ciclos, y que cada ciclo es totalmente diferente a los otros en velocidad, arranque,
frenado y fin de ciclo.
Suponga que a una de las máquinas se le quemó el motor y además se le quemó el
circuito computarizado que controlaba el motor.

Nota: Ni el motor, ni el controlador computarizado tienen reparación, no se consiguen


en el mercado bajo ninguna condición, solo se consigue un motor también DC que calza
exactamente en el lugar del motor que se quemó, pero sus características eléctricas son
diferentes.

¿Cómo resolvería esta situación?

¡DIFICIL!
No!,
Facilito: Eso no es más que copiar en tiempo real las RPS de un motor (el bueno) en el
otro, el que se va a instalar.
Cómo lo hago:
Nota: RPCS quiere decir: Revoluciones por centésima de segundo.

1ro) Coloco un opto acoplador en el primer motor (el bueno), para medir sus RPCS a
cada centésima de segundo.
2d0) Coloco otro opto acoplador en el motor adaptado para medir sus RPCS también a
cada centésima de segundo.
3r0.) Uso el modulador de ancho de pulso del microcontrolador para alimentar el motor
adaptado, de manera que si las RPCS están por debajo de las del motor bueno se
aumente el ciclo de trabajo, y si están por encima entonces disminuya el ciclo de
trabajo.
4to.) Como las lecturas se están realizando cada centésima de segundo, lo más que
puede ocurrir es un desfase de 3 centésimas de segundo, (claro todo depende de la
capacidad del motor adaptado para responder a cambios de voltaje).

Y para rematar lo que tengo que usar es un PIC16F84A, que no tiene modulador de
ancho de pulso, pero lo voy a simular mediante programación, más adelante estará el
mismo programa pero con el PIC16F876 haciendo lo mismo, y además mostrando las
RPCS de cada motor en una pantalla LCD.
Programa ejemplo 16.

#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=12000000)
#include <math.h>

void main (){


int m1,m2,x;

282
float c;
set_tris_a(0b10000);
set_tris_b(0b00000000);
setup_timer_0(rtcc_ext_l_to_h);
enable_interrupts(int_timer0);
enable_interrupts(global);
set_timer0(0);
output_low(pin_a4);
While (1){
output_low(pin_a3);
output_high(pin_a2);
set_timer0(0);
output_high(pin_a4);
delay_us(10000);
output_low(pin_a4);
m1=get_timer0();
output_high(pin_b0);delay_us(x);
output_low(pin_b0);delay_us(1000-x);
output_low(pin_a2);
output_high(pin_a3);
set_timer0(0);
output_high(pin_a4);
delay_us(10000);
output_low(pin_a4);
m2=get_timer0();
if (m2!=0) c=m1/m2;
if (c>1) x=x+1;
if (c<1) x=x-1;
output_high(pin_b0));delay_us(x);
output_low(pin_b0);delay_us(1000-x);}}

Explicación del programa.


Bloque Rojo:
En el bloque rojo se configura el timer0 como un contador de pulsos externos
set_timer_0(rtcc_ext_l_to_h), con enable_interrupts(int_timer0) y
enable_interrupts(global), se habilita, se carga el valor de 0 en el contador
set_timer0(0) , y se cerciora que no esté activado con a output_low(pin_a4)

Nota: Recuerde que hay 2 motores a los que hay que captarles la velocidad RPCS, y que
los dos van a ser leídos por el mismo pin_a4 del microcontrolador, así que en la
electrónica se discrimina cual es el sensor al que se le van a leer los pulsos de la
siguiente manera:
Cuando el pin_b0 está en alto, pasan sus pulsos al contador. b0=1, b1=0
Cuando el pin_b1 está en alto, pasan sus pulsos al contador. b0=0, b1=1
Así que sólo puede estar uno solo en alto a la vez, b0 o b1, si están los dos, entonces
pasan las dos señales y el resultado no solo es indeterminado sino que seguro que está
malo.

283
Bloque Azul:
Como hay dos sensores que necesitan ser leídos por el mismo contador, y el motor1 del
bloque azul activa sus pulsos con b0=1 y b1=0, entonces se enciende b0 y apaga b1,
luego se carga el timer0 con 0 (para contar desde cero), se activa el contador timer0
(output_high(pin_a4)), se detiene el programa con el delay, pero no el contador por
10000 millonésimas de segundo que equivale a 1/100 seg. Para que se cuente las RPCS
de motor1, luego se desactiva el timer0 output_low(pin_a4); y se carga el valor de
las RPCS a m1. m1=get_timer0( );

Nota: la señal que lleva la energía para energizar a motor2 está en el pin_a0

Los bloques Violeta son la simulación del modulador de ancho de pulso,


Si x=0, Entonces no hay voltaje para el motor2 por lo tanto no se mueve.
Si x=1000 Entonces al motor le llega el máximo de energía que se puede: importante es
que la máxima cantidad de energía sea superior a la necesaria para asegurar que el
motor2 puede copiar la mayor velocidad o potencia.

Bloque Verde:
El bloque verde se comporta igual que el bloque azul, pero cambiando de sensor.

Bloque Marrón.
En el bloque marrón se comparan las velocidades de los motores, si c>1 motor2 está
lento, si c<1 entonces motor2 está más rápido y si c=1 entonces van a la misma
velocidad, el valor de x le incrementa la energía.

Circuito recomendado para el programa 16.

284
Explicación del circuito:
Si necesito medir la velocidad de los dos motores pero tengo solo una entrada por la que
se puede medir la velocidad, entonces necesito emplear un multiplexor.

¿Que es un multiplexor?
Es un circuito que tiene varias entradas y una salida, y su función es dejar pasar los
datos de una sola de las entradas y dirigirlos hacia la misma salida para todos, ahora,
cual de las entradas es la seleccionada, bueno, los multiplexores tienen unos pines
selectores en los que según la combinación que pongas (esa combinación es un número
en código binario) seleccionas la entrada a la que le vas a permitir que sus datos pasen.
(Es una especie de selector).

1ro.) A los dos motores les conecto un opto acoplador para capturar en forma de pulsos
eléctricos cada vuelta o fracción de vuelta que cada uno de ellos realiza, y así poder
determinar la velocidad de cada uno, estas dos series de pulsos las transmito por cables
separados y las dirijo hacia dos de las entradas de un multiplexor.

2do.) Una vez con las dos series de pulsos en el multiplexor, utilizo los terminales del
microcontrolador pin_a2 y pin_a3 para seleccionar cual de los trenes de pulsos va a
pasar hasta la salida.
Si pongo el pin_a2 en alto, el tren de pulsos que pasa es el del motor 1.
Si pongo el pin_a3 en alto, el tren de pulsos que pasa es el del motor 2.
Nota: este multiplexor tiene 4 entradas, de tal manera que con el puedo dirigir hasta 4
motores, por lo tanto si pongo en alto los dos pines pin_a1 y pin_a2 no pasa ninguno de
los pulsos, e igual si los dos pines están en bajo.

3r0.) Con el pin_b0 controlo la potencia entregada al motor, al controlar el paso de


energía que pasa por el transistor.

4to.) Para que necesito el transistor TIP122, porque es obvio que el voltaje y la corriente
que puede entregar el microcontrolador al motor este ni lo siente, entonces utilizo el
transistor para controlar la energía entregada al motor, energía ésta que viene de otra
fuente, una que no es la alimentación del microcontrolador.

Nota: El circuito multiplexor es el TTL SN75LS153, realmente este circuito integrado


contiene dos multiplexores, cada uno de 4 entradas y con dos pines para selección de la
entrada a permitirle el paso.

Programa ejemplo 16.1 El caso del carrito seguidor de una línea.

No quisiera hacer este programa, porque si nos ponemos a pensar un poco en la


electrónica digital, sinceramente no hace falta un microcontrolador para contruir la
electrónica de control de este carrito.
Ahora, este carrito funciona de la sigiente forma.
1ro) Tiene 2 sensores de luz, (digamos que de luz infrarroja), y 2 emisores de luz
infrarroja que están alineadas en la parte delantera del carrito y casi en contacto con el
piso, de tal manera que si la luz se refleja la capta el sensor y enciende el motor de ese
circuito, de lo contrario el motor no enciende, y esto no solo impulsa el carrito, sino
que le controla la dirección.

285
2do) Mientras los sensores del carro reciban luz reflejada, se deaplazará en línea recta,
cuando alguno de los sensores deja de recibir luz porque está sobre la línea negra, se
apaga el motor de ese lado, entonces el motor que permanezca encendido lo endereza
mientras lo sigue impulsando.

Como podrán darse cuenta realmente no hace falta el microcontrolador para esto, pero
igual les voy a dar el programa y el circuito, porque sé que lo mandan muchos
profesores como asignación práctica.

Circuito recomendado para el problema del carro seguidor de linea negra.


Tenga en cuenta que la línea a seguir debe ser de trazos suaves y no bruscos, (giros con
una amplitud que le permita al carrito seguir la línea)

286
Programa para el carrito seguidor de línea negra.
#include <16f84a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#include <math.h>
void main () {
int16 x,z;
int a[9];
int i;
float y;
set_tris_a(0b11111);
set_tris_b(0b00000000);
output_b(0);
while (1) {
if (input(pin_a2)) output_high(pin_b1);
else {output_low(pin_b1);
delay_ms(200);
output_high(pin_b1); }
if (input(pin_a3)) output_high(pin_b2);
else {output_low(pin_b2);
delay_ms(200);
output_high(pin_b2); }} }

Nota: El programa es de lo más sencillo, en la subrutina cuando el sensor deja de


recibir la señal del emisor, el motor se apaga solo durante 2 décimas de segundo, esto es
para evitar un cabeceo fuerte (Efecto sabueso) y que con cierta suavidad regrese a la
línea que lo dirige.
Bueno compañeros, hasta aquí llegó el PIC16F84 o PIC16F84A, como dije antes, no es
que él no de para más, todavía tiene mucho potencial, pero vamos a avanzar al
PIC16F876 o PIC16f876A.

Nota: Si con 13 pines hicimos todo lo que hicimos, ahora tenemos 22 pines, además
convertidor analógico digital, modulador de ancho de pulso, y comunicación serial con
otro microcontrolador o con una computadora., el límite está en la imaginación.

287
Repaso necesario de electrónica.

Explicación:
Existen unos circuitos llamados compuertas lógicas, estos son circuitos para trabajar
con señales digitales, es decir para una cierta entrada tienen una determinada salida,
ellos no amplifican, ni regulan, ni ajustan señales, una compuerta puede tener varios
pines o conexiones de entrada, pero solo una salida. Los circuitos básicos de las
compuertas son
AND (Y), NAND (Y invertido), OR (O), NOR (O invertido), EXOR (O excluyente) y
EXNOR (O excelente invertida), sus símbolos están en la siguiente tabla; pero usted
nunca, pero nunca jamás las verá como sus símbolos, solo verá los IC (circuitos
integrados) donde ellas están encapsuladas y por eso en tan importante tener a mano un
manual de diagramas de circuitos integrados bien sean TTL o CMOS etc.
Nota: No se preocupe cuando diga circuito TTL o CMOS, eso es solo como los
fabrican, porque de resto se comportan igualito. Cada TTL tiene su equivalente en
CMOS, a las diferencias por ahora ni las tome en cuenta.

La siguiente tabla, es llamada la tabla de la verdad.

Ahora, esta tabla no tiene utilidad para el diseño digital, pero si para entender como
funcionan las compuertas, tenga en cuenta lo siguiente.

288
1ro.) Una compuerta solo entiende dos tipos de señal, hay voltaje (señal nivel alto o
estado de 1) y, no hay voltaje (señal nivel bajo o estado de 0), para una compuerta todos
los voltajes iguales o mayores a 3.3 voltios es el mismo estado 1, y todos los voltajes
menores o iguales a 2.0 voltios son el mismo estado 0, pero eso no quiere decir que la
va a conectar a 120 voltios, porque se funde en el acto, así que las entradas no deberían
ser mayores a 5 voltios.

2d0.) Cuando a una compuerta se le pone en su entrada alrededor de 2.5 voltios, se hace
impredecible como lo va a interpretar y su respuesta.

3ro.) En los símbolos de las compuertas solamente salen las entradas y la salida.
Nota importante: En electrónica digital existen varios tipos de diagramas.
1ro) El diagrama más importante en electrónica digital es el diagrama lógico, en el
aparecen todos los símbolos de los componentes y como se interconectan, no aparece ni
la alimentación positiva, ni la alimentación negativa, ni la distribución como estarán los
componentes electrónicos en el circuito, y lo más probable es que este diagrama no se
parezca en nada al circuito en la realidad, pero sin él no se entendería como funciona el
aparato.
2do) El diagrama de construcción, diagrama de la baquelita, etc., en este diagrama
aparecen los componentes como son a la vista, como se distribuyen en la tarjeta
electrónica, el trazado de las pistas conductoras, como se conectan (que pata de este
conecta con cual pata del otro).
La tabla anterior es una tabla con los diagramas lógicos de las compuertas, y la tabla de
la verdad es una tabla en la que se le da valor a las entradas para observar como es su
salida según las entradas.

Para explicar la tabla anterior, solo hablaré de la fila 2 y la 3, para que se entiendan las
demás.

Como podrán observar esta compuerta tiene 2 entradas a y b, y la salida s.


Esta compuerta se llama AND, en español Y, y esto significa que solo cuando hay
señal de estado 1 en las todas las entradas a=1 y b=1, solo entonces en la salida habrá
señal 1, (Ese 1 en la salida significa que en ese pin hay 5 voltios), de ahí en adelante
es otra historia lo que se haga con esos 5 voltios.
Compuerta Y significa que para que haya salida = 1, debe haber señal = 1 en la entrada
a y en la entrada b, y la entrada c, y la entrada d,…y la entrada x.
Son apagadores en serie. Si uno no esta encendido no hay la señal a la salida.

Observe que la diferencia es el circulito en la salida


La entrada NAND en español Y invertida, en su salida se comporta lo opuesto que la
AND (Y), si la AND necesita 1 en todas las entradas para mandar alto en la salida, esta
necesita 1 todas las entradas para mandar bajo a la salida. (recuerde que en esto, todo se
trata de la salida), si entiendo como se comporta una, ya se como se comporta su
inversa.

289
Breve explicación de los transistores de unión bipolar cuyas siglas en ingles son BJT
( Bipolar Tansistor Junction).

Los transistores bipolares se asemejan a dos diodos unidos por uno de sus terminales
(en serie, uno detrás del otro), y además unidos por el mismo terminal, como todos
saben los diodos son componentes polarizados, así que tienen un terminal positivo y un
terminal negativo, de esta manera esos diodos están unidos bien sea por el terminal
positivo o por su terminal negativo: (ver figura)

de esta manera al tener dos diodos


unidos por el mismo terminal tenemos un nuevo elemento, pero con 3 terminales

al que llamamos transistor de unión


bipolar, ahora bien, como quiera que estos estén unidos y como cada uno de esos
terminales sigue teniendo polaridad entonces al observarlos con su polaridad tenemos lo
siguiente.

y de ahí tenemos que, cuando los


diodos están unidos por el polo positivo son transistores NPN y cuando están unidos por
el polo negativo son transistores PNP.

Ahora bien, al terminal que es común para ambos (por donde están unidos), se le llama
base (imagine que se llama así porque es por donde se unen), y los otros 2 terminales,
uno se llama emisor y el otro se llama colector.

Por supuesto que 2 diodos unidos por el mismo terminal nunca se comportarán como un
transistor, porque sus elementos de construcción (silicio, fósforo, germanio, etc.) tienen
que estar en contacto directo e interactuar atómica y electrónicamente a nivel atómico-
molecular. (pero esto es un cuento que no viene a este caso).

Los diagramas con los que se representan los transistores


bipolares tienen cierta información que debemos reconocer.
1ro) El terminal de la flecha siempre es el emisor.
2do) El Terminal que está de un lado solo es la base.
3ro) Como esa flecha es la flecha que indica la polaridad de un diodo, también está
indicando la polaridad de la base, la flecha hacia adentro PNP, indica base negativa y
los demás positivos.
Lo que nos interesa: ¿Cómo usarlos?, ¿Cómo seleccionarlos? ¿Cómo instalarlos?.
Los transistores tienen 3 posibles alternativas para usarlos, cada una tiene sus ventajas y
desventajas, y por eso es importante conocer las diferentes configuraciones, a) Base
común, b) Emisor común, y c) Colector común. (Eso es para los electrónicos puros),
pero nosotros solo nos vamos a concentrar en la configuración emisor común, que es a
la que mejor nos sirve por sus características.

Configuración emisor común.

290
Como ya sabemos los transistores tienen tres terminales, Emisor, Base y Colector, y se
puede usar como amplificador de una señal, en este caso la señal que le vamos a meter
para amplificar es, o un pulso de onda cuadrada, o una señal constante DC, (ni
senosoidales, ni exponenciales, ni nada de eso a lo que le tenemos que cuidar su figura).

Como también ya sabemos, si el transistor tiene 3 terminales, entonces le puedo poner


tres alimentaciones independientes, (ver diagrama)

La alimentación A volt se llama voltaje base-emisor, la alimentación B


volt. se llama voltaje emisor colector, y la alimentación C volt. se llama voltaje base-
colector. Para lo que nos interesa, cuando el transistor trabaja en la configuración
emisor común, solo le ponemos 2 alimentaciones. A) La alimentación emisor-base, y
B) La alimentación emisor colector, (por eso es que se llama configuración emisor
común).

Ahora bien, (importantísimo). ¿Que es polarización directa, y que es polarización


inversa en un diodo?. (aquí está la clave de todo).
Polarización directa es cuando el diodo conduce electricidad, o sea cuando le pongo el
positivo de mi batería o fuente de poder al positivo del diodo y este deja pasar la
corriente (no lo olvide, cuando a un diodo le pongo positivo a su positivo, el deja pasar
la corriente).
Polarización inversa es cuando el diodo no conduce electricidad; o sea cuando le pongo
el positivo de mi batería o fuente de poder al negativo del diodo. (conectado así no deja
pasar la corriente).

Muy bien, volviendo a los transistores, y recordando que los transistores se asemejan a
dos diodos pegados, y que además se pueden usar como amplificadores de potencia
(Nota: Realmente es amplificador de señales, la potencia siempre la pone una fuente
externa, el transistor lo que hace es copiar esa señal como un pantógrafo, la pasa de
pequeña a grande) entonces procedemos de la siguiente manera.

Nota: Este es un proceso general, quizás de todo el proceso solo usaremos en la práctica
un par de pasos.

Muy importante:
Sabiendo que en un transistor instalado con la configuración emisor común, la señal que
voy a amplificar se conecta entre el emisor y la base, y que la señal amplificada se
recoge entre el emisor y el colector.

291
Procedemos así.
1ro) Busco el manual del transistor para tener los siguientes datos.

Código del transistor. TIP122


Tipo de transistor NPN (Esquina superior izquierda)
Disposición de las patas (Esquina inferior derecha) Base-Colector-Emisor
Voltaje Emisor-colector 100 Vdc (rojo verde)
Voltaje Emisor-Base 5 Vdc (rojo azul)
Corriente de colector 5 Amperes con corriente dc
Corriente de base 120 mili Amperes con dc

¿Que quiere decir esto?:


Esto quiere decir que con 5 voltios y 120 miliamperes (voltaje emisor-base) puedo
controlar hasta 100 voltios y 5 amperes (voltaje emisor colector). y obtener hasta 65
watts

2do) Identificando que el transistor es del tipo NPN, ya se que la señal que viene del
microcontrolador (señal positiva) la voy a conectar a la base del transistor y el negativo
de la alimentación del microcontrolador al emisor.

¿Por qué así y no al revés?


Porque si ese transistor es NPN esto quiere decir que el diodo Emisor-Base tiene como
emisor el terminal negativo de un diodo y como terminal positivo la base del mismo
diodo, y como este diodo (el diodo emisor-base) se debe polarizar directamente se
conecta el positivo de la señal con positivo del diodo y el negativo con negativo. (ésta es
la entrada de la señal que quiero amplificar)

3ro) Ahora conecto el colector del transistor con el positivo de la fuente de energía (El
positivo de los 100 voltios dc, “no necesariamente tienen que ser 100, este es el máximo
que soporta este transistor –garantizado-), el negativo de la fuente al motor y el otro
terminal del motor a el emisor del transistor, note que el emisor se conecta a las dos, a la
señal de entrada y a la señal de salida (emisor común, para uno es entrada y para el otro
es salida)
¿Por qué así y no al revés?

292
Porque como el transistor es NPN, esto quiere decir que el diodo Base-Colector tiene
como colector el terminal negativo de un diodo y como terminal positivo la base del
mismo diodo, y como a este diodo (el diodo base-colector) se debe polarizar
inversamente se conecta positivo con negativo y negativo con positivo, siempre y
cuando entre ellos se conecte la carga, es decir el motor (por ejemplo).
Ver diagrama.

Si usted usa este transistor y esta configuración no necesitar salirse de estos parámetros.
1.)La salida del pin del microcontrolador siempre al pin-1 del transistor.
2.)El positivo de la fuente de potencia al pin-2 del transistor.
3.) Los 2 polos negativos juntos en el pin-3 (central)
4.) La carga (motor) interrumpiendo el negativo de la fuente.

PLANO ELECTRÓNICO Y DIAGRAMA LÓGICO.

En la electrónica digital hay gran variedad de componentes, y todos esos componentes


tienen sus símbolos gráficos, pero cuando tenemos un circuito impreso (lo que llaman
una tarjata electrónica) en las manos y la observamos, salvo que estemos familiarizados
con ella, o conozcamos muchos códigos de circuitos integrados, su funcionamiento y su
pinado, no tenemos idea de para que sirve esa tarjeta y como trabaja, y en la mayoría de
los casos aún conociendo los códigos de los circuitos y su pinado si no podemos
determinar como están interconectados, tampoco podemos hacer algo con esa tarjeta.

Ahora, todo circuito electrónico tiene (necesariamente) esos dos diagramas, el plano y el
diagrama lógico.
El plano es como una foto del mismo circuito, en el están todos sus componentes de la
manera como están instalados en la tarjeta electrónica, se aprecian las pistas de
intercornexión (aquellas que están decubiertas), y deberían estar los códigos de los
circuitos integrados, los valores de las resistencias y los códigos de los transistores, hay
fabricantes que no colocan los códigos originales sino un código particular, este plano
nos es util cuando tenemos una tarjeta con un desperfecto que ya está diagnosticado y
sabemos cual es el componente que está dañado, entonces lo ubicamos para quitarlo y
sustituirlo.

El diagrama lógico, es realmente el diagrama importatnte, es el que necesitamos


estudiar para entender la lógica de la tarjeta, y poder diagnosticar una falla.

Ahora vamos a ver un diagrama lógico y un plano electrónico, y los compararemos, y


aunque no lo crea, son el mismo, “el presente es un circuito comparador de 8 bits“, a
la izquierda las entradas, y a la derecha la salida –como se dará cuanta: Ni hay palabras
de comparación.-

293
De hecho, cuando se hace diseño digital, lo que se hace es diseño lógico, y una vez que
se ha resuelto el problema lógico, es que se pasa a el diseño y rediseño de la tarjeta
electrónica, hasta que se tiene la definitiva.

Y como es normal, de una tarjeta se pueden obtener varios diagramas.


El diagrama lógico de cada uno de los subcircuitos que forman un sistema.
El diagrama de alimentaciones, entre otros.

Y si está diseñando, y está bien informado, instala un solo circuito que hace todo eso en
un solo IC.

Gracias a dios que les estoy dando todos los diagramas para montajes ya probados, tanto
los montajes como los programas en este libro has sido montados y probados, estos no
deben fallar, salvo que tengan conexiones mal puestas

294
Detalles del Microcontrolador PIC16F876 y PIC16F876A

IMAGEN DEL MICROCONTROLADOR

295
No comenzaré a hacer programas sin primero decir todo lo que pueda de este
microcontrolador, pues y como dije al principio del libro, lo primero que hay que saber
de un microcontrolador es ¿Qué és?, después ¿Para que me sirve?, y por último,
¿Cómo lo puedo usar?.

Bueno, en cuanto a Que és, Para que sirve y Como lo puedo usar, es algo que se ha
venido explicando desde el principio del libro, ahora bien, entre las características de
este microcontrolador, por encima del PIC16F84A son varias.

1ro.) Tiene 22 pines para trabajar.


2do.) Tiene 5 entradas convertidoras analógico-digital.
3ro.) Tiene un modulador de ancho de pulso.
4to.) Tiene 13 posibilidades de interrupción.
5t0.) Soporta cristales resonadores de 20 Mghz.
6to.) Tiene 8K de memoria de flash de programa.
7mo.) Tiene 368Bytes de memoria de datos
8v0.) Tiene 3 contadores.
9no.) Tiene puerto de comunicación en serie.
10m0.) Tiene 256 bites de EEPROM.

Lo segundo, es explicar lo mejor que pueda cada PIN.

El pin_1, Es el RESET y entrada de voltaje para programación.


A este pin se le conecta a positivo a través de una resistencia de 10k.

El pin_2, Es un pin de entrada o salida digital, o entrada al convertidor analógico


digital.

El pin_3, Es un pin de entrada o salida digital, o entrada al convertidor analógico


digital.

El pin_4 Es un pin de entrada o salida digital, o entrada al convertidor analógico


digital, o entrada del voltaje de referencia negativo que el convertidor analógico digital
va a tener como referencia mínima para la conversión:

Aclaratoria: Cuando se va a convertir un valor de analógico a digital, se necesita tener


dos referencias para hacer la conversión, la mínima (que no siempre es 0 porque puede
ser negativa o positiva) Vref- , y la máxima Vref+ que es el tope hasta adonde se
debería poder medir, ahora, entre ese mínimo y ese máximo deben estar todas las
señales analógicas que se van a convertir, y si la señal se iguala a la mínima referencia
Vref- entonces su conversión a digital debe ser 0% 0, y si es igual a la máxima Vref+
entonces su conversión debe ser 100% o 1024 para el caso del convertidor del
microcontrolador, entonces: si se pone la referencia negativa (realmente está por encima
de 0 pero es la de menor valor) en 2,00 voltios, entonces cuando introduzca 2,00 voltios
por la entrada a convertir, el convertidor me debe dar como resultado digital 0 (cero), y
si el voltaje de referencia positivo Vref+ es 4.00 voltios, entonces cuando introduzca

296
una señal a convertir de 4.00 voltios, el convertidor me debe dar 100% o 1024 en el
caso del convertidor del microcontrolador, y por supuesto si introduzco 3.00 votios que
esta en la mitad entre 2.00 y 4.00 el convertidor me debe dar 50% o 512 en el caso del
microcontrolador.

Entonces, este pin Vref- es por donde introducimos el voltaje de referencia más bajo, en
caso de no introducir nada, ningún voltaje de referencia, se supone que el voltaje de
referencia es cero (0), pero esto no lo he comprobado en la práctica.

La explicación del pin_5 es igual que la explicación del pin_4, pero con el voltaje de
referencia máximo.

El pin_6: Es una entrada o salida digital, o es la entrada de pulsos externos para el


contador 0. T0CKI es Timer 0 ClocK In que en español significa
“entrada de pulsos externos para el contador 0”.

El contador 0 (timer 0) es un contador de eventos externos o un cronómetro, todo


depende de cómo lo configuremos, si lo configuramos como contador de eventos
externos, entonces su entrada está por el pin_a4, y se configura para que cuente flancos
de subida u flancos de bajada, si se configura como contador de los pulsos internos,
entonces se puede usar como un cronómetro.

El predivisor o prescaler de los contadores o timers.


El predivisor o prescaler no es el número por el cual se van a dividir los pulsos de
entrada para ser contados por el contador, si por ejemplo uso un prescaler de 4, esto
quiere decir que se va a tomar en cuenta 1 de cada 4 pulsos, que no es lo mismo que
equivaler a cada pulso por ¼ de pulso.

Conociendo esto, como el timer0 es un contador de 8bits, esto me quiere decir que se
desbordará al llegar el conteo a 256, lo que puede producir una interrupción del
programa si yo lo he programado para una interrupción con el desborde del timer0,
pero si a este contador le pongo un prescaler de 4, entonces el desbordamiento ocurrirá
a los 256*4 =1024 conteos.

El pin_7. Es una entrada o salida digital, entrada al convertidor analógico, o sirve para
seleccionar el modo esclavo durante una comunicación serial.

Cuando se establece una comunicación tipo serial entre dos aparatos, se establece el
siguiente protocolo, primero se usan dos cables, por uno viajan los pulsos de datos y por
el otro viajan los pulsos de control de los datos, pero estos pulsos (llamados pulsos de
sincronización) los tiene que poner uno de los dos aparatos, bueno, el que pone los
pulsos de sincronización es el aparato maestro y el otro es al aparato esclavo.

Cuando este microcontrolador establece comunicación serial con otro microcontrolador,


si cuando van a iniciar la comunicación el otro le pone una señal negativa en este pin, le

297
está indicando que el tiene que ser el que tiene que poner los pulsos de sincronización
para la comunicación entre ambos, de lo contrario entonces tiene que ser el esclavo.

El pin_8, es uno de los pines de alimentación negativa, V-, cuando un microcontrolador


tiene varios pines de alimentación, basta con alimentarlo por uno solo, ya que las
alimentaciones se conectan internamente, dependiendo el microcontrolador puede tener
varias alimentaciones pero esto se hace generalmente para facilitarle el trabajo al
diseñador digital.

En el pin_9, se coloca el oscilador de trabajo, generalmente es una de las patillas de un


cristal resonador.

El pin 10 es igual al pin_9, ahí se coloca la otra patilla del cristal resonador.

En el pin_11, Esta una entrada o salida digital, pero también puede ser la entrada de
pulsos para que sean contador por el timer1, o:

Muchas veces queremos controlar el tiempo exacto (centésimas de segundos o


milésimas) con una señal independiente y que no dependa del oscilador principal, ya
que el oscilador principal puede esta afectado porque él es el que da la velocidad de
procesamiento y ejecución del programa, entonces entre el pin_11 y el pin_12 se coloca
otro cristal resonador de 32, khz que es el ideal para que el timer1 mida el tiempo con
exactitud en segundos o centésimas de segundo.

En el pin_12, Está una entrada o salida digital, está el acceso a las funciones CCP que
significa (Captura, Comparación o Pulsador), o el pin donde se coloca la otra patilla del
resonador para que el time1 mida el tiempo con exactitud.

Los módulos CCP, son operaciones que están ubicados en ciertos pines y cuya función
depende de la configuración de le imponga el programador y entre sus funciones están:

1ro.) Captura (detecta un flanco de subida o de bajada) un pulso por el pin donde está
ubicada su entrada y cuando esto sucede interrumpe la ejecución de un programa y
ejecuta alguna tarea y después de ejecutar esa tarea (por lo general es una subrutina
fuera del cuerpo principal del programa) regresa y sigue la ejecución del programa
desde donde salto.

2d0.) Compara, en muchos procesos químicos o mecánicos, el tiempo en el que se


ejecuta algo debe ser controlado con precisión, para esto el microcontrolador tiene un
contador interno que va midiendo el tiempo internamente o pulsos externamente, y
cuando el tiempo se iguala con uno que tiene adentro entre sus datos guardado de
referencia, o cuando la cantidad de pulsos si iguala a este dato guardado, el
microcontrolador por ese pin_CCP, manda una señal para informar que es tiempo o esa
cantidad de eventos ya se igualaron.

298
3ro.) Modulador de señales de pulsos: a todos los aparatos que trabajan con corriente
continua DC, se le puede controlar la cantidad de energía que se le entrega, controlando
mediante pulsos positivos y pulsos a 0 voltios la cantidad de energía que reciben y así
poder controlar la velocidad de un motor, la intensidad de luz, la cantidad de calor.

La cantidad de energía que se le entrega a un motor (por ejemplo) que está conectado
directamente a la fuente, es constante, es decir recibe el 100% del tiempo la energía,
ahora si yo quisiera entregarle el 99% de la energía, lo conecto el 99% del tiempo y el
1% del tiempo lo desconecto, y así de está manera cuando se le quiera poner a trabajar a
media potencia, se le conecta el 50% del tiempo y se desconecta el otro 50%, esto es lo
que hace el modulador de ancho de pulso, controla el tiempo que un aparato (motor,
luminaria, potencia calórica) recibe energía, y esta señal de conexión a la energía y
desconexión es tan rápida si el aparato fuera un ser vivo no lo notara, es decir lo conecta
150 micro-segundos y lo desconecta 50 microsegundos, o sea hace ese trabajo 5000
veces por segundo.

El pin_13 se comporta igual que el pin_12 pero no tiene TIOS1, RC2 y CCP1 son
como los del pin_12

En el pin_14 está una entrada o salida digital, también la señal de pulsos SCK y SCL
para establecer comunicación serial del tipo SPI y IIC, que son dos protocoles de
comunicación serial entre aparatos. (con este tipo de comunicación no vamos a trabajar)

En este pin_15 está una entrada o salida digital, también la señal de entrada de datos de
los tipos de protocolo de comunicación serial SPI y IIC.

En este pin_16 esta una entrada o salida digital, también está la señal de salida de los
datos para el protocolo de comunicaciones SPI

En este pin_17 está una entrada o salida digital, también para el protocolo de
comunicaciones RS232 tiene la línea de transmisión de datos, o la línea de pulso para
ese mismo protocolo de comunicación.

En este pin_18 está una entrada o salida digital, está la línea de recepción de datos para
el protocolo RS232, o las señales de pulso para ese mismo protocolo.

Pin 19 Alimentación negativa.

Pin_20 Alimentación positiva.

299
En el pin_21 está una entrada o salida digital, o es el pin de entrada para interrupción
del la función INT_EXT.

Los pines 22,23,25 y 26 son entradas o salidas digitales.

En el pin_24 esta una salida o entrada digital, también esta en pin para hacerrle
programación a bajo voltaje.

En el pin_27 está una entrada o salida digital, y la entrada de los pulsos cuando se está
programando en forma serial el microcontrolador.

En el pin_28 está una entrada o salida digital, y la entrada de señales de datos en forma
serial cuando se está programando.

300
MECATRÓNICA O ROBÓTICA

Desde el punto de vista de los ingenieros y especialistas en mecatrónica, robótica,


sistemas, electrónica, etc., y una vez que han sido superados los problemas electrónicos
y mecánicos (hardware), el buen funcionamiento de muchos aparatos depende casi
absolutamente de la programación, es decir, del programa de computadora que ese
aparato lleva por dentro y que lo pone a funcionar integrando todas sus partes, de ahí la
importancia de la programación y el conocimiento eletrónico y mecánico del aparato,
pero ,y es que; además del conocimiento necesario para dominar un lenguaje de
computadoras y poder comunicarle a los aparatos y dispositivos programables cómo
desea el programador que se comporten (así como se hace con los niños en las casas
ajenas), también es muy importante conocer la electrónica de los aparatos desde el
punto de vista de los chips, transistores, autonomía, motores, sensores etc., para conocer
su potencial (no le vas a pedir a un ciego que opine sobre colores) y programarlo a
consciencia desde el punto de vista tanto de la misma programación como desde el
punto de vista electromecánico.

Piensa que un microprocesador o microcontrolador es un cerebro en blanco, al que le


podemos conectar todos los órganos que podamos, le ponemos tacto con sensores de
contacto, ojos con sensores de proximidad y sensores de todo tipo de luz, oídos con
micrófonos, sentido de la orientación con giroscopios y brújulas electrónicas, sensores
de temperatura, sensores de la gravedad, locomoción con motores y ruedas, e infinidad
de mecanismos y otros sensores, y una vez conectado todo esto, la mecánica y
electrónica, lógicamente, tenemos un robot que no sabe hacer nada, ni hace nada,
ahora solamente falta enseñarlo y ahí es donde nadie puede hacer nada, solo el
programador.

En pocas palabras “El programa de un aparato programable, no es más que su


personalidad” de ahí viene la expresión: Este es un sistema amigable.

Desde ahora en adelante, este es el circuito básico que se recomienda usar para los
programas y el encabezado de los programas, si se hace algún cambio se informa.

301
Nota: pant.c, pantallai.c, pantalla.c

Programa ejemplo 17. Es una adaptación del programa 16 al PIC16F876A


Utilizando pantalla LCD y el modulador de ancho de pulsos.
Leer el enunciado del programa nro. 16
Programa ejemplo 17

#include <16f876.h>
#fuses hs,nowdt,noprotect,put,brownout
#device adc=10
#use delay (clock=20000000)
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>
void main (){
int m1,m2,x;
float c;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
setup_timer_0(rtcc_ext_l_to_h);
enable_interrupts(int_timer0);
enable_interrupts(global);
set_timer0(0);
output_low(pin_a4);
setup_ccp1(ccp_pwm);
setup_timer_2(t2_div_by_1,255,1);
lcd_init();
lcd_clear();
While (1){
output_low(pin_c1);
output_high(pin_c0);
set_timer0(0);
output_high(pin_a4);
delay_us(100000);
output_low(pin_a4);
m1=get_timer0();
output_low(pin_c0);
output_high(pin_c1);
set_timer0(0);
output_high(pin_a4);
delay_us(100000);

302
output_low(pin_a4);
m2=get_timer0();
if (m2!=0) c=m1/m2;
if (c>1) x=x+1;
if ((x>0) && (c<1)) x=x-1;
set_pwm1_duty(x);
printf(lcd_data,"Motor 1 RPDS = %u ",m1);
lcd_cmd(192);
printf(lcd_data,"Motor 2 RPDS = %u ",m2); }}

CIRCUITO RECOMENDADO PARA EL PROGRAMA 17

El transistor es tipo NPN TIP122, el que con un voltaje de 5 voltios y 0.12 Amperes se
controlan 100Voltios y 5 Amperes

Explicación del programa.

303
Encabezado

Se declara el código del microcontrolador.


#include <16F876A.h>

Se declaran directivas
#fuses
hs Cristal resonador frecuencia>4000000hz.
nowdt No activar circuito de perro guandia
noprotect Sin protección del código del programa.
put Esperar para arrancar el programa la estabilidad eléctrica.

Le informamos a PIC C que se va a trabajar con los módulos CCP, esto es porque
vamos a utilizar el modulador de ancho de pulsos, entonces activamos el dispositivo
adc=10 para que trabaje con 10 bits
#device adc=10

Ya declaramos que el tipo de oscilador era hs, ahora le informamos la velocidad que
este cristal tiene. #use delay (clock=20000000)

Las siguientes líneas son para el control y manejo de la librería que controla la pantalla
LCD, aquí lo importante es tener la pantalla bien conectada el microcontrolador, estas
líneas se la puede aprender de memoria o tenerlas guardadas en algún archivo e
insertarlas cuando lo see.

Declaración de inicio de cuerpo principal de programa, {no olvide la llave abierta y al


final del cuerpo cerrarla}

Declaración de variables a usar en el programa, m1, m2 y x enteras (sin decimales) y


c variable con decimales.

Configuración de los puertos:


Puerto A Todos los pines son entrada digital

304
Puerto B Todos los pines son salida digital.
Puerto C Todos los pines son salida digital.

Configuración del contador 0 timer0.


1ra línea) Se establece el flanco “entrada externa y flanco de subida”
2da línea) Se habilita la interrupción del INT_TIMER0
3ra línea) Se habilita como interrupción general

Se carga en el contador timer0 el valor 0 (cero)


Se asegura que el pin de entrada del timer0 (pin_a4) este apagado. (inactivo)

Se configura al pin_CCP1 cono pin para salida del modulador de pulsos.


Se configura al timer2: esto se hace porque la base de tiempo que usa el modulador de
ancho de pulsos depende del tiemer2. (cópiela siempre igual)

Se inicializa la pantalla LCD


Se borra la pantalla LCD

Inicio de bucle infinito

Por la construcción del circuito electrónico, cuando el pin_c0=1 y pin_c1=0 se activa el


sensor de las revoluciones del motor 1
Se activa el sensor de RPM del motor 1 (las dos primeras líneas)
Se borra el valor del timer0 (timer0=0)
Se activa en pin_a4, por lo tanto comienza el conteo de las RPM de motor1
Delay_us(10000) detengo el programa pero no el conteo del timer0 1/10 sg
Se desactiva el contador timer0 al apagar el pin_a4.
Se carga a m1 con los conteos del motor1. (las RPM están en timer0)

305
Esta explicación es igual a la anterior del motor1; pero para el motor 2

Como c es la división de las velocidades de los motores m1/m2, entonces si por alguna
razón m2=0 existe la posibilidad de un error matemático, por eso se preestablece que
m2!=0, ( != significa diferente de) y se calcula la división de las velocidades. c=m1/m2
Si c>1 motor1 está más rápido por lo tanto se aumenta el ciclo x=x+1
Si c<1 motor1 está más lento por lo tanto se disminuye el ciclo x=x-1
Si c=1 == > motor1 = motor2 No pasa nada
X es la variable que controla el ciclo de trabajo del modulador de pulso, por eso X no
puede ser menor a 0 (nunca x<0, porque no hay trabajo negativo).

Se establece el ciclo de trabajo con el valor de x anteriormente calculado

Se presenta por pantalla la velocidad de motor1


Se pasa a la línea de debajo de la pantalla
Se presenta por pantalla la velocidad de motor2
Se cierran las llaves 1ro la de void main(){ y 2d0 la de while (1){

---------------------------------------------------------------------------------

Programa ejemplo 18. En el siguiente programa vamos a controlar un motor paso a paso
como si fuera el motor de un ascensor de un edificio de 7 pisos y vamos a ver en la
pantalla en que piso está el ascensor.

El puerto C va a ser la botonera del ascensor y también los botones de llamado en los
pisos.

306
El puerto B va conectado a la pantalla

El puerto A va al controlar los pasos del motor y controlará cuando pase por el primer
piso.

Circuito para el programa 18.

Parámetros que se deben tener en cuenta.

Debe existir alguna forma de determinar en cual piso está el ascensor, esto
normalmente se hace con sensores en los pisos donde este se detiene, pero para hacer
eso, se necesita al menos un ascensor en maqueta, así que voy a asumir que cada 600
pasos del motor ( 3 revoluciones en un motor de 200 pasos) es un piso y controlaré la
posición exacta del ascensor con los pasos del motor.
Nota: En los ascensores normalmente se usan sensores por piso y un mecanismo en la
sala de máquinas que indica su posición.
Nota: En programación en lenguaje C decir x=x+1 o decir x++ es lo mismo, y x=x-1
o x--

Programa 18, Para controlar el ascensor

#include <16f876a.h>
#fuses hs,nowdt,noprotect,put
#use delay (clock=8000000)
#define mode 0
#define set_tris_x set_tris_b

307
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pant1.c>
#define s0 output_a(1);delay_ms(50);
#define s1 output_a(2);delay_ms(50);
#define s2 output_a(4);delay_ms(50);
#define s3 output_a(8);delay_ms(50);
void main (){
int p,a,x,ss,r;
signed int8 s;
set_tris_a(0b010000);
set_tris_b(0b00000000);
set_tris_c(0b11111111);
output_a(0b00000);
output_b(0b00000000);
r=0;
lcd_init();
lcd_clear();
s=0;ss=0;a=0;
while (r==0){
if (input(pin_a4)){
;s3;s2;s1;s0;}
else r=1;}
While (1){
If(input(pin_c0)) a=0;
if(input(pin_c1)) a=1;
If(input(pin_c0)) a=2;
if(input(pin_c1)) a=3;
If(input(pin_c0)) a=4;
if(input(pin_c1)) a=5;
If(input(pin_c0)) a=6;
if(input(pin_c1)) a=7;
s=a-ss;
printf(lcd_data,"PISO = %u ",a);
lcd_cmd(192);
printf(lcd_data," DETENIDO ");
if (s>0){
lcd_clear();
output_high(pin_a5);delay_ms(1000);
output_high(pin_b1);
printf(lcd_data,"SUBIENDO AL PISO %u",a);
for (p=0;p<=s;p++){
for (x=1;x<=50;x++){s0;s1;s2;s3;}}
delay_ms(500);output_low(pin_a5);
output_low(pin_b1);}
if (s<0){s=-s;
lcd_clear();
output_high(pin_a5);delay_ms(1000);

308
output_high(pin_b0);
printf(lcd_data,"SUBIENDO AL PISO %u",a);
for (p=0;p<=s;p++){
for (x=1;x<=50;x++){s3;s2;s1;s0;}}
delay_ms(500);output_low(pin_a5);
output_low(pin_b0);
s=-s;
}
ss=a;
}}

Explicación del programa. (Solo se explicará lo que no aparezca en programas


anteriores).

Las líneas 1 hasta 10 están explicadas en el programa anterior.


#define s0 output_a(1):delay_ms(50);
La palabra #define es una sentencia que relaciona dos expresiones separadas por
espacios en blanco, de tal manera que la primera expresión representa a la segunda, de
esta manera en la línea de programa que aparezca s0 el programa lo asume como
output_a(1);delay_ms(50);

Int p,a,x,ss,r Declaración de variables enteras menores d 255


Signed int8 s; Es la forma de declarar una variable que podría tener como valor un
numero negativo, -127 <= s <=127.

309
En la parte electrónica se colocó un opto acoplador en el camino del ascensor en la
planta baja (ver diagrama), de tal manera que cuando el ascensor llegue a PB este sensor
se activa y sirva para informar el programa maestro que el mismo está en la PB

Cuando el programa arranca necesariamente antes de llegar a la parte del programa que
controla el ascensor desde las botoneras pasa por este bucle,
Como el valor de r inicialmente es 0 entonces el programa entra en este bucle y ocurre
una de dos alternativas.

1ro) Si el ascensor está en la PB entonces el opto acoplador está activado y => r=1 el
programa se sale del bucle y no sucede nada.

2do) Si el ascensor no está en la PB obligatoriamente debe estar en un piso superior (no


hay sótanos), entonces el programa comienza a bajarlo hasta llegar a la PB y ahí lo
detiene, lo pone en servicio y quede funcionando por las botoneras.

Este bucle es necesario para que cuando ocurra un corte de energía, después al regresar
el suministro de electricidad, el ascensor se pone en servicio por sí solo en la PB.
Nota: La línea s3;s2;s1;s0; en la rutina que baja el ascensor, recuerde de estas
expresiones están relacionadas al inicio con la palabra #define

Se utilizan como el control de las botoneras:


En la electrónica hay dos botoneras, una es la que va adentro del ascensor, la otra está
colocada botón por botón uno en cada piso según en valor de a, tenga en cuenta que
llamar al ascensor desde el piso 6 o montarse en el ascensor y envíarlo al piso 6 es hacer
lo mismo pero desde dos botones separados.

ss es el piso en el que se encuentra el ascensor en un momento dado, a es el piso desde


donde se llama o el piso al que un usuario lo envía, y s es la cantidad de pisos que se
debe desplazar el ascensor.

Suponga que el ascensor está en el piso 4, y lo llaman del piso 6 entonces


s = 6-4 = 2 la cuenta informa que el ascensor debe subir 2 pisos, para nuestro caso
1200 pasos del motor paso a paso.

310
Suponga que el ascensor está en el piso 4, y lo llaman del piso 2 entonces
s = 2 – 4 = -2 la cuenta informa que el ascensor debe bajar 2 pisos.

Y una vez que el ascensor ya ha cumplido la tarea, ss se hace igual a a (ss=a => ss-a=0
el ascensor no se mueve) de tal manera que el ascensor se queda en ese piso hasta que
vuelvan a presionar un botón diferente al piso donde se encuentra.

Indica en la pantalla el piso en el que está el ascensor.


Comando para imprimir en la línea más baja de la pantalla.
Indica en la pantalla que el ascensor está detenido

-Si s>0 entonces el ascensor debe subir de piso, inicio del bucle
-Borra la pantalla
-El pin_a5 activa el mecanismo que cierra la puerta y espera 1 segundo.
-El pin_b1 enciende la luz de la flecha que indica subiendo.
-Printf Informa en la pantalla que va subiendo al piso número a
-Como s es la cantidad de pisos que tiene que subir y p es el que cuenta piso por piso
lo que va subiendo.
-x es el que mide los pasos que da el motor moviendo el ascensor y s0, s1,s2,s3 son
cada uno de los pasos dados en forma creciente para subir.
-Se detiene el ascensor y en 0.5 segundo se abre la puerta.(pi_b5)
Se apaga la luz de la flecha que indica subiendo.. fin del bucle

Igual al bucle anterior; pero este para que el ascensor baje, debido a la rutina
s3,s2,s1,s0.

311
-Se iguala ss y a para que el ascensor se quede estático en el piso.
- Fin de los bucles principal y el bucle infinito.

----------------------------------------------------------------------------

Programa ejemplo 19. control de varias temperaturas y velocidad de motores

En el programa siguiente vamos a hacer un código para monitorear y actuar:

En void uno:
Se monitorea la temperatura que se capta por el canal a0 con un sensor de temperatura,
y si la temperatura es t<40 usando el pin_c0 se controla en encendido y apagado de
una resistencia que produce calor.

En void dos:
Se monitorea la temperatura que se capta por el canal a1 con un sensor de temperatura,
y si la teperatura es t<80 usando el pin_c1 se controla el encendido y apagado de una
resistencia que produce calor.

En void tres:
Se monitorea la temperatura que se capta por el canal a3 con un sensor de temperatura,
y si la temperatura es t>120 entonces con el CCP1 se controla la velocidad del motor de
un ventilador.

En void cuatro
Se capta la velocidad de un motor y si las RPS>30 entonces con el pin_c3 se activa un
freno para disminuirle la velocidad.

Programa ejemplo 19.

#include <16f876a.h>
#fuses hs,nowdt,noprotect,put
#device adc=10
#use delay (clock=8000000)
#include <math.h>
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pantallai.c>

312
void uno() {
int vu;
set_adc_channel(0);
delay_ms(10);
vu=read_adc();
output_high(pin_C6);
printf(lcd_data,"Temperatura 1 = %u ",vu);
lcd_cmd(192);
printf(lcd_data," Resistencia de calor 1 ");
if (vu<40) output_high(pin_c0);
else output_low(pin_c0);
output_low(pin_c6);}
void dos() {
int vd;
set_adc_channel(1);
delay_ms(10);
vd=read_adc();
output_high(pin_C7);
printf(lcd_data,"Temperatura 2 = %u",vd);
lcd_cmd(192);
printf(lcd_data,"resistencia de calor 2");
if (vd<80) output_high(pin_c1);
else output_low(pin_c1);
delay_ms(3000);
output_low(pin_c1);
output_low(pin_c7);}
void tres() {
int vt,x;
set_adc_channel(3);
delay_ms(10);
vt=read_adc();
output_high(pin_C4);
printf(lcd_data,"Temperatura 3 = %u ",vt);
lcd_cmd(192);
printf(lcd_data," control ventilador");
if (vt> 120) x=x+1;
else x=x-1;
set_pwm1_duty(512);
output_low(pin_c4);}
void cuatro() {
int vc;
output_high(pin_a4);
delay_ms(1000);
output_low(pin_a4);
vc=get_timer0();
set_timer0(0);
output_high(pin_C5);
printf(lcd_data,"RPS el motor %u ",vc);
lcd_cmd(192);
printf(lcd_data,"Control del freno ");

313
if (vc>30) output_high(pin_c3);
else output_low(pin_c3);
output_low(pin_c5);}
void main (){
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
setup_adc_ports(all_analog);
setup_adc(adc_clock_div_32);
setup_timer_0(rtcc_ext_l_to_h);
enable_interrupts(int_timer0);
enable_interrupts(global);
output_low(pin_a4);
set_timer0(0);
setup_ccp1(ccp_pwm);
setup_timer_2(t2_div_by_1,255,1);
output_b(0b11111111);
output_c(0b11111111);
lcd_init();
lcd_clear();
output_b(0b00000000);
output_c(0b00000000);

While (1){
uno();
dos();
tres();
cuatro();
}}

Nota: El IC que aparece en el plano es SN74LS08: 4 compuertas NAND de 2 entradas

314
Circuito recomendado para el programa 19

Explicación del programa 19.


En cuanto a la parte de diseño electrónico todo está a la vista en el plano.
1ro) Del puerto A:
Los pines del puerto A están destinados a ser conectados con sensores (transductores)
de temperatura, y aunque hay varios, recomiendo el LM35 del que ya expliqué su
funcionamiento y que es muy comercial, el pin_a4 está destinado a contar los pulsos
provenientes de las revoluciones de un motor, y para eso se configura como entrada del
timer0, los otros, el pin_a2 y el pin_a5 no se están utilizando en el programa.
2do) Del puerto B.
El puerto B, está dedicado totalmente a la pantalla, y a pesar de que sus pines pin_b0 y
pin_b1 no están conectados a nada, son usados de vez en cuando por el programa que
controla la pantalla, es importante que se sepa que el programador si quiere puede

315
controlar esos pines, pero parcialmente, mientras no se esté trabajando con la pantalla,
así que se puede usar pero no para tareas importantes.
3ro) Del puerto C.
El puerto C está dividido en dos partes, nible inferior (los pines c0,c1,c2,c3) para el
control de los actuadotes mecánicos, excepto el pin_c2 porque en el está la salida del
modulador de ancho de pulsos y se usa para modular la energía entregada a un motor, el
nible superior (los pines c4,c5,c6,c7) son usados como un demultiplexor para controlar
el tren de pulsos que provienen por el pin_b3, de manera que cuando uno de esos pines
se pone en alto, esa pantalla comienza a presentar información.

En cuanto al programa, este está hecho en bloques, módulos, cuerpos, o las llamadas
funciones en lenguaje C.

El cuerpo principal (void main())

void main (){


set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
setup_adc_ports(all_analog);
setup_adc(adc_clock_div_32);
setup_timer_0(rtcc_ext_l_to_h);
enable_interrupts(int_timer0);
enable_interrupts(global);
output_low(pin_a4);
set_timer0(0);
setup_ccp1(ccp_pwm);
setup_timer_2(t2_div_by_1,255,1);
output_b(0b11111111);
output_c(0b11111111);
lcd_init();
lcd_clear();
output_b(0b00000000);
output_c(0b00000000);
While (1){
uno();
dos();
tres();
cuatro();
}}

En este cuerpo toda ha sido explicado, sin embargo repetiré


En las líneas de color rojo se está (1ra. Línea) configurando que todos los pines que
posean entrada analógica, trabajen como entradas analógicas y (2da. Línea) dando la
mayor cantidad de tiempo disponible para la conversión.

En las líneas azules, (1ra. Línea) se está configurando el contador timer0, como
contador con el conteo por la entrada externa (esa es la entrada que tienen ese contador
en el pin_a4) y que lo haga cuando detecte los flancos de subida de los pulsos.

316
En las líneas verdes, (1ra. Línea) se está configurando al pin_c2 (que es donde está
ubicado el CCP1) como modulador de ancho de pulsos, (2da línea) se esta definiendo el
tiempo de ancho de un solo pulso, recuerde que esto se hace configurando el timer2 de
esa manera.

Cuerpo uno()

void uno() {
int vu;
set_adc_channel(0);
delay_ms(10);
vu=read_adc();
output_high(pin_C6);
printf(lcd_data,"Temperatura 1 = %u ",vu);
lcd_cmd(192);
printf(lcd_data," Resistencia de calor 1 ");
if (vu<40) output_high(pin_c0);
else output_low(pin_c0);
output_low(pin_c6);}

En las líneas rojas (1ra línea) se define por cual entrada analógica se va a hacer esa
lectura, (2da línea) se retiene el programa para dar tiempo para que se estabilice
eléctricamente el sistema (la entrada del voltaje al pin)., (3ra . línea) se toma el dato de
la lectura ya convertida en digital y se asigna a la variable vu.

En la líneas azules primero se activa y luego se desactiva el pin_c6 que es el que


controla la pantalla 1, para que solo la información que está en la líneas verdes aparezca
en ella.
La línea de color violeta, es el comando para que se imprima en la parta baja de la
pantalla, (esto es para los que están usando pantallas de 2 líneas)

Las líneas marrones son la condicional, si vu<40º, se enciende una resistencia, de lo


contrario se apaga.

Cuerpo dos() : No hay nada nuevo.

317
Cuerpo tres()

void tres() {
int vt,x;
set_adc_channel(3);
delay_ms(10);
vt=read_adc();
output_high(pin_C4);
printf(lcd_data,"Temperatura 3 = %u ",vt);
lcd_cmd(192);
printf(lcd_data," control ventilador");
if (vt> 120) x=x+1;
else x=x-1;
set_pwm1_duty(x);
output_low(pin_c4);}

En las líneas rojas se evalúa el valor de vt, si vt> 120 se incrementa x si no se


decrementa.
Línea azul. Se coloca el número que da la proporción de la modulación del ancho del
pulso, si x=256, se trabaja al 25% del máximo, si x=512 se trabaja al 50% y x=768 se
trabaja al 75%, note que x puede tomar cualquier valor entra 0 que es 0% y 1024 que es
100%.
Cuerpo cuatro()

void cuatro() {
int vc;
output_high(pin_a4);
delay_ms(1000);
output_low(pin_a4);
vc=get_timer0();
set_timer0(0);
output_high(pin_C5);
printf(lcd_data,"RPS el motor %u ",vc);
lcd_cmd(192);
printf(lcd_data,"Control del freno ");
if (vc>30) output_high(pin_c3);
else output_low(pin_c3);
output_low(pin_c5);}

En el cuerpo cuatro, lo único que se puede decir es que en las líneas rojas; (1ra. Línea)
se activa la entrada del contador timer0, para que esta pueda leer los pulsos, (2da línea)
se detiene el programa, pero no se detiene el conteo de pulsos, se detiene por i segundo
exacto, con el fin de determinas las RPS = revoluciones por segundo, (3ra línea), se
vuelve a desactivar el pin_a4 de entrada al contador, para que no cuente más hasta
nueva orden.

En las líneas azules, (1ra. Línea) Se toma el número que contó el timer0, y se le asigna a
la variable vc, (2da línea) se vuelve a poner el contador timer0 en valor 0, para que
cuando vuelva a contar no continua la cuenta anterior sino una nueva.

318
Programa ejemplo 20. Hacer una calculadora con el microcontrolador PIC16F876A.

Esta calculadora se opera como cualquier calculadora básica, la unica diferencia es que
el igual (=) es cualquiera de las operaciones +, -, /, *,
Nota: Con un telado matricial e puede hacer una cientifica.
Modo de operación.
1ro) Introduzca la primera cantidad.
2do) Presione la operación. (+, -, *, /)
3ro) Introduzca la segunda cantidad.
4to) Presione cualquera de las operaciones para vel el resultado.

319
Programa ejemplo 20

#include <16f876a.h>
#fuses hs,nowdt,noprotect,put
#device adc=10
#use delay (clock=8000000)
#include <math.h>
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pant1.c>
int16 a,aa,ua,uaa;

void espera(){
int x,y;
x=0;y=0;
while ((x==0) && (y==0)){
x=input_a();
y=input_c();}}

void divide(){
float dv;
dv=ua/uaa;
lcd_init();
lcd_clear();
printf(lcd_data," %lu + %lu = %4.2f ",ua,uaa,dv);
espera();}

void dividir(){
int b, df; b=0;df=0;
lcd_clear();
while(df==0){
if(input(pin_c7)) {uaa=10*uaa;delay_ms(200);}
if(input(pin_c6)) {aa=1;b=b+1;delay_ms(200);}
if(input(pin_c5)) {aa=2;b=b+1;delay_ms(200);}
if(input(pin_c4)) {aa=3;b=b+1;delay_ms(200);}
if(input(pin_c3)) {aa=4;b=b+1;delay_ms(200);}
if(input(pin_c2)) {aa=5;b=b+1;delay_ms(200);}
if(input(pin_c1)) {aa=6;b=b+1;delay_ms(200);}
if(input(pin_c0)) {aa=7;b=b+1;delay_ms(200);}
if(input(pin_a5)) {aa=8;b=b+1;delay_ms(200);}
if(input(pin_a4)) {aa=9;b=b+1;delay_ms(200);}
if(input(pin_a3)) {divide();df=1;}
if(input(pin_a2)) {divide();df=1;}
if(input(pin_a1)) {divide();df=1;}
if(input(pin_a0)) {divide();df=1;}
if(b>1) uaa=10*uaa;

320
uaa=aa+uaa;
aa=0;
printf(lcd_data," %lu / ",ua);}}

void multiplica(){
lcd_init();
lcd_clear();
printf(lcd_data," %lu * %lu = %lu ",ua,uaa,ua*uaa);
espera();}

void multiplicar(){
int b, de; b=0;de=0;
lcd_clear();
while(de==0){
if(input(pin_c7)) {uaa=10*uaa;delay_ms(200);}
if(input(pin_c6)) {aa=1;b=b+1;delay_ms(200);}
if(input(pin_c5)) {aa=2;b=b+1;delay_ms(200);}
if(input(pin_c4)) {aa=3;b=b+1;delay_ms(200);}
if(input(pin_c3)) {aa=4;b=b+1;delay_ms(200);}
if(input(pin_c2)) {aa=5;b=b+1;delay_ms(200);}
if(input(pin_c1)) {aa=6;b=b+1;delay_ms(200);}
if(input(pin_c0)) {aa=7;b=b+1;delay_ms(200);}
if(input(pin_a5)) {aa=8;b=b+1;delay_ms(200);}
if(input(pin_a4)) {aa=9;b=b+1;delay_ms(200);}
if(input(pin_a3)) {multiplica();de=1;}
if(input(pin_a2)) {multiplica();de=1;}
if(input(pin_a1)) {multiplica();de=1;}
if(input(pin_a0)) {multiplica();de=1;}
if(b>1) uaa=10*uaa;
uaa=aa+uaa;
aa=0;
printf(lcd_data," %lu - ",ua);}}

void resta(){
lcd_init();
lcd_clear();
printf(lcd_data," %lu - %lu = %lu ",ua,uaa,ua-uaa);
espera();}

void restar(){
int b, dg; b=0;dg=0;
lcd_clear();
while(dg==0){
if(input(pin_c7)) {uaa=10*uaa;delay_ms(200);}
if(input(pin_c6)) {aa=1;b=b+1;delay_ms(200);}
if(input(pin_c5)) {aa=2;b=b+1;delay_ms(200);}
if(input(pin_c4)) {aa=3;b=b+1;delay_ms(200);}
if(input(pin_c3)) {aa=4;b=b+1;delay_ms(200);}
if(input(pin_c2)) {aa=5;b=b+1;delay_ms(200);}
if(input(pin_c1)) {aa=6;b=b+1;delay_ms(200);}

321
if(input(pin_c0)) {aa=7;b=b+1;delay_ms(200);}
if(input(pin_a5)) {aa=8;b=b+1;delay_ms(200);}
if(input(pin_a4)) {aa=9;b=b+1;delay_ms(200);}
if(input(pin_a3)) {resta();dg=1;}
if(input(pin_a2)) {resta();dg=1;}
if(input(pin_a1)) {resta();dg=1;}
if(input(pin_a0)) {resta();dg=1;}
if(b>1) uaa=10*uaa;
uaa=aa+uaa;
aa=0;
printf(lcd_data," %lu - ",ua);}}

void suma(){
lcd_init();
lcd_clear();
printf(lcd_data," %lu + %lu = %lu ",ua,uaa,ua+uaa);
espera();}

void sumar(){
int b,dd; b=0;dd=0;
lcd_clear();
while(dd==0){
if(input(pin_c7)) {uaa=10*uaa;delay_ms(200);}
if(input(pin_c6)) {aa=1;b=b+1;delay_ms(200);}
if(input(pin_c5)) {aa=2;b=b+1;delay_ms(200);}
if(input(pin_c4)) {aa=3;b=b+1;delay_ms(200);}
if(input(pin_c3)) {aa=4;b=b+1;delay_ms(200);}
if(input(pin_c2)) {aa=5;b=b+1;delay_ms(200);}
if(input(pin_c1)) {aa=6;b=b+1;delay_ms(200);}
if(input(pin_c0)) {aa=7;b=b+1;delay_ms(200);}
if(input(pin_a5)) {aa=8;b=b+1;delay_ms(200);}
if(input(pin_a4)) {aa=9;b=b+1;delay_ms(200);}
if(input(pin_a3)) {suma();dd=1;}
if(input(pin_a2)) {suma();dd=1;}
if(input(pin_a1)) {suma();dd=1;}
if(input(pin_a0)) {suma();dd=1;}
if(b>1) uaa=10*uaa;
uaa=aa+uaa;
aa=0;
printf(lcd_data," %lu + ",ua);}}

void main() {
int b,d;b=0;d=0;
set_tris_a(0b111111);
set_tris_b(0b00000000);
set_tris_c(0b11111111);
lcd_init();
lcd_clear();
while(1){
while (d==0){

322
if(input(pin_c7)) {ua=10*ua;delay_ms(200);}
if(input(pin_c6)) {a=1;b=b+1;delay_ms(200);}
if(input(pin_c5)) {a=2;b=b+1;delay_ms(200);}
if(input(pin_c4)) {a=3;b=b+1;delay_ms(200);}
if(input(pin_c3)) {a=4;b=b+1;delay_ms(200);}
if(input(pin_c2)) {a=5;b=b+1;delay_ms(200);}
if(input(pin_c1)) {a=6;b=b+1;delay_ms(200);}
if(input(pin_c0)) {a=7;b=b+1;delay_ms(200);}
if(input(pin_a5)) {a=8;b=b+1;delay_ms(200);}
if(input(pin_a4)) {a=9;b=b+1;delay_ms(200);}
if(input(pin_a3)) sumar();
if(input(pin_a2)) restar();
if(input(pin_a1)) multiplicar();
if(input(pin_a0)) dividir();
if(b>1) ua=10*ua;
ua=a+ua;
a=0;
printf(lcd_data," %lu ",ua);}}}

Explicación del programa ejemplo 20, (Que no por ser largo es difícil).

1ro). Nótese que al final del encabezado se declaran la variables a, aa, ua, uaa, int16
a,aa,ua,uaa,d esto se debe a que estas variables deben pasar de un cuerpo a otro cuerpo
de programa manteniendo su valor.

2do) Como ya se sabe, nunca puede haber un cuerpo de programa llamando a otro
cuerpo que esté después de él, por eso es que el cuerpo principal void main() está de
último.

Ahora en el cuerpo principal no hay nada que no se haya explicado antes, solo la lógica
del programa. Así que voy a explicar la lógica sin ir al cuerpo.

Pregunta ¿Cómo funciona una calculadora básica?

Cuando usted enciende una calculadora básica, ella en el acto está esperando que le
presionen sus teclas, pero que sean las teclas que tienen números, y aparte que la
primera tecla sea diferente de 0.

Imaginese que necesita sumar las cantidades 123 + 456.

Al presionar 1 la calculadora todavía ni sabe cual es la cantidad total que usted quiere
colocar, así que ella lo asume como 1 unidad, y se queda esperando (hasta que usted
quiera), luega presiona el 2, entonces ella ya sabe que ese 2 va después del 1, entonces a
1 lo multiplica por diez 1*10 y le suma en 2, entonces hace esto 1*10+2 =12, pero
todavía sigue esperando (ella siguen sin saber si usted quiere 12 simple o más), ahora
presiona el 3, y ella toma el 12 y lo multiplica por 10 y le vuelve 12*10=120 y le suma
el 3 y ya tiene el 123,.

323
Note que siempre que usted presiona otro número, ella multiplica la cantidad que ya
tiene por 10, porque sabe que para colocar el nuevo digito tiene que mover los demás
una pocisión a la izquierda que es como multiplicar * 10. y así se mantiene hasta que
usted presiona una operación.

Una vez que se presiona la operación, ella ya sabe cual es la primera cantidad y la
operación, así que se va para una subrutina o bloque que realiza solo esa operación, ella
ya tiene la primera cantidad y usted comienza a presionar la segunda cantidad, y ella
repite el proceso que hizo para recibir la primera cantidad con la segunda cantidad, una
vez que usted ya puso la segunda cantidad, ella se entera que usted terminó de colocar la
segunda cantidad porque prsiona la tecla igual (=), entonces ella opera las dos
cantidades y las presenta en pantalla.

Luego de haber presentado el resultado se queda mostrandolo, hasta que se presionan


alguna tecla y entonces vuelve a empezar.

Explicación con algunas líneas de programa.

while(1){
while (d==0){
if(input(pin_c7)) {ua=10*ua;delay_ms(200);}
if(input(pin_c6)) {a=1;b=b+1;delay_ms(200);}
if(input(pin_c5)) {a=2;b=b+1;delay_ms(200);}
if(input(pin_c4)) {a=3;b=b+1;delay_ms(200);}
if(input(pin_c3)) {a=4;b=b+1;delay_ms(200);}
if(input(pin_c2)) {a=5;b=b+1;delay_ms(200);}
if(input(pin_c1)) {a=6;b=b+1;delay_ms(200);}
if(input(pin_c0)) {a=7;b=b+1;delay_ms(200);}
if(input(pin_a5)) {a=8;b=b+1;delay_ms(200);}
if(input(pin_a4)) {a=9;b=b+1;delay_ms(200);}
if(input(pin_a3)) sumar();
if(input(pin_a2)) restar();
if(input(pin_a1)) multiplicar();
if(input(pin_a0)) dividir();
if(b>1) ua=10*ua;
ua=a+ua;
a=0;
printf(lcd_data," %lu ",ua);
}}}

La línea roja.
Si usted presiona en pin_c4, es como presionar el número 3 en la calculadora.
El b=b+1 es para saber si ya se había presionado un número antes para hacer la
multiplicación por diez ( *10) , el delay_ms(200) es para que no se le vaya la mano y en
vez de presionar 3 le salga 333, porque es programa es muy rápido.

Las líneas azules.


Cuando se presiona el primer digito b=1
Cuando se presiona el segundo dígito b>1.

324
Si se presiona una tecla nueva se hace a !=0 y b>1 entonces
Se suman el valor presionado y el anterior multiplicado por 10 para tener el nuevo
valor, luego para que solo se sume una vez hacemos el valor recien entrado a 0 (a=0)
para que no se siga sumando cada vez que el programa da un clclo, recuerde que es un
bucle infinito.

----------------------------------------------------------------------------------
Programa ejemplo 21. Comunicaciones seriales.

Muchas veces necesitamos monitorear a cierta distancia los parámetros de algún


proceso que está siendo controlado por un microcontrolador que tiene incluido los
componentes electrónicos para realizar comunicación serial.

En el programa ejemplo 21, monitorearemos 2 temperaturas y la velocidad de 3


motores y transmitiremos esa información por el puerto serial a una computadora con
entrada por el puerto COM1

Programa ejemplo
#include <16f876a.h>
#fuses hs,nowdt,noprotect,put
#device adc=10
#use delay (clock=8000000)
#use rs232 (baud=9600, xmit=pin_c6,rcv=pin_c7)
#include <math.h>
#define mode 0
#define set_tris_x set_tris_b
#define input_x input_b
#define output_x output_b
#define rs pin_b2
#define stb pin_b3
#include <pant1.c>

void main (){


int m1,m2,m3,t1,t2,X;
set_tris_a(0b010011);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
setup_adc_ports (ra0_ra1_ra3_analog);
setup_adc(adc_clock_div_32);
setup_timer_0(rtcc_ext_l_to_h);
enable_interrupts(int_timer0);
enable_interrupts(global);
setup_ccp1(ccp_pwm);
setup_ccp2(ccp_pwm);
setup_timer_2(t2_div_by_1,255,1);
output_low(pin_a4);
set_timer0(0);
set_pwm1_duty(256);

325
set_pwm2_duty(512);
while (1){
set_adc_channel(0);
delay_ms(100);
t1=read_adc();
printf(lcd_data,"la temperatura 1 es %u ",t1);
lcd_cmd(192);

set_adc_channel(1);
delay_ms(100);
t2=read_adc();
printf(lcd_data,"la temperatura 2 es %u ",t1);
for (x=1;x<=10;x++) delay_ms(1000);

lcd_clear();
output_high(pin_a5);
output_high(pin_a4);
delay_ms(1000);
output_low(pin_a4);
output_low(pin_a5);
m1=get_timer0();
printf(lcd_data,"RPS Motor 1 = %u ",m1);
set_timer0(0);

lcd_cmd(192);
output_high(pin_a2);
output_high(pin_a4);
delay_ms(1000);
output_low(pin_a4);
output_low(pin_a2);
m2=get_timer0();
printf(lcd_data,"RPS Motor 2 = %u ",m2);
set_timer0(0);
for (x=1;x<=10;x++) delay_ms(1000);

lcd_clear();
output_high(pin_a2);
output_high(pin_a5);
output_high(pin_a4);
delay_ms(1000);
output_low(pin_a4);
output_low(pin_a2);
output_low(pin_a2);
m3=get_timer0();
printf(lcd_data,"RPS Motor 3 = %u ",m3);
lcd_cmd(192);
set_timer0(0);
for (x=1;x<=10;x++) delay_ms(1000);}}

326
En este programa se capta las temperaturas de los sensores conectados a las entradas
RA0 y RA1, y las velocidades de tres motores, y todo esa información la transmite por
el puerto de comunicación serial, usted debe conseguir un cable con un terminal DB9
hembra y conectarlo como está en el plano al puerto COM1 de la computadora y
ejecutar el programa SIO, que está en el directorio de PIC C.

327
C:\Archivos de programa\PICC

328
Icono del programa para supervisar el comunicación por el puerto serial.

Ventana del programa: Ahora deberá configurarla para adaptarla a nuestras necesidades.

Ingrese a configuración / Set port option

Y aparecerá la siguiente ventana

329
Verifique o coloque los siguiente parámetros

En ComPort Direct to COM1


En Buad rates 9600
En parury none
Data bits 8
Stop bits 1

Luego presione (clickee) OK

Mil gracias por haber estudiado.


Edgar Morales

INDICE GENERAL

Introducción 2
Temas a tratar 3
El microcontrolador 6
Plano del programador JDM 7

330
El PICpgm programmer 9
El puerto serial en las computadores PC 15
Sistemas de numeración 18
Directivas del PIC C 21
Notas sobre el enguaje C 26
Lineamientos del lenguaje C 27
Programar con el PIC C 28
Primer programa 31
Primer montaje 39
Lista de comandos C en este libro y parámetros para PICs 46
Bucles en C 61
Segundo montaje 81
La electrónica y el microcontrolador 88
El display 7 segmentos 92
El manejo del display 7 segmentos 95
Los decodificadores 7447, 7448 y 7449 103
Estrategias en electrónica digital 105
Las pantallas LCD 110
Las librerías en C 117
Conexión entre la pantalla y el PIC16F84 124
Circuitos integrados para electrónica digital TTL 141
Avance del PIC16F84 al PIC16f876 159
Repaso de los temas 160
El convertidor analógico digital 161
El modulador de ancho de pulsos 167
Ajuste de una señal 168
Los amplificadores operacionales 170
El capturador del CCP 172
La comunicación serial 174
El pinado del PIC16F876 176
El transductor sensor térmico LM35 181
Conexión entre la pantalla y el PIC16F876 187
Los optoacopladores 191
El convertidor digital analógico 194
Modulando pulsos para un motor DC 198
El transistor (generalidades) 202
El transistor TIP-122 208
Comunicación entre microcontroladores 211
El programa SIOW 213
Comandos que trabajan en grupo 216
Las funciones CCP 222
Las funciones de interrupción 229
Lista de errores comunes en principiantes 242
Cantidad mínima de componentes para las prácticas 244
La electrónica analógica 246
La electrónica digital 247
La electrónica de potencia 248
Circuitos TTL útiles y tabla de la verdad 249
Listado de circuitos TTL 254
Listado de circuitos CMOS 258

331
Listado de amplificadores operacionales 259
Listado de circuitos para comunicaciones 260
Listado de arreglos discretos 260
Listador de circuitos integrados lineales y reguladores 261
Listado de transistores 262
Caracteristicas del microcontrolador PIC16F84 y PIC16F84A 264
Características del microcontrolador PIC16F876 y PIC16F876A 269
Características del microcontrolador PIC16F877 276
Programas didacticos de inicio 294
Programas para manejo de pines y leds 295 - 307
Programas para el manejo de los displays 7 segmentos 309
Nota sobre el integrado TTL 74LS154 320
Nota sobre el integrado par darlintong 321
El motor paso a paso 326
Programas para el manejo de motores paso a paso 341
Segundo repaso antes de entrar al PIC16F876 349
Notación en electrónica 356
Símbolos en electrónica 360
Plano electrónico y plano lógico 362
Etalles del PIC16F876 364
Mecatrónica o robótica 372
Circuito básico para eplicaciones con el PIC16F876 373
Programa ejemplo para el control de motores DC 374
Programas ejemplo para el control de motores paso a paso 379
Programa ejemplo para control de temperatura y motor DC 385
Programa ejemplo de una calculadora básica 393
El manejo del programa SIOW del directorios de PIC C 404

332
MECATRÓNICA O ROBÓTICA

Desde el punto de vista de los ingenieros y especialistas en mecatrónica, robótica,


sistemas, electrónica, etc., y una vez que han sido superados los problemas electrónicos
y mecánicos (hardware), el buen funcionamiento de muchos aparatos depende casi
absolutamente de la programación, es decir, del programa de computadora que ese
aparato lleva por dentro y que lo pone a funcionar integrando todas sus partes, de ahí la
importancia de la programación y el conocimiento electrónico y mecánico del aparato,
pero ,y es que; además del conocimiento necesario para dominar un lenguaje de
computadoras y poder comunicarle a los aparatos y dispositivos programables cómo
desea el programador que se comporten, también es muy importante conocer la
electrónica de los aparatos desde el punto de vista de los chips, transistores, memorias,
motores, sensores etc., para conocer lo mejor posible su potencial y programarlo a
consciencia desde el punto de vista tanto de la misma programación como desde el
punto de vista electromecánico.

Piense que un microprocesador o microcontrolador es un cerebro en blanco y suelto, al


que le podemos conectar todos los órganos que podamos, le ponemos tacto con
sensores de contacto, ojos con sensores de proximidad y sensores de todo tipo de luz,
oídos con micrófonos, sentido de la orientación con giroscopios y brújulas electrónicas,
sentido del frío sensores de temperatura, sensores de la gravedad, locomoción con
motores y ruedas, e infinidad de mecanismos y otros sensores, y una vez conectado todo
esto, la mecánica y electrónica, lógicamente bien instalados, tenemos un robot que no
sabe hacer nada, ni hace nada, ahora solamente falta enseñarlo a hacer cosas, y en ese
momento es cuando nadie lo puede hacer nada, unicamente el programador.

En pocas palabras “El programa de un aparato programable, no es más que su


personalidad” de ahí viene la expresión: Este es un sistema amigable.

333

También podría gustarte