Interconectando un teclado con un microcontrolador

3

Estoy usando un PIC16F877A, corriendo a 20 MHz.

Tengo dos teclas en paralelo, 3 columnas y 4 filas. Mi configuración es la siguiente:

KR1 a KR4 son filas, KC1 a KC3 son columnas, y todas van al microcontrolador.

En el programa, las filas se configuran como salidas digitales y las columnas se configuran como entradas digitales. Otros periféricos de los pines están deshabilitados. La forma en que escaneo las teclas es la siguiente:

Hago que la primera fila sea ALTA, luego verifico la columna 1, la columna 2 y la columna 3. Si alguna de ellas es ALTA, entonces espero un poco y verifico nuevamente para deshacer el rebote. Si aún está en ALTO, el programa decide que se presiona una tecla. Esta rutina sigue para las otras 3 filas.

Verifico el teclado cada 100 ms, y para cada fila, toma aproximadamente 2.4uS como medí con el osciloscopio. Eso, supongo, significa, para un dígito específico; póngalo en alto y luego intente medir aproximadamente 800 nS, si no sucede nada, continúe.

Así que el problema era extraño. Cada dígito trabajado, excepto de '0'. Funcionó al azar y ese azar significa raramente al mismo tiempo. Además, cuando intenté medir su voltaje al suelo con un multímetro en modo de voltios de CC, y luego presioné el botón al mismo tiempo, funcionó con cada pulsación.

Luego agregué un retraso de 5 uS después de hacer la fila específica ALTO y luego revisé las columnas. ¡Funcionó!

Ahora, ¿cuál es el problema aquí? Los cables del teclado tienen una longitud de unos 30 cm (~ 12 pulgadas). ¿Es algún tipo de problema en la línea de transmisión, como si estuviera agregando un retraso? O si el problema proviene del microcontrolador; ¿El microcontrolador no es lo suficientemente rápido?

Aquí hay una parte del código que es relevante para el problema:

...

KEY_R4 = 1;
delay_us(5);
if (KEY_C1)
{
    scan_keys.waitstate = 10;
    goto c4r1;
}
else if (KEY_C2)
{
    scan_keys.waitstate = 11;
    goto c4r2;
}
else if (KEY_C3)
{
    scan_keys.waitstate = 12;
    goto c4r3;
}
else
{
    KEY_R4 = 0;
    presstime = 0;
}

...

c4r2:
if (++presstime >= PRESSTIMEVALUE && !KEY_C2)
{
    scan_keys.waitstate = 0;
    KEY_R4 = 0;
    return '0';
}
return 'n';

...
    

2 respuestas

6

primero, el problema de lectura-modificación-escritura (de enlace , p51):

Los PIC utilizan una arquitectura IO divertida en la que la lectura de un pin siempre devuelve el nivel externo actual del pin, que puede ser diferente del último valor escrito en un pin, incluso cuando el pin está configurado como salida, por dos razones :

• Las instrucciones PIC se ejecutan en una tubería de 2 etapas, y para los pines IO, la parte leída de la siguiente instrucción tiene lugar antes de que se escriba la instrucción anterior.

• La carga en el pasador puede ser demasiado alta para que pueda alcanzar su nivel "deseado". Esto puede suceder fácilmente (por un corto tiempo) cuando la carga es capacitiva, pero también puede ocurrir con una carga estática que se encuentre dentro de las especificaciones de funcionamiento normales.

Todas las instrucciones PIC que modifican algunos bits en un byte son instrucciones de lectura-modificación-escritura, por lo que cuando, por ejemplo, se ejecutan dos instrucciones BCF (bit clear) consecutivas en el mismo puerto IO, la segunda instrucción puede arruinar el efecto de la primera Debido a la primera de las dos razones. En realidad, una instrucción BCF (y muchas otras instrucciones, como INCF) en un puerto pueden arruinar cualquier configuración anterior de ese puerto debido a la segunda razón. Se debe tener en cuenta que la primera razón ocurre con mucha más frecuencia, y se puede evitar colocando un NOP u otra instrucción entre dos instrucciones de lectura-modificación-escritura en el mismo puerto IO. Pero para evitar realmente todos los problemas, se recomienda asignar un registro separado, realizar manipulaciones en ese registro y copiarlo en el registro del puerto después de cada cambio. Esta técnica se denomina "usar un registro de sombra".

=============================================== ======

Siguiente: retardo RC. Cuando cambia un pin de E / S conectado a una cantidad no trivial de cable siempre , espere un tiempo razonable antes de esperar el resultado. En ausencia de otra fuente de "razonable": averigüe qué es lo que parece funcionar, luego duplique el tiempo.

=============================================== ======

Último: debouncing. AFAIK 50 ms es un límite superior razonable para el tiempo de rebote de un interruptor. Cuando su intervalo de muestra es más largo que este tiempo (usa 100 ms), no tiene ningún problema de rebote. La prueba se deja como ejercicio para el lector :)

    
respondido por el Wouter van Ooijen
1

Parece un problema de lectura-modificación-escritura, vea la hoja de datos. Utilice un registro sombra para la salida en lugar de cambiar los bits de salida directamente.

    
respondido por el Leon Heller

Lea otras preguntas en las etiquetas