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

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

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

Q&A

解決済

1回答

1159閲覧

サーバーとクライアント間でデータの送受をしたい

babamichiru

総合スコア6

0グッド

0クリップ

投稿2020/09/30 06:32

Arduinoでシステムを作っています。よろしくお願いします。

1.サーバー側  ESP32 モジュール APIPモード
2.クライアント側  ESP-WROOM02基板Assy
3.ソフトウェア開発 ArduinoIDE
4.説明
親機(ESP32モジュール)をAPにして、子機(ESP-WROOM02)を無線接続して、親機からのコマンドを受けて、子機からデータを親機に送ろうとしているが、親機からの1byteづつの文字を言葉にしたい。"S""T""A""R""T" -> "START"
5.問題点
・サーバー側から1byteずつ送付されたデータをコマンドとして判別したいが文字の積算が出来ない。
ボードに書き込む時、子機側の cmd=cmd+command; でエラーになる。

  • どこが拙いんでしょうか?
/* Client */  子機側 /* esp-wroom02 200925 */ #include <ESP8266WiFi.h> const char* ssid = "ESP32-WiFi"; const char* password = "esp32wifi"; static WiFiClient client; void setup() { Serial.begin(115200); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); IPAddress ip(192,168,0,9); client.connect(ip,80); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } // 収集データ char command,c; char bdata[] = "board=3,ring=7,point=4,total=159 /"; char cmd[]=""; void loop() { //Serial.println("sending data to server"); delay(1000); if (client.connected() == true){ client.write(bdata); // send a string to server } command = client.read(); Serial.printf("%c",command); cmd=cmd+command;   <---------------------------エラー発生 if(command == '0'){ Serial.print(cmd); Serial.println("/"); } //c=""; delay(3000); // execute once every 1 minutes }
/* Server */ #include<WiFi.h> const char *ssid="ESP32-WiFi"; //SSID const char *pass="esp32wifi"; //パスワード const IPAddress ip(192,168,0,9); //サーバーのIPアドレス const IPAddress subnet(255,255,255,0); //サブネットマスク WiFiServer server(80); void setup() { Serial.begin(115200); WiFi.softAP(ssid,pass); //SSIDとパスの設定 delay(100); //接続失敗防止 WiFi.softAPConfig(ip,ip,subnet); //IPアドレス、ゲートウェイ、サブネットマスク設定 IPAddress myIP = WiFi.softAPIP(); //WiFi.softAPIP()でWiFi起動 server.begin(); Serial.println(); Serial.println("WiFi connected"); Serial.print("SSID:"); Serial.println(ssid); Serial.print("AP IP address:"); Serial.println(myIP); Serial.println("Server start!"); } uint8_t value ; int boad,ring,point,total; // ボード番号,輪数,ポイント,合計 char cmand[] = "start0"; void loop() { // クライアントの情報を得る。 WiFiClient client = server.available(); if(client){ Serial.println("new client"); while(client.connected()){ if(client.available()){ value=client.read(); Serial.printf("%c", value); if(value == '/') { // '/' 区切り文字 Serial.println(""); } client.write(cmand); // クライアントへコマンド送付 delay(500); } } } }

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

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

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

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

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

Y.H.

2020/09/30 06:40

> 子機側の cmd=cmd+command; でエラーになる。 どのようなエラーになるのでしょうか? 具体的に記載した方が回答得られやすいと思います。 (特に同様の環境を用意し辛い環境のようですので。)
babamichiru

2020/10/01 05:05

お世話になります。 incompatible types in assignment of 'char*' to 'char[1]' というエラーが出ます。 どういう事でしょうか?
babamichiru

2020/10/03 04:58

お世話になります。 配列を使って以下のように変更しました。 char cmd[4]; int cnt=0;   : command=client.read(); cmd[cnt]=command; cnt+=1; if (command='/'){ cnt=0; } エラーは出ずに、1byteデータが積算されてcmd[]にコマンドを再生できました。
babamichiru

2020/10/05 02:15

エラーが出る件は、一応解決です。ありがとうございました。
guest

回答1

0

ベストアンサー

まず、

char cmd[]="";

この配列はサイズ1しかありません
これにいくら文字を蓄積したいと言ってもアクセス違反にしかなりませんね
んで、

cmd=cmd+command; 

こういう演算はできません。
C言語における文字列操作を学びましょう

投稿2020/09/30 06:39

y_waiwai

総合スコア87749

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

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

babamichiru

2020/09/30 07:49

回答ありがとうございます。 文字列操作を見直してみます。これが悪いと言う事が判っただけでも、価値あります。
y_waiwai

2020/09/30 07:57

通信でメッセージのやり取りする場合は、メッセージの区切り文字というのを決めておきましょう #ふつうテキストなら改行文字 この区切りが来るまでデータを取り込んで貯めていき、区切り文字が来たらメッセージとして処理するようにします
babamichiru

2020/10/01 05:10

送付するサーバー側の文字列には”start0”のように”0”を区切りにしようかと‥。 文字列を扱う為には、string を使う事になりますか?
y_waiwai

2020/10/01 05:17

メモリに余裕があるなら、stringを使うほうが簡単で便利です ましかし、こういうマイコンモジュールは容量的に余り余裕はないため、文字配列を使うほうがいいかとは思いますね まあ、実験のうちははstringを使えばいいんじゃないでしょうか
babamichiru

2020/10/01 05:40

商品化を目論んでいるので、配列で何とかしたいと思います。
y_waiwai

2020/10/01 05:46

いろいろ機能を詰め込みたいなら容量削減は至上命題になりますね そういう場合は、C++的な機能は使わずに、C言語ベースでいきましょう
babamichiru

2020/10/03 04:53

配列を使って以下のようにしました。 char cmd[4]; int cnt=0;   : command=client.read(); cmd[cnt]=command; cnt+=1; if (command='/'){ cnt=0; } 一応、動いています。cmdが受信データですが、サーバー側のコマンド"stop/"に対して、クライアント側では、”stop//”となる("/"が一つ多い)のはどうしてでしょう? 教えて下さい。
y_waiwai

2020/10/03 05:04

char cmd[4]; ってのは、4文字分の配列ってことです。 C言語の文字列は、後端に'\0'文字を入れなけりゃならないんで、これでは領域が足りません どんなに長いコマンドでも格納できるように100文字ぐらい確保しときましょう。 そして、文字列終わりの標識に、'\0'を入れてください
babamichiru

2020/10/05 02:59

領域を確保すると言う事ですので、メモリー節約の為に可能性のあるコマンド(文字数+2)位にしたいと思います。 ご指摘に対し以下のようにしましたが、クライアント側でエラーが出ましたので、教えて下さい。 エラーの内容(クライアント側): ISO C++ forbids comparison between pointer and integer [-fpermissive] <サーバー側> uint8_t value ; int boad,ring,point,total; // ボード番号,輪数,ポイント,合計 char cmand[] = "start\0"; void loop() { // クライアントの情報を得る。 WiFiClient client = server.available(); if(client){ Serial.println("new client"); while(client.connected()){ if(client.available()){ client.write(cmand); // クライアントへコマンド送付 value=client.read(); // クライアントデータ(1byte)読込み Serial.printf("%c", value); if(value == '/') { // '/' 区切り文字 Serial.println(""); } delay(500); } <クライアント側> // 収集データ char command,c; char bdata[] = "board=2,ring=7,point=4,total=159 /"; char cmd[10]; int cnt=0; void loop() { // send data to/from server delay(1500); if (client.connected() == true){ command = client.read(); // receive command from server cmd[cnt]=command; cnt += 1; if(command == "\0" ){ // Delimiter   <-----------  ここでエラー Serial.print(cmd); Serial.print(" "); cnt = 0; } client.write(bdata); // send a string to server }
y_waiwai

2020/10/05 03:18

"\0" では文字列になってしまっています 文字\0を表現するなら、'\0' ですよ
babamichiru

2020/10/05 06:02

有難うございます。 修正し、コンパイルと書き込みはできましたが、今度は exception (9) が出て、wdt reset が出ます。 クライアント側は動作(接続)しません。サーバー側の送付データに問題があるんでしょうか?
babamichiru

2020/10/05 06:41

サーバー側の送付コマンドを以下のように変えました。 <サーバー側> uint8_t value ; int boad,ring,point,total; // ボード番号,輪数,ポイント,合計 char cmand[] = "start\0";  -> char cmand[] = "start";    <---- 変更 クライアント側は動いているようです。 WiFi connected IP address: 192.168.0.10 しかし、コマンド受信ができないようです。 if(command == ’\0’ ){              // Delimiter  に引っ掛かっていない ??
y_waiwai

2020/10/05 06:44

送信側では'\0'のデータは送ってるんですか?
babamichiru

2020/10/05 07:55

'\0'のデータは送っています。 1.指摘された後にchar cmand[] = "start\0"; をサーバー側で送るようにしました。 クライアント側も、一部変更しました。if(command == ’\0’ ){  コンパイル後、リセットスタートした時に、以下のエラーとなります。 exception (9) が出て、wdt reset が出る。 2.サーバー側の送るコマンドから ’\0’ を削除して送ってみましたが、クライアント側で'\0'が認識できなくて、コマンドが検出できない。サーバーから送ってないから当然。 3.最初の送出コマンドに再変更しました。char cmand[] = "start\0";  クライアント側で下記が出たまま、以降動作しない。 WiFi connected IP address: 192.168.0.10 クライアント側をリセットしても反応がない。 スクリーンショット(.png)を添付しようとしたが、ここに入らないです。
y_waiwai

2020/10/05 08:01

まあ、そのテのエラーが出るというのはどこかでメモリ破壊が起こってるということです もうちょっと基本的なところからやり直してみてはどうでしょう。
babamichiru

2020/10/05 08:36

可能性としては、'\0' が見つからないまま、cnt がカウントアップして破綻したか? <サーバー側> void loop() { // send data to/from server delay(1500); if (client.connected() == true){ command = client.read(); // receive command from server cmd[cnt]=command; cnt += 1; if(command == "\0" ){         // Delimiter Serial.print(cmd); Serial.print(" "); cnt = 0; } if(command == "\0" ){ は、問題ないでしょうか?
y_waiwai

2020/10/05 08:41

文字列ではダメです。'\0'にしないと。 どうも基本的なところができてないようですが
babamichiru

2020/10/05 09:00

失礼しました。 修正前のを添付してしまいました。実際は、if(command == '\0' ){ で実行させています。 もう少し、調べてみたい。
babamichiru

2020/10/06 02:45

お世話になります。 サーバー側では、クライアント側へコマンドを送付した後、クライアント側からデータを収集していますが、途中で途絶えて、Guru Meditation Error:エラーが発生しています。 クライアント側では、サーバーから来たコマンドの'\0'を13回ほど検出できないまま、エラーに至って停止しています。 対策案: client側で '\0' を検出できれば何も問題は出ないと思いますので、ここら辺を何とかしたいですが、正しいでしょうか? 面倒な話しですが、よろしくお願いします。 <Server PGM> int boad,ring,point,total; // ボード番号他 char cmand[] = "start\0"; <----------- clientへの送付コマンド void loop() { // クライアントの情報を得る。 WiFiClient client = server.available(); if(client){ Serial.println("new client"); while(client.connected()){ if(client.available()){ client.write(cmand); // クライアントへコマンド送付 <Server_シリアルモニター> WiFi connected SSID:ESP32-WiFi AP IP address:192.168.0.9 Server start! dhcps: send_offer>>udp_sendto result 0 new client board=2,ring=7,point=4,total=159 / board                 <--------- クライアントからのデータが途中でOFFに Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled. <-- エラー Core 1 register dump: PC : 0x400d1444 PS : 0x00060430 A0 : 0x800d1518 A1 : 0x3ffb1ef0 A2 : 0x00000000 A3 : 0x3ffb1f3f A4 : 0x00000001 A5 : 0x00000001 A6 : 0x3ffc34b4 A7 : 0x00000001 A8 : 0x00000000 A9 : 0x00000000 A10 : 0x00000000 A11 : 0x00000000 A12 : 0x3ffccc18 A13 : 0x00000000 A14 : 0x00000000 A15 : 0x00000001 SAR : 0x00000019 EXCCAUSE: 0x0000001c EXCVADDR: 0x00000008 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0xffffffff <Client> char command,c; char bdata[] = "board=2,ring=7,point=4,total=159 /"; <------- サーバーへの送付データ char cmd[10]; int cnt=0; void loop() { delay(1500); if (client.connected() == true){ command = client.read(); // received command from server cmd[cnt]=command; cnt += 1; if(command=='\0' ){ // Delimiter Serial.print(cmd); Serial.print(" "); cnt = 0; } Serial.print(cnt); <-------- cnt の確認 client.write(bdata); // send a string to server } <Client シリアルモニター> Connecting to ESP32-WiFi . WiFi connected IP address: 192.168.0.10 12345678910111213          <--------- 13回 '\0' をチェック Exception (3):              <-------- エラー発生 epc1=0x40202e04 epc2=0x00000000 epc3=0x00000000 excvaddr=0x40202ddc depc=0x00000000 >>>stack>>> ctx: cont sp: 3ffffdc0 end: 3fffffc0 offset: 0190 3fffff50: 3ffee3c8 0000000d 00000000 40202dfb 3fffff60: 3fffdad0 3ffee49c 3ffef18c 3ffee368 3fffff70: 402024b4 3ffee378 3ffee378 402024c9 3fffff80: 402024b4 3ffee378 3ffe84cc 40201199 3fffff90: 3fffdad0 00000000 3ffee400 3ffee440 3fffffa0: 3fffdad0 00000000 3ffee400 402033f4 3fffffb0: feefeffe feefeffe 3ffe8510 40100ba9 <<<stack<<< ets Jan 8 2013,rst cause:2, boot mode:(3,7)
babamichiru

2020/10/06 06:06

原因が判りました。 サーバー側から下記を送っても、 char cmand[] = "start\0"; <----------- clientへの送付コマンド クライアント側では、'\0' を受け取っていない。 command = client.read();  <-----  received command Serial.print(command); <----- 受け取った文字を確認 cmd[cnt]=command; cnt += 1; if(command=='\0' ){        // Delimiter  <---- 問題あり 依って、上の if は成立しない。待ってても '\0' は来ない。従って、別の文字をDelimiterにする必要がある。サーバーから char cmand[] = "start5\0"; <------- clientへの送付コマンド 上記を送り、クライアント側では '5' をDelimiterにすると、コマンド”start55”を受け取る事ができた。 因みに番号 '5' はクライアントの識別番号(board=5)として使えるので、有益。
babamichiru

2020/10/07 01:10

クライアント側で"start55"と5が1つ余計に出る癖があるが、ほぼ目的は達成したので、次の目標(サーバーのコマンドを受けてクライアントがデータを送付する)と言う事に進めたいですが、このまま続けて良いんでしょうか?一区切りして、別テーマで質問した方が良いんでしょうか?
y_waiwai

2020/10/07 01:34

別の疑問があるなら別質問でどうぞ。
babamichiru

2020/10/07 02:03

y_waiwai 様 一区切りして、進めていく中で分からなくなった時に、また質問したいと思います。 大変お世話になりました。有難うございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問