La stampa seriale Arduino modifica il comportamento del programma in modo indesiderato


10

Sto usando un contatore di loop, dichiarato in un'intestazione:

int loop_counter = 0;

Uso questo contatore per attivare un evento ogni tanto. Utilizzavo un modulo per questo stesso tipo di comportamento, ma l'ho semplificato in modo che sia più facile lavorare con (comporta comunque lo stesso comportamento)

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

    //Serial.println("hey");

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

Va tutto bene, finché non provo a comunicare con il Serialcommento //Serial.println("hey"); ( "hey"in questo esempio perché, per me, questo comportamento è assurdo).

Ciò si traduce in loop_counternon attivare mai la do_something_important();sezione di codice. Ho provato dichiarando loop_countercome volatile, che non cambia nulla. Ho provato Serial.printing loop_counter, e mi è stato anche sempre un comportamento strano (sarebbe congelare la loop). Serial.println("hey");funziona nel senso che nel monitor seriale ottengo un sacco di "ehi", (cioè rapidamente molto più di 100 "ehi", il numero di iterazioni in cui dovrebbe attivarsi l'altra sezione di codice)

Cosa potrebbe causare l'utilizzo di Serial, con dati che non sono (per quanto posso dire) legati per loop_counterimpedirne il corretto funzionamento?

EDIT : Ecco la parte del file principale che ha finito per porre il problema (beh, contribuendo maggiormente ad esso (usando troppa 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);
 }
}

Ecco "lettere.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 ; short led_matrix [num_rows] [num_cols];short led_matrix [ num_rows ] [ num_cols ];

const short letter_a [nrows] [ncols] = {{0,1,1,0}, short letter_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 * brevi dati;const * brevi dati ; letter_node * successivo;* successivo ; 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_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 ]; #finisci se

Qualche informazione in più: - Sto usando uno (ATMega328)


Qual è la dimensione del tuo stack? C'è una possibilità che puoi dipingere il tuo stack e vedere se si sta corrompendo. La stampa seriale utilizza gli interrupt, il tuo codice è rientrato?
Ktc,

La stampa seriale non è innescata da alcun interrupt, la sto usando solo nella loop()funzione. Come devo dipingere il mio stack se l'unico metodo di output che ho ( Serial.print()) mi sta fallendo?
eqzx,

2
Per eliminare possibili errori e incomprensioni di effetti collaterali di modifiche apparentemente banali, si prega di sostituire il codice nella domanda con una copia letterale esatta del carattere di uno schizzo ridotta al minimo necessario per innescare il problema . Non "questo è il mio programma che fallisce se io ..." ma esattamente il programma minimo che fallisce in questo modo.
Chris Stratton,

Risposte:


2

Ho anche avuto un problema simile a questo, e sono molto sicuro che anche il tuo sia fuori dallo spazio dello stack. Prova a ridurre il codice il più possibile.

Nel mio caso il codice a volte veniva eseguito quando avevo un messaggio seriale, ma poi sembrava non funzionare quando non lo facevo. Ho anche avuto un caso in cui l'invio di messaggi seriali avrebbe causato il reset infinito di Arduino.

Stavo anche usando un arduino328. Probabilmente dovresti ridurre le dimensioni dell'array se ne hai una delle dimensioni più piccole accettabili.


grazie, tu e Dave Tweed avete capito. Ho refactored la funzione display_state () per non aver bisogno di tale allocazione aggiuntiva. Raramente eseguo l'elaborazione integrata, suppongo che a un certo punto dovremo colpire il muro della memoria!
eqzx,

Ciao, ho la situazione simile. Cambio la dimensione dell'array da 128 a 96 e il mio programma funziona bene. Ma penso che questo problema sia davvero fuori traccia per il debug, perché la dimensione del mio array è più piccola della dimensione dello stack dichiarata. Sai dove posso trovare informazioni per affrontare questo tipo di problema?
Lion Lai,

4

Il tuo codice inizializza la porta seriale? Per esempio.

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

In caso contrario, potrebbe verificarsi un arresto anomalo al primo utilizzo del seriale.


Sì, ce l'ho.
eqzx,

3

Forse stai esaurendo la memoria? Tutte le stringhe stampate con Serial.print ("qualcosa") si svolgono in SRAM, pari al numero di caratteri di quella stringa + 1 per il terminatore \ 0. È possibile esaurire la memoria anche se la dimensione compilata del tuo schizzo è molto più piccola della memoria flash Arduino, perché SRAM è solo 2048 byte per Atmega328 e 1024 byte per Atmega 168. Ho avuto un problema simile, che ho risolto accorciando tutto testi e rimozione di messaggi di debug non necessari.


Hmm. Ho diversi array multidimensionali dichiarati nella mia intestazione, forse è questo il problema? Sono memorizzati in SRAM?
eqzx,

1
@ nrhine1: In questo caso, probabilmente si dovrebbe mostrarci l'intero disegno, non solo le parti in cui si pensa le bugie di problema.
Dave Tweed,

@DaveTweed Sì, lo farà.
eqzx,

1
Ho notato che stai definendo un sacco di spazio di archiviazione nel tuo file di intestazione, piuttosto che dichiararlo semplicemente lì (se non capisci la distinzione vedi questa pagina ). Ciò sarebbe insolito in un programma C; è la pratica normale su Arduino? Potresti finire con più copie di queste strutture. Inoltre, stai definendo alcune variabili automatiche molto grandi, come l'array "alive" in display_state (), che necessita di oltre 1024 byte di spazio dello stack. Sono abbastanza sicuro che stai semplicemente esaurendo la memoria.
Dave Tweed,

@DaveTweed grazie, tu e Reza avete capito. Ho riformattato la display_state()funzione per non aver bisogno di tale allocazione aggiuntiva. Raramente eseguo l'elaborazione integrata, suppongo che a un certo punto dovremo colpire il muro della memoria!
eqzx,

1

Non è stato mostrato il codice che inizializza la variabile "loop_counter". È fuori dalla routine loop () ?

Hai forse dichiarato questo in modo che sia adiacente ad un'altra area di archiviazione di memoria che sta funzionando al di fuori delle dimensioni dichiarate e questo tromping sulla variabile loop_counter?


Ho provato a dichiararlo in molti modi diversi, in molti luoghi diversi. Nell'intestazione, proprio sopra loop(), ecc. Stai dicendo che il Serial.print()metodo potrebbe sovrascriverlo in qualche modo?
eqzx,

Ciò che intendevo per commento precedente è che sono quasi certo di aver isolato il comportamento "cattivo" all'esistenza di Serial.print (). Quando non c'è, le cose funzionano bene.
eqzx,

@nrbine1 - Mi sembra che la tua variabile variabile globale "loop_counter" venga calpestata dal metodo Serial.print () come ho suggerito nella mia risposta. Nella risposta di posipiet ti è stato chiesto se l'oggetto seriale è stato correttamente inizializzato. Se ciò non è stato fatto, potrebbe essere spiegato il "tromping" sul contatore poiché Serial.print () tenta di utilizzare un buffer che non è stato allocato e configurato correttamente.
Michael Karas,

Ho aggiunto tutta la mia fonte.
eqzx,

1

Non vedo nel tuo codice dove stai chiamando loop(). Inoltre non sembra che tu stia usando loop_counteral di fuori di quella funzione. C'è un motivo per cui lo dichiari globale? Suppongo sia perché vuoi che mantenga il suo valore tra le chiamate. Invece potresti farlo con una variabile locale statica .

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

Ciò dovrebbe assicurarsi che nessun'altra funzione esterna possa calpestarla. Dovresti sempre dichiarare le tue variabili nel più piccolo ambito possibile per evitare comportamenti indesiderati.

Se il problema persiste, dovrai analizzare davvero l'utilizzo della memoria. Controlla questo EE.SE Domande e risposte per vari codici di esempio per farlo all'interno di un Arduino.


Ho già provato a renderlo statico. Non ha aiutato Questa è un'iterazione diversa. setup()e loop()sono funzioni che arduino esegue per impostazione predefinita, setup()primo, loop()secondo. loop()è essenzialmente simile main(), tranne per il fatto che viene chiamato più volte. riferimento: arduino.cc/en/Reference/loop controllerò quel link.
eqzx,

di nuovo, come ho già detto in altri commenti, non posso eseguire il debug con Serial.print(). Sembra che dovrò fuori processingdall'IDE normale se voglio poter usare GDB
eqzx

@ nrhine1 Hai detto che Serial.print()stava funzionando bene in quanto stava stampando molto "ehi". È loop_counterche ti sta dando un problema. Prova a rimuovere il if(loop_counter == 0)codice e a inserire il get_free_memory()codice (lascia l' loop_counterincremento) ed eseguilo. Questo ti dirà almeno se hai grossi problemi con l'allocazione della memoria.
embedded.kyle,

1

La libreria seriale del software Arduino utilizza gli interrupt. (vedi "softwareSerial.cpp, .h"). Potresti avere un problema in cui l'ISR sta "calpestando" il codice principale (o viceversa). Prova a utilizzare i flag di interblocco, in modo che il codice sia in attesa al completamento delle operazioni di stampa.


0

Ad un certo punto qualche tempo fa ho avuto l'impressione di avere lo stesso problema. Allora, l'ho risolto aggiungendo un ritardo (1) davanti o dopo il serial.println. Quello era con Arduino 0022 su Linux. Non sono sicuro di quale scheda fosse, probabilmente un seriale Boarduino. Non posso riprodurlo neanche.

Attualmente, funziona per me su un boarduino USB con Arduino 1.01 su 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!");
    }      
}

Grazie per il suggerimento Purtroppo non ha risolto il problema.
eqzx,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.