PicManía by RedRaven
 

Búsqueda personalizada

 

PROYECTOS : TECLADO MATRICIAL 4x4
 con DRIVER ANALÓGICO

 

 

 

Teclado Matricial 4 x 4 con Driver Analógico

Primera Parte:
 

Objetivo: Leer un teclado matricial de 4 x 4 teclas mediante un único pin del PIC.

Conceptos involucrados: Suma de resistencias en serie, divisor de tensión y conversión Analógico-Digital del PIC.

Necesitamos: Un teclado matricial de 4 x 4 teclas, 9 resistencias y un PIC.

Antecedentes: En el documento "Hardware Techniques for PICmicro Microcontrollers" AN234 de Microchip se describe someramente lo que vamos a intenta realizar. De ahí he sacado la idea y a continuación os describiré lo que he desarrollado a partir de ella.

Desarrollo: Como todos sabéis, y si no lo sabéis este es un buen momento para aprenderlo, un teclado matricial 4 x 4 es un artilugio compuesto por 4 x 4 teclas con 4 + 4 líneas que conectan entre si las teclas, una línea por cada fila de teclas mas una línea por cada columna de teclas. Al ser pulsada una cualquiera de ellas une entre sí una de las líneas, la de su columna, con otra de ellas, la de su fila. Así al pulsar una tecla quedan unidas solo dos de las ocho que tiene.

Tradicionalmente se ha conectado un teclado de estos a un PIC usando 8 pines de éste, 4 para las filas y 4 para las columnas y se leían poniendo en alto las filas, o las columnas, y leyendo las columnas, o las filas, para detectar qué tecla se había pulsado. Esta técnica es muy fácil de implementar pero tiene el costo de usar muchos pines del PIC.

Lo que aquí vamos a desarrollar es la idea de poder hacer esto mismo pero haciendo uso de un solo pin del PIC, pero que tenga la especial función de Conversor Analógico a Digital. Para ello tenemos que conseguir que al pulsar cada una de las teclas obtengamos un voltaje distinto en una única línea. Leyendo este voltaje con el Conversor AD del PIC podemos llegar a saber qué tecla es la que se ha pulsado.

Una imagen vale mas que mil palabras:



Como veis en ella cada círculo en la rejilla central del teclado del dibujo representa una de las teclas, que al pulsar une una de las resistencias de R1 a R4 conectadas a VDD con otra de R5 a R8 conectadas al PIC. Así si pulsamos en la tecla situada en la esquina superior izquierda tendremos que VDD le llega al PIC tras atravesar R1+R5. Si por el contrario pulsamos la tecla inferior derecha la corriente nos llegará a través de la unión entre R4+R8. Siempre que pulsemos una tecla cualquiera obtendremos un voltaje de caída entre la suma de dos resistencias Rcolumna+Rfila

Otro detalle a tener en cuenta es que si no pulsamos ninguna tecla nuestro pin del PIC estaría conectado a nada, la línea que une el PIC con las resistencias R5 a R8 y tras ella el vacío. Esto podría, y sería con total seguridad, una verdadera antena que recogería todo lo que pasase cerca de allí, dándonos todo tipo de lecturas falsas mientras no pulsásemos ninguna tecla. Para evitar ese efecto colocamos R9 que mantendrá el pin del conversor conectado a GND mientras nos pulsemos nada sobre el teclado.

Pero esta configuración es lo que conocemos como un Divisor de Tensión en la que tenemos una resistencia conectada a VDD y otra a GND y nosotros tomamos el valor del voltaje en la unión que hay entre ellas.



Este divisor de tensión en el que tenemos un Vin o voltaje de entrada y un Vout o voltaje de salida tras él, que es perfectamente calculable mediante la fórmula que aparece a la derecha.
 
Como vemos en esta configuración lo que llamamos aquí Rtop es lo que en nuestro teclado hemos llamado Rcolumna+Rfila o sea la suma de las dos resistencias correspondientes al pulsar una tecla en él. Y Rbottom es nuestra R9 del teclado.

La gran falta del documento de Microchip es que no nos aporta ni valores de R1 a R9, ni comportamiento aproximado de cómo podríamos elegir dichos valores. Pero con lo que hemos visto hasta aquí estamos en condiciones de poder calcular con bastante precisión el comportamiento de nuestro circuito, sabiendo que Rtop es Rc+Rf y que VDD es 5V podemos concluir que Vout = R9 / R9+Rc+Rf * 5V y así tendremos un valor de Vout para cada pareja de resistencias Rc+Rf.

Con esta información me he construido una tabla Excel en la que he puesto primero la tabla de resistencias de columnas y filas y las distintas sumas de cada una de ellas. Después otra con los distintos voltajes que se generan en el divisor de tensión con cada una de las parejas anteriores. Y por último otra tabla en la que hago corresponder cada uno de estos voltajes con el valor de la conversión AD del PIC con precisión de 10 bits (1024 -> 5V lo que Vout es a X)

Jugando con las combinaciones entre valores de unas y otras resistencias he llegado a obtener uno valores que veo correctos.

Los resultados:


Nota1

Como podéis ver tenemos abajo los valores que vamos a obtener en la conversión AD para cada tecla pulsada. Son valores razonablemente separados unos de otros y que nos pueden permitir leer nuestro teclado con un único pin del PIC (con AD) que es lo que queríamos hacer.

Conclusión: R1=0, R2=470R, R3=1K, R4=2K2, R5=220R, R6=330R, R7=470R, R8=560R y R9=1K2 con VDD a 5V Nota2.

Y con esto completamos el documento de Microchip poniéndole valores a lo propuesto por los amables señores de nuestro proveedor favorito.


Nota1 teclado_resistivo_cad.xls
Nota2 Todas las resistencias son Comerciales

Segunda Parte:
 
 



Bueno ... tras unas cuantas horas perdidas debido a que el cable negro, el que tira a masa la resistencia R9, no hacía buen contacto y por consiguiente no había divisor de tensión ni nada que se le parezca, lo he solucionado y ya funciona.

He implementado una forma de leer que intenta minimizar los efectos aleatorios, y perversos, de las interferencias, transitorios y otras zarandajas.

Simplemente lo que hago es acumular n lecturas consecutivas y después calcular la media de todas ellas. Cuanto mas lecturas realice menor impacto pueden tener lecturas aleatorias esporádicas que puedan producirse.

Como leo con 10 bits de precisión, 1024 valores posibles, pero la menor y la mayor resistencia que puedo obtener son de 220R y 2760R que generan voltajes de 4,225V y 1,515V respectivamente, solo puedo obtener lecturas entre 865 y 310 aproximadamente.

Si es la mayor, 865, y acumulo sobre una variable de 16 bits solo podré acumular 75 lecturas (2^16/865) y después dividir por 75 para obtener la media de todas ... pero no es necesario ajustarse tanto al límite, con 32 lecturas tendremos mas que suficiente.

Asi que implementando que es gerundio:

 
     
  void main(void){
  int16 ANval;
  int16 ANval_Acumuleitor=0;
  int16 ANVal_Result;
  int16 ANVAL_Minimun=255;
  int8 CAN_count=0;
  int8 CAN_maxcount=32;

  setup_adc_ports(AN0 | VSS_VDD); // Configuro AN0 para lectura ADC, usando como referencia VSS y  VDD
  setup_adc(ADC_CLOCK_INTERNAL); // Configuro velocidad de muestreo la interna del PIC 2-6 us
  set_adc_channel(0); // Configuro siguiente canal de lectura a AN0;

  do{

    ANVal = read_adc(); // Leo canal ACD y guardo en ANVal
    ANval_Acumuleitor += ANVal; // Acumulo sucesivas lecturas sobre ANval_Acumuleitor
    if(++Can_Count==CAN_maxcount){ // Si hago mas de CAN_maxcount lecturas ...
      ANVal_Result = (int16) ANval_Acumuleitor/CAN_maxcount; // Calculo la media de las lecturas realizadas ...
      if(ANVal_Result>ANVAL_Minimun){ // Que si resulta mayor que ANVAL_Minimun ...
        printf("KeyScan %Lu\r\n",ANVal_Result); // La tomo en consideración, en este caso lo muestro, ya haremos la conversión a teclas por margen.
      }
      Can_Count=0; // Reinicio Can_Count, el contador de lecturas.
      ANval_Acumuleitor=0; // Reinicio ANval_Acumuleitor, el acumulador de lecturas.
    }
  }while(1);
}
 
 
     


Asi el funcionamiento es claro y simple. Leo CAN_maxcount veces (32) sobre ANval, acumulando sobre ANval_Acumuleitor, incrementando CAN_count cada vez que leo. Cuando CAN_count alcanza el valor de CAN_maxcount lecturas calculo ANVal_Result dividiendo ANval_Acumuleitor por CAN_maxcount. Si ANVal_Result es mayor que ANVAL_Minimun lo muestro, recordad que en nuestra tabla el menor resultado posible de una lectura correspondía a la mayor resistencia posible que nos daba una lectura de unos 310. Reinicio CAN_count y ANval_Acumuleitor y volvemos a empezar.

El resultado, mas abajo, tras pulsar la tecla Col4/Row4, F4 en el teclado de la imagen:



Los resultados obtenidos son compatibles, en desviación, con el 5% de precisión de las resistencias usadas (las de la banda dorada). Con resistencias mas precisas, del 1% por ejemplo, podríamos afinar la lectura proporcionalmente.

Ahora ya solo queda identificar cada lectura con cada tecla, cosa que haremos teniendo en cuenta un margen de error de +-(mas, menos) ese 5%, disminuido a aproximadamente un 1% por la ponderación realizada, alrededor de cada valor teórico calculado, de forma que nuestra tecla F4 que debería generar una lectura de 310 deberemos fijarla como 307>[F4]>313.

 
Tercera Parte:
 
 

En la Primera Parte discutíamos la configuración teórica del cómo podríamos leer un teclado matricial 4x4 mediante un único canal de conversión Analógico-Digital:



En la Segunda Parte implementábamos un sistema estadístico para recoger n valores consecutivos de una misma lectura con el fin de minimizar los posibles errores por interferencias, inestabilidad u otras posibles influencias en la lectura:



Vamos ahora a solucionar los últimos flecos de nuestra implementación  de una Lectura de un Teclado Matricial 4x4 con un solo pin del PIC consiguiendo una lectura segura, estable y unívoca de nuestro teclado.

El nuevo objetivo a conseguir es detectar infaliblemente una tecla pulsada, que no se confunda con ninguna otra, que solo la obtengamos tras asegurarnos que lleva un tiempo mínimo siendo pulsada, que no se repita la lectura independiente del tiempo que la tengamos pulsada y que sea válida cuando detectemos que la hemos soltado, reiniciando todo el sistema para obtener la siguiente tecla.

O sea esto:



El mundo Analógico es fundamentalmente distinto del Digital. En éste entre dos estados distintos y consecutivos no hay ningún estado intermedio, en aquel hay infinitos estados. Nuestra conversión AD es conocida hasta el décimo bit de precisión, si usamos un AD de 10 bits ya que si el conversor que usamos es de 8 bits será esta la precisión de nuestro conocimiento.

Pero independiente de esta precisión para la parte analógica de nuestra conversión vamos a recibir distintos voltajes en distintos momentos dependiendo de cientos de factores que van a influir en él: Desde el mismo error en la construcción de la red de resistencias que hemos montado, hasta las variaciones del voltaje VCC que utilizamos pasando por la misma inestabilidad térmica del sistema o la presión y forma de presionar que ejerzamos sobre cada una de las teclas al pulsarlas.

Al pulsar y soltar una única tecla podemos obtener toda una gama de distintos valores, lo he comprobado empíricamente, que pueden recorrer todo el espectro de valores posibles para nuestro teclado.

Desde el momento en que empieza a haber contacto de la tecla, que cierra y abre el circuito una decenas de veces, pasando por el tiempo que mantenemos dicho contacto con distintas áreas de contacto y presiones sobre la tecla, y hasta el momento en que soltamos la tecla volviendo a un tren de voltajes distintos generados durante la separación de la membrana de contacto.

La solución que he adoptado es la de recoger todas estas variaciones y tomar en cuenta aquella que estadísticamente mas se repita.

Para la primera fase, la del valor de la conversión, ya visteis cómo recogía n veces cada conversión individual y después sacaba el valor medio de todas las conversiones realizadas.

Ahora doy otro paso más:

Este valor obtenido no deja de ser una propuesta de lectura, recordad que puedo obtener x valores compatibles con la tecla KEY1 mezclada con y valores de KEY2 e incluso z valores de una KEY3.

La implementación que he hecho es la de recoger los distintos valores de Key leídos sobre una matriz (arreglo) de contadores, incrementando cada contador individual cuando recibo una key leída.

Cuando un contador de éstos alcanza un valor determinado y definido doy por absolutamente válida dicha key, limpio el resto de contadores y vuelvo a empezar.

Si obtengo un cierto número de lecturas por debajo de la mínima lectura posible es que estoy en estado de no tener ninguna tecla presionada, en dicho caso también limpio la matriz de contadores.

Si por el contrario obtengo insistentemente la misma key válida es que estoy manteniendo la tecla pulsada, asi que después de devolverla la primera vez no vuelvo a hacerlo hasta no pasar de nuevo por el estado de tecla no pulsada.

La matriz de contadores es de 17 contadores, el primero [ 0 ] para contar las lecturas menores a la mínima que me va a indicar el estado de tecla no pulsada, y el resto de contadores [ 1 ]..[ 16 ] para cada una de las teclas.

Y ya por fin, y dejándome de tanta filosofía, aquí tenéis la implementación en CCS C que he realizado:
 

     
   
int16 ANval;
int16 ANval_Acumuleitor=0;
int16 ANVal_Result;
int8 CAN_count=0;
int8 NumKeys=0;
int8 NumKeysMinimun=0;
int8 Keys[17]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int8 Key_Pressed=0;
int8 Key_Previous=0;

const int16 ANVAL_Minimun=255;
const int8 CAN_maxcount=64;
const int8 NumKeysForValidKey=15;
const int8 NumKeysForDepressed=25;
const int8 WideForKey=5;
const int16 KeyValues[17]={0,310,318,329,339,445,460,486,508,551,574,614,650,698,736,803,855};
const char KeySimbols[17]={'\0','A','B','C','D','3','6','9','u','2','5','8','X','1','4','7','0'};


void main(void){

  setup_adc_ports(AN0 | VSS_VDD);
  setup_adc(ADC_CLOCK_INTERNAL);
  set_adc_channel(0);

  do{
    task_Analog_Keyboard();
  }
}

void task_Analog_Keyboard(void){

  int1 flag_Depressed=0;
  int8 i;

  ANVal = read_adc(); // Leo canal ACD y guardo en ANVal
  ANval_Acumuleitor += ANVal; // Acumulo sucesivas lecturas sobre ANval_Acumuleitor
  if(++Can_Count==CAN_maxcount){ // Si hago mas de CAN_maxcount lecturas ...
    ANVal_Result = (int16) ANval_Acumuleitor/CAN_maxcount; // Calculo la media de las lecturas realizadas ...
    if(ANVal_Result>ANVAL_Minimun){ // Que si resulta mayor que ANVAL_Minimun ...
      for(i=1;i<17;i++){
        if(ANVal_Result>(KeyValues[i]-WideForKey) AND ANVal_Result<(KeyValues[i]+WideForKey)){ // Si el valor está dentro del margen de error ~ WideForKey
          if(++Keys[i]==NumKeysForValidKey){
            Key_Pressed=i; // Si alcanzo NumKeysForValidKey marco definitivamente Key_Pressed
            for(i=0;i<17;i++){Keys[i]=0;} // Limpio los acumulados de Keys hasta el momento
            break; // Aborto ejecución del bucle para tomar en cuenta la tecla pulsada.
          }
        }
      }
    }
    else{ // Si es menor que ANVAL_Minimun estoy en Key_Depressed
      if(++Keys[0]==NumKeysForDepressed){
        if(flag_Depressed==0) flag_Depressed=1; // Si alcanzo NumKeysForDepressed marco definitivamente Key_Depressed
      }
    }
    Can_Count=0; // Reinicio Can_Count, el contador de lecturas.
    ANval_Acumuleitor=0; // Reinicio ANval_Acumuleitor, el acumulador de lecturas.
    // Si tengo una Key_Pressed y no es igual a la última Key_Pressed y ya he detectado que he soltado la telca
    // tomo en consideración los resultados obtenidos: son válidos y estables.
    if((Key_Pressed!=0) AND (Key_Pressed!=Key_Previous) AND flag_Depressed==1){

      printf("Key = %2u Symbol=%c\r\n",Key_Pressed,KeySimbols[Key_Pressed]); // Aqui tenemos disponibles los valores de Key pulsada y/o Simbolo asociado
      flash_BUZZER(1,50);

      Key_Previous=Key_Pressed; // Asigno valor actual de tecla al anterior para evitar repeticiones
      Key_Pressed=0; // Limpio valor actual para seguir investigando teclas pulsadas.
    }
    if(flag_Depressed==1){ // Si recibo estado definitivo de Key_Depressed ...
      flag_Depressed=0; // Marco como leido dicho estado ...
      Key_Previous=0; // Reinicio valor anterior de tecla pulsada Key_Previous
    }
  }
}
 
 
     
El resultado el que os mostré mas arriba.



Seguro, estable, fiable y confiable.  Mr. Green Mr. Green Mr. Green

Hasta otra.
 

 

 

Esta página se modificó el 27/12/2008


Esta página usa la letra Ñ

Nota pública importante sobre las consultas al Webmaster de PicManía.


Sugerencias a Picmanía... (que serán leídas pero seguramente no podrán ser contestadas)

Esta página pertenece al grupo de páginas de Diego RedRaven

 

 



Nota: Esta página Web esta repleta de imágenes, textos, logotipos y demás material extraídos de los mas variados medios de los que no soy ni autor ni depositario de los correspondientes derechos de autor, uso y/o reproducción. Si Ud. es depositario de dichos derechos y desea que el material correspondiente sea eliminado de esta Web no dude en ponerse en contacto conmigo mediante e-mail y será inmediatamente retirado. Gracias.
 
Visitas
Totales : 32623 Hoy: 1 Activas: 1 Vistas: 32623

Esta página fue modificada el 07-08-2010 15:42:20

           
 DmSoft WAMP Escribir Unreal