Control de 4 LEDs con 5 pulsadores y Arduino

Mi código:

#define MAX 50
const int LED1 = 2;
const int LED2 = 3;
const int LED3 = 4;
const int LED4 = 5;
int array[MAX];
int old_b = 0;
int val;
int counter = 0;
int i;
int temp;
int L1;
int L2;

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

int readButtons (int pin) {
  int b, c;
  c = analogRead(pin);
  Serial.print("analogRead =  ");
  Serial.println(c);
  delay(100);
  if (c > 1015) b = 0;
  else if (c > 70 && c < 76) b = 1;
  else if (c > 122 && c < 128) b = 2;
  else if (c > 169 && c < 175) b = 3;
  else if (c > 209 && c < 217) b = 4;
  else if (c > 247 && c < 256) b = 5;
  else if (c > 280 && c < 291) b = 6;
  else b = 0;
  if (b == old_b) {
   return 0;
   old_b = b;
  } else {
    return b;
    old_b = b;              
    }                           
}

void loop () {
  while ((val = readButtons(5)) != 5) {
    if ((val == 1) || (val == 2) || (val == 3) || (val == 4)) {
      array[counter] = val;
      Serial.print("In  ");
      Serial.print(counter);                
      Serial.print(" saving ");            
      Serial.println(val);
      delay(200);
      counter++;
      if (counter == MAX) {
        counter = 0;
      } 
    }
  }

  temp = counter;
  counter = 0;

  for (i = 0; i < temp; i++) {
    if (array[i] % 2 == 0) {
      L1 = 2;
      L2 = array[i] / 3 + 3; 
    } else {
      L2 = 5;
      L1 = array[i] % 3 + 3;    
      }

    if (readButtons(5) != 5) {
     digitalWrite (L1, HIGH);
     if (readButtons(5) != 5) {
      digitalWrite (L2, HIGH);
      delay(1000);
      digitalWrite (L1, LOW);
      digitalWrite (L2, LOW);
      if (readButtons(5) == 5) {
        i = temp;
      }
     } else {
       digitalWrite (L1, LOW);
       i = temp; 
     }
    }

  }
}

Entonces tengo una función que detecta si se presionó un botón. Antes de eso, he determinado en qué rango están los valores para cierto botón y todos los botones están conectados en el pin analógico 5 de esta manera , excepto que tengo 6 y mis resistencias tienen 2200 ohmios. En elwhile () {...}bucle, mientras que el quinto botón no está presionado, Arduino está "mirando" si se presionó alguno de los primeros cuatro botones. Si lo fue, guárdelo en una matriz y, si no, siga "buscando". Cuando se presiona el quinto botón, frenamos y almacenamos el último lugar conocido en la matriz en la que se almacenó el valor y configuramos el contador de lugares en cero para que, al comenzar de nuevo, Arduino almacene los valores en el primer lugar de la matriz. Luego, en función de lo que está almacenado, determino qué pin/LED se encenderá. Si en cualquier momento durante el parpadeo de los LED, se presiona nuevamente el quinto botón, Arduino detiene el parpadeo y nuevamente espera las presiones de los primeros cuatro botones. Así es como se supone que funciona en teoría. En la práctica, todavía no puedo hacer que deje de parpadear cada vez que se presiona nuevamente el quinto botón. Tengo que presionarlo varias veces, a veces son necesarias dos o incluso más pulsaciones si quiero que deje de parpadear. No creo que el uso de interrupciones ayude, ya que no sé cómo debo implementarlas en mi problema. Aquí está mi circuito (excepto que tengo Arduino Duemilanove Atmega 168). Los LED van del 1 al 4 de derecha a izquierda:

esquemas

Respuestas (3)

Según su descripción, parece que necesita rebotar el interruptor.

Puedes hacerlo

Dado que parece estar utilizando algún tipo de escalera resistiva para leer varios botones en un puerto ADC, esto será un poco más complicado.

Esta sección de tu código me parece extraña:

    if (readButtons(5) != 5) {
       digitalWrite (L1, HIGH);
       if (readButtons(5) != 5) {
         digitalWrite (L2, HIGH);

Su función readButtons(5) devolverá 0 a menos que haya ocurrido un cambio en el estado del botón.

Entonces, para digitalWrite (L2, HIGH); Para ejecutar el código, necesitaría detectar dos pulsaciones de botón en una sucesión muy rápida.

Creo que esto debe ser un error, ya que no puedo pensar en ninguna razón plausible para que el código sea así.

¿Quizás tiene la intención de tener prensas separadas por un segundo (por ejemplo)?

Entonces seguramente el código debería ser:

        if (readButtons(5) != 5) {
          digitalWrite (L1, HIGH);
          delay(1000);
          if (readButtons(5) != 5) {
            digitalWrite (L2, HIGH);

Creo que el problema es la forma en que aplicas grandes retrasos que impiden el escaneo rápido de los botones.

En el siguiente código (no probado), estoy usando pequeños retrasos de 1 ms ejecutados varias veces mientras se escanean los botones

#define MAX 50
const int LED1 = 2;
const int LED2 = 3;
const int LED3 = 4;
const int LED4 = 5;
int array[MAX];
int old_b = 0;
int val;
int counter = 0;
int i;
int temp;
int L1;
int L2;

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

int readButtons(int pin)
{
    int b, c;
    c = analogRead(pin);
    Serial.print("analogRead =  ");
    Serial.println(c);
    //delay(100);

    if(c > 1015)
    {
        b = 0;
    }
    else
        if(c > 70 && c < 76)
        {
            b = 1;
        }
        else
            if(c > 122 && c < 128)
            {
                b = 2;
            }
            else
                if(c > 169 && c < 175)
                {
                    b = 3;
                }
                else
                    if(c > 209 && c < 217)
                    {
                        b = 4;
                    }
                    else
                        if(c > 247 && c < 256)
                        {
                            b = 5;
                        }
                        else
                            if(c > 280 && c < 291)
                            {
                                b = 6;
                            }
                            else
                            {
                                b = 0;
                            }

    if(b == old_b)
    {
        return 0;
        old_b = b;
    }
    else
    {
        return b;
        old_b = b;
    }
}

void loop()
{
    unsigned char counter_var = 0;
    val = readButtons(5);  // read the buttons

    while(val != 5)
    {
        val = readButtons(5);  // read the buttons

        if(counter_var == 0)
        {
            if((val == 1) || (val == 2) || (val == 3) || (val == 4))
            {
                counter_var == 200;  // to apply ~200ms delay
                array[counter] = val;
                Serial.print("In  ");
                Serial.print(counter);
                Serial.print(" saving ");
                Serial.println(val);
                //delay(200);
                counter++;

                if(counter == MAX)
                {
                    counter = 0;
                }
            }
        }
        else
        {
            counter_var--;  // if delay>0 then this decrements and counts delay ms
            delay(1);
        }
    }

    counter_var = 0;
    temp = counter;
    counter = 0;

    for(i = 0; i < temp; i++)
    {
        if(array[i] % 2 == 0)
        {
            L1 = 2;
            L2 = array[i] / 3 + 3;
        }
        else
        {
            L2 = 5;
            L1 = array[i] % 3 + 3;
        }

        if(readButtons(5) != 5)
        {
            digitalWrite(L1, HIGH);

            if(readButtons(5) != 5)
            {
                digitalWrite(L2, HIGH);
                delay(1000);
                digitalWrite(L1, LOW);
                digitalWrite(L2, LOW);

                if(readButtons(5) == 5)
                {
                    i = temp;
                }
            }
            else
            {
                digitalWrite(L1, LOW);
                i = temp;
            }
        }
    }
}

El cambio principal que he aplicado está en la siguiente parte (inicio de bucle())

  unsigned char counter_var = 0;
    val = readButtons(5);  // read the buttons

    while(val != 5)
    {
        val = readButtons(5);  // read the buttons

        if(counter_var == 0)
        {
            if((val == 1) || (val == 2) || (val == 3) || (val == 4))
            {
                counter_var == 200;  // to apply ~200ms delay
                array[counter] = val;
                Serial.print("In  ");
                Serial.print(counter);
                Serial.print(" saving ");
                Serial.println(val);
                //delay(200);
                counter++;

                if(counter == MAX)
                {
                    counter = 0;
                }
            }
        }
        else
        {
            counter_var--;  // if delay>0 then this decrements and counts delay ms
            delay(1);
        }
    }

y he quitado el delay(100)dereadButtons()

He cansado tu código y lamentablemente no funcionó. El que no tiene los cambios en el bucle funcionaría perfectamente, excepto que de alguna manera siempre se olvida de ejecutar el primer comando de botón presionado. Por ejemplo, presiono 1,2,2,3,4, se ejecutará como si hubiera presionado 2,2,3,4. Con las correcciones en bucle, no reconoce las pulsaciones del quinto botón, es decir, no comienza/finaliza el parpadeo después de pulsar el quinto botón.
@Mate, ¿entonces funciona la cesión de 1-4 botones y solo tiene un problema con la detección del botón 5 en mi código?
Sí, cuando en el ciclo está el código de la segunda parte de su respuesta.
@Mate Lo que has usado es el código completo de la primera parte de mi respuesta, ¿verdad? El segundo ya es parte del primero y debe ignorarse.
Lo siento, no me di cuenta de eso. Entonces, el único problema es que no recuerda / guarda la presión de un primer botón que se presionó, sin importar cuál se presionó primero.
@Mate Verifiqué el código en un simulador y parece funcionar bien (tal vez solo necesite aumentar la demora de 200 a 500 o más para evitar múltiples eventos de tienda por cada 1-4 botones presionados) así que no estoy seguro de por qué usted está teniendo un problema con él. ¿Está seguro de que el nivel de voltaje para el botón 5 está configurado correctamente para que el ADC lo reconozca?
Soy positivo. He agregado mis esquemas, así que si lo desea, puede probarlo usted mismo y ver si obtiene resultados similares.
@alexan_e - ¿Puedes decirnos qué simulador usaste?
@ricardo proteo
@Mate Entonces, si entiendo correctamente, el código que proporcioné funciona pero, por alguna razón, nunca detecta/almacena el primer botón presionado, ¿verdad? ¿Recibe un mensaje en el terminal serial de que se presionó este primer botón?
@alexan_e: A veces no detecta la primera pulsación de botón, pero siempre hay un mensaje en el terminal serie de que se detectó.