Leer varios datos desde el puerto de serie.

LLevo un tiempo intentando hacer esto, he buscado mucho, y en ninguno de los ejemplos lo he visto, asi que no estoy seguro de que sea posible.

El caso es que tengo 2 motores paso a paso conectados al arduino, que funcionan perfectamente. Quiero enviar desde el puerto de serie al arduino varios datos, para que los motores se muevan, concretamente quiero enviar 4 datos (la velocidad, y la posicion de los dos motores)

Pero desde el puerto de serie solo consigo enviar un solo dato. He probado con if’s con while y cualquier tipo de loop y no consigo leer mas de un valor. Tambien he pensado de enviar un numero muy grande y luego separarlo para dar la posicion y velocidad a cada uno de los motores, pero no lo he conseguido.

Esta es una de mis ultimas pruebas fallidas:

//en este caso solo hay un stepper (para simplificar)
//y quiero darle dos valores, la velocidad y la posicion (en pasos)
#include <Stepper.h>


#define STEPS 120
Stepper stepper(STEPS, 8, 9, 10, 11); 

int valor = 0;
int lectura[2]={0}; //un array para almacenar los datos

void setup()
{

  Serial.begin(9600); //velocidad de comunicacion a 9600 baudios.
 Serial.println("0-Velocidad, 1-pasos");
  
}

void loop()
{
   
  while(valor <= 1){
   if(Serial.available() ){
     lectura[valor] = Serial.read();
     Serial.println(valor);
     Serial.flush();
     valor++;
     delay(1000);
     
     
     }
  }
  if(valor >= 1){
    valor = 0;
  stepper.setSpeed(lectura[0]);
  stepper.step(lectura[1]);
  }
  }

Mi arduino usa un atmega 8 y se comunica por puerto de serie.
Saludos.

Mira, justamente un código mío hacia eso (aunque enviaba velocidad y dirección):

void loop()
{
  if(Serial.available()>2)
    if(Serial.read()==0xEE)
      {
        int val_s = Serial.read(), val_t = Serial.read();

        if(val_s!=0xFF)
          steer(map(val_s,0,90,-45,45));

        if(val_t!=0xFF)
          throttle(map(val_t,0,200,-100,100));
      }
}

Primero, se manda 0xEE como "inicio del paquete de control", luego un byte que define la dirección, va de 0 a 90º en decimal, pero como byte es decir de 0x00 a 0x5A lo que se convierte en la rotación de un motor desde -45, 0 y 45 grados.

El último byte es la velocidad de 0 a 200, en donde 100 es detenido, 200 máxima velocidad hacia adelante y 0 es máxima hacia atrás, así es un valor desde 0x00 a 0xC8.

Si te das cuenta, siempre debes enviar ambos valores pero si quieres puedes omitir uno colocando 255 como valor, por ejemplo para detener el vehículo manteniendo la última rotación de las ruedas sería: 0xEE, 0xFF, 0x64.

Un ejemplo de la rotación utilizada anteriormente:

#define SERVO_STEERING 11
#define CENTER_OFFSET -10

// Recibe un e1 ángulo de giro, valores desde -45 a 45 grados
void steer(int angle)
{
  // Control de dirección
  analogWrite(SERVO_STEERING,map(-angle-CENTER_OFFSET,-45,45,100,240)); 
}

Primero gracias por tu ayuda. Hay partes del codigo que no entiendo muy bien (llevo poco tiempo con arduino).

if(Serial.available()>2)

Por que mayor que dos?

if(Serial.read()==0xEE)
      {

Esto bien, un condicional para ver si se recibe 0xEE.

int val_s = Serial.read(), val_t = Serial.read();

Mi pregunta es si arduino esperara a recibir un valor, es decir, que hasta que no lo reciba no continuara o continuara con lo que halla recibido en ese momento, y si no ha recibido nada pondra 0.

Esa es mi principal duda. Te preguntaras porque no lo pruebo yo mismo, en vez de preguntar. Voy a pasar unos dias con este ordenador que no tiene puerto de serie (y mi arduino es la version en una protoboard con cable serial).

Saludos y Gracias.

El puerto serie tiene un “buffer”, por eso pregunto available, es decir hay más de 2 bytes? digamos 3…

Si hay más compruebo de que el primero sea 0xEE (que es como mi flag de inicio). Se puede hacer óptimo pues este escenario no es muy útil en caso de que se pierda por ejemplo un 0xEE, en ese caso la segunda instrucción quedaría encolada:

0xEE, 0x00, 0x00 ← instrucción original

0x00, 0x00 ← instrucción recibida (en caso de pérdida)

Entonces por

if(Serial.available()>2)

nunca lo leeríamos, así una 2da instrucción:

0x00, 0x00, 0xEE, 0x00, 0x00

comeríamos 0x00, 0x00 “limpiando” el buffer y volviendo a la normalidad

En este caso podría hacerse de mejor forma, o para asegurar que no exista nunca una pérdida podría mandarse un 0xEE, 0xFF, 0xFF al finalizar.

Nunca se quedará bloqueado, y si no hay comandos no hará ningún cambio.