Prácticas de Microcontroladores PIC para Mecánica
Prácticas de Microcontroladores PIC para Mecánica
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.
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.
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.
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.
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).
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.
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).
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.
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).
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.
7
El PICPgm programmer
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
9
Ahora cliquee en el menú Programmer Connection seleccione en port com1
10
Pin configuration
Funtion pin
MCLR/Vpp 3
PGM/Vdd 0
Clock 7
Data Out 4
Data In 8
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).
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.
13
El puerto de comunicación serial COM1 en las computadoras.
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.
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
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.
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 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
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).
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:
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
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.
EL PIC C
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.
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)
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.
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.
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)
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.
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
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.
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.
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.
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.
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).
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.
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.
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:
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:
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.
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.
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 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
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.
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).
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
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
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)
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)
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)
38
LISTA DE COMANDOS Y DE DIRECTIVAS A EXPLICAR
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
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.
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.
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.
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.
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
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
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>.
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.
#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:
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).
47
Programa ejemplo.
#include <16f84a.h>
#fuses hs,nowdt,put
#use delay (clock=4000000)
void main()
{
a;
b;
a;
b;
a;
b;
}
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);
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)
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:
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
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
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.
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
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;
}
}
}
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.
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);
}
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 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.
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).
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);
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);
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);
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.
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.)
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.
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).
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).
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.
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.
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.
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
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).
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).
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.
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.
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.
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.
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);
}
}
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,
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);
}}}
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.
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);
}}}
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.
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.
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.
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á.
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.
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.
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 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.
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.
Ejemplo:
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”
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.
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.
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.
#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>
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),.
Los siguientes programas son muy sencillos, pero solo sirven para ilustrar como utilizar
los operadores
#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);
}
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.
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);
}
--------------------------------------------------------------------------
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: 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(); }}
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.
#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 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);
}
}
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);
}
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();
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.
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);
}
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
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.
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.
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.
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.
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;
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).
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).
#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.
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
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.
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.
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.
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).
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.
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.
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.
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.
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.
134
EL MODULADOR DE ANCHO DE PULSOS
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).
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.
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.
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.
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:
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)
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:
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.
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.
PIN 4:
RA2: Entrada o salida digital.
AN2: Entrada analógica 2.
VREF-: Voltaje de referencia negativo.
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 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 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 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 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.
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.
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.
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!).
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
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
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
#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.
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.
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.
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.
#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);
}}
153
Diodos azules 1N914, resistencias en leds 220 ohm.
LOS OPTOACOPLADORES
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.
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);
} }
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.
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.
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.
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);
} }
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.
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.
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) }}
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.
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.
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.
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.
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.
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.
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.
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.
170
Nota: la línea naranja es una fuente de energía de 15 voltios extra.
LA COMUNICACIÓN ENTRE LOS MICROCONTROLADORES
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:
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.
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);
} }
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.
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 );
} }
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
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.
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);
} }
178
Circuito para el programa anterior.
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.
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
Ahora:
¿Que es lo que se captura y cuando?:
Eventos posibles a configurar en los pines CCP para que lo anterior ocurra.
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.
#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;}}
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.
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).
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).
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.
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){ } }
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.
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.
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:
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ó.
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).
#INT_EXT
Void nombre () { }
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).
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:
¿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.
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);
}
}
190
Circuito recomendado para el programa anterior.
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.
191
vertical | ( su código ASCII es 124).
3ro.) No ponga condiciones que no se puedan cumplir simultáneamente.
-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);
- 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á.
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.
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.
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.
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.
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 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.
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.
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
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.
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).
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.
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
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
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).
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
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.
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.
205
TABLA DE COMPONENTES ELECTRONICOS
206
207
208
209
COMPONENTES CMOS 40XXXX
210
AMPLIFICADORES OPERACIONALES Y COMPARADORES
211
CIRCUITO INTEGRADOS PARA COMUNICACIONES
ARREGLOS DISCRETOS
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.
215
CARACTERISTICAS TECNICAS DEL
PIC16F84
Encapsulado de 18 pines.
Microcontrolador de 8 bits
.
La arquitectura de la CPU es del tipo HARVARD.
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.
216
Características de los periféricos incorporados.
OTRAS CARACTERISTICAS.
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.
218
CARACTERISTICAS TECNICAS 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.
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
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.
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.
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.
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.
#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.
Nota: Las sentencias que inicializan ciclos no llevan punto y coma (;) al final de la
línea.
#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.
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);
}
}
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.
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.
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.
#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
#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)
#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)
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); } } }
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.
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í.
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);
}}
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.
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.
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.
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.
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.
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.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)
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.
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); }}}
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.
A = [9743/1000] = [9.743] = 9
B= [ (9743-A*1000) / 100 ]
B= [ (9743-9*1000) / 100 ] = [ (9743-9000) / 100 ] = [ (743) / 100 ] =
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
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.
263
Ejemplo: A B C
El Par Darlington:
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.
Programa ejemplo 11. Haga un programa que informe cual o cuales botones tiene
presionados como entrada el microcontrolador.
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. 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.
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.
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.
En el programa 11.1 sólo con explicar una línea se entiende todo lo demás.
---------------------------------------------------------------------------------------------------
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);
output_b(x): Saca por el puerto B, el valor de x que fue leído del puerto A.
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.
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; }}}}}
#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; }}} } }
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.
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.
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
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.
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; }}}
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
#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:
}}
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
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
278
El programa es realmente simple.
3ro) Extraemos (tomamos) el valor contado por el timer0 y lo asignamos a una variable.
Ejemplo rps=get_timer0();
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.
¡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>
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);}}
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
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.
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.
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.
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.
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: 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.
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.
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)
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).
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).
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.
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.
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.
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.
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 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
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.
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.
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.
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 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:
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.
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.
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.
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 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
#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); }}
El transistor es tipo NPN TIP122, el que con un voltaje de 5 voltios y 0.12 Amperes se
controlan 100Voltios y 5 Amperes
303
Encabezado
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.
304
Puerto B Todos los pines son salida digital.
Puerto C Todos los pines son salida digital.
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).
---------------------------------------------------------------------------------
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.
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--
#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;
}}
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.
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
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.
-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.
----------------------------------------------------------------------------
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.
#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();
}}
314
Circuito recomendado para el programa 19
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.
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.
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);}
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.
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.
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.
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.
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.
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>
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.
329
Verifique o coloque los siguiente parámetros
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
333