Go Down

Topic: switch case anidados (Solucionado) (Read 734 times) previous topic - next topic

Adrian_E

Jan 13, 2018, 01:48 am Last Edit: Jan 15, 2018, 01:03 am by Adrian_E
estoy tratando de hacer funcionar un codigo con switch anidados.
lo subo resumido, el switch simple me funciona perfecto, asi que lo subo con una sola opcion ya que lo demas se refiere a 3 servos mas conectados, la inteniones que por ejemplo preciono la A deberia ir a case A. y yo cargar los grados del movimiento y asi sucesivamente, pero no me funciona ni la primera opcion "A" las demas serian repetitivas de esta. la verdad no se porque no me selecciona las opciones.
Code: [Select]

#include <Keypad.h>

#include <Servo.h>
Servo miservo;
Servo miservo2;
Servo miservo3;
Servo miservo4;


const byte Filas = 4; //KeyPad de 4 filas
const byte Cols = 4; //y 4 columnas
byte Pins_Filas[] = {33,35,37,39}; //Pines Arduino para las filas.
byte Pins_Cols[] = {41,43,45,47}; // Pines Arduino para las columnas.


char ABCD;
char pulsacion;
String valor_util = ""; // teclas digitadas
int  datos_ingresado ; // cadena de datos digitados a travez del teclado
//int numero; // datos mostrar puerto serie


char cadena[17];  // la conversion a número
 
char Teclas [Filas][Cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'.','0','#','D'}
};
 
Keypad Teclado = Keypad(makeKeymap(Teclas), Pins_Filas, Pins_Cols, Filas, Cols);
 


void setup() {

miservo.attach(5);
miservo.attach(4);
miservo.attach(3);
miservo.attach(2);


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

  ABCD = Teclado.getKey();
  pulsacion =Teclado.getKey();
 
 
 switch (ABCD) {
 case 'A' :
      switch (pulsacion) {
      case '0' ... '9':
        valor_util +=pulsacion; // se agrega a la cadena
        break;
      case '#' : // guardo los datos
        valor_util.toCharArray(cadena, 17);
        datos_ingresado = atof (cadena);
        Serial.println(datos_ingresado); // veo el angulo ingresado.
        break;
        case '*': // teclas para borrar
      valor_util ="";
        break;
         }   
case 'B':
 // miservo2
  break;

case 'C':
//miservo3
  break;
case 'D':
//miservo4
  break; 

  }
 miservo.write(datos_ingresado);
}
 

surbyte

Lo que ocurre que estas precipitando las cosas.
Code: [Select]
ABCD = Teclado.getKey();
  pulsacion =Teclado.getKey();


La primera lectura de teclado va a ABCD pero entonces deberías haberte quedado dentro de la primera selección case A: y establecer como vas a salir de esa situación.

La única forma de hacerlo es con un while y entonces debes seguir leyendo el angulo

Code: [Select]
#include <Keypad.h>
#include <Servo.h>

Servo miservo;
Servo miservo2;
Servo miservo3;
Servo miservo4;

const byte Filas = 4; //KeyPad de 4 filas
const byte Cols = 4; //y 4 columnas
byte Pins_Filas[] = {33,35,37,39}; //Pines Arduino para las filas.
byte Pins_Cols[] = {41,43,45,47}; // Pines Arduino para las columnas.

char ABCD;
char pulsacion;
String valor_util = ""; // teclas digitadas
int  datos_ingresado ; // cadena de datos digitados a travez del teclado
//int numero; // datos mostrar puerto serie


char cadena[17];  // la conversion a número
 
char Teclas [Filas][Cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'.','0','#','D'}
};
 
Keypad Teclado = Keypad(makeKeymap(Teclas), Pins_Filas, Pins_Cols, Filas, Cols);
 


void setup() {

  miservo.attach(5);
  miservo.attach(4);
  miservo.attach(3);
  miservo.attach(2);

  Serial.begin(9600);
}

void loop() {

  ABCD = Teclado.getKey();
   
  switch (ABCD) {
  case 'A' :
        while (pulsacion != '*') {
          pulsacion = Teclado.getKey();
          switch(pulsacion) { 
                case '0' ... '9':
                            valor_util +=pulsacion; // se agrega a la cadena
                            break;
                case '#' :  // guardo los datos
                            valor_util.toCharArray(cadena, 17);
                            datos_ingresado = atof (cadena);
                            Serial.println(datos_ingresado); // veo el angulo ingresado.
                            break;
                case '*':   // teclas para borrar
                            valor_util ="";
                            break;
          }   
        }
  case 'B':
            // miservo2
            break;

  case 'C':
            //miservo3
            break;
  case 'D':
            //miservo4
            break; 

  }
  miservo.write(datos_ingresado);
}

Adrian_E

subo solo una parte de codigo, me queda en un loop interminable, y ademas no me yo cargo angulo 120 por ejemplo y ahora me lo toma 1 despues 2 luego 0. le agregue un println (ABCD)  y cambie * por D. pero nunca sale de loop.
Code: [Select]
void loop() {

  ABCD = Teclado.getKey();
  Serial.println(ABCD);
   
  switch (ABCD) {
  case 'A' :
        while (pulsacion != 'D')
        {
          pulsacion = Teclado.getKey();
          switch(pulsacion) { 
                case '0' ... '9':
                            valor_util +=pulsacion; // se agrega a la cadena
                            break;
                case '#' :  // guardo los datos
                            valor_util.toCharArray(cadena, 17);
                            datos_ingresado = atof (cadena);
                            Serial.println(datos_ingresado); // veo el angulo ingresado.
                            break;
                case '*':   // teclas para borrar
                            valor_util ="";
                            break;
          }   
        }

surbyte

Entonces te malentendí. Que no funcionaba en el primer código tuyo?

Adrian_E

#4
Jan 13, 2018, 04:09 pm Last Edit: Jan 13, 2018, 04:45 pm by Adrian_E
Este codigo es con un switch de un solo nivel funciona, pero cuando lo quiero anidar como el anterior empiezan los problemas, una vez que consegui que me funcione decidi anidar para los otros servos,
 ya que switch me di cuenta que es de mucha utilidad para algunas pruebas que hago para ir aprendiendo
Code: [Select]

#include <Keypad.h>

#include <Servo.h>
Servo miservo;



const byte Filas = 4; //KeyPad de 4 filas
const byte Cols = 4; //y 4 columnas
byte Pins_Filas[] = {33,35,37,39}; //Pines Arduino para las filas.
byte Pins_Cols[] = {41,43,45,47}; // Pines Arduino para las columnas.

char pulsacion;
String valor_util = ""; // teclas digitadas
int  datos_ingresado ; // cadena de datos digitados a travez del teclado
int numero; // datos mostrar puerto serie


char cadena[17];  // la conversion a número
 
char Teclas [Filas][Cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'.','0','#','D'}
};
 
Keypad Teclado = Keypad(makeKeymap(Teclas), Pins_Filas, Pins_Cols, Filas, Cols);
 


void setup() {

miservo.attach(5);


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

  pulsacion = Teclado.getKey();

  switch (pulsacion) {
      case '0' ... '9':
        valor_util +=pulsacion; // se agrega a la cadena
        break;
      case '#' : // guardo los datos
        valor_util.toCharArray(cadena, 17);
        datos_ingresado = atof (cadena);
        Serial.println(datos_ingresado); // veo el angulo ingresado.
        break;
      case 'D': // teclas para borrar
      valor_util ="";
      //default:
        // do something
  }
 miservo.write(datos_ingresado);
}

ArduMyth

No he probado el código pero con una mirada rápida lo veo es el primer código que has puesto es que falta un BREAK como una casa en el primer switch, el case 'A',  Porque el break que está justo arriba pertenece al anidado case '*'.

Saludos.

Adrian_E

tenes razon falta la llave de cierre. y tengo unsolo miservo1.write(datos_ingresado); yaque no consigo que funcione uno, menos 4
Code: [Select]
#include <Keypad.h>
#include <Servo.h>
Servo miservo1;
Servo miservo2;
Servo miservo3;
Servo miservo4;
const byte Filas = 4; //KeyPad de 4 filas
const byte Cols = 4; //y 4 columnas
byte Pins_Filas[] = {33,35,37,39}; //Pines Arduino para las filas.
byte Pins_Cols[] = {41,43,45,47}; // Pines Arduino para las columnas.

char ABCD;
char pulsacion;
String valor_util = ""; // teclas digitadas
int  datos_ingresado ; // cadena de datos digitados a travez del teclado
//int numero; // datos mostrar puerto serie
char cadena[17];  // la conversion a número
char Teclas [Filas][Cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'.','0','#','D'}
};
Keypad Teclado = Keypad(makeKeymap(Teclas), Pins_Filas, Pins_Cols, Filas, Cols);

void setup() {
miservo1.attach(5);
miservo2.attach(4);
miservo3.attach(3);
miservo4.attach(2);
 Serial.begin(9600);
}
void loop() {

  ABCD = Teclado.getKey();
   
 
 switch (ABCD) {

 case 'A' :
        pulsacion =Teclado.getKey();
      switch (pulsacion) {
      case '0' ... '9':
        valor_util +=pulsacion; // se agrega a la cadena
        break;
     
          case '#' : // guardo los datos
        valor_util.toCharArray(cadena, 17);
        datos_ingresado = atof (cadena);
        Serial.println(datos_ingresado); // veo el angulo ingresado.
        break;
       
        case '*': // teclas para borrar
      valor_util ="";
          break;
                          }   
         
break;
       
case 'B':
 // miservo2
  break;

case 'C':
//miservo3
  break;
case 'D':
//miservo4
  break; 

 }
 
 miservo1.write(datos_ingresado);
 
}

Adrian_E

#7
Jan 13, 2018, 11:15 pm Last Edit: Jan 13, 2018, 11:49 pm by Adrian_E
este codigo me sucede lo mismo si lo hago de un nivel funciona si agrego otro nivel deja de funcionar
Code: [Select]
#include <Keypad.h>
int led_1 =8;
int led_2 =9;
int led_3=11;
int led_4 =12;

const byte Filas = 4; //KeyPad de 4 filas
const byte Cols = 4; //y 4 columnas
byte Pins_Filas[] = {33,35,37,39}; //Pines Arduino para las filas.
byte Pins_Cols[] = {41,43,45,47}; // Pines Arduino para las columnas.

char pulsacion;
char leds;

char cadena[17];
char Teclas [Filas][Cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
Keypad Teclado = Keypad(makeKeymap(Teclas), Pins_Filas, Pins_Cols, Filas, Cols);

void setup() {
 Serial.begin(9600);
pinMode(led_1, OUTPUT);
pinMode(led_2, OUTPUT);
pinMode(led_3, OUTPUT);
pinMode(led_4, OUTPUT);

}
void loop() {

pulsacion = Teclado.getKey();

switch (pulsacion) {

    case 'A' :
        leds =Teclado.getKey();
            switch (leds) {
         case '1':
              digitalWrite(led_1, !digitalRead(led_1));
              break;
         case '2':
              digitalWrite(led_2, !digitalRead(led_2));
              break;
               }
           break;           
    case 'B' :
    leds =Teclado.getKey();
      switch (leds){
      case '3':
            digitalWrite(led_3, !digitalRead(led_3));
              break;
          case '4':
            digitalWrite(led_4, !digitalRead(led_4));
              break;
               }
     
break;
        }
   
}
       
       
       
       





        }
         
 


Adrian_E

ya no se que inventar, si unas de las variables por ejemplo pulsaciones que pertenece al primer nivel, le de claro como int pulsaciones ='A'; el segundo nivel perfecto con el teclado y lo mismo con la variable leds, pero los dos juntos no me funciona.
Code: [Select]
#include #include <Keypad.h>
int led_1 =8;
int led_2 =9;
int led_3=11;
int led_4 =12;

const byte Filas = 4; //KeyPad de 4 filas
const byte Cols = 4; //y 4 columnas
byte Pins_Filas[] = {33,35,37,39}; //Pines Arduino para las filas.
byte Pins_Cols[] = {41,43,45,47}; // Pines Arduino para las columnas.



//int pulsacion ='A';
//int leds ='1';

char cadena[17];
char Teclas [Filas][Cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
Keypad Teclado = Keypad(makeKeymap(Teclas), Pins_Filas, Pins_Cols, Filas, Cols);




void setup() {
 Serial.begin(9600);
pinMode(led_1, OUTPUT);
pinMode(led_2, OUTPUT);
pinMode(led_3, OUTPUT);
pinMode(led_4, OUTPUT);

}
void loop() {
char pulsacion = Teclado.getKey();
char leds = Teclado.getKey();

//pulsacion = Teclado.getKey();
//leds = Teclado.getKey();


switch (pulsacion) {

    case 'A' :
       
            switch (leds) {

         case '1':
              digitalWrite(led_1, !digitalRead(led_1));
              break;
         case '2':
              digitalWrite(led_2, !digitalRead(led_2));
              break;
              }
              break;

    case 'B' :
   
      switch (leds){
             
      case '3':
            digitalWrite(led_3, !digitalRead(led_3));
              break;
          case '4':
            digitalWrite(led_4, !digitalRead(led_4));
              break;
               }

     
break;

        }
   
}
       
       
       
       





       
         
 



Adrian_E

arranque tempranito, con unos matecitos, pero nada reescribi el codigo me lei como hacerlo en C C# C++, hasta java  y no le veo el error.

IgnoranteAbsoluto

Señores, creo que no están teniendo en cuenta que la llamada a Teclado.getKey() no es bloqueante y retorna el valor de la tecla que se acaba de pulsar, cero si ya ha retornado ese valor con anterioridad (si se deja pulsada no la retorna sino una sola vez) o también cero si no hay ninguna tecla pulsada. Así que si hacemos dos llamadas seguidas lo más probable es que sólo una de las dos llamadas nos de un valor distinto de cero (siempre que almenos se pulse una tecla) por muy rápido que seamos pulsando más de una tecla. Asumamos pues que nunca vamos a tener como resultado dos teclas distinto a cero si realizamos dos llamadas consecutivas sin ningún tipo de espera entre ellas.

Cosa diferente sería que llamásemos a waitForKey() en lugar de getKey(). Pero esto haría que el programa estuviera detenido mientras está esperando a que pulsemos alguna tecla. Es algo similar a si usamos delay() o millis(), bloqueante vs. no bloqueante. Así que o se utiliza la versión bloqueante (waitForKey()) o no tendremos más remedio que usar la técnica de la máquina de estados, por muy pocos estados que deba de tener.

Para la máquina de estado necesitaremos una variable que nos indique en qué estado estamos y variables auxiliares para almacenar valores "temporales" del resultado.

Supongamos que lo que se quiere es que mediante un teclado de 16 teclas (los dígitos del '0' al '9', letras de la 'A' a la 'D', el '*' y el '#') indicar el ángulo al que queremos posicionar cuatro servos que "etiquetamos" de la 'A' a la 'D' en un ángulo de 0 a 180 grados. Para ello hemos de pulsar primero la letra que "identifica" el servo a posicionar. Luego una cantidad arbitrarias de dígitos del '0' al '9' para indicar los grados y por último la tecla '#' para confirmar que ya hemos tecleado los valores deseado y que ejecute el posicionamiento del servo según esos valores.

Cosas a tener en cuenta, si entre que pulsamos la letra y el '#' no hemos pulsado ningún dígito del '0' al '9' asumiremos que queremos posicionarlo a 0 grados. Si entre la letra y el '#' pulsamos más de tres dígitos sólo tendremos en cuenta los últimos tres dígitos (si se teclea 'A13025#' se comportará como si se hubiera pulsado 'A025#' con lo que posicionaría el servo 'A' a 25 grados. Si no se ha pulsado ninguna letra y se pulsa '#' no se hará nada y será como si no se hubiera pulsado nada en ningún momento. Si se empieza pulsando dígitos del '0' al '9' sin haber pulsado antes ninguna letra, no se tendrán en cuenta y será como si no se hubiera pulsado nada. Si en cualquier momento se pulsa una letra de la 'A' a la 'D' se descartará todo lo pulsado hasta ese momento y se considera la letra pulsada (El pulsar 'A123B054#' sería como si sólo se hubiera pulsado 'B054#'). Si se pulsa cualquier otra tecla que no sean los dígitos del '0' al '9', las letras de la 'A' a la 'D' o el '#' se "cancelará" la entrada de datos y volverá a esperar a que se pulse una letra de la 'A' a la 'D'.

Hemos indicado que sólo los tres últimos dígitos del '0' al '9' que se han tecleado son los que se van a tener en cuenta ya que el valor máximo del ángulo ha de ser 180 grados. Si el valor tecleado supera esa cantidad, asumiremos el máximo (180).

Ahora que tenemos más o menos claro cómo queremos que funcione, vemos que la máquina de estado no ha de controlar sino si está esperando por la letra inicial o por el resto (dígito del '0' al '9' o el '#'). Como variables auxiliares necesitamos una para guardar la letra que identifica el servo y otra para guardar el valor del ángulo que se ha tecleado. Para la máquina de estado nos vale un simple boolean que nos indica si ya tenemos una letra o no. Para guardar la letra que se ha pulsado nos basta con una variable de tipo char. Y para el valor del ángulo en principio parece que nos podría valer una variable de tipo byte ya que nos permitiría guardar un valor entre 0 y 255, pero mejor si utilizamos una variable de tipo int ya que en algún momento podríamos tener un valor mayor de 255 (si por ejemplo tecleamos 'A999#' el valor sería 999) y nos será más fácil controlar que supera los 180 grados después.

Realmente la variable que controla el estado de la máquina de estado nos la podríamos ahorrar si usamos un valor no válido para la variable que almacena la letra pulsada. Ese valor nos indicaría que aún estamos esperando una letra. Pero tal vez más adelante queramos controlar la entrada de otros tipos de datos mediante el teclado con lo cual la máquina de estado debería de tener más estados. Así que lo mejor es usar una variable independiente para controlar la máquina de estados. Yo, personalmente, suelo utilizar un tipo enumerado para la variable que controla la máquina de estados. Ya sé que ahora es muy sencilla (sólo tiene dos estados posibles), pero puede que en el futuro el programa necesite hacer más cosas o incluso que queramos usar un tercer estado que nos indique que ya tenemos un valor correcto porque no vamos a usarlo y "descartarlo" sobre la marcha.

IgnoranteAbsoluto

Posible implementación de mi propuesta:

Llamemos estado a la variable que guarda el estado de la máquina. A la que guarda la letra la llamamos letra y a la que guarda el ángulo la llamamos cantidad. Yo declararía las tres variables globales algo tal que así:

Code: [Select]

enum estado_t {
  ESTADO_ESPERANDO_LETRA,
  ESTADO_ESPERANDO_DIGITO
};

estado_t estado = ESTADO_ESPERANDO_LETRA;
char letra;
int cantidad;


Creo el tipo enumerado estado_t e inicializo la variable estado con el valor ESTADO_ESPERANDO_LETRA ya que al inicio aún no tenemos ninguna letra definida. Las otras dos variables no son nesesarias inicializarlas con algún valor ya que no se deben utilizar hasta que no cambiemos al estado ESTADO_ESPERANDO_DIGITO y en el momento del cambio es cuando estableceremos el valor de letra y pondermos a cero el valor de cantidad.

Ahora lo que deberíamos de tener es algo así como:

Code: [Select]

loop() {
  char tecla = Teclado.getKey()
  switch (tecla) {
    case 'A' ... 'D' :  // Se ha pulsado una letra
      letra = tecla;                     // Ya sabemos qué servo es el que se quiere accionar, lo guardamos
      cantidad = 0;                      // Iniciamos a cero la cantidad
      estado = ESTADO_ESPERANDO_DIGITO;  // Pasamos al estado en se espera a que se ingrese la cantidad
      break;  // Salimos del switch (tecla)

    case '0' ... '9' :  // Se trata de un dígito, así que actualizamos la cantidad
      // No hace falta verificar en que estado estamos ya que si no estamos en ESTADO_ESPERANDO_DIGITO el valor de cantidad no se usará
      cantidad = ((cantidad * 10) + tecla - '0') % 1000; // Desplazamos un dígito a la izquierda (* 10), le sumamos valor la tecla pulsada (+ tecla - '0'), y nos quedamos con los tres dígitos menos significativos (% 1000) al obtener el resto de dividirlo entre 1000
      break;  // Salimos del switch (tecla)

    case '#' :  // Se confirman los valores pulsando el '#'
      if (estado == ESTADO_ESPERANDO_DIGITO) { // Si ya se había ingresado una letra (está esperando por un dígito) procedemos con el valor que tenemos
        cantidad = min(cantidad, 180);       // Nos aseguramos que cantidad valga como máximo 180
        switch (letra) {
          case 'A' :
            miservo.write(cantidad);     // Posicionamos el servo deseado en el ángulo indicado
            break;  // Salimos del switch (letra), pero no del switch (tecla)
          case 'B' :
            miservo2.write(cantidad);    // Posicionamos el servo deseado en el ángulo indicado
            break;  // Salimos del switch (letra), pero no del switch (tecla)
          case 'C' :
            miservo3.write(cantidad);    // Posicionamos el servo deseado en el ángulo indicado
            break;  // Salimos del switch (letra), pero no del switch (tecla)
          case 'D' :
            miservo4.write(cantidad);    // Posicionamos el servo deseado en el ángulo indicado
            break;  // Salimos del switch (letra), pero no del switch (tecla)
        }
      }
      // Ojo, no salimos del switch (tecla) ya que lo siguiente queremos que lo haga también en el caso de ser '#'
    default:
      estado = ESTADO_ESPERANDO_LETRA;    // Si se ha pulsado '#' o cualquier techa no contemplada hasta ahora, pasa al estado de esperar una letra
      break;  // Salimos del switch (tecla). Realmente este break no es necesario ya que no hay más casos
  }
}


En el código se comenta qué hace y porqué. Puede resultar algo "esotérica" la instrucción cantidad = ((cantidad * 10) + tecla - '0') % 1000; por lo que si no se comprende me lo dicen y trato de explicarla.

También hay que tener en cuenta que no hay un break; al final del caso '#' ya que se va a asignar igualmente el valor ESTADO_ESPERANDO_LETRA a la variable estado una vez hecho todo lo anterior, así como si la tecla pulsada no es ninguna de las ya consideradas en el switch, por eso el default:.

No lo he probado, no tengo teclado para ello, pero en teoría debería de funcionar. Claro está que falta el resto del código (el setup(), la declaración de algunas variables e inicialización, etc).

Adrian_E

entonces por lo que vos comentas una variable boolean seria la solucion??

IgnoranteAbsoluto

#13
Jan 14, 2018, 05:03 pm Last Edit: Jan 14, 2018, 05:03 pm by IgnoranteAbsoluto
Creo que no has visto que cinco minutos después de mi primera respuesta he puesto una propuesta. Es que no me cabía todo en uno, superaba los 9000 caractéres.

Adrian_E

#14
Jan 14, 2018, 05:52 pm Last Edit: Jan 14, 2018, 05:53 pm by Adrian_E
 :smiley-confuse:   :o , voy a ver si lo puedo implementar  primero con los leds, que hay cosas como esto
Code: [Select]
enum estado_t {
  ESTADO_ESPERANDO_LETRA,
  ESTADO_ESPERANDO_DIGITO
};


ni lo sabia, va al comienzo del skecht?

Go Up