Arduino Serial print cambia el comportamiento del programa indeseablemente

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

int loop_counter = 0;

Uso este contador para activar un evento de vez en cuando. 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 da como resultado 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á muy bien, hasta que intento comunicarme con Serialdescomentando //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. Intenté declarar loop_countercomo volatile, eso no cambió nada. Intenté Serial.printing loop_counter, y también obtuve un comportamiento extraño (congelaría el ciclo). Serial.println("hey");funciona en el sentido de que en el monitor Serial recibo muchos "hey" (es decir, rápidamente mucho más de 100 "heys", el número 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 (que yo sepa) vinculados para loop_counterevitar que funcione correctamente?

EDITAR : Aquí está la parte del archivo principal que terminó planteando el problema (bueno, contribuyendo más (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á "letras.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 bucle_contador = 0; short led_matrix[num_rows][num_cols];

const letra corta_a[nrows][ncols] = {{0,1,1,0}, {1,0,0,1}, {1,1,1,1}, {1,0,0,1}}; const letra corta_b[nrows][ncols] = {{1,0,0,0},{1,1,1,0},{1,0,1,0},{1,1,1,0} }; const letra corta_c[nrows][ncols] = {{0,1,1,1},{1,0,0,0},{1,0,0,0},{0,1,1,1} }; const letra corta_t[nrows][ncols] = {{1,1,1,1},{0,1,0,0},{0,1,0,0},{0,1,0,0} };

typedef struct letter_node{ const corto *datos; letter_node *siguiente; intx; int y; } letra_nodo;

letra_nodo aa = {&letra_a[0][0],NULL,1,1}; letter_node bb = {&letter_b[0][0],NULL,1,1}; letra_nodo cc = {&letra_c[0][0],NULL,1,1}; letter_node tt = {&letter_t[0][0],NULL,1,1};

letter_node letter_map[NÚMERO_DE_CARACTERES]; #terminara si

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

¿Cuál es el tamaño de su pila? ¿Existe la posibilidad de que pueda pintar su pila y ver si se está corrompiendo? ¿La impresión en serie usa interrupciones, es su código reentrante?
La impresión en serie no se activa por ninguna interrupción, la estoy usando solo en la loop()función. ¿Cómo debo pintar mi pila si el único método de salida que tengo ( Serial.print()) me está fallando?
Para eliminar posibles errores y efectos secundarios mal entendidos de cambios aparentemente triviales, reemplace el código en su pregunta con una copia literal, con caracteres exactos 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.

Respuestas (7)

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

En mi caso, el código a veces se ejecutaba cuando tenía un mensaje en serie, pero luego parecía no ejecutarse cuando no lo tenía. 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. Es probable que deba reducir el tamaño de su matriz si tiene alguna al tamaño más pequeño que sea aceptable.

gracias, tú y Dave Tweed lo conseguisteis. Refactoricé la función display_state() para no necesitar esa asignación adicional. Rara vez hago procesamiento integrado, ¡supongo que todos tenemos que golpear la pared de la memoria en algún momento!
Hola, yo tengo la misma situacion. 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 rastro para la depuración, porque el tamaño de mi matriz es más pequeño que el tamaño de la pila declarada. ¿Sabes dónde puedo encontrar información para tratar este tipo de problema?

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

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

Si no lo hace, podría provocar un bloqueo en el primer uso de la serie.

Sí, tengo eso.

¿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 quedarse sin memoria incluso si el tamaño compilado de su boceto es mucho más pequeño que la memoria flash Arduino, porque SRAM es 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.

Mmm. Tengo varias matrices multidimensionales declaradas en mi encabezado, ¿tal vez ese sea el problema? ¿Están almacenados en SRAM?
@nrhine1: En ese caso, probablemente debería mostrarnos su boceto completo, no solo las partes donde cree que radica el problema.
@DaveTweed Sí, lo haré.
Noté que está definiendo una gran cantidad de almacenamiento en su archivo de encabezado, en lugar de simplemente declararlo allí (si no comprende la distinción, consulte esta página ). Esto sería inusual en un programa 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.
@DaveTweed gracias, tú y Reza lo entendieron. Refactoricé la display_state()función para no necesitar esa asignación adicional. Rara vez hago procesamiento integrado, ¡supongo que todos tenemos que golpear la pared de la memoria en algún momento!
@Erion tú también. +1

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

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

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

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

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 pisarlo. Siempre debe declarar sus variables en el ámbito más pequeño posible para evitar comportamientos no deseados.

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

Intenté hacerlo estático ya. No ayudó. Esta es una iteración diferente. setup()y loop()son funciones que ejecuta arduino por defecto, setup()primero, loop()segundo. loop()es esencialmente como main(), excepto que se llama repetidamente. referencia: arduino.cc/en/Reference/loop Revisaré ese enlace.
nuevamente, como mencioné en otros comentarios, no puedo depurar con Serial.print(). Parece que tendré que salir del processingIDE normal si quiero poder usar GDB
@ nrhine1 Dijiste que Serial.print()estaba funcionando bien porque estaba imprimiendo "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.

La biblioteca en serie del software Arduino utiliza interrupciones. (ver "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 interbloqueo, de modo que el código espere mientras se completan las operaciones de impresión.

En un momento hace algún tiempo tuve la impresión de tener el mismo problema. En ese entonces, lo resolví agregando un retraso (1) al frente o después de 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 me funciona en un boarduino USB 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!");
    }      
}
Gracias por la sugerencia. Desafortunadamente no resolvió el problema.