Inicio
. Mapa
. Presentación .
Electrónica Básica .
Experimentos . Proyectos .
CCS C . C30 .MPASM .
Invitados . Eagle |
|
PROYECTOS : AUX Botones |
|
|
| Descripción: |
| En este
artículo vamos a intentar presentar de forma clara y concisa el modo
correcto de usar botones, pulsadores e interruptores en nuestros montajes.
Estos elementos son muy útiles a la hora de proporcionar señales de
entrada para nuestros PICs que luego procesamos para modificar su
funcionamiento, configuración, etc. |
| Los botones,
pulsadores e interruptores son artilugios mecánicos. Esta circunstancia
produce un efecto que es muy importante tener en cuenta a la hora de
procesar la señal que le envía al PIC: el rebote. |
| La conexión o
interrupción del contacto eléctrico generada por estos cacharros depende
mecánicamente de un muelle o fleje que hace que el contacto permanezca
estable, sin embargo el proceso de cierre o apertura de dicho contacto no
se produce de una sola vez y para siempre, sino que por el contrario hay
una secuencia mas o menos larga de conexiones y desconexiones, dependiendo
de la potencia del muelle o fleje, que hace que en vez de tener un paso
claro de ON a OFF, o viceversa, lo que tenemos es todo un tren de pulsos,
cada vez mas cortos, hasta que se estabiliza en uno u otro estado. |
| Véase la
imagen de abajo en la que mostramos los modos mas usuales de conexión de
los pulsadores y cómo la señal vibra antes de estabilizarse: |
|
|
| Al ser el PIC
mucho mas rápido en su ejecución que las múltiples señales que recibe y al
ejecutar nuestro programa funciones distintas dependiendo del estado ON/OFF
de entrada es fácilmente observable que dichas funciones se dispararán
tantas veces como rebotes tengamos en los pulsadores o interruptores. Los
resultados de lanzar la ejecución de estas funciones muchas veces,
pudiendo incluso superponerse entre ellas, puede llevar a nuestro programa
a cometer errores, inconsistencia o a resultados indefinidos. |
| Al final de
este artículo tenéis un Análisis de rebotes en
un botón mediante un programa monitor con el que podéis comprobar de
forma práctica y real qué ocurre con vuestro botón cuando es pulsado. |
| Esquema de Conexión: |
| El esquema de conexión que vamos a utilizar es muy simple y lo vamos a hacer usando los dos métodos de conexión vistos mas arriba, Pull-Up y Pull-Down, con los que vamos a leer "ceros" en T1 y "unos" en T2 con los pulsadores sin accionar y "unos" en T1 y "ceros" en T2 cuando los accionemos : |
|
|
| Nuestra solución: |
|
Conceptualmente nuestra solución va a consistir en solo admitir como
pulsado, o liberado, un botón cuando periódicamente obtengamos varios
valores consecutivos de un estado válido estable. Para ello vamos a tener
que usar una variable fundamental en este problema : el tiempo. |
| Vamos a
definir un periodo de tiempo durante el cual vamos a muestrear el estado
de la pulsación, si obtenemos sucesivos valores de la pulsación de igual
valor a los anteriores daremos por válida la pulsación. |
| Lo que debemos hacer
entonces es : |
|
|
|
|
|
| El siguiente gráfico
muestra claramente como actúa nuestra rutina de lectura de botones: |
|
|
| El cuerpo principal de nuestro programa solo debe entonces usar el valor de BtnPush que le indicará sin errores el estado de nuestro botón, pulsador o interruptor. |
|
Análisis de rebotes mediante un programa monitor. |
| Teniendo en
cuenta lo desarrollado en la Descripción de nuestro
Circuito auxiliar para el Uso de Botones
debemos partir de algún dato real que nos permita saber de cuantos y de
que calidad son los rebotes de que estamos hablando. |
| En este corolario de
dicho artículo os propongo un método para conocer la realidad del
interruptor o pulsador concreto que estamos utilizando. |
| Podéis
consultar alguna información accesoria y conceptos que ya ha sido tratado
en esta Web en: |
| Descripción del
análisis: |
| Nuestra
pretensión es calcular cuantos rebotes se producen en una única pulsación
del pulsador y cuanto dura cada uno de ellos. Con esto debemos tener una
idea clara de qué debemos hacer para corregirlos y obtener una sola
pulsación válida, tal como se describe en nuestra solución del artículo
que precede a éste. |
| Nuestro
programa hace uso del TIMER0 del PIC configurado en su velocidad máxima, o
sea con el Preescaler puesto a 1:2 con lo que TIMER0 da una vuelta
completa, de 00h a FFh cada 512
μS,
lo que significa que cada incremento del mismo se procude cada 512 / 256 =
2
μS.
Ésta va ser nuestra unidad de media. |
| Usamos también
ExtInt, la interrupción externa, configurada para dispararse con el flanco
de bajada, falling edge, que es la que nos va a enviar la información que
posteriormente vamos a transmitir a nuestro PC. Recordad que mi
hardware está conectado de
forma que el PIN RB0 está permanentemente a nivel alto (Vcc) y es el
pulsador quien lo tira a nivel bajo (Vss). Al dispararse la
interrupción, y dentro de la rutina que la maneja, lo único que hacemos es
guardar el estado de TIMER0 en el momento de entrar. Para ello usamos un
Array de valores, con su correspondiente índice para ir incrementándolo, y
poder así guardar sucesivos valores de TIMER0. |
| Al recibir por la RS-232 cualquier carácter procedente del PC respondemos enviando el contenido completo del Array al mismo y podemos así conocer lo ocurrido durante la pulsación. |
|
Programa monitor de rebotes (Versión monoflanco) |
||
| //
button_bounce_analisis #include <16f876a.h> // Selecciona el PIC #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Opciones de configuración #use delay(clock=4000000) // Velocidad del Cristal : 4 Mhz #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Definición del RS232 int i=0x00; int uTime=0; char Keypress=0; char Command=0; int Times[20]; #int_rda void serial_isr() { Keypress=0; if(kbhit()){ Keypress=getc(); if(Keypress!=0){ Command=Keypress; } } } #int_EXT EXT_isr() { Times[uTime++]=GET_RTCC(); } void main() { ext_int_edge(H_TO_L); setup_counters(RTCC_INTERNAL,RTCC_DIV_2); setup_timer_1(T1_DISABLED); setup_timer_2(T2_DISABLED,0,1); setup_comparator(NC_NC_NC_NC); setup_vref(FALSE); enable_interrupts(int_rda); enable_interrupts(int_ext); enable_interrupts(global); for(i=0;i<20;i++){ Times[i]=0;} printf("\r\Button Bounce waiting ...\r\r"); set_rtcc(0); do{ if(Command!=0){ Command=0; // Transmite resultados printf("\n\Results Table:\n\n"); for(i=0;i<20;i++){ printf("%2u Value: %3u\r",i,Times[i]); } } } while (TRUE); } |
||
|
|
| El
procedimiento a seguir tras grabar el programa en nuestro PIC consiste en
conectar el PIC a nuestro PC mediante la RS-232, provocar el RESET del PIC
conectando la alimentación o pulsando el botón correspondiente, y pulsar
una única vez el botón conectado al PIN receptor de la Interrupción
Externa. Tras enviamos cualquier carácter desde nuestro PC a la RS-232 y
recibiremos la tabla de tiempos correspondiente al análisis realizado: |
| Abajo os
muestro un ejemplo muy representativo de una pulsación que he obtenido
mediante este método: |
|
|
| Como podéis
comprobar he obtenido 5 interrupciones externas con una única pulsación de
mi pulsador, estando en cada una de ellas el contador de TIMER0 en los
valores: 89, 168, 254, 90 (después de haber llegado a 255) y 218. Esto
puede representarse mediante el siguiente cronograma: |
|
|
| Fijaos que he
marcado los valores obtenidos sobre cada uno de los flancos de subida. Así
tenemos que entre cada uno de ellos hay una diferencia de valores de
TIMER0 de 168 - 89 = 79, 254 - 168 = 86, 2 + 90 = 92 y 218 - 90 = 128.
Esto corresponde con tiempos de 158
μS, 172
μS, 184
μS y 256
μS
respectivamente. |
| Así que en
conclusión mi botón rebota, o puede rebotar, ya que cada pulsación me va
dando de 1 a 6 rebotes, durante unos 0.80 milisegundos aproximadamente,
casi un milisegundo completo, desde que lo pulso hasta que lo suelto y
queda estable. |
| Ahora ya sabemos de qué estamos hablando. |
| Ampliando nuestro
análisis: |
| Este análisis
puede realizarse de forma más precisa aún si ampliamos la información
recopilada de forma que guardemos los valores de TIMER0 tanto en los
flancos de subida como en los de bajada. |
| Para ello solo
tenemos que conmutar el flanco analizado en cada disparo de interrupción.
Empezamos con el de bajada, cuando se dispare INTEXT por primera vez
guardamos el valor de TIMER0 y conmutamos con
ext_int_edge(L_TO_H) para esperar al
de subida que volverá a disparar la INTEXT durante la cual volveremos a
guardar el valor de TIMER0 y conmutamos de nuevo al flanco de subida con
ext_int_edge(H_TO_L). Así se repetirá
en cada pulso generado por cada rebote. |
| Con este
procedimiento, mas completo, obtenemos el doble de valores siendo los
impares los de los flancos de bajada y lo pares los de subida. Tendremos
de esta forma el número de rebotes, la duración de cada uno de ellos y la
distancia que los separa. |
| Nuestro nuevo programa
quedaría como sigue: |
|
Programa monitor de rebotes (Versión biflanco) |
||
#include <16f876a.h> // Selecciona el PIC #fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Opciones de configuración #use delay(clock=4000000) // Velocidad del Cristal : 4 Mhz #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Definición del RS232 char Keypress=0; char Command=0; int i=0x00; int uTimeUp=0; int uTimeDown=0; int TimesUp[6]; int TimesDown[6]; int fedge=0; int nTintext=0; void Transmission(void); #int_rda void serial_isr() { Keypress=0; if(kbhit()){ Keypress=getc(); if(Keypress!=0){ Command=Keypress; } } } #int_EXT EXT_isr() { ++nTintext; switch(fedge){ case 0: TimesDown[uTimeDown++]=GET_RTCC(); fedge=1; ext_int_edge(L_TO_H); break; case 1: TimesUp[uTimeUp++]=GET_RTCC(); fedge=0; ext_int_edge(H_TO_L); break; } } void main() { nTintext=0; fedge=0; ext_int_edge(H_TO_L); setup_counters(RTCC_INTERNAL,RTCC_DIV_2); setup_timer_1(T1_DISABLED); setup_timer_2(T2_DISABLED,0,1); setup_comparator(NC_NC_NC_NC); setup_vref(FALSE); enable_interrupts(int_rda); enable_interrupts(int_ext); enable_interrupts(global); for(i=0;i<6;i++){ TimesUp[i]=0;} for(i=0;i<6;i++){ TimesDown[i]=0;} printf("\r\Button Bounce waiting ...\r\r"); set_rtcc(0); do{ if(Command!=0){ Command=0; Transmission(); } } while (TRUE); } void Transmission(void){ printf("\n\Results Table:\n\n"); printf("Total intext %2u\r",nTintext); printf("\n\Down Table:\n\n"); for(i=0;i<6;i++){ printf("%2u Value: %3u\r",i,TimesDown[i]); } printf("\n\Up Table:\n\n"); for(i=0;i<6;i++){ printf("%2u Value: %3u\r",i,TimesUp[i]); } } |
||
|
|
| Con la modificación
correspondiente del programa anterior tenemos una tabla de resultados tal
y como puede verse en la imagen inferior en la que Down Table
representa los flancos de bajada y Up Table los de subida: |
|
|
| ¿Alguien da más? |
| (Pues sí ... ya que aún no tenemos controlado el tiempo que mantenemos pulsado el pulsador ... durante el cual pueden pasar centenares o miles de ticks de TIMER0 cruzando la frontera entre FFh y 00h decenas de veces con lo que los valores entre el ultimo rebote al pulsar y el primero al soltar no son nada válidos; pero su solución es fácil y os la dejo para que la soluciones ustedes :-) Ya sábies qué hacer ... ¿o no?) |
Esta página se modificó el 27/12/2008
Visitas
Totales : 3975 Hoy: 1 Activas: 1 Vistas: 3975
|