La impresión en serie de Arduino cambia el comportamiento del programa indeseablemente

10

Estoy usando un contador de bucle, declarado en un encabezado:

int loop_counter = 0;

Uso este contador para activar un evento cada cierto tiempo. Solía ​​usar un módulo para este mismo tipo de comportamiento, pero lo simplifiqué para que sea más fácil trabajar con él (todavía resulta en el mismo comportamiento)

void loop() {
    if(loop_counter > 100) loop_counter = 0;
    else loop_counter++;

    //Serial.println("hey");

    if(loop_counter == 0) {
         //do_something_important();
    }      
}

Todo está bien, hasta que trato de comunicarme sin Serialcomentar el //Serial.println("hey"); ( "hey"en este ejemplo porque, para mí, este comportamiento es absurdo).

Esto da como resultado que loop_counternunca se active la do_something_important();sección de código. Traté de declarar loop_counterque volatileeso no cambió nada. Probé Serial.printing loop_counter, y también estaba recibiendo un comportamiento extraño (que congelaría el bucle). Serial.println("hey");funciona en el sentido de que en el monitor de serie obtengo un montón de "hey" (es decir, rápidamente más de 100 "heys", la cantidad de iteraciones en las que debería activarse la otra sección del código)

¿Qué podría estar causando el uso de Serial, con datos que no están (por lo que puedo decir) vinculados para loop_counterevitar que funcione correctamente?

EDITAR : Aquí está la parte del archivo principal que terminó presentando el problema (bueno, contribuyendo al máximo (usando demasiada memoria)):



void display_state() {
  int i,j,index=0;
  short alive[256][2];

 for(i=0;i<num_rows;i++) { 
   for(j=0;j<num_cols;j++) {
     if(led_matrix[i][j]==1) { 
       alive[index][0]=i;
       alive[index][1]=j;
       index++;
     }
   }
 }
 alive[index][0]=NULL; //Null-terminate.
 alive[index][1]=NULL;

 //383 is a great number
 for(int idx=0;idx < index; idx++) {
   display(alive[idx][0],alive[idx][1]);
   delayMicroseconds(283);
 }
}

Aquí está "cartas.h":


    #ifndef _MY_LETTERS_H
    #define _MY_LETTERS_H

#define nrows 4
#define ncols 4

#define num_rows 16
#define num_cols 16

#define MAX_WORD_LENGTH 16
#define NUMBER_OF_CHARACTERS 26

#include <stdlib.h>

int loop_counter = 0 ; short led_matrix [ num_rows ] [ num_cols ];

const short letter_a [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 0 }, { 1 , 0 , 0 , 1 }, { 1 , 1 , 1 , 1 }, { 1 , 0 , 0 , 1 } }; const short letter_b [ nrows ] [ ncols ] = {{ 1 , 0 , 0 , 0 }, { 1 , 1 , 1 , 0 }, { 1 , 0 , 1 , 0 }, { 1 , 1 , 1 , 0 }}; const short letter_c [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 1 }, { 1 , 0 , 0 , 0 }, { 1 , 0 , 0 , 0 }, { 0 , 1 , 1 , 1 }}; const short letter_t [ nrows ] [ ncols ] = {{ 1 , 1 , 1 , 1 }, { 0 , 1 , 0 , 0 }, { 0 , 1 , 0 , 0 }, { 0 , 1 , 0 , 0 } };

typedef struct letter_node { const short * data ; letra_nodo * siguiente ; int x ; int y ; } letra_nodo ;

letter_node aa = {&letter_a[0][0],NULL,1,1}; letter_node bb = {&letter_b[0][0],NULL,1,1}; letter_node cc = {&letter_c[0][0],NULL,1,1}; letter_node tt = {&letter_t[0][0], NULL , 1 , 1 };

carta_nodo carta_mapa [ NUMBER_OF_CHARACTERS ]; #terminara si

Alguna información más: - Estoy usando un Uno (ATMega328)

eqzx
fuente
¿Cuál es el tamaño de tu pila? ¿Existe la posibilidad de que pueda pintar su pila y ver si se está corrompiendo? ¿La impresión en serie utiliza interrupciones, es su código reentrante?
Ktc
La impresión en serie no se activa por ninguna interrupción, solo la uso en la loop()función. ¿Cómo debo pintar mi pila si el único método de salida que tengo ( Serial.print()) me falla?
eqzx
2
Para eliminar posibles errores y efectos secundarios malinterpretados de cambios aparentemente triviales, reemplace el código en su pregunta con una copia literal y exacta de caracteres de un boceto reducido al mínimo necesario para desencadenar el problema . No "este es mi programa que falla si yo ...", sino exactamente el programa mínimo que falla de esta manera.
Chris Stratton

Respuestas:

2

También tuve un problema similar a este, y estoy muy seguro de que el tuyo también está fuera del espacio de la pila relacionado. Intenta reducir el código tanto como sea posible.

En mi caso, el código a veces se ejecuta cuando tengo un mensaje en serie, pero parece que no se ejecuta cuando no lo tengo. También tuve un caso en el que enviar mensajes en serie haría que el arduino se reiniciara sin cesar.

También estaba usando un arduino328. Probablemente debería reducir el tamaño de su matriz si tiene alguno al tamaño más pequeño que sea aceptable.

Reza Hussain
fuente
gracias, tú y Dave Tweed lo entendieron. Refactoré la función display_state () para no necesitar esa asignación adicional. Raramente realizo procesamientos incrustados, ¡supongo que todos tenemos que llegar al muro de la memoria en algún momento!
eqzx
Hola, tengo una situación similar. Cambio el tamaño de la matriz de 128 a 96 y mi programa funciona bien. Pero creo que este problema está realmente fuera de lugar para la depuración, porque el tamaño de mi matriz es menor que el tamaño de la pila de declarar. ¿Sabes dónde puedo encontrar información para tratar este tipo de problema?
Lion Lai
4

¿Su código inicializa el puerto serie? P.ej.

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

De lo contrario, podría producirse un bloqueo en el primer uso del serial.

Toby Jaffey
fuente
Si, tengo eso.
eqzx
3

¿Quizás te estás quedando sin memoria? Todas las cadenas que imprime con Serial.print ("algo") tienen lugar en SRAM, igual al número de caracteres de esa cadena + 1 para el terminador \ 0. Es posible que se quede sin memoria incluso si el tamaño compilado de su boceto es mucho más pequeño que la memoria flash Arduino, porque SRAM tiene solo 2048 bytes para Atmega328 y 1024 bytes para Atmega 168. Tuve un problema similar, que resolví acortando todo textos y eliminando mensajes de depuración innecesarios.

Erion
fuente
Hmm Tengo varias matrices multidimensionales declaradas en mi encabezado, ¿tal vez ese es el problema? ¿Están almacenados en SRAM?
eqzx
1
@ nrhine1: En ese caso, probablemente debería mostrarnos toda su dibujo, no sólo las partes donde se piensa que las mentiras de problemas.
Dave Tweed
@DaveTweed Sí, lo haré.
eqzx
1
Noté que está definiendo una gran cantidad de almacenamiento en su archivo de encabezado, en lugar de simplemente declararlo allí (si no entiende la distinción, consulte esta página ). Esto sería inusual en un programa en C; ¿Es la práctica normal en Arduino? Es posible que termine con varias copias de estas estructuras. Además, está definiendo algunas variables automáticas muy grandes, como la matriz "viva" en display_state (), que necesita más de 1024 bytes de espacio de pila. Estoy bastante seguro de que simplemente te estás quedando sin memoria.
Dave Tweed
@DaveTweed gracias, tú y Reza lo entendieron. Refactoré la display_state()función para no necesitar esa asignación adicional. Raramente realizo procesamientos incrustados, ¡supongo que todos tenemos que llegar al muro de la memoria en algún momento!
eqzx
1

No ha mostrado el código que inicializa la variable "loop_counter". ¿Está eso fuera de la rutina loop () ?

¿Es posible que haya declarado eso de una manera adyacente a otra área de almacenamiento de memoria que está operando fuera de su tamaño declarado y esto afecta a la variable loop_counter?

Michael Karas
fuente
He intentado declararlo de muchas maneras diferentes, en muchos lugares diferentes. En el encabezado, justo arriba loop(), etc. ¿Estás diciendo que el Serial.print()método podría estar sobrescribiéndolo de alguna manera?
eqzx
Lo que quise decir con un comentario anterior es que estoy casi seguro de que he aislado el comportamiento 'malo' de la existencia de Serial.print (). Cuando no está allí, las cosas funcionan bien.
eqzx
@ nrbine1 - Me parece que su variable variable global "loop_counter" está siendo pisoteada por el método Serial.print () como sugerí en mi respuesta. En la respuesta de posipiet, se le preguntó si el objeto de serie se ha inicializado correctamente. Si eso no se ha hecho, puede explicar el "tromping" en su contador ya que Serial.print () intenta usar un búfer que no se ha asignado y configurado correctamente.
Michael Karas
He agregado toda mi fuente.
eqzx
1

No veo en tu código dónde estás llamando loop(). Tampoco parece que esté usando loop_counterfuera de esa función. ¿Hay alguna razón por la que lo declaras global? Supongo que es porque desea que conserve su valor entre llamadas. En su lugar, podría hacer esto con una variable local estática .

void loop() {
    static int loop_counter = 0;

    if(loop_counter > 100)
    {
        loop_counter = 0;
    }
    else
    {
        loop_counter++;
    }

    Serial.println("hey");

    if(loop_counter == 0)
    {
         //do_something_important();
    }      
}

Eso debería asegurar que ninguna otra función externa pueda pisotearlo. Siempre debe declarar sus variables en el menor alcance posible para evitar comportamientos no deseados.

Si eso no funciona, deberá analizar realmente el uso de su memoria. Revise estas preguntas y respuestas de EE. UU. Para ver varios códigos de muestra para hacer esto dentro de un Arduino.

Embedded.kyle
fuente
Traté de hacerlo estático ya. No sirvió de nada. Esta es una iteración diferente. setup()y loop()son funciones que arduino ejecuta por defecto, setup()primero, loop()segundo. loop()es esencialmente como main(), excepto que se llama repetidamente. referencia: arduino.cc/en/Reference/loop Comprobaré ese enlace.
eqzx
De nuevo, como he mencionado en otros comentarios, no puedo depurar Serial.print(). Parece que tendré que salir del processingIDE normal si quiero poder usar GDB
eqzx
@ nrhine1 Dijiste que Serial.print()funcionaba bien porque imprimía "hey" mucho. Es loop_counterque te está dando un problema. Intente eliminar el if(loop_counter == 0)código y poner el get_free_memory()código (deje el loop_counterincremento) y ejecútelo. Esto al menos le dirá si tiene algún problema importante con su asignación de memoria.
embedded.kyle
1

La biblioteca en serie del software Arduino usa interrupciones. (consulte "softwareSerial.cpp, .h"). Es posible que tenga un problema en el que el ISR está "pisando" el código principal (o viceversa). Intente usar banderas de enclavamiento para que el código espere mientras se completan las operaciones de impresión.

Bob Kugler
fuente
0

Hace un tiempo tuve la impresión de tener el mismo problema. En aquel entonces, lo resolví agregando un retraso (1) al frente o después del serial.println. Eso fue con Arduino 0022 en Linux. No estoy seguro de qué placa era, probablemente una serie de Boarduino. No puedo reproducirlo tampoco.

Actualmente, funciona para mí en un USB boarduino con Arduino 1.01 en Windows:

int loop_counter = 0;
int led = 13;

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);}

void loop() {
    if(loop_counter > 100) {
      loop_counter = 0;
    }
    else {
      loop_counter++;
    }

    Serial.println(loop_counter);

    if(loop_counter == 0) {
      Serial.println("hey hey orange, hey hey!");
    }      
}
posipiet
fuente
Gracias por la sugerencia. Desafortunadamente no resolvió el problema.
eqzx