Video-tutorial de la semana

lunes, 8 de noviembre de 2010

Control de Acceso Usando la RFid – Parte III

Hoy se muestra la parte III del proyecto control de acceso, esta parte habla del diseño del software para el microcontrolador PIC16F73, se muestra el código del programa, se realizarón todas las funciones para el LCD, no se uso ninguna librería ni para el LCD ni para la comunicación serial,  todo fue en base a las hojas de datos y se puso todo el código quizá a alguna persona le pueden servir las funciones para otros proyectos, el código se edito en el entorno llamado SourceBoost IDE, da clic aqui si deseas bajar este compilador de C para PIC.

4.1 Diagrama de flujo del programa

La siguiente figura muestra el diagrama de flujo del programa realizado para el microcontrolador




El funcionamiento del sistema en terminos generales es así:
• El sistema envía un mensaje de bienvenida en el LCD

• Por medio de un switch se elige el modo de programación o el modo de monitoreo

        o El modo de monitoreo sirve para leer las etiquetas y activar o desactivar la cerradura
           electrónica, en caso de recibir una etiqueta autorizada o no.

       o El modo de programación almacena las etiquetas autorizadas en la memoria del PIC.

Componentes del software.

El código fuente está compuesto por funciones, estas realizan una determinada acción sobre el sistema de hardware, de la misma manera se conforma de una función principal (main), que es la que gobierna todas las funciones que conforman el programa, y las cuales se describe en el presente capitulo. El software desarrollado para el PIC fue realizado en el entorno SourceBoost usando como base el lenguaje C, no se usaron ninguna librería para el LCD todo fue programado.

Programa principal (main)

El programa principal está en el listado 4.1; se comentan algunas líneas de código para mejor comprensión del programa.

Listado 4.1 Función para seleccionar opciones.

 1 void main()
 2 {
 3   int u,c,i,opcion;
 4   char tag[11];
 5   char DatosDeEtiqueta[11];
 6   char string[33];
 7   adcon1=0x06;  // puerto A como I/O digitales
 8   trisb=0x00;   // Se configura el Puerto B como salida
 9   trisa=0x00;   // Se configura el Puerto A como salida
10   porta=0x00;   // Pone al Puerto A apagado
11   trisc=0x87;   // 1000 0111 puerto C como entradas y salidas
12   def();    // Se manda llamar la subrutina de default
13   iniLCD();   // Se manda llamar la subrutina de inicialización
14   configserial();  // Llama la funcion configurar serial
15   set_bit(portc,5);  // Led VERDE desactivado lector RFID
16   strcpy(string, "  BIENVENIDOS   CONTROL  ACCESO");
17   escribeCadenaEnLCD(string);
18   delay_s(3);
19   inst(0x01);  // borrar LCD
20   while (1)
21     {
22       opcion=menu();
23       switch (opcion)
24         {
25         case 1:
26           leerEtiquetaDeRF(DatosDeEtiqueta);
27           if (portc.5==1)
28             {
29               strcpy(string, "   ETIQUETA #      ");
30               escribeCadenaEnLCD(string);
31               mostrarEtiquetaEnLCD(DatosDeEtiqueta);
32               delay_s(3);
33               inst(0x01);  // instrucción borra LCD
34             }
35           c=0;
36           for (i=0; i<11; i++)
37             {
38               if (tag[i]==DatosDeEtiqueta[i]) // verifica tag valido
39                 {
40                   c++;
41                 }
42             }
43           if (c<=10)
44             {
45               porta.5=1;
46               strcpy(string, "     ACCESO        AUTORIZADO");
47               escribeCadenaEnLCD(string);
48               delay_s(10);
49               inst(0x01);  // instrucción borra LCD
50               porta.5=0;
51             }
52           else
53             {
54               strcpy(string, "    ACCESO         DENEGADO");
55               escribeCadenaEnLCD(string);
56               delay_s(3);
57               inst(0x01);    // instrucción borra LCD
58             }
59           break;
60         case 2:
61           if (portc.1==0)          //push botton # 1
62             {
63               for (i=0; i<11; i++)
64                 {
65                   tag[i]=0x00; // borra un tag(etiqueta) grabada
66                 }
67               strcpy(string, "   ETIQUETA          BORRADA");
68               escribeCadenaEnLCD(string);
69               delay_s(3);
70               inst(0x01);   // instrucción borra LCD
71             }
72           if ((portc.1==1) && (portc.2==0)) // push botton 1 y 2
73             {
74               strcpy(string, "    GRABANDO        ETIQUETA");
75               escribeCadenaEnLCD(string);
76               leerEtiquetaDeRF(DatosDeEtiqueta);
77               u=0;
78               for (i=0; i<12; i++)
79                 {
80                   tag[u]=DatosDeEtiqueta[i]; //grabar tag en arreglo
81                   u++;
82                 }
83               inst(0x01); // instrucción borra LCD
84               strcpy(string, "ETIQUETA GRABADA ES ");
85               escribeCadenaEnLCD(string);
86               mostrarEtiquetaEnLCD(DatosDeEtiqueta);
87               delay_s(3);
88               inst(0x01); // instrucción borra LCD
89             }
90           if ((portc.1==1) && (portc.2==1))
91             {
92               menu();
93               delay_s(3);
94             }
95           break;
96         } // fin de switch
97     } // fin de while
98 } // fin de función main
99 

Funciones para el LCD.
Las funciones necesarias para trabajar con la pantalla LCD son tres esencialmente, y son la inicialización, enviar instrucción y enviar dato, estas funciones fueron programadas usando los diagramas de tiempo pueden verse en cualquier hoja de datos para el LCD.

Función para inicializar LCD.
Esta función es la encargada de la inicialización de la pantalla LCD; En el listado 4.2 de escribe una función llamada def, descrita en el programa como función default , esta es necesaria para controlar los estados de E (enable del LCD ) , por el hecho de que enable del LCD debe cambiar a “0” valor de “inicial”, para que al interpretar la función iniLCD (descrita posteriormente en el listado 4.4) sea única para cada instrucción enviada.

Listado 4.2 función default devuelve  E=0.
01 void def()     // Condiciones default del LCD.
02 {
03   clear_bit(porta,0);   // Señal E = 0
04   set_bit(porta,1);  // Señal RW = 1
05   set_bit(porta,2);  // Señal RS  = 1
06 }
07 

El listado 4.3 muestra una función que carga un valor de inicialización y consta de una retardo de 15ms y las instrucciones que se carga una a una a la función llamada inst (instrucción al LCD); estos valores se toman de la tabla 3.7 y tabla 3.8 expuestas en el capitulo III.

Listado 4.3 función para carga el valor de inicialización.
01 void iniLCD()  // Condiciones para inicializar el LCD
02 {
03   delay_ms(15);  // Espera 15 milisegundos
04   inst(0x01);   // 0000 0001 limpia LCD
05   inst(0X3F);   // 0011 1111 Funtion Set: 8bit, activa 2 líneas, 5x10 puntos.
06   inst(0X0F);   // 0000 1111 on/off pantalla y cursor, parpadea el cursor.
07   inst(0X06);  // 0000 0110 Modo de Entrada de caracteres
08 }
09 

Función para escribir instrucciones
Para enviar una instrucción al LCD y inicializarlo es necesario cumplir con los tiempos requeridos y expuestos en el capitulo III, en la sección 3.5.2, con uso del diagrama de tiempo expuesto en la figura 3.10 de dicho capitulo, por lo tanto, es necesario crear una función que lo realice; el siguiente listado 4.4 describe una función llamada inst() que en conjunto con las función def y la función iniLCD descritas anteriormente cumplen con ese diagrama de tiempo.

Listado 4.4 función para enviar instrucción al LCD.

01 void inst(int i)   // Secuencia para enviar las instrucciones al LCD
02 {
03   clear_bit(porta,2);  // RS = 0
04   clear_bit(porta,1); // RW = 0
05   portb=i;  // carga el valor de i al puerto B
06   set_bit(porta,0); // E = 0
07   delay_ms(50);  // retardo de 50 milisegundos
08   def();   // llama a la función def
09 }
10 

Función para enviar dato al LCD.

Al igual que la función para enviar instrucciones al LCD, la función de enviar datos en esta caso la función se llama datos(); Hace uso también de la función def, para regresar el valor E=0; La función “enviar datos” se muestra en el listado 4.5, la cual cumple con el diagrama de tiempo de una LCD estándar. Esta función es usada para escribir los datos en LCD, tanto los obtenidos por las etiquetas RFID como los letreros de información de estado del sistema; La descripción de esta función es tan simple como la función de enviar instrucción, solamente que en esta función cambian los valores RS, E y RW , lo cual se describe en las hojas de daos de una LCD

Listado 4.5 función para enviar dato al LCD .
01 void datos(int j)  // Instrucciones para enviar los datos al LCD
02 {
03   set_bit(porta,2); // RS = 1
04   clear_bit(porta,1); // RW = 0
05   portb=j;  // carga el valor de j al puerto B
06   set_bit(porta,0); // E = 1
07   delay_ms(20);  // retardo de 50 milisegundos
08   def();   // llama a la función def
09 }
10 

Función para escribir el número de etiqueta en el LCD.
Esta función llamada en el programa principal así: mostrarEtiquetaEnLCD, requiere que otras funciones sean ejecutadas con anterioridad, las cuales obtiene el numero de etiqueta, para posteriormente, poder mostrar su valor en el LCD, pero por razones de orden y descripción del programa es mencionada primero.

Esta función es mostrada en el listado 4.6, la función opera de la siguiente manera, los datos cargados en el arreglo etiqueta[ ] , son enviados a la función datos() para qué esta función los escrita en el LCD.

Al comenzar la función inicializamos una variable llamada u donde esta variable tomó valores desde 1 hasta 10, que representan los datos obtenidos del etiqueta; Que son los que se pueden mostrar, esto se describe en la sección anterior donde se habla del protocolo de cserial del lector, lafunción sólo mostrará los 10 bytes donde está escrito él ID del etiqueta leída.
Es de notar el arreglo etiqueta[] ese tipo char, el cual devuelve un valor hexa-decimal representativo de tipo ASCII, que se reciben del etiqueta en cuestión. El primer byte de start 0x0A se ubica en la posición etiqueta[0] y el byte de stop 0x0D se ubica en la posición etiqueta[11], es por eso que u comienza en uno y terminar en 10 el byte start y stop de la etiqueta no es necesario mostrarlos.

Listado 4.6. Función muestra datos de etiqueta en el LCD .
01 void mostrarEtiquetaEnLCD(char etiqueta[])
02 {
03   int u;     // declaramos una variable
04   for (u=1; u<11; u++)    // ciclo for con u =1 hasta U=11
05     {
06       datos(etiqueta[u]);  // llama a la función datos()
07       delay_ms(100);  // retardo 100 milisegundos
08     }
09 }
10 

Función para escribir una cadena de texto en el LCD
Al usar esta función llamada escribeCadenaEnLCD y que se muestra en el listado 4.7, se puede mandar una cadena de caracteres “texto” al LCD, sin la necesidad de escribir cada letra del texto en un código hexa-decimal, ya que como se menciona una cadena devuelve el valor en tipo ASCII al arreglo, para este caso, se usa el arreglo llamado str[ ] , que además es tipo char.
El proceso es el siguiente, los datos almacenados en el arreglo str[ ], son enviados uno a uno desde str[0] hasta str[a], donde a es valorada con la función strlen incluida en la librería string.h, y es devuelta como un entero el cual tiene la medida de longitud de la cadena; Aquí podemos intuir que una cadena de mas de 32 caracteres no podrá ser mostrada, pues el LCD tiene precisamente esos espacios 2x16, en todo caso si se escribiera una cadena de mayor longitud no se podrá visualizar con esta función.

Listado 4.7. función para escribir texto en el LCD.
01 void escribeCadenaEnLCD(char str[ ])
02 {
03   int a, u;      // declaramos variables usadas
04   a = strlen(str);   // mide la longitud de una cadena.
05   for (u=0; u < a; u++)   // ciclo for; u=0 hasta u < a
06     {
07       if (u==16)    // el if  para verificar el renglón del LCD
08         {
09           inst(0xc0);      // para cambiar a renglón 2
10         }
11       datos(str[u]);   // manda toda la cadena a la función datos
12     }
13 }
14 

Dentro de esta misma función esta un if que es el encargado de verificar que renglón del LCD se esta visualizando, es decir, los primeros 16 caracteres, sobrepasando este valor el LCD comenzara ha escribir en el renglón 2 y con esto se da una visualización legible.

Por ultimo se vuelve a llamar la función datos() que es la encargada de enviar la información al LCD para que sea posible visualizarla, como se menciona al principio envía uno a uno los datos en el arreglo str[u].

Función para la comunicación serial
Para establecer una comunicación serial primero se debe configurar el microcontrolador, para que se establezca los pines de comunicación y esto se logra con la función del listado 4.8 llamada configserial() en este código.

Listado 4.8 Configuración del PIC para recepción serial.
01 void configserial()  // Configuración PIC para recepción Serial
02 {
03   trisc.6= 0; // configura el pin 6 puerto C como salida
04   trisc.5= 0; // configura el pin 5 puerto C como salida
05   trisc.7= 1; // configura el pin 7 puerto C como entrada
06   spbrg = 25; // frecuencia en baudios 2400bps
07   txsta = 0x00; // valor requerido en el registro txsta
08   rcsta = 0x80; // valor requerido en el registro rcsta
09 }
10 
Lo que realiza esta función es configurar los registros TXSTA y RCSTA descritos en la hoja de datos del PIC16F73 para establecer la recepción serial.

Función para leer un dato serial
La función esta en el listado 4.9 y se llama leer1DatoSerial(), este proceso de obtener un dato serial esta descrito en la sección 3.3.4.2. En esta función se toma en cuenta los bit star y stop de cada byte recibido, es posible realizar esto porque RCIF (pir1<5>) se coloca a 1 lógico solo cuando recibe un dato completo; Puesto que ya se sabe que la etiqueta RFID se obtienen 12 bytes de su ID, entonces esta función se ejecuta 12 veces u once si no se toma en cuenta el byte stop de la etiqueta tal como se ve en el listado 4.10 con el while.

Listado 4.9 Función leer un dato del puerto Serie
01 int leer1DatoSerial()
02 {
03   int x=0;  // Declaramos una variable y la iniciamos en 0
04   while (pir1.5 == 0);  // Espera a que llegue el un Dato x el puerto serial
05   x = rcreg;       // Guarda el dato
06   while (pir1.5 == 1);  // Terminada la recepción de un dato (8bits)
07   return x;  // Regresa el valor de x
08 }
09 

El dato recibido se guarda en una variable x, la cual regresa el valor a otra función que se encarga de ir almacenado en un arreglo llamado etiqueta [u] esto byte a byte hasta los 12 bytes de la etiqueta RFID.

Función para leer los datos de una etiqueta.

La función encargada de la lectura de la etiqueta, esta en el listado 4.10, la función es llamada leerEtiquetaDeRF, esta función almacena cada byte de la etiqueta RFID en un arreglo de 10 pociones llamado etiqueta[u], los bytes son obtenidos a través de la función anteriormente descrita llamada leer1DatoSerial().

Listado 4.10 Lee datos de etiqueta RFID.

01 void leerEtiquetaDeRF(char etiqueta[])
02 {
03   int u = 0;  //Declara una variable u=0 para el control
04   clear_bit(portc,5);  //Activa el Lector
05   rcsta.4 = 1;   //Activa recepcion Continua
06   do
07     {
08       etiqueta[u]=leer1DatoSerial(); //Uno a uno byte recibido al arreglo
09       u++;
10     }  // incrementamos u para las posiciones del arreglo
11   while (u<11);    //Repite el ciclo hasta que es falsa la condición
12   set_bit(portc,5);    //Desactiva el Lector
13   rcsta.4 = 0;   //Desactiva recepción Continua
14 }
15 

En esta función, como primer instrucción se activa el lector RFID, mandando un “0” al pin 5 de puerto C, puesto que en el se encuentra conectado la terminal /enable del lector RFID.

Seguido se activa la recepción continua colocando un “1”lógico en el bit CREN, ubicado en el registro RCSTA del microcontrolador descrito en la sección 3.3.4.2. entra en un ciclo do-while que se repetirá hasta haber obtenido los 10 bytes de ID de la etiqueta RFID, dentro del ciclo se manda llamar la función leer1DatoSerial() que obtiene un byte y lo almacena en el arreglo; Terminando el ciclo do-while se desactiva el lector RFID al igual que la recepción continua del Pic.

Función para mostrar el menú de opciones
La función menú() nos permite seleccionar una entre dos opciones que son: CONTROL ACCESO ***ACTIVADO*** y MODO DE PROGRAMACIÓN.

Esta función solamente muestra en el lcd los dos letreros anteriores, y mediante un if se selecciona la opción deseada, lo que hay que resaltar es la función strcpy que pertenece a la librería string.h, dicha función strcpy, se encarga de copiar el letrero a la cadena de caracteres llamada string[ ], que es de 33 posiciones, después es mandada a la función escribeCadenaEnLCD() que se encarga de mandar la cadena al LCD y que es descrita en el listado 4.7.

Además esta función devuelve la opción seleccionada op para que mediante un switch en el programa principal (main), ejecute lo que concierne a la opción seleccionada.

Listado 4.10 Función para seleccionar opciones.
01 int menu()
02 {
03   char string[33];  // cadena de 32 posiciones, segmentos tiene el LCD
04   int op;
05   if (portc.0==1)
06     {
07       strcpy(string, " CONTROL  ACCESO ***ACTIVADO***");
08       escribeCadenaEnLCD(string);
09       delay_s(3);
10       inst(0x01);
11       op=1;
12     }
13   else
14     {
15       strcpy(string, "    MODO  DE      PROGRAMACION");
16       escribeCadenaEnLCD(string);
17       delay_s(3);
18       inst(0x01);
19       op=2;
20     }
21   return op;
22 }
23 

Ups, fue basante código, espero se haya explicado y si hay duda del código no duden en preguntar.

6 comentarios:

  1. jajaja si que es mucho código; pero para eso existen la librerías, de comunicación serial,y para el LCD jajaja

    aunque es buen proyecto aunque solo se trato de la comunicación serial.

    no hubo mucho de RFID solo fue un lector que entrega datos por medio de comunicación serial?

    saludos

    ResponderEliminar
  2. Hola¡¡¡ je je je, Si fue bastante código como puede verse todo se hizo siguiendo las hojas de datos del LCD (los diagramas de tiempo) y de la hoja de datos del PIC para la parte serial, se hizo hace ya varios años el proyecto, y tienes toda la razón las librerias ya lo simplifican todo actualmente usamos las de MikroC y se reduce el código muchisimo... Lo del RFid si fue solo el lector que envía varios byte en forma serial y lo único que se hizo fue capturar cada byte con el PIC y hacer las comparaciones y listo...

    saludos

    ResponderEliminar
  3. Hola!! tengo una duda, yo no se mucho de esto, pero me interesa saber como es que implementan el codigo en el source, ya que no comprendo muy bien como es ke se utiliza, espero me puedan contestar, gracias!

    ResponderEliminar
  4. mmmm, te refieres a que hicimos con ese codigo? si es asi, pues el codigo que se ve arriba, usando el software se convierte a un archivo con extension .HEX, este archivo se introduce en un microcontrolador (chip) por medio de un programador, ese es el enlace que hay, despues el chip tiene el codigo y se ejecuta dentro de el y listo.. esa era tu duda? si no escribeme y con gusto te ayudo.

    ResponderEliminar
  5. mi nombre es julio me gusta este proyecto pero la verdad soy principiante el en los microcontroladores no se como se compila el programa si usted me puede ayudar por favor y me envia el codigo .hex para programarlo al pic le agradezco en el alma que dios le bendiga.

    mi correo es julroj07@hotmail.com

    gracias

    ResponderEliminar
  6. mmm.. el codigo HEX no lo tengo. pues hace muchos años que se hizo ese proyecto.. ala fecha ya usamos el PICC para compilar los programas.. siento no poder ayudarte...

    ResponderEliminar