Arduino Serial Print ändert das Verhalten des Programms unerwünscht

10

Ich verwende einen Schleifenzähler, der in einem Header deklariert ist:

int loop_counter = 0;

Ich benutze diesen Zähler, um von Zeit zu Zeit ein Ereignis auszulösen. Früher habe ich ein Modulo für dieselbe Art von Verhalten verwendet, aber ich habe es vereinfacht, damit es einfacher ist, damit zu arbeiten (es führt immer noch zu demselben Verhalten).

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

    //Serial.println("hey");

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

Alles ist gut und schön, bis ich versuche, mit dem zu kommunizieren, Serialindem ich das auskommentiere //Serial.println("hey"); ( "hey"in diesem Beispiel, weil dieses Verhalten für mich absurd ist).

Dies führt dazu, dass der Codeabschnitt loop_counterniemals ausgelöst wird do_something_important();. Ich versuchte zu erklären , loop_counterwie volatile, dass nichts geändert hat. Ich habe versucht , Serial.printing loop_counter, und ich war auch seltsames Verhalten bekommen (es würde die Schleife einfrieren). Serial.println("hey");funktioniert in dem Sinne, dass ich im seriellen Monitor viel "hey" bekomme (dh schnell viel mehr als 100 "heys", die Anzahl der Iterationen, bei denen der andere Codeabschnitt ausgelöst werden soll).

Was könnte möglicherweise die Verwendung von SerialDaten verursachen, die nicht (soweit ich das beurteilen kann) gebunden sind, loop_counterum die ordnungsgemäße Funktion vollständig zu verhindern?

BEARBEITEN : Hier ist der Teil der Hauptdatei, der das Problem aufwirft (nun, am meisten dazu beiträgt (mit zu viel Speicher)):



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);
 }
}

Hier ist "letter.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;loop_counter = 0 ; kurze led_matrix [num_rows] [num_cols];kurze led_matrix [ num_rows ] [ num_cols ];

const short letter_a [nrows] [ncols] = {{0,1,1,0}, kurzer Buchstabe_a [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 0 }, {1,0,0,1},{ 1 , 0 , 0 , 1 }, {1,1,1,1},{ 1 , 1 , 1 , 1 }, {1,0,0,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_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_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} };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 { struct letter_node { const short * data;const short * data ; letter_node * next;* weiter ; int x;int x ; int y;int y ; } letter_node;} letter_node ;

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

letter_node letter_map [NUMBER_OF_CHARACTERS];[ NUMBER_OF_CHARACTERS ]; #endif#endif

Weitere Informationen: - Ich verwende ein Uno (ATMega328)

Gl
quelle
Was ist Ihre Stapelgröße? Gibt es eine Chance, dass Sie Ihren Stapel malen und sehen können, ob er beschädigt wird? Verwendet der serielle Druck Interrupts, ist Ihr Code wiedereintrittsfähig?
Ktc
Der serielle Druck wird nicht durch Interrupts ausgelöst, ich verwende ihn nur in der loop()Funktion. Wie soll ich meinen Stapel malen, wenn die einzige Ausgabemethode, die ich habe ( Serial.print()), darin besteht, dass ich versage?
eqzx
2
Um mögliche Fehler und missverstandene Nebenwirkungen scheinbar trivialer Änderungen zu vermeiden, ersetzen Sie den Code in Ihrer Frage durch eine wörtliche, zeichengenaue Kopie einer Skizze , die auf das zur Auslösung des Problems erforderliche Minimum reduziert wurde . Nicht "das ist mein Programm, das fehlschlägt, wenn ich ...", sondern genau das Mindestprogramm, das auf diese Weise fehlschlägt.
Chris Stratton

Antworten:

2

Ich hatte auch ein ähnliches Problem wie dieses und bin mir sehr sicher, dass Ihr Problem auch nicht mit dem Stapelspeicher zusammenhängt. Versuchen Sie, den Code so weit wie möglich zu verkleinern.

In meinem Fall wurde der Code manchmal ausgeführt, wenn ich eine serielle Nachricht darin hatte, aber dann schien er nicht ausgeführt zu werden, wenn ich dies nicht tat. Ich hatte auch einen Fall, in dem das Senden von seriellen Nachrichten dazu führen würde, dass das Arduino endlos zurückgesetzt wird.

Ich habe auch ein Arduino328 verwendet. Wahrscheinlich sollten Sie die Größe Ihres Arrays reduzieren, wenn Sie eine auf die kleinste akzeptable Größe haben.

Reza Hussain
quelle
Danke, du und Dave Tweed haben es verstanden. Ich habe die Funktion display_state () überarbeitet, um diese zusätzliche Zuordnung nicht zu benötigen. Ich mache selten eingebettete Verarbeitung, ich nehme an, wir müssen alle irgendwann auf die Speicherwand stoßen!
eqzx
Hallo, ich habe die ähnliche Situation. Ich ändere die Größe des Arrays von 128 auf 96 und mein Programm funktioniert einwandfrei. Aber ich denke, dieses Problem ist wirklich nicht zu debuggen, da die Größe meines Arrays kleiner ist als die deklarierte Stapelgröße. Wissen Sie, wo ich Informationen finden kann, um diese Art von Problem zu lösen?
Lion Lai
4

Initialisiert Ihr Code die serielle Schnittstelle? Z.B.

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

Andernfalls kann es bei der ersten Verwendung der Seriennummer zu einem Absturz kommen.

Toby Jaffey
quelle
Ja, das habe ich.
eqzx
3

Vielleicht geht Ihnen der Speicher aus? Alle Zeichenfolgen, die Sie mit Serial.print ("etwas") drucken, finden im SRAM statt, entsprechend der Anzahl der Zeichen dieser Zeichenfolge + 1 für den Terminator \ 0. Es ist möglich, dass der Speicher knapp wird, selbst wenn die kompilierte Größe Ihrer Skizze viel kleiner als der Arduino-Flash-Speicher ist, da SRAM nur 2048 Byte für Atmega328 und 1024 Byte für Atmega 168 beträgt. Ich hatte ein ähnliches Problem, das ich durch Verkürzen aller gelöst habe Texte und Entfernen unnötiger Debug-Meldungen.

Erion
quelle
Hmm. Ich habe mehrere mehrdimensionale Arrays in meinem Header deklariert. Vielleicht ist das das Problem? Sind sie im SRAM gespeichert?
eqzx
1
@ nrhine1: In diesem Fall sollten Sie uns wahrscheinlich Ihre gesamte Skizze zeigen, nicht nur die Teile, an denen das Problem Ihrer Meinung nach liegt.
Dave Tweed
@ DaveTweed Ja, reicht.
eqzx
1
Ich stelle fest, dass Sie viel Speicherplatz in Ihrer Header-Datei definieren, anstatt ihn dort einfach zu deklarieren (wenn Sie den Unterschied nicht verstehen, lesen Sie diese Seite ). Dies wäre in einem C-Programm ungewöhnlich. ist es die normale Praxis auf Arduino? Möglicherweise erhalten Sie mehrere Kopien dieser Strukturen. Außerdem definieren Sie einige sehr große automatische Variablen, z. B. das Array "lebendig" in display_state (), das mehr als 1024 Byte Stapelspeicher benötigt. Ich bin mir ziemlich sicher, dass Ihnen einfach der Speicher ausgeht.
Dave Tweed
@ DaveTweed Danke, du und Reza haben es verstanden. Ich habe die display_state()Funktion überarbeitet, um diese zusätzliche Zuordnung nicht zu benötigen. Ich mache selten eingebettete Verarbeitung, ich nehme an, wir müssen alle irgendwann auf die Speicherwand stoßen!
eqzx
1

Sie haben den Code, der die Variable "loop_counter" initialisiert, nicht angezeigt. Liegt das außerhalb der loop () -Routine?

Haben Sie das möglicherweise so deklariert, dass es an einen anderen Speicherbereich angrenzt, der außerhalb seiner deklarierten Größe arbeitet, und dieses Tromping auf die Variable loop_counter?

Michael Karas
quelle
Ich habe versucht, es auf viele verschiedene Arten und an vielen verschiedenen Orten zu deklarieren. In der Kopfzeile rechts oben loop()usw. Wollen Sie damit sagen, dass die Serial.print()Methode sie möglicherweise irgendwie überschreibt?
eqzx
Was ich mit vorherigem Kommentar gemeint habe, ist, dass ich fast sicher bin, dass ich das "schlechte" Verhalten auf die Existenz von Serial.print () isoliert habe. Wenn es nicht da ist, funktionieren die Dinge gut.
eqzx
@ nrbine1 - Es scheint mir, dass Ihre globale Variablenvariable "loop_counter" von der Serial.print () -Methode betreten wird, wie ich in meiner Antwort vorgeschlagen habe. In der Antwort von posipiet wurden Sie gefragt, ob das serielle Objekt ordnungsgemäß initialisiert wurde. Wenn dies nicht getan wurde, wird möglicherweise das "Tromping" auf Ihrem Zähler erklärt, wenn Serial.print () versucht, einen Puffer zu verwenden, der nicht ordnungsgemäß zugewiesen und eingerichtet wurde.
Michael Karas
Ich habe alle meine Quellen hinzugefügt.
eqzx
1

Ich sehe in Ihrem Code nicht, wo Sie anrufen loop(). Es sieht auch nicht , wie Sie verwenden sind loop_counterdiese Funktion außerhalb. Gibt es einen Grund, warum Sie es für global erklären? Ich gehe davon aus, dass Sie möchten, dass der Wert zwischen den Anrufen erhalten bleibt. Sie können dies stattdessen mit einer statischen lokalen Variablen tun .

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();
    }      
}

Das sollte sicherstellen, dass keine anderen externen Funktionen darauf stampfen können. Sie sollten Ihre Variablen immer im kleinstmöglichen Bereich deklarieren, um unerwünschtes Verhalten zu vermeiden.

Wenn dies nicht funktioniert, müssen Sie Ihre Speichernutzung wirklich analysieren. In diesen EE.SE-Fragen und Antworten finden Sie verschiedene Beispielcodes, um dies in einem Arduino zu tun.

embedded.kyle
quelle
Ich habe bereits versucht, es statisch zu machen. Es hat nicht geholfen. Dies ist eine andere Iteration. setup()und loop()sind Funktionen, die Arduino standardmäßig ausführt, setup()erstens, loop()zweitens. loop()ist im Wesentlichen wie main(), außer es wird wiederholt aufgerufen. Referenz: arduino.cc/en/Reference/loop Ich werde diesen Link überprüfen.
eqzx
Wie ich bereits in anderen Kommentaren erwähnt habe, kann ich nicht mit debuggen Serial.print(). Es sieht so aus processing, als
müsste
@ nrhine1 Du hast gesagt, Serial.print()das funktioniert gut, da es viel "hey" druckt . Es ist das loop_counter, was dir ein Problem gibt. Versuchen Sie, den if(loop_counter == 0)Code zu entfernen, den Code einzugeben get_free_memory()(das loop_counterInkrement zu belassen) und auszuführen . Dies wird Ihnen zumindest sagen, ob Sie größere Probleme mit Ihrer Speicherzuordnung haben.
embedded.kyle
1

Die serielle Bibliothek der Arduino-Software verwendet Interrupts. (siehe "softwareSerial.cpp, .h"). Möglicherweise haben Sie ein Problem, bei dem der ISR auf den Hauptcode "tritt" (oder umgekehrt). Versuchen Sie, Interlock-Flags zu verwenden, damit der Code wartet, während die Druckvorgänge abgeschlossen sind.

Bob Kugler
quelle
0

Vor einiger Zeit hatte ich den Eindruck, das gleiche Problem zu haben. Damals habe ich es gelöst, indem ich eine Verzögerung (1) vor oder nach der serial.println hinzugefügt habe. Das war mit Arduino 0022 unter Linux. Ich bin mir nicht sicher, um welches Board es sich handelt, wahrscheinlich um eine Boarduino-Serie. Kann es auch nicht reproduzieren.

Derzeit funktioniert es für mich auf einem Boarduino USB mit Arduino 1.01 unter 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
quelle
Danke für den Vorschlag. Das Problem wurde leider nicht gelöst.
eqzx