Interrupciones 49 4.4 Interrupciones RBI (Interrupciones por cambio de estado) Cuatro pines del PORTB (RB7:RB4) son capaces de disparar una interrupción por cambio de estado. Este tipo de interrupciones son comúnmente usadas para el manejo de teclados matriciales, de ahí que estos pines también los denominen KBI0:KBI3. De estos 4 pines, solo producirán interrupción aquellos configurados como entradas, si alguno está configurado como salida, queda excluido de la interrupción por cambio de estado. Cualquiera de estos 4 pines dispara la misma interrupción, es decir la misma bandera de interrupción se activa, la bandera RBIF (INTCON<0>). Para activar esta interrupción se puede usar la función OpenPORTB de la librería portb.h. Figura 4-3. Función para activar interrupción RBI ([7] ) Ing. Juan Ramon Terven Salinas Interrupciones 50 4.4.1 Teclado Matricial Un teclado matricial está constituido por una matriz de pulsadores dispuestos en filas y columnas como se muestra en la Figura 4-4. La finalidad es reducir el número de líneas necesarias para la conexión. Como se observa en la figura, cada tecla se conecta a una fila y a una columna. En este caso se tiene un teclado de 4x4 en el cual se necesitan sólo 8 pines del microcontrolador en lugar de 16 si fueran botones independientes. Cuando se pulsa una tecla, queda en contacto una fila con una columna. Si no hay tecla pulsada, las filas están desconectadas de las columnas. Figura 4-4. Teclado matricial con microcontrolador [11] 4.4.2 Conexión del Teclado matricial con el microcontrolador PIC18F4550 La Figura 4-4 muestra una posible conexión de un teclado matricial a un microcontrolador con las siguientes características: Ing. Juan Ramon Terven Salinas Interrupciones • 51 Las filas del teclado se conectan a las líneas de la parte baja del PORTB configuradas como salida. • Las columnas del teclado se conectan a las líneas de la parte alta del PORTB configuradas como entrada. Observe que estas líneas deben tener resistencias de pull-up. En el caso del PIC18F4550, todos los pines del PORTB poseen resistencias de pull-up internas que pueden ser activadas por software. Para detectar que tecla se pulsa, se aplica a una fila un nivel bajo y a las otras filas un nivel alto. Si se presiona una tecla en la fila por la que se aplica el nivel bajo, ese nivel bajo aparecerá en la columna correspondiente con la que ha hecho contacto. En la Figura 4-4 se pulsa la tecla “3”, de tal forma que cuando el microcontrolador explora la fila F1, este cero aparece en la columna C3 y es leído por el pin RB6. 4.4.3 Algoritmo para lectura del teclado El algoritmo de lectura del teclado utilizado en este proyecto hace uso de la interrupción RBI para detectar si se pulsa alguna tecla. Una vez que la interrupción detecta que se pulso una tecla, el siguiente paso es determinar que tecla se pulso. 1. Primeramente a cada tecla se le asigna un código que puede ser el orden de la tecla, como se muestra en la Figura 4-5. Figura 4-5- Codigo asignado a cada tecla Ing. Juan Ramon Terven Salinas Interrupciones 52 2. Luego ejecutamos el algoritmo siguiente: Tecla = 0 Fila1 = 0, demás filas = 1 SI Columna1 = 0? NO Incrementa Tecla SI Columna2 = 0? NO Incrementa Tecla SI Columna3 = 0? NO Incrementa Tecla SI Columna4 = 0? NO Incrementa Tecla ¿Última Tecla? NO SI Decodifica Tecla Fin Figura 4-6. Algorítmo de detección de tecla pulsada Ing. Juan Ramon Terven Salinas Siguiente Fila=0, las demas Filas en 1 Interrupciones 53 A continuación se muestra una función llamada leeTecla la cual implementa el algoritmo anterior en lenguaje C: // Esta funcion obtiene la tecla pulsada del // teclado matricial y la decodifica. // Regresa el caracter ASCII que representa la tecla int leeTecla(void) { int tecla = 0; int fila = 0x0E; PORTB = fila; // Tecla = 0 // Fila1 = 0, demás filas = 1 do { //Columna1 = 0? if(PORTBbits.RB4 == 0) break; //si tecla++; //no //Columna2 = 0? if(PORTBbits.RB5 == 0) break; tecla++; //Columna3 = 0? if(PORTBbits.RB6 == 0) break; tecla++; //Columna4 = 0? if(PORTBbits.RB7 == 0) break; tecla++; //Siguiente Fila=0, las demas Filas fila <<= 1; fila++; PORTB = fila; }while(tecla < 16); //Última tecla? LATB = 0; // Decodifica la tecla switch(tecla) { case 0: return '7'; case 1: return '8'; case 2: return '9'; case 3: return '/'; case 4: return '4'; case 5: return '5'; case 6: return '6'; case 7: return 'X'; case 8: return '1'; case 9: return '2'; Ing. Juan Ramon Terven Salinas en 1 Interrupciones 54 case 10: return '3'; case 11: return '-'; case 12: return 'C'; case 13: return '0'; case 14: return '='; case 15: return '+'; default: return -1; } }//fin de función leeTecla Programa 4-4. Algoritmo de lectura del teclado, función leeTecla En la función anterior, una vez terminado el ciclo do-while, en la variable tecla se tiene el número de tecla pulsada (de 0 a 15). Teniendo este número se decodifica al valor final deseado usando un switch (puede ser el que indica la serigrafía del teclado). Ahora la idea es que cuando se pulse cualquier tecla se produzca una interrupción RBI, para esto usamos la función OpenPORTB y habilitaremos las interrupciones con el bit GIE del registro INTCON. La función iniciaTeclado mostrada en el código siguiente deja listo el microcontrolador para detectar las interrupciones RBI. // Esta función Activa la interrupción RBI y Pull-ups internas // para detectar la tecla pulsada void iniciaTeclado(void) { // Configura el nible alto de PORTB como entrada // y el nible bajo como salida TRISB = 0xF0; PORTB = 0; // Inicia PORTB para recibir interrupcion // Configura interrupcion por cambio de estado en PORTB y // activa pull-ups OpenPORTB( PORTB_CHANGE_INT_ON & PORTB_PULLUPS_ON); // Habilitación de interrupciones INTCONbits.GIE = 1; } Programa 4-5. Función iniciaTeclado La función setTeclado se usa para dejar listo el puerto para recibir interrupciones, esta función la podemos usar en caso que el teclado y el display compartan el mismo puerto, ya que las función del LCD modifican el puerto. Ing. Juan Ramon Terven Salinas Interrupciones 55 // Esta función Deja listo el puerto B para detectar una tecla pulsada // Se usa porque las funciones del LCD modifican TRISB y PORTB void setTeclado(void) { // Configura el nible alto de PORTB como entrada // y el nible bajo como salida TRISB = 0xF0; //Deja listo PORTB para producir interrupcion (salidas enviando 0) PORTB = 0; } Programa 4-6. Función setTeclado Estas 3 funciones anteriores forman parte de un archivo llamado teclado.c el cual forma parte de una librería denominada teclado.h, cuyo contenido se muestra a continuación: #ifndef TECLADO_H #define TECLADO_H void iniciaTeclado(void); void setTeclado(void); int leeTecla(void); #endif Programa 4-7. teclado.h Ing. Juan Ramon Terven Salinas Interrupciones 56 Ejemplo 4-4. Uso de Teclado Matricial El siguiente ejemplo demuestra el uso de un teclado matricial de 4x4 usando el algoritmo explicado anteriormente. Al pulsarse una tecla se muestra su símbolo en el LCD. El diagrama se muestra en la Figura 4-7, observe que las filas (FIL1 – FIL4) se conectan a los pines RB0 – RB3 y las columnas (COL1 – COL4) a los pines RB4 – RB7. Las columnas conectadas a los pines RB4 – RB7 se usan como entradas de interrupción (KBI0 – KBI3) y las filas son son salidas del microcontrolador que envían ceros a las columnas cuando se pulsa alguna tecla del teclado matricial. Figura 4-7. Diagrama con Teclado Matricial y LCD El código se muestra a continuación Ing. Juan Ramon Terven Salinas Interrupciones 57 Programa 4-8. Uso de Teclado Matricial y LCD /* Uso de Teclado Matricial y LCD */ #include <p18F4550.h> #include "lcd.h" #include "teclado.h" void Teclado_ISR(void); //Código para bootloader extern void _startup (void); #pragma code REMAPPED_RESET_VECTOR = 0x1000 void _reset (void) { _asm goto _startup _endasm } // Seccion de codigo #pragma code void main() { char cad[] = "Probando Teclado"; ADCON1 = 0x0f; // Configura pines como digitales // configura LCD OpenLCD(FOUR_BIT & LINES_5X7); putsLCD(cad); SetDDRamAddr(0x40); // se coloca en el renglon 2 //Inicia interrupcion RBI, pull-ups y deja listo el teclado iniciaTeclado(); while(1){} } // Vector de interrupción #pragma code Interrupcion=0x1008 void VectorInterrupcion (void) { _asm GOTO Teclado_ISR _endasm } #pragma code // Rutina de interrupción de teclado #pragma interrupt Teclado_ISR void Teclado_ISR(void) { int tecla; tecla = leeTecla(); while(leeTecla()!=-1); // lee y decodifica la tecla pulsada //espera a que se suelte la tecla if(tecla != -1) { WriteDataLCD(tecla); // si hay tecla valida // escribe la tecla pulsada en LCD // deja listo el teclado para la siguiente interrupción setTeclado(); } // Limpia la bandera de interrupcion INTCONbits.RBIF = 0; } Ing. Juan Ramon Terven Salinas Interrupciones PRÁCTICA 4. Cerradura Electrónica Diseñe un sistema de cerradura electrónica con contraseña de 4 dígitos. • Usar un teclado matricial para digitar la contraseña. • Al encender el circuito se le pedirá al usuario que escriba la contraseña. • Si la escribe correctamente, aparecerá en el display “PASSW CORRECTA” y activará la chapa eléctrica durante 2 segundos aproximadamente. • Si la contraseña escrita es incorrecta aparecerá en el display “PASSW INCORRECTA” • Cuando se escriba la contraseña se mostrarán “*” en lugar del valor de la tecla pulsada. Ing. Juan Ramon Terven Salinas 58