6 votos

Cómo eliminar seis botones en un pin analógico con Arduino

Estoy usando el pin analógico 5 de Arduino para detectar las pulsaciones de 6 pulsadores. En la imagen el botón de arriba a la derecha es el número 1 y luego de derecha a izquierda van como 2, 3, 4, 5, 6. El programa debe imprimir 0 cuando ninguno de los botones es presionado y si uno de ellos es presionado, debe imprimir su posición como mencioné antes. Actualmente el problema es que si pulso, por ejemplo, el segundo botón, a veces (en lugar de una sola vez) imprime 2 un par de veces. Supongo que es por el "ruido" que se produce al pulsar el botón y que debería ser desbordado, pero no sé cómo desbordar el pin analógico.

Mi código:

int old_button = 0;
int button;
int pressed_button;
int z;

void setup () {
  Serial.begin(9600);
  pinMode(A5, INPUT);
}

void loop () {
  z = analogRead(5);
  if (z > 1021) button = 0;                                           
  else if (z > 511 && z < 514) button = 1;                     
  else if (z > 680 && z < 684) button = 2;                
  else if (z > 766 && z < 770) button = 3;                
  else if (z > 817 && z < 822) button = 4;             
  else if (z > 851 && z < 856) button = 5; 
  else if (z > 875 && z < 880) button = 6;
  else button = 0;                                                      

  if (old_button == button) {                                           
    old_button = button;                                              
    pressed_button = 0;                                               
  }  

  else {                                                                
    old_button = button;                                             
    pressed_button = button;                                        
  }
  Serial.println(pressed_button);
}

Circuito (resistencias de 2200 ohmios):

enter image description here

1 votos

Un esquema eléctrico sería mejor que un diagrama de Fritzing, en este caso concreto. Utiliza el editor de esquemas incorporado.

1 votos

@Mate Sólo para que lo sepas. Ahora hay una pila especializada en Arduino: arduino.stackexchange.com

0 votos

¿Puede esta solución funcionar con el modo DEEP SLEEP (utilizando 0,2 uA de media con un ATmega o ATtiny en breadboard), y con el Pin Change Interrupt (PCINT)?

4voto

ianb Puntos 659

Cuando detecte una diferencia significativa en la lectura del ADC, espere 20 milisegundos y luego promedie algunas lecturas y tome una decisión. Si una de las lecturas sigue pareciendo mal cuantificada, espere otro corto periodo de tiempo.

0 votos

+1 por la respuesta. hey Andy, ¿es prudente conectar a tierra un condensador 104 desde la línea de botones (para desbancar)?

0 votos

@roh no es prudente si significa conectar un interruptor a través de una tapa de 100nF cargada porque el pulso de corriente podría reiniciar la MCU. Lo mejor es poner 100 ohmios en serie con el interruptor.

0 votos

@Andyaka: ¿Podrías escribirme un pseudocódigo para tu respuesta?

3voto

Matt McMinn Puntos 6067

Sí, es ruido de rebote. Hay que esperar un poco (digamos 50 ms) y volver a leer la entrada analógica. Si el resultado coincide, entonces el valor del botón puede considerarse válido. Algo así:

int old_button = 0;

int getButton()
{
  int i, z, sum
  int button;

  sum = 0;
  for (i=0; i < 4; i++)
  {
     sum += analogRead(5);
  }
  z = sum / 4;
  if (z > 1021) button = 0;                                           
  else if (z > 511 && z < 514) button = 1;                     
  else if (z > 680 && z < 684) button = 2;                
  else if (z > 766 && z < 770) button = 3;                
  else if (z > 817 && z < 822) button = 4;             
  else if (z > 851 && z < 856) button = 5; 
  else if (z > 875 && z < 880) button = 6;
  else button = 0;

  return button;
}

void loop ()
{
  int button, button2, pressed_button;  
  button = getButton();
  if (button != old_button)
  {
      delay(50);        // debounce
      button2 = getButton();

      if (botton == button2)
      {
         old_button = button;
         presed_button = button;
         Serial.println(pressed_button);
      }
   }
}

Como Andy no quería proporcionar ningún código, añadí un poco de promedio al tomar las lecturas del ADC. Así que el promedio dentro de getButton da cuenta de cualquier ruido de lectura de la línea analógica que entra en el ADC, y el retraso de 50 ms se encarga de detectar el rebote del interruptor.

0 votos

@Mate He añadido el código para promediar el ruido del ADC a mi respuesta. Gracias a Andy aka por sugerirlo, fue una buena adición.

3voto

Alex Andronov Puntos 178

Muchos interruptores del estilo que estás usando son difíciles de desbaratar bien, y tratar de usar un multiplexor resistivo no lo hará más fácil. Aún así, si puedes permitirte dos pines de puerto (uno analógico), puedo ofrecerte una receta para el éxito que debería funcionar incluso si tus interruptores son bastante pésimos. Sugeriría mover la resistencia de la barra de bus (ignora la barra de bus inferior de la protoboard) a la izquierda de la que está más a la izquierda, y cablearla a un pin de puerto no analógico. El cable común de la parte superior debería estar conectado al pin del puerto analógico. El cable de la resistencia más a la derecha debe conectarse a tierra.

Cuando su unidad está "en reposo" [no cree que se pulse ningún botón] ponga la salida común en alto y haga flotar la otra. Se leerá bajo cuando no se pulse ningún botón, y se leerá cerca de VDD cuando se pulse cualquier botón.

Para saber qué botón está pulsado, ponga a flote el cable común y ponga a tope el cable del lado izquierdo. Brevemente Poner el cable común alto o bajo (ver nota) y ponerlo a flote de nuevo, luego leer la tensión en ese pin un rato después (manteniendo el cable del lado izquierdo alto). Una vez tomada la lectura, puede, si lo desea, desconectar la alimentación del cable del lado izquierdo (vuelva a conectarlo antes del siguiente ciclo de lectura).

Mientras se pulsa un botón, el voltaje en el cable común debería ser una buena fracción de VDD (si hay seis botones y siete resistencias, los botones deberían leer 1/7, 2/7, 3/7, etc. hasta 6/7); el voltaje no debería verse demasiado afectado por si el pin común ha sido brevemente pulsado alto o bajo. Si no se pulsa ningún botón, las lecturas después de que el pin haya sido pulsado alto serán mucho más altas que después de que haya sido pulsado bajo. Esto indicará que el botón ha sido liberado.

Una vez soltado el botón, se puede volver a la configuración de "reposo". Cuando la resistencia izquierda es conducida a un nivel alto, la cadena de resistencias tomará corriente tanto si se pulsa algún botón como si no, pero cuando el pin izquierdo está flotando y el cable común está alto, no se tomará corriente hasta que se pulse un botón.

Para obtener buenos resultados con los interruptores baratos, debe retrasar lo suficiente después de cada pulso momentáneo de "tierra" o "VDD" en su cable común que si el interruptor está haciendo cualquier contacto en absoluto dará una buena lectura (trate de poner una resistencia de 100K en paralelo con un interruptor, y ajustar el retraso y la sensibilidad para que "apenas" registra el interruptor como se mantiene). Los interruptores baratos tienen una resistencia de más de un mega cuando están totalmente liberados, y menos de 10 ohmios cuando están totalmente presionados, pero su resistencia puede oscilar por todo el lugar entre esos estados, y el tiempo de rebote convencional no ayudará. Lo que sí ayudará es tener un circuito que no detecte la pulsación de un botón hasta que la resistencia sea bastante baja, y que considere que el botón está pulsado a menos que su resistencia sea mucho mayor. Para el circuito que he descrito, el botón del lado izquierdo será más "sensible" a las "nuevas" pulsaciones de botón que el botón del lado derecho, y la sensibilidad de "retención" puede ser diferente para los seis botones, pero no deberías tener muchos problemas para asegurar que la sensibilidad de "retención" de cada botón es mucho más alta que su sensibilidad de "nueva pulsación", que es el requisito para un rebote fiable.

1 votos

Esto suena muy bien pero necesita algún tipo de gráfico.

0 votos

Totalmente de acuerdo. Un diagrama del circuito (incluso un boceto) ayudaría realmente a dilucidar la, por otra parte, excelente respuesta.

3voto

Ryan McGrath Puntos 1259

Hace poco que he empezado a trabajar con Arduino, y aunque esta es una pregunta antigua, encontré este hilo cuando intentaba ampliar el número de botones que podía escuchar.

Trabajé a partir de la ilustración original de Fritzing y produje una ligera variante tanto en el hardware como en el software.

Arduino Analog listening to 6 pushbuttons

Modifiqué el conjunto de resistencias para utilizar diferentes valores para tratar de producir un paso más consistente entre los interruptores en lugar de los pasos logarítmicos producidos por el uso de las mismas resistencias en todo.

A partir de 5V, las resistencias son:

  • 1k
  • 180
  • 240
  • 330
  • 510
  • 800

Esto produce pasos de alrededor de 0,5V entre cada interruptor.

También construí un software básico que busca el mismo valor durante 3 lecturas seguidas antes de reconocer un cambio de tensión. Esto elimina las pequeñas variaciones en la lectura.

int sensorPin = A5; // The input port
int sensorValue; // Current reading
int outputValue; // The reported reading
int lastValues[3] = {0,0,0}; // The last 3 readings

void setup() {
  Serial.begin(9600);
}

void loop() {
  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);
  // Initialise variables for checks
  int i;
  int updateOutput = 1;
  // Loop through previous readings
  for( i = 0 ; i<3 ; i++ ){
    // If this historic value doesn't match the current reading,
    // we will not update the output value
    if( lastValues[i] != sensorValue ){
      updateOutput = 0;
    }
    // Shift the array elements to make room for new value
    if( i>0 ){
      lastValues[(i-1)] = lastValues[i];
    }
  }
  // Update if needed
  if( updateOutput == 1 ){
    outputValue = sensorValue;
  }
  // Append the new value
  lastValues[2] = sensorValue;
  // Debugging output
  Serial.print(sensorValue);
  Serial.print(" ");
  Serial.println(outputValue);
}

Obviamente, el lastValues puede hacerse de la longitud que se desee: cuanto más larga sea la matriz, más tiempo habrá que pulsar un interruptor para que sea detectado.

En mis pruebas, los valores de los sensores reportados fueron:

  • 1023: No hay botón
  • 0: Botón #1
  • 196: Botón #2
  • 301: Botón #3
  • 405: Botón #4
  • 508: Botón #5
  • 613: Botón #6

(Probado según el diagrama.)

Mis cálculos aproximados sugieren que incluso se podría ampliar a 8 botones, añadiendo las siguientes resistencias a continuación (que deberían hacer que el voltaje volviera a caer en pasos de 0,5V):

  • 1.7k
  • 5k

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X