質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • Arduino

    515questions

    Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

ArduinoでString(val, base) の動作が安定しない。メモリリーク?

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 376

fenri

score 3

Arduino pro mini にてRTCや外付けのEEPROMを使ったプログラムを書いているのですが

String(val, base)の結果がうまく出ません。
文字列(str)の文字数を2桁のHEXで別の文字列に格納しようとしています。

~略~
  String str = "test";
  String sLen = String( (int)str.length(), HEX);
  if (sLen.length() == 1)
    sLen = "0" + sLen;

  Serial.print("sLen:");
  Serial.println(sLen);
  Serial.flush();

上記プログラムを単体で動作させると正常に動作出来るのですが、
全く同じ文を今作成しているものに組み込むとString(val, base) の結果をprintしても何も表示されません。
(sLen:が出力される)

またsLenが何表示されないプログラム内の全く別のソースを一部削ると正常に動作します。
(sLen:04が出力される)

このことからメモリーリーク等を疑っているのですが
何か確認できる方法はありますでしょうか。

追記:
正常に動作出来る状態(*本来必要なソースを削った状態*)から
上記ソースの最後にprintを一行追加した所、また値が何も表示されなくなりました。

  Serial.print("sLen:");
  Serial.println(sLen);
  Serial.print("sLen2:"); // 追記したらsLenが何も表示されない
  Serial.flush();

コンパイル時のメッセージでは

最大30720バイトのフラッシュメモリのうち、スケッチが19632バイト(63%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が1452バイト(70%)を使っていて、ローカル変数で596バイト使うことができます。

~中略~

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

と表示されています。

開発環境:Windows10 ArduinoIDE
Arduino pro mini 3.3V 8MHz

*追記1 2018/04/19*
以下のソースを追記した所
やはりStringの結果が返ってきていないように見えます。
別のString変数 cmd に "@"、 str文字数、strの文字列、 "/A" を格納し
シリアルにて出力させてみたところ
strの文字数の部分のみ表示されませんでした。

~略~
  String cmd = "";
  String str = "test";
  String sLen = String( (int)str.length(), HEX);
  if (sLen.length() == 1)
    sLen = "0" + sLen;

  Serial.print("sLen:");
  Serial.println(sLen);
  Serial.flush();

  cmd += "@";
  cmd += sLen;
  cmd += str;
  cmd += "/A";

  debugSerial.print("cmd:");
  debugSerial.println(cmd);
  debugSerial.flush();

出力結果
cmd:@test/A

*追記2 2018/04/19*
グローバル変数で結構な量を配列で定義していたものを一時的に減らした所
正常動作することを確認しました。
どうもこの辺りがあやしいのかもしれません。

ちなみにその時のコンパイル後のメッセージは
最大30720バイトのフラッシュメモリのうち、スケッチが19624バイト(63%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が1166バイト(56%)を使っていて、ローカル変数で882バイト使うことができます。
となっていました。

もうちょっと調べてみようと思います。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

メモリリークと言うのはちょっと考えづらいように思います。

ArduinoのStringオブジェクトはかなりプリミティブなものに見受けられ、ご提示のコードのような、基本的な操作ですぐメモリリークを起こすようなものには思えません。

全く同じ文を今作成しているものに組み込むとString(val, base) の結果をprintしても何も表示されません。

とのことですので、ハードウェアに依存した問題のような気がします。シリアル出力の部分で問題が出ているかもしれません。通信速度を遅くしてみたり、出力する文字列を1文字ずつ、更にディレイとSerial.flush()を追加してみたりして、問題点の切り分けをしてみてください。

原因がまた違うところにあれば、更に詳しい別の回答者さんのフォローを私も待ちたいところです。

下のコードは、自作のprintOneByOne関数でStringオブジェクトの文字列をひとつずつ出力する例です。通信速度は9.600bpsにして、1文字ずつ、Serial.flushして100ミリ秒待機もさせています。これくらいやればいくらなんでも通信用チップの送信用FIFOバッファがあふれるようなことも無いでしょう。

int num;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  num = 0;
}

void printOneByOne(String& s) {
  for (int i = 0; i < s.length(); i++) {
    Serial.print(s.charAt(i));
   Serial.flush();
    delay(100);
  }
  Serial.println("");
  Serial.flush();
}

void loop() {
  // put your main code here, to run repeatedly:
  num++;
  Serial.println(num);
  Serial.flush();
  delay(500);

  String str = "test";
  printOneByOne(str);
}


上記のコードをArduinoUNOで走らせ、シリアルモニターで確認している様子です。
イメージ説明

ご参考まで。


追記しました: 2018/04/18 11:24

回答した後に質問を見直して気がつきましたが、お使いのものは「Arduino pro mini 3.3V 8MHz」とのことで低電圧で電源供給能力が少し弱いのかもしれません。周辺のハードウェアを色々付けていると影響が無いとも言えません。

ご提示のコードですとSerial.printlnを実行したときに出力されるべき文字列の先頭の方がデータが欠けている様子なので、シリアル出力の立ち上がりに問題が出ているようにも思えます。通信速度を下げると改善するかも、です。(これもあくまで「可能性としてあるかも?」程度の思い付きの意見です)


質問の追記2を受けて更に追記:2018/04/19 12:34

ローカル変数の領域が残り882バイトですと、スタック領域としてかなり切迫していると思います。
(まぁ、RAMが2048バイトなら仕方が無いですが)

どこか、自作のコード部分でメモリを破壊している可能性が高いように思います。
Stringオブジェクトのメモリリークと言うよりは、Stringオブジェクトは恐らく被害者かと。

自作の関数の呼び出しが深くなっていないか、自作の関数の中でローカル(auto)変数を無駄に多く使っていないかなどをチェックして、スタックをなるべく使わないよう工夫してみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/19 09:46

    回答ありがとうございます。
    5V 16Mhzに焼き、Arduino単体で動作させてみましたが現象変わらずでした。
    質問の方に追記しようと思いますが、どうもシリアルの出力ではなさそうです。

    キャンセル

  • 2018/05/01 19:58

    グローバル変数を減らしRAMの空きを増やした所安定したようです。
    まだ確定ではないので引き続き注意しながらやってみようと思います。
    ありがとうございました。

    キャンセル

0

dodox86氏の回答にありますように”電源不足”が可能性として高いと考えます。
まず予測の根拠として提示されているソース以外のボリュームが大きい(コンパイル結果から)。
予想としてRTC以外にも何かハードを使用しているのでは?

またメモリーリークか否かを判断するために

  Serial.print("sLen:");
  Serial.println(sLen);
  Serial.print("sLen2:"); // 追記したらsLenが何も表示されない
  Serial.flush();


の部分を

  Serial.print("sLen:");
  Serial.println("4");
  Serial.print("sLen2:"); // 追記したらsLenが何も表示されない
  Serial.flush();


と仮に書いての実行結果で判断。(メモリーを使用しない)

もしこれで表示されなければ電源を疑うべき。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/19 09:43

    回答ありがとうございます。
    上記ソースに書き換えてみた所正常に表示されました。

    確かにRTC以外にも付いているのでArduino単体で動作させてみましたが、
    現象は変わらず[sLen:\r\n]が出力されました。
    また間にdelayを入れても現象変わらず、表示されていません。
    質問の方に追記しますが、どうもシリアルの出力ではなくやはり
    Stringの結果が返ってきていないようです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Arduino

    515questions

    Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。