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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Arduino

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

Q&A

解決済

2回答

1641閲覧

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

fenri

総合スコア11

Arduino

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

0グッド

0クリップ

投稿2018/04/18 00:53

編集2018/04/19 03:03

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

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

c

1~~ 2 String str = "test"; 3 String sLen = String( (int)str.length(), HEX); 4 if (sLen.length() == 1) 5 sLen = "0" + sLen; 6 7 Serial.print("sLen:"); 8 Serial.println(sLen); 9 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の文字数の部分のみ表示されませんでした。

c

1~~ 2 String cmd = ""; 3 String str = "test"; 4 String sLen = String( (int)str.length(), HEX); 5 if (sLen.length() == 1) 6 sLen = "0" + sLen; 7 8 Serial.print("sLen:"); 9 Serial.println(sLen); 10 Serial.flush(); 11 12 cmd += "@"; 13 cmd += sLen; 14 cmd += str; 15 cmd += "/A"; 16 17 debugSerial.print("cmd:"); 18 debugSerial.println(cmd); 19 debugSerial.flush();

出力結果
cmd:@test/A

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

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

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

arduino

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

の部分を

arduino

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

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

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

投稿2018/04/18 04:13

MasahikoHirata

総合スコア3747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fenri

2018/04/19 00:43

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

0

ベストアンサー

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

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

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

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

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

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

C++

1int num; 2void setup() { 3 // put your setup code here, to run once: 4 Serial.begin(9600); 5 num = 0; 6} 7 8void printOneByOne(String& s) { 9 for (int i = 0; i < s.length(); i++) { 10 Serial.print(s.charAt(i)); 11  Serial.flush(); 12 delay(100); 13 } 14 Serial.println(""); 15 Serial.flush(); 16} 17 18void loop() { 19 // put your main code here, to run repeatedly: 20 num++; 21 Serial.println(num); 22 Serial.flush(); 23 delay(500); 24 25 String str = "test"; 26 printOneByOne(str); 27}

上記のコードを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/18 02:02

編集2018/04/19 03:34
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fenri

2018/04/19 00:46

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

2018/05/01 10:58

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問