Algunas de las rutinas están escritas en Cy
las demás en ensamblador. Estas últimas son desarrolladas
utilizando la
directiva #pragma asm y
#pragma dasm, las cuales permiten realizar la interface entre programas
escritos en
ensamblador y en C.
1. Rutina principal .
/* ***************************************************************************************
upuerta.c
Rutina principal de manejo del módulo de control de la puerta
---------------------------------------------------------------
Trabajo Práctico
Proyecto con Microprocesadores 1
1er semestre - 1999
Facultad de Ciencias y Tecnología
Universidad Católica Nuestra Señora de la Asunción
---------------------------------------------------------------
Descricpción : implementación
de la máquina de estados principal
que controla el sistema de control de acceso de la puerta.
---------------------------------------------------------------
Fecha : 22 / 07 / 1999 ( Versión final)
Por José Ricardo Otazo Torres
**************************************************************************************** */
#include<stdlib.h>
#include<reg51.h>
// Definiciones
// ---------------------------------------------------------------------------------------
// Dirección del
módulo en la red
// ------------------------------
#define DIRECCION_RED
0x01
// Estados posibles para
la máquina de estados principal
// -----------------------------------------------------
#define RED
0x00
#define B_BOT
0x01
#define B_TEC
0x02
#define PES
0x03
// Modos de funcionamiento
posibles
// --------------------------------
#define BOTON
0x20
#define TECLADO
0x21
#define BOT_TEC
0x22
#define PESENC
0x24
#define BLOQUEADO
0x25
// Comandos posibles
enviados desde la unidad de control central
// -------------------------------------------------------------
#define ENVIAR_CONDICION
0x10
#define CAMBIAR_MODO
0x11
#define ENVIAR_BOTON
0x12
#define ENVIAR_TECLADO
0x13
#define BOTON_CORRECTO
0x14
#define CODIGO_INCORRECTO
0x15
#define ACCIONAR_PESTILLO
0x16
#define RE_TX
0x19
// Variables globales
// ------------------------------------------------------------------------------------------
extern unsigned char
idata estado_rx;
extern unsigned char
idata CTECLAS;
// Estado de la máquina
principal
unsigned char idata
estado;
// Buffer de almacenamiento
de a paquete a transmitir
unsigned char idata
buffer_tx[12];
// Puntero al buffer
de almacenamiento de paquete recibido por la capa de enlace
unsigned char idata
*buffer_rx;
// Buffer de almacenamiento
de código de teclado capturado
unsigned char idata
buffer_teclado[6];
// Buffer de almacenamiento
de código de botón leído
unsigned char idata
buffer_boton[8];
// Almacenamiento de
la condicion del módulo
unsigned char idata
condicion;
/*
b7
b6 b5 b4 b3
b2 b1 b0
______ ______
______ ______ ______ ______ ______ ______
|
| | |
| | |
| |
|
X | X | X | X
| PES | PTA | T | B |
|______|______|______|______|______|______|______|______|
B :
1=botón leído
T : 1=seis teclas leídas
PTA : 1=puerta
abierta
PES : 1=pestillo
accionado
*/
// Almacenamiento del
comando recibido a través de la red
unsigned char comando;
// Modo de funcionamiento
del módulo
unsigned char modo;
// Contador de múltiplos
de 30 ms para el tiempo de apertura
unsigned char idata
tiempo;
// Bits de bandera
// ----------------
bit COD ;
// código correcto ingresado
bit BUF_BOT;
// código de botón ingresado
bit BUF_TEC;
// código de teclado ingresado
bit MODO_BT;
// modo botón+teclado : indica que el código de botón
ya fue correcto
// Bits de interface
(pines específicos del microcontrolador)
// ----------------------------------------------------------
sbit PESTILLO = 0x82;
// pin P0.2
sbit SENSOR_PUERTA =
0x80; // pin P0.0
// Funciones
// -----------------------------------------------------------------------------------------
// Inicializaciones del
microcontrolador
// -------------------------------------
extern void inicializaciones(unsigned
char direccion_red);
// Aplicaciones de red
// -------------------
extern void enviar_condicion(unsigned
char idata *buffer_tx,unsigned char condicion);
extern void teclado_enviar(unsigned
char idata *buffer_tx,unsigned char idata *codigo);
extern void boton_enviar(unsigned
char idata *buffer_tx,unsigned char idata *codigo);
extern void re_tx( unsigned
char idata *buffer_tx);
extern unsigned char
cambiar_modo(unsigned char comando);
// Capa de enlace
// ---------------
extern void iniciar_red(unsigned
char midireccion);
extern int a_enlace(unsigned
char idata *buffer);
extern unsigned char
idata *de_enlace(void);
// Teclado
// -------
extern bit leer_teclado(unsigned
char idata *teclado);
// Boton
// -----
extern bit leer_boton(unsigned
char idata *boton);
// LCD
// ----
extern void lcd_men1(
bit TIPO);
extern void lcd_men2(
void);
extern void lcd_men3(void);
extern void lcd_borrar(void);
// Temporizadores
// --------------
extern void temp_pes(void);
void main(void)
{
// inicializaciones para la red, lcd y temporizadores
inicializaciones( DIRECCION_RED );
// máquina de estados principal
while(1)
{
switch (estado)
{
case RED:
// hay paquete recibido ?
if(buffer_rx = de_enlace())
{
// leer comando
comando = buffer_rx[2];
// interpretación de comando
switch (comando&0x1F)
{
case ENVIAR_CONDICION:
// envío del byte de condición
enviar_condicion(buffer_tx,condicion);
break;
case ENVIAR_BOTON:
// envío del buffer de boton
boton_enviar(buffer_tx,buffer_boton);
break;
case ENVIAR_TECLADO:
// envío del buffer de teclado
enviar(buffer_tx,buffer_teclado);
break;
case BOTON_CORRECTO:
BUF_BOT = 0;//botón atendido
MODO_BT = 1;//pasamos a esperar teclas
condicion&=0xFE;//actualizamoscondicion
//despliegue de mensaje
//" Ingresar código por teclado"
lcd_borrar();
lcd_men2();
break;
case CODIGO_INCORRECTO:
// inicializamos los bits de bandera
BUF_BOT = 0;
BUF_TEC = 0;
MODO_BT = 0;
condicion = 0;// actualizamos condicion
// despliegue de mensaje
// " Código incorrecto "
lcd_borrar(); //borramos lcd
lcd_men1(0);// despliegue de mensaje
temp_pes(); / / inicializamos temporizador
while(tiempo<30); // esperamos por tiemout
//desactivamos temporizador
TR0 = 1;
ET0 = 0;
lcd_borrar();
break;
case ACCIONAR_PESTILLO:
PESTILLO = 1;//accionamos pestillo
//activación del temporizador de tiempo
//de apertura
temp_pes();
// inicializamos bits de bandera
BUF_BOT = 0;
BUF_TEC = 0;
MODO_BT = 0;
COD = 1;//señal pestillo accionado
condicion=0x08;//actualizamos condicion
// " Código correcto "
lcd_borrar();//borramos lcd
lcd_men1(1);//despligue de mensaje
break;
case CAMBIAR_MODO:
// solo importan los 5 MSB
comando&=0xE0;
// cambiamos modo
modo = cambiar_modo(comando);
//inicializamos bits de bandera
BUF_BOT = 0;
BUF_TEC = 0;
MODO_BT = 0;
lcd_borrar(); //
borramos lcd
if(modo==BLOQUEADO)
//deplegamos mensaje en
caso
// de modo bloqueado
lcd_men3();
break;
case RE_TX:
// retransmisión de último frame
re_tx(buffer_tx);
break;
default:
break;
}
}
// cambio de estado
if (COD) estado = PES; // ya hay un código validado
else
{
switch(modo)
{
case BOTON :
if(!BUF_BOT)
//si no hay botón leído
//cambio al estado B_BOT
estado = B_BOT;
break;
case TECLADO :
if(!BUF_TEC)
//si no hay teclado leído
//cambio al estado B_TEC
estado = B_TEC;
break;
case BOT_TEC :
if (!MODO_BT)
{ // todavía no hay botón
if(!BUF_BOT) estado = B_BOT;
}
else
{ // ya hay botón correcto
if(!BUF_TEC) estado = B_TEC;
}
break;
default :
break;
}
} // final de decisión de cambio de estado
break;// final estado = RED
case B_BOT:// estado de búsqueda de botones
if (leer_boton(buffer_boton))//leemos botón
{
// hay botón leído
BUF_BOT = 1; // botón leído
condicion|= 0x01; // actualizamos byte de condicion
estado = RED; // pasamos al estado RED
}
else
{ // no hay botón leído
if (estado_rx == 7)
// si hay paquete de red pasamos al estado RED
estado = RED;
}
break;
case B_TEC:// estado de búsqueda de teclas
if (leer_teclado(buffer_teclado))
{
// hay código de 6 teclas leídas
BUF_TEC = 1; // alertamos bit de bandera
condicion|=0x02; // actualizamos byte de condicion
estado = RED; // pasamos al estado RED
}
else
{
// no hay código de 6 teclas leído
if (estado_rx == 7)
// si hay paquete de red pasamos al estado RED
estado = RED;
}
break;
case PES: // estado de pestillo accionado
if(tiempo >100)
{
//se cumplieron los tres
segundos
PESTILLO = 0;//apagamos el pestillo
TR0 = 1; // timer 0 off
ET0 = 0; // deshabilitación de interrupciones
// para el timer 0
COD = 0;
// actualizamos bandera
lcd_borrar();// borramos mensaje en el display
estado = RED;// cambiamos al estado RED
}
else
{
if (estado_rx == 7)
// si hay paquete de red pasamos al estado RED
estado = RED;
}
break;
default :
break;
}//fin switch de la máquina de estados
//revisamos condicion de la puerta
if(!SENSOR_PUERTA) condicion|= 0x04; // puerta abierta
else condicion&=0xFB; // puerta cerrada
}
}
2. Inicializaciones .
/* *****************************************************************************************
SUBRUTINA : inicializaciones
------------------------------------------------------------------------------------
DESCRIPCION : se inicializan todas las variables y registros del microcontrolador,
asimismo como la capa de enlace.
------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
unsigned char direccion_red : direccion de red(solo importan los cinco
bits MSB)
------------------------------------------------------------------------------------
VALORES DE RETORNO:Ninguno
------------------------------------------------------------------------------------
*****************************************************************************************
*/
void inicializaciones(unsigned
char direccion_red)
{
// inicialización de la capa de enlace
iniciar_red(direccion_red);
// inicialización del timer 0
TMOD|= 0x01; // timer 0 modo 1: 16-Bit
// habilitación de interrupciones
EA = 1;
// inicialización del lcd driver
lcd_iniciar(LCD_MODO);
lcd_borrar();
// máquina de estados principal
estado = RED;
// inicializamos máquina de estados
modo = BOTON;
// BOTON = modo por defecto
BUF_BOT = 0;
// no hay botón leído
BUF_TEC = 0;
// no hay tecla leída
MODO_BT = 0;
// en el modo botón + teclado, todavía no hay botón
correcto
COD = 0;
// sin código correcto
PESTILLO = 0;
// pestillo apagado
}
3. Rutinas de comunicaciones .
/* *********************************************************************************************
enlace.c
Rutinas para la capa de enlace de datos
---------------------------------------------------------------
Trabajo Práctico
Proyecto con Microprocesadores 1
1er semestre - 1999
Facultad de Ciencias y Tecnología
Universidad Católica Nuestra Señora de la Asunción
---------------------------------------------------------------
Por José Ricardo Otazo Torres
*********************************************************************************************
*/
#include<stdlib.h>
#include <stdlib.h>
#include <reg51.h>
// Estados posibles para
estado_rx y estado_tx
//----------------------------------------------------------
#define T0 0
#define T1 1
#define T2 2
#define R0 3
#define R1 4
#define R2 5
#define R3 6
#define R4 7
// Habilitador de transmisión
( Pin 12 del AT89C52)
//----------------------------------------------------------
#define TX_E INT0
// Variables del protocolo
//----------------------------------------------------------
unsigned char idata
estado_tx = T0; // Estado
de transmisión
unsigned char idata
estado_rx = R0; // Estado
de recepcion
unsigned char idata
chksm_tx;
// Check Sum de salida
unsigned char idata
chksm_rx;
// Check Sum de entrada
unsigned char idata
*puntero_tx;
// Puntero al buffer de salida
unsigned char idata
bufferi_ser[10]; // Buffer de
entrada
unsigned char idata
conteo_tx;
// Número de byte de entrada
unsigned char idata
conteo_rx;
// Número de byte de salida
unsigned char direccion_red;
// Dirección en la red
/* *****************************************************************************************
FUNCION : iniciar_red
---------------------------------------------------------------------------------
DESCRIPCION : inicialización del modo, velocidad y flags de interrupciones
el puerto serial. Recibe el valor de direccion de red en midireccion y
lo
guarda en direccion_red.
---------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
unsigned char midireccion : dirección de red
---------------------------------------------------------------------------------
VALOR DE RETORNO : Ninguno
---------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA FUNCION : SCON, TH1,TMOD, TR, IE,
---------------------------------------------------------------------------------
*****************************************************************************************
*/
void iniciar_red(unsigned
char midireccion)
{
// dirección
de red
direccion_red
= midireccion&0x1F; // solo importan los 5 bit menos significativos
// modo de funcionamiento
del puerto serial
SM2 = 1;
//9no. bit
SM0 = 1; SM1 =
1; //modo 3
REN = 1;
//habilitamos recepción
TX_E = 0;
//no se transmite
//velocidad de
comunicación (se utiliza al timer 1 para generar la tasa de bits)
TMOD |= 0x20;
// timer 1 modo 2: 8-Bit reload
TH1
= 0xFD; // valor de reload 9600 baudios (f = 11.059MHz)
TR1
= 1; // timer 1 run
// interrupciones
para el puerto serial
ES
= 1; // Habilitar interrupcion serial
EA
= 1; // Habilitar interrupciones
}
/* *****************************************************************************************
FUNCION : Rutina de interrupción de TX/RX de la capa de enlace
---------------------------------------------------------------------------------
DESCRIPCION : implementación de las máquinas de estado de
transmisión y recepción.
---------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
* puntero_tx, TI, TX_E, RB8, SBUF, chksm_tx, conteo_tx
puntero_rx, RI, estado_rx, estado_tx
---------------------------------------------------------------------------------
VALOR DE RETORNO : Ninguno
---------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA FUNCION :
* puntero_tx, TI, TX_E, TB8, SBUF, chksm_tx, conteo_tx
puntero_rx, RI, SM2, estado_rx, estado_tx
---------------------------------------------------------------------------------
*****************************************************************************************
*/
void isr_serial(void)
interrupt 4 using 2//rutina de interrupciones para el puerto serial
{
if(TI)
{
TI=0;
// Borrar flag
switch (estado_tx)
{
case T0: TX_E = 0;// deshabilitar escritura al canal
break;
case T1:
TB8=0; // Solo son datos
TX_E=1; // Habilitar escritura al canal
chksm_tx^=*puntero_tx;
SBUF=*puntero_tx++;
if (!(--conteo_tx)) estado_tx=T2;//Ultimo byte del buffer?
break;
case T2:
// Enviar check sum
SBUF=chksm_tx;
estado_tx=T0;
break;
default: estado_tx=T0;
}
}
if(RI)
{
RI=0; // Borrar flag de recepción
switch (estado_rx)
{
case R0:
if((SBUF&0x1F)==direccion_red)//Mi direccion?
{
bufferi_ser[0]=SBUF;
chksm_rx=SBUF;
SM2=0; //Recibir datos
estado_rx=R1;
}
break;
case R1:
if(RB8)//Es control?
{
if((SBUF&0x1F)==direccion_red)//Es mi dirección
{
bufferi_ser[0]=SBUF;//almacenamos direccion
chksm_rx=SBUF; //calculamos
CHKSM
}
else
{
estado_rx=R0;
SM2=1;//solo recibimos con 9°bit = 1
}
}
else
{
conteo_rx=0;// Para llevar cuenta de bytes recibidos
chksm_rx^=SBUF;
bufferi_ser[1]=SBUF;//Número de bytes
estado_rx=R2;
}
break;
case R2:
if(RB8)//Es control?
{
if((SBUF&0x1F)==direccion_red)//Es mi dirección?
{
bufferi_ser[0]=SBUF;
chksm_rx=SBUF;
estado_rx=R1;
}
else
{
estado_rx=R0;
SM2=1;
}
}
else
{
bufferi_ser[conteo_rx+2]=SBUF;
chksm_rx^=SBUF;
//Es el fin de los datos antes del check sum
if(++conteo_rx==bufferi_ser[1]) estado_rx=R3;
}
break;
case R3:
if(RB8)// Es control?
{
if((SBUF&0x1F)==direccion_red)//Es mi dirección?
{
bufferi_ser[0]=SBUF;
chksm_rx=SBUF;
estado_rx=R1;
}
else
{
estado_rx=R0;
SM2=1;
}
}
else
{
if (chksm_rx==SBUF)//Es correcto el check_sum
{
estado_rx=R4;
}
else
{
estado_rx=R0;//Anular trama recibida
}
SM2=1;//Recibir solo byte de dirección
}
break;
case R4: //Estado de buffer con información
if((SBUF&0x1F)==direccion_red)//Es mi dirección
{
bufferi_ser[0]=SBUF;
chksm_rx=SBUF;
SM2=0;//Recibir datos
estado_rx=R1;
}
break;
default: estado_rx=R0;
}
}
}
/* *****************************************************************************************
FUNCION : a_enlace
---------------------------------------------------------------------------------
DESCRIPCION : transmisión del byte de dirección destino (
9°bit = 1) e
inicialización de la máquina de estados de transmisión.
---------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
unsigned char *buffer : puntero al buffer de transmisión
---------------------------------------------------------------------------------
VALOR DE RETORNO : 0 = Se ha transmitido la dirección destino.
1 = Se está transmitiendo otra trama
---------------------------------------------------------------------------------
*****************************************************************************************
*/
int a_enlace(unsigned
char idata *buffer)
{
if (estado_tx==T0)
{
puntero_tx=buffer;
//Envío
del byte de control
TI=0;
TX_E=1;
TB8=1;
SBUF=*puntero_tx;
chksm_tx=*puntero_tx++;
//Inicializamos
el contador
conteo_tx=*puntero_tx+1;
//Inicializamos
máquina de estados
estado_tx=T1;
return(0);
}
else
{
return(1); //error, el sistema está transmitiendo otra trama
}
}
/* *****************************************************************************************
FUNCION : de_enlace
---------------------------------------------------------------------------------
DESCRIPCION : pregunta si hay un frame recibido por la capa de enlace.
De ser así reinicializa la máquina de recepción
---------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
---------------------------------------------------------------------------------
VALOR DE RETORNO : Devuelve el puntero al buffer de recepción si
hay una trama
recibida o Null(0) en caso contrario.
---------------------------------------------------------------------------------
*****************************************************************************************
*/
unsigned char idata *de_enlace(void)
{
if (estado_rx==R4)//hay
frame recibido?
{
estado_rx = R0;
//se reinicializa la máquina de recepción
return(bufferi_ser);
}
return(0); // Puntero
NULL
}
4. Rutinas de aplicaciones de la capa de enlace.
/* *******************************************************************************************
FUNCION : enviar_condicion
---------------------------------------------------------------------------------------
DESCRIPCIÓN : Utilizando los servicios de la capa de enlace, se
envía el byte de
condicion, que indica las condiciones del módulo de control de la
puerta.
---------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
*buffer_tx : puntero al buffer de transmisión de paquetes
estado : byte de estado
---------------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
*******************************************************************************************
*/
void enviar_condicion(unsigned
char idata *buffer_tx,unsigned char condicion)
{
//armado del frame de enlace
buffer_tx[1]=0x01;
// N = 1
buffer_tx[2]=condicion;
// dato = estado
while(a_enlace(buffer_tx)); // inicio
de tx a través de la capa de enlace
}
/* *******************************************************************************************
FUNCION : teclado_enviar
---------------------------------------------------------------------------------------
DESCRIPCIÓN : Utilizando los servicios de la capa de enlace, se
envía el código
de 6 bytes almacenado en buffer_teclado.
---------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
--------------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
*******************************************************************************************
*/
void teclado_enviar(void)
{
unsigned char idata indice = 0; // indice del vector del código
// armado del frame de enlace
buffer_tx[1]=6; // N =
6
while(indice < 6)
{
buffer_tx[indice+2]=buffer_teclado[indice]; // copiamos digito número
indice
indice++; // siguiente digito del código
}
while(a_enlace(buffer_tx)); // transimisión del frame de enlace
}
/* *******************************************************************************************
FUNCION : boton_enviar
---------------------------------------------------------------------------------------
DESCRIPCIÓN : Utilizando los servicios de la capa de enlace, se
envía el código
de 6 bytes almacenado en buffer_boton.
---------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
--------------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
*******************************************************************************************
*/
void boton_enviar(void)
{
unsigned char idata indice = 0; // indice del vector del código
// armado del frame de enlace
buffer_tx[1]=7;
// N = 7
while(indice < 7)
{
buffer_tx[indice+2]=buffer_boton[indice]; // copiamos digito número
indice
indice++; // siguiente digito del código
}
while(a_enlace(buffer_tx)); // transimisión del frame de enlace
}
/* *******************************************************************************************
FUNCION : re_tx
---------------------------------------------------------------------------------------
DESCRIPCIÓN : Retransimisión del último paquete enviado.
---------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
*buffer_tx : puntero al buffer de transmisión de paquetes. Aquí
quedó almacenado el
frame de enlace transmitido.
---------------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
---------------------------------------------------------------------------------------
*******************************************************************************************
*/
void re_tx( unsigned
char idata *buffer_tx)
{
while(a_enlace(buffer_tx));// enviamos el último frame
}
/* *******************************************************************************************
FUNCION : cambiar_modo
---------------------------------------------------------------------------------------
DESCRIPCIÓN : Cambio del byte de modo, de acuerdo a lo indicado
por el comando
recibido desde control central.
---------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
unsigned char comando : comando recibido desde control central (solo los
tres bits
más significativos )
--------------------------------------------------------------
VALORES DE RETORNO:
unsigned char modo : byte de modo de funcionamiento
---------------------------------------------------------------------------------------
*******************************************************************************************
*/
unsigned char cambiar_modo(unsigned
char comando)
{
unsigned char modo; // variable local de nuevo
modo
//de acuerdo a comando cambiamos de modo
switch(comando)
{
case 0x20 : // cambiamos a modo BOTON
modo = BOTON;
break;
case 0x40 : // cambiamos a modo TECLADO
modo = TECLADO;
break;
case 0x60 : // cambiamos a modo BOTON y TECLADO
modo = BOT_TEC;
break;
case 0x80 : // cambiamos a modo BLOQUEADO
modo = BLOQUEADO;
break;
default :
break;
}
return modo;
}
5. Rutinas de lectura de ibuttom .
/* **********************************************************************************************
boton.c
Rutinas para lectura de ibuttom
---------------------------------------------------------------
Trabajo Práctico
Proyecto con Microprocesadores 1
1er semestre - 1999
Facultad de Ciencias y Tecnología
Universidad Católica Nuestra Señora de la Asunción
---------------------------------------------------------------
Por José Ricardo Otazo Torres
*********************************************************************************************
*/
#include<stdlib.h>
#include<reg51.h>
// funciones a utilizar
en leer_boton
// ---------------------------------------------------------------------------------------------
bit boton_reset(void);
unsigned char boton_leer_byte(void);
void boton_hab_lect(void);
unsigned char boton_calcular_crc(unsigned
char crc,unsigned char entrada);
// pin del microcontrolador
utilizado para la comunicación con el botón
// ---------------------------------------------------------------------------------------------
sbit BOTON = 0x81;
//P0.1
/* *******************************************************************************************
FUNCION : leer_boton
---------------------------------------------------------------------------------------
DESCRIPCIÓN : Lectura del ibuttom y almacenamiento del código
en buffer_boton
---------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
unsigned char idata *buffer : puntero al buffer del boton
--------------------------------------------------------------
VALORES DE RETORNO:
1 : se leyó un botón
0 : no hay botón en el lector
---------------------------------------------------------------------------------------
******************************************************************************************* */
bit leer_boton(unsigned
char idata *buffer)
{
bit bot_ok = 0;
// valor de retorno
unsigned char idata indice; // contador de bytes
del botón leídos
unsigned char idata boton_crc; // control de errores en la comunicación
con el botón
// hay un botón?
if(boton_reset())
{
//si hay
//deshabilitar la red
ES = 0;
EA = 0;
boton_hab_lect();//comando para leer el botón
//lectura del botón
indice = 0;
while(indice<8)
{
buffer[indice++] = boton_leer_byte();//leemos el boton byte a byte
}
//habilitar nuevamente la red
ES = 1;
EA = 1;
//control de errores en la lectura del boton
// cálculo del polinomio crc
indice = 0;
while(indice<8)
{
boton_crc = boton_calcular_crc(boton_crc,buffer[indice++]);
}
// si no hay errores retornar 1
if(!boton_crc)
{
bot_ok = 1;
}
}
return bot_ok;
}
/*
********************************************************************************
FUNCION : boton_reset
--------------------------------------------------------------------------------
DESCRIPCION: transmisión del pulso de reset al ibuttom y espera
por presencia
de ibuttom. El período de reset es de 480 us como mínimo
y el período de
presencia es de 60 us como mínimo.
--------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
--------------------------------------------------------------------------------
VALOR DE RETORNO : 1, se detectó un ibuttom
0, nio hay ibuttom
--------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA: los acumuladores A y B.
--------------------------------------------------------------------------------
******************************************************************************** */
bit boton_reset(void)
{
#pragma asm
push ACC
; salvamos A en la pila
push B
; salvamos B en la pila
; envío del pulso de reset con duración de 480 us
mov A,#4
; inicializamos A con 4 , para uso posterior
clr BOTON
; enviamos pulso de reset
mov B,#221
; inicilizamos B para duración de pulso de 480 us
djnz B,$
; espera por 480 us
setb BOTON
; línea del botón = 1
mov B,#6
; inicializamos B, para espera por 0 en la línea
clr C
; borramos valor de retorno
ESPERA:
jb BOTON, WH
; si la línea está en alto, no hay botón
djnz B,ESPERA
; la línea está en 0, esperamos 60 us
djnz ACC,ESPERA
sjmp FIN
; si la línea se mantiene en bajo se venció el tiempo
WH:
mov B,#111
; número de muestras de línea
HL:
orl C,/BOTON
; detectamos nivel
djnz B,HL
; repetimos por 111 veces
FIN
pop ACC
; recuperamos A
pop B
; recuperamos B
RET
#pragma endasm
}
/*
********************************************************************************
FUNCION : boton_leer_byte
------------------------------------------------------------------------------
DESCRIPCION: se lee un byte del código del botón en forma
serial utilizando el
procedimiento interno LEER_BIT. Se forma el time slot correspondiente para
el
envío de datos al botón.
------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
------------------------------------------------------------------------------
VALOR DE RETORNO : el byte leído
------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA: los acumuladores A y B.
------------------------------------------------------------------------------
********************************************************************************
*/
unsigned char boton_leer_byte(void)
{
#pragma asm
push ACC
; salvamos A en la pila
mov A,#0FFh
; cargamos valor de envío al botón ( FF para lectura)
push B
; salvamos B
mov B,#8
; 8 bits a leer
; lectura de 8 bits usando la función LEER_BIT
BIT_LOOP:
rrc A
; copiamos bit a enviar
call LEER_BIT
; mandamos bit al ibuttom
djnz B,BIT_LOOP
; se realiza 8 veces
rrc A
; alineamos A
mov R7,A
; copiamos valor de retorno
pop B
; recuperamos B
pop ACC
; recuperamos A
RET
; salimos de la función
; lectura de 1 bit
LEER_BIT:
clr BOTON
; línea del botón = 0
nop
; retardo de 1 us de tal forma que el ibuttom sienta
NOP
; el pulso
NOP
NOP
mov BOTON, C
; enviamos bit contenido en C
NOP
; retardo para asegurar dato válido
NOP
NOP
NOP
NOP
NOP
mov C,BOTON
; copiamos valor de retorno
push B
; salvamos B
mov B,#18
; cargmos B para finalizar temporización
djnz B,$
; esperamos por fin de temporización
pop B
; recuperamos B
SETB BOTON
; línea del botón = 1 ( final de time slot de lectura)
RET
#pragma endasm
}
/*
********************************************************************************
FUNCION : boton_crc
------------------------------------------------------------------------------
DESCRIPCION: cálculo del byte crc para un byte leído desde
el botón
------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
unsigned char crc : byte crc del byte
anterior
unsigned char entrada : byte leído
------------------------------------------------------------------------------
PASO DE PARAMETROS : a través de los registros R7 (crc) y R5 (byte
leído)
------------------------------------------------------------------------------
VALOR DE RETORNO : el nuevo valor del byte crc
------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA: R7
------------------------------------------------------------------------------
******************************************************************************** */
unsigned char boton_crc(unsigned
char crc,unsigned char entrada)
{
#pragma asm
push ACC
; salvamos A
mov A,R5
; cargamos byte leído en A
push ACC
; salvamos valor leído
push B
; salvamos B
push ACC
; salvamos nuevamente valor leído ( se usa dos veces)
mov B,#8
; 8 bits
CRC_LOOP:
xrl A,R7
; calculamos crc
RRC A
; lo movemos al bit de acarreo
mov A,R7
; obtenemos el último valor de crc
jnc CERO
; si fue cero, no actualizamos
xrl A,#24
; actualizamos valor de crc
CERO:
rrc A
; posicionamos el nuevo CRC
mov R7,A
; almacenamos nuevo valo de crc
pop ACC
; obtenemos los bits restantes
rr A
; posicionamos el siguiente bit
push ACC
; salvamos los bits que faltan
djnz B,CRC_LOOP
; repetimos para 8 bits
pop ACC
; recuperamos A
pop B
; recuperamos B
pop ACC
; limpiamos la pila
pop ACC
; recuperamos valor original de A
; el valor de retorno queda almacenado en R7
#pragma endasm
}
6. Rutinas de lectura de teclado .
/* **********************************************************************************************
teclado.c
Rutinas para lectura de teclado
---------------------------------------------------------------
Trabajo Práctico
Proyecto con Microprocesadores 1
1er semestre - 1999
Facultad de Ciencias y Tecnología
Universidad Católica Nuestra Señora de la Asunción
---------------------------------------------------------------
Por José Ricardo Otazo Torres
*********************************************************************************************
*/
// Variables globales
// ------------------------------------------------------------------------
bit BUSCAR_TECLA;
// habilitación de barrido
bit TECLA_VALIDA;
// tecla válida sin rebotes
unsigned char idata
CTECLAS; // contador del número de teclas capturadas
bit TECLA_PROC;
// tecla en procesamiento
bit TECLA_PRES;
// bandera de tecla presionada
/* *******************************************************************************************
FUNCION : leer_teclado
---------------------------------------------------------------------------------------
DESCRIPCIÓN :se realiza una vez el barrido del teclado y se almacena
los resultados
en variables estáticas locales, de tal forma a seguir desde donde
se había quedado
en la próxima llamada.
---------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
*buffer : puntero al buffer de teclado
---------------------------------------------------------------------------------------
VALORES DE RETORNO: En el bit C (acarreo): código de 6 dígitos
leído
---------------------------------------------------------------------------------------
*******************************************************************************************
*/
bit leer_teclado(unsigned
char idata *buffer)
{
#pragma asm
; Se puede buscar una tecla?
jb BUSCAR_TECLA,NO_TECLA_PRESIONADA ; si se puede
se salta a NO_TECLA_PRESIONADA
; BUSCAR_TECLA = 0, hay una tecla presionada
lcall PRUEBA_TECLA_PRESIONADA
; prueba de tecla presionada
jmp SI_HAY_TECLA
NO_TECLA_PRESIONADA:
lcall LEER_TECLA
; captura de tecla
; hay una tecla válida?
SI_HAY_TECLA:
jnb TECLA_VALIDA,SI_CTECLAS_MAYOR_A_5
; TECLA_VALIDA = 1, hay una tecla válida
clr TECLA_VALIDA
; borrar bit de tecla válida
clr BUSCAR_TECLA
; inhabilitamos búsqueda de nueva tecla
lcall CODIFICAR_TECLA
; llamada a la función CODIFICAR_TECLA
lcall PRUEBA_TECLA_VALIDA
; comprobamos que la tecla sea válida
jnc SI_CTECLAS_MAYOR_A_5
; si C = 0 la prueba dio tecla no válida
; C=1, tecla con código válido
; almacenar tecla
válida en buffer de teclado
push ACC
; salvamos valor de tecla codificada en la pila
mov R0,#CTECLAS
; dirección de CTECLAS a R0
mov A,@R0
; copiamos R0 a A
add A,R7
; nos ubicamos en buffer_teclado
mov R0,A
; enviar dirección efectiva a R0
pop ACC
; recuperamos tecla codificada
mov @R0,A
; almacenar tecla codificada
mov R0,#CTECLAS
; copiamos dirección de CTECLAS
inc @R0
; incrementamos CTECLAS
SI_CTECLAS_MAYOR_A_5:
mov R0,#CTECLAS
; copiamos dirección de CTECLAS
cjne @R0,#6,MENOR_O_IGUAL_A_5
; mayor a 5
mov @R0,#0
; CTECLAS = 0
setb C
; indicar buffer de teclado lleno
ljmp RETORNO
MENOR_O_IGUAL_A_5 :
clr C
ljmp RETORNO
;
************************************************************************************
;
;
SUBRUTINA : LEER_TECLA
;
-----------------------------------------------------------------------------------
;
;
DESCRIPCIÓN : Se realiza el barrido de las tres columnas del teclado
y se leen las
;
filas del mismo. En caso de haberse detectado una tecla se la almacena
y se siguen
;
realizando el barrido por 10 veces más. En caso de que las diez
veces se haya dado
;
la misma tecla, se levanta la bandera de tecla válida TECLA_VALIDA
y se devuelve en
;
el acumulador A la tecla codificada en filas y columnas. Si la tecla no
se llegó a
;
dar se borra la bandera de tecla válida y se sale de la subrutina.
;
-----------------------------------------------------------------------------------
;
;
PARAMETROS DE ENTRADA : Ninguno
;
-----------------------------------------------------------------------------------
;
;
VALORES DE RETORNO: ACC = tecla capturada en el formato filas y columnas
;
Solamente es válida si la TECLA_VALIDA = 1
;
-----------------------------------------------------------------------------------
;
;
REGISTROS MODIFICADOS POR LA SUBRUTINA :
;
R1, R2, R3, R4, TECLA_VALIDA
;
-----------------------------------------------------------------------------------
;
************************************************************************************
LEER_TECLA:
; señales para
barrido del teclado a través de un puerto de 8 bits
; ----------------------------------------------------------------------------------------
BARRIDO_C1
EQU 11111110b
; barrido primera columna
BARRIDO_C2
EQU 11111101b
; barrido segunda columna
BARRIDO_C3
EQU 11111011b
; barrido tercera columna
; variables locales
; ----------------------------------------------------------------------------------------
C1
EQU R1
; contador de veces de la columna 1
C2
EQU R2
; contador de veces de la columna 2
C3
EQU R3
; contador de veces de la columna 3
TECLA
EQU R4
; tecla capturada en proceso
; cuerpo de la subrutina
; ----------------------------------------------------------------------------------------
mov B,C1
; salvar C1 = R1 en la pila
push B
mov B,C2
; salvar C2 = R2 en la pila
push B
mov B,C3
; salvar C3 = R3 en la pila
push B
mov B,TECLA
; salvar TECLA = R4 en la pila
push B
mov C1,#10
; inicializamos C1 al máximo de pruebas
mov C2,#10
; inicializamos C2 al máximo de pruebas
mov C3,#10
; inicializamos C3 al máximo de pruebas
; Operaciones con la
columna 1
; --------------------------------------------------------------------------------------
OPERACIONES_C1:
clr TECLA_PROC ; inicializamos TECLA_PROC
mov P1,#BARRIDO_C1
; barrido columna 1 a través de puerto 1
mov R6,#10
; espera por propagación
djnz R6,$
mov A,P1
; leer filas
orl A,#07h
; solo interesan las filas
; hubo teclas?
cjne A,#0FFh,HUBO_TECLA_C1
; si A <> FFh se salta a HUBO_TECLA_C1
; no hubo tecla
jmp OPERACIONES_C2
; se sale de las operaciones con la columna 1
; hubo tecla
HUBO_TECLA_C1 :
setb TECLA_PROC
; tecla en proceso
anl A,#BARRIDO_C1
; máscara para la primera columna
; fue la primera vez?
cjne C1,#10,NFPV_C1
; si C1<>10 se salta a NFPV_C1
; primera vez
mov TECLA,A
; almacenamos tecla capturada
dec C1
; decrementamos C1
mov C2,#10
; inicializamos C2
mov C3,#10
; inicializamos C3
jmp OPERACIONES_C2
; fin de operaciones con la columna 1
; no fue la primera vez
NFPV_C1:
; la tecla capturada es igual a la anterior?
xrl A,TECLA
; comparación por operación xor
jnz TNIA_C1
; si no es igual a la anterior se salta a TNIA_C1
; son iguales
dec C1
; decrementamos C1
jmp FIN_SI_SON_IGUALES_C1
; salimos de sentencia Si A = TECLA
; no son iguales
TNIA_C1:
mov C1,#10
; inicializamos C1
clr TECLA_PROC
; ya no hay tecla en proceso
FIN_SI_SON_IGUALES_C1:
; C1=0 ?
cjne C1,#0,FIN_SI_C1_IGUAL_CERO
; si C1<>0 se salta a FIN_SI_C1_IGUAL_CERO
; C1 = 0
setb TECLA_VALIDA
; TECLA_VALIDA = 1
clr TECLA_PROC
; ya no hay tecla en proceso
FIN_SI_C1_IGUAL_CERO:
; Operaciones con la
columna 2
; ----------------------------------------------------------------------------------------
OPERACIONES_C2:
jb TECLA_VALIDA,OPERACIONES_C3 ; si ya hay tecla válida, saltamos el barrido
; barrer columna 2
mov P1,#BARRIDO_C2
; barrido columna 2 a través de puerto 1
mov R6,#10
; espera por propagación
djnz R6,$
; leer filas
mov A,P1
; lectura de filas
orl A,#07h
; solo interesan las filas
; hubo teclas?
cjne A,#0FFh,HUBO_TECLA_C2
; si A <> FFh se salta a HUBO_TECLA_C2
; no hubo tecla
jmp OPERACIONES_C3
; se sale de las operaciones con la columna 2
; hubo tecla
HUBO_TECLA_C2 :
anl A,#BARRIDO_C2
; máscara para la columna 2
setb TECLA_PROC
; hay tecla en proceso
; fue la primera vez?
cjne C2,#10,NFPV_C2
; si C2<>10 se salta a NFPV_C2
; primera vez
mov TECLA,A
; almacenamos tecla capturada
dec C2
; decrementamos C2
mov C1,#10
; inicializamos C1
mov C3,#10
; inicializamos C3
jmp OPERACIONES_C3
; fin de operaciones con la columna 2
; no fue la primera vez
NFPV_C2:
; la tecla capturada es igual a la anterior?
xrl A,TECLA
; comparación por operación xor
jnz TNIA_C2
; si no es igual se salta a TNIA_C2
; son iguales
dec C2
; decrementamos C2
jmp FIN_SI_SON_IGUALES_C2
; salimos de sentencia Si A = TECLA
; no son iguales
TNIA_C2:
mov C2,#10
; inicializamos C2
clr TECLA_PROC
; ya no hay tecla en proceso
FIN_SI_SON_IGUALES_C2:
; C2=0 ?
cjne C2,#0,FIN_SI_C2_IGUAL_CERO
; si C2<>0 se salta a FIN_SI_C2_IGUAL_CERO
; C2 = 0
setb TECLA_VALIDA
; TECLA_VALIDA = 1
clr TECLA_PROC
; ya no hay tecla en proceso
FIN_SI_C2_IGUAL_CERO:
; Operaciones con la
columna 3
; ----------------------------------------------------------------------------------------
OPERACIONES_C3:
jb TECLA_VALIDA,FIN_OPERACIONES_C3 ; si ya hay tecla válida saltamos el barrido
; barrer columna 3
mov P1,#BARRIDO_C3
; barrido columna 3 a través de puerto 1
mov R6,#10
; espera por propagación
djnz R6,$
; leer filas
mov A,P1
; lectura de filas
orl A,#07h
; solo interesan las filas
; hubo teclas?
cjne A,#0FFh,HUBO_TECLA_C3
; si A <> FFh se salta a HUBO_TECLA_C3
; no hubo tecla
jmp FIN_OPERACIONES_C3
; se sale de las operaciones con la columna 3
; hubo tecla
HUBO_TECLA_C3 :
anl A,#BARRIDO_C3
; máscara para la tercera columna
setb TECLA_PROC
; hay tecla en proceso
; fue la primera vez?
cjne C3,#10,NFPV_C3
; si C3<>10 se salta a NFPV_C3
; primera vez
mov TECLA,A
; almacenamos tecla capturada
dec C3
; decrementamos C3
mov C1,#10
; inicializamos C1
mov C2,#10
; inicializamos C2
jmp FIN_OPERACIONES_C3
; fin de operaciones con la columna 3
; no fue la primera vez
NFPV_C3:
; la tecla capturada es igual a la anterior?
xrl A,TECLA
; comparación por operación xor
jnz TNIA_C3
; si no es igual a la anterior se salta a TNIA_C3
; son iguales
dec C3
; decrementamos C3
jmp FIN_SI_SON_IGUALES_C3
; salimos de sentencia Si A = TECLA
; no son iguales
TNIA_C3:
mov C3,#10
; inicializamos C3
clr TECLA_PROC
; ya no hay tecla en proceso
FIN_SI_SON_IGUALES_C3:
; C3=0 ?
cjne C3,#0,FIN_SI_C3_IGUAL_CERO
; si C3<>0 se salta a FIN_SI_C3_IGUAL_CERO
; C3 = 0
setb TECLA_VALIDA
; TECLA_VALIDA = 1
clr TECLA_PROC
; ya no hay tecla en proceso
FIN_SI_C3_IGUAL_CERO:
FIN_OPERACIONES_C3:
jnb TECLA_PROC,SIG_INST ; si hay tecla en proceso continuar el barrido
; TECLA_PROC = 1
ljmp OPERACIONES_C1 ; continuamos el barrido
; TECLA_PROC =
0
SIG_INST:
jnb TECLA_VALIDA,FIN_LEER_TECLA
; si no hay tecla válida salir
mov A,TECLA
; si hay tecla válida, copiar valor de retorno
FIN_LEER_TECLA:
mov P1,#0FFh
; ponemos a 1 lógico las columnnas
; devolver los valores originales de las variables locales desde la pila
pop B
mov C1,B
; retornamos C1 = R1
pop B
mov C2,B
; retornamos C2 = R2
pop B
mov C3,B
; retornamos C3 = R3
pop B
mov TECLA,B
; retornamos TECLA = R4
ret ; salimos de la función
; **********************************************************************************************
;
;
SUBRUTINA : PRUEBA_TECLA_PRESIONADA
;
-----------------------------------------------------------------------------------
;
;
DESCRIPCIÓN : Se prueba si una tecla está presionada. Se
utiliza para esperar que
;
una tecla presionada se suelte de modo a no volver a leerla.
;
-----------------------------------------------------------------------------------
;
;
PARAMETROS DE ENTRADA : Ninguno
;
-----------------------------------------------------------------------------------
;
;
VALORES DE RETORNO: BUSCAR_TECLA = 1 Barrido habilitado para búsqueda
de nueva tecla
;
-----------------------------------------------------------------------------------
;
;
REGISTROS MODIFICADOS POR LA SUBRUTINA :
;
-----------------------------------------------------------------------------------
PRUEBA_TECLA_PRESIONADA:
; Variables locales
;------------------
C_PRUEBAS
EQU R1
; Contador de pruebas realizadas
; Cuerpo de la subrutina
; ------------------------------------------------------------------------------------------
mov B,C_PRUEBAS ; salvamos registro
utilizado por la función
push B
; inicialización de variables locales
mov C_PRUEBAS,#10
; C_PRUEBAS = 10
clr TECLA_PRES
; no hay tecla presionada
; ponemos a 0 lógico las tres columnas
mov P1,#11111000b
; ciclo mientras C_PRUEBAS
> 0
MIENTRAS_C_PRUEBAS:
cjne C_PRUEBAS,#0,C_PRUEBAS_MAYOR_0 ; si C1 > 0
se salta a C_PRUEBAS_MAYOR_0
; C_PRUEBAS = 0
sjmp FIN_MIENTRAS_C_PRUEBAS
; salimos del bucle MIENTRAS
; C_PRUEBAS > 0
C_PRUEBAS_MAYOR_0:
mov A,P1
; leemos las filas y columnas
xrl A,#07h
; solo importan las filas
; hay tecla?
cjne A,#0FFh,HAY_TECLA_PRESIONADA
; no hay tecla presionada
dec C_PRUEBAS
; decrementamos el contador de pruebas
sjmp FIN_SI_HAY_TECLA_PRES
; salimos de la estructura SI
; hay tecla presionada
HAY_TECLA_PRESIONADA:
setb TECLA_PRES
; TECLA_PRES = 1
mov C_PRUEBAS,#0
; C_PRUEBAS = 0 ( forzamos salida del ciclo )
FIN_SI_HAY_TECLA_PRES:
sjmp MIENTRAS_C_PRUEBAS
; retornamos al principio del bucle MIENTRAS
; salimos del bucle
FIN_MIENTRAS_C_PRUEBAS:
; TECLA_PRES = 1?
jb TECLA_PRES,FIN_SI_TECLA
; si es igual a 1 se salta a FIN_SI_TECLA
; TECLA_PRES = 0
setb BUSCAR_TECLA
; habilitamos búsqueda de teclas
FIN_SI_TECLA:
mov P1,#0FFh
; ponemos a 1 lógico las tres columnas
; retornamos valor
original de C_PRUEBAS = R1
pop B
mov C_PRUEBAS,B
ret
; salimos de la función
**********************************************************************************************
;
;
SUBRUTINA : CODIFICAR_TECLA
;
-----------------------------------------------------------------------------------
;
;
DESCRIPCIÓN : Se procede a codificar la tecla en ASCII desde el
formato de filas
;
y columnas.
;
-----------------------------------------------------------------------------------
;
;
PARAMETROS DE ENTRADA : Registro A : Tecla no codificada
;
-----------------------------------------------------------------------------------
;
;
VALORES DE RETORNO: Registro A : Tecla codificada
;
-----------------------------------------------------------------------------------
;
;
REGISTROS MODIFICADOS POR LA SUBRUTINA : Ninguno
;
-----------------------------------------------------------------------------------
CODIFICAR_TECLA:
; Códigos para
las teclas muestreadas del puerto de 8 bits
F1C1
EQU 11101110b
; fila 1, columna 1
F1C2
EQU 11101101b
; fila 1, columna 2
F1C3
EQU 11101011b
; fila 1, columna 3
F2C1
EQU 11011110b
; fila 2, columna 1
F2C2
EQU 11011101b
; fila 2, columna 2
F2C3
EQU 11011011b
; fila 2, columna 3
F3C1
EQU 10111110b
; fila 3, columna 1
F3C2
EQU 10111101b
; fila 3, columna 2
F3C3
EQU 10111011b
; fila 3, columna 3
F4C1
EQU 01111110b
; fila 4, columna 1
F4C2
EQU 01111101b
; fila 4, columna 2
F4C3
EQU 01111011b
; fila 4, columna 3
; case TECLA NO CODIFICADA?
P_F1C1:
cjne A,#F1C1,P_F1C2
; prueba para fila 1 , columna 1
; es igual
mov A,#'1'
; F1C1 = tecla 1
jmp FINAL_CODIF
; break
P_F1C2:
cjne A,#F1C2,P_F1C3
; prueba para fila 1 , columna 2
; es igual
mov A,#'2'
; F1C2 = tecla 2
jmp FINAL_CODIF
; break
P_F1C3:
; prueba para fila 1 , columna 3
cjne A,#F1C3,P_F2C1
; es igual
mov A,#'3'
; F1C3 = tecla 3
jmp FINAL_CODIF
; break
P_F2C1:
cjne A,#F2C1,P_F2C2
; prueba para fila 2 , columna 1
; es igual
mov A,#'4'
; F1C1 = tecla 4
jmp FINAL_CODIF
; break
P_F2C2:
cjne A,#F2C2,P_F2C3
; prueba para fila 2 , columna 2
; es igual
mov A,#'5'
; F1C2 = tecla 5
jmp FINAL_CODIF
; break
P_F2C3:
cjne A,#F2C3,P_F3C1
; prueba para fila 2 , columna 3
; es igual
mov A,#'6'
; F1C3 = tecla 6
jmp FINAL_CODIF
; break
P_F3C1:
cjne A,#F3C1,P_F3C2
; prueba para fila 3 , columna 1
; es igual
mov A,#'7'
; F3C1 = tecla 7
jmp FINAL_CODIF
; break
P_F3C2:
cjne A,#F3C2,P_F3C3
; prueba para fila 3 , columna 2
; es igual
mov A,#'8'
; F3C2 = tecla 8
jmp FINAL_CODIF
; break
P_F3C3:
cjne A,#F3C3,P_F4C1
; prueba para fila 3 , columna 3
; es igual
mov A,#'9'
; F3C3 = tecla 9
jmp FINAL_CODIF
; break
P_F4C1:
cjne A,#F4C1,P_F4C2
; prueba para fila 4 , columna 1
; es igual
mov A,#'*'
; F4C1 = tecla *
jmp FINAL_CODIF
; break
P_F4C2:
cjne A,#F4C2,P_F4C3
; prueba para fila 4 , columna 2
; es igual
mov A,#'0'
; F4C2 = tecla 0
jmp FINAL_CODIF
; break
P_F4C3:
cjne A,#F4C3,COD_NV
; prueba para fila 4 , columna 1
; es igual
mov A,#'#'
; F4C3 = tecla #
jmp FINAL_CODIF
; break
; código
no válido
COD_NV:
mov A,#0
; se devuelve 0
FINAL_CODIF:
ret
RETORNO:
#pragma endasm
}
5. Rutinas de LCD .
/* *********************************************************************************************
lcd.c
Rutinas para manejo del driver de LCD 44780
---------------------------------------------------------------
Trabajo Práctico
Proyecto con Microprocesadores 1
1er semestre - 1999
Facultad de Ciencias y Tecnología
Universidad Católica Nuestra Señora de la Asunción
---------------------------------------------------------------
Por José Ricardo Otazo Torres
*********************************************************************************************
*/
#include<stdlib.h>
#include<reg51.h>
//
Definiciones
//
------------
#define LCD_MODO 0x38
// bus de datos de 8 bits, 5x8 puntos, 2 líneas
#define LCD_DES
0x06
// desplazamiento de caracteres y del cursor a la derecha
#define LCD_ON
0x0E
// habilitación de funcionamiento del driver
#define LCD_BORRADO
0x01 // borrar
el LCD y retornar a la primera posición
// Conexión con
el driver_LCD 44780U
// ---------------------------------
sbit EN = 0x85;
//pin P0.5
sbit RS = 0x86;
//pin P0.6
sbit RW = 0x87;
//pin P0.7
sfr DATO_LCD =
0xA0;
//port 2 del 8051
// Prototipo de funciones
// ----------------------
void lcd_enviar_instruccion(unsigned
char instruccion);
void lcd_enviar_dato(unsigned
char dato);
void lcd_espera(void);
/* *********************************************************************************************
;
;
SUBRUTINA : lcd_iniciar
;
-----------------------------------------------------------------------------------
;
;
DESCRIPCIÓN : inicialización de modo de funcionamiento, ancho
del bus de datos
;
fuente de caracteres, número de líneas.
;
-----------------------------------------------------------------------------------
;
;
PARAMETROS DE ENTRADA :
;
unsigned char modo : modo de funcionamiento del lcd driver 44780U.
;
-----------------------------------------------------------------------------------
;
;
VALORES DE RETORNO: Ninguno
;
-----------------------------------------------------------------------------------
;
;
REGISTROS MODIFICADOS POR LA SUBRUTINA :
;
-----------------------------------------------------------------------------------
;
;
FECHA : 27 / 06 / 1999
;
-----------------------------------------------------------------------------------
; ********************************************************************************************
*/
void lcd_iniciar(unsigned
char modo)
{
lcd_enviar_instruccion(modo); //inicializamos modo
lcd_enviar_instruccion(LCD_ON); // habilitamos funcionamiento del driver del LCD
lcd_enviar_instruccion(LCD_DES); // desplazamiento del cursor a la derecha
}
/* ********************************************************************************************
SUBRUTINA : BORRAR_LCD
-----------------------------------------------------------------------------------
DESCRIPCIÓN : borrado de todos los caracteres puestos en el LCD
y regreso del cursor
a su posición de origen
-----------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
-----------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
-----------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA :
-----------------------------------------------------------------------------------
FECHA : 27 / 06 / 1999
-----------------------------------------------------------------------------------
*********************************************************************************************
*/
void lcd_borrar(void)
{
lcd_enviar_instruccion(LCD_BORRADO); // enviamos comando de borrado
lcd_espera(); // espera por procesamiento en el driver
}
/* ********************************************************************************************
SUBRUTINA : LCD_ENVIAR_INSTRUCCION
-----------------------------------------------------------------------------------
DESCRIPCIÓN : envío de una instrucción al registro
IR del driver de LCD 44780
-----------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Instrucción
-----------------------------------------------------------------------------------
PASO DE PARAMETROS : a través del registro A
-----------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
-----------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA :
-----------------------------------------------------------------------------------
FECHA : 27 / 06 / 1999
-----------------------------------------------------------------------------------
*********************************************************************************************
*/
void lcd_enviar_instruccion(unsigned
char instruccion)
{
//paso de parámetro a través de R7
#pragma asm
; producimos temporización de envío de instrucción
; ------------------------------------------------
clr RS
; envío de instrucción
clr RW
; escritura del registro IR
setb EN
; inicio de ciclo de envío
; envío de la instrucción
; -----------------------
mov DATO_LCD,R7
; copia del parámetro al bus de datos del LCD
; espera para cumplir temporización ( 4 us )
; ---------------------------------
nop
nop
nop
nop
clr EN
; final de ciclo de envío
#pragma endasm
lcd_espera(); // espera por procesamiento del driver 44780
}
/* *******************************************************************************************
SUBRUTINA : LCD_ENVIAR_DATO
-----------------------------------------------------------------------------------
DESCRIPCIÓN : envío de un dato a ser exhibido en el display
-----------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Dato de 8 bits
-----------------------------------------------------------------------------------
PASO DE PARAMETROS : a través del registro A
-----------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
-----------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA :
-----------------------------------------------------------------------------------
FECHA : 27 / 06 / 1999
-----------------------------------------------------------------------------------
*******************************************************************************************
*/
void lcd_enviar_dato(unsigned
char dato)
{
//paso de parámetro dato a través de R7
#pragma asm
; producimos temporización de escritura de datos
; ---------------------------------------------
setb RS
; envío de dato
clr RW
; señal de escritura
setb EN
; inicio de ciclo de envío
; envío del dato
; --------------
mov DATO_LCD,R7
; espera para cumplir temporización
; ---------------------------------
nop
nop
nop
nop
clr EN ; final de ciclo de envío
#pragma endasm
lcd_espera(); // espera por procesamiento en el driver del LCD
}
/* *********************************************************************************************
SUBRUTINA : LCD_ESPERA
-----------------------------------------------------------------------------------
DESCRIPCIÓN : establecimiento de un ciclo de espera hasta que el
driver del
LCD, haya terminado de ejecutar la última instrucción enviada.
Se muestrea continuamente el pin DATA_LCD.7, hasta que el driver establezca
el
pin a un nivel lógico 0.
-----------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
-----------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
-----------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA : Ninguno
-----------------------------------------------------------------------------------
FECHA : 27 / 06 / 1999
-----------------------------------------------------------------------------------
********************************************************************************************
*/
void lcd_espera(void)
{
#pragma asm
push ACC ; salvamos el acumulador A en la pila
CICLO_ESPERA:
; producimos temporización de lectura de estado del 44780
; -------------------------------------------------------
clr RS
; envío de instrucción
setb RW
; operación de lectura
setb EN
; inicio de ciclo de lectura
mov DATO_LCD, #0FFh
; DATA_LCD = 11111111 para lectura del puerto
; leeemos el bus de datos del driver del LCD
; ------------------------------------------
mov A,DATO_LCD
; lectura del puerto 2
; estado = ocupado ?
; ------------------
jb ACC.7,CICLO_ESPERA
; Si ACC.7 = 1, el driver está ocupado y se salta a
; CICLO_ESPERA
; estado <> ocupado
; -----------------
clr EN
; final de ciclo de lectura
pop ACC ; recuperamos el valor original del acumulador A
#pragma endasm
}
/* *********************************************************************************************
SUBRUTINA : lcd_men1
-----------------------------------------------------------------------------------
DESCRIPCIÓN : despliegue del mensaje " Código incorrecto"
o " Código correcto" en
el LCD.
-----------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : TIPO = 0 " Código incorrecto"
= 1 " Código correcto"
-----------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
-----------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA : Ninguno
-----------------------------------------------------------------------------------
FECHA : 27 / 06 / 1999
-----------------------------------------------------------------------------------
********************************************************************************************
*/
void lcd_men1( bit TIPO)
{
unsigned char idata indice = 0; //variable auxiliar para envío de
caracteres
unsigned char dato;//almacenamiento temporal del dato a enviar al LCD
//envío de los primeros caracteres
while(indice < 6)
{
switch(indice)
{
case 0: dato = 'C'; break;
case 1: dato = 'o'; break;
case 2: dato = 'd'; break;
case 3: dato = 'i'; break;
case 4: dato = 'g'; break;
case 5: dato = 'o'; break;
case 6: dato = ' '; break;
default: break;
}
lcd_enviar_dato(dato);
indice++;
}
if(TIPO)
indice = 2;//solo enviamos los últimos 9 caracteres " correcto"
else indice = 0;//enviamos todo " incorrecto"
//se completa el mensaje
while(indice < 11)
{
switch(indice)
{
case 0 : dato = 'i'; break;
case 1 : dato = 'n'; break;
case 2 : dato = 'c'; break;
case 3 : dato = 'o'; break;
case 4 : dato = 'r'; break;
case 5 : dato = 'r'; break;
case 6 : dato = 'e'; break;
case 7 : dato = 'c'; break;
case 8 : dato = 't'; break;
case 9 : dato = 'o'; break;
case 10: dato = '!'; break;
default: break;
}
lcd_enviar_dato(dato);
indice++;
}
}
/* *********************************************************************************************
SUBRUTINA : lcd_men2
-----------------------------------------------------------------------------------
DESCRIPCIÓN : despliegue del mensaje " Ingresar código por
teclado"
-----------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
-----------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
-----------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA : Ninguno
-----------------------------------------------------------------------------------
FECHA : 27 / 06 / 1999
-----------------------------------------------------------------------------------
********************************************************************************************
*/
void lcd_men2(void)
{
unsigned char idata indice = 0;//variable auxiliar para envío de
caracteres
unsigned char idata dato;//caracter a enviar
// enviamos el mensaje caracter a caracter
while(indice < 26)
{
switch(indice)
{
case 0: dato = 'I'; break;
case 1: dato = 'n'; break;
case 2: dato = 'g'; break;
case 3: dato = 'r'; break;
case 4: dato = 'e'; break;
case 5: dato = 's'; break;
case 6: dato = 'a'; break;
case 7: dato = 'r'; break;
case 8: dato = ' '; break;
case 9: dato = 'c'; break;
case 10: dato = 'o'; break;
case 11: dato = 'd'; break;
case 12: dato = 'i'; break;
case 13: dato = 'g'; break;
case 14: dato = 'o'; break;
case 15: dato = 'p'; break;
case 16: dato = 'o'; break;
case 17: dato = 'r'; break;
case 18: dato = ' '; break;
case 19: dato = 't'; break;
case 20: dato = 'e'; break;
case 21: dato = 'c'; break;
case 22: dato = 'l'; break;
case 23: dato = 'a'; break;
case 24: dato = 'd'; break;
case 25: dato = 'o'; break;
default: break;
}
lcd_enviar_dato(dato);// enviamos caracter
indice++;
}
}
/* *********************************************************************************************
SUBRUTINA : lcd_men3
-----------------------------------------------------------------------------------
DESCRIPCIÓN : despliegue del mensaje " Puerta bloqueada"
-----------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
-----------------------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
-----------------------------------------------------------------------------------
REGISTROS MODIFICADOS POR LA SUBRUTINA : Ninguno
-----------------------------------------------------------------------------------
FECHA : 27 / 06 / 1999
-----------------------------------------------------------------------------------
********************************************************************************************
*/
void lcd_men3(void)
{
unsigned char idata indice = 0;// variable auxiliar para el envío
caracter a caracter
unsigned char dato;//caracter a enviar
//enviamos el mensaje caracter a caracter
while(indice < 16)
{
switch(indice)//elegimos caracter
{
case 0: dato = 'P'; break;
case 1: dato = 'u'; break;
case 2: dato = 'e'; break;
case 3: dato = 'r'; break;
case 4: dato = 't'; break;
case 5: dato = 'a'; break;
case 6: dato = ' '; break;
case 7: dato = 'b'; break;
case 8: dato = 'l'; break;
case 9: dato = 'o'; break;
case 10: dato = 'q'; break;
case 11: dato = 'u'; break;
case 12: dato = 'e'; break;
case 13: dato = 'a'; break;
case 14: dato = 'd'; break;
case 15: dato = 'a'; break;
default: break;
}
lcd_enviar_dato(dato);//enviamos caracter
indice++;
}
}
8. Rutinas de temporización.
/*
*******************************************************************************************
FUNCION : temp_pes()
---------------------------------------------------------------------------------------
DESCRIPCIÓN : inicialización del temporizador de conteo de
múltiplos de 30 ms.
El temporizador funciona por interrupciones.
---------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA : Ninguno
------------------------------------------------------------------
VALORES DE RETORNO: Ninguno
*******************************************************************************************
*/
void
temp_pes(void)
{
tiempo = 0;
// inicialización del contador de múltiplos de 30 ms
TH0 = 0x94;
// valor de carga = 37889 para que produzca una interrupción
TL0 = 0x01;
// cada 30 ms
TR0 = 1;
// timer 0 run
ET0 = 1;
// habilitación de interrupciones para el timer 0
}
/* *****************************************************************************************
SUBRUTINA : timer0
------------------------------------------------------------------------------------
DESCRIPCION : rutina de manejo de interrupciones en el temporizador 0.
Se incrementa
el contador de múltiplos de 30 ms para medir el tiempo de apertura.
------------------------------------------------------------------------------------
PARAMETROS DE ENTRADA :
unsigned char tiempo = contador de tiempo de apertura
------------------------------------------------------------------------------------
VALORES DE RETORNO: tiempo
------------------------------------------------------------------------------------
*****************************************************************************************
*/
void
timer0(void) interrupt 1 using 2
{
tiempo++; // incrementamos contador de múltiplos
de 30 ms
}