質問するログイン新規登録

回答編集履歴

2

テストプログラム追記

2020/09/19 12:14

投稿

thkana
thkana

スコア7738

answer CHANGED
@@ -110,4 +110,26 @@
110
110
  32.45.809 COM3:DE
111
111
  32.45.815 COM16:DE
112
112
  ```
113
- 32.45.703のあたりなど、微妙なタイミングによってハンドラが呼ばれる順番が変わったりしているのが見えますが、つまりほぼ同時に入力された信号をきちんと処理できているようです。
113
+ 32.45.703のあたりなど、微妙なタイミングによってハンドラが呼ばれる順番が変わったりしているのが見えますが、つまりほぼ同時に入力された信号をきちんと処理できているようです。
114
+
115
+ マイコン側テストプログラムも追記
116
+ ```C++
117
+ //mbed(STM32)
118
+ #include "mbed.h"
119
+
120
+ int main(void){
121
+ Serial pc(USBTX, USBRX);
122
+ pc.baud(115200);
123
+ char c='A';
124
+ int offset=0;
125
+ while(1){
126
+ printf("%c%c",c+offset,c+offset+1);
127
+ fflush(0);
128
+ printf("%c%c",c+offset,c+offset+1);
129
+ fflush(0);
130
+ offset=(offset+1)%('H'-'A');// 'A'~'H'を回す
131
+ wait(40/115.2);//送り返し時間分待ち
132
+ }
133
+ return 0;
134
+ }
135
+ ```

1

サンプル追加

2020/09/19 12:14

投稿

thkana
thkana

スコア7738

answer CHANGED
@@ -5,4 +5,109 @@
5
5
  私の趣味的には、シリアルポート毎にハンドラを個別に持たせて、それぞれのポートはそれぞれに処理させるかな。もちろん、ひとつのハンドラで、sender毎に処理を切り替えてもいいと思いますけれど。
6
6
 
7
7
  それと、ハンドラは送信データに対して「いつ呼ばれるかわからない」ものです。極論、1回目の送信の途中で呼ばれるかも(1バイトでも受信すればハンドラは呼ばれるかも)、逆に2回送信が完了してしまってから呼ばれるかも(いつまでに呼ばれる、という期限もありません)、そのどんな場合でも正しくデータを得て、2回送信されたことの確認ができるようにプログラムを作らなきゃいけません。
8
- そうなっているでしょうか。
8
+ そうなっているでしょうか。
9
+
10
+ ---
11
+ サンプル書いてみました。シリアル周りだけ、エラーとかは無視。
12
+ 全然マルチスレッドでないのは、解決したい内容にマルチスレッドが全く寄与しないためです。
13
+
14
+ ```C#
15
+ using System;
16
+ using System.Collections.Generic;
17
+ using System.Linq;
18
+ using System.Text;
19
+ using System.Threading.Tasks;
20
+ using System.IO.Ports;
21
+
22
+ namespace SerialMulti
23
+ {
24
+ class Program
25
+ {
26
+ static void Main(string[] args)
27
+ {
28
+ object lockObj = new object();
29
+ //シリアルポート毎にインスタンスを生成する
30
+ Connection con1 = new Connection(args[0], lockObj);
31
+ Connection con2 = new Connection(args[1], lockObj);
32
+
33
+ string timeStamp = DateTime.Now.ToString("mm.ss.fff");
34
+ Console.WriteLine("Start: {0}\n", timeStamp);
35
+
36
+ //なにかキーを押したら終了
37
+ ConsoleKeyInfo tmp = Console.ReadKey();
38
+ }
39
+ }
40
+ // シリアルポートとハンドラをクラスにまとめておく
41
+ class Connection
42
+ {
43
+ SerialPort port = new SerialPort();
44
+ char[] buf = new char[4];
45
+ object lockObj;
46
+
47
+ public Connection(string portName, object lockObj)
48
+ {
49
+ this.lockObj = lockObj;
50
+ port.PortName = portName;
51
+ port.BaudRate = 115200;
52
+ port.DataReceived += Port_DataReceived;
53
+ port.Open();
54
+ }
55
+ ~Connection()
56
+ {
57
+ port.Close();
58
+ }
59
+ //インスタンス毎に各ポート「専用」のハンドラとなる
60
+ private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
61
+ {
62
+ //受信文字がある限り処理する。
63
+ //受信文字が空になって一旦ハンドラを抜けても次の文字を受信したら動作が継続できなければいけない
64
+ while (port.BytesToRead != 0)
65
+ {
66
+ //直近4文字のバッファに受信する
67
+ for (int i = 0; i < buf.Length - 1; i++)
68
+ {
69
+ buf[i] = buf[i + 1];
70
+ }
71
+ buf[buf.Length - 1] = (char)port.ReadByte();
72
+ //直近4文字において前半2文字と後半2文字が同じか検査
73
+ if (buf[0] == buf[2] && buf[1] == buf[3])
74
+ {
75
+ string timeStamp = DateTime.Now.ToString("mm.ss.fff");
76
+ //念の為排他処理にしておく
77
+ lock (lockObj)
78
+ {
79
+ Console.WriteLine("{0} {1}:{2}{3}", timeStamp, port.PortName, buf[0], buf[1]);
80
+ }
81
+ //送り返し
82
+ port.Write(String.Format("{0}{1}", buf[0], buf[1]));
83
+ }
84
+ }
85
+ }
86
+
87
+ }
88
+ }
89
+ ```
90
+ これに、マイコンと、そのUART出力をパラに別のUSB-UART変換を噛ませてPCのポートに入力、つまり「複数のシリアル信号を全く同時に入力」した時の出力がこんな感じです。(USBを通ったりしているうちにプログラムからみて完全に同時とは言えなくなるでしょうが、まぁそこそこ)
91
+ ```text
92
+ 32.45.494 COM3:BC
93
+ 32.45.495 COM16:BC
94
+ 32.45.529 COM3:CD
95
+ 32.45.543 COM16:CD
96
+ 32.45.564 COM3:DE
97
+ 32.45.575 COM16:DE
98
+ 32.45.599 COM3:EF
99
+ 32.45.607 COM16:EF
100
+ 32.45.634 COM3:FG
101
+ 32.45.639 COM16:FG
102
+ 32.45.669 COM3:GH
103
+ 32.45.671 COM16:GH
104
+ 32.45.703 COM16:AB
105
+ 32.45.704 COM3:AB
106
+ 32.45.739 COM3:BC
107
+ 32.45.751 COM16:BC
108
+ 32.45.774 COM3:CD
109
+ 32.45.783 COM16:CD
110
+ 32.45.809 COM3:DE
111
+ 32.45.815 COM16:DE
112
+ ```
113
+ 32.45.703のあたりなど、微妙なタイミングによってハンドラが呼ばれる順番が変わったりしているのが見えますが、つまりほぼ同時に入力された信号をきちんと処理できているようです。