複数のスレッドの作成と管理
https://blog.csdn.net/u010307521/article/details/50238997
1.スタート
最近、社内の上位コンピュータと機器間のシリアル通信プロジェクトに取り組み、シリアル通信ツールを自作しましたが、今日で3日目ですが、シリアルポートの双方向通信に気づきました。
2. ソフトウェアインターフェース
まずインターフェースを設計し、そこに必要な機能を実装します。
主な機能には、シリアル ポートのオープン、シリアル ポートのクローズ、シリアル ポートへのデータの送信、シリアル ポートからのデータの読み取りが含まれます。送受信のテキストボックスに、デバッグに便利な16進数の切り替え機能を追加しました。
メイン フォームでは、シリアル ポート名やシリアル ポート バッファ データなどの関連情報を格納するためにいくつかの変数が必要です。
private string[] portNames = null;
private List<SerialPort> serialPorts;
private byte[] portBuffer;
- 1
- 2
- 3
- 4
シリアル ポート番号の選択にはドロップダウン メニューが採用されており、フォームの初期化時に使用可能なすべてのシリアル ポートをスキャンしてコンボボックスに表示する必要があります。初期化後、次のコードを追加する必要があります。
this.serialPorts = new List<SerialPort>();
this.portNames = SerialPort.GetPortNames();
this.portBuffer = new byte[1000];
- 1
- 2
- 3
- 4
2 行目は、スキャンされたシリアル ポート名を文字列として this.portNames 配列に保存します。次に、スキャンしたシリアル ポートをコンボボックスに読み取る必要があります。
//Assign the value of port names to serial ports display
if (this.portNames.Length > 1)
{
for(int i = 0;i<this.portNames.Length;i++)
{
this.serialPorts.Add(new SerialPort(this.portNames[i]));
}
}
this.portNumberComboBox1.Items.AddRange(this.portNames); this.portNumberComboBox2.Items.AddRange(this.portNames);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
上記のコードはこれを行います。この時点で、ソフトウェア インターフェイスの初期化とシリアル ポート番号の初期スキャンが完了し、その後、ボタンの応答機能を完了する必要があります。
3. シリアルポートの操作機能
シリアルポートの開閉は非常に簡単で、対応する API を直接呼び出すだけです。
private void openButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < this.portNames.Length; i++)
{
try
{
if (this.portNames.ElementAt(i) == this.portNumberComboBox1.Text.ToString())
{
if (!this.serialPorts.ElementAt(i).IsOpen)
{
this.serialPorts.ElementAt(i).Open();
MessageBox.Show("已打开串口!");
}
//this.serialPorts.ElementAt(i).
}
}
catch (IOException eio)
{
MessageBox.Show("打开串口异常:" + eio);
}
}
}
private void closeButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < this.portNames.Length; i++)
{
try
{
if (this.portNames.ElementAt(i) == this.portNumberComboBox1.Text.ToString())
{
if (this.serialPorts.ElementAt(i).IsOpen)
{
this.serialPorts.ElementAt(i).Close();
MessageBox.Show("已关闭串口!");
}
}
}
catch (IOException eio)
{
MessageBox.Show("关闭串口异常:" + eio);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
シリアル ポート経由でデータを送信する場合は、まずテキスト ボックスで送信する内容を読み取ってから、write 関数を呼び出す必要があります。
private void sendButton_Click(object sender, EventArgs e)
{
for (int i = 0; i < this.portNames.Length; i++)
{
try
{
if (this.portNames.ElementAt(i) == this.portNumberComboBox1.Text.ToString())
{
if (this.serialPorts.ElementAt(i).IsOpen)
{
string sendContent = this.sendTextBox.Text.ToString();
this.serialPorts.ElementAt(i).Write(sendContent);
MessageBox.Show("已发送数据!");
}
}
}
catch (IOException eio)
{
MessageBox.Show("串口发送异常:" + eio);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
読み取り操作の場合、シリアル ポートには監視できる dataReceived イベントがあるため、ここではスレッドを使用せず、イベントを監視することを選択します。2 番目のコンボボックスをスキャンするタイマーを作成します。2 番目のコンボボックスが選択されると、イベントが監視されます。
private void timer1_Tick(object sender, EventArgs e)
{
this.AddEventHandlerForResponse();
}
private void AddEventHandlerForResponse()
{
for (int i = 0; i < this.portNames.Length; i++)
{
try
{
if (this.portNames.ElementAt(i) == this.portNumberComboBox2.Text.ToString())
{
if ((this.serialPorts.ElementAt(i).IsOpen)&&(this.serialPorts.ElementAt(i).BytesToRead > 0))
{
this.serialPorts.ElementAt(i).Read(this.portBuffer, 0, this.serialPorts.ElementAt(i).BytesToRead);
this.serialPorts.ElementAt(i).DataReceived += new SerialDataReceivedEventHandler(this.DataReceiveEventHandler);
}
}
}
catch (IOException eio)
{
MessageBox.Show("串口异常:" + eio);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
上記のコードには、DataReceived イベントを処理する関数があります。this.DataReceiveEventHandler
シリアル ポートの読み取り操作は比較的特殊であるため、シリアル ポートは補助スレッドを通じてバッファ データを読み取ります。読み取り操作を実行すると、UI のコンテンツが表示されます。直接変更することはできないため、テキスト ボックスで受信した内容は、invoke を通じて実現する必要があります。
private void DataReceiveEventHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
this.receiveTextBox.Invoke(
new MethodInvoker(
delegate
{
this.receiveTextBox.AppendText(sp.ReadExisting());
this.receiveTextBox.Text += " ";
}
)
);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
ここまでで、シリアルポートのオープン、シリアルポートのクローズ、読み書き動作など、シリアルポート通信の基本的な機能が実現されました。