今まで、受信ばかりしていて送信をしたことがなかったのですが、STA23で、ログシステムの操作をするために、WIN10タブレットからBlueToothSPP経由でマイコン側に指示命令を送信する機能で壁にぶち当たって、4か月放置してました。しかし、最近chatGPTでプログラム学習するようなって、懸案事項のスレッド処理とか、シリアル通信 同時送受信と聞いてみるといろいろなアドバイスがもらえて、なんと解決できました。
●送信時の課題
送信ボタンをおして、1文字を送信するだけですが、受信処理でデータがNULLになったり、配列変数がある場合は、配列エラーが発生してしまいます。
●chatGPTへ聞いて回答をもらった
「C# serialPort Datareceived 受信中に送信」で聞くと、送信用のスレッドを作成するという回答がありましたが、スレッドが作れないので苦労しているので、別の方法を考えました。
<データ受信してないときに送信すればいいので、serialPortDataReceivedがBUSYかどうか>
を判別して、BUSYでないときに送信すればいいので、聞いてみました。**assistant:**以下が回答
**Human:** 私の質問
「C# SerailPort.DatareceivedがBUSYかどうか」
***
**Assistant:**
SerialPortクラスには、DataReceivedイベントが発生したときにコードが実行中であるかどうかを確認するための特別なプロパティはありません。ただし、DataReceivedイベントが発生するたびに、データを処理する前にフラグを設定し、データの処理が完了するとフラグを解除することで、DataReceivedイベントが実行中であるかどうかを追跡できます。
以下は、DataReceivedイベントが実行中であるかどうかを確認するための基本的なコード例です。
“`
private bool isDataReceivedBusy = false;
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// フラグを設定する
isDataReceivedBusy = true;
// 受信したデータを処理する
// …
// フラグを解除する
isDataReceivedBusy = false;
}
private void buttonSend_Click(object sender, EventArgs e)
{
// DataReceivedイベントが実行中でないことを確認する
if (!isDataReceivedBusy)
{
// データを送信する
serialPort.Write(“Data to send”);
}
else
{
// DataReceivedイベントが実行中であることを示すエラーを表示する
MessageBox.Show(“DataReceivedイベントが実行中です。しばらくしてからもう一度試してください。”);
}
}
“`
この例では、DataReceivedイベントが実行中であるかどうかを示すフラグ `isDataReceivedBusy` を使用して、データを送信する前にDataReceivedイベントが実行中でないことを確認しています。 DataReceivedイベントが実行中である場合、エラーメッセージが表示されます。フラグが設定される場所は、実際に受信されたデータを処理する前に設定され、処理が完了するとフラグが解除されます。
ただし、注意点として、DataReceivedイベントが非同期に発生することがあるため、フラグを正確に追跡するには、適切な同期方法が必要です。例えば、`lock`ステートメントを使用して、`isDataReceivedBusy`フラグにアクセスする際に排他制御を行うことができます。
***
●解決策
serialDataRecivedの直下にフラグを設けるだけで、解決できるそうです。
さっそくやってみたら、なんとボタン押してもハングしなくなりました。
コードは下記です。
https://gist.github.com/dj1711572002/2a0e9e81c3921266c8fe0d28db72ad49
短いのので表記しておきます。赤文字がフラグ部分です。
注意するのは、serialPortDataRecivedの直下にフラグをtrueにたてることです。
最後に建てたら、送信エラーがでてしまいました。受信動作する前にフラグあげておかないといけませんでした。
flagの public static bool isDataReceivedBusy ; 宣言はグローバル扱いにして、すべてのクラスから参照できるようにしておきます。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; using System.Diagnostics; using static System.Net.Mime.MediaTypeNames; using static System.Windows.Forms.VisualStyles.VisualStyleElement; using System.Threading; using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolBar;namespace STA23_SerialTest_rev02 { public partial class Form1 : Form { int i; public struct rdata { public string[] lines; public string[] sline; public string[] sline1; public string[] sline2; public string[] sline3; public string[] sline4;public string itowB; } static rdata r; public Form1() { InitializeComponent();}private void button1_Click(object sender, EventArgs e) { serialPort1.BaudRate = 115200; serialPort1.Parity = Parity.None; serialPort1.DataBits = 8; serialPort1.StopBits = StopBits.One; serialPort1.Handshake = Handshake.None; serialPort1.PortName = portComboBox.Text; serialPort1.Open(); }public static bool isDataReceivedBusy ; private void Form1_Load(object sender, EventArgs e) { this.Text = “STA23_Serial_Test_rev02”; string[] ports = SerialPort.GetPortNames(); foreach (string port in ports) { portComboBox.Items.Add(port); } if (portComboBox.Items.Count > 0) portComboBox.SelectedIndex = 0; }delegate void DataDelegate(string sdata); //=================printdata 内でデータ処理================================ private void printdata(string text) { Debug.Print(“[printdata IN]”+text); richTextBox1.AppendText(text); if (text.IndexOf(‘[‘) > 0) { r.lines = text.Split(‘[‘); Debug.Print(“lines=” + r.lines[1]);if (r.lines.Length > 0) { r.sline = r.lines[1].Split(‘,’); Debug.Print(“sline=” + r.sline[1]); if (r.sline.Length>0) { if (r.sline[0] == “m]” || r.sline[0] == “p]” || r.sline[0] == “s]”) { r.sline1 = r.sline; Debug.Print(“sline1=” + r.sline1[1]); inputtbox1(r.sline1); textBox2.Text = “[” + r.sline1[0]; } if (r.sline[0] == “Base]”) if (r.sline[0] == “Rover]”) if (r.sline[0] == “BNO]”) // ——————-Serial受信部————————————————– } } private void inputtbox2(string[] s)//[Base]行入力 textBox3-11 } private void button2_Click(object sender, EventArgs e) } private void button3_Click(object sender, EventArgs e) private void button4_Click(object sender, EventArgs e) } private void button5_Click(object sender, EventArgs e) } private void button6_Click(object sender, EventArgs e) } private void button2_Click_1(object sender, EventArgs e) } private void textBox1_TextChanged(object sender, EventArgs e) } private void button7_Click(object sender, EventArgs e) |