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.
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.
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.
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 } 10Lo 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().
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.
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.
jajaja si que es mucho código; pero para eso existen la librerías, de comunicación serial,y para el LCD jajaja
ResponderEliminaraunque 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
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...
ResponderEliminarsaludos
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!
ResponderEliminarmmmm, 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.
ResponderEliminarmi 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.
ResponderEliminarmi correo es julroj07@hotmail.com
gracias
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