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

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

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

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Arduino

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

Q&A

解決済

3回答

1400閲覧

C#でのシリアル通信によるセンサ値取得

nekoneko_317

総合スコア13

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Arduino

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

0グッド

1クリップ

投稿2022/10/07 15:40

目的

c#初学者です.
現在,C#を用いてセンサ値を400Hzで取得するプログラムを作成しています.
現在は,マイコン側から9bytesのデータをシリアルを通じてc#側で取得するようなプログラムを作成しています.

現在

9bytesの内,はじめの1byteは0xFFを送り,c#側では読み込んだ初めの1byteが0xFFであれば,センサ値を配列に入れ替えるようなプログラムを組んでおります.

c#側では,button1が押された場合に,データの読み取りを行うようにして,別のボタンによってfragを入れ替えるようなプログラムを書いております.
また,マイコン側ではfloat型のデータをシリアルで送るために,共用体を用いてfloat型をint型として送信しています.

質問

質問は,c#側でのserial.Readのタイミングや方法を教えていただきたいです.
現在のプログラムでは,全く異なるデータが取得されてしまいます.
ただ,マイコン側がデータを正しく送信していることは別のプログラムで確認しましたので,特にc#について改善点を教えていただきたいです.

以下にコードを示します.

c#

1//一部抜粋です. 2public static class Condition 3 { 4 public static string[,] condition = new string[6, 2];// Modifiable 5 public static int clicked_num = 0; 6 public static int[] index_num = new int[6]; 7 public static bool frag = false; 8 9 } 10public static class Data_t 11 { 12 public static float[,] data = new float[50000, 2]; 13 } 14 15private void button1_Click(object sender, EventArgs e) 16 { 17 button3.Enabled = true; 18 button1.Enabled = false; 19 Condition.frag = true; 20 if (Condition.clicked_num < 6) 21 { 22 23 int count = 0; 24 while (Condition.frag) 25 { 26 //dataの読み取りと配列に値渡し 27 //System.Console.WriteLine("test_now1"); 28 byte[ ] buffer = new byte[9]; 29 //System.Console.WriteLine("test_now2"); 30 serialPort1.Read(buffer, 0, buffer.Length); 31 //System.Console.WriteLine("test_now3"); 32 if (buffer[0] == 0xff) 33 { 34 float tmp1 = BitConverter.ToSingle(buffer,0); 35 float tmp2 = BitConverter.ToSingle(buffer, 4); 36 //System.Console.WriteLine("get_value"); 37 Data_t.data[count, 0] = tmp1; 38 Data_t.data[count, 1] = tmp2; 39 System.Console.WriteLine(tmp1.ToString() + ","+tmp2.ToString()); 40 count++; 41 } 42 43 Application.DoEvents(); 44 } 45 } 46 else 47 { 48 label1.Text = "FINISH"; 49 button3.Enabled = false; 50 serialPort1.DiscardOutBuffer(); 51 serialPort1.DiscardInBuffer(); 52 serialPort1.Close(); 53 } 54 } 55 56 private void button3_Click(object sender, EventArgs e) 57 { 58 Condition.frag = false; 59 button1.Enabled = true; 60 button3.Enabled = false; 61 }

またマイコン側のプログラムは以下です.

arduino

1#include <Arduino.h> 2#include <rhio-LIS2HH12.h> 3#define ODR 200 4float x, y, z; 5float mx,mz; 6//https://gitlab.com/rhombio/rhio-libraries/rhio-LIS2HH12 7LIS2HH12 lis = LIS2HH12(); 8 9bool frag = false; 10 11union float2int{ 12 float value; 13 int i; 14}; 15 16void setup() { 17 // put your setup code here, to run once: 18 19 Serial.begin(115200); 20 Serial.println("LIS2HH12 example"); 21 lis.begin(); 22 lis.setBasicConfig(); 23 lis.setFrequency(80);//400Hz 24} 25 26void loop() { 27 unsigned long pre = micros(); 28 29 lis.getAccelmG(&x,&y,&z); 30 union float2int X; 31 union float2int Z; 32 X.value = x; 33 Z.value = z; 34 35 Serial.write(0xFF); 36 Serial.write(X.i>>24 |0x00); 37 Serial.write(X.i>>16 |0x00); 38 Serial.write(X.i>>8 | 0x00); 39 Serial.write(X.i&0xFF); 40 Serial.write(Z.i>>24|0x00); 41 Serial.write(Z.i>>16|0x00); 42 Serial.write(Z.i>>8|0x00); 43 Serial.write(Z.i&0xFF); 44 45 while(micros()-pre<2500); 46}

お手数ですがご確認お願いいたします。

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

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

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

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

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

YAmaGNZ

2022/10/07 16:07

まずはバイト配列レベルでデータ受信が問題ないかを判断すべきかと思います。
nekoneko_317

2022/10/07 16:17

マイコン側から0xFFの後に0x00だったりのデータを送信し,c#側でconsole.writeを用いてデバッグしてみましたが,結果としてはうまく送信できていないようでした. また,他のプログラムとしてpythonではマイコン側のプログラムは全く同じでセンサ値取得できましたので,やはりc#側で受信の問題(プログラムの問題)があるようですが,何か改善すべき点など教えていただけると幸いです.
YAmaGNZ

2022/10/07 16:19

どうやって判断したのですか? bufferの中身ですか?
nekoneko_317

2022/10/07 16:51 編集

マイコン側から0xFFの後に0x00だったりのデータを送信し,c#側でconsole.writeを用いてデバッグしてみましたが,結果としてはうまく送信できていないようでした. ⇒この点に関しては, float tmp1 = BitConverter.ToSingle(buffer,0); float tmp2 = BitConverter.ToSingle(buffer, 4); を確認しました.
KOZ6.0

2022/10/07 19:37 編集

・通信速度、パリティビット、ストップビット、データ長などの通信パラメータはちゃんと設定できてますか? ・serialPort1.Read(buffer, 0, buffer.Length); の戻り値(受信データ長)を確認しましたか? ・float 型に変換する前に、buffer の中身を確認してください。マイコンからは何を送って、何を受信するはずだったのですか? ・float 型に変換する位置がおかしくありませんか? float tmp1 = BitConverter.ToSingle(buffer, 1); float tmp2 = BitConverter.ToSingle(buffer, 5); なのでは?
KOZ6.0

2022/10/07 19:32

あと、Open が見当たりませんが、どこでやっているのでしょうか?
YAmaGNZ

2022/10/07 22:44

float tmp1 = BitConverter.ToSingle(buffer,0); float tmp2 = BitConverter.ToSingle(buffer, 4); これでは受信した生データを確認していることにはなりません。 受信した生データがおかしいのか、数値へのコンバートがおかしいのか切り分ける必要があります。
dodox86

2022/10/07 23:14

C#の初学者である自覚がおありならば、最初からアプリの機能を作り込むのではなく、最初は問題の切り分けがし易いよう極力シンプルなかたちでプログラムを作ってみることをお勧めします。シリアル通信のサンプルプログラムをもとに動かして、充分理解してからでも遅くはありません。
dodox86

2022/10/07 23:17

コメントしてる間にクローズしてしまいましたね。結局通信できたのか、あるいはダメだった理由のひとつが分かっただけなのか分かりませんが。
guest

回答3

0

c#側では読み込んだ初めの1byteが0xFFであれば

この時点でダメダメです。シリアル通信の単位はバイト(まぁ、7bitとか9bitだったりの可能性もありますが)。それ以上でも以下でも、通信のレイヤーにおいては区切りはありません。9byteまとめて送ったからその9byteのブロックがまとめて受信できる、そんな保証は全くありません。なんらかのエラーによって、あるいは受信/送信のタイミングによって、あるいは受信ルーチンのタイムアウト等によって、ff,01,02,..,08,ff,09,10,...16のストリームから07,08,ff,09,10,...が受信されることは普通にあって、受信側はそういう事態を想定したプログラムになっていなければいけません。
受信側は

1byte受信する
そのデータが0xffであれば、続く8byteを受信してdoubleとしてデコードする

あるいは、

直近8byteのデータを保存している
さらに受信したデータが0xffであれば、保持している8byteをdoubleとしてデコードする

とするべきでしょう。

これだけが原因とは言いませんが、すくなくともこれはおかしいです。

あと、本題ではない小さいことを言えば

共用体を用いてfloat型をint型として送信

floatの内部構造が送り側と受け側で同じであることは確認しているのですね? まぁ大丈夫だと思いますけれど。

button1が押された場合に,データの読み取りを行う

ボタンの処理の中でデータを待ってグルグル回るような処理というのはあまりよろしくないかと思います。ボタン処理に留まっているあいだUI含む全体処理がとまり、それをごまかすためにApplication.DoEvents();を入れるというのは、VB6時代にはアンチパターンのひとつとされていたような気がしますが、最近はどうなのでしょう。自分で作れと言われたら、ボタン動作で受信スレッドを起動するようなことをするかしら。

frag

flag?

投稿2022/10/07 23:11

thkana

総合スコア7639

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

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

thkana

2022/10/07 23:20

あと一点、0xffをデリミタとするならば、データ本体に0xffが登場しないか、あるいはレアであるなどでないと使い物にならないかも知れません。単に浮動小数点の内部構造をそのまま垂れ流すのであれば、とても不安です。 デリミタを複数バイトのシーケンスにしてデータとの重複を減らす、簡単なハッシュ(チェックサム等)をつけて妥当性を確認するなどが必要だったりしないでしょうか。
guest

0

自己解決

YAmaGNZさんのご指摘通りでした。

float tmp1 = BitConverter.ToSingle(buffer,0); float tmp2 = BitConverter.ToSingle(buffer, 4); これでは受信した生データを確認していることにはなりません。 受信した生データがおかしいのか、数値へのコンバートがおかしいのか切り分ける必要があります。

投稿2022/10/07 23:08

nekoneko_317

総合スコア13

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

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

YAmaGNZ

2022/10/08 00:59

それはあくまで今回の問題を解決するための調査の方法に過ぎません。 なのでこれで解決というのはおかしいです。 他の方が指摘しているようにおかしな箇所がいくつかありますのでそちらも考慮しましょう。
guest

0

まずは、その9byteを受信して、画面に表示させる、あるいはコンソールに表示させて、正常に通信が行われてるのか、をチェックしましょう。
それできちんと通信周りが正常だ、ということを確認してからその先に進みましょう。

投稿2022/10/07 22:11

y_waiwai

総合スコア87774

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

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

y_waiwai

2022/10/07 22:54

勘違いしてはいけないのが、受信データを順番に表示させる、のではなく、9バイトの一つのメッセージ(通信単位)で表示させるってことです。 開始データを判定してメッセージの開始位置を決めてるようですが、その考え方そのものが果たして妥当なものであるか、それに対しあなたのコードが妥当なものであるかってのも含めて、それで確認していきましょう
episteme

2022/10/08 04:05 編集

「まずちゃんと受信できてるか確認/検証しましょう」が 「質問に対する回答となっていない投稿」とは思えないんだが...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問