Sincronización de la gestión de dos pulsadores y un único led rgb

Buenas tardes, soy novato en este foro así que discupad algún error de forma al escribir este post. Bueno, el problema es que estoy haciendo un proyecto con servomotores y con dos pulsadores y un led RGB quería que al recibir corriente un pulsador al recibir un click sirviera para seleccionar el modo de funcionamiento (distintas velocidades 1,2,3) y el otro pulsador, sirviera para comenzar la actividad de los servos haciendo parpadear el led en función del modo con su color correspondiente (cada modo un color). Para acabar la actividad de los servos se vuelve a pulsar el pulsador 2. Tenía una función para el pulsador 1 con antirrebotes y que en una variable me guarda el "modo" pero no consigo compatibilizarla con la segunda para el parpadeo. Solo consigo que parpadeé si en uno de los modos el led está apagado lo que me quiere decir que la función 1 no deja de funcionar en ningún momento y los leds siempre van a estar encendidos. No se si a alguien se le ocurre alguna solución. Dejo por aquí el código. Un saludo

const int boton1 = 40;
const int boton2 = 42;
int   anterior1; 
int   estado1;       
int contador;
int pinR1=26;
int pinG1=24;
int pinB1=22;
unsigned long temporizador1;
unsigned long tiemporebote1 = 50;
bool estadoactual = false;        
bool estadoanterior     = false; // 
bool inicio = false;
unsigned long tiempo_anterior = 0;
unsigned long intervalo  = 500;
byte estado   = 0;



void setup() {
  Serial.begin(9600);
  contador=1;
  pinMode(boton1,INPUT);
  pinMode(boton2,INPUT);
  estado1 = HIGH;
  anterior1 = HIGH;
  pinMode(pinR1,OUTPUT);
  pinMode(pinG1,OUTPUT);
  pinMode(pinB1,OUTPUT);
}



void funcionboton1(){
  if ( estado1==digitalRead(40) ) {
    temporizador1 = 0;
  }
  else 
  if ( temporizador1 == 0 ) {
    temporizador1 = millis();
  }
  else 
  if ( millis()-temporizador1 > tiemporebote1 ) {
    estado1 = !estado1;
  }
  if ( anterior1==HIGH && estado1==LOW ) {
    Serial.print(" Botón pulsado ");
    Serial.print(contador);
    contador=contador+1;
  }
  anterior1 = estado1;
  if (contador==2){
     digitalWrite(pinG1,HIGH);
     digitalWrite(pinB1,LOW);
     digitalWrite(pinR1,LOW);  
   }
    else if (contador==3) {
     digitalWrite(pinG1,LOW);
     digitalWrite(pinB1,LOW);
     digitalWrite(pinR1,HIGH);
    
    }
   else if (contador==4) {
     digitalWrite(pinG1,HIGH);
     digitalWrite(pinB1,LOW);
     digitalWrite(pinR1,HIGH);
     contador=1;
   }
}



void funcionboton2(int cont){
  estadoAC = digitalRead(boton2);
 if (estadoactual && !estadoanterior)         
 inicio = ! inicio;
 
 if (inicio) { 
 switch (estado) { 
 case 0:  digitalWrite(pinG1, HIGH);
          digitalWrite(pinR1, HIGH);
          digitalWrite(pinB1, HIGH);  
        tiempo_anterior = millis();      
        estado = 1; // 
    break;
 case 1: if (millis() - tiempo_anterior >= intervalo) { 
         digitalWrite(pinR1, LOW); // 
         digitalWrite(pinG1, LOW);
         digitalWrite(pinB1, LOW);
         tiempo_anterior = millis(); 
         estado = 2;   
    }
    break;
 case 2: if (millis() - tiempo_anterior >= intervalo) {
 estadoMaquina = 0; 
 }
 break;
 }
 }
 else 
 digitalWrite(pinG1, LOW);
 digitalWrite(pinR1, LOW);
 digitalWrite(pinB1, LOW);
 estadoanterior = estadoactual;
}

 
void loop() {
   funcionboton1();
   funcionboton2(contador);
}   

Moderador:
Por favor, lee las Normas del foro y edita el título. Quita la palabra ayuda.
Lee el punto 3. de las normas y entenderàs porque te lo estoy pidiendo.

Lo siento, creo que ahora ya cuenta con un título más apropiado.

Sin mirar en produndidad el código ni probarlo,
El 'else' solo ejecutará la primera línea de código.
¿quizá debería ser?

else 
{ //añadido
 digitalWrite(pinG1, LOW);
 digitalWrite(pinR1, LOW);
 digitalWrite(pinB1, LOW);
 estadoanterior = estadoactual;
} //añadido
}

De todas formas te recomiendo que antes de postear un código fuente le des formato para verlo mejor.
Saludos.

Anoche habia hecho esto pero como tengo un problema que no puedo detectar con mi PC no lo posteé.


void funcionboton1(){

  estado1 = digitalRead(40);
  // comprobar para ver si acaba de presionar el botón
   // (por ejemplo, la entrada fue de LOW a HIGH), y ha esperado
   // el tiempo suficiente desde la última pulsación para ignorar cualquier ruido:

   // Si el interruptor cambió, debido al ruido, o pulsando:
  if (estado1 != ultimoEstadoPuls) {
    // restablecer el temporizador de supresión de rebotes
    temporizador1 = millis();
  } 
  
  if ((millis() - temporizador1) > tiemporebote1) {
    // cualquiera que sea la lectura que se mantiene más tiempo
     // que el retardo de entrada, así que se toma como el estado actual real:

    if (estado1 != estadoPulsador) {
      estadoPulsador = leer;

      if (estadoPulsador == HIGH) {
        contador = contador+1;
      }
    }
  }

  switch(contador) {
    case 2: digitalWrite(pinG1,HIGH);
            digitalWrite(pinB1,LOW);
            digitalWrite(pinR1,LOW);  
            break;
    case 3: 
            digitalWrite(pinG1,LOW);
            digitalWrite(pinB1,LOW);
            digitalWrite(pinR1,HIGH);
            break;
    case 4: 
            digitalWrite(pinG1,HIGH);
            digitalWrite(pinB1,LOW);
            digitalWrite(pinR1,HIGH);
            contador=1;
            break;
  }
}

void funcionboton2(int cont){
  estadoAC = digitalRead(boton2);
  if (estadoAC && !estadoAN)         
      inicio = ! inicio;

  if (inicio) { 
      switch (estadoMaquina) { 
        case 0: digitalWrite(pinG1, HIGH);
                digitalWrite(pinR1, HIGH);
                digitalWrite(pinB1, HIGH);    // si pausa complata => parpadeo OFF 
                tiempo_anterior = millis();   // pongo el LED en ON y inicio la primer pausa.
                estadoMaquina = 1; // voy al paso 1
                break;
        case 1: if (millis() - tiempo_anterior >= intervalo) { // se ha completado la pausa?
                    digitalWrite(pinR1, LOW); // si pausa complata => parpadeo OFF
                    digitalWrite(pinG1, LOW);
                    digitalWrite(pinB1, LOW);
                    tiempo_anterior = millis(); // ajusto variable tiempo para proxima pausa
                    estadoMaquina = 2;   // voy al siguiente paso lógico, el 2.
                }
                break;
        case 2: if (millis() - tiempo_anterior >= intervalo) {
                    estadoMaquina = 0; // vuelvo al primer estado y aseguro el parpadeo ON
                }
                break;
        }
      }
  else {
    digitalWrite(pinG1, LOW);
    digitalWrite(pinR1, LOW);
    digitalWrite(pinB1, LOW);
    estadoAN = estadoAC;
  }
}

Hay algunas correcciones en la secuencia antirebotes.
Agrega esto a tus variables globales.

int estado1, ultimoEstadoPuls;    

Aparace que no han sido declaradas tanto "leer" como "estadoPulsador". Con este último no se si fue un error o querías referirte a "estadoUltPulsador".

Pero te lo escribí al final con 1, agrégalas.
Yo rara vez pruebo el código, cuando lo hago lo digo.
No puedes agregar las variables que hacen falta?

Si por supuesto que las puedo añadir, pero no entiendo su funcionamiento en el programa. He podido probarlo ya y creo que el problema reside ahí.

  if (estado1 != estadoPulsador) {
      estadoPulsador = leer;

Son estas dos líneas las que no logro entender para el funcionamiento global de la función del botón 1.

Diego vas bien encaminado, sobre todo con el uso de millis(). Me he tomado la libertad de hacerte el ejercicio completo, ya que un futuro (si la cosa va bien) pretendo mostrar "otras formas de programar" y subir ejercicios a una web.

Debido a que no has especificado que tipo led RGB, usé el que traía el emulador, con cátodo común. Si usas de ánodo en común tenlo en cuenta con el diagrama.

Al no decir nada sobre el movimiento de los servos me tomé la libertad de poner las "rutas" en un array.

Diagrama:

Código:

////////////////////////////////
/*
Cuantron - ejercicio


(2) pulsadores:
Pulsadores en modo interruptor
pulsador 1 -> cambia la velocidad del servomotor
pulsador 2 -> activa/desactiva el servomotor

(1) led RGB
Led -> Cambia de color según la velocidad seleccionada
en base al listado de colores dados.
El led está fijo si el servo está activo, hace blink en
caso contrario.

(1) Servomotor
Servo -> Se mueve a los ángulos establecidos en la variable 
"posiciones". La velocidad viene dada del timer.
La variable "pasos" también puede usarse para la velocidad del Servo. 

No delays() ^^
*/
////////////////////////////////

//Macro
#define SIZE(x) (sizeof(x) / sizeof(x[0]))

#include <Servo.h>

////////////////////////////////
//Servo
struct servo{
  const byte pin = 8;
  //(control de velocidad) -> pasos por tiempo.
  byte 
    angulo,                          //posición actual
    siguiente,                       //posición futura
    pasos = 4,                       //pasos +- ángulo
    indice_posicion,                 //indice con la posición siguiente
    indice_velocidad,                //indice para el array tiempo_servo
    posiciones[4] = {60, 180, 90, 0};//algunos movimientos de prueba
  bool activo;                       //sólo se mueve si está activo
  unsigned int 
    tiempo_servo[3] = {100,200,400},//velocidades (tiempo movimiento)
    intervalo;                       //duracion
  unsigned long tiempo;              //millis()
  Servo id_servo;
};
servo mi_servo;

////////////////////////////////
//led RGB
struct led{
  const byte pines_RGB[3] = {11,9,10};
  bool estado;
  unsigned int intervalo = 500;     //duracion blink
  unsigned long tiempo;              //millis()
};
led mi_led;

////////////////////////////////
//colores
struct colores{
  byte color[3]; 
};
//El tamaño del array será un color por velocidad
colores lista_colores[SIZE(mi_servo.tiempo_servo)+1] = {
  {255,0,0}, //rojo  -> primera velocidad
  {0,255,0}, //verde -> segunda velocidad
  {0,0,255}  //azul  -> tercera velocidad
};

////////////////////////////////
//pulsadores

struct btn{
  const byte pin;  
  bool 
    activo,               //activación switch
    estado;               //LOW - HIGH
  unsigned int intervalo; //duracion
  unsigned long tiempo;   //millis()
};
btn mis_btn[] = {
  {2,0,150,0,false},
  {7,0,150,0,false}   
};

void setup(){ 
  Serial.begin(9600);
  //Inicializar
  mi_servo.id_servo.attach(mi_servo.pin);
  mi_servo.intervalo = mi_servo.tiempo_servo[0];
  for(byte i = 0; i < 3; i++) pinMode(mi_led.pines_RGB[i], OUTPUT);
  for(byte i = 0; i < SIZE(mis_btn); i++) pinMode(mis_btn[i].pin, INPUT); 
  //Info inicial
  String str = (mi_servo.activo) ? "activo" : "inactivo";
  Serial.println("El servo esta "+ str );
  Serial.println("velocidad "+ String(mi_servo.intervalo));
}

void loop(){
  //Comprobamos los pulsadores
  //////////////////////////////////////////////////
  for(byte i = 0; i < SIZE(mis_btn); i++){
    
    //Modo interruptor
    //guardamos para comprobar si después hay un cambio.
    bool estado_actual = mis_btn[i].estado;
    
    bool presionado = digitalRead(mis_btn[i].pin);
    if(presionado && !mis_btn[i].activo && comprobar_tiempo(mis_btn[i].intervalo, mis_btn[i].tiempo ) ){
      mis_btn[i].estado = !mis_btn[i].estado;
      mis_btn[i].tiempo = millis();  
    }
    mis_btn[i].activo = presionado;
    
    //evento keydown
    if(mis_btn[i].estado != estado_actual){
      switch(i){
        case 0 : cambiar_velocidad(); break; // primer pulsador
        case 1 : activar_servo();     break; // segundo pulsador
        //...
      }
    }
  }
  
  //Si el servo está activo
  //////////////////////////////////////////////////
  if(mi_servo.activo && comprobar_tiempo(mi_servo.intervalo, mi_servo.tiempo)){
     
    mi_servo.siguiente = mi_servo.posiciones[mi_servo.indice_posicion];
    
    if(mi_servo.angulo != mi_servo.siguiente ){

      //Nos dirigimos a un ángulo superior respecto al actual
      if(mi_servo.angulo < mi_servo.siguiente){
        if(mi_servo.angulo + mi_servo.pasos <= 180){
          mi_servo.angulo += mi_servo.pasos;
          if(mi_servo.angulo > mi_servo.siguiente){
            mi_servo.angulo = mi_servo.siguiente;
          }
        }else{
          mi_servo.angulo = mi_servo.siguiente;
        }
      }
      //Nos dirigimos a un ángulo inferior respecto al actual
      else{
        if(mi_servo.angulo - mi_servo.pasos >= 0){  
          mi_servo.angulo -= mi_servo.pasos;
          if(mi_servo.angulo < mi_servo.siguiente || mi_servo.angulo < 0){
            mi_servo.angulo = mi_servo.siguiente;
          }
        }else{
          mi_servo.angulo = mi_servo.siguiente;
        } 
      }

	  Serial.println("Estamos en la posicion "+String(mi_servo.angulo));
    }
    //Hemos llegado a la posición siguiente, seleccionamos el próx. ángulo
    else{
      mi_servo.indice_posicion++;
      if(mi_servo.indice_posicion > SIZE(mi_servo.posiciones)-1){
        mi_servo.indice_posicion = 0;
      }
    }
    //Serial.println(mi_servo.intervalo);
    mi_servo.id_servo.write(mi_servo.angulo);
    mi_servo.tiempo = millis();
  }
  
  //Color led en base a la velocidad
  //////////////////////////////////////////////////
  if(comprobar_tiempo(mi_led.intervalo, mi_led.tiempo)){
    
    for(byte i = 0; i < SIZE(mi_led.pines_RGB); i++){ 
      if(mi_led.estado || mi_servo.activo){  
        analogWrite(mi_led.pines_RGB[i], lista_colores[mi_servo.indice_velocidad].color[i]);
  	  }
      else if(!mi_servo.activo){
        analogWrite(mi_led.pines_RGB[i], 0);
      }
    }
    mi_led.estado = !mi_led.estado;
    mi_led.tiempo = millis();
  }
}

void cambiar_velocidad(){
  mi_servo.indice_velocidad++;
  if(mi_servo.indice_velocidad > SIZE(mi_servo.tiempo_servo)-1 ){
    mi_servo.indice_velocidad = 0;
  }
  mi_servo.intervalo = mi_servo.tiempo_servo[mi_servo.indice_velocidad];
  Serial.println("velocidad "+ String(mi_servo.intervalo));
}

void activar_servo(){
  mi_servo.activo = !mi_servo.activo;
  String str = (mi_servo.activo) ? "activo" : "inactivo";
  Serial.println("El servo esta "+ str );
}

bool comprobar_tiempo(unsigned int interv, unsigned long tiempo_total){
  return bool(millis() - tiempo_total >= interv);
}
  1. El botón de la izquierda activa/desactiva el movimiento del servo
  2. El botón de la derecha cambia las velocidad. (Ambos pulsadores con funcionamiento switch)
  3. El led RGB dispone de tantos colores cómo velocidades posibles. En este ejemplo puse 3 posibles.
  4. El led parpadeará (Blink) si el servo está inactivo. En caso de estar activo el led estará fijo.
  5. La velocidad del servo se controla con el intervalo de tiempo. Puedes regularla con la variable de intervalo o bien modificar la variable pasos.
  6. En el ejemplo pasos es igual 4, así que cuando el servo va de la posición 60 a la 90 por ejemplo si la velocidad es de 200 miliseg. El servo seguirá este patrón: 60-64-68-72... Hasta llegar al ángulo designado. A mayor paso o menor intervalo más rápido.

Mi consejo es que lo pruebes en tinkercad, crees el circuito y pruebes (copiar-pegar) si es lo que buscas. Yo intenté basarme en lo dicho en el primer post

Edito: Si te fijas está pensado para añadir si quisieras más pulsadores y en caso de necesitar más leds o servos sólo tienes que convertir dichas estructuras en un array struct.

1 Like

Revisé el código y en algunos reemplazos que hice cambié nombres pero solo te pedi que reemplazaras las dos funciones. Creo que no me entendiste.

const int boton1 = 40;
const int boton2 = 42;
int anterior1; 
int estado1, ultimoEstadoPuls, estadoPulsador, leer;       
int contador;
int pinR1=26;
int pinG1=24;
int pinB1=22;
unsigned long temporizador1;
unsigned long tiemporebote1 = 50;
bool estadoActual = false;        
bool estadoAnterior     = false; // 
bool inicio = false;
unsigned long tiempo_anterior = 0;
unsigned long intervalo  = 500;
byte estadoMaquina   = 0;



void setup() {
  Serial.begin(9600);
  contador=1;
  pinMode(boton1,INPUT);
  pinMode(boton2,INPUT);
  estado1 = HIGH;
  anterior1 = HIGH;
  pinMode(pinR1,OUTPUT);
  pinMode(pinG1,OUTPUT);
  pinMode(pinB1,OUTPUT);
}

void funcionboton1(){

  estado1 = digitalRead(40);
  // comprobar para ver si acaba de presionar el botón
   // (por ejemplo, la entrada fue de LOW a HIGH), y ha esperado
   // el tiempo suficiente desde la última pulsación para ignorar cualquier ruido:

   // Si el interruptor cambió, debido al ruido, o pulsando:
  if (estado1 != ultimoEstadoPuls) {
    // restablecer el temporizador de supresión de rebotes
    temporizador1 = millis();
  } 
  
  if ((millis() - temporizador1) > tiemporebote1) {
    // cualquiera que sea la lectura que se mantiene más tiempo
     // que el retardo de entrada, así que se toma como el estado actual real:

    if (estado1 != estadoPulsador) {
      estadoPulsador = leer;

      if (estadoPulsador == HIGH) {
        contador = contador+1;
      }
    }
  }

  switch(contador) {
    case 2: digitalWrite(pinG1,HIGH);
            digitalWrite(pinB1,LOW);
            digitalWrite(pinR1,LOW);  
            break;
    case 3: 
            digitalWrite(pinG1,LOW);
            digitalWrite(pinB1,LOW);
            digitalWrite(pinR1,HIGH);
            break;
    case 4: 
            digitalWrite(pinG1,HIGH);
            digitalWrite(pinB1,LOW);
            digitalWrite(pinR1,HIGH);
            contador=1;
            break;
  }
}

void funcionboton2(int cont){
  estadoActual = digitalRead(boton2);
  if (estadoActual && !estadoAnterior)         
      inicio = ! inicio;

  if (inicio) { 
      switch (estadoMaquina) { 
        case 0: digitalWrite(pinG1, HIGH);
                digitalWrite(pinR1, HIGH);
                digitalWrite(pinB1, HIGH);    // si pausa complata => parpadeo OFF 
                tiempo_anterior = millis();   // pongo el LED en ON y inicio la primer pausa.
                estadoMaquina = 1; // voy al paso 1
                break;
        case 1: if (millis() - tiempo_anterior >= intervalo) { // se ha completado la pausa?
                    digitalWrite(pinR1, LOW); // si pausa complata => parpadeo OFF
                    digitalWrite(pinG1, LOW);
                    digitalWrite(pinB1, LOW);
                    tiempo_anterior = millis(); // ajusto variable tiempo para proxima pausa
                    estadoMaquina = 2;   // voy al siguiente paso lógico, el 2.
                }
                break;
        case 2: if (millis() - tiempo_anterior >= intervalo) {
                    estadoMaquina = 0; // vuelvo al primer estado y aseguro el parpadeo ON
                }
                break;
        }
      }
  else {
    digitalWrite(pinG1, LOW);
    digitalWrite(pinR1, LOW);
    digitalWrite(pinB1, LOW);
    estadoAnterior = estadoActual;
  }
}

void loop() {
   funcionboton1();
   funcionboton2(contador);
} 

Muchísimas gracias por tu respuesta, por otro lado me gustaría saber si habría alguna posibilidad de que estando el servo en funcionamiento (led sin parpadeo) se pudiese ignorar la interrupción del pulsador 1, es decir, que no se pueda cambiar velocidad sobre la marcha.

Sí claro, añadiendo un flag, una variable bool o condicional que controle dicha acción.

Si usáramos el código que creé cambiaríamos el switch y pondríamos un if:

tan simple cómo cambiar:

case 0 : cambiar_velocidad(); break; // primer pulsador

por:

case 0 : if(!mi_servo.activo) {cambiar_velocidad();} break; // primer pulsador

Y quedando así

//evento keydown
    if(mis_btn[i].estado != estado_actual){
      switch(i){
        case 0 : if(!mi_servo.activo) {cambiar_velocidad();} break; // primer pulsador
        case 1 : activar_servo();     break; // segundo pulsador
        //...
      }

Disculpa la demora en responder. Suelo ausentarme del foro.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.