El valor del Pin Arduino se atasca

1

Estoy usando un programa Python para enviar un mensaje a través de un puerto serie a Arduino. Este mensaje contiene el número de pin del pin y si debe ser HIGH o LOW . Por ejemplo: enviar 2H\n debe establecer el pin 2 a HIGH .

pins array asigna los números de pin en los mensajes al número de pin real de arduino. 1H corresponde al pin 22 en Arduinio Mega.

Al enviar manualmente un mensaje a la vez, las cosas funcionan bien. Sin embargo, cuando Python envía una serie de 30 mensajes de este tipo uno tras otro en un bucle sin retrasos, el pin 1 siempre se atasca en el valor que se establezca en la primera serie de mensajes.

Ejemplo:

1L\n
2H\n
3H\n
4H\n
5H\n
...

seguido de

1H\n
2H\n
3H\n
4H\n
5H\n
...

hará que el pin 1 se atasque en LOW cuando debería estar alto.

En arduino, este es el código que analiza el mensaje y establece los valores de pin.

void setPinValues(String message) {

  for(int i = 1; i <= sizeof(pins) / sizeof(pins[0]); i++ ) {
    String pinNumber = String(i);

    if( message == pinNumber + "H\n" ) {
      pinValues[i] = HIGH;
    }
    if( message == pinNumber + "L\n" ) {
      pinValues[i] = LOW;
    }
  }

}


void loop(){
    if( Serial.available() > 0 ) {
        received = Serial.read();
        message += received;
        if(received == '\n') {

            // Set pin values
            setPinValues(message);

            // Write to pins        
            for (int i = 1; i <= sizeof(pins) / sizeof(pins[0]); i++) {
                digitalWrite(pins[i], pinValues[i]);
            }

            // Clear buffer
            message = "";

        }       

    }

}

Arduino Mega se comunica con el sistema Windows 8 x64 a través de USB utilizando una velocidad de transmisión de 57600. Cuando se utiliza una velocidad de transmisión de 9600, este problema no se ve.

Además, a una velocidad en baudios de 57600, si tuviera que reemplazar setPinValues con el siguiente código, el pin 1 está correctamente activado y desactivado.

void setPinValues(String message) {

  for(int i = 1; i <= sizeof(pins) / sizeof(pins[0]); i++ ) {
    if( message == String(1) + "H\n" ) {
      pinValues[1] = HIGH;
    }
    if( message == String(1) + "L\n" ) {
      pinValues[1] = LOW;
    }
    if( message == String(2) + "H\n" ) {
      pinValues[2] = HIGH;
    }
    if( message == String(2) + "L\n" ) {
      pinValues[2] = LOW;
    }
    if( message == String(3) + "H\n" ) {
      pinValues[3] = HIGH;
    }
    if( message == String(3) + "L\n" ) {
      pinValues[3] = LOW;
    }
  }

}

¿Las dos versiones de setPinValues hacen lo mismo? ¿Por qué la reducción de la velocidad de transmisión evita el problema? No puedo usar una velocidad en baudios más baja porque el búfer USB se llena y las cosas se vuelven más lentas.

Para comparar el último carácter H o L :

String pinValueString = message.substring(message.length() - 1);
char pinValueBuffer[2];
pinValueString.toCharArray(pinValueBuffer,2);

if(pinValueBuffer[0] == 'H') {
    digitalWrite(pins[pinNumber], HIGH);
}
    
pregunta Nyxynyx

2 respuestas

7

No estoy seguro de si este es tu problema, pero setPinValues me parece extraño:

void setPinValues(String message) {
  for(int i = 1; i <= sizeof(pins) / sizeof(pins[0]); i++ ) {
    String pinNumber = String(i);

    if( message == pinNumber + "H\n" ) {
      pinValues[i] = HIGH;
    }
    if( message == pinNumber + "L\n" ) {
      pinValues[i] = LOW;
    }
  }
}

Salir fuera de límites

Cada vez que llame a setPinValues , i variará de 1 a length(pins) , entonces si pins se declaró como pins[5] , i será 1 , 2 3 , 4 y 5 . Suponiendo que length(pins) == length(pinValues) esto es un problema en sí mismo, ¡porque pinValues[5] ni siquiera existiría!

pinValues[5] solo crea pinValues[0] a pinValues[4] (sí, sé que es raro, estás declarando 5 elementos pero, dado que C tiene un índice de 0, son 0 , 1 , 2 , 3 y 4 ), por lo que i no debería NUNCA llegar a 5 o estará fuera de los límites, lo que es un comportamiento indefinido (y bien podría ser la fuente de sus problemas) porque estás escribiendo en la ubicación de memoria incorrecta.

La forma correcta de hacer esto es pasar de 0 a i < sizeof(pins) / sizeof(pins[0]) (observe que estricto es menos que el operador < ) que varía de 0 a length(pins) - 1 y luego solo String pinNumber = String(i + 1); . De esa manera, 1H cambiará el valor de pinValues[0] , asignando sus mensajes seriales indexados 1 a arreglos C indexados 0.

No es necesario bucear

No estoy seguro de por qué estás haciendo un bucle sobre pins . Estás haciendo un trabajo innecesario y probablemente acapare la unidad de usuario (especialmente porque, como señala Dave Tweed en la otra respuesta, estás usando funciones caras como String y comparación de cadenas con == ).

message tiene una sola instancia, por ejemplo, 1H\n , por lo que no se necesita un bucle. char pinNumber = message[0] - '0'; almacenará el valor entero del primer carácter en pinNumber , con el que podrá indexar la matriz.

¿Cómo funciona eso?

  • message[0] sería un tipo char (por ejemplo, '1' )
  • '0' también es un char , que corresponde al valor ASCII de 0 (48 en decimal).
  • Si message[0] contiene el char '0' , entonces el resultado es '0' - '0' == 48 - 48 == 0
  • Como los números son contiguos y aumentan en el conjunto ASCII , el resultado de la resta es el número real como un entero de un solo byte.
  • '1' - '0' == 49 - 48 == 1 y sigue y sigue.

También es posible que desee rechazar entradas falsas:

if (pinNumber >= sizeof(pins) / sizeof(pins[0]))
  return;

Trabajo más falso

En cada iteración loop() haces esto:

// Write to pins        
for (int i = 1; i <= sizeof(pins) / sizeof(pins[0]); i++) {
  digitalWrite(pins[i], pinValues[i]);
}

Que tiene el mismo problema con los fuera de los límites que antes.

También hace un trabajo innecesario, ya que estás escribiendo TODOS los valores de pin, ya sea que hayan cambiado o no. ¿Por qué no digitalWrite(pins[pinNumber], HIGH or LOW); directamente en setPinValues y evita este bucle? Incluso podría deshacerse de la matriz pinValues si realmente no necesita almacenarlos (o puede conservarlo si lo necesita por alguna razón).

Mi setPinValues alternativo

void setPinValue(char pin, char value) {
  char pinNumber = pin - '0';  // Get the integer value of the ASCII char

  if (pinNumber >= sizeof(pins) / sizeof(pins[0]))  // Reject out-of-bounds input
    return;

  switch (value) {
    case 'H':
      pinValues[pinNumber] = HIGH;  // Not necessary if you don't want to store the pin values
      digitalWrite(pins[pinNumber], HIGH);
      break;
    case 'L':
      pinValues[pinNumber] = LOW;  // Not necessary if you don't want to store the pin values
      digitalWrite(pins[pinNumber], LOW);
  }
}

Y luego simplemente llámalo desde loop() como setPinValue(message[0], message[1]);

Hazme saber si esto resuelve tu problema.

    
respondido por el DuckTyped
4

Es un problema de rendimiento. La primera versión de setPinValues() realiza muchas llamadas a String() cada vez que se llama, y esta es una función no trivial. Esto hace que setPinValues() demore mucho más tiempo de lo que cree que termine, por lo que no es muy sorprendente que el Arduino finalmente no pueda mantenerse al día con los mensajes entrantes a 57600 bps.

En la segunda versión de setPinValues() , los argumentos para las llamadas String() son constantes, por lo que se evalúan en el momento de la compilación. Esta versión se ejecuta mucho más rápido, y es capaz de mantenerse a 57600.

    
respondido por el Dave Tweed

Lea otras preguntas en las etiquetas