Arduino Serial print verändert das Verhalten des Programms auf unerwünschte Weise

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

int loop_counter = 0;

Ich verwende diesen Zähler, um von Zeit zu Zeit ein Ereignis auszulösen. Früher habe ich für dieselbe Art von Verhalten ein Modulo 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 schön und gut, bis ich versuche, mit zu kommunizieren, Serialindem ich das Kommentarzeichen entferne //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. Ich habe versucht, als zu do_something_important();deklarieren , das hat nichts geändert. Ich habe versucht ing , und ich habe auch ein seltsames Verhalten bekommen (es würde die Schleife einfrieren). 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)loop_countervolatileSerial.printloop_counterSerial.println("hey");

Was könnte möglicherweise die Verwendung von Serialmit Daten verursachen, die (soweit ich das beurteilen kann) nicht daran gebunden sind, loop_counterdass es vollständig daran gehindert wird, ordnungsgemäß zu funktionieren?

BEARBEITEN : Hier ist der Teil der Hauptdatei, der das Problem aufgeworfen hat (na ja, am meisten dazu beigetragen hat (zu viel Speicher verwendet)):



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 "letters.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; letter_node *weiter; Ganzzahl x; int y; } letter_node;

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

letter_node letter_map[NUMBER_OF_CHARACTERS]; #endif

Einige weitere Informationen: - Ich verwende ein Uno (ATMega328)

Was ist Ihre Stapelgröße? Besteht die Möglichkeit, dass Sie Ihren Stapel malen und sehen können, ob er beschädigt wird? Verwendet der Serial Print Interrupts, ist Ihr Code reentrant?
Der serielle Druck wird nicht durch Interrupts ausgelöst, ich verwende ihn nur in der loop()Funktion. Wie soll ich meinen Stack malen, wenn die einzige Ausgabemethode, die ich habe ( Serial.print()), mich versagt?
Um mögliche Fehler und missverstandene Nebeneffekte scheinbar trivialer Änderungen zu vermeiden, ersetzen Sie bitte den Code in Ihrer Frage durch eine wörtliche, zeichengenaue Kopie einer Skizze , die auf das zum Auslösen des Problems erforderliche Minimum reduziert ist . Nicht "das ist mein Programm, das fehlschlägt, wenn ich ...", sondern genau das Minimalprogramm, das auf diese Weise fehlschlägt.

Antworten (7)

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

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

Ich habe auch einen Arduino328 verwendet. Wahrscheinlich sollten Sie die Größe Ihres Arrays, falls vorhanden, auf die kleinste akzeptable Größe reduzieren.

Danke, Sie und Dave Tweed haben es verstanden. Ich habe die Funktion display_state() so umgestaltet, dass sie diese zusätzliche Zuordnung nicht benötigt. Ich mache selten eingebettete Verarbeitung, ich nehme an, wir alle müssen irgendwann an die Wand der Erinnerung stoßen!
Hallo, ich habe eine ä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 als die Deklarationsstapelgröße ist. Wissen Sie, wo ich Informationen finden kann, um mit dieser Art von Problem umzugehen?

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.

Ja, das habe ich.

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

Hmm. Ich habe mehrere mehrdimensionale Arrays in meinem Header deklariert, vielleicht ist das das Problem? Sind sie im SRAM gespeichert?
@nrhine1: In diesem Fall sollten Sie uns wahrscheinlich Ihre gesamte Skizze zeigen, nicht nur die Teile, in denen Ihrer Meinung nach das Problem liegt.
@DaveTweed Ja, geht.
Mir ist aufgefallen, dass Sie viel Speicherplatz in Ihrer Header-Datei definieren, anstatt ihn einfach dort zu deklarieren (wenn Sie den Unterschied nicht verstehen, lesen Sie diese Seite ). Dies wäre in einem C-Programm ungewöhnlich; ist es die übliche Praxis auf Arduino? Möglicherweise erhalten Sie mehrere Kopien dieser Strukturen. Außerdem definieren Sie einige sehr große automatische Variablen, wie z. B. das Array "alive" in display_state(), das über 1024 Byte Stapelspeicherplatz benötigt. Ich bin mir ziemlich sicher, dass dir einfach der Speicher ausgeht.
@DaveTweed danke, du und Reza haben es verstanden. Ich habe die display_state()Funktion so umgestaltet, dass sie diese zusätzliche Zuordnung nicht benötigt. Ich mache selten eingebettete Verarbeitung, ich nehme an, wir alle müssen irgendwann an die Wand der Erinnerung stoßen!
@Erion du auch. +1

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

Haben Sie das möglicherweise so deklariert, dass es neben einem anderen Speicherbereich liegt, der außerhalb seiner deklarierten Größe arbeitet, und dies auf die Loop_counter-Variable stößt?

Ich habe versucht, es auf viele verschiedene Arten und an vielen verschiedenen Orten zu erklären. In der Kopfzeile, direkt über loop()usw. Wollen Sie damit sagen, dass die Serial.print()Methode sie möglicherweise irgendwie überschreibt?
Was ich mit dem vorherigen 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.
@ nrbine1 - Es scheint mir, dass Ihre globale Variablenvariable "loop_counter" von der Methode Serial.print () getreten wird, wie ich in meiner Antwort vorgeschlagen habe. In der Antwort von posipiet wurden Sie gefragt, ob das Serial-Objekt ordnungsgemäß initialisiert wurde. Wenn dies nicht getan wurde, kann dies das "Trotten" auf Ihrem Zähler erklären, da Serial.print() versucht, einen Puffer zu verwenden, der nicht richtig zugewiesen und eingerichtet wurde.
Ich habe alle meine Quellen hinzugefügt.

Ich sehe in Ihrem Code nicht, wo Sie anrufen loop(). Es sieht auch nicht so aus, als würden Sie loop_counterdiese Funktion außerhalb verwenden. Gibt es einen Grund, warum Sie es für global erklären? Ich gehe davon aus, dass Sie möchten, dass es zwischen den Anrufen seinen Wert behält. Sie könnten 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 herumtrampeln können. Sie sollten Ihre Variablen immer im kleinstmöglichen Umfang deklarieren, um unerwünschtes Verhalten zu vermeiden.

Wenn das nicht funktioniert, müssen Sie Ihre Speichernutzung wirklich analysieren. In diesem EE.SE Q&A finden Sie verschiedene Beispielcodes, um dies in einem Arduino zu tun.

Ich habe bereits versucht, es statisch zu machen. Es half nicht. 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 dass es wiederholt aufgerufen wird. Referenz: arduino.cc/en/Reference/loop Ich werde diesen Link überprüfen.
Auch hier kann ich, wie ich in anderen Kommentaren erwähnt habe, nicht mit debuggen Serial.print(). Es sieht so aus, als müsste ich die normale processingIDE verlassen, wenn ich GDB verwenden möchte
@nrhine1 Sie sagten, Serial.print()das funktionierte gut, da es viel "Hey" ausdruckte. Das loop_countermacht dir ein Problem. Versuchen Sie, den if(loop_counter == 0)Code zu entfernen und den Code einzufügen get_free_memory()(lassen Sie das loop_counterInkrement) und führen Sie ihn aus. Dies wird Ihnen zumindest sagen, ob Sie größere Probleme mit Ihrer Speicherzuweisung haben.

Die serielle Bibliothek der Arduino-Software verwendet Interrupts. (siehe "softwareSerial.cpp, .h"). Möglicherweise liegt ein Problem vor, 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.

Irgendwann hatte ich vor einiger Zeit 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 eingefügt habe. Das war mit Arduino 0022 unter Linux. Ich bin mir nicht sicher, welches Board es war, wahrscheinlich eine Boarduino-Serie. Kann es auch nicht reproduzieren.

Derzeit funktioniert es bei mir 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!");
    }      
}
Danke für den Vorschlag. Es hat das Problem leider nicht gelöst.