Arduinoシリアルプリントはプログラムの動作を望ましくなく変更します


10

ヘッダーで宣言されているループカウンターを使用しています。

int loop_counter = 0;

私はこのカウンターを使用して、時々イベントをトリガーします。私はこれと同じタイプの動作にモジュロを使用していましたが、操作を簡単にするために単純化しました(それでも同じ動作になります)

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

    //Serial.println("hey");

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

(この例では、この動作はばかげているので、この例ではSerialコメントを外して)通信を試みるまで、すべてが順調です。//Serial.println("hey");"hey"

これにより、コードloop_counterdo_something_important();セクションがトリガーされることはありません。と宣言しloop_counterてみましたがvolatile、何も変わりませんでした。私が試したSerial.printINGのloop_counter、そして私も(それがループをフリーズします)異常な動作を得ていました。 Serial.println("hey");シリアルモニターでたくさんの「ねえ」を取得するという意味で機能します(つまり、すぐに100を超える「ねえ」、コードの他のセクションがトリガーする必要がある反復の数)。

の使用を引き起こしている可能性のあるものは何ですか?Serial(私が知る限り)loop_counter正しく関連付けられていないデータが関連付けられていませんか?

編集:問題を引き起こしてしまったメインファイルの一部を次に示します(まあ、それに最も貢献しています(メモリの使用が多すぎます))。



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

これが「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 ; 短いled_matrix [ num_rows ] [ num_cols ];

CONST 短い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 短いletter_c [ NROWS ] [ ncolsの] = {{ 0 1 1 1 }、{ 1 0 0 0 }、{ 1 0 0 0 }、{ 0 1 1 1 }}。CONST 短い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 * ; int 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

その他の情報:-Unoを使用しています(ATMega328)


スタックサイズは何ですか?スタックをペイントして、破損しているかどうかを確認できる可能性はありますか。シリアルプリントは割り込みを使用していますか?コードは再入可能ですか?
Ktc 2012

シリアルプリントは割り込みによってトリガーされず、loop()関数でのみ使用します。私が持っている唯一の出力方法(Serial.print())が失敗した場合、スタックをどのようにペイントすればよいですか?
eqzx 2012

2
一見ささいな変更の可能性のある間違いや誤解されている副作用を排除するには、問題のトリガーに必要な最小限にカットされた、スケッチの文字どおりの正確なコピーで質問のコードを置き換えてください。「これは私が失敗すると失敗する私のプログラムです」ではなく、まさにこの方法で失敗する最小のプログラムです。
Chris Stratton

回答:


2

私もこれと同様の問題を抱えていて、あなたのスタックスペースも関連していると確信しています。コードを可能な限り縮小してみてください。

私の場合、シリアルメッセージが含まれているとコードが実行されることがありますが、そうでない場合は実行されないようです。また、シリアルメッセージを送信するとArduinoが無限にリセットされる場合もありました。

私はarduino328も使用していました。許容できる最小のサイズがある場合は、アレイのサイズを小さくする必要があります。


ありがとう、あなたとデイブ・ツイードがそれを手に入れました。その余分な割り当てを必要としないように、display_state()関数をリファクタリングしました。組み込み処理を行うことはめったにありませんが、ある時点で全員がメモリの壁にぶつかる必要があると思います!
eqzx 2012

こんにちは、私も同じような状況です。配列のサイズを128から96に変更すると、プログラムは正常に動作します。しかし、私の配列のサイズは宣言スタックサイズよりも小さいため、この問題は実際にはデバッグできません。この種の問題に対処するための情報がどこにあるか知っていますか?
ライオンライ

4

あなたのコードはシリアルポートを初期化しますか?例えば。

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

これを怠ると、シリアルを初めて使用するときにクラッシュする可能性があります。


はい、あります。
eqzx 2012

3

たぶんあなたはメモリを使い果たしていますか?Serial.print( "something")で印刷するすべての文字列は、その文字列の文字数+ \ 0ターミネータの1に等しいSRAMで行われます。SRAMはAtmega328の場合は2048バイト、Atmega 168の場合は1024バイトしかないため、スケッチのコンパイルサイズがArduinoフラッシュメモリよりもはるかに小さい場合でも、メモリ不足になる可能性があります。同様の問題があり、すべて短縮して解決しましたテキストと不要なデバッグメッセージの削除。


うーん。ヘッダーで複数の多次元配列が宣言されていますが、それが問題なのでしょうか?それらはSRAMに保存されますか?
eqzx 2012

1
@ nrhine1:その場合、問題があると思われる部分だけでなく、スケッチ全体を表示する必要があります。
Dave Tweed 2012

@DaveTweedはい、そうします。
eqzx 2012

1
ヘッダーファイルで単に宣言するのではなく、多くのストレージをヘッダーファイルで定義していることに気づきました(違いがわからない場合は、このページを参照してください)。これはCプログラムでは珍しいことです。Arduinoでの通常の練習ですか?これらの構造の複数のコピーが作成される可能性があります。また、1024バイトを超えるスタック領域を必要とする、display_state()の「alive」配列など、いくつかの非常に大きな自動変数を定義しています。私はあなたが単にメモリを使い果たしていると確信しています。
Dave Tweed 2012

@DaveTweedありがとう、あなたとRezaはそれを手に入れました。display_state()その余分な割り当てを必要としないように関数をリファクタリングしました。組み込み処理を行うことはめったにありませんが、ある時点で全員がメモリの壁にぶつかる必要があると思います!
eqzx 2012

1

変数「loop_counter」を初期化するコードは示していません。それはloop()ルーチンの外ですか?

宣言されたサイズの範囲外で動作している別のメモリストレージ領域に隣接し、loop_counter変数がこのように宣言されている可能性がありますか?


私は多くの異なる方法で、多くの異なる場所でそれを宣言しようとしました。ヘッダーの真上loop()など。Serial.print()メソッドが何らかの方法で上書きしている可能性があると言っていますか?
eqzx 2012

以前のコメントで私が言ったことは、「悪い」動作をSerial.print()の存在に分離したことはほぼ肯定的だということです。そこにない場合、問題はありません。
eqzx 2012

@ nrbine1-私の回答で提案したように、グローバル変数変数「loop_counter」がSerial.print()メソッドによって実行されているようです。posipietによる回答では、シリアルオブジェクトが適切に初期化されているかどうかを尋ねられました。それが行われていない場合、Serial.print()が適切に割り当てられて設定されていないバッファを使用しようとするため、カウンタが「切り替わる」可能性があります。
Michael Karas

すべてのソースを追加しました。
eqzx 2012

1

私はあなたのコードであなたがどこを呼んでいるか見ませんloop()。またloop_counter、その関数の外で使用しているようにも見えません。グローバルと宣言する理由はありますか?私はそれがあなたがそれが呼び出しの間でそれの価値を保持することを望んでいるからだと思います。代わりに、静的ローカル変数を使用してこれを行うことができます。

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

これにより、他の外部関数が踏みつけられないようにする必要があります。不要な動作を避けるために、変数は可能な限り最小のスコープで常に宣言する必要があります。

それが機能しない場合は、実際にメモリ使用量を分析する必要があります。Arduino内でこれを行うためのさまざまなサンプルコードについては、このEE.SE Q&Aを確認してください。


既に静的にしてみました。それは助けにはならなかった。これは別のイテレーションです。setup()そして、loop()、デフォルトで実行をArduinoの機能でありsetup()、最初のloop()二つ目は。 繰り返し呼び出されることを除いて、loop()本質的にに似main()ています。参照:arduino.cc/en/Reference/loop そのリンクを確認します。
eqzx 2012

繰り返しになりますが、他のコメントで述べたように、でデバッグすることはできませんSerial.print()processingGDBを使用できるようにするには、通常のIDEの外部に移動する必要があるようです
eqzx

@ nrhine1 Serial.print()「ねえ」をたくさん出力するという点で、それはうまく機能していたとおっしゃいました。それloop_counterが問題を引き起こしているのです。if(loop_counter == 0)コードを削除してコードをget_free_memory()挿入し(loop_counter増分を残して)、実行してみてください。これにより、少なくともメモリ割り当てに大きな問題があるかどうかがわかります。
embedded.kyle

1

Arduinoソフトウェアシリアルライブラリは割り込みを使用します。(「softwareSerial.cpp、.h」を参照)。ISRがメインコードを「ステップ」している(またはその逆)問題がある場合があります。インターロックフラグを使用して、印刷操作が完了するまでコードが待機するようにしてください。


0

ある時点で、私は同じ問題を抱えているような印象を受けました。当時、serial.printlnの前後に遅延(1)を追加することで解決しました。それはLinux上のArduino 0022でした。どちらのボードかわからない、おそらくBoarduinoシリアル。どちらも再現できません。

現在、私はWindowsのArduino 1.01を搭載したboarduino USBで動作します。

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

提案をありがとう。残念ながら問題は解決しませんでした。
eqzx 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.