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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Arduino

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

Q&A

解決済

1回答

11536閲覧

シリアル通信のデータの先頭を把握したい ヘッダのうまい使い方

bobby2128

総合スコア42

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Arduino

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

0グッド

0クリップ

投稿2017/03/07 09:39

編集2017/03/07 09:50

###前提・実現したいこと
Arduinoを複数用いて、シリアル通信をしています。ArduinoNANO側でRTCモジュールから時間情報を取得し、それをArduinoM0Proへ送信しています。

現状では、電源を二台同時に付けると、時間情報が正確に伝わるのですが(シリアルモニタ上で確認済み)、タイミングがずれると、以下に示すようにほしい形に正確にデータが通信できません。

原因としては、現状のコードではシリアル通信の順番に構わず、来た順番にデータをアウトプットしてしまうので、これに順番を守らせるコードを付け足したいのですが、いいアイデアが浮かびません。

便利な手法やアイデアなどございましたら、ぜひご教授お願いいたします。

※プログラムは長さの関係で本質問と関係性の低い箇所は省略させていただいております。

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

タイミングが正しいとき

2017.03.17,Tue 4:44:07 @ 26.43 °C

タイミングが正しくないとき

02.16.44, 2643:2017:03 @ 00.07 °C

###該当のソースコード
送信側

c

1 2void loop(){ 3 4 DateTime now=RTC.now(); // aktuelle Zeit abrufen 5 show_time_and_date(now); // Datum und Uhrzeit ausgeben 6 7 sensors.requestTemperatures(); // Temperatursensor auslesen 8 show_temperature(sensors.getTempCByIndex(0)); // Temperatur ausgeben 9 10 delay(1000); // 30 Sekunden warten bis zur nächsten Ausgabe 11} 12 13// Wochentag ermitteln 14String get_day_of_week(uint8_t dow){ 15 16 String dows=" "; 17 switch(dow){ 18 case 0: dows="Sun"; break; 19 case 1: dows="Mon"; break; 20 case 2: dows="Tue"; break; 21 case 3: dows="Wed"; break; 22 case 4: dows="Thu"; break; 23 case 5: dows="Fri"; break; 24 case 6: dows="Sat"; break; 25 } 26 return dows; 27} 28 29// Datum und Uhrzeit ausgeben 30void show_time_and_date(DateTime datetime){ 31 32/////////////////////////////////////////////// 33 int byou=datetime.second(); 34 int fun=datetime.minute(); 35 int zikan=datetime.hour(); 36 int hi=datetime.day(); 37 int tuki=datetime.month(); 38 int nen=datetime.year(); 39 int youbi=datetime.dayOfWeek(); 40 41 sendNenData(nen); 42 sendTukiData(tuki); 43 sendHiData(hi); 44 sendYoubiData(youbi); 45 sendZikanData(zikan); 46 sendFunData(fun); 47 sendByouData(byou); 48} 49 50void sendNenData(int value){ 51 Serial.write('H'); // ヘッダの送信 52 Serial.write(lowByte(value)); // 下位バイトの送信 53 Serial.write(highByte(value)); // 上位バイトの送信 54} 55void sendTukiData(int value){ 56 Serial.write('H'); // ヘッダの送信 57 Serial.write(lowByte(value)); // 下位バイトの送信 58 Serial.write(highByte(value)); // 上位バイトの送信 59} 60void sendHiData(int value){ 61 Serial.write('H'); // ヘッダの送信 62 Serial.write(lowByte(value)); // 下位バイトの送信 63 Serial.write(highByte(value)); // 上位バイトの送信 64} 65void sendYoubiData(int value){ 66 Serial.write('H'); // ヘッダの送信 67 Serial.write(lowByte(value)); // 下位バイトの送信 68 Serial.write(highByte(value)); // 上位バイトの送信 69} 70void sendZikanData(int value){ 71 Serial.write('H'); // ヘッダの送信 72 Serial.write(lowByte(value)); // 下位バイトの送信 73 Serial.write(highByte(value)); // 上位バイトの送信 74} 75void sendFunData(int value){ 76 Serial.write('H'); // ヘッダの送信 77 Serial.write(lowByte(value)); // 下位バイトの送信 78 Serial.write(highByte(value)); // 上位バイトの送信 79} 80void sendByouData(int value){ 81 Serial.write('H'); // ヘッダの送信 82 Serial.write(lowByte(value)); // 下位バイトの送信 83 Serial.write(highByte(value)); // 上位バイトの送信 84}

受信側

c

1 2void loop() { 3// 受信バッファに3バイト(ヘッダ+int)以上のデータが着ているか確認 4 if ( Serial2.available() >= sizeof('H') + sizeof(int) ) { 5// ヘッダの確認 6 if( Serial2.read() == 'H'){ 7 int low = Serial2.read(); // 下位バイトの読み取り 8 int high = Serial2.read(); // 上位バイトの読み取り 9 recv_data = makeWord(high,low); // 上位バイトと下位バイトを合体させてint型データを復元 10 11 if( recv_data <10 && counter!=3)Serial.print(0); 12 if(counter!=3){ 13 Serial.print(recv_data); 14 } 15 } 16 counter++; 17//Serial.print(counter); 18 switch(counter){ 19 case 1: Serial.print("."); break; 20 case 2: Serial.print("."); break; 21 case 3: Serial.print(", "); break; 22 case 4: 23 if(recv_data==0)Serial.print("Sun"); 24 if(recv_data==1)Serial.print("Mon"); 25 if(recv_data==2)Serial.print("Tue"); 26 if(recv_data==3)Serial.print("Wed"); 27 if(recv_data==4)Serial.print("Thu"); 28 if(recv_data==5)Serial.print("Fri"); 29 if(recv_data==6)Serial.print("Sat"); 30 Serial.println(""); 31 break; 32 case 5: Serial.print(":"); break; 33 case 6: Serial.print(":"); break; 34 case 7: Serial.println(""); break; 35 } 36 37 38 if(counter==7){ 39 counter=0; 40 } 41 } 42

###補足情報(言語/FW/ツール等のバージョンなど)
Arduino IDE 1.8.0
Arduino M0 Pro
Arduino NANO

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは。

質問の内容が書かれていないので、ソースは呼んでいません。
タイトルから「シリアル通信のデータの先頭をどうやって判別すればよいのか?」だろうと推測して回答してみます。外してたらごめんなさい。

実はこの問題は結構難しいです。恐らくざっくり2種類しかないと思います。

  1. タイムアウト

パケットは必ず連続して送信し、一定時間以上データを受信できない時に内部カウンタをクリアします。クリア後に届いた最初のデータが先頭です。
シリアル通信では、何かエラーが発生した場合に備えてタイムアウトの実装がほぼ必須ですから新たにロジックを追加しなければならないケースは少ないです。

  1. 特殊コード

ペイロード内に記録しないコードを決めます。バケット先頭にそのようなコードの一つを割り当てます。
例えば、よく使われるベーシック手順はこの方式です。
この方式はタイムアウトに頼らない点で優れています。ペイロードに使えない値を伝送できるようにするため、それなりの工夫(エスケープするなど)で高速化することもできます。


【追記】
回答を書いている間に質問の内容が書かれてました。フライングしてしまった。すいません。


【質問を読み直して】
ソースもざっとみました。バイナリー・データを送っているので、先に書いた「2. 特殊コード」方式を使うのは難しいですね。かと言って「1. タイムアウト」もタイマの制御が必要になるのでやはり難しいてす。

バイナリー・データを送らないように改造するのが、恐らく簡単です。
今はint型を2バイトでそのまま送っていますが、例えば4ビットづつを8ビットへ拡張して4バイトで送ることが考えられます。4ビットの値が10未満ならオフセット0x30を加え、10以上ならオフセット0x41を加えるとASCIIコードでの16進数表現になります。そして、それを受信側でデコードすることがかのうです。
このような工夫をして送受信することで、例えばベーシック手順のSYNコードなどをペイロード中に発生しないようにします。

そして、送信側はパケット先頭にSYNコードを付加して送り、受信側はSYNコードを受信できるまでデータを1バイトづつ破棄することが考えられます。

投稿2017/03/07 09:53

編集2017/03/07 10:07
Chironian

総合スコア23272

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

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

bobby2128

2017/03/07 10:20

Chironian様 こんにちはご回答いただきまして誠にありがとうございます。 「今はint型を2バイトでそのまま送っていますが、例えば4ビットづつを8ビットへ拡張して4バイトで送ることが考えられます。4ビットの値が10未満ならオフセット0x30を加え、10以上ならオフセット0x41を加えるとASCIIコードでの16進数表現になります。そして、それを受信側でデコードすることがかのうです。 」この箇所ができたら理想なのですが、勉強不足のため、何かサンプルコードやURLをご提供いただけますと幸甚に存じます。 お手数おかけいたしますが、どうかよろしくお願いいたします、
Chironian

2017/03/07 10:46 編集

答えを求めるのではなく、何が分からないか具体的に質問して下さい。 この部分は中身を深く理解しないとデバッグできませんので、部分的な答えを教えても完成しないと思います。 また、私の手元には開発環境がないですし、仮にあったとしても結構手間がかかるデバッグですので、私の方でデバッグした完全な答えをお教えすることもできません。
bobby2128

2017/03/08 02:50

Chironian様 こんにちはコメントいただきありがとうございました。 あれから自身でいろいろ試行錯誤した結果、下記の二つのコンセプトで実行した結果、送信と受信がずれた状態からでもそれを修正し表示するようにうまく動作いたしました。 ・送信側のデータ送信の最後にdelay関数にて一定時間の間を設ける。 ・間があった直後に来たデータは先頭であることを受信側で判断する。 はじめたばかりでうまくいかないことばかりでしたが、アイデアをいただきありがとうございました。
Chironian

2017/03/08 04:31

おお、時間制御方式でうまくいったのですね。それは良かったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問