uacceso ( MicroControl de acceso) 
      Implementación de las rutinas
      Por José Ricardo Otazo Torres


     Las rutinas para el sistema de control de acceso de la puerta fueron desarrolladas utilizando la herramienta de
         desarrollo Keil para el microcontrolador 8051, específicamente el compilador de lenguaje C C51
        y el ensamblador A51.

    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

}
 
 



                                                                          A la página principal