Go Down

Topic: Problema con while(serial.available) (Read 243 times) previous topic - next topic

mxt08

Oct 03, 2018, 06:44 pm Last Edit: Oct 03, 2018, 07:18 pm by surbyte Reason: Agregado de etiquetas de código
Hola, mi problema es el siguiente:

Estoy utilizando un sensor infrarrojo para medir la velocidad de un motor DC, midiendo con interrupciones los pulsos que el eje del motor genera. Esa parte del código funciona con normalidad.

El tema es que programé un menú para que el usuario ingrese la velocidad inicial del motor (del 0 al 9, representando diferentes duty cycle para el motor). Para esperar a que el usuario ingrese un valor, utilicé
while (!Serial.available());, el cual efectivamente funciona y espera a que el usuario ingrese un valor. Hecho esto, procede al código principal, el cual en función a un swtich...case realiza las funciones de medición y arroja el valor en RPM. Hasta ahí, sin problemas. El tema es que quiero que cuando acabe una medición, se muestre el menú nuevamente y permita ingresar otro valor del 0 al 9 para realizar alguna otra medición de velocidad.

En el ejemplo, utilicé el valor de val=9 (el selector de velocidad), lo cual funciona con normalidad. Una vez terminada la medición, asigné a val el valor de 10 (val=10), para que así pueda ingresar otra vez al menú. El problema viene aquí: al abrir el menú por segunda vez, ya no espera en el monitor serial a que el usuario ingrese un valor, sino que automáticamente asigna a val el valor con el cual lo reinicié previamente (val=10), lo cual arroja un resultado en el switch...case incorrecto. Luego de ello, el menú se vuelve a abrir, esta vez sí esperando a que el usuario ingrese un número.

Quisiera saber qué es lo que está mal en mi código, pues solo quiero que se muestre el menú una vez se finalice una medición y este espere a que el usuario ingrese un valor para val, no que se quede con un valor previamente asignado.

Adjunto mi código y el resultado en el monitor serial.

Code: [Select]


int sensorpin = 2; // define pint 2 for sensor
volatile byte pulsos = 0;
unsigned int resolucion = 2;

unsigned int rpm;

int interruptor = 0;
int out1 = 5;

int val;

void isr() {

  pulsos = pulsos + 1;

}

void menu() {

  Serial.println("Ingrese velocidad del motor (0-9):");

  while (!Serial.available());          //Espero a un ingreso del usuario

  if (Serial.available()) {               //Leo el ingreso del usuario y lo asigno a val.
    val = Serial.read();
  }

  Serial.flush();                            //No sé si sea adecuado, pero agregué flush para limpiar el buffer.

}

void setup() {

  Serial.begin(9600);
  Serial.println("Sistema iniciado.");

  pinMode(sensorpin, INPUT_PULLUP);
  attachInterrupt(interruptor, isr, RISING);

  pinMode(out1, OUTPUT);

  pulsos = 0;
  rpm = 0;


}

void loop() {

  menu();                                                         //En el inicio de cada loop, llamo a menu().
  
  Serial.print("Velocidad escogida:  ");
  Serial.println(val - 48, DEC);
  delay(1000);

  switch (val) {
    case '9':
      analogWrite(out1, 255);
      delay(50);
      analogWrite(out1, 255);
      Serial.println("Speed is = 9");

      Serial.println("Calculando velocidad...");

      delay(5000);

      rpm = (pulsos / resolucion);

      Serial.print("La velocidad en RPM es:");
      Serial.print("  ");
      Serial.println(rpm, DEC);

      pulsos = 0;
      rpm = 0;                                                 //Hasta aquí funciona tal y como quiero, sin problemas.
      val=10;                                                   //Le doy un nuevo valor a val, el cual debería ser
                                                                        reemplazado en la siguiente llamada al menu en el
                                                                        nuevo inicio del loop, sin embargo en el menu no se
                                                                       lee ningún valor para asignar a val, sino
                                                                       automáticamente le da este valor val =10.
      break;

    default:
      Serial.println("Valor incorrecto.");
      break;

  }

  Serial.flush();
  Serial.println("----------------------------------------------------");
}




Quote
Monitor serial:
Sistema iniciado.
Ingrese velocidad del motor (0-9):
Velocidad escogida:  9
Speed is = 9
Calculando velocidad...
La velocidad en RPM es:  9
----------------------------------------------------         Hasta aquí todo funciona correctamente.
Ingrese velocidad del motor (0-9):                          Aquí se muestra el menú para una nueva medición.
Velocidad escogida:  -38                                         ...y no espera a que el usuario ingrese un valor,
                                                                            sino que le asigna automáticamente -38.
Valor incorrecto.
----------------------------------------------------
Ingrese velocidad del motor (0-9):                           Luego, se vuelve a mostrar el menú, esta vez si
                                                                             esperando un valor del usuario.


surbyte

Esta reaccionando a dos caracteres que no ves que son

carriage return ASCII 13 o '\r'
line feed ASCII 10 o '\n'

mxt08

Disculpa, no estoy muy familiarizado con este entorno de programación.

Cómo podría adicionar tu sugerencia a mi código para que este funcione correctamente?

Gracias de antemano.

surbyte

Acabo de corregir tu código pero me dio algun trabajito

Code: [Select]
const byte sensorpin = 2; // define pint 2 for sensor
volatile unsigned int pulsos = 0;
unsigned int resolucion = 2;

unsigned int rpm;

const byte interruptor = 0;
int out1 = 5;
int val;
bool flag = false;

void isr() {

  pulsos = pulsos + 1;

}

void setup() {

  Serial.begin(9600);
  Serial.println("Sistema iniciado.");

  pinMode(sensorpin, INPUT_PULLUP);
  attachInterrupt(interruptor, isr, RISING);
  pinMode(out1, OUTPUT);
  pulsos  = 0;
  rpm     = 0;
  flag    = true;
}

void loop() {

  if (flag) {
      Serial.println("Ingrese velocidad del motor (0-9):");
      flag = false;
  }

  while (Serial.available()) {
      val = Serial.read();
      if (val != '\n' && val != '\r') {
          Serial.print("Velocidad escogida:  ");
          Serial.println(val, HEX);
          switch (val) {
            case '9':
                      analogWrite(out1, 255);
                      delay(50);
                      analogWrite(out1, 255);
                      Serial.println("Speed is = 9");
                      Serial.println("Calculando velocidad...");
                      delay(5000);
                      rpm = (pulsos / resolucion);
                      Serial.print("La velocidad en RPM es:");
                      Serial.print("  ");
                      Serial.println(rpm, DEC);
                      pulsos  = 0;
                      rpm     = 0;       // Hasta aquí funciona tal y como quiero, sin problemas.
                      val     = 10;      // Le doy un nuevo valor a val, el cual debería ser
                                         // reemplazado en la siguiente llamada al menu en el
                                         // nuevo inicio del loop, sin embargo en el menu no se
                                         // lee ningún valor para asignar a val, sino
                                         // automáticamente le da este valor val =10.
                      break;
            default:
                      Serial.println("Valor incorrecto.");
                      break;

          }
          flag = true;
      }
  }                                                       
}

mxt08

Realmente solucionó mi problema, muchas gracias!

Por otro lado, ya veo que debo jugar con valores booleanos para que el menu no salte intempestivamente, además verificar que val no sea val != '\n' o val != '\r'.

surbyte

Exacto, cada vez que digitas algo llegan 3 cosas, tu dígito ASCII supongamos '9' que no es 9, pero tambien llega 0x0d y 0x0a expresado en Hexadecimal.

De modo que tienes que bypasearlos para que no te molesten.
Cuando dije que me llevo un momento, fue porque en cada vez que digitaba algo me llegaban 3 respuestas incluso mas.. porque cuando no se piensa se hacen tonterias.

Luego me detuve, pude bloquear los datos molestos CR y LF y me quedé con el importante.

mxt08

Me he topado con un pequeño problemilla:

Intento hacer ahora un programa con la misma idea, pero que en este caso espere a dos ingresos consecutivos del usuario, para luego proceder a realizar operaciones en función a lo que el usuario ingrese, similar a esto:

Simulación de monitor serial deseado:
Code: [Select]


Ingrese valor 1:
//Usuario ingresa valor 1.
//El programa debe esperar a que el usuario ingrese el dígito por el monitor serial, y no ejecutar ninguna otra acción hasta que algún valor haya sido ingresado.
Ingrese valor 2:
//Usuario ingresa valor 2.
//El programa debe esperar a que el usuario ingrese el dígito por el monitor serial, y no ejecutar ninguna otra acción hasta que algún valor haya sido ingresado.

//Solo después de que ambos valores hayan sido ingresados, procede:

//Código para las operaciones con los valores.

//Una vez las operaciones han finalizado, vuelve a solicitar dos nuevos valores al usuario para realizar nuevas operaciones.

Ingrese valor 1:
//Usuario ingresa valor 1.
.
.
.
.
.



He intentado anidar el código que me sugirió @surbyte, de la siguiente manera:

Code: [Select]



void loop(){

  if (flag1) {
    Serial.println("-------------------------------------------------");
    Serial.println("Ingrese val1:");
    flag1 = false;
  }

  while (Serial.available()) {
    val1 = Serial.read();
    if (val1 != '\n' && val1 != '\r') {
      Serial.print("Val1 =    ");
      Serial.println(val1);
      flag1 = true;
    }
  }

  if (flag2) {
    Serial.println("-------------------------------------------------");
    Serial.println("Ingrese val2:");
    flag2 = false;
  }

  while (Serial.available()) {
    val2 = Serial.read();
    if (val2 != '\n' && val2 != '\r') {
      Serial.print("Val2 =    ");
      Serial.println(val2);
      flag2 = true;
    }
  }


O de la siguiente manera:

Code: [Select]


void loop(){

  if (flag) {
    Serial.println("-------------------------------------------------");
    Serial.println("Ingrese velocidad del motor (0-9):");
    flag = false;
  }

  while (Serial.available()) {
    val = Serial.read();
    if (val != '\n' && val != '\r') {

       if (flag) {
         Serial.println("-------------------------------------------------");
         Serial.println("Ingrese velocidad del motor (0-9):");
         flag = false;
       }

       while (Serial.available()) {
         val = Serial.read();
         if (val != '\n' && val != '\r') {

          //Código de operaciones

         flag2=true;

         }
     }

     flag1=true;
}
}
}





Pero ambas sin éxito alguno. Alguna idea de cómo podría lograrlo? Muchísimas gracias de antemano.

ArduMyth

Quote
Intento hacer ahora un programa con la misma idea, pero que en este caso espere a dos ingresos consecutivos
A ver, lo que surbyte hace con los flags (booleans) no tiene nada que ver con lo que tu requieres ahora.
Lo que planteaste inicialmente era una cosa y esto otra.
El quid es que cuando te exponen un ejemplo lo entiendas, porque que lo otro se solucionara con una variable global bool no significa que esto sea una varita mágica para cada problema.

Fíjate en tu mismo planteamiento. Necesitas 2 caracteres consecutivos y esto lo puedes saber sumando...
Es decir necesitas un número, un contador que se incremente a cada caracter introducido.

Go Up