Controla diferentes funciones con el mismo pulsador. BRAZO 7

Estoy tratando de implementar un pequeño fragmento de código, y básicamente se puede simplificar a lo siguiente.

Tengo tres LED diferentes (digamos P0.0, P0.1 y P0.2). Tengo un botón que, cuando se presiona, primero debe encender el LED en P0.0. Cuando se presiona nuevamente, debe encender P0.1 y así sucesivamente. El LED debe permanecer encendido hasta que se detecte el siguiente botón.

En el siguiente código de prueba, me refiero a cada LED como una función. Mi idea era incrementar un contador y dependiendo del conteo, encender un LED en particular.

El resultado de este código no es lo que esperaba. No hay transición entre funciones. Cualquier sugerencia sobre cómo podría reestructurar este código sería útil.

No quiero usar interrupciones para este código. Además, no he incluido la eliminación de rebotes, ya que mi objetivo es poder reproducir este código desde cero en 15 minutos.

else if ( SW1 != (0x00000002) )  //when pressed     
    {
    delay();  //for debouncing
    count++;
    }   

    if (count == 1) {
        IO0SET = (1<<0);
        pattern1();
}
 else   if (count == 2) {
        IO0SET = (1<<6);
        pattern2();
}
     else   if (count == 3) {
        IO0SET = (1<<7);
        pattern3();
}

¿Hay alguna manera de salir inmediatamente de la función actual, en lugar de tener que esperar a que termine?

Está leyendo el estado del interruptor una vez, al comienzo de su bucle principal while(1), pero parece que tiene líneas de código más abajo que están esperando que cambie. Su variable SW1 no cambiará hasta que la lea de IO0PIN nuevamente.
Además del punto de Finbarr, tampoco espera a que se suelte el interruptor antes del tiempo, por lo que su condición de tiempo siempre será falsa porque el código llegará allí antes de que se suelte el interruptor.
Gracias por sus dos comentarios. Intentaré implementar algunos cambios en consecuencia.

Respuestas (2)

No va a funcionar sin un rebote básico que, si no quiere usar interrupciones, significa una función de espera básica a menos que rebote en el hardware.

La funcionalidad prevista de su código parece ser llamar a las funciones LED establecidas constantemente mientras se presiona el botón, siguiendo su descripción, no hay necesidad de hacer esto, puede llamarlas una vez y luego esperar a que se suelte el botón. Permanecerán encendidos hasta que se llame a una función de ajuste de LED diferente.

Finalmente, si está haciendo AND en el registro IO con 0x02, el resultado es 2 o 0. En lugar de verificar un valor específico, puede usar la convención c de que 0 es falso y todos los demás valores son verdaderos, esto hace que el código sea mucho más limpio mirando. Mover eso a una función lo hace aún más agradable de leer.

int SW1Pressed (void) {
  return !(IO0PIN & 0x00000002) //switch connected on P0.1. Low when pressed.
}

....

count = 0;
while (1){
  if (SW1Pressed()) {                         //when pressed
    wait_ms(100);                             // wait 100 ms
    if (SW1Pressed()) {                       // still pressed.
      if (count==0)                           // turn on correct led
        function1();
      else
        function2();

      if (++count == 2)                       // update count
        count = 0;

       while(SW1Pressed())                  // do nothing until the button is released
         ;
    }    
  }
}
Hola Andrés, gracias por tu conocimiento sobre este tema. Actualicé mi código en la pregunta original. El código funciona como se esperaba. En cada pulsación del interruptor voy a la siguiente función. Sin embargo, la función debe terminar. Entonces, si tengo algún tipo de patrón de LED que puede demorar 30 segundos, debo esperar antes de que cambie. ¿Alguna idea de cómo puedo cambiar de inmediato? ¿Quizás una declaración de cambio de caso?
@JohnSmith Haga que sus patrones de visualización funcionen en segundo plano. Puede hacer esto manejando una máquina de estado con un temporizador, por ejemplo. La alternativa es "saltar" sus rutinas de patrón con código de monitoreo clave y considero que eso es "muy malo" a largo plazo. es un truco Podría resolver su problema inmediato "dentro de una cierta idea de razón", pero no es una buena manera de hacerlo porque todo se convierte en un nido de ratas de pesadilla a medida que desarrolla más código. Nunca bajes por ese agujero de conejo.
@jonk, no estoy 100% seguro de haberte entendido correctamente. Sin embargo, buscaré estos métodos e intentaré implementarlos.
@JohnSmith Si no está familiarizado con las ideas, debe familiarizarse. Son una herramienta vital. Desglose sus patrones en el período de tiempo más pequeño entre cada uno (o como el factor común más grande [busque GCD].) Luego implemente un temporizador a esa velocidad. Entonces, si un patrón usara 15 ms, 12 ms y 30 ms, su GCD sería T = 3 ms. Así que configurarías tu temporizador para eso. Entonces su sincronización es 5T, 4T y 10T. Contadores fáciles de configurar para números enteros. Cuando el contador de 5 expira, avanza al siguiente estado y configura su contador en 4, etc. Pero ahora es fácil terminar el patrón (¿simplemente detener el temporizador quizás?)
@JohnSmith Su nuevo código debe esperar hasta que se libere el interruptor. No es un problema si el patrón LED tarda 30 segundos, pero lo será una vez que lo solucione. Como Jonk indicó, la mejor manera de salir del patrón de LED es tener una interrupción de temporizador a una velocidad fija que actualice los LED. Su código de botón puede iniciar/detener ese temporizador o establecer una variable que el temporizador verifica para ver qué patrón debería mostrar.

Creo que el problema básico es que su código no rebota el interruptor. Al presionar un interruptor mecánico, inicialmente se abrirá y cerrará rápidamente. Esto hará que su código pase rápidamente por las distintas funciones.

Su código tiene controles de condición innecesarios que también podrían limpiarse. Básicamente, desea esperar a que se presione el botón, verifique si todavía está presionado, digamos 75-100 mS más tarde y, de ser así, espere a que se suelte el botón y luego incremente su contador de funciones y listo.

Hola, procedí a hacer lo que me dijiste. Actualizaré mi código. Funciona bien, excepto que cuando presiono el interruptor, la función aún debe realizarse antes de pasar a la siguiente función. ¿Hay alguna manera de que pueda salir inmediatamente después de presionar el interruptor?
La lógica para controlar los distintos LED podría ser algo así como If Count ==1, entonces haga esto. Si Count ==2 entonces haz esto. Si Count == 3 entonces haz esto. En la parte inferior de estas declaraciones de condición, simplemente regrese a la supervisión del botón pulsador.
¿Es el nuevo código editado de lo que estás hablando? Arreglé la codificación y todo funciona bien, excepto que parece que no puedo cambiar de función de inmediato. Esto significa que tengo que esperar a que finalice la función actual antes de que se registre la pulsación del interruptor.
Normalmente, poner el interruptor en una entrada de interrupción sería la forma de manejar esto. Una alternativa sería usar una interrupción de temporizador interno para verificar el interruptor. Una alternativa menos atractiva es llamar a la función de verificación de cambio periódicamente desde dentro de sus funciones más largas (especialmente durante los bucles de espera internos).