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

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

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

バイナリは、「0」と「1」だけで表現されている2進数のデータ形式。または、テキスト以外の情報でデータが記述されているファイルを指します。コンピューター内の処理は全て2進数で表記されています。

シリアルポート

シリアルポートは一度に一ビットごと移行される物理的なインターフェイスです。一般的には、9ピンのd-subコネクタであるRS-232を指します。

Arduino

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

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

Q&A

解決済

3回答

2198閲覧

loop関数が実行されず、setup関数が繰り返される。

photan

総合スコア5

バイナリ

バイナリは、「0」と「1」だけで表現されている2進数のデータ形式。または、テキスト以外の情報でデータが記述されているファイルを指します。コンピューター内の処理は全て2進数で表記されています。

シリアルポート

シリアルポートは一度に一ビットごと移行される物理的なインターフェイスです。一般的には、9ピンのd-subコネクタであるRS-232を指します。

Arduino

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

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

0グッド

0クリップ

投稿2020/04/11 07:38

編集2020/04/11 18:00

前提・実現したいこと

マイコンのATmega1284Pを用いて様々なセンサーを使い得たデータをバイナリデータとして送信したいです。

発生している問題・エラーメッセージ

setup()関数の処理が終了したことを示す"Start"が出力された後、loop()関数で出力されるはずのバイナリデータが出力されずにまたsetup()関数に戻り“Start”が出力され、それが繰り返されています。たまにloop関数が作動してバイナリデータがシリアルモニタに出力されることもありますが、4,5回でまたsetup()関数に戻り“Start”が出力されます。
ATmega1284PはArduinoIDEでブートローダーを書き込み、arduino互換機として動作させています。

該当のソースコード

arduino

1#include <Wire.h> 2#include <MadgwickAHRS.h> 3#include <math.h> 4#include <SoftwareSerial.h> 5 6//ピン番号 7int r_pin = A0; 8int e_pin = A1; 9int h_pin = 0; 10int cad_pin = 1; 11int A_pin = 2; 12 13//ソフトウェアシリアル(rx, tx) 14SoftwareSerial GPSSerial(18, 19); 15SoftwareSerial W0Serial(20, 21); 16SoftwareSerial MissileSerial(22, 23); 17 18const byte HEAD_BYTE = 0x7E; 19const byte ESCAPE_BYTE = 0x7D; 20const byte ESCAPE_MASK = 0x20; 21float data[18]; 22byte buf[48] = {HEAD_BYTE, 0, 0, 0, 0, 0, 0, 0}; 23byte Sequence = 0; 24 25void setup() { 26 Serial.begin(115200); 27 Serial1.begin(19200); 28 pinMode(cad_pin,INPUT); 29 pinMode(r_pin,INPUT); 30 pinMode(e_pin,INPUT); 31 pinMode(h_pin,INPUT); 32 attachInterrupt(2, PulseCount, RISING); 33 34 GPS_Init(); 35 W0Serial.begin(9600); 36 MissileSerial.begin(9600); 37 38 Wire.begin(); 39 BMX055_Init(); 40 LPS25HB_Init(); 41 Serial.println("Start"); 42} 43 44void loop() { 45 dataAquisition(); 46 Recordbuf(data); 47 for(int i=0; i<48; i++){ 48 Serial.print(buf[i],HEX); 49 Serial.print(" "); 50 } 51 Serial.println(""); 52} 53 54//データ取得 55void dataAquisition() { 56 int rud = analogRead(r_pin); 57 int elv = analogRead(e_pin); 58 59 data[0] = rud; 60 data[1] = elv; 61 getrpm(); 62 getHeight(); 63 getAttitude(); 64 getGPS(); 65 getBaro(); 66 getASpeed(); 67 data[13] = -13.32; 68 data[14] = 1.26; 69 data[15] = -2.1; 70 data[16] = 1.23; 71 data[17] = 7.86; 72} 73 74//データ変換 75void Recordbuf(float d[]) { 76 Sequence++; 77 unsigned long integerData[18]; //小数点があると嫌 78 for (int i = 0; i < 18; i++) { 79 switch (i) { 80 case 0: 81 case 1: 82 integerData[i] = d[i]; 83 break; 84 85 case 2: 86 case 10: 87 integerData[i] = d[i] * 10; 88 break; 89 90 case 7: 91 case 8: 92 integerData[i] = d[i] * 10000000; 93 break; 94 95 default: 96 integerData[i] = d[i] * 100; 97 } 98 } 99 buf[1] = Sequence; 100 buf[8] = (integerData[0] >> 0) & 0xFF; 101 buf[9] = (integerData[0] >> 8) & 0xFF; 102 buf[10] = (integerData[1] >> 0) & 0xFF; 103 buf[11] = (integerData[1] >> 8) & 0xFF; 104 buf[12] = (integerData[2] >> 0) & 0xFF; 105 buf[13] = (integerData[2] >> 8) & 0xFF; 106 buf[14] = (integerData[3] >> 0) & 0xFF; 107 buf[15] = (integerData[3] >> 8) & 0xFF; 108 buf[16] = (integerData[4] >> 0) & 0xFF; 109 buf[17] = (integerData[4] >> 8) & 0xFF; 110 buf[18] = (integerData[5] >> 0) & 0xFF; 111 buf[19] = (integerData[5] >> 8) & 0xFF; 112 buf[20] = (integerData[6] >> 0) & 0xFF; 113 buf[21] = (integerData[6] >> 8) & 0xFF; 114 buf[22] = (integerData[7] >> 0) & 0xFF; 115 buf[23] = (integerData[7] >> 8) & 0xFF; 116 buf[24] = (integerData[7] >> 16) & 0xFF; 117 buf[25] = (integerData[7] >> 24) & 0xFF; 118 buf[26] = (integerData[8] >> 0) & 0xFF; 119 buf[27] = (integerData[8] >> 8) & 0xFF; 120 buf[28] = (integerData[8] >> 16) & 0xFF; 121 buf[29] = (integerData[8] >> 24) & 0xFF; 122 buf[30] = (integerData[9] >> 0) & 0xFF; 123 buf[31] = (integerData[9] >> 8) & 0xFF; 124 buf[32] = (integerData[10] >> 0) & 0xFF; 125 buf[33] = (integerData[10] >> 8) & 0xFF; 126 buf[34] = (integerData[11] >> 0) & 0xFF; 127 buf[35] = (integerData[11] >> 8) & 0xFF; 128 buf[36] = (integerData[12] >> 0) & 0xFF; 129 buf[37] = (integerData[12] >> 8) & 0xFF; 130 buf[38] = (integerData[13] >> 0) & 0xFF; 131 buf[39] = (integerData[13] >> 8) & 0xFF; 132 buf[40] = (integerData[14] >> 0) & 0xFF; 133 buf[41] = (integerData[14] >> 8) & 0xFF; 134 buf[42] = (integerData[15] >> 0) & 0xFF; 135 buf[43] = (integerData[15] >> 8) & 0xFF; 136 buf[44] = (integerData[16] >> 0) & 0xFF; 137 buf[45] = (integerData[16] >> 8) & 0xFF; 138 buf[46] = (integerData[17] >> 0) & 0xFF; 139 buf[47] = (integerData[17] >> 8) & 0xFF; 140}

Serial.printで送信している箇所(loop内のfor文以降)はデバッグのためにprintを使っていますので、printで正常な動作が見られたら以下のように置き換えるつもりです。

Serial.write(buf[0]); for (int i = 1; i < 48; i++) { if (buf[i] == HEAD_BYTE | buf[i] == ESCAPE_BYTE) { Serial.write(ESCAPE_BYTE); Serial.write(buf[i] ^ ESCAPE_MASK); } else { Serial.write(buf[i]); } }

試したこと

dataAquisition()関数の中に以下のようにシリアルプリントを挿入したらうまくいきました。

arudino

1void dataAquisition() { 2 int rud = analogRead(r_pin); 3 int elv = analogRead(e_pin); 4 5 data[0] = rud; 6 data[1] = elv; 7 getrpm(); 8 Serial.println("get rpm"); 9 getHeight(); 10 Serial.println("get Height"); 11 getAttitude(); 12 Serial.println("get Attitude"); 13 getGPS(); 14 Serial.println("get GPS"); 15 getBaro(); 16 Serial.println("get Baro"); 17 getASpeed(); 18 Serial.println("get AirSpeed"); 19 data[13] = -13.32; 20 data[14] = 1.26; 21 data[15] = -2.1; 22 data[16] = 1.23; 23 data[17] = 7.86; 24}

ただ、最終的には余計なデータ送信をしたくないのでこれらのデバッグ用のシリアル送信は削除したいと思っています。Serial.printlnの有無で挙動が変わるというのも不可解です。

####追記
プログラムが止まるタイミングからgetGPS()関数が怪しいと思いコメントアウトしてみたところ、デバッグ用のシリアル通信を削除した上でバイナリデータの送信が成功しました。getGPS()関数は以下になります。

void getGPS() { String line; String s; double LAT; //緯度 double LNG; //経度 double GS; //対地速度 GPSSerial.listen(); while (!GPSSerial.isListening()); //1つのセンテンスを読み込む do { String line = GPSSerial.readStringUntil('\n'); if (line != "") { int i, index = 0, len = line.length(); String str = ""; //Stringlist生成 String list[30]; for (i = 0; i < 30; i++) { list[i] = ""; } //「,」を区切り文字として文字列を配列にする for (i = 0; i < len; i++) { if (line[i] == ',') { list[index++] = str; str = ""; continue; } str += line[i]; } //$GPRMCセンテンスを読み込んで、緯度、経度、対地速を表示する if (list[0] == "$GPRMC") { //素子に応じて$以下の部分を変える if (list[2] == "A") { //GPSが測位不可でない時 //緯度 LAT = NMEA2DD(list[3].toFloat()), 6; //経度 LNG = NMEA2DD(list[5].toFloat()), 6; //対地速(km/h) GS = list[7].toFloat() * 1.852; //1ノット=1.852km/h } s += String(LAT, 6); s += String(LNG, 6); s += (String)GS; data[7] = LAT; data[8] = LNG; data[9] = GS; } } } while (s == ""); //ちゃんと読めるまで } //NMEAの緯度経度を「度」(DD)の表記に変換 float NMEA2DD(float val) { float u; int d = val / 100; int m = (((val / 100.0) - d) * 100.0) / 60; float s = (((((val / 100.0) - d) * 100.0) - m) * 60) / (60 * 60); u = d + m + s; return u; }

秋月電子通商で販売されているGPSモジュールを使用しています。通信にはソフトウェアシリアルを使用しています。

補足情報(FW/ツールのバージョンなど)

dataAquisition()関数内のget○○の関数すべてが正常に動作することは確認されています。また、バイナリデータへ変換するRecordbuf()も正常に動作することが確認できています。
ただ、これらを組み合わせたときに上記の問題が発生しました。

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

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

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

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

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

ozwk

2020/04/12 03:29

シリアルの代わりに、getGPS()の前後にsleep適当に入れるとどうなります?
guest

回答3

0

ベストアンサー

Serial.printlnの有無で挙動が変わるというのも不可解です。

そういうときは、どこか最後のひと押しをくれた場所で止まる、ということもあって、「止まった場所」が直接悪くはなかったりしますけどね。まだなんとも言えません。

getGPS()関数は以下になります。

リセットの原因ではなさそうですけど、よろしくないところは見つけました。先に直しておいては。

C++

1void getGPS() { 2 String line; ///// do~whileループ内のline変数と名前が重なっています。結果としてこちらは使われていません。 3 String s; ///// 明示的な代入が為されないままdo~whileの最後の(s=="")に到達する可能性があります。Stringのデフォルトコンストラクタは""で初期化してくれるのかしら? それを信用せず途中ではline[]の各要素に""を代入してるのなら、ここも""で初期化すべきでしょう。 4 double LAT; //緯度 /////明示的な代入が為されないままs += String(LAT, 6);で参照される可能性があります 5 double LNG; //経度 /////同上 6 double GS; //対地速度 /////同上 7<> 8 while (!GPSSerial.isListening());/////ソフトシリアルを信用しなければ無限ループの可能性は考えられるけれど、実験レベルであればタイムアウトとか考えなくてもいいかな... 9<> 10 String line = GPSSerial.readStringUntil('\n');///// 前述のline変数重なり 11<> 12 //Stringlist生成 13 String list[30]; 14<> 15 //「,」を区切り文字として文字列を配列にする 16 for (i = 0; i < len; i++) { 17 if (line[i] == ',') { 18 list[index++] = str;/////このindexが30未満である保証はない。 19 str = ""; 20 continue; 21 } 22 str += line[i]; 23 } 24<> 25 //緯度 26 LAT = NMEA2DD(list[3].toFloat()), 6; ///// , 6は何? 27 //経度 28 LNG = NMEA2DD(list[5].toFloat()), 6; /////同上 29<> 30 s += String(LAT, 6);/////測位されてなくてもSに値が設定されて関数を抜けることになりますがそれでもいいのですか? 31

投稿2020/04/12 02:37

thkana

総合スコア7629

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

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

photan

2020/04/12 14:41

回答ありがとうございます。 LAT等の変数が未初期化である問題を解消したところ、本題の問題も解決しました。調べてみるとC言語で未初期化の変数を最小するとバグが発生し、print関数で挙動が変化することもあるそうです。 他にご指摘いただいた点は直しておきました。
thkana

2020/04/12 22:05

こういうのって、行った修正とその効果の間にちゃんとスジの通った説明をみつけておかないと(せめてわかったつもりになれるくらいに突き詰めておかないと)ある日またちょっと違った状況でおかしな現象が出てきたりしますよ... > C言語で未初期化の変数を最小するとバグが発生し、print関数で挙動が変化することもあるそうです。 むやみに初期化すると、本来のバグが隠蔽されるだけで本質はそのまま、ということもあります。 初期化することで何が変わるのかはちゃんと検討しておいて下さい。
guest

0

不定期にリセットが掛かっているらしき状況からして、
電源の容量が足りていないのではないでしょうか。

投稿2020/04/11 10:56

ikadzuchi

総合スコア3047

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

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

photan

2020/04/11 18:06

回答ありがとうございます。 電源はPCからUSB経由で供給しているので問題ないと思います。また、同じ回路で同じセンサの値を取得し、シリアルモニタにprintするだけのプログラムでしたら問題なく動作しますので電源は足りていると思います。 自分なりに対処してみて問題個所が分かったので追記しました。
ikadzuchi

2020/04/11 18:51

PCからUSB経由で供給していると問題ないという理屈が分かりません。 電圧降下や電流を測ったり、各センサの仕様を見て必要な電力を算出したりしないと問題ないとは言えないと思うのですが。 また、シリアルモニタにprintするだけで動作が変わる点も、プログラム自体の問題ではなく処理に伴う実行時間や消費電力など物理的な部分に影響されているように見えます。 電力消費の大きそうなGPSを止めると正常動作することからも電源の問題に思えます。
photan

2020/04/12 14:39

確かにそうですね。今後の運用に際しても消費電力は気になっていたので検証してみようと思います。
guest

0

Setup関数が実行される、のではなく、

  • 暴走して再起動してしまっている
  • 何らかの原因でリセットしている

のではないでしょうか。

ざっと見た限り、コードのバグで暴走というのはなさそうなんで、
まずは、

  • スタックがどこにあるか
  • WDT(ウオッチドッグタイマ)が有効になってないか

をチェックしてみてはどうでしょう

#ブートローダって、そのCPUにきちんと対応されてるもんなんでしょうか

投稿2020/04/11 08:02

編集2020/04/11 08:03
y_waiwai

総合スコア87749

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

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

photan

2020/04/11 18:04

回答ありがとうございます。 勉強不足で『スタックがどこにあるか』というのがあまりよくわからなかったのですが、メモリ領域に関してはグローバル変数を除きローカルで15kB使える状態なので問題ないかと考えています。的外れでしたら申し訳ございません。 WTDに関して、調べてみてwdt_disable();をsetup()関数内で実行させてみたのですが、改善には至りませんでした。 ブートローダーに関しては、対応していると調べ、書き込んだ状態で他のプログラムの実行もできているので問題ないかと思います。 自分なりに対処してみて問題個所が分かったので追記しました。
y_waiwai

2020/04/12 02:31

ざっと見て問題はなさそうですが、ローカル変数を大量に使用してるのが気になります。 ローカル変数はスタックを消費しますんで、スタック領域がオーバーして暴走してるんではないかと思われます ATmega1284PはRAMが16Kあるので、適切に領域を割り振ればオーバーってのはありえませんが、もしかしたらATmega164 とかの設定になってないでしょうか。(これだとRAMが1K) これならオーバーして暴走するのは納得できます
photan

2020/04/12 14:38

設定を確認しましたが、ATmega1284Pの設定でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問