L'impression série Arduino modifie le comportement du programme de manière indésirable

10

J'utilise un compteur de boucles, déclaré dans un en-tête:

int loop_counter = 0;

J'utilise ce compteur pour déclencher un événement de temps en temps. J'avais l'habitude d'utiliser un modulo pour ce même type de comportement, mais je l'ai simplifié pour qu'il soit plus facile de travailler avec (il en résulte toujours le même comportement)

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

    //Serial.println("hey");

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

Tout va bien, jusqu'à ce que j'essaie de communiquer avec Serialen décommentant le //Serial.println("hey"); ( "hey"dans cet exemple parce que, pour moi, ce comportement est absurde).

Cela se traduit par loop_counterne jamais déclencher la do_something_important();section de code. J'ai essayé de déclarer loop_counterque volatilecela ne changeait rien. J'ai essayé Serial.printing loop_counter, et j'obtenais aussi un comportement étrange (cela gèlerait la boucle). Serial.println("hey");fonctionne en ce sens que dans le moniteur série, j'obtiens beaucoup de "hey", (c'est-à-dire rapidement beaucoup plus de 100 "heys", le nombre d'itérations auxquelles l'autre section de code devrait se déclencher)

Qu'est-ce qui pourrait éventuellement causer l'utilisation de Serial, avec des données qui ne sont pas (pour autant que je sache) liées à l' loop_counterempêcher complètement de fonctionner correctement?

EDIT : Voici la partie du fichier principal qui a fini par poser le problème (enfin, y contribuer le plus (utiliser trop de mémoire)):



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

Voici "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;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 short * data;const short * data ; letter_node * suivant;* suivant ; 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 ]; #fin si#fin si

Quelques informations supplémentaires: - J'utilise un Uno (ATMega328)

eqzx
la source
Quelle est la taille de votre pile? Y a-t-il une chance que vous puissiez peindre votre pile et voir si elle est corrompue. L'impression série utilise-t-elle des interruptions, votre code est-il réentrant?
Ktc
L'impression série n'est déclenchée par aucune interruption, je ne l'utilise que dans la loop()fonction. Comment dois-je peindre ma pile si la seule méthode de sortie que j'ai ( Serial.print()) échoue?
eqzx
2
Pour éliminer les erreurs possibles et les effets secondaires incompris de changements apparemment insignifiants, veuillez remplacer le code de votre question par une copie littérale et exacte d'un croquis réduit au minimum nécessaire pour déclencher le problème . Pas "c'est mon programme qui échoue si je .." mais exactement le programme minimum qui échoue de cette façon.
Chris Stratton

Réponses:

2

J'ai également eu un problème similaire à cela, et je suis très sûr que le vôtre est également hors de l'espace de pile. Essayez de réduire le code autant que possible.

Dans mon cas, le code s'exécutait parfois lorsque j'avais un message série, mais il semblait alors ne pas fonctionner lorsque je ne le faisais pas. J'ai également eu un cas où l'envoi de messages série entraînerait la réinitialisation sans fin de l'arduino.

J'utilisais également un arduino328. Vous devriez probablement réduire la taille de votre baie si vous en avez une à la plus petite taille acceptable.

Reza Hussain
la source
merci, vous et Dave Tweed l'avez compris. J'ai refactorisé la fonction display_state () pour ne pas avoir besoin de cette allocation supplémentaire. Je fais rarement du traitement intégré, je suppose que nous devons tous frapper le mur de la mémoire à un moment donné!
eqzx
Bonjour, j'ai la situation similaire. Je change la taille du tableau de 128 à 96 et mon programme fonctionne bien. Mais je pense que ce problème est vraiment hors de propos pour déboguer, car la taille de mon tableau est inférieure à la taille de la pile de déclaration. Savez-vous où trouver des informations pour faire face à ce type de problème?
Lion Lai
4

Votre code initialise-t-il le port série? Par exemple.

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

Ne pas le faire pourrait entraîner un crash lors de la première utilisation de la série.

Toby Jaffey
la source
Oui, je l'ai.
eqzx
3

Peut-être que vous manquez de mémoire? Toutes les chaînes que vous imprimez avec Serial.print ("quelque chose") ont lieu dans SRAM, égal au nombre de caractères de cette chaîne + 1 pour le terminateur \ 0. Il est possible de manquer de mémoire même si la taille compilée de votre croquis est beaucoup plus petite que la mémoire flash Arduino, car SRAM n'est que de 2048 octets pour Atmega328 et 1024 octets pour Atmega 168. J'ai eu un problème similaire, que j'ai résolu en raccourcissant tout textes et supprimer les messages de débogage inutiles.

Erion
la source
Hmm. J'ai plusieurs tableaux multidimensionnels déclarés dans mon en-tête, c'est peut-être le problème? Sont-ils stockés dans SRAM?
eqzx
1
@ nrhine1: Dans ce cas, vous devriez probablement nous montrer l'intégralité de votre croquis, pas seulement les parties où vous pensez que le problème réside.
Dave Tweed
@DaveTweed Oui, ça va.
eqzx
1
Je remarque que vous définissez beaucoup de stockage dans votre fichier d'en-tête, plutôt que de simplement le déclarer là (si vous ne comprenez pas la distinction, voir cette page ). Ce serait inhabituel dans un programme C; est-ce la pratique normale sur Arduino? Vous pourriez vous retrouver avec plusieurs copies de ces structures. De plus, vous définissez de très grandes variables automatiques, telles que le tableau "vivant" dans display_state (), qui nécessite plus de 1024 octets d'espace de pile. Je suis presque sûr que vous manquez tout simplement de mémoire.
Dave Tweed
@DaveTweed merci, vous et Reza l'avez compris. J'ai refactorisé la display_state()fonction pour ne pas avoir besoin de cette allocation supplémentaire. Je fais rarement du traitement intégré, je suppose que nous devons tous frapper le mur de la mémoire à un moment donné!
eqzx
1

Vous n'avez pas montré le code qui initialise la variable "loop_counter". Est-ce en dehors de la routine loop () ?

Avez-vous éventuellement déclaré cela de manière à ce qu'il soit adjacent à une autre zone de stockage de mémoire qui fonctionne en dehors de sa taille déclarée et ce trompe sur la variable loop_counter?

Michael Karas
la source
J'ai essayé de le déclarer de différentes manières, dans de nombreux endroits différents. Dans l'en-tête, juste au loop()- dessus , etc. Êtes-vous en train de dire que la Serial.print()méthode pourrait l'écraser d'une manière ou d'une autre?
eqzx
Ce que je voulais dire par le commentaire précédent, c'est que je suis presque certain d'avoir isolé le «mauvais» comportement de l'existence de Serial.print (). Quand il n'est pas là, les choses fonctionnent bien.
eqzx
@ nrbine1 - Il me semble que votre variable variable globale "loop_counter" est mise en marche par la méthode Serial.print () comme je l'ai suggéré dans ma réponse. Dans la réponse de posipiet, on vous a demandé si l'objet Serial avait été correctement initialisé. Si cela n'a pas été fait, cela peut expliquer le "trompage" sur votre compteur alors que Serial.print () tente d'utiliser un tampon qui n'a pas été correctement alloué et configuré.
Michael Karas
J'ai ajouté toute ma source.
eqzx
1

Je ne vois pas dans votre code où vous appelez loop(). Il ne semble pas non plus que vous utilisiez en loop_counterdehors de cette fonction. Y a-t-il une raison pour laquelle vous le déclarez mondial? Je suppose que c'est parce que vous voulez qu'il conserve sa valeur entre les appels. Vous pouvez le faire avec une variable locale statique à la place.

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

Cela devrait garantir qu'aucune autre fonction externe ne puisse y piétiner. Vous devez toujours déclarer vos variables dans la plus petite étendue possible pour éviter tout comportement indésirable.

Si cela ne fonctionne pas, vous devrez vraiment analyser votre utilisation de la mémoire. Consultez ce Q&A EE.SE pour divers exemples de code pour le faire dans un Arduino.

embedded.kyle
la source
J'ai déjà essayé de le rendre statique. Cela n'a pas aidé. Il s'agit d'une itération différente. setup()et loop()sont des fonctions qu'arduino exécute par défaut, en setup()premier, en loop()second. loop()est essentiellement similaire main(), sauf qu'il est appelé à plusieurs reprises. référence: arduino.cc/en/Reference/loop Je vais vérifier ce lien.
eqzx
encore une fois, comme je l'ai mentionné dans d'autres commentaires, je ne peux pas déboguer avec Serial.print(). Il semble que je devrai sortir de l' processingIDE normal si je veux pouvoir utiliser GDB
eqzx
@ nrhine1 Vous avez dit que cela Serial.print()fonctionnait bien dans la mesure où cela imprimait beaucoup "hé". C'est loop_countercela qui vous pose un problème. Essayez de supprimer le if(loop_counter == 0)code et de mettre le get_free_memory()code (laissez l' loop_counterincrément) et de l'exécuter. Cela vous indiquera au moins si vous avez des problèmes majeurs avec votre allocation de mémoire.
embedded.kyle
1

La bibliothèque série du logiciel Arduino utilise des interruptions. (voir "softwareSerial.cpp, .h"). Vous pouvez avoir un problème où l'ISR "marche" sur le code principal (ou vice versa). Essayez d'utiliser des drapeaux de verrouillage, de sorte que le code attend pendant la fin des opérations d'impression.

Bob Kugler
la source
0

Il y a quelque temps, j'ai eu l'impression d'avoir le même problème. À l'époque, je l'ai résolu en ajoutant un délai (1) devant ou après le serial.println. C'était avec Arduino 0022 sous Linux. Je ne sais pas de quelle carte il s'agissait, probablement une série Boarduino. Je ne peux pas non plus le reproduire.

Actuellement, cela fonctionne pour moi sur un boarduino USB avec Arduino 1.01 sous 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
la source
Merci pour la suggestion. Cela n'a malheureusement pas résolu le problème.
eqzx