TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Diploko en 11 de Noviembre de 2010, 05:32:18

Título: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: Diploko en 11 de Noviembre de 2010, 05:32:18
Hola a tod@s,
En primer lugar enhorabuena a todos los que aportais ideas y soluciones, gracias a todos ustedes me resulta mas fácil iniciarme.

Consigo capturar todas las teclas del teclado sin problemas siempre y cuando no use interrupciones, por ejemplo, así:
Código: [Seleccionar]
while(true)
{
    button=ConsultaTecla();       //Me quedo con la tecla pulsada

    if(!button==0) //Si se pulsó tecla la saco por RS232
printf("Button: \%02u \n",button);

    delay_ms(10); //Pequeño retardo
}
Con este código simple en el main consigo leer correctamente el teclado.

El problema lo tengo cuando quiero hacerlo de la forma correcta mediante interrupción RB4-RB7. Esto es lo que hago:
Código: [Seleccionar]
#include <16F877.h>
#FUSES XT,NOPROTECT,PUT,BROWNOUT,NOLVP,NOWDT,NOWRT,NODEBUG
#USE DELAY(CLOCK=4000000)
#USE RS232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)

//Archivos incluidos en la compilación
#include <BotoneraTemporal.c>

#byte PORTB=0x06
#byte TRISB=0x86

int button;

#int_RB
void RB_isr(void) //función de interrupción
{
button=ConsultaTecla();      
printf("Int Button: \%02u ",button); //Monitorizo por RS232 el botón pulsado
clear_interrupt(INT_RB);
}

void main()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_RB);

set_tris_a(0xFF);
set_tris_b(0xF0);
set_tris_c(0x00);
set_tris_d(0b11000000);
set_tris_e(0x00);
  
port_b_pullups(true);

while(true)
{

}


"BotoneraTemporal.c":
Código: [Seleccionar]

#byte kbd_port_b= 6

int const Teclas[4][4] = {{1,2,3,4},
                          {5,6,7,8},
                          {9,10,11,12},
                          {13,14,15,16}};

//Función que devuelve el código [int] de cada tecla
int ConsultaTecla()
{
int tecla=0;
int f,c,t,i,j;

set_tris_b(0x0F); // RB7-RB4 salidas, RB3-RB0 entradas

for(f=0x10, i=0; i<4; f<<=1, i++)
{
for(c=0x01, j=0; j<4; c<<=1, j++)
{
kbd_port_b = ~f;
delay_cycles(1);
t = kbd_port_b & 0x0F;
t = ~(t | 0xF0);
if(t == c)
{
delay_ms(20);
tecla=Teclas[i][j];
while(t==c)
{
t = kbd_port_b & 0x0F;
t = ~(t | 0xF0);
}
break;
 }
}
if(tecla)
break;
}

return tecla;
}


Creo que el problema lo tengo en la configuración del portb o bien de la interrupción... con los cambios que intento hacer o no entra en la interrupción o entra constantemente...
He leido varios temas relacionados que he encontrado pero no consigo detectar el problema, ¿alguien me puede ayudar?

Gracias
Salu2!

Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 11 de Noviembre de 2010, 09:30:18
Qué tal diploko!
Tengo algo de tiempo alejado de los pics, ahora me estoy reactivando...

Pero si mal no recuerdo, en la rutina de interrupción de RB debes:
- desactivar las interrupciones.
- leer el puerto B (esa una condición obligatoria).
- hacer lo que quieras que se ejecute cuando hay interrupción.
- volver a activar las interrupciones.

Estuve viendo por ahí y creo que por aquí hay códigos que te pueden ser útiles:
Leer teclado en C (http://www.todopic.com.ar/foros/index.php?topic=4807.0)
Sería cuestión de echarle una retocada a las líneas...

Bueno como siempre, si estoy en un error que por favor lo corrijan los maestros del foro.
Saludos a todos, nos leemos!  :mrgreen:
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: AngelGris en 11 de Noviembre de 2010, 10:06:03
Yo utilizaría el nibble alto del puerto B (RB4 a RB7) como entrada y el nibble bajo como salida.
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 11 de Noviembre de 2010, 10:10:02
Yo utilizaría el nibble alto del puerto B (RB4 a RB7) como entrada y el nibble bajo como salida.

Jeje qué tonto soy... "elemental mi querido Wakson" jeje...
Gracias AngelGris!  :-/  Pues claro, si se usan RB4:7 como salidas cómo vamos a esperar que funcionen la interrupción en RB??

Por ahí debe ir el error principal...
Ojalá que logres resolver Diploko!
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: Diploko en 11 de Noviembre de 2010, 12:44:37
Gracias a los 2 por responder!
firepic, tomo nota de los cambios que indicas pero no hay mejoría.
El enlace que indicas ya lo había visto y los códigos que ponen no me funcionan y tampoco me queda claro que a ellos les funcionase la interrupción  :?.

AngelGris, el PORTB ya lo tengo configurado como dices
Código: [Seleccionar]
set_tris_b(0xF0); solo que en la funcion "ConsultaTecla" le doy la vuelta para conseguir la tecla pulsada pero luego vuelvo a configurarla como al principio (RB4-7 como entradas) en dicha función.
Insisto, la función "ConsultaTecla" funciona bien siempre y cuando no use #int_RB.

Pruebo y pruebo... sin resultados satisfactorios...  :5] ¿Debería usar otra función para leer la tecla pulsada? si es así aconsejenme una porque las que encontré no me funcionan.

Este es el código que tengo funcionando ahora mismo (ahora en un solo archivo para que sea más rápido de leer), el resultado es que #int_RB se ejecuta constantemente:
Código: [Seleccionar]
#include <16F877.h>
#FUSES XT,NOPROTECT,PUT,BROWNOUT,NOLVP,NOWDT,NOWRT,NODEBUG
#USE DELAY(CLOCK=4000000)
#USE RS232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)

#byte PORTB=0x06 //Pic 16f877a
#byte TRISB=0x86 //


/** FUNCIONES GLOBALES ********/
int ConsultaTecla(void);

/** VARIABLES *****************/
int button,aux;
int const Teclas[4][4] ={{1,2,3,4},
{5,6,7,8},
                        {9,10,11,12},
                        {13,14,15,16}};



/** INTERRUPCIONES ******************************************************************************************/
#int_RB
void RB_isr(void) //función de interrupción
{
disable_interrupts(INT_RB);
disable_interrupts(GLOBAL);

button=ConsultaTecla();     
printf("Int Button: \%02u\n",button);

                enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
}



//Función que devuelve el código [int] de cada tecla
int ConsultaTecla()
{
int tecla=0;
int f,c,t,i,j;


set_tris_b(0x0F); // RB7-RB4 salidas, RB3-RB0 entradas

for(f=0x10, i=0; i<4; f<<=1, i++)
{
for(c=0x01, j=0; j<4; c<<=1, j++)
{
PORTB = ~f;
delay_cycles(1);
t = PORTB & 0x0F;
t = ~(t | 0xF0);
if(t == c)
{
delay_ms(20);
tecla=Teclas[i][j];
while(t==c)
{
t = PORTB & 0x0F;
t = ~(t | 0xF0);
}
break;
  }
}
if(tecla)
break;
}

set_tris_b(0xF0);

return tecla;
}



void main()
{

printf("Inicio Main 0\n");

enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);

set_tris_b(0xF0);
 
port_b_pullups(true);

printf("Inicio bucle\n");

while(true)
{

delay_ms(1000);

}
}

Salu2!
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: AngelGris en 11 de Noviembre de 2010, 16:23:44
A ver...

  En el programa principal primero tenés que setear los tris y luego habilitar las interrupciones.
  En la rutina de atención a la interrupción creo que no es necesario deshabilitarlas y luego volver a habilitarlas, si mal no recuerdo de ello ya se encarga el compilador por el hecho de que precediste la función con "#INT_RB". Sí tenés que borrar el flag que indica que hubo interrupción. Usar "Printf" dentro de la propia interrupción no es recomendable.

  Yo haría algo asi....


Código: C
  1. rutina de interrupción de RB4..RB7
  2. {
  3.   testear si hay tecla presionada, o se activó la interrupción por una tecla soltada
  4.   si es por tecla presionada activar una variable (tiene que estar declarada golbalmente) usada como flag
  5.   borrar el flag de la interrupción de RB.
  6.  
  7. // si es por tecla presionada, sabemos que algunos de los bits del nibble alto va a tener que estar en 0 (si es que susás R de pullups). En cambio si usás R de pull down (dichos bits van a estar normalmente en 0 pero cuando presiones una tecla alguno de dichos bits va a estar en 1)
  8. }
  9.  
  10.  
  11. rutina de consulta del teclado
  12. {
  13.   hacer todas las cosas necesarias.
  14.  
  15. }
  16.  
  17. main
  18. {
  19.   setear el tris
  20.   activar las interrupciones
  21.  
  22.   while (1)
  23.   {
  24.     if (variable usada como flag == 1)  // indica que se presionó una tecla.
  25.     {
  26.       deshabilitar interrupciones RB
  27.       espera de unos 10ms //para que funcione como antirrebote
  28.       testear el puerto B para saber si sigue presionada una tecla
  29.       si sigue presionada
  30.       {
  31.          leo el teclado //llamando a tu rutina "consulta"
  32.  
  33.          printf (o todo lo que quieras hacer con la tecla)
  34.       }
  35.       leer el puerto B para eliminar cualquier condición de mismatch (o sea, para que no haya diferencias y así evitar que se
  36.                                                                                                   active el flag de interrupción RB)
  37.       borrar el flag de interrupción RB
  38.       activar las interrupciones
  39.     }
  40.   }
  41. }
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 12 de Noviembre de 2010, 14:53:02
Qué tal!

Bueno me he interesado en este programita porque tengo en mente un proyecto en el cual también tendré que usar un tecladito jeje  :D
Tengo este código, lo he probado en proteus y hasta ahora funciona bien la interrupción y logro identificar qué columna del teclado se ha presionado, lo que falta es identificar la fila...

Código: C
  1. ///////////////////////////////////////////////
  2. //             lee un teclado 4x4                //
  3. //   y envia al pc por puerto serial         //
  4. ///////////////////////////////////////////////
  5.  
  6. #include <16f876.h>
  7. #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  8. #define Tx PIN_C6
  9. #define Rx PIN_C7
  10. #use delay (CLOCK=20000000)
  11. #use rs232 (BAUD=19200,XMIT=Tx,RCV=Rx)
  12. #use fast_io(B)
  13. #byte port_b = 0x06
  14. boolean flag;
  15. int fila,columna;
  16.  
  17. #INT_RB
  18. void tecla_presionada()
  19. {
  20.         int i,puerto_1;
  21.         disable_interrupts(INT_RB);                                                             //deshabilita las interrupciones
  22.         puerto_1 = port_b & 0b11110000;                                                 //lee portb4:7 y lo guarda en puerto_1
  23.         if(puerto_1!=0)                                                                                 //si se presionó una tecla (flanco hacia arriba)
  24.         {
  25.                 for(i=4;i<=7;i++) if(bit_test(puerto_1,i))columna=i-4;                 //para saber qué columna se presionó
  26.                 //Aquí falta código para saber qué fila se ha presionado.                   
  27.         }
  28.         flag=1;
  29.         set_tris_b(0xf0);
  30.         output_b(0x0f);
  31.         clear_interrupt(INT_RB);
  32.         enable_interrupts(INT_RB);
  33. }
  34.  
  35. main()
  36. {
  37.         output_b(0x0f);
  38.         set_tris_b(0xf0);
  39.         enable_interrupts(INT_RB);
  40.         enable_interrupts(GLOBAL);
  41.         while(TRUE)
  42.         {
  43.                 if(flag==1)
  44.                 {
  45.                         printf("Columna: %i\n\r",columna);
  46.                         printf("Fila: %i\n\r",fila);
  47.                         flag=0;
  48.                 }
  49.         }
  50. }

Te dejo la simulación en proteus...
Si logras hacer lo que falta por favor no dejes de publicarlo eh!

Un cordial saludo! Nos leemos!  :mrgreen:
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: AngelGris en 12 de Noviembre de 2010, 14:57:10
Para saber la fila, dentro de tu rutina de lectura de teclas, tenés que ir activando una a una y leyendo a su vez. Osea...

Pongo a 1 una única fila y leeo el puerto, si en alguna entrada sigue habiendo un 1 es porque a esa fila pertenece la tecla presionada, sino voy a leer 0. Entonces pongo a 1 la siguiente fila y vuelvo a leer y así sucesivamente
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 12 de Noviembre de 2010, 15:07:29
Para saber la fila, dentro de tu rutina de lectura de teclas, tenés que ir activando una a una y leyendo a su vez. Osea...

Pongo a 1 una única fila y leeo el puerto, si en alguna entrada sigue habiendo un 1 es porque a esa fila pertenece la tecla presionada, sino voy a leer 0. Entonces pongo a 1 la siguiente fila y vuelvo a leer y así sucesivamente

Correcto AngelGris, esa es la teoría y debería funcionar... pero en la práctica aún no me ha funcionado   :shock:  :?
Debe ser porque no he almorzado y ya no razono del hambre...  :D

En un rato vuelvo a darle a ver si termino eso...
Gracias y saludos! Nos leemos!  :mrgreen:
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 12 de Noviembre de 2010, 18:37:20
Bueno esto es lo que tengo hasta ahora, pero la parte de leer la fila no funciona, hice la lógica tal como me dijo AngelGris y la he revisado y no encuentro la falla...  :5]
Posiblemente estoy cometiendo una gran burrada... pero creo que será todo por hoy, luego seguiré revisando...

Lo positivo es que sí funciona la parte de interrupción en RB y la detección de la columna... ese es mi consuelo  :lol:

Dejo el código:
Código: C
  1. ///////////////////////////////////////////////
  2. //             lee un teclado 4x4                //
  3. //   y envia al pc por puerto serial         //
  4. ///////////////////////////////////////////////
  5.  
  6. #include <16f876.h>
  7. #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  8. #define Tx PIN_C6
  9. #define Rx PIN_C7
  10. #use delay (CLOCK=20000000)
  11. #use rs232 (BAUD=19200,XMIT=Tx,RCV=Rx)
  12. #use fast_io(A)
  13. #use fast_io(B)
  14. #byte port_b = 0x06
  15. #byte tris_b = 0xff
  16. boolean flag;
  17. int fila,columna;
  18.  
  19. #INT_RB
  20. void tecla_presionada()
  21. {
  22.         int i,puerto_1,puerto_2;
  23.         disable_interrupts(INT_RB);                                                             //deshabilita las interrupciones
  24.         puerto_1 = port_b & 0b11110000;                                                 //lee portb4:7 y lo guarda en puerto_1
  25.         if(puerto_1!=0)                                                                                 //si se presionó una tecla (flanco hacia arriba)
  26.         {
  27.                 output_b(0x00);                                                                         //aclaro el puerto b
  28.                 for(i=0;i<=3;i++)                                                                       //ciclo para saber cuál fila se presionó
  29.                 {
  30.                         bit_set(port_b,i);                                                              //pongo un pin de portb0:3 en 1
  31.                         puerto_2 = port_b & 0b11110000;                                 //leo los pines 4:7 de portb
  32.                         if(puerto_2!=0)fila=i;                                                  //si alguno esta en 1 es porque ese pin corresponde a la fila
  33.                 }
  34.                 for(i=4;i<=7;i++) if(bit_test(puerto_1,i))columna=i-4;  //para saber qué columna se presionó
  35.         }
  36.         flag=1;
  37.         set_tris_b(0xf0);
  38.         output_b(0x0f);
  39.         clear_interrupt(INT_RB);
  40.         enable_interrupts(INT_RB);
  41. }
  42.  
  43. void main()
  44. {
  45.         output_a(0x00);
  46.         output_b(0x0f);
  47.         set_tris_b(0xf0);
  48.         enable_interrupts(INT_RB);
  49.         enable_interrupts(GLOBAL);
  50.         while(TRUE)
  51.         {
  52.                 if(flag==1)
  53.                 {
  54.                         printf("Columna: %i\n\r",columna);
  55.                         printf("Fila: %i\n\r",fila);
  56.                         flag=0;
  57.                 }
  58.         }
  59. }


El archivo de proteus donde están las conexiones está en el otro post...
Nos leemos!  :mrgreen:

Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: AngelGris en 12 de Noviembre de 2010, 22:01:49
Acá te dejo un programa hecho en Hitech pero con algunos "trucos" para que se parezca a CCS. Hay que acomodar varias cosas y otras no. El Código es muy básico y muy malo, funciona pero es muy mejorable. Sólo que preferí dejarlo así para que sea más fácil su entendimiento

Código: C
  1. #include <htc.h>
  2.  
  3. __CONFIG (LVPDIS & WDTDIS);
  4.  
  5. #include "Def16f87xa.h"                 // algunas definiciones propias para esta familia de PICs
  6. #define PIC_CLK 20000000                // defino la velocidad de trabajo
  7. #include "delayhd.h"                    // rutinas de retardo
  8.  
  9. #define set_tris_b(x)   TRISB=x
  10. #define output_b(x)             PORTB=x
  11. #define set_tris_a(x)   TRISA=x
  12. #define output_a(x)             PORTA=x
  13.  
  14. /************************************************************************************************
  15. Todos esos include y define son para poder trabajar con el pic, estoy usando el compilador HiTech
  16. pero tratando de dejar el codigo lo mas parecido posible a CCS
  17.  
  18. Hay que adaptar la cabecera y parte del programa para que trabaje correctamente con CCS
  19.  
  20. Tambien la linea __CONFIG (xxxx) hay que cambiarla por el tipo soportado por CCS
  21. **************************************************************************************************/
  22.  
  23.  
  24.  
  25. unsigned char flag_teclado = 0; // variable para saber si se presiono una tecla
  26.  
  27.  
  28. /*****************************************
  29.   Rutina de delay de aproximadamente 10mS
  30. para usar como anti-rebote
  31. ******************************************/
  32. void AntiRebote (void)
  33. {
  34.   unsigned char tiempo;
  35.  
  36.   for (tiempo = 40; tiempo > 0; tiempo--)
  37.   {
  38.     DelayUs (250);
  39.   }
  40. }
  41.  
  42. /****************************************************************
  43.  Esta es la rutina de atencion de interrupcion que permite Hitech
  44. hay que cambiarla y adaptarla al formato de CCS
  45. ******************************************************************/
  46. void interrupt isr (void)
  47. {
  48.   unsigned char temporal;
  49.  
  50.   temporal = PORTB & 0xF0;
  51.   if (temporal != 0) flag_teclado = 1;  // si hay tecla pulsada activo el flag
  52.  
  53.   temporal = PORTB;             // leo el puerto B para que ya no exista condicion de cambio
  54.   RBIF = 0;                             // borro el flag de cambio de RB. (Adaptar a CCS)
  55.  
  56. /*
  57.   No deshabilito ni vuelvo a habilitar las interrupciones por que
  58. de ello ya se encarga el compilador. Adaptar a CCS si es necesario
  59. */
  60.  
  61. }
  62.  
  63. /************************************************
  64.  Esta es la rutina que devuelve la tecla pulsada
  65. Los valores devueltos van de 1 a 16
  66. *************************************************/
  67. unsigned char captura(void)
  68. {
  69.   unsigned char lectura;
  70.  
  71.   output_b (0b00000001);                // activo la primer fila
  72.   lectura = PORTB & 0xF0;               // leo el puerto B y hago una and porque solo me interesa el nibble alto
  73.   output_b (0x0F);                              // activo todas las salidas
  74.   if (lectura == 0b00010000) return 1;
  75.   if (lectura == 0b00100000) return 2;
  76.   if (lectura == 0b01000000) return 3;
  77.   if (lectura == 0b10000000) return 4;
  78.   output_b (0b00000010);                // activo la segunda fila
  79.   lectura = PORTB & 0xF0;               // leo el puerto B y hago una and porque solo me interesa el nibble alto
  80.   output_b (0x0F);                              // activo todas las salidas
  81.   if (lectura == 0b00010000) return 5;
  82.   if (lectura == 0b00100000) return 6;
  83.   if (lectura == 0b01000000) return 7;
  84.   if (lectura == 0b10000000) return 8;
  85.  
  86.   output_b (0b00000100);                // activo la tercer fila
  87.   lectura = PORTB & 0xF0;               // leo el puerto B y hago una and porque solo me interesa el nibble alto
  88.   output_b (0x0F);                              // activo todas las salidas
  89.   if (lectura == 0b00010000) return 9;
  90.   if (lectura == 0b00100000) return 10;
  91.   if (lectura == 0b01000000) return 11;
  92.   if (lectura == 0b10000000) return 12;
  93.   output_b (0b00001000);                // activo la cuarta fila
  94.   lectura = PORTB & 0xF0;               // leo el puerto B y hago una and porque solo me interesa el nibble alto
  95.   output_b (0x0F);                              // activo todas las salidas
  96.   if (lectura == 0b00010000) return 13;
  97.   if (lectura == 0b00100000) return 14;
  98.   if (lectura == 0b01000000) return 15;
  99.   if (lectura == 0b10000000) return 16;
  100.  
  101.   return 0;
  102. }
  103.  
  104.  
  105. void main (void)
  106. {
  107.   unsigned char lectura_temporal;
  108.   unsigned char tecla_pulsada;
  109.  
  110.  
  111.   setup_adc (ADC_OFF);
  112.   setup_comparator (NC_NC_NC_NC);
  113.   set_tris_a (0);                                       // Puerto A como salida
  114.   output_a (0);                                         // todo en 0
  115.   set_tris_b (0b11110000);                      // Nibble alto como entrada, nibble bajo como salida
  116.   output_b (0x0F);                                      // Todas las salidas en 1
  117.  
  118.   RBIF = 0;                                                     // borro el flag que indica cambio en RB4..RB7
  119.  
  120. /*
  121.  Creo que en CCS se usa clear_interrupt (INT_RB)
  122. */
  123.  
  124.   enable_interrupt (INT_RB);            // habilito interrupcion por cambio
  125.   enable_interrupt (GLOBAL);            // habilito todas las interrupciones
  126.   while (1)
  127.   {
  128.     if (flag_teclado == 1)                      // si se presiono alguna tecla...
  129.     {
  130.       disable_interrupt (INT_RB);
  131.       AntiRebote();                                     // Aca se podria usar alguna funcion de delay de CCS
  132.       if (PORTB != 0)                           // si sigue presionada alguna tecla....
  133.       {
  134.         tecla_pulsada = captura();      // guardo en una variable la tecla pulsada
  135.         output_a (tecla_pulsada);       // la muestro en formato binario por el puerto A
  136.       }
  137.       flag_teclado = 0;                         // borro para avisar que ya procese la tecla
  138.       lectura_temporal = PORTB;         // leo el puerto B para que ya no exista condicion de cambio
  139.       RBIF = 0;                                         // borro el flag de cambio;
  140.       enable_interrupt (INT_RB);
  141.     }
  142.   }
  143. }
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 12 de Noviembre de 2010, 22:10:19
Gracias por el código AngelGris, está muy ordenado y sencillo, me gusta!  :-/
Ahora bien, podrías colocar el diagrama del circuito que usas para ese código por favor?
De antemano muy agradecido! Saludos!  :mrgreen:
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: AngelGris en 12 de Noviembre de 2010, 23:52:41
Usé el diagrama que vos subiste. Y el teclado lo tomé de la siguiente manera

  1    2   3    4
  5    6   7    8
  9  10  11  12
13  14  15  16
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 15 de Noviembre de 2010, 10:54:41
Perfecto AngelGris, muchas gracias!
Dios mediante mañana me pongo a probar el código que me mandaste.
Que estés bien! Nos leemos!  :mrgreen:
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: MLO__ en 15 de Noviembre de 2010, 13:58:17
 :-/ :-/

Que bueno leerte de nuevo Fire!!!!

 :-/ :-/
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 15 de Noviembre de 2010, 22:14:04
Qué tal!! Pues listo, listo!  :-/  :-/  :-/
Código funcionando... introduje el código de AngelGris (la función "captura") en la parte de la rutina de interrupción que yo tenía y funcionó de lujo!!  :)
Creo que todavía se puede optimizar un poquito más el código, pero sólo es cuestión de "cursilería", pues este funciona perfecto (por lo menos en proteus, habría que probarlo en vivo a ver qué tal se comporta)...
Por ahora aquí está el código en CCS funcionando:

Código: C
  1. ///////////////////////////////////////////////
  2. //             lee un teclado 4x4                //
  3. //   y envia al pc por puerto serial         //
  4. ///////////////////////////////////////////////
  5.  
  6. #include <16f876.h>
  7. #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  8. #define Tx PIN_C6
  9. #define Rx PIN_C7
  10. #use delay (CLOCK=20000000)
  11. #use rs232 (BAUD=19200,XMIT=Tx,RCV=Rx)
  12. #use fast_io(A)
  13. #use fast_io(B)
  14. #byte port_b = 0x06
  15. #byte tris_b = 0xff
  16. boolean flag;
  17. int fila,columna,tecla;
  18.  
  19. /************************************************
  20. Esta es la rutina que devuelve la tecla pulsada
  21. Los valores devueltos van de 1 a 16
  22. [Esta rutina es cortesía de AngelGris, muchas gracias compañero!]
  23. *************************************************/
  24. unsigned char captura(void)
  25. {
  26.  unsigned char lectura;
  27.  output_b (0b00000001); // activo la primer fila
  28.  lectura = port_b & 0xF0; // leo el puerto B y hago una and porque solo me interesa el nibble alto
  29.  output_b (0x0F); // activo todas las salidas
  30.  if (lectura == 0b00010000) return 1;
  31.  if (lectura == 0b00100000) return 2;
  32.  if (lectura == 0b01000000) return 3;
  33.  if (lectura == 0b10000000) return 4;
  34. output_b (0b00000010); // activo la segunda fila
  35. lectura = port_b & 0xF0; // leo el puerto B y hago una and porque solo me interesa el nibble alto
  36. output_b (0x0F); // activo todas las salidas
  37. if (lectura == 0b00010000) return 5;
  38. if (lectura == 0b00100000) return 6;
  39. if (lectura == 0b01000000) return 7;
  40. if (lectura == 0b10000000) return 8;
  41. output_b (0b00000100); // activo la tercer fila
  42. lectura = port_b & 0xF0; // leo el puerto B y hago una and porque solo me interesa el nibble alto
  43. output_b (0x0F); // activo todas las salidas
  44. if (lectura == 0b00010000) return 9;
  45. if (lectura == 0b00100000) return 10;
  46. if (lectura == 0b01000000) return 11;
  47. if (lectura == 0b10000000) return 12;
  48. output_b (0b00001000); // activo la cuarta fila
  49. lectura = port_b & 0xF0; // leo el puerto B y hago una and porque solo me interesa el nibble alto
  50. output_b (0x0F); // activo todas las salidas
  51. if (lectura == 0b00010000) return 13;
  52. if (lectura == 0b00100000) return 14;
  53. if (lectura == 0b01000000) return 15;
  54. if (lectura == 0b10000000) return 16;
  55. return 0;
  56. }
  57.  
  58. #INT_RB
  59. void tecla_presionada()
  60. {
  61.         int i,puerto_1,puerto_2;
  62.         disable_interrupts(INT_RB);                                                             //deshabilita las interrupciones
  63.         tecla=captura();
  64.         flag=1;
  65.         set_tris_b(0xf0);
  66.         output_b(0x0f);
  67.         clear_interrupt(INT_RB);
  68.         enable_interrupts(INT_RB);
  69. }
  70.  
  71. void main()
  72. {
  73.         output_a(0x00);
  74.         output_b(0x0f);
  75.         set_tris_b(0xf0);
  76.         enable_interrupts(INT_RB);
  77.         enable_interrupts(GLOBAL);
  78.         while(TRUE)
  79.         {
  80.                 if(flag==1)
  81.                 {
  82.                         printf("Tecla presionada: %i\n\r",tecla);
  83.                         flag=0;
  84.                 }
  85.         }
  86. }

Ok saludos a todos, nos leemos!  :mrgreen:
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: AngelGris en 16 de Noviembre de 2010, 09:05:01
Hola FirePic

  Sería conveniente que antes de "leer la tecla", es decir, antes de ejecutar la función captura pongas un delay de unos 10mS (en mi ejemplo lo había llamado Antirrebote) porque en muchas ocasiones la teclas generan ( "rebote"  ) falsos presionados.
  También sería conveniente hacer primero una lectura del puerto, luego el delay (10mS) y otra vez una lectura, entonces si ambas lecturas son iguales (y distinto de 0 ) es porque realmente tenés presionada una tecla, y ahí si activás el flag y ejecutás la función captura. Si la lectura da 0, quiere decir que no hay tecla presionada.

  En mi ejemplo activo directamente el flag (en la rutina de itnerrupción), pero luego en el bucle principal sólo ejecuto captura si al hacer 2 lecturas consecutivas (con el AntiRebote de por medio) en el puerto tengo el mismo valor.

 
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 16 de Noviembre de 2010, 12:10:53
Qué tal!
Bueno ahora creo que sí ya listo!  :-/

Agregué lo que me dices AngelGris, gracias por tus sugerencias! También acomodé un poco más  a mi gusto el código de rastrear la tecla...  :-)
En proteus funciona correctamente, ahí se los dejo:

Código: C
  1. ///////////////////////////////////////////////
  2. //             lee un teclado 4x4                //
  3. //   y envia al pc por puerto serial         //
  4. ///////////////////////////////////////////////
  5.  
  6. #include <16f876.h>
  7. #fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  8. #define Tx PIN_C6
  9. #define Rx PIN_C7
  10. #use delay (CLOCK=20000000)
  11. #use rs232 (BAUD=19200,XMIT=Tx,RCV=Rx)
  12. #use fast_io(A)
  13. #use fast_io(B)
  14. #byte port_b = 0x06
  15. #byte tris_b = 0xff
  16. boolean flag_teclado;
  17. int tecla,fila,columna;
  18.  
  19. /********************************
  20. Esta Rutina permite rastrear el teclado
  21. y devuelve el valor de la tecla que se
  22. ha presionado
  23. ************************************/
  24. int captura(void)
  25. {
  26.         int const teclado[4][4] = {{1,2,3,4},
  27.                                             {5,6,7,8},
  28.                                             {9,10,11,12},
  29.                                             {13,14,15,16}};
  30.         int tecla,lectura,i;
  31.         for(i=0;i<4;i++)
  32.         {
  33.                 output_b(0);
  34.                 bit_set(port_b,i);
  35.                 lectura = port_b & 0xf0;
  36.                 switch(lectura)
  37.                 {
  38.                         case 0b00010000: columna=0;
  39.                                                   fila=i;      
  40.                                                   break;       
  41.                         case 0b00100000: columna=1;
  42.                                                   fila=i;      
  43.                                                   break;
  44.                         case 0b01000000: columna=2;
  45.                                                   fila=i;      
  46.                                                   break;
  47.                         case 0b10000000: columna=3;
  48.                                                   fila=i;      
  49.                                                   break;
  50.                 }
  51.         }
  52.         tecla = teclado[fila][columna];
  53.         return(tecla);
  54. }
  55.  
  56. /***************************************
  57. Rutina de Interrupci&#243;n.
  58. - Antirebote.
  59. - Llama a rutina "captura" para saber
  60.    la tecla presionada.
  61. - Activa la bandera "flag_teclado"
  62.    a usar en el main o en otra parte
  63.    del programa.
  64. ***************************************/
  65. #INT_RB
  66. void tecla_presionada()
  67. {
  68.         int lectura_1,lectura_2;
  69.         lectura_1 = port_b & 0b11110000;                //lee portb4:7 y lo guarda en lectura_1
  70.         delay_ms(10);                                   //Funci&#243;n AntiRebotes:   - Espero 10ms.
  71.         lectura_2 = port_b & 0b11110000;                //                               - Vuelvo a leer el puerto.
  72.         if(lectura_1==lectura_2 && lectura_1!=0) //                               - Si el valor es igual y distinto de 0
  73.         {                                                       //                                  es porque en realidad se presion&#243; una tecla.
  74.                 tecla = captura();
  75.                 flag_teclado=1;
  76.         }
  77.         set_tris_b(0xf0);
  78.         output_b(0x0f);
  79.         clear_interrupt(INT_RB);
  80. }
  81.  
  82. void main()
  83. {
  84.         set_tris_b(0xf0);
  85.         enable_interrupts(INT_RB);
  86.         enable_interrupts(GLOBAL);
  87.         while(TRUE)
  88.         {
  89.                 if(flag_teclado==1)
  90.                 {
  91.                         printf("Tecla presionada: %i\n\r",tecla);
  92.                         flag_teclado=0;
  93.                 }
  94.         }
  95. }

Quiero dejarlo como una librería para futuros usos, por eso preferí dejar el antirebote y todo lo demás en la misma rutina de interrupción en lugar de en el main. También tomé la idea original de redpic de usar una constante para definir las teclas del teclado, así como también lo estaba haciendo diploko... por cierto, qué será de diploko, que dió origen al hilo??  :?  :shock:

Bueno cualquier sugerencia para pulir más el código es bienvenida!
Y pues como siempre digo, nos leemos!  :mrgreen:
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: Diploko en 16 de Noviembre de 2010, 16:15:50
Hola! aquí estoy!,
Gracias a los 2 por seguir interesados en la lectura del teclado mediante interrupción y no escribía nada porque no tenía nada más válido que lo existente para aportar a la conversación pero no lo he dejado de lado el asunto ni mucho menos... no os librareis de mí tan facilmente jeje.

No he probado tu programa en Proteus porque no lo tengo ni instalado... (lo tengo anotado como tarea pdte).
Donde sí acabo de probar este último código que has puesto es en una "protoboard" y siento decirlo pero no funciona. Del cableado no es porque con el código inicial que puse sí funciona, pero claro, sin interrupción...
Hay un par de detalles que he corregido en tu código porque creo que hacen falta:
- habilitar las resistencias pull-ups en el port_b
- cambiar la configuración del tris_b no es 0xff si no 0x86 tal y como indica el datasheet.
Pero con estos y otros cambios sigue sin funcionar  :?.

El programa que estoy casi acabando manejo entradas y salidas de pulsos, analógicas, 6 dispositivos en I2C... hay cosas que me cuestan pero gracias al las conversaciones existentes de este foro voy avanzando sin problemas excepto con esto de la interrupción del teclado  :x. Este programa tiene que funcionar si o si y si no lo consigo (en breve) mediante interrupción acabaré haciendo la gran chapuza de poner otro pic solo para el teclado y que éste genere una interrupción externa al pic principal controlando tb la detección de "tecla mantenida" para acelerar los cambios de parámetros. Esto ya lo he probado y vá como un fuego! pero desde luego es una chapuza que hasta me da verguenza comentarla  :oops:...

Ánimo lo conseguiremos! A ver si puedes hacer el pequeño montaje en una protoboard y lo compruebas y si hay alguien que tenga ya solucionado y probado este problema (con un PIC y en CCS) que se apiade de nosotros!

Salu2!

Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 16 de Noviembre de 2010, 17:01:54
Qué bueno saber que estás ahí diploko!  :)

Lamentablemente tenía tiempo alejado de los pics y ahorita no tengo ni micro ni teclado para probar...
A mí cuando me funcionan las cosas en proteus generalmente me funcionan en físico salvo que falten algunos detalles que proteus no toma en cuenta, como los fuses y ese tipo de cosas...

Te sugiero que añadas al programa en la rutina de interrupción unas líneas que prendan y apaguen un led, eso para saber si el micro está ejecutando la interrupción... eso tiene que funcionar, yo he probado antes esa interrupción en RB con CCS y me ha funcionado perfecto... cuando te funcione lo de la interrupción pues lo demás debería funcionar automáticamente...

Por cierto, qué circuito estás usando? Porque si no tienes el proteus instalado entonces no pudiste ver el diagrama que te coloqué...
Ahí te lo adjunto en imagen...

Lo del trisb si fue una burrada de error  :D ... pero en todo caso no afectaría porque si te fijas bien estoy usando la instrucción set_tris_b del ccs.

Recuerda que al programa que te mandé tienes que cambiarle los fuses, yo le puse 20MHz, y tú estás trabajando con un cristal de 4MHz...
A ver si AngelGris u otra persona si puede probarlo en físico y nos echa una mano...

Ok nos leemos!  :mrgreen:
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: Diploko en 16 de Noviembre de 2010, 18:04:16
Hola firepic!
Pues la verdad es que daba por supuesto que tendríamos el mismo esquema.... la diferencia es que yo no estoy usando resistencias externas, uso las pull-up internas del pic que por cierto éstas creo que estan conectadas a + en vez de a gnd.
Pero tanto dá, sigue sin funcionar de una forma u otra hace cosas sin sentido, con tus resistencias entra en interrupción constantemente y solo reacciona a las 2 filas de abajo y con las pull-up solo entra en interrupción cuando pulsas una tecla de las 2 filas de abajo y el printf responde con la tecla "14" siempre....

Este es tu código con el pic que tengo ahora montado 16F873:

Código: C
  1. ///////////////////////////////////////////////
  2. //             lee un teclado 4x4                //
  3. //   y envia al pc por puerto serial         //
  4. ///////////////////////////////////////////////
  5.  
  6. #include <16f873.h>
  7. #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  8. #define Tx PIN_C6
  9. #define Rx PIN_C7
  10. #use delay (CLOCK=4000000)
  11. #use rs232 (BAUD=19200,XMIT=Tx,RCV=Rx,bits=8)
  12. #use fast_io(A)
  13. #use fast_io(B)
  14.  
  15. #byte port_b=0x06      
  16. #byte tris_b=0x86      
  17. #byte port_c=0x07      
  18. #byte tris_c=0x87      
  19.  
  20.  
  21. boolean flag_teclado;
  22. int tecla,fila,columna;
  23.  
  24. /********************************
  25. Esta Rutina permite rastrear el teclado
  26. y devuelve el valor de la tecla que se
  27. ha presionado
  28. ************************************/
  29. int captura(void)
  30. {
  31.         int const teclado[4][4] = {     {1,2,3,4},
  32.                                                                 {5,6,7,8},
  33.                                                                 {9,10,11,12},
  34.                                                                 {13,14,15,16}   };
  35.         int tecla,lectura,i;
  36.  
  37.         for(i=0;i<4;i++)
  38.         {
  39.                 output_b(0);
  40.                 bit_set(port_b,i);
  41.                 lectura = port_b & 0xf0;
  42.                 switch(lectura)
  43.                 {
  44.                         case 0b00010000: columna=0;
  45.                         fila=i;
  46.                         break; 
  47.                         case 0b00100000: columna=1;
  48.                         fila=i;
  49.                         break;
  50.                         case 0b01000000: columna=2;
  51.                         fila=i;
  52.                         break;
  53.                         case 0b10000000: columna=3;
  54.                         fila=i;
  55.                         break;
  56.                         }
  57.                 }
  58.                 tecla = teclado[fila][columna];
  59.                 return(tecla);
  60. }
  61.  
  62. /***************************************
  63. Rutina de Interrupción.
  64. - Antirebote.
  65. - Llama a rutina "captura" para saber la tecla presionada.
  66. - Activa la bandera "flag_teclado" a usar en el main o en otra parte del programa.
  67. ***************************************/
  68.  
  69. #INT_RB
  70. void tecla_presionada()
  71. {
  72.         // Para comptrobar que entra en la interrupcion
  73.         output_bit(PIN_C0,1);
  74.        
  75.         int lectura_1,lectura_2;
  76.        
  77.         lectura_1 = port_b & 0b11110000;                        // Lee portb4:7 y lo guarda en lectura_1
  78.         delay_ms(10);                                                           // AntiRebotes: Espero 10ms.
  79.         lectura_2 = port_b & 0b11110000;                        // Vuelvo a leer el puerto.
  80.        
  81.         if(lectura_1==lectura_2 && lectura_1!=0)        // Si el valor es igual y distinto de 0
  82.         {                                                                                       // es porque en realidad se presiona una tecla.
  83.                 tecla = captura();
  84.                 flag_teclado=1;
  85.         }
  86.        
  87.         set_tris_b(0xf0);
  88.         output_b(0x0f);
  89.         clear_interrupt(INT_RB);       
  90. }
  91.  
  92. void main()
  93. {
  94.         printf("Inicio main\n");
  95.        
  96.         set_tris_b(0xF0);              
  97.         set_tris_c(0x00);                      
  98.        
  99.         port_b=0;
  100.         port_c=0;
  101.        
  102.         port_b_pullups(true);
  103.        
  104.         enable_interrupts(INT_RB);
  105.         enable_interrupts(GLOBAL);
  106.        
  107.         printf("Inicio bucle\n");
  108.        
  109.         while(TRUE)
  110.         {
  111.                 if(flag_teclado==1)
  112.                 {
  113.                         printf("Tecla presionada: %i\n\r",tecla);
  114.                         flag_teclado=0;
  115.                 }
  116.                
  117.                 delay_ms(500);                          // Para que me dé tiempo a ver el led activado
  118.                 output_bit(PIN_C0,0);           // Desactivo led
  119.                
  120.         }
  121. }

Si este código te funciona en Proteus se me quitan las ganas de instalarlo jeje  ;-).

Gracias y salu2!
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: AngelGris en 16 de Noviembre de 2010, 19:27:39
Hola! aquí estoy!,
Gracias a los 2 por seguir interesados en la lectura del teclado mediante interrupción y no escribía nada porque no tenía nada más válido que lo existente para aportar a la conversación pero no lo he dejado de lado el asunto ni mucho menos... no os librareis de mí tan facilmente jeje.

..........

- habilitar las resistencias pull-ups en el port_b
- cambiar la configuración del tris_b no es 0xff si no 0x86 tal y como indica el datasheet.
Pero con estos y otros cambios sigue sin funcionar  :?.

............


  Para el programa que hizo FirePic, el tris tiene que estar configurado como él lo muestra (0xF0). Y con respecto a las resistencias del pull-up no son necesarias ya que es el nibble bajo el que va a generar el estado alto en las distintas salidas. Y sí son necesarias las resistencias de pull-down para asegurar que cuando ninguna tecla esté presionada haya un estado bajo en todos los pines del nibble alto del puerto B.

  En el main, antes del whle, es conveniente hacer "1" todas las salidas del nibble bajo del puerto B.
Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: firepic en 17 de Noviembre de 2010, 15:14:34
Diploko prueba más bien haciendo un "toggle" en la interrupción, de esa manera podrás saber realmente cuándo entra o no a la interrupción... encendiendo en al rutina de interrupción y apagando en el while no lo veo muy bueno...

Código: C
  1. ///////////////////////////////////////////////
  2. //             lee un teclado 4x4                //
  3. //   y envia al pc por puerto serial         //
  4. ///////////////////////////////////////////////
  5.  
  6. #include <16f873.h>
  7. #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
  8. #define Tx PIN_C6
  9. #define Rx PIN_C7
  10. #use delay (CLOCK=4000000)
  11. #use rs232 (BAUD=19200,XMIT=Tx,RCV=Rx,bits=8)
  12. #use fast_io(A)
  13. #use fast_io(B)
  14.  
  15. #byte port_b=0x06      
  16. #byte tris_b=0x86      
  17. #byte port_c=0x07      
  18. #byte tris_c=0x87      
  19.  
  20.  
  21. boolean flag_teclado;
  22. int tecla,fila,columna;
  23.  
  24. /********************************
  25. Esta Rutina permite rastrear el teclado
  26. y devuelve el valor de la tecla que se
  27. ha presionado
  28. ************************************/
  29. int captura(void)
  30. {
  31.         int const teclado[4][4] = {     {1,2,3,4},
  32.                                                                 {5,6,7,8},
  33.                                                                 {9,10,11,12},
  34.                                                                 {13,14,15,16}   };
  35.         int tecla,lectura,i;
  36.  
  37.         for(i=0;i<4;i++)
  38.         {
  39.                 output_b(0);
  40.                 bit_set(port_b,i);
  41.                 lectura = port_b & 0xf0;
  42.                 switch(lectura)
  43.                 {
  44.                         case 0b00010000: columna=0;
  45.                         fila=i;
  46.                         break; 
  47.                         case 0b00100000: columna=1;
  48.                         fila=i;
  49.                         break;
  50.                         case 0b01000000: columna=2;
  51.                         fila=i;
  52.                         break;
  53.                         case 0b10000000: columna=3;
  54.                         fila=i;
  55.                         break;
  56.                         }
  57.                 }
  58.                 tecla = teclado[fila][columna];
  59.                 return(tecla);
  60. }
  61.  
  62. /***************************************
  63. Rutina de Interrupción.
  64. - Antirebote.
  65. - Llama a rutina "captura" para saber la tecla presionada.
  66. - Activa la bandera "flag_teclado" a usar en el main o en otra parte del programa.
  67. ***************************************/
  68.  
  69. #INT_RB
  70. void tecla_presionada()
  71. {
  72.         int lectura_1,lectura_2;
  73.         lectura_1 = port_b & 0b11110000;                        // Lee portb4:7 y lo guarda en lectura_1
  74.         delay_ms(10);                                                           // AntiRebotes: Espero 10ms.
  75.         lectura_2 = port_b & 0b11110000;                        // Vuelvo a leer el puerto.
  76.         if(lectura_1==lectura_2 && lectura_1!=0)        // Si el valor es igual y distinto de 0
  77.         {                                                                                       // es porque en realidad se presiona una tecla.
  78.                 tecla = captura();
  79.                 // Para comptrobar que entra en la interrupcion
  80.                 output_toggle(PIN_C0);
  81.                 flag_teclado=1;
  82.         }
  83.        
  84.         set_tris_b(0xf0);
  85.         output_b(0x0f);
  86.         clear_interrupt(INT_RB);       
  87. }
  88.  
  89. void main()
  90. {
  91.         printf("Inicio main\n");
  92.         set_tris_b(0b11110000); //nible alto entradas, nible bajo salidas.             
  93.         set_tris_c(0b10000000); //el bit 7 es recepción (Rx)                  
  94.         port_b_pullups(false); //no se usarán las pullups, usa las resistencias de 1k o 10k a GND.
  95.         port_b=0x0f; //ESENCIAL: coloca el nible bajo del puerto b a 1, para que pueda monitorear todas las filas del teclado.
  96.         port_c=0;      
  97.         enable_interrupts(INT_RB);
  98.         enable_interrupts(GLOBAL);
  99.         printf("Inicio bucle\n");
  100.         while(TRUE)
  101.         {
  102.                 if(flag_teclado==1)
  103.                 {
  104.                         printf("Tecla presionada: %i\n\r",tecla);
  105.                         flag_teclado=0;
  106.                 }
  107.                
  108.         }
  109. }

Bueno compañero sigue probando, no te desanimes que lo lograrás!!  :wink:
Generalmente para que algo nuevo te funcione con los pics tienes que grabar y probar no menos de unas cuantas decenas de veces!  :D

Ánimo y no dejes de publicar tus resultados! Nos leemos!  :mrgreen:

Título: Re: Problema con teclado e Interrupcion RB en CCS y 16F877
Publicado por: AngelGris en 17 de Noviembre de 2010, 16:02:56
Les cuento, hice las pruebas físicas sobre un 16f628A porque no tengo otro. Con el primer programa que subí funcionó bien, luego tomé el de FirePic y lo adapté a HiTech, lo probé y también me funcionó bien.

Por las dudas aquí les dejo el código tal cual lo grabé al pic.

Código: C
  1. #include <htc.h>
  2.  
  3. __CONFIG (LVPDIS & WDTDIS & MCLRDIS & INTIO);
  4.  
  5. #include "Def16f62xa.h"                 // algunas definiciones propias para esta familia de PICs
  6. #define PIC_CLK 4000000         // defino la velocidad de trabajo
  7. #include "delayhd.h"                    // rutinas de retardo
  8.  
  9. #define set_tris_b(x)   TRISB=x
  10. #define output_b(x)             PORTB=x
  11. #define set_tris_a(x)   TRISA=x
  12. #define output_a(x)             PORTA=x
  13.  
  14.  
  15. /************************************************************************************************
  16. Todos esos include y define son para poder trabajar con el pic, estoy usando el compilador HiTech
  17. pero tratando de dejar el código lo más parecido posible a CCS
  18.  
  19. Hay que adaptar la cabecera y parte del programa para que trabaje correctamente con CCS
  20.  
  21. También la línea __CONFIG (xxxx) hay que cambiarla por el tipo soportado por CCS
  22. **************************************************************************************************/
  23.  
  24.  
  25.  
  26. unsigned char flag_teclado = 0; // variable para saber si se presionó una tecla
  27. unsigned char tecla_pulsada;
  28.  
  29. /*****************************************
  30.   Rutina de delay de aproximadamente 10mS
  31. para usar como anti-rebote
  32. ******************************************/
  33. void AntiRebote (void)
  34. {
  35.   unsigned char tiempo;
  36.  
  37.   for (tiempo = 40; tiempo > 0; tiempo--)
  38.   {
  39.     DelayUs (250);
  40.   }
  41. }
  42.  
  43. /************************************************
  44.  Esta es la rutina que devuelve la tecla pulsada
  45. Los valores devueltos van de 1 a 16
  46. *************************************************/
  47. unsigned char captura(void)
  48. {
  49.   unsigned char teclado[4][4] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
  50.   int tecla,lectura,i;
  51.   unsigned char fila, columna;
  52.  
  53.   for(i=0;i<4;i++)
  54.   {
  55.     output_b(0);
  56.  
  57. //    bit_set(port_b,i);
  58.  
  59.     PORTB = (1 << i);                   // utilizo esto en lugar de bit_set, porque Hitech no tiene dicha funcion
  60.     lectura = PORTB & 0xf0;
  61.     switch(lectura)
  62.     {
  63.       case 0b00010000: columna=0;
  64.                        fila = i;
  65.                        break;
  66.       case 0b00100000: columna=1;
  67.                        fila = i;
  68.                        break;
  69.       case 0b01000000: columna=2;
  70.                        fila = i;
  71.                        break;
  72.       case 0b10000000: columna=3;
  73.                        fila = i;
  74.                        break;
  75.     }
  76.   }
  77.   tecla = teclado[fila][columna];
  78.   return(tecla);
  79. }
  80.  
  81.  
  82. /****************************************************************
  83.  Esta es la rutina de atención de interrupción que permite Hitech
  84. hay que cambiarla y adaptarla al formato de CCS
  85. ******************************************************************/
  86. void interrupt isr (void)
  87. {
  88.   unsigned char temporal;
  89.  
  90.   temporal = PORTB & 0xF0;
  91.   if (temporal != 0)
  92.   {
  93.     AntiRebote();
  94.         temporal = PORTB & 0xF0;
  95.     if (temporal != 0)
  96.         {
  97.           flag_teclado = 1;  // si hay tecla pulsada activo el flag
  98.       tecla_pulsada = captura();
  99.     }
  100.   }
  101.   PORTB = 0x0F;                 // todo el nibble bajo del puerto B en "1"
  102.   temporal = PORTB;             // leo el puerto B para que ya no exista condición de cambio
  103.   RBIF = 0;                             // borro el flag de cambio de RB. (Adaptar a CCS)
  104.  
  105. /*
  106.   No deshabilito ni vuelvo a habilitar las interrupciones por que
  107. de ello ya se encarga el compilador. Adaptar a CCS si es necesario
  108. */
  109.  
  110. }
  111.  
  112.  
  113. void main (void)
  114. {
  115.   //setup_adc (ADC_OFF);
  116.   setup_comparator (NC_NC_NC_NC);
  117.   set_tris_a (0);                                       // Puerto A como salida
  118.   output_a (0);                                         // todo en 0
  119.   set_tris_b (0b11110000);                      // Nibble alto como entrada, nibble bajo como salida
  120.   output_b (0x0F);                                      // Todas las salidas en 1
  121.   RBIF = 0;                                                     // borro el flag que indica cambio en RB4..RB7
  122. /*
  123.  Creo que en CCS se usa clear_interrupt (INT_RB)
  124. */
  125.   enable_interrupt (INT_RB);            // habilito interrupción por cambio
  126.   enable_interrupt (GLOBAL);            // habilito todas las interrupciones
  127.   while (1)
  128.   {
  129.     if (flag_teclado == 1)                      // si se presionó alguna tecla...
  130.     {
  131.       output_a (tecla_pulsada); // la muestro en formato binario por el puerto A
  132.       flag_teclado = 0;
  133.     }
  134.   }
  135. }