Una interrupcin es un evento interno o externo que requiere atencin inmediata del CPU. La arquitectura del PIC32 puede manejar hasta 64 vectores de interrupcin distintos y puede soportar hasta 96 fuentes de interrupcin distintas. Cada fuente de interrupcin puede tener su propia rutina de interrupcin (ISR) en un vector individual, o varias fuentes de interrupcin pueden compartir la misma ISR dentro de un solo vector de interrupcin.
Bits asociados con cada fuente de interrupcin Cada fuente de interrupcin tiene 7 bits de control agrupados en distintos SFRs. Estos bits se describen a continuacin:
1. Bit de Habilitacin de Interrupcin (con terminacin IE). Cuando est en 0 la fuente de interrupcin asociada est deshabilitada. Cuando est en 1 la fuente de interrupcin puede disparar una interrupcin. Al reset, todas las fuentes de interrupcin estn deshabilitadas. 2. Bit de Bandera de Interrupcin (con terminacin IF). Este bit se activa automticamente cuando se dispara un evento de interrupcin. Se debe limpiar (poner en 0) por cdigo. 3. Bits de Nivel de Prioridad Grupal (con terminacin IP). Son 3 bits que determinan la prioridad de la interrupcin (desde ipl1 hasta ipl7). Cuando ocurren 2 disparos de interrupcin al mismo tiempo, se ejecutar primero la fuente de interrupcin con mayor prioridad. Al reset todas las fuentes de interrupcin tienen un nivel de prioridad ipl0 el cual indica deshabilitado. 4. Bits de Nivel de Subprioridad (cont terminacin IS). Son 2 bits ms usados para especificar 4 niveles de subprioridad distintos dentro de un mismo grupo.
Adems de estos niveles de prioridad, si aun as 2 fuentes de interrupcin con la misma prioridad se disparan al mismo tiempo, se ejecutar primero la que tenga la mayor prioridad natural. La Tabla 5-1 muestra todas las fuentes de interrupcin con sus bits asociados y el orden mostrado en esta tabla determina la prioridad natural. 5- Interrupciones Ing. Juan Ramon Terven Salinas 66 Tabla 5-1. Fuentes de Interrupcin con sus bits asociados
5- Interrupciones Ing. Juan Ramon Terven Salinas 67
5- Interrupciones Ing. Juan Ramon Terven Salinas 68
Librera de Manejo de Interrupciones El Lenguaje C32 provee una librera para manejo de interrupciones con funciones que nos permiten configurar las interrupciones de manera sencilla. Podemos agregar la librera como int.h o como plib.h (esta incluye int.h adems de las funciones de manejo de perifricos). Manejo de Interrupciones de un vector (Single Vector) El PIC32 permite usar un solo vector para varias fuentes de interrupcin, o permite usar vectores individuales para cada fuente de interrupcin. Para activar el modo Single Vector podemos usar la siguiente funcin de la librera:
INTEnableSystemSingleVectoredInt();
Y definimos la rutina de interrupcin de la siguiente manera: void __ISR( 0, ipl1) InterruptHandler (void) { //aqu va el cdigo de la rutina de interrupcin }
En este cdigo el argumento (0, ipl1) se refiere a que usaremos el vector 0 con prioridad 1. 5- Interrupciones Ing. Juan Ramon Terven Salinas 69 Ejemplo 1: Interrupcin CN en Single Vector La Interrupcin Change Notification (CN) se dispara cuando ocurre un cambio de estado en alguno de los pins denominados CN (vea el diagrama de pines del PIC32). Todos los pines CN producen la misma interrupcin. Cada pin CN tiene una pull up conectada que puede ser habilitada o deshabilitada por software. Las pull ups deben ser deshabilitadas si el pin est configurado como salida. Una vez que se produce una interrupcin CN, se debe leer el puerto donde se ubica el pin CN que la produjo, de lo contrario, la interrupcin se producir otra vez al salir de la rutina de interrupcin. Recuerde limpiar la bandera de interrupcin antes de salir de la rutina de interrupcin.
La Figura 5-1 muestra un diagrama a bloques del mecanismo de interrupcin Change Notification.
Figura 5-1. Diagrama a bloques de la interrupcin CN [8]
5- Interrupciones Ing. Juan Ramon Terven Salinas 70 Configuracin de Change Notification De acuerdo al manual de referencia de la familia PIC32MX en el apartado de puertos [8] , el procedimiento para configurar la interrupcin por Change Notification es el siguiente: 1. Deshabilitar interrupciones del CPU. 2. Configurar los pines CN como entradas digitales (usando registro TRISx). 3. Activar el mdulo CN (bit ON del registro CNCON en 1). 4. Activar cada pin CN que deseamos utilizar (bits CNENx del registro CNEN). 5. Opcionalmente podemos activar las pull ups de cada pin CN (bits CNPUEx del registro CNPUE). 6. Leer los puertos donde se ubican los pines CN para limpiar la condicin de cambio. 7. Configurar la prioridad y subprioridad de la interrupcin (registro IPC6 vea la Tabla 5-1). 8. Limpiar la bandera de interrupcin CN (bit CNIF del registro IFS1). 9. Activar la interrupcin CN (bit CNIE del registro IEC1). 10. Activar las interrupciones del CPU.
El ejemplo que se muestra a continuacin usa 2 pines CN, el RB0 (CN2) y el RB1 (CN3) para producir una interrupcin cuando cualquiera de estos 2 pines cambia de estado. La rutina de interrupcin simplemente cambia el estado de 2 LEDs en funcin de cual pin CN produjo un cambio positivo (de 0 a 1). El circuito usado se muestra en la Figura 5-2 y el cdigo se muestra en el Programa 5-1. El cdigo del programa muestra el procedimiento de configuracin de la interrupcin Change Notification descrito anteriormente. 5- Interrupciones Ing. Juan Ramon Terven Salinas 71
Figura 5-2. Ejemplo Interrupcin CN
Programa 5-1. Uso de interrupcin CN con Single Vector #include <p32xxxx.h> #include <plib.h>
// Funcin Main int main(void) { AD1PCFG = 0xFFFF; // configura AN pins como digitales
TRISE = 0; //Puerto E como salidas LATE = 0; //Limpia salida de puerto E
/**CONFIGURACION DE INTERRUPCION CHANGE NOTIFICATION EN CN2 Y CN3****/
//Configura RB0(CN2) y RB1(CN3) como entradas _TRISB0 = 1; _TRISB1 = 1;
5- Interrupciones Ing. Juan Ramon Terven Salinas 72 //Activa el mdulo CN CNCONbits.ON = 1;
//Activa la interrupcin CN en los pines CN2 y CN3 CNENbits.CNEN2 = 1; CNENbits.CNEN3 = 1;
//Activa las pull-ups en los pines CN2 y CN3 CNPUEbits.CNPUE2 = 1; CNPUEbits.CNPUE3 = 1;
//Lee el registro PORTB para limpiar el change notification PORTB;
//Selecciona prioridad 1 y subprioridad de 0 //La prioridad de 1 (ipl1) debe coincidir con la indicada en la // rutina de interrupcin IPC6bits.CNIP = 1; //prioridad de 1 IPC6bits.CNIS = 0; //subprioridad de 0
//Limpia la bandera de interrupcion IFS1bits.CNIF = 0;
// Activa el modo Single Vector INTEnableSystemSingleVectoredInt();
//Activa la interrupcion CN IEC1bits.CNIE = 1; /********************************************************************/
while(1) { }
return 0; }
//RUTINA DE INTERRUPCIN void __ISR( 0, ipl1) InterruptHandler( void) { if(PORTB & 1) //Lee el PORTB y extra el bit RB0 (CN2) _LATE0 ^= 1; else if(PORTB & 2) //Lee el PORTB y extra el bit RB1 (CN3) _LATE1 ^= 1;
//Limpia la bandera de interrupcin IFS1bits.CNIF = 0; }
Mltiples Interrupciones en un solo vector (Single Vector) Para tener varias rutinas de interrupcin en un solo vector, simplemente configuramos las interrupciones con la misma prioridad y usamos la misma funcin INTEnableSystemSingleVectoredInt(); 5- Interrupciones Ing. Juan Ramon Terven Salinas 73 La nica diferencia es que dentro de la rutina de interrupcin debemos averiguar cual interrupcin fue disparada analizando la bandera de interrupcin de cada fuente de interrupcin que comparte el mismo vector. Ejemplo 2. Interrupciones INT0 y CN en el mismo vector El PIC32 ofrece 5 fuentes de interrupcin externa disparadas por flanco llamadas INT0, INT1, INT2, INT3 e INT4. Cada una de estas fuentes de interrupcin se puede configurar para generar una interrupcin cuando se produce un flanco ascendente o un flanco descendente en dicho pin. El siguiente ejemplo muestra el uso de la interrupcin INT0 (pin RD0) y la interrupcin CN (CN2 y CN3) Programa 5-2. Interrupcin INT0 y CN en single vector #include <p32xxxx.h> #include <plib.h>
int main(void) { AD1PCFG = 0xFFFF; // configura AN pins como digitales
TRISE = 0; //Puerto E como salidas LATE = 0; //Limpia salida de puerto E
/** CONFIGURACION DE INTERRUPCIONES CN2 Y CN3 *****/
//Configura RB0(CN2) y RB1(CN3) como entradas _TRISB0 = 1; _TRISB1 = 1;
//Activa el mdulo CN CNCONbits.ON = 1;
//Activa la interrupcin CN en los pines CN2 y CN3 CNENbits.CNEN2 = 1; CNENbits.CNEN3 = 1;
//Activa las pull-ups en los pines CN2 y CN3 CNPUEbits.CNPUE2 = 1; CNPUEbits.CNPUE3 = 1;
//Lee el registro PORTB para limpiar el change notification PORTB;
5- Interrupciones Ing. Juan Ramon Terven Salinas 74
//Activa prioridad 1 con subprioridad de 0 //La prioridad de 1 (ipl1) debe coincidir con la indicada en la // rutina de interrupcin IPC6bits.CNIP = 1; //prioridad de 1 IPC6bits.CNIS = 0; //subprioridad de 0
//Limpia la bandera de interrupcin IFS1bits.CNIF = 0;
/************* CONFIGURACION DE INTERRUPCION INT0 ***************/ //Configura RD0 (INT0) como entrada _TRISD0 = 1;
//Activacin por flanco descendente INTCONbits.INT0EP = 0;
//Prioridad 1(ipl1) con subprioridad de 1 IPC0bits.INT0IP = 1; IPC0bits.INT0IS = 1;
//Limpia la bandera de interrupcin IFS0bits.INT0IF = 0;
// Activa el modo Single Vector INTEnableSystemSingleVectoredInt(); /****************************************************************/
//FINALMENTE ACTIVA AMBAS INTERRUPCIONES IEC1bits.CNIE = 1; //Activa la interrupcin CN IEC0bits.INT0IE = 1; //Activa la interrupcin INT0
while(1) { } return 0; }
//RUTINA DE INTERRUPCIN void __ISR( 0, ipl1) InterruptHandler( void) { // Si se dispar la rutina de interrupcion CN if(IFS1bits.CNIF) { if(PORTB & 1) //Lee el PORTB y extra el bit RB0 (CN2) _LATE0 ^= 1; else if(PORTB & 2) //Lee el PORTB y extra el bit RB1 (CN3) _LATE1 ^= 1;
//Limpia la bandera de interrupcin IFS1bits.CNIF = 0; } // Si se dispar la rutina de interrupcin INT0 else if(IFS0bits.INT0IF) { _LATE2 ^= 1;
//Limpia la bandera de interrupcin IFS0bits.INT0IF = 0; } } 5- Interrupciones Ing. Juan Ramon Terven Salinas 75 Manejo de Interrupciones con mltiples vectores El PIC32 soporta el manejo de interrupciones con mltiples vectores. La ventaja de este mtodo es que la latencia en el servicio de interrupcin es menor. La latencia del servicio de interrupcin es aun menor si se asigna prioridad nivel 7 ya que se hace uso de un registro conjunto de registros alterno para respaldo. La Tabla 5-2 muestra los vectores de interrupcin con su nombre simblico que se usar en la rutina de interrupcin. Tabla 5-2. Vectores de Interrupcin [14]
5- Interrupciones Ing. Juan Ramon Terven Salinas 76
5- Interrupciones Ing. Juan Ramon Terven Salinas 77 Ejemplo 3. Interrupciones INT0 y CN en mltiples vectores El siguiente ejemplo demuestra el uso de interrupciones en modo Multivector. El funcionamiento del circuito es equivalente al ejemplo anterior. Se resalta con color azul el cdigo distinto al ejemplo anterior que usaba un solo vector de interrupcin. Programa 5-3. Uso de Interrupciones CN e INT2 en vectores separados #include <p32xxxx.h> #include <plib.h>
int main(void) { AD1PCFG = 0xFFFF; // configura AN pins como digitales
TRISE = 0; //Puerto E como salidas LATE = 0; //Limpia salida de puerto E
/******CONFIGURACION DE INTERRUPCIONES CN2 Y CN3 *****/ //Configura RB0(CN2) y RB1(CN3) como entradas _TRISB0 = 1; _TRISB1 = 1;
//Activa el mdulo CN CNCONbits.ON = 1;
//Activa la interrupcion CN en los pines CN2 y CN3 CNENbits.CNEN2 = 1; CNENbits.CNEN3 = 1;
//Activa las pull-ups en los pines CN2 y CN3 CNPUEbits.CNPUE2 = 1; CNPUEbits.CNPUE3 = 1;
//Lee el registro PORTB para limpiar el change notification PORTB;
//Activa la prioridad 1 en la interrupcion CN con subprioridad de 0 //La prioridad de 1 (ipl1) debe coincidir con la indicada //en la rutina de interrupcin IPC6bits.CNIP = 1; //prioridad de 1 IPC6bits.CNIS = 0; //subprioridad de 0
//Limpia la bandera de interrupcin IFS1bits.CNIF = 0; /*****************************************************************/
/************** CONFIGURACION DE INTERRUPCION INT0 **************/ //Configura RD0 (INT0) como entrada _TRISD0 = 1;
//Activacin por flanco descendente 5- Interrupciones Ing. Juan Ramon Terven Salinas 78 INTCONbits.INT0EP = 0;
//Prioridad 2(ipl2) con subprioridad de 1 IPC0bits.INT0IP = 2; IPC0bits.INT0IS = 1;
//Limpia la bandera de interrupcion IFS0bits.INT0IF = 0;
// Activa el modo MultiVectored INTEnableSystemMultiVectoredInt(); /****************************************************************/
//FINALMENTE ACTIVA AMBAS INTERRUPCIONES IEC1bits.CNIE = 1; //Activa la interrupcion CN IEC0bits.INT0IE = 1; //Activa la interrupcion INT0
while(1) { }
return 0; }
//RUTINA DE INTERRUPCIN DE CHANGE NOTIFICATION void __ISR( _CHANGE_NOTICE_VECTOR, ipl1) CNInterruptHandler(void) { if(PORTB & 1) //Lee el PORTB y extra el bit RB0 (CN2) _LATE0 ^= 1; else if(PORTB & 2) //Lee el PORTB y extra el bit RB1 (CN3) _LATE1 ^= 1;
//Limpia la bandera de interrupcin IFS1bits.CNIF = 0; }
//RUTINA DE INTERRUPCIN DE INT0 void __ISR( _EXTERNAL_0_VECTOR, ipl2) INT0InterruptHandler(void) { _LATE2 ^= 1;
//Limpia la bandera de interrupcion IFS0bits.INT0IF = 0; }
5- Interrupciones Ing. Juan Ramon Terven Salinas 79 Uso de un Teclado Matricial Un teclado matricial est constituido por una matriz de pulsadores dispuestos en filas y columnas como se muestra en la Figura 5-3. La finalidad es reducir el nmero de lneas necesarias para la conexin. 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 slo 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 estn desconectadas de las columnas.
Figura 5-3. Teclado matricial con microcontrolador [19]
5.1.1 Conexin de un Teclado matricial con un PIC32
La Figura 5-3 muestra una posible conexin de un teclado matricial a un PIC32 con las siguientes caractersticas: Las filas del teclado se conectan a pines configurados como salida. Las columnas del teclado se conectan a pines con interrupcin CN. Observe que estas pines deben tener habilitadas las resistencias de pull-up.
5- Interrupciones Ing. Juan Ramon Terven Salinas 80 Si se presiona una tecla, una de las columnas (entras CN) recibe un nivel bajo produciendo una interrupcin. Por ejemplo en la Figura 5-3 se pulsa la tecla 3, de tal forma que se produce una interrupcin Change Notification. En la rutina de interrupcin, debemos determinar que tecla se puls por medio del siguiente algortmo.
5.1.2 Algoritmo para lectura del teclado
1. A cada tecla se le asigna un cdigo que puede ser el orden de la tecla, como se muestra en la Figura 5-4.
Figura 5-4- Codigo asignado a cada tecla
2. Luego ejecutamos el algoritmo siguiente: 5- Interrupciones Ing. Juan Ramon Terven Salinas 81
Figura 5-5. Algoritmo de deteccin de tecla pulsada
5- Interrupciones Ing. Juan Ramon Terven Salinas 82 A continuacin se muestra una funcin llamada leeTecla la cual implementa el algoritmo anterior en lenguaje C32:
//VALORES DE LAS TECLAS char teclas[16] ={ '1','2','3','A', '4','5','6','B', '7','8','9','C', '*','0','#','D'};
// Esta funcion obtiene la tecla pulsada del // teclado matricial y la decodifica. // Regresa el caracter ASCII que representa la tecla int leeTecla(void) { char tecla;
}//fin de funcin leeTecla Programa 5-4. Algoritmo de lectura del teclado, funcin leeTecla
La idea es que cuando se pulse cualquier tecla se produzca una interrupcin CN, para esto debemos habilitar la interrupcin CN en los pines donde se conectan las columnas C1-C4. 5- Interrupciones Ing. Juan Ramon Terven Salinas 84 La funcin openTeclado mostrada en el cdigo siguiente deja listo el microcontrolador para detectar las interrupciones CN.
// Esta funcin Activa la interrupcin CN en los pines // En el archivo teclado.h se encuentran las definiciones de los pines void openTeclado(void) { //Configura columnas como entradas TRIS_COL1 = 1; TRIS_COL2 = 1; TRIS_COL3 = 1; TRIS_COL4 = 1;
//Escribe 0 en las filas para dejar listo el teclado FIL1 = 0; FIL2 = 0; FIL3 = 0; FIL4 = 0;
//Activa el mdulo CN CNCONbits.ON = 1;
//Activa la interrupcion CN en cada columna CN_COL1 = 1; CN_COL2 = 1; CN_COL3 = 1; CN_COL4 = 1;
//Activa las pull-ups en cada columna PULL_COL1 = 1; PULL_COL2 = 1; PULL_COL3 = 1; PULL_COL4 = 1;
//Lee los pines de columnas para limpiar el change notification COL1; COL2; COL3; COL4;
//Prioridad del teclado IPC6bits.CNIP = PRIORIDAD_TECLADO; IPC6bits.CNIS = SUBPRIORIDAD_TECLADO;
//Limpia la bandera de interrupcion IFS1bits.CNIF = 0;
// Activa el modo de interrupcin (vea teclado.h) MODO_DE_INTERRUPCION
IEC1bits.CNIE = 1; //Activa la interrupcion CN } Programa 5-5. Funcin openTeclado
5- Interrupciones Ing. Juan Ramon Terven Salinas 85
Estas funciones anteriores forman parte de un archivo llamado teclado.c el cual junto con otro archivo llamado teclado.h forman la librera para el teclado. A continuacin se muestra el contenido del archivo teclado.h. #ifndef TECLADO_H #define TECLADO_H #include <p32xxxx.h> #include <plib.h>
//AQUI MODIFIQUE LO REFERENTE A LA INTERRUPCION #define PRIORIDAD_TECLADO 1 //ipl1 #define SUBPRIORIDAD_TECLADO 0 #define MODO_DE_INTERRUPCION INTEnableSystemMultiVectoredInt();
//AQUI CAMBIE LOS PINES DE ACUERDO A SU CONEXIN //Registro TRIS de Columnas #define TRIS_COL1 TRISBbits.TRISB0 #define TRIS_COL2 TRISBbits.TRISB1 #define TRIS_COL3 TRISBbits.TRISB4 #define TRIS_COL4 TRISBbits.TRISB5
//Pines de entrada de Columnas #define COL1 PORTBbits.RB0 #define COL2 PORTBbits.RB1 #define COL3 PORTBbits.RB4 #define COL4 PORTBbits.RB5
//Interrupciones CN de cada columna #define CN_COL1 CNENbits.CNEN2 #define CN_COL2 CNENbits.CNEN3 #define CN_COL3 CNENbits.CNEN6 #define CN_COL4 CNENbits.CNEN7
//Pull-ups de cada columna #define PULL_COL1 CNPUEbits.CNPUE2 #define PULL_COL2 CNPUEbits.CNPUE3 #define PULL_COL3 CNPUEbits.CNPUE6 #define PULL_COL4 CNPUEbits.CNPUE7
//Registro TRIS de Filas #define TRIS_FIL1 TRISDbits.TRISD4 #define TRIS_FIL2 TRISDbits.TRISD5 #define TRIS_FIL3 TRISBbits.TRISB9 #define TRIS_FIL4 TRISDbits.TRISD11
//Pines de salida de las filas #define FIL1 LATDbits.LATD4 #define FIL2 LATDbits.LATD5 #define FIL3 LATBbits.LATB9 #define FIL4 LATDbits.LATD11
//Prototipos de funciones void openTeclado(void); void setTeclado(void); int leeTecla(void);
#endif Programa 5-6. teclado.h 5- Interrupciones Ing. Juan Ramon Terven Salinas 86 Ejemplo 4. Uso de Teclado Matricial El siguiente ejemplo hace uso de la librera teclado.h explicada anteriormente para probar el funcionamiento de un teclado matricial conectado como se muestra en la Figura 5-6. El programa simplemente muestra en pantalla la tecla pulsada.
Figura 5-6. Circuito para ejemplo de teclado matricial
Cada vez que se pulsa cualquier tecla, se genera una interrupcin CN. Dentro de la rutina de servicio de interrupcin se identifica la tecla pulsada con la funcin leeTecla() y luego se muestra en el display el cdigo asociado con dicha tecla. 5- Interrupciones Ing. Juan Ramon Terven Salinas 87 Programa 5-7. Ejemplo de Teclado Matricial #include <p32xxxx.h> #include "../librerias/LCD/alpha_lcd.h" #include "../librerias/teclado/teclado.h" #include "../librerias/retardos/retardos.h"
AD1PCFG = 0xFFFF; // configura pines AN como digitales
// configura LCD openLCD();
//Escribe TECLADO en renglon 1 setDDRamAddr(0x0); putsLCD("TECLADO");
//Coloca el cursor en renglon 2 setDDRamAddr(0x40);
//Activa el teclado matricial openTeclado();
//Ciclo principal while(1) { //Solo espera a que se pulse una tecla }
return 0; }
//RUTINA DE INTERRUPCIN DE CHANGE NOTIFICATION //Se produce cuando se pulsa cualquier tecla void __ISR( _CHANGE_NOTICE_VECTOR, ipl1) CNInterruptHandler( void) { char tecla;
retardoms(5); tecla = leeTecla();
if(tecla != -1) // si hay tecla valida { putcLCD(tecla); // escribe la tecla pulsada en LCD while(leeTecla()!=-1); //espera a que se suelte la tecla retardoms(5); }
//Limpia la bandera de interrupcin IFS1bits.CNIF = 0; } 5- Interrupciones Ing. Juan Ramon Terven Salinas 88 Ejemplo 5. Calculadora Bsica El siguiente ejemplo consiste en una calculadora bsica capaz de realizar las operaciones suma, resta, multiplicacin y divisin. La Figura 5-7 muestra el diagrama de la calculadora bsica. Observe que el diagrama es idntico al anterior, la nica diferencia es el valor de las teclas del teclado matricial. El cdigo se encuentra bastante comentado para hacerlo autoexplicativo.
Figura 5-7. Calculadora Bsica
5- Interrupciones Ing. Juan Ramon Terven Salinas 89 Programa 5-8. Calculadora Bsica #include <p32xxxx.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include "../librerias/LCD/alpha_lcd.h" #include "../librerias/teclado/teclado.h" #include "../librerias/retardos/retardos.h"
//Ciclo principal while(1) { //Solo espera a que se pulse una tecla }
return 0; }
5- Interrupciones Ing. Juan Ramon Terven Salinas 90 //RUTINA DE INTERRUPCIN DE CHANGE NOTIFICATION //Se produce cuando se pulsa cualquier tecla //1. Decodifica la tecla pulsada //2. Si se pulsa una tecla de operacion matemtica // guarda el valor escrito y el operador //3. Si se pulsa = realiza la oepracin y // muestra el resultado en pantalla //4. Si se pulsa C limpia todo //5. Si se pulsa una tecla de nmero lo agrega // a la cadena str_operando void __ISR( _CHANGE_NOTICE_VECTOR, ipl1) CNInterruptHandler(void) { char tecla; retardoms(5);
1). tecla = leeTecla();
if(tecla != -1) // si hay tecla valida { switch(tecla) { //2) Si se puls una tecla de operacion case '+': case '-': case '*': case '/': //convierte la cadena a double y guarda en resultado resultado = atof(str_operando); //Guarda el operador operador = tecla; //Reinicia indice para almacenar cadena numerica indiceOperando = 0; //Imprime el operador putcLCD(tecla); break; //3) Si se puls la tecla = case '=': //Convierte la cadena de operando a double operando = atof(str_operando); //realiza la operacion resultado = operacion(resultado,operador,operando); //convierte resultado a cadena sprintf(str_operando,"%f",resultado); //lo muestra en renglon2 setDDRamAddr(0x40); putsLCD(str_operando); //reinicia la cadena operando strcpy(str_operando,"0"); indiceOperando = 0; break; //4) Si se puls la tecla 'C' case 'C': //limpia cadena operando indiceOperando = 0; strcpy(str_operando,"0"); //limpia operador y resultado operador=0; resultado = 0; //limpia pantalla setDDRamAddr(0x0); 5- Interrupciones Ing. Juan Ramon Terven Salinas 91 putsLCD("0 "); setDDRamAddr(0x40); putsLCD(" "); setDDRamAddr(0x0); break; //5) De lo contrario si se puls un numero default: //Si indiceOperando es 0, limpia renglon 1 //y se coloca al inicio de LCD if(indiceOperando == 0) { setDDRamAddr(0x0); putsLCD(" "); setDDRamAddr(0x0); } //Si aun caben digitos... if(indiceOperando <= SIZE_NUMBERS) { //almacena el digito en la cadena operando str_operando[indiceOperando++] = tecla; str_operando[indiceOperando] = 0; //fin de cadena //lo muestra en LCD putcLCD(tecla); } } while(leeTecla()!=-1); //espera a que se suelte la tecla retardoms(5); }
//Limpia la bandera de interrupcion IFS1bits.CNIF = 0; }
//Realiza la operacin matemtica indicada double operacion(double valor1, char operador, double valor2) { double r = 0; switch(operador) { case '+': r = valor1 + valor2; break; case '-': r = valor1 - valor2; break; case '*': r = valor1 * valor2; break; case '/': if(valor2 != 0) r = valor1 / valor2; break; } return r; }
5- Interrupciones Ing. Juan Ramon Terven Salinas 92 PRCTICA 3. Calculadora Cientfica bsica Usando el mismo circuito de los 2 ejemplos anteriores, disee una calculadora cientfica que realice las operaciones mostradas en la Figura 5-8.
Nota: Use las funciones de la librera math.h para realizar las operaciones trigonomtricas y transcendentes.