Capitulo 4 Microcontrolador
Capitulo 4 Microcontrolador
Capitulo 4 Microcontrolador
Alimentación;
Señal de reinicio; y
Señal de reloj.
1
Como se muestra en la figura anterior, se trata de circuitos simples, pero no tiene que ser
siempre así. Si el dispositivo destino se utiliza para controlar las máquinas caras o para
mantener funciones vitales, todo se vuelve mucho más complicado.
ALIMENTACIÓN
SEÑAL DE REINICIO
2
SEÑAL DE RELOJ
¿Por qué son estos modos importantes? Como es casi imposible construir un oscilador
estable que funcione a un amplio rango de frecuencias, el microcontrolador tiene que
“saber” a qué cristal está conectado, para poder ajustar el funcionamiento de sus
componentes internos. Ésta es la razón por la que todos los programas utilizados para
escribir un programa en el chip contienen una opción para seleccionar el modo de
oscilador. Vea la figura de la izquierda.
Cristal de cuarzo
3
valores proporcionados en la siguiente tabla se deben tomar como recomendación y no
como regla estricta.
Resonador cerámico
Un resonador cerámico es más barato y muy similar a un cuarzo por la función y el modo
de funcionamiento. Por esto, los esquemas que muestran su conexión al microcontrolador
son idénticos. No obstante, los valores de los condensadores difieren un poco debido a las
diferentes características eléctricas. Refiérase a la tabla que está a continuación.
Oscilador RC
4
Oscilador externo
Los interruptores y los botones de presión son los dispositivos simples para proporcionar la
forma más simple de detectar la aparición de voltaje en un pin de entrada del
microcontrolador. No obstante, no es tan simple como parece... Es por un rebote de
contacto. El rebote de contacto es un problema común en los interruptores mecánicos.
5
Al tocarse los contactos, se produce un rebote por su inercia y elasticidad. Por consiguiente,
la corriente eléctrica es rápidamente pulsada en lugar de tener una clara transición de cero a
la corriente máxima. Por lo general, esto ocurre debido a las vibraciones, los desniveles
suaves y la suciedad entre los contactos. Este efecto no se percibe normalmente al utilizar
estos componentes en la vida cotidiana porque el rebote ocurre demasiado rápido para
afectar a la mayoría de los dispositivos eléctricos. Sin embargo, pueden surgir problemas en
algunos circuitos lógicos que responden lo suficientemente rápido de manera que
malinterpreten los pulsos producidos al tocarse los contactos como un flujo de datos. De
todos modos, el proceso entero no dura mucho (unos pocos micro - o milisegundos), pero
dura lo suficiente para que lo detecte el microcontrolador. Al utilizar sólo un botón de
presión como una fuente de señal de contador, en casi 100% de los casos ocurren los
errores.
El problema se puede resolver con facilidad al conectar un simple circuito RC para suprimir
rápidos cambios de voltaje. Como el período del rebote no está definido, los valores de los
componentes no están precisamente determinados. En la mayoría de los casos es
recomendable utilizar los valores que se muestran en la siguiente figura.
6
Si se necesita una estabilidad completa, entonces hay que tomar medidas radicales. La
salida del circuito, mostrado en la siguiente figura (biestable RS, también llamado flip flop
RS), cambiará de estado lógico después de detectar el primer pulso producido por un rebote
de contacto. Esta solución es más cara (interruptor SPDT), pero el problema es resuelto.
Aparte de estas soluciones de hardware, hay también una simple solución de software.
Mientras el programa prueba el estado de circuito lógico de un pin de entrada, si detecta un
cambio, hay que probarlo una vez más después de un cierto tiempo de retardo. Si el
programa confirma el cambio, esto significa que un interruptor/botón de presión ha
cambiado de posición. Las ventajas de esta solución son obvias: es gratuita, se borran los
efectos del rebote de contacto y se puede aplicar a los contactos de una calidad más baja
también.
RELÉ
Un relé es un interruptor eléctrico que se abre y se cierra bajo el control de otro circuito
electrónico. Por eso está conectado a los pines de salida del microcontrolador y utilizado
para encender/apagar los dispositivos de alto consumo tales como: motores,
transformadores, calefactores, bombillas etc. Estos dispositivos se colocan casi siempre
lejos de los componentes sensibles de la placa. Hay varios tipos de relés, pero todos
funcionan de la misma manera. Al fluir la corriente por la bobina, el relé funciona por
medio de un electromagneto, abriendo y cerrando uno o más conjunto de contactos. Similar
a los optoacopladores no hay conexión galvánica (contacto eléctrico) entre los circuitos de
entrada y salida. Los relés requieren con frecuencia tanto un voltaje más alto y una
corriente más alta para empezar a funcionar. También hay relés miniatura que se pueden
poner en marcha por una corriente baja obtenida directamente de un pin del
microcontrolador.
7
La figura que sigue muestra la solución utilizada con más frecuencia.
Para prevenir la aparición de un alto voltaje de autoinducción, causada por una parada
repentina del flujo de corriente por la bobina, un diodo polarizado invertido se conecta en
paralelo con la bobina. El propósito de este diodo es de “cortar” este pico de voltaje.
DIODOS LED
Probablemente sepa todo lo que necesita saber sobre los diodos LED, pero también debe
pensar en los jóvenes... A ver, ¿cómo destruir un LED? Bueno...muy fácil.
8
Quemar con rapidez
Como cualquier otro diodo, los LEDs tienen dos puntas - un ánodo y un cátodo. Conecte un
diodo apropiadamente a la fuente de alimentación y va a emitir luz sin ningún problema.
Ponga al diodo al revés y conéctelo a la misma fuente de alimentación (aunque sea por un
momento). No emitirá luz - ¡nunca más!
Quemar lentamente
Hay un límite de corriente nominal, o sea, límite de corriente máxima especificada para
cada LED que no se deberá exceder. Si eso sucede, el diodo emitirá luz más intensiva, pero
sólo por un período corto de tiempo.
De manera similar, todo lo que tiene que hacer es elegir una resistencia para limitar la
corriente mostrada a continuación. Dependiendo de voltaje de alimentación, los efectos
pueden ser espectaculares.
VISUALIZADOR LED
9
Básicamente, un visualizador LED no es nada más que varios diodos LED moldeados en la
misma caja plástica. Hay varios tipos de los visualizadores y algunos de ellos están
compuestos por varias docenas de diodos incorporados que pueden visualizar diferentes
símbolos. No obstante, el visualizador utilizado con más frecuencia es el visualizador de 7
segmentos. Está compuesto por 8 LEDs. Los siete segmentos de un dígito están
organizados en forma de un rectángulo para visualizar los símbolos, mientras que el
segmento adicional se utiliza para el propósito de visualizar los puntos decimales. Para
simplificar la conexión, los ánodos y los cátodos de todos los diodos se conectan al pin
común así que tenemos visualizadores de ánodo común y visualizadores de cátodo común,
respectivamente. Los segmentos están etiquetados con letras de a a g y dp, como se muestra
en la siguiente figura. Al conectarlos, cada diodo LED se trata por separado, lo que
significa que cada uno dispone de su propia resistencia para limitar la corriente.
Aquí le presentamos unas cosas importantes a las que debe prestar atención al comprar un
visualizador LED:
10
Los visualizadores conectados al microcontrolador normalmente ocupan un gran número de
los pines de E/S valiosos, lo que puede ser un problema sobre todo cuando se necesita
visualizar los números compuestos por varios dígitos. El problema se vuelve más obvio si,
por ejemplo, se necesita visualizar dos números de seis dígitos (un simple cálculo muestra
que en este caso se necesitan 96 pines de salida). La solución de este problema es
denominada multiplexión.
Veamos la figura anterior. Primero se aplica un byte que representa unidades al puerto
PORT2 del microcontrolador y se activa el transistor T1 a la vez. Después de poco tiempo,
11
el transistor T1 se apaga, un byte que representa decenas se aplica al puerto PORT2 y el
transistor T2 se activa. Este proceso se está repitiendo cíclicamente a alta velocidad en
todos los dígitos y transistores correspondientes.
Antes que nada, un número de varios dígitos debe ser dividido en unidades, centenas etc. en
una subrutina específica. Luego, cada de estos dígitos se debe almacenar en los bytes
particulares. Los dígitos se hacen reconocibles al realizar "enmascaramiento". En otras
palabras, el formato binario de cada dígito se sustituye por una combinación diferente de
los bits por medio de una subrutina simple. Por ejemplo, el dígito 8 (0000 1000) se
sustituye por el número binario 0111 1111 para activar todos los LEDs que visualizan el
número 8. El único diodo que queda inactivo aquí está reservado para el punto decimal.
Si un puerto del microcontrolador está conectado al visualizador de tal manera que el bit 0
active el segmento 'a', el bit 1 active el segmento 'b', el bit 2 active el segmento 'c' etc,
entonces la tabla que sigue muestra la "máscara" para cada dígito.
Dígitos a
Segmentos del vi sualizador
visualizar
dp a b c d e f g
0 0 1 1 1 1 1 1 0
1 0 0 1 1 0 0 0 0
2 0 1 1 0 1 1 0 1
12
3 0 1 1 1 1 0 0 1
4 0 0 1 1 0 0 1 1
5 0 1 0 1 1 0 1 1
6 0 1 0 1 1 1 1 1
7 0 1 1 1 0 0 0 0
8 0 1 1 1 1 1 1 1
9 0 1 1 1 1 0 1 1
En caso de que se utilicen los visualizadores de ánodo común, todos los unos contenidos en
la tabla anterior se deben sustituir por ceros y viceversa. Además, los transistores PNP se
deben utilizar como controladores.
OPTOACOPLADORES
13
La red R/C representada por una línea quebrada en la figura anterior indica una conexión
opcional de la base de transistores dentro del optoacoplador, que reduce los efectos de
ruidos al eliminar los pulsos muy cortos.
VISUALIZADOR LCD
Este componente está específicamente fabricado para ser utilizado con los
microcontroladores, lo que significa que no se puede activar por los circuitos integrados
estándar. Se utiliza para visualizar los diferentes mensajes en un visualizador de cristal
líquido miniatura. El modelo descrito aquí es el más utilizado en la práctica por su bajo
precio y grandes capacidades. Está basado en el microcontrolador HD44780 (Hitachi)
integrado y puede visualizar mensajes en dos líneas con 16 caracteres cada una. Puede
visualizar todas las letras de alfabeto, letras de alfabeto griego, signos de puntuación,
símbolos matemáticos etc. También es posible visualizar símbolos creados por el usuario.
Entre otras características útiles es el desplazamiento automático de mensajes (a la
izquierda y a la derecha), aparición del cursor, retroiluminación LED etc.
14
Pines del visualizador LCD
A lo largo de un lado de una placa impresa pequeña del visualizador LCD se encuentran los
pines que le permiten estar conectado al microcontrolador. Hay 14 pines en total marcados
con números (16 si hay retroiluminación). Su función se muestra en la tabla que sigue:
Pantalla LCD
Una pantalla LCD puede visualizar dos líneas con 16 caracteres cada una. Cada carácter
consiste en 5x8 o 5x11 píxeles. Este libro cubre un visualizador de 5x8 píxeles que es
utilizado con más frecuencia.
15
El contraste del visualizador depende del voltaje de alimentación y de si los mensajes se
visualizan en una o dos líneas. Por esta razón, el voltaje variable 0-Vdd se aplica al pin
marcado como Vee. Un potenciómetro trimer se utiliza con frecuencia para este propósito.
Algunos de los visualizadores LCD tienen retroiluminación incorporada (diodos LED
azules o verdes). Al utilizarlo durante el funcionamiento, se debe de conectar una
resistencia en serie a uno de los pines para limitar la corriente (similar a diodos LED).
16
Memoria LCD
Memoria DDRAM
La memoria DDRAM se utiliza para almacenar los caracteres a visualizar. Tiene una
capacidad de almacenar 80 caracteres. Algunas localidades de memoria están directamente
conectadas a los caracteres en el visualizador.
Todo funciona muy simple: basta con configurar el visualizador para incrementar
direcciones automáticamente (desplazamiento a la derecha) y establecer la dirección inicial
para el mensaje que se va a visualizar (por ejemplo 00 hex).
Luego, todos los caracteres enviados por las líneas D0-D7 se van a visualizar en el formato
de mensaje al que nos hemos acostumbrado - de la izquierda a la derecha. En este caso, la
visualización empieza por el primer campo de la primera línea ya que la dirección inicial es
00hex. Si se envía más de 16 caracteres, todos se memorizarán, pero sólo los primeros 16
serán visibles. Para visualizar los demás, se debe utilizar el comando shift. Virtualmente,
parece como si el visualizador LCD fuera una ventana, desplazándose de la izquierda a la
derecha sobre las localidades de memoria con diferentes caracteres. En realidad, así es
cómo se creó el efecto de desplazar los mensajes sobre la pantalla.
Esto es un tipo de memoria RAM así que los datos se pueden escribir en ella y leer de ella,
pero su contenido se pierde irrecuperablemente al apagar la fuente de alimentación.
Memoria CGROM
La memoria CGROM contiene un mapa estándar de todos los caracteres que se pueden
visualizar en la pantalla. A cada carácter se le asigna una localidad de memoria:
17
Las direcciones de las localidades de memoria CGROM corresponden a los caracteres
ASCII. Si el programa que se está actualmente ejecutando llega al comando ‘enviar el
carácter P al puerto’, el valor binario 0101 0000 aparecerá en el puerto. Este valor es el
equivalente ASCII del carácter P. Al escribir este valor en un LCD, se visualizará el
símbolo de la localidad 0101 0000 de la CGROM. En otras palabras, se visualizará el
carácter P. Esto se aplica a todas las letras del alfabeto (minúsculas y mayúsculas), pero no
se aplica a los números.
18
Como se muestra en el mapa anterior, las direcciones de todos los dígitos se desplazan por
48 en relación con sus valores (dirección del dígito 0 es 48, dirección del dígito 1 es 49,
dirección del dígito 2 es 50 etc.). Por consiguiente, para visualizar los dígitos correctamente
es necesario añadir el número decimal 48 a cada uno antes de enviarlos a un LCD.
¿Qué es un código ASCII? Desde su aparición hasta hoy en día, las computadoras han sido
capaces de reconocer solamente números, y no las letras. Esto significa que todos los datos
que una computadora intercambia con un periférico, reconocidos como letras por los
humanos, en realidad están en el formato binario (el teclado es un buen ejemplo). En otras
palabras, a cada carácter le corresponde la combinación única de ceros y unos. El código
ASCII representa una codificación de caracteres basada en el alfabeto inglés. El ASCII
especifica una correspondencia entre los símbolos de caracteres estándar y sus equivalentes
numéricos.
19
Memoria CGRAM
Los registros de memoria son de 8 bits de anchura, pero sólo se utilizan 5 bits más bajos.
Un uno lógico (1) en cada registro representa un punto oscurecido, mientras que 8
localidades agrupados representan un carácter. Esto se muestra en la siguiente figura:
Los símbolos están normalmente definidos al principio del programa por una simple
escritura de ceros y unos de la memoria CGRAM así que crean las formas deseadas. Para
visualizarlos basta con especificar su dirección. Preste atención a la primera columna en el
mapa de caracteres CGROM. No contiene direcciones de la memoria RAM, sino los
símbolos de los que se está hablando aquí. En este ejemplo ‘visualizar 0’ significa
visualizar ‘sonrisa’, ‘visualizar 1’ significa - visualizar ‘ancla’ etc.
20
Comandos básicos del visualizador LCD
Todos los datos transmitidos a un visualizador LCD por las salidas D0-D7 serán
interpretados como un comando o un dato, lo que depende del estado lógico en el pin RS:
Tiempo de
Comando RS RW D7 D6 D5 D4 D3 D2 D1 D0
ejecución
Borrar el visualizador 0 0 0 0 0 0 0 0 0 1 1.64mS
Poner el cursor al inicio 0 0 0 0 0 0 0 0 1 x 1.64mS
Modo de entrada 0 0 0 0 0 0 0 1 I/D S 40uS
Activar/desactivar el
0 0 0 0 0 0 1 D U B 40uS
visualizador
Desplazar el cursor/visualizador 0 0 0 0 0 1 D/C R/L x x 40uS
Modo de funcionamiento 0 0 0 0 1 DL N F x x 40uS
Establecer la dirección CGRAM 0 0 0 1 Dirección CGRAM 40uS
Establecer la dirección DDRAM 0 0 1 Dirección CGRAM 40uS
Leer la bandera
0 1 BF Dirección CGRAM -
"BUSY"(ocupado) (BF)
Escribir en la CGRAM o en la
1 0 D7 D6 D5 D4 D3 D2 D1 D0 40uS
DDRAM
Leer la CGRAM o la DDRAM 1 1 D7 D6 D5 D4 D3 D2 D1 D0 40uS
I/D 1 = Incremento (por 1) R/L 1 =
Desplazamiento a la derecha
0 = Decremento (por 1) 0 =
Desplazamiento a la izquierda
21
0 = Cursor desactivado 0 = Carácter de
5x7 puntos
Pocas veces se leen los datos del LCD (por lo general se transmiten del microcontrolador al
LCD) así que, con frecuencia, es posible guardar un pin de E/S de sobra. Es simple, basta
con conectar el pin L/E a Tierra. Este “ahorro” del pin tiene su precio. Los mensajes se
22
visualizarán normalmente, pero no será posible leer la bandera de ocupado ya que tampoco
es posible leer los datos del visualizador. Afortunadamente, hay una solución simple.
Después de enviar un carácter o un comando es importante dar al LCD suficiente tiempo
para hacer su tarea. Debido al hecho de que la ejecución de un comando puede durar
aproximadamente 1.64mS, el LCD tarda como máximo 2mS en realizar su tarea.
Por lo general, el reinicio automático se lleva a cabo sin problemas. ¡En la mayoría de los
casos, pero no siempre! Si por cualquier razón, el voltaje de alimentación no llega a su
máximo valor en 10mS, el visualizador se pone a funcionar de manera completamente
imprevisible. Si la unidad de voltaje no es capaz de cumplir con las condiciones o si es
necesario proporcionar un funcionamiento completamente seguro, se aplicará el proceso de
inicialización. La inicialización, entre otras cosas, reinicia de nuevo al LCD, al habilitarle
un funcionamiento normal.
Refiérase a la Figura que sigue para el procedimiento de inicialización por el bus de datos
de 8 bits:
23
¡Esto no es un error! En este algoritmo, el mismo valor se transmite tres veces en fila.
24
Vamos a hacerlo en mikroC...
/* En mikroC for PIC, basta con escribir sólo una función para realizar
todo el proceso
de la inicialización del LCD. Antes de llamar esta función es necesario
declarar los
bits LCD_D4-LCD_D7, LCD_RS y LCD_EN. */
...
Lcd_Init(); // Inicializar el LCD
...
25
EJEMPLOS PRÁCTICOS
El proceso de crear un proyecto nuevo es muy simple. Seleccione la opción New Project
del menú Project como se muestra en la Figura de la derecha.
Aparecerá una ventana que le guiará a través del proceso de creación de un proyecto nuevo.
La ventana de entrada de este programa contiene una lista de acciones a realizar para crear
un proyecto nuevo. Pulse el botón Next.
26
El proceso de creación de un proyecto nuevo consiste en cinco pasos:
Después de crear el proyecto, aparecerá una ventana blanca en la que debe escribir el
programa. Vea la siguiente figura:
27
Una vez creado el programa, es necesario compilarlo en un código .hex. Seleccione una de
las opciones para compilar del menú Project:
Para crear un archivo .hex, seleccione la opción Build (Ctrl+F9) del menú Project o
pulse sobre el icono Build de la barra de herramientas Project.
Por medio de la opción Build All Projects (Shift+F9) se compilan todos los archivos
del proyecto, librerías (si el código fuente contiene alguna de ellas) y los archivos
def para el microcontrolador utilizado.
La opción Build + Program (Ctrl+F11) es importante ya que permite al compilador
mikroC PRO for PIC cargar automáticamente el programa en el microcontrolador
después de la compilación. El proceso de la programación se realiza por medio del
programador PICFlash.
4.3 EJEMPLO 1
Escribir cabecera, configurar pines de E/S, utilizar la función Delay y el
operador Switch
28
Al encender la fuente de alimentación, cada segundo, el diodo LED en el puerto B emite
luz, lo que indica que el microcontrolador está conectado correctamente y que funciona
normalmente.
En este ejemplo se muestra cómo escribir una cabecera correctamente. Lo mismo se aplica
a todos los programas descritos en este libro. Para no repetir, en los siguientes ejemplos no
vamos a escribir la cabecera. Se considera estar en el principio de cada programa, marcada
como "Cabecera".
29
Para hacer este ejemplo más interesante, vamos a habilitar que los LEDs conectados al
puerto PORTB parpadeen. Hay varios modos de hacerlo:
1. Tan pronto como se encienda el microcontrolador, todos los LEDs emitirán la luz
por un segundo. La función Delay se encarga de eso en el programa. Sólo se
necesita ajustar la duración del tiempo de retardo en milisegundos.
2. Después de un segundo, el programa entra en el bucle for, y se queda allí hasta que
la variable k sea menor que 20. La variable se incrementa en 1 después de cada
iteración. Dentro del bucle for, el operador switch monitorea el estado lógico en el
puerto PORTB. Si PORTB=0xFF, su estado se invierte en 0x00 y viceversa.
Cualquier cambio de estos estados lógicos hace todos los LEDs parpadear. El ciclo
de trabajo es 5:1 (500mS:100mS).
3. Al salir del bucle for, el estado lógico del puerto POTRB cambia (0xb 01010101) y
el programa entra en el bucle infinito while y se queda allí hasta que 1=1. El estado
lógico del puerto PORTB se invierte cada 200mS.
30
4.4 EJEMPLO 2
Utilizar instrucciones en ensamblador y el oscilador interno LFINTOSC...
En realidad, esto es una continuación del ejemplo anterior, pero se ocupa de un problema
un poco más complicado... El propósito era hacer los LEDs en el puerto PORTB parpadear
lentamente. Se puede realizar al introducir un valor suficiente grande para el parámetro del
tiempo de retardo en la función Delay. No obstante, hay otra manera más eficiente para
ejecutar el programa lentamente. Acuérdese de que este microcontrolador tiene un oscilador
31
incorporado LFINTOSC que funciona a una frecuencia de 31kHz. Ahora llegó la hora de
“darle una oportunidad”.
El programa se inicia con el bucle do-while y se queda allí por 20 ciclos. Después da cada
iteración, llega el tiempo de retardo de 100ms, indicado por un parpadeo relativamente
rápido de los LEDs en el puerto PORTB. Cuando el programa salga de este bucle, el
microcontrolador se inicia al utilizar el oscilador LFINTOSC como una fuente de señal de
reloj. Los LEDs parpadean más lentamente aunque el programa ejecuta el mismo bucle do-
while con un tiempo de retardo 10 veces más corto.
/* Cabecera *********************************************/
void main() {
ANSEL = 0; // Todos los pines de E/S se configuran
como digitales
ANSELH = 0;
PORTB = 0; // Todos los pines del puerto PORTB se
ponen a 0
TRISB = 0; // Pines del puerto PORTB se configuran
como salidas
do {
PORTB = ~PORTB; // Invertir el estado lógico del puerto
PORTB
Delay_ms(100); // Tiempo de retardo de 100mS
k++; // Incrementar k en 1
}
while(k<20); // Quedarse en bucle hasta que k<20
32
bcf OSCCON,5 // de frecuencia de 31KHz
bcf OSCCON,4
bsf OSCCON,0 // Microcontrolador utiliza oscilador
interno
} // Final de la secuencia en ensamblador
do {
PORTB = ~PORTB; // Invertir el estado lógico del puerto
PORTB
Delay_ms(10); // Tiempo de retardo de 10 mS
k++; // Incrementar k en 1
}
while(k<20); // Quedarse en el bucle hasta que k<20
}
4.5 EJEMPLO 3
Timer0 como un contador, declarar variables nuevas, constantes de enumeración,
utilizar relés...
33
/*Cabecera****************************************************/
void main() {
char TEST = 5; // Constante TEST = 5
enum salidas {RELÉ = 3}; // Constante RELAY = 3
do {
if (TMR0 == TEST) // ¿Coincide el número en el temporizador con
la
// constante TEST?
(PORTD.RELAY = 1); // Números coinciden. Poner el bit RD3 a uno
(salida RELÉ)
34
}
while (1); // Quedarse en el bucle infinito
}
Sólo una constante de enumeración RELÉ se utiliza en este ejemplo. Se le asigna un valor
mediante la declaración.
Si varios pines del puerto PORTD están conectados a los relés, la expresión anterior se
puede escribir de la siguiente manera también:
A todas las constantes, precedidas por las constantes con valores asignados (RELÉ=3 y
MOTOR=6), se les asignan automáticamente los valores de las constantes precedentes,
incrementados en 1. En este ejemplo, a las constantes CALENTADOR y SURTIDOR se
les asignan los valores 4 y 7, es decir (CALENTADOR=4 y SURTIDOR=7),
respectivamente.
4.6 EJEMPLO 4
Utilizar los temporizadores Timer0, Timer1 y Timer2. Utilizar
interrupciones, declarar nuevas funciones...
¿Se acuerda usted del capítulo de los temporizadores? ¿Se acuerda de lo de interrupciones?
Este ejemplo los conecta de una manera práctica. El esquema se queda inalterada, y el
desafío sigue siendo presente. Es necesario proporcionar un tiempo de retardo suficiente
largo para darse cuenta de los cambios en el puerto. Para este propósito se utiliza el
temporizador Timer0 con el pre-escalador asignado. Siempre que se genere una
interrupción con cada desbordamiento en el registro del temporizador, la variable cnt se
aumenta automáticamente en 1 al ejecutarse cada rutina de interrupción. Cuando la variable
llega al valor 400, el puerto PORTB se incrementa en 1. Todo el procedimiento se lleva a
cabo “entre bastidores”, lo que habilita al microcontrolador hacer otra tarea.
35
/*Cabecera******************************************************/
void interrupt() {
cnt++; // Con una interrupción la cnt se incrementa en 1
TMR0 = 96; // El valor inicial se devuelve en el temporizador
TMR0
INTCON = 0x20; // Bit T0IE se pone a 1, el bit T0IF se pone a 0
}
void main(){
OPTION_REG = 0x84; // Pre-escalador se le asigna al temporizador TMR0
ANSEL = 0; // Todos los pines de E/S se configuran como
digitales
ANSELH = 0;
TRISB = 0; // Todos los pines de puerto PORTB se configuran
// como salidas
PORTB = 0x0; // Reiniciar el puerto PORTB
TMR0 = 96; // Temporizador T0 cuenta de 96 a 255
INTCON = 0xA0; // Habilitada interrupción TMR0
cnt = 0; // A la variable cnt se le asigna un 0
do { // Bucle infinito
36
if (cnt == 400) { // Incrementar el puerto PORTB después 400
interrupciones
PORTB = PORTB++; // Incrementar número en el puerto PORTB en 1
cnt = 0; // Reiniciar la variable cnt
}
} while(1);
/*Cabecera******************************************************/
void interrupt() {
cnt++ ; // Con una interrupción la cnt se incrementa en 1
PIR1.TMR1IF = 0; // Reiniciar el bit TMR1IF
TMR1H = 0x80; // El valor inicial se devuelve en los registros
TMR1L = 0x00; // del temporizador TMR1H y TMR1L
}
void main() {
ANSEL = 0; // Todos los pines de E/S se configuran como
digitales
ANSELH = 0;
PORTB = 0xF0; // Valor inicial de los bits del puerto PORTB
TRISB = 0; // Pines del puerto PORTB se configuran como
salidas
T1CON = 1; // Configurar el temporizador TMR1
PIR1.TMR1IF = 0; // Reiniciar el bit TMR1IF
TMR1H = 0x80; // Ajustar el valor inicial del temporizador TMR1
TMR1L = 0x00;
PIE1.TMR1IE = 1; // Habilitar la interrupción al producirse un
desbordamiento
cnt = 0; // Reiniciar la variable cnt
INTCON = 0xC0; // Interrupción habilitada (bits GIE y PEIE)
do { // Bucle infinito
if (cnt == 76) { // Cambiar el estado del puerto PORTB después de 76
interrupciones
PORTB = ~PORTB; // Número en el puerto PORTB está invertido
cnt = 0; // Reiniciar la variable cnt
}
} while (1);
}
37
En este caso, una interrupción se habilita después de que se produzca un desbordamiento en
el registro del temporizador TMR1 (TMR1H, TMR1L). Además, la combinación de los bits
que varía en el puerto POTRB difiere de la en el ejemplo anterior.
/*Cabecera******************************************************/
void Reemplazar() {
PORTB = ~PORTB; // Definir nueva función ‘Reemplazar’
} // Función invierte el estado del puerto
void interrupt() {
if (PIR1.TMR2IF) { // Si el bit TMR2IF = 1,
cnt++ ; // Incrementar variable la cnt en 1
PIR1.TMR2IF = 0; // Reiniciar el bit y
TMR2 = 0; // Reiniciar el registro TMR2
}
}
// main
void main() {
cnt = 0; // Reiniciar la variable cnt
ANSEL = 0; // Todos los pines de E/S se configuran como
digitales
ANSELH = 0;
PORTB = 0b10101010; // Estado lógico en los pines del puerto PORTB
TRISB = 0; // Todos los pines del puerto PORTB se configuran
como salidas
T2CON = 0xFF; // Configurar el temporizador T2
TMR2 = 0; // Valor inicial del registro del temporizador TMR2
PIE1.TMR2IE = 1; // Interrupción habilitada
INTCON = 0xC0; // Bits GIE y PEIE se ponen a 1
38
En este ejemplo, una interrupción ocurre después de que se produce un desbordamiento en
el registro del temporizador TMR2. Para invertir el estado lógico de los pines del puerto se
utiliza la función Reemplazar, que normalmente no pertenece al lenguaje C estándar.
4.7 EJEMPLO 5
Utilizar el temporizador perro - guardián
/*Cabecera******************************************************/
39
void main() {
OPTION_REG = 0x0E; // Pre-escalador se le asigna al temporizador WDT
(1:64)
asm CLRWDT; // Comando en ensamblador para reiniciar el
temporizador WDT
PORTB = 0x0F; // Valor inicial del registro PORTB
TRISB = 0; // Todos los pines del puerto PORTB se configuran
como salidas
Delay_ms(300); // Tiempo de retardo de 30mS
PORTB = 0xF0; // Valor del puerto PORTB diferente del inicial
4.8 EJEMPLO 6
Módulo CCP1 como generador de señal PWM
Este ejemplo muestra el uso del módulo CCP1 en modo PWM. Para hacer las cosas más
interesantes, la duración de los pulsos en la salida P1A (PORTC,2) se puede cambiar por
medio de los botones de presión simbólicamente denominados ‘OSCURO’ y ‘CLARO’. La
duración ajustada se visualiza como una combinación binaria en el puerto PORTB. El
funcionamiento de este módulo está bajo el control de las funciones pertenecientes a la
librería especializada PWM. Aquí se utilizan las tres de ellas:
La librería PWM también contiene la función PWM_Stop utilizada para deshabilitar este
modo. Su prototipo es: void Pwm1_Stop(void);
40
/*Cabecera******************************************************/
void initMain() {
ANSEL = 0; // Todos los pines de E/S se configuran como digitales
ANSELH = 0;
PORTA = 255; // Estado inicial del puerto PORTA
TRISA = 255; // Todos los pines del puerto PORTA se configuran como
entradas
PORTB = 0; // Estado inicial del puerto PORTB
TRISB = 0; // Todos los pines del puerto PORTB se configuran como
salidas
PORTC = 0; // Estado inicial del puerto PORTC
TRISC = 0; // Todos los pines del puerto PORTC se configuran
// como salidas
PWM1_Init(5000); // Inicialización del módulo PWM (5KHz)
}
void main() {
initMain();
ciclo_de_trabajo_actual = 16; // Valor inicial de la variable
ciclo_de_trabajo_actual
ciclo_de trabajo_anterior = 0; // Reiniciar la variable ciclo_de
trabajo_anterior
PWM1_Start(); // Iniciar el módulo PWM1
41
if (Button(&PORTA, 1,1,1)) // Si se presiona el botón conectado
al RA1
ciclo_de_trabajo_actual-- ; // decrementar el valor de la variable
current_duty
if (old_duty != ciclo_de_trabajo_actual) { // Si
ciclo_de_trabajo_actual y
// ciclo_de trabajo_anterior no son iguales
PWM1_Set_Duty(ciclo_de_trabajo_actual); // ajustar un
nuevo valor a PWM,
ciclo_de trabajo_anterior = ciclo_de_trabajo_actual; // Guardar el
nuevo valor
PORTB = ciclo_de trabajo_anterior; // y
visualizarlo en el puerto PORTB
}
Delay_ms(200); // Tiempo de retardo de 200mS
}
}
Para que este ejemplo funcione apropiadamente, es necesario marcar las siguientes librerías
en la ventana Library Manager antes de compilar el programa:
PWM
Button
4.9 EXAMPLE 7
Utilizar el convertidor A/D
El convertidor A/D del microcontrolador PIC16F887 se utiliza en este ejemplo. ¿Hace falta
decir que todo es pan comido? Una señal analógica variable se aplica al pin AN2, mientras
que el resultado de la conversión de 10 bits se muestra en los puertos POTRB y PORTD (8
bits menos significativos en el puerto PORTD y 2 bits más significativos en el puerto
PORTB). La Tierra (GND) se utiliza como voltaje de referencia bajo Vref-, mientras que el
voltaje de referencia alto se aplica al pin AN3. Esto habilita que la escala de medición se
estire y encoja.
IEn otras palabras, el convertidor A/D siempre genera un resultado binario de 10 bits, lo
que significa que reconoce 1024 niveles de voltaje en total (210=1024). La diferencia entre
dos niveles de voltaje no es siempre la misma. Cuánto menor sea la diferencia entre Vref+
y Vref-, tanto menor será la diferencia entre dos de 1024 niveles. Como hemos visto, el
convertidor A/D es capaz de detectar pequeños cambios de voltaje.
42
/*Cabecera******************************************************/
void main() {
ANSEL = 0x0C; // Pines AN2 y AN3 se configuran como
analógicos
TRISA = 0xFF; // Todos los pines del puerto PORTA se
configuran
// como entradas
ANSELH = 0; // Los demás pines se configuran como
digitales
TRISB = 0x3F; // Pines del puerto PORTB, RB7 y RB6 se
configuran
// como salidas
TRISD = 0; // Todos los pines del PORTD se configuran
como salidas
ADCON1.F4 = 1 ; // Voltaje de referencia es llevado al pin
RA3.
do {
temp_res = ADC_Read(2); // Resultado de la conversión A/D es copiado
a temp_res
43
PORTD = temp_res; // 8 bits menos significativos se mueven al
puerto PORTD
PORTB = temp_res >> 2; // 2 bits más significativos se mueven a los
bits RB6 y RB7
} while(1); // Bucle infinito
}
Para que este ejemplo funcione apropiadamente, es necesario marcar la librería ADC en la
ventana Library Manager antes de compilar el programa:
ADC
4.10 EJEMPLO 8
Utilizar memoria EEPROM
Este ejemplo muestra cómo escribir y leer la memoria EEPROM incorporada. El programa
funciona de la siguiente manera. El bucle principal lee constantemente el contenido de
localidad de la memoria EEPROM en la dirección 5 (decimal). Luego el programa entra en
el bucle infinito en el que el puerto PORTB se incrementa y se comprueba el estado de
entradas del puerto PORTA.2. En el momento de presionar el botón denominado MEMO,
un número almacenado en el puerto PORTB será guardado en la memoria EEPROM,
directamente leído y visualizado en el puerto PORTD en forma binaria.
44
/*Cabecera******************************************************/
void main() {{
ANSEL = 0; // Todos los pines de E/S se configuran como
digitales
ANSELH = 0;
PORTB = 0; // Valor inicial del puerto PORTB
TRISB = 0; // Todos los pines del puerto PORTB se
configuran
// como salidas
PORTD = 0; // Valor inicial del puerto PORTB
TRISD = 0; // Todos los pines del puerto PORTD se
configuran
// como salidas
45
TRISA = 0xFF; // Todos los pines del puerto PORTA se
configuran
// como entradas
PORTD = EEPROM_Read(5); // Leer la memoria EEPROM en la dirección 5
do {
PORTB = PORTB++; // Incrementar el puerto PORTB en 1
Delay_ms(100); // Tiempo de retardo de 100mS
if (PORTA.F2)
EEPROM_Write(5,PORTB); // Si se pulsa el botón MEMO, guardar el
puerto PORTB
do {
while (PORTA.F2); // Quedarse en este bucle hasta que el botón
esté pulsado
}
}
while(1); // Bucle infinito
}
Para comprobar el funcionamiento de este circuito, basta con pulsar el botón MEMO y
apagar el dispositivo. Después de reiniciar el dispositivo, el programa visualizará el valor
guardado en el puerto PORTD. Acuérdese de que en el momento de escribir, el valor fue
visualizado en el puerto PORTB.
Para que este ejemplo funcione apropiadamente, es necesario marcar la librería EEPROM
en la ventana Library Manager antes de compilar el programa:
EEPROM
4.11 EJEMPLO 9
Contador de dos dígitos LED, multiplexión
46
/*Cabecera******************************************************/
void interrupt() {
if (digit_no == 0) {
PORTA = 0; // Apagar ambos visualizadores
PORTD = digit1; // Colocar máscara para visualizar unidades en el
// puerto PORTD
PORTA = 1; // Encender el visualizador para las unidades (LSD)
digit_no = 1;
}else{
PORTA = 0; // Apagar ambos visualizadores
PORTD = digit10; // Colocar máscara para visualizar decenas en el
// puerto PORTD
PORTA = 2; // Encender el visualizador para las decenas (MSD)
digit_no = 0;
}
void main() {
OPTION_REG = 0x80; // Ajustar el temporizador TMR0
TMR0 = 0;
INTCON = 0xA0; // Deshabilitar las interrupciones
PEIE,INTE,RBIE,T0IE
PORTA = 0; // Apagar ambos visualizadores
TRISA = 0; // Todos los pines del puerto PORTA se configuran
47
// como salidas
PORTD = 0; // Apagar todos los segmentos del visualizador
TRISD = 0; // Todos los pines del puerto PORTD se configuran
// como salidas
do {
for (i = 0; i<=99; i++) { // Contar de 0 a 99
digit = i % 10u;
digit1 = mask(digit); // Preparar la máscara para visualizar
unidades
digit = (char)(i / 10u) % 10u;
digit10 = mask(digit); // Preparar la máscara para visualizar
decenas
Delay_ms(1000);
}
} while (1); // Bucle infinito
}
mask.c
/*Cabecera******************************************************/
Para que este ejemplo funcione apropiadamente, es necesario incluir el archivo mask.c en el
proyecto (aparte del archivo example9.c) en la ventana Project Manager antes de compilar
el programa:
mask.c
example9.c
4.12 EJEMPLO 10
Utilizar el visualizador LCD
48
Este ejemplo muestra cómo utilizar un visualizador LCD alfanumérico. Las librerías de
funciones simplifican este programa, lo que significa que al final el esfuerzo para crear el
software vale la pena.
mikroElektronika
LCD example
Dos segundos más tarde, el mensaje en la segunda línea cambia, y se visualiza el voltaje
presente en la entrada del convertidor A/D (el pin RA2). Por ejemplo:
mikroElektronika
voltage:3.141V
En un dispositivo real se puede visualizar temperatura actual o algún otro valor medido en
vez de voltaje.
Para que este ejemplo funcione apropiadamente, es necesario marcar las siguientes librerías
en la ventana Library Manager antes de compilar el programa:
ADC
LCD
/*Cabecera*****************************************************/
49
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// Final de las conexiones del módulo LCD
// Declarar variables
unsigned char ch;
unsigned int adc_rd;
char *text;
long tlong;
void main() {
INTCON = 0; // Todas las interrupciones
deshabilitadas
ANSEL = 0x04; // Pin RA2 se configura como una entrada
analógica
TRISA = 0x04;
ANSELH = 0; // Los demás pines se configuran como
digitales
while (1) {
adc_rd = ADC_Read(2); // Conversión A/D. Pin RA2 es una
entrada.
Lcd_Out(2,1,text); // Escribir el resultado en la segunda
línea
tlong = (long)adc_rd * 5000; // Convertir el resultado en milivoltios
tlong = tlong / 1023; // 0..1023 -> 0-5000mV
ch = tlong / 1000; // Extraer voltios (miles de
milivoltios)
// del resultado
50
Lcd_Chr(2,9,48+ch); // Escribir resultado en formato ASCII
Lcd_Chr_CP('.');
ch = (tlong / 100) % 10; // Extraer centenas de milivoltios
Lcd_Chr_CP(48+ch); // Escribir resultado en formato ASCII
ch = (tlong / 10) % 10; // Extraer decenas de milivoltios
Lcd_Chr_CP(48+ch); // Escribir resultado en formato ASCII
ch = tlong % 10; // Extraer unidades de milivoltios
Lcd_Chr_CP(48+ch); // Escribir resultado en formato ASCII
Lcd_Chr_CP('V');
Delay_ms(1);
}
}
4.13 EJEMPLO 11
Comunicación serial RS-232
Este ejemplo muestra cómo utilizar el módulo EUSART del microcontrolador. La conexión
a una PC se habilita por medio del estándar de comunicación RS-232. El programa
funciona de la siguiente manera. Cada byte recibido por medio de la comunicación serial se
visualiza al utilizar los LEDs conectados al puerto PORTB y después se devuelve
automáticamente al transmisor. Si ocurre un error en recepción, se lo indicará al encender el
diodo LED. La manera más fácil es comprobar el funcionamiento del dispositivo en la
práctica al utilizar un programa estándar de Windows denominado Hyper Terminal.
51
/*Cabecera******************************************************/
unsigned short i;
void main() {
UART1_Init(19200); // Inicializar el módulo USART
// (8 bits, tasa de baudios 19200, no hay bit
// de paridad...)
while (1) {
if (UART1_Data_Ready()) { // si se ha recibido un dato
i = UART1_Read(); // leerlo
UART1_Write(i); // enviarlo atrás
}
}
}
Para que este ejemplo funcione apropiadamente, es necesario marcar la librería UART en la
ventana Library Manager antes de compilar el programa:
52
UART
4.14 EJEMPLO 12
Medición de temperatura por medio del sensor DS1820. Uso del protocolo
‘1-wire’...
Este ejemplo muestra la ventaja de utilizar librerías con las funciones listas para ser
utilizadas. Concretamente, no tiene que examinar la documentación proporcionada por el
fabricante para utilizar el sensor. Basta con copiar alguna de estas funciones en el
programa. Si le interesa saber cómo se declaran, basta con pulsar sobre alguna de ellas y
seleccione la opción Help.
/*Cabecera******************************************************/
53
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// Final de conexiones del módulo LCD
// Set TEMP_RESOLUTION to the corresponding resolution of used DS18x20
sensor:
// 18S20: 9 (default setting; can be 9, 10, 11, or 12)
// 18B20: 12
// extraer temp_whole
temp_whole = temp2write >> RES_SHIFT ;
54
Lcd_Out(2, 5, text);
}
void main() {
ANSEL = 0; // Configurar los pines AN como digitales
ANSELH = 0;
C1ON_bit = 0; // Deshabilitar los comparadores
C2ON_bit = 0;
Para que este ejemplo funcione apropiadamente, es necesario marcar las siguientes librerías
en la ventana Library Manager antes de compilar el programa:
One_Wire
LCD
4.15 EXAMPLE 13
Generación de sonido, librería de sonido...
Las señales de audio se utilizan con frecuencia cuando se necesita llamar la atención de
usuario, confirmar que alguno de los botones se ha pulsado, avisar que se ha llegado hasta
55
los valores mínimos o máximos etc. Pueden ser una simple señal de pitido así como
melodías de una duración más larga o más corta. En este ejemplo se muestra la generación
de sonido por medio de funciones que pertenecen a la librería Sound.
Además de estas funciones, la función Button que pertenece a la misma librería se utiliza
para probar los botones de presión.
/*Cabecera******************************************************/
void Tone1() {
Sound_Play(659, 250); // Frecuencia = 659Hz, duración = 250ms
}
void Tone2() {
Sound_Play(698, 250); // Frecuencia = 698Hz, duración = 250ms
}
void Tone3() {
Sound_Play(784, 250); // Frecuencia = 784Hz, duración = 250ms
}
56
Tone1(); Tone2(); Tone3(); Tone3();
Tone1(); Tone2(); Tone3(); Tone3();
Tone1(); Tone2(); Tone3();
Tone1(); Tone2(); Tone3(); Tone3();
Tone1(); Tone2(); Tone3();
Tone3(); Tone3(); Tone2(); Tone2(); Tone1();
}
void main() {
ANSEL = 0; // Todos los pines de E/S son digitales
ANSELH = 0;
TRISB = 0xF0; // Pines RB7-RB4 se configuran como
entradas
while (1) {
if (Button(&PORTB,7,1,1)) // RB7 genera Tono1
Tone1();
while (PORTB & 0x80) ; // Esperar que se suelte el botón
if (Button(&PORTB,6,1,1)) // RB6 genera Tono2
Tone2();
while (PORTB & 0x40) ; // Esperar que se suelte el botón
if (Button(&PORTB,5,1,1)) // RB5 genera melodía 2
Melody2();
while (PORTB & 0x20) ; // Esperar que se suelte el botón
if (Button(&PORTB,4,1,1)) // RB4 genera melodía 1
Melody1();
while (PORTB & 0x10) ; // Esperar que se suelte el botón
}
}
Para que este ejemplo funcione apropiadamente, es necesario marcar las siguientes librerías
en la ventana Library Manager antes de compilar el programa:
57
Button
Sound
4.16 EJEMPLO 14
Utilizar el visualizador LCD gráfico
En este ejemplo el GLCD visualiza una secuencia de imágenes, de las que un mapa de bits
representa un camión almacenado en otro archivo denominado truck_bmp.c. Para habilitar
que este programa funcione apropiadamente, usted debe añadir este archivo como archivo
fuente a su proyecto.
Las directivas del preprocesador incluidas en este ejemplo le permiten elegir si quiere
visualizar toda la secuencia de imágenes o sólo una secuencia corta. Por defecto se
visualizará toda la secuencia de imágenes. Sin embargo, al añadir un comentario delante de
la directiva #define COMPLETE_EXAMPLE se deshabilita visualizar algunas imágenes de la
secuencia. Si se comenta (o si se borra) esta directiva, las sentencias entre las directivas
#ifdef COMPLETE_EXAMPLE y #endif no serán compiladas, así que no se ejecutarán.
/*Cabecera******************************************************/
//Declaraciones----------------------------------------------------------
-------
58
const code char truck_bmp[1024]; // Declarar la constante definida en
truck_bmp.c
// para utilizarla en este archivo
//--------------------------------------------------------final-de-
declaraciones
void main() {
unsigned short ii;
char *someText;
59
/* Dibujar la segunda imagen */
Glcd_Box(62,40,124,56,1); // Dibujar la caja
Glcd_Rectangle(5,5,84,35,1); // Dibujar el rectángulo
Glcd_Line(0, 0, 127, 63, 1); // Dibujar la línea
delay2S();
delay2S();
Glcd_Fill(0x00); // Borrar el GLCD
#ifdef COMPLETE_EXAMPLE
Glcd_Set_Font(Character8x7, 8, 7, 32); // Seleccionar la fuente,
ver
// __Lib_GLCDFonts.c en la carpeta Uses
#endif
60
truck_bmp.c:
/*Cabecera*****************************************************/
61
191,191,239,239,239,191,255,191,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,127,127,127,127,255,255,191,191,191,191,255,254,
255,253,255,255,255,251,255,255,255,127,125, 63, 31, 31, 31, 31,
31, 31, 63, 15, 15, 7, 7, 3, 3, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 3, 3, 3, 11, 11, 11, 11, 7, 3, 14, 6, 6,
6, 2, 18, 19, 19, 3, 23, 21, 21, 17, 1, 19, 19, 3, 6, 6,
14, 15, 15, 7, 15, 15, 15, 11, 2, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
Para que este ejemplo funcione apropiadamente, es necesario marcar la librería GLCD en la
ventana Library Manager antes de compilar el programa. Asimismo, es necesario incluir el
documento truck_bmp.c en el proyecto.
4.17 EJEMPLO 15
Utilizar el panel táctil...
Un panel táctil está compuesto por dos láminas rígidas, formando una estructura de
‘sándwich’ que tiene capas resistivas en sus caras internas. La resistencia de estas capas no
excede normalmente de 1Kohm. Los lados opuestos de las láminas disponen de los
contactos para acceder a un cable plano.
62
El procedimiento para determinar las coordenadas de la posición del panel que ha sido
presionado se puede dividir en dos pasos. El primero es determinación de la coordenada X,
y el segundo es de determinar la coordenada Y de la posición.
63
respectivos contactos. El software consiste en mostrar un menú en una pantalla LCD
gráfica, conmutar de encendido a apagado del panel táctil (control del panel táctil) y leer los
valores del convertidor A/D que representan realmente las coordenadas X e Y de la
posición.
Una vez determinadas las coordenadas, es posible decidir qué es lo que deseamos que haga
el microcontrolador. En este ejemplo se explica cómo conmutar entre encendido y apagado
dos pines digitales del microcontrolador, conectados a los LEDs A y B.
En este ejemplo se utilizan las funciones que pertenecen a las librerías Glcd y ADC.
Teniendo en cuenta que la superficie del panel táctil es ligeramente mayor que la del LCD
gráfico, en caso de requerir una mayor precisión en la determinación de las coordenadas,
es necesario incluir el software de calibración del panel táctil.
/* Cabecera ***************************************************/
// Leer la coordenada X
unsigned int GetX() {
//reading X
PORTC.F0 = 1; // DRIVEA = 1 (electrodo izquierdo (LEFT)
conectado, electrodo
64
// derecho (RIGHT) conectado, electrodo superior
(TOP)desconectado)
PORTC.F1 = 0; // DRIVEB = 0 (electrodo inferior (BOTTOM)
desconectado)
Delay_ms(5);
return ADC_Read(0); // leer el valor de X de RA0(BOTTOM)
}
// Leer la coordenada Y
unsigned int GetY() {
//Leer la Y
PORTC.F0 = 0; // DRIVEA = 0 (electrodo izquierdo (LEFT)
desconectado, electrodo
// derecho (RIGHT) desconectado, electrodo superior
(TOP) conectado)
PORTC.F1 = 1; // DRIVEB = 1 (electrodo inferior (BOTTOM)
conectado)
Delay_ms(5);
return ADC_Read(1); // leer el valor de Y de RA1 (del eléctrodo
izquierdo LEFT)
}
void main() {
PORTA = 0x00;
TRISA = 0x03; // RA0 y RA1 son entradas analógicas
ANSEL = 0x03;
ANSELH = 0; // Configurar otros pines AN como digitales de E/S
PORTC = 0 ; // Todos los pines del puerto PORTC están a 0 (incluyendo
los
// pines RC6 y RC7)
while (1) {
// leer X-Y y convertirlo en la resolución de 128x64 píxeles
x_coord = GetX();
y_coord = GetY();
65
x_coord128 = (x_coord * 128) / 1024;
y_coord64 = 64 -((y_coord *64) / 1024);
Para que este ejemplo funcione apropiadamente, es necesario marcar las siguientes librerías
en la ventana Library Manager antes de compilar el programa.
GLCD
ADC
C_Stdlib
66