Está en la página 1de 15

Laboratorio de Control con Microprocesadores GR.

Práctica 4: LCD y Técnicas de Barrido de Teclados


Mauricio Anchitipán
Laboratorio de Control con Microprocesadores, Ingeniería Eléctrica y Electrónica, Escuela Politécnica Nacional

Quito, Ecuador

imaurisio@hotmail.com

Abstract- Este documento presenta el desarrollo del


preparatorio correspondiente a la práctica 4 del al exterior, de fácil conexión a otros microcontroladores o
laboratorio de Control con Microprocesadores. En microprocesadores.
dicha práctica se va a familiarizar con el manejo de
displays de cristal líquido y técnicas de barrido y B. Líneas de interface (RS, R/W, E, D4-D7, D0-D3, Vdd,
decodificación de teclados. Dicho escrito, consta de Vss, Vo).
una consulta acerca de los LCDs y de la
RS: selección del registro de control/registro de
implementación de dos programas; uno en lenguaje
datos:
assembler para inicializar un LCD y otro en lenguaje RS=0 Selección del registro de control.
C para resolver el problema planteado por la hoja RS=1 Selección del registro de datos.
guía. Al final se incluyen las correspondientes
simulaciones y líneas de código. R/W: señal de lectura/escritura:
R/W=0 El módulo LCD es escrito.
I. OBJETIVOS R/W=1 El módulo LCD es leído.

1) Familiarizar al estudiante con el manejo de los E: señal de activación del módulo LCD:
E=0 Módulo desconectado.
displays de cristal líquido (LCD) y las técnicas de barrido
E=1 Módulo conectado.
y decodificación de teclados.
D0-D7: bus de datos bi-direccional. Por medio de
II. CONSULTA estas líneas se realiza la transferencia de información
entre el módulo LCD y el sistema informático que lo
Consultar acerca del display de cristal líquido: gestiona.

A. Funcionamiento del módulo LCD. Vdd: patilla de alimentación a 5 V.

Un display alfanumérico de matriz de puntos es un Vss: patilla de alimentación a tierra.


dispositivo de interfaz humana compuesto por una
pantalla de cristal líquido o LCD (Liquid Crystal Display) Vo: patilla de contraste del cristal líquido.
sobre la que se pueden mostrar mensajes formados por
distintos caracteres: letras, números, símbolos, etc. Estos C. Modos de interface con el Microprocesador.
dispositivos estan gobernados por un controlador, que
El HD44780 puede enviar datos en una sola
normalmente va incorporado sobre la misma placa de
operación de 8 bits o en dos de 4 bits, lo que le permite
circuito impreso que soporta el LCD, Es muy común
conectarse con un microprocesador de 8 o 4 bits.
encontrarse con el controlador HD44780 de Hitachi, el
cual se encarga de gestionar el display líquido: polarizar
los puntos de la pantalla, generar los caracteres, desplazar
la pantalla, mostrar el cursor, etc. De esta forma el usuario
se despreocupa de todos estos problemas y sencillamente
necesita conocer una serie de comandos o instrucciones
de alto nivel (limpia display, posiciona cursor, etc.) que le
permitirán mostrar mensajes o animaciones sobre la
pantalla de forma sencilla. Para comunicarse con el
controlador del display se dispone de una interfaz paralela Fig. 1 Modo de interface de 8 bits.
El interfaz con microcontrolador a 8 bits es la forma
de manejo más sencilla de programar, pero presenta la
desventaja de emplear 8 pines del microcontrolador solo
para el envío de datos y otros 2 pines para las señales de
control.

Fig. 2 Modo de interface de 4 bits.

Esta interfaz es la más utilizada para aprovechar los


puertos de un microcontrolador dejando disponibles pines
de los mismos para otras funciones.

D. Inicialización del módulo: por medio de instrucciones.

Fig. 4 Inicialización del LCD a 4 bits.

E. Set de Instrucciones.

Las instrucciones o comandos que pueden ser


utilizados por un microcontrolador o microprocesador
externo para programar el LCD se pueden agrupar en
cuatro tipos:
− Instrucciones para establecer funciones del LCD como
el formato del display o la longitud de los datos.
− Instrucciones para direccionar la RAMs internas.
− Instrucciones para transferir datos desde/a las RAMs
internas.
− Otras Instrucciones.

A continuación se detallan las instrucciones:

CLEAR DISPLAY (CD): “Limpia Pantalla”

Fig. 3 Inicialización del LCD a 8 bits.

Borra la pantalla. La DDRAM se rellena con el


carácter correspondiente al espacio (0×20). El contador de
direcciones se pone a cero (AC = 0). Si el display fue D (Display On/Off): Cuando D = 1, el display se
desplazado, se restaura la posición original. El display se habilita. Cuando D = 0, el display se apaga, pero se
deshabilita (D = 0) y el cursor y el parpadeo (blink), si retiene el contenido de la DDRAM.
estaban activados, se mueven a la esquina superior
C (Cursor On/Off): Cuando C = 1, el cursor se
izquierda de la pantalla (dirección 0×00). Pone por muestra en la posición especificada por el AC. Cuando C
defecto el bit I/D = 1 (incremento). = 0, el cursor no se muestra en pantalla. El cursor está
formado por una línea de 5 puntos en la octava fila del
Return home (RH): “Retorno a casa” carácter, por debajo del bloque de 5×7 puntos que forman
un carácter. Para caracteres de 5×10 puntos, el cursor es
dibujado en la fila undécima como una línea de 5 puntos.

B (Parpadeo On/Off): Cuando B = 1, el carácter que


se encuentra en la posición del cursor parpadea. Cuando B
= 0, la función de parpadeo queda deshabilitada.
Retorna el cursor a la posición inicial (dirección
0×00). El contador de direcciones se pone a cero (AC = CURSOR OR DISPLAY SHIFT (CDS):
“Desplazamiento Cursor o Pantalla”
0). Si el display fue desplazado, se restaura la posición
original. El cursor y el parpadeo (blink), si estaban
activados, se mueven a la esquina superior izquierda de la
pantalla. El contenido de la DDRAM no se ve afectado.

ENTRY MODE SET (EMS): “Establece Modo de


Entrada” La pantalla y/o el cursor son desplazados a derecha
(R/L = 1) o izquierda (R/L = 0) sin modificar el contenido
de la DDRAM. Para un display de 2 líneas el cursor es
movido desde la posición 40 de la primera línea a la
posición 1 de la segunda línea. Sin embargo, de la
posición 40 de la segunda línea el cursor no retorna a casa
(posición 1, línea 1), sino que pasa a la posición 1 de la
I/D (Cursor Izquierda/Derecha): Establece la segunda línea.
dirección de movimiento del cursor. El AC se incrementa
(I/D=1) o decrementa (I/D = 0) en 1 después de escribir o
leer cada carácter en/de la DDRAM o CGRAM. El cursor FUNCTION SET (FS): “Establece Función”
y la función de parpadeo (blink) se mueven sobre el
display una posición a la derecha (I/D = 1) o a la
izquierda (I/D = 0).

S (Pantalla Izquierda/Derecha): Cuando S = 1 el


display entero se desplaza una posición a la izquierda (I/D
= 1) o a la derecha (I/D = 0) después de escribir o leer
cada carácter en/de la DDRAM. El cursor y el parpadeo DL (Ancho del Bus de Datos): Selecciona el ancho
no se mueven en relación a la posición del display. del Bus de Datos. Cuando DL = 1, se utiliza un bus de 8
Cuando S = 0 el display no se desplaza. Tampoco se bits (DB7 – DB0). Cuando DL = 0, se utiliza un bus de
desplaza el display cuando se escriben datos en la datos de 4 bits (DB7 – DB4). En este caso es necesario
CGRAM. realizar dos transferencias consecutivas para poder
transferir desde/a el display.
DISPLAY ON/OFF CONTROL (DC): “Control
Encendido/Apagado de Pantalla” N (Número de Líneas): Selecciona el formato del
display (1 ó 2 líneas). N = 1, 2 líneas. N = 0, 1 línea.

F (Tamaño de las Fuentes): Cuando F = 1, se usan


caracteres de 5×10 puntos. Cuando F = 0, se usan los de
5×7.

SET CGRAM ADDRESS (SCG): “Establece


Dirección CGRAM”
presenta una tabla (Tomado de [4]) donde se especifica
con mayor detalle dichos parámetros:

SET DDRAM ADDRESS (SDD): “Establece Dirección


DDRAM”

Fig. 3 Especificaciones eléctricas de un LCD alfanumérico 16x2.

Desarrollar las subrutinas para el manejo del LCD en


READ BUSY FLAG & ADDRESS (RBF): “Lee BF y lenguaje ensamblador.
Dirección”
La solución de la presente pregunta se encuentra en el
ANEXO 1.

III. ANÁLISIS DE ENTRADAS, SALIDAS Y


RECURSOS DEL
MICROCONTROLADOR
WRITE DATA TO CG/DDRAM (WD): “Escribe Dato
a CG/DDRAM” Entradas:

1) 1 dipswitch.
2) 1 decodificador de teclado MM74C922.

Salidas:

1) 2 leds.
2) 1 sirena.
READ DATA FROM CG/DDRAM (RD): “Lee Dato 3) 1 LCD.
desde CG/DDRAM”
Recursos: los recursos usados del microcontrolador
son:

1) Reset manual.
2) Interrupción externa INT0.
3) Puertos digitales.
4) Memoria EEPROM.
F. Características eléctricas.
IV. JUSTIFICACIÓN DEL
Consumo muy reducido de potencia: alrededor de MICROCONTROLADOR A UTILIZAR
7.5mW.
Se eligió al microcontrolador ATMEGA 164P para la
Voltaje de alimentación: 5V. realización de la práctica porque presentaba el suficiente
número de pines para poder implementar el presente
Pin 15 (ánodo de la retroiluminación) : R + 5V. sistema microprocesado. También debido a que poseía
Pin 16 (cátodo de la retroiluminación): GND. todos los recursos para resolver fácilmente el problema.

Para un mejor entendimiento y conocimiento de las


V. DIAGRAMA DE FLUJO
características eléctricas del LCD, a continuación se
VII. BIOGRAFÍA

Edwin Mauricio Anchitipán N,


nació en Quito-Ecuador el 27 de
junio de 1993. Se graduó de la
secundaria "Colegio Técnico
Ecuador" como técnico eléctrico y
electrónico. Actualmente cursa
sus estudios de Ingeniería
Electrónica y Control en la
“Escuela Politécnica Nacional” en Quito.

VIII. ANEXOS (CÓDIGO FUENTE DEL


PROGRAMA Y SIMULACIÓN DE LO
SOLICITADO)

ANEXO 1: subrutinas para el manejo del LCD en


lenguaje ensamblador

;Programa para inicializar un LCD con bus de


datos de 8 bits
.include "m164pdef.inc"
.def tempo=R16
.def conta=R17
.def aux=R18

.cseg
.org 0x0000

inicio:
;se configuran los puertos
ldi tempo,0b00000000
out ddrb,tempo
Fig. 5 Diagrama de flujo del programa. out ddrd,tempo
ldi tempo,0b00000011
VI. REFERENCIAS out ddra,tempo ;puerto a para realizar el
control del LCD
[1] “LCD AVR Pantalla LCD 2x16 con el AVR - ldi tempo,0b11111111
MICROCONTROLADORES.” [Online]. Available: out ddrc,tempo ;puerto c para el bus de
http://microcontroladores-mrelberni.com/lcd-avr/. datos de direcciones del LCD
[Accessed: 30-Nov-2016]. out portb,tempo
out portd,tempo
[2] “LCD Programming Example using ‘C.’” [Online]. ldi tempo,0b11111100
Available: out porta,tempo
http://web.alfredstate.edu/weimandn/programming/lcd/A ldi tempo,0b00000000
Tmega328/LCD_code_gcc_4d.html. [Accessed: 30-Nov- out portc,tempo
2016].
;se configura el pull-up
in tempo,mcucr
[3] “Manejo de display LCD” [Online]. Available:
andi tempo,0b11101111
http://www.bolanosdj.com.ar/SOBRELCD/TEORIALCD
out mcucr,tempo
V1.pdf [Accessed: 30-Nov-2016].
;se configura el stack pointer
[4] “ALPHANUMERIC LCD DISPLAY (16 X 2)” ldi tempo,high(ramend)
[Online]. Available: out sph,tempo
http://www.picaxe.com/docs/LED008.pdf [Accessed: 30- ldi tempo,low(ramend)
Nov-2016]. out spl,tempo
sei
;se configura (inicializa) el LCD. Para esto rcall retardo
se han utilizado los pdf "Instrucciones LCD
(Ingles)" y "Display LCD" (especialmente la ;PASO 4
tabla que esta cbi porta,0 ;se deshabilita el lcd
;en la pagina 10 del primer pdf) que estan ldi tempo,0x38 ;(0b00111000) se envia por
en la carpeta de "Control con Micros". tercera vez la primera instruccion
;Tambien se ha cumplido con el siguiente out portc,tempo
orden estipulado para inicializar el LCD: sbi porta,0 ;se habilita el display
; Deshabilitar display ldi aux,1 ;este valor sera cargado al ocr2a
; Colocar instruccion en la subrutina "retardo" para hacer un
; Habilitar display retardo mayor a 40us, mas precisamente de
; Retardo 64us
; Deshabilitar display rcall retardo
; Colocar instruccion
; Habilitar display ;Los pasos del 1 al 4 sirven para resetear
; Retardo el LCD
; Deshabilitar display
; .... y asi sucesivamente ;PASO 5
cbi porta,0 ;se deshabilita el lcd
; <<< INICIO INICIALIZACION LCD >>> ldi tempo,0x38 ;(0b00111000) se envia por
;al momento que se alimenta el display se cuarta vez la primera instruccion
debe realizar un retardo mayor a 15ms por out portc,tempo
eso se usan estas 4 primeras lineas de sbi porta,0 ;se habilita el display
codigo ldi aux,1 ;este valor sera cargado al ocr2a
;PASO 1 en la subrutina "retardo" para hacer un
ldi aux,255 ;@ - este valor sera cargado al retardo mayor a 40us, mas precisamente de
ocr2a en la subrutina "retardo" para hacer 64us
un retardo mayor a 15ms, mas precisamente de rcall retardo
8.192ms
rcall retardo ;Con la primera instruccion (Function set -
ldi aux,255 ;este valor sera cargado al Establece funcion) 0x38 (0b00111000) se
ocr2a en la subrutina "retardo" para hacer configura lo siguiente:
un retardo mayor a 15ms, mas precisamente de ; 001: function set
8.192ms ; 1: bus de datos de 8 bits
rcall retardo ;& - las lineas que van desde ; 1: se usan las dos lineas del LCD
@ hasta & sirven para hacer un retardo de ; 0: se usan caracteres de 5x7 puntos
16.384ms es decir mayor a 15ms ; 00: no importa el valor de estos bits

;PASO 2 ;PASO 6
cbi porta,0 ;se deshabilita el display. Solo cbi porta,0 ;se deshabilita el lcd
cuando esta habilitado se puede comunicar ldi tempo,0x06 ;(0b00000110) se envia la
con el segunda instruccion
cbi porta,1 ;se selecciona el registro de out portc,tempo
instrucciones sbi porta,0 ;se habilita el display
ldi tempo,0x38 ;(0b00111000) se envia por ldi aux,1 ;este valor sera cargado al ocr2a
primera vez la primera instruccion en la subrutina "retardo" para hacer un
out portc,tempo retardo mayor a 40us, mas precisamente de
sbi porta,0 ;se habilita el display 64us
ldi aux,132 ;este valor sera cargado al rcall retardo
ocr2a en la subrutina "retardo" para hacer
un retardo mayor a 4.1ms, mas precisamente ;Con la segunda instruccion (Entry mode set
de 4.256ms - Establece modo entrada) 0x06 (0b00000110)
rcall retardo se configura lo siguiente:
; 000001: entry mode set
;PASO 3 ; 1: al AC (address counter) se incrementa
cbi porta,0 ;se deshabilita el lcd en 1 después de escribir o leer cada
ldi tempo,0x38 ;(0b00111000) se envia por carácter en/de la DDRAM o CGRAM.
segunda vez la primera instruccion ; 0: no se desplaza el display
out portc,tempo
sbi porta,0 ;se habilita el display ;PASO 7
ldi aux,3 ;este valor sera cargado al ocr2a cbi porta,0 ;se deshabilita el lcd
en la subrutina "retardo" para hacer un ldi tempo,0x0E ;(0b00001110) se envia la
retardo mayor a 100us, mas precisamente de tercera instruccion
128us out portc,tempo
sbi porta,0 ;se habilita el display
ldi aux,1 ;este valor sera cargado al ocr2a lazo:
en la subrutina "retardo" para hacer un ;De aqui en adelante se realiza el codigo
retardo mayor a 40us, mas precisamente de para mostrar los mensajes por el LCD y los
64us retardos seran de 40us
rcall retardo cbi porta,0 ;se deshabilita el lcd
rcall linea_1
;Con la tercera instruccion (Display ON/OFF ldi zl,low(tabla_1<<1) ;se apunta al primer
control - Control de encendido/apagado del elemento de la tabla 1
display) 0x0E (0b00001110) se configura lo ldi zh,high(tabla_1<<1)
siguiente: cbi porta,0 ;se deshabilita el display
; 00001: display ON/OFF control rcall escritura
; 1: se habilita el display cbi porta,0 ;se deshabilita el lcd
; 1: se habilita el cursor (se muestra en rcall linea_2
la posición especificada por el AC) ldi zl,low(tabla_2<<1) ;se apunta al primer
; 0: funcion de parpadeo deshabilitada (el elemento de la tabla 2
caracter que se encuentra en la posición del ldi zh,high(tabla_2<<1)
cursor no parpadea) cbi porta,0 ;se deshabilita el display
rcall escritura
;PASO 8 cbi porta,0 ;se deshabilita el lcd
cbi porta,0 ;se deshabilita el lcd ldi tempo,0x01 ;(0b00000001) se utiliza la
ldi tempo,0x01 ;(0b00000001) se envia la instruccion Clear display para limpiar el
cuarta instruccion display
out portc,tempo out portc,tempo
sbi porta,0 ;se habilita el lcd sbi porta,0 ;se habilita el lcd
ldi aux,53 ;este valor sera cargado al ocr2a ldi aux,53 ;este valor sera cargado al ocr2a
en la subrutina "retardo" para hacer un en la subrutina "retardo" para hacer un
retardo mayor a 1.64ms, mas precisamente de retardo mayor a 1.64ms, mas precisamente de
1.728ms 1.728ms
rcall retardo rcall retardo
rcall retardo_dos
;Con la cuarta instruccion (Clear display - rjmp lazo
Limpiar display) 0x01 (0b00000001) se
configura lo siguiente: linea_1:
; 00000001: limpiar display push R16
in R16,sreg
;La quinta instruccion (Set DDRAM address - push R16
Establece direccion DDRAM) sirve para cbi porta,1 ;se selecciona el registro de
manejar las direcciones del AC es decir para instrucciones
mostrar ldi R16,0x80 ;(0b10000000) se utiliza la
;algun dato en la primera linea o en la instruccion set DDRAM address para mostrar
segunda linea del display. Para displays de dato en la primera linea
2 líneas (N=1) la direccion (ADD) puede ir out portc,R16
de sbi porta,0 ;se habilita el display
;0×00 a 0×27 para la primera línea y de 0×40 ldi aux,1 ;este valor sera cargado al ocr2a
a 0×67 para la segunda línea. Entonces: en la subrutina "retardo" para hacer un
; si se escribe 0x80 (0b10000000) se retardo mayor a 40us, mas precisamente de
configura lo siguiente: 64us
;1: set DDRAM address rcall retardo
;0000000 son los 7 bits restantes (0×00): se pop R16
carga el AC con esta dirección (7 bits), con out sreg,R16
lo se muestra algun dato desde la primera pop R16
linea ret
; si se escribe 0xC0 (0b11000000) se
configura lo siguiente: linea_2:
;1: set DDRAM address push R16
;1000000 son los 7 bits restantes (0×40): se in R16,sreg
carga el AC con esta dirección (7 bits), con push R16
lo se muestra algun dato desde la segunda cbi porta,1 ;se selecciona el registro de
linea instrucciones
;Entonces esta instruccion se la usara mas ldi R16,0xC0 ;(0b11000000) se utiliza la
abajo instruccion set DDRAM address para mostrar
dato en la segunda linea
; <<< FIN INICIALIZACION LCD >>> out portc,R16
sbi porta,0 ;se habilita el display ;se usa el timmer 2 para realizar los
ldi aux,1 ;este valor sera cargado al ocr2a retardos: se hace que este cuente hasta
en la subrutina "retardo" para hacer un cuando exista una igualdad entre el tcnt2 y
retardo mayor a 40us, mas precisamente de el valor fijado en el ocr2a
64us ;Cuando esto ocurra se sale de la subrutina
rcall retardo de retardo. No se usa ninguna interrupcion
pop R16 del timer
out sreg,R16 push R16
pop R16 in R16,sreg
ret push R16
sts ocr2a,aux ;se pone el valor tope hasta
limpiar_lcd: el cual debe contar el timer
cbi porta,1 ;se selecciona el registro de clr aux
instrucciones sts tcnt2,aux ;se limpia el registro del
ldi tempo,0b00000001 contador/timer
out portc,tempo ;se limpia el display ldi aux,0b00000000
sbi porta,0 ;se habilita el lcd sts tccr2a,aux ;modo normal (los
ldi aux,52 ;retardo de alrededor 40us comparadores OC2A y OC2B desconectados),
rcall retardo modo normal del timer
cbi porta,0 ;se deshabilita el lcd ldi aux,0b00000110 ;no se fuerzan las
sbi porta,1 salidas, modo normal del timer, preescalador
ret de 256. Tambien se puede poner esta
instruccion: ldi aux,(1<<cs22)|(1<<cs21)
escritura: sts tccr2b,aux
push R16 ldi aux,0b00000010 ;se limpia la bandera
in R16,sreg OCF2A de la comparacion entre el timer 2 y
push R16 el OCR2A. Tambien se puede poner esta
sbi porta,1 ;se selecciona el registro de instruccion: (1<<ocf2a)
datos out tifr2,aux
mostrar: ldi tempo,0b00000000
lpm R16,z+ sts assr,tempo ;se trabaja en modo sincrono
cpi R16,'.' ;se verifica si se ha terminado (reloj principal de 8MHz)
de mostrar toda la oracion lazo_retardo:
breq salir ;en este lazo se espera hasta que se
out portc,R16 ;se envia el codigo (dato) de produzca una igualdad entre el tcnt2 y el
cada letra al LCD valor fijado en el ocr2a
sbi porta,0 ;se habilita el display in aux,tifr2
ldi aux,1 ;este valor sera cargado al ocr2a sbrs aux,ocf2a ;se salta una linea de codigo
en la subrutina "retardo" para hacer un cuando la bandera ocf2a se ponga en 1L, es
retardo mayor a 40us, mas precisamente de decir cuando haya ocurrido la igualdad entre
64us el tcnt2 y el valor fijado en el ocr2a
rcall retardo rjmp lazo_retardo
cbi porta,0 ;se deshabilita el display ldi aux,0b00000000
rjmp mostrar sts tccr2b,aux ;no se fuerzan las salidas,
salir: modo normal del timer, no preescalador (se
pop R16 detiene el timer)
out sreg,R16 pop R16
pop R16 out sreg,R16
ret pop R16
ret
;Para la subrutina "retardo" se usa reloj de
8MHz (1CM=0.125us) y preescalador de 256 retardo_dos:
;Para saber el valor de retardo realizado, ;este retardo sirve para no ver que el
hacer: cursor no se este movimiendo continuamente
; se obtiene el valor contado por el timer por el LCD
(#CM): cuenta=(#CM)=(ocr2a+1)*256 push R16
; se hace regla de tres: 1CM ---> in R16,sreg
0.125us push R16
; cuenta ---> ? push R17
?=valor de retardo push R18
realizado=(cuenta*0.125us)/1CM ldi R16,255
repite_barrido_uno:
retardo: ldi R17,255
repite_barrido_dos:
ldi R18,255 //esto para poder ver
repite_barrido_tres: datos numéricos en el LCD
dec R18 #include <stdio.h> //otra manera de ver
brne repite_barrido_tres datos de tipo entero y cualquier otro tipo
dec R17 es por medio de esta librería
brne repite_barrido_dos #include "lcd.h" //libreria para poder
dec R16 utilizar el LCD. Tener presente que dicha
brne repite_barrido_uno libreria solo trabaja para enviar los datos
pop R18 y
pop R17 //caracteres al LCD con 4
pop R16 bits, se puede elegir entre el nible alto o
out sreg,R16 el nible bajo del bus de datos del LCD.
pop R16 //Por eso es que
ret se conecto el LCD de la manera que esta en
la simulacion en Proteus
;el punto colocado en las tablas sirve para
saber cuando ya se ha mostrado todo el texto //se definen funciones
de cada tabla void config_puertos(void);
tabla_1: void EEPROM_write(unsigned int uiAddress,
.db " Hola Mauricio ." unsigned char var); //subrutina (funcion)
para escribir la memoria EEPROM
tabla_2: unsigned char EEPROM_read(unsigned int
.db " Anchitipan ." uiAddress); //subrutina (funcion) para leer
la memoria EEPROM
void ingresar_clave(void);
void comprobar_clave(void);

//se definen variables


unsigned char tecla=0; //variable para
guardar la tecla
unsigned char clave0_adm; //variables para
guardar la clave establecida por el
administrador
unsigned char clave1_adm;
unsigned char clave2_adm;
unsigned char clave3_adm;
unsigned char clave0_ope; //variables para
guardar la clave ingresada por el operario
unsigned char clave1_ope;
unsigned char clave2_ope;
unsigned char clave3_ope;
int aux; //variable para seguir ejecutando
los lazos donde se muestra el mensaje de
bienvenida y el de ingreso de clave
int aux1; //variable para seguir ejecutando
el lazo donde se muestra el mensaje de
presionar enter
int aux2=0; //variable para permitir la
Fig. 6 Simulación del sistema microprocesado en Proteus. modificacion de las variables subir y bajar
int opcion; //variable para saber que
selecciono el operario en el menu principal
unsigned char dipswitch; //variable para
ANEXO 2: solución del problema planteado acerca saber el numero ingresado por el dipswitch
int menu_circular; //variable para saber
del sistema microprocesado referido en la hoja guía.
como mostrar el menu circular
char verif_clave; //variable para verificar
#define F_CPU 8000000UL
la clave ingresada
#include <avr/io.h>
//si se asigna 1 a
#include <avr/interrupt.h>
verif_clave significa que clave ingresada es
#include <util/delay.h>
correcta
#include <stdlib.h> //este archivo de
//si se asigna 0 a
cabecera tiene una serie de funciones que
verif_clave significa que clave ingresada es
permiten convertir numeros a cadena de
incorrecta
caracteres viceversa;
char subir=0; //variable para realizar el ingresar_clave(); //se invoca
desplazamiento hacia arriba del menu esta funcion y se va almacenando y mostrando
principal por el LCD la clave ingresada por el
char bajar=0; //variable para realizar el operario
desplazamiento hacia abajo del menu aux1=1;
principal while(aux1==1)
char resta=0; //variable para guarda el {
resultado subir-bajar o bajar-subir //se muestra el mensaje
char tecla1[16]; //tecla1 es un arreglo de presionar enter mientras no se lo
donde se guardará el numero sin signo (valor presione. No importa que se presione alguna
de la tecla ingresada) convertido a cadena, tecla distinta
//esto se hace para poder //a la del enter ya que
visualizar en el LCD los digitos de la clave no afecta en nada a la clave ya ingresada
ingresada por el usuario antes, esto porque en esta parte del codigo,
la tecla
//las direcciones de memoria utilzadas en la //presionada no se la
EEPROM para guardar la clave son: 13, 14, 15 guarda
y 16 (las escogi yo) lcd_clrscr(); //se borra
o limpia la pantalla y el cursor se lo
int main(void) coloca en la primera fila y primera columna
{ lcd_puts(" Presione
//se establece la clave del sistema ENTER "); //se muestra el mensaje de
microprocesado presionar enter
clave0_adm=2; _delay_ms(200);
clave1_adm=7; }
clave2_adm=1;
clave3_adm=3; comprobar_clave(); //se invoca
esta funcion para verificar la clave
//se guarda la clave establecida por ingresada
el administrador switch (verif_clave)
EEPROM_write(13,clave0_adm); {
EEPROM_write(14,clave1_adm); case 0: //si se entra
EEPROM_write(15,clave2_adm); aqui la clave ingresada fue incorrecta
EEPROM_write(16,clave3_adm); lcd_clrscr(); //se borra
o limpia la pantalla y el cursor se lo
config_puertos(); //se invoca la coloca en la primera fila y primera columna
funcion para configurar los puertos del lcd_puts("Acceso
micro Denegado"); //se muestra el mensaje de
lcd_init(LCD_DISP_ON); //se inicia el acceso denegado
LCD con el cursor no visible _delay_ms(1000);
//si se llega hasta aqui
while(1) //lazo del programa se vuelve a repetir el lazo del programa
{ break;
aux=1;
while(aux==1) case 1: //si se entra
{ aqui la clave ingresada fue correcta
//se muestra el mensaje aux2=1;
de bienvenida mientras no se ingrese el lcd_clrscr(); //se borra
primer digito de la clave o limpia la pantalla y el cursor se lo
lcd_clrscr(); //se borra coloca en la primera fila y primera columna
o limpia la pantalla y el cursor se lo lcd_puts(" Menu
coloca en la primera fila y primera columna Principal "); //se muestra el mensaje menu
lcd_puts(" BIENVENIDO principal
"); //se muestra un mensaje de bienvenida _delay_ms(500);
lcd_gotoxy(0,1); //se aux1=1;
situa el cursor en la columna 1 y fila 2 while(aux1==1)
lcd_puts("Ingresar {
Clave: "); //se muestra el mensaje de //se ejecuta este
ingresar clave while mientras el operario no haya
_delay_ms(200); seleccionado una opcion del menu principal
//retardo para ver mejor los mensajes con la tecla enter
} if(bajar >=
subir)
{
resta=bajar-subir; opcion=1;
}
bajar=resta; else
subir=0; if(bajar==2)
{
menu_circular=1; //para mostrar el
menu circular de bajada lcd_clrscr(); //se borra o limpia la
} pantalla y el cursor se lo coloca en la
else primera fila y primera columna
{
lcd_puts("OFF led verde"); //se
resta=subir-bajar; muestra el mensaje

subir=resta; lcd_gotoxy(0,1); //se situa el cursor


bajar=0; en la columna 1 y fila 2

menu_circular=2; //para mostrar el lcd_puts("> ON led rojo"); //se


menu circular de subida muestra el mensaje
}
_delay_ms(200);

if(menu_circular==1) opcion=2;
{ }
if else
(bajar==0) if(bajar==3)
{ {

lcd_clrscr(); //se borra o limpia la lcd_clrscr(); //se borra o limpia la


pantalla y el cursor se lo coloca en la pantalla y el cursor se lo coloca en la
primera fila y primera columna primera fila y primera columna

lcd_puts("> ON led verde"); //se lcd_puts("ON led rojo"); //se muestra


muestra el mensaje el mensaje

lcd_gotoxy(0,1); //se situa el cursor lcd_gotoxy(0,1); //se situa el cursor


en la columna 1 y fila 2 en la columna 1 y fila 2

lcd_puts("OFF led verde"); //se lcd_puts("> OFF led rojo"); //se


muestra el mensaje muestra el mensaje

_delay_ms(200); _delay_ms(200);

opcion=0; opcion=3;
} }
else else
if(bajar==1) if(bajar==4)
{ {

lcd_clrscr(); //se borra o limpia la lcd_clrscr(); //se borra o limpia la


pantalla y el cursor se lo coloca en la pantalla y el cursor se lo coloca en la
primera fila y primera columna primera fila y primera columna

lcd_puts("ON led verde"); //se lcd_puts("OFF led rojo"); //se


muestra el mensaje muestra el mensaje

lcd_gotoxy(0,1); //se situa el cursor lcd_gotoxy(0,1); //se situa el cursor


en la columna 1 y fila 2 en la columna 1 y fila 2

lcd_puts("> OFF led verde"); //se lcd_puts("> Leer dipswitch"); //se


muestra el mensaje muestra el mensaje

_delay_ms(200); _delay_ms(200);
opcion=4; lcd_puts("ON led verde"); //se
} muestra el mensaje
else
if(bajar==5) _delay_ms(200);
{
opcion=5;
lcd_clrscr(); //se borra o limpia la }
pantalla y el cursor se lo coloca en la else
primera fila y primera columna if(subir==2)
{
lcd_puts("Leer dipswitch"); //se
muestra el mensaje lcd_clrscr(); //se borra o limpia la
pantalla y el cursor se lo coloca en la
lcd_gotoxy(0,1); //se situa el cursor primera fila y primera columna
en la columna 1 y fila 2
lcd_puts("> Leer dipswitch"); //se
lcd_puts("> Activar sirena"); //se muestra el mensaje
muestra el mensaje
lcd_gotoxy(0,1); //se situa el cursor
_delay_ms(200); en la columna 1 y fila 2

opcion=5; lcd_puts("Activar sirena"); //se


} muestra el mensaje
}
_delay_ms(200);

if(menu_circular==2) opcion=4;
{ }
if else
(subir==0) if(subir==3)
{ {

lcd_clrscr(); //se borra o limpia la lcd_clrscr(); //se borra o limpia la


pantalla y el cursor se lo coloca en la pantalla y el cursor se lo coloca en la
primera fila y primera columna primera fila y primera columna

lcd_puts("> ON led verde"); //se lcd_puts("> OFF led rojo"); //se


muestra el mensaje muestra el mensaje

lcd_gotoxy(0,1); //se situa el cursor lcd_gotoxy(0,1); //se situa el cursor


en la columna 1 y fila 2 en la columna 1 y fila 2

lcd_puts("OFF led verde"); //se lcd_puts("Leer dipswitch"); //se


muestra el mensaje muestra el mensaje

_delay_ms(200); _delay_ms(200);

opcion=0; opcion=3;
} }
else else
if(subir==1) if(subir==4)
{ {

lcd_clrscr(); //se borra o limpia la lcd_clrscr(); //se borra o limpia la


pantalla y el cursor se lo coloca en la pantalla y el cursor se lo coloca en la
primera fila y primera columna primera fila y primera columna

lcd_puts("> Activar sirena"); //se lcd_puts("> ON led rojo"); //se


muestra el mensaje muestra el mensaje

lcd_gotoxy(0,1); //se situa el cursor lcd_gotoxy(0,1); //se situa el cursor


en la columna 1 y fila 2 en la columna 1 y fila 2
}
lcd_puts("OFF led rojo"); //se }
muestra el mensaje switch (opcion)
{
_delay_ms(200); case 0: //ON led
verde
opcion=2; PORTD=PIND |
} 0b00001000;
else break;
if(subir==5) case 1: //OFF led
{ verde
PORTD=PIND &
lcd_clrscr(); //se borra o limpia la 0b11110111;
pantalla y el cursor se lo coloca en la break;
primera fila y primera columna case 2: //ON led
rojo
lcd_puts("> OFF led verde"); //se PORTD=PIND |
muestra el mensaje 0b00010000;
break;
lcd_gotoxy(0,1); //se situa el cursor case 3: //OFF led
en la columna 1 y fila 2 rojo
PORTD=PIND &
lcd_puts("ON led rojo"); //se muestra 0b11101111;
el mensaje break;
case 4:
_delay_ms(200);
break;
opcion=1; case 5: //Activar
} sirena
} PORTD=PIND |
//este 0b00100000;
condicional es para mostrar el numero break;
ingresado por el dipswitch si es que se default:
presiono enter y se selecciono break;
//la opcion 4 }
(Leer dipswitch)
if((aux1==0) && break;
(opcion==4)) default:
{ break;
}
dipswitch=PINB; }
}
lcd_clrscr(); //se borra o limpia la
pantalla y el cursor se coloca en la primera void config_puertos (void)
fila y primera columna {
DDRA=0b00000000;
lcd_puts("Dipswitch: "); //se muestra DDRB=0b00000000;
el mensaje DDRC=0b01111111;
DDRD=0b00111000;
utoa(dipswitch,tecla1,10); PORTA=0b11111111;
PORTB=0b11111111;
lcd_gotoxy(0,1); //se situa el cursor PORTC=0b10000000;
en la columna 1 y fila 2 PORTD=0b11000111; //se activa el
pull-up en la patita del INT0
lcd_puts(tecla1); //se muestra el EICRA=0b00000010; //interrupcion
numero ingresado por el dipswitch activada por flanco de bajada ya que el DA
se pone en 1L cuando hay una tecla
_delay_ms(300); presionada
aux1=1; EIMSK=0b00000001; //INT0 activada
//se deshabilita el enter sei();
}
//terminado este condicional se
vuelve a mostrar el menu principal
void EEPROM_write (unsigned int uiAddress, lcd_gotoxy(0,1); //se situa el
unsigned char var) //en var va la variable, cursor en la columna 1 y fila 2
uiAddres es cualquier numero de 0-255 lcd_puts(tecla1); //se muestra
{ el primer digito ingresado
/* Wait for completion of previous _delay_ms(200);
write */ }
while(EECR & (1<<EEPE));
clave1_ope=tecla; //se guarda el
/* Set up address and data registers segundo digito de la clave ingresada
*/ utoa(tecla,tecla1,10);
EEAR=uiAddress; aux=1;
EEDR=var; while (aux==1)
/* Write logical one to EEMPE */ {
EECR |= (1<<EEMPE); //se muestra el segundo digito
/* Start eeprom write by setting EEPE ingresado mientras no se ingrese el tercer
*/ digito
EECR |= (1<<EEPE); lcd_gotoxy(1,1); //se situa el
} cursor en la columna 2 y fila 2
lcd_puts(tecla1); //se muestra
unsigned char EEPROM_read (unsigned int el segundo digito ingresado
uiAddress) _delay_ms(200);
{ }
/* Wait for completion of previous
write */ clave2_ope=tecla; //se guarda el
while(EECR & (1<<EEPE)); tercer digito de la clave ingresada
utoa(tecla,tecla1,10);
/* Set up address register */ aux=1;
EEAR=uiAddress; while (aux==1)
/* Start eeprom read by writing EERE {
*/ //se muestra el tercer digito
EECR |= (1<<EERE); ingresado mientras no se ingrese el cuarto
/* Return data from Data Register */ digito
return EEDR; lcd_gotoxy(2,1); //se situa el
} cursor en la columna 3 y fila 2
lcd_puts(tecla1); //se muestra
void ingresar_clave (void) el tercer digito ingresado
{ _delay_ms(200);
lcd_clrscr(); //se borra o limpia la }
pantalla y el cursor se coloca en la primera
fila y primera columna clave3_ope=tecla; //se guarda el
lcd_puts("Ingresar Clave: "); //se cuarto digito de la clave ingresada
muestra el mensaje de ingresar clave utoa(tecla,tecla1,10);
aux=1;
clave0_ope=tecla; //se guarda el //estas tres lineas de codigo no se
primer digito de la clave ingresada las puso dentro de un while, para que el
utoa(tecla,tecla1,10); //la función programa
utoa convierte un numero entero sin signo en //retorne solo al main y no se
una cadena de caracteres muestre indefinidamente el cuarto digito
//tecla es el lcd_gotoxy(3,1); //se situa el cursor
numero sin signo que se quiere visualizar en en la columna 4 y fila 2
el LCD por lo cual hay que convertirlo en lcd_puts(tecla1); //se muestra el
una cadena de caracteres cuarto digito ingresado
//tecla1 es un _delay_ms(200);
arreglo donde se guardará el numero sin }
signo convertido a cadena
//10 es la void comprobar_clave (void)
base numerica en la que se quiere ver el {
numero convertido en la pantalla LCD clave0_adm=EEPROM_read(13); //se saca
aux=1; (lee) la clave, establecida por el
while (aux==1) administrador, de la memoria EEPROM
{ clave1_adm=EEPROM_read(14);
//se muestra el primer digito clave2_adm=EEPROM_read(15);
ingresado mientras no se ingrese el clave3_adm=EEPROM_read(16);
segundo digito
if ((clave0_adm == clave0_ope) && case 10:
(clave1_adm == clave1_ope) && (clave2_adm == tecla=7;
clave2_ope) && (clave3_adm == clave3_ope)) aux=0;
{ break;
verif_clave=1; //significa que case 11:
clave ingresada es correcta aux=1;
} if(aux2==1)
else {
{ bajar++;
verif_clave=0; //significa que }
clave ingresada es incorrecta if(bajar==6)
} {
} bajar=0;
}
//interrupcion para obtener la tecla break;
presionada case 12:
ISR(INT0_vect) aux=1;
{ break;
tecla=(PINA & (0b00001111)); //se case 13:
escogen los 4 bits menos significativos, es aux=1;
decir solo el codigo de la tecla que da el break;
MM74C922 case 14:
switch (tecla) aux=1;
{ break;
case 0: case 15:
tecla=3; aux=1;
aux=0; if(aux2==1)
break; {
case 1: subir++;
tecla=2; }
aux=0; if(subir==6)
break; {
case 2: subir=0;
tecla=1; }
aux=0; break;
break; default:
case 3: break;
tecla=0; }
aux=0; }
break;
case 4:
tecla=6;
aux=0;
break;
case 5:
tecla=5;
aux=0;
break;
case 6:
tecla=4;
aux=0;
break;
case 7:
//tecla del enter
aux1=0;
break;
case 8:
tecla=9;
aux=0;
break;
case 9:
tecla=8;
aux=0;
Fig. 7 Simulación del sistema microprocesado en Proteus.
break;

También podría gustarte