私は、シリアル通信を介して Arduino マイクロコントローラー AtMega32U4 にデータを送信するクライアント ソフトウェアを含むプロジェクトに取り組んでいます。これまでに多くの回答された質問に目を通しましたが、どれも私の問題に固有のものではありませんでした. ただし、私の問題は、スレッドの問題または Arduino の自動リセットの問題に限定されている可能性があると思います。
コード 1:
public MainForm()
{
InitializeComponent();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.DtrEnable = true;
//serialPort1.RtsEnable = true;
}
private void button3_Click(object sender, EventArgs e)
{
// Disables button while processing
button3.Enabled = false;
GetDir dir = new App.GetDir();
dir.getCoords(Origin.Text, Destination.Text, Application.StartupPath + @"\temp2.html", "temp2.xml");
dataBrowser.Navigate(Application.StartupPath + @"\temp2.html");
dataBrowser.Update();
waypoints = dir.coordsLat.Length;
counter = dir.coordsLat.Length;
coords = new double[dir.coordsLat.Length, 2];
for (int i = 0; i < counter; i++)
{
coords[i, 0] = (Convert.ToDouble(dir.coordsLat[i]));
coords[i, 1] = (Convert.ToDouble(dir.coordsLon[i]));
}
//serialPort1.Close();
//System.Threading.Thread.Sleep(1000);
if (serialPort1.IsOpen && !doubleClick)
{
serialPort1.Close();
System.Threading.Thread.Sleep(2000);
try
{
serialPort1.Open();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
System.Threading.Thread.Sleep(2000);
}
else
{
if (!serialPort1.IsOpen)
{
try
{
serialPort1.Open();
doubleClick = true;
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
System.Threading.Thread.Sleep(2000);
serialPort1.Write("^");
System.Threading.Thread.Sleep(1000);
Console.WriteLine('^');
//button3.Enabled = true;
}
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//System.Threading.Thread.Sleep(1000);
readData = serialPort1.ReadLine();
Console.WriteLine(readData);
// If microcontroller sends "&", it is ready to receive next piece of data
if (readData == "&")
{
sendRequest = true;
}
else
{
sendRequest = false;
}
// Write next piece of data to microcontroller if it is ready
if (sendRequest)
{
this.BeginInvoke( new EventHandler (write_serialPort1));
}
}
コード 1 のデバッグ中に、イベント ハンドラー (serialPort1_DataReceived) が呼び出されることはありません。このプロセスでは、コンソールが '^' を 2 回出力するので、どういうわけか button3_click が 2 回呼び出されます。その後、何も受信されないため、クライアントは停止します。サーカムフレックス ('^') を受け取ると、Arduino はアンパサンド ('&') で応答することに注意してください。Arduino コードは Arduino IDE でテストされており、正常に動作しているようです。button3_click が 2 回呼び出される問題は、button3_down と button3_up に起因すると思います。
ただし、コード 2 を使用してこの問題を回避することができました。しかし、別のレンガの壁にもぶつかりました。
コード 2 :
private void button3_Click(object sender, EventArgs e)
{
// Disables button while processing
button3.Enabled = false;
GetDir dir = new App.GetDir();
dir.getCoords(Origin.Text, Destination.Text, Application.StartupPath + @"\temp2.html", "temp2.xml");
dataBrowser.Navigate(Application.StartupPath + @"\temp2.html");
dataBrowser.Update();
waypoints = dir.coordsLat.Length;
counter = dir.coordsLat.Length;
coords = new double[dir.coordsLat.Length, 2];
for (int i = 0; i < counter; i++)
{
coords[i, 0] = (Convert.ToDouble(dir.coordsLat[i]));
coords[i, 1] = (Convert.ToDouble(dir.coordsLon[i]));
}
serialPort1.Close();
try
{
serialPort1.Open();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
if (serialPort1.IsOpen)
{
System.Threading.Thread.Sleep(2000);
using (serialPort1)
{
serialPort1.Write("^");
System.Threading.Thread.Sleep(1000);
Console.WriteLine("^");
serialPort1.Close();
System.Threading.Thread.Sleep(5000);
}
}
else
{
button3.Enabled = true;
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//SerialPort sp = (SerialPort)sender;
System.Threading.Thread.Sleep(10000);
/*if (!serialPort1.IsOpen)
{
serialPort1.Close();
System.Threading.Thread.Sleep(10000);
serialPort1.Open();
System.Threading.Thread.Sleep(10000);
}*/
//serialPort1.Open();
//using (sp)
using (serialPort1)
{
serialPort1.Open();
System.Threading.Thread.Sleep(5000);
readData = serialPort1.ReadExisting();
Console.WriteLine(readData);
// If microcontroller sends "&", it is ready to receive next piece of data
if (readData == "&")
{
sendRequest = true;
}
else
{
sendRequest = false;
}
// Write next piece of data to microcontroller if it is ready
if (sendRequest)
{
this.BeginInvoke(new EventHandler(write_serialPort1));
}
}
}
コード 2 では、イベント ハンドラーが呼び出され、button3_click は 1 回だけ実行されます。しかし、ポートを開こうとすると、エラー ' Access to Port X denied
' が返されます。さらに、このようにポートを閉じたり開いたりする必要がなければいいのですが、(以前のコードで) イベント ハンドラーが呼び出されると、COM ポートが開かれていないというエラーが返されました。button3_click
そのエラーを満たすために、イベント処理中に閉じてから再度開く必要がありました。
シリアル通信のスレッド化の問題に対処する多くの問題について読んだ後、コードに多くの遅延を追加しました。問題を解決するためにスレッドが終了することを期待して、私はわずかな遅延さえ試みました. しかし、そこには運がありません。
また、シリアル ポートをコードで宣言するのではなく、MainForm デザイナで指定しました (最初は両方を実行しましたが、冗長であることに気付きました)。これが問題の原因かどうかはわかりませんが、両方が使用されている例を見てきました。
最後に、シリアル接続が確立されるたびに Arduino の自動リセット (ポートの開閉など) を確実に処理できます。要約すると、シリアル経由でデータを送信しているようですが、シリアルから受信データを読み取ることができません。
これを読んでくれてありがとう。誰かが私を正しい方向に向けることができれば、それは非常にありがたい.
編集 #1:コード 1 で BeginInvoke を使用した後でも、イベント ハンドラーが呼び出されなかったため、デッドロックが発生します。
編集#2:初心者の提案に従ってコード1を編集します。
編集 #3:メインフォームの初期化を追加し、コード 1 を現在の状態に更新しました。
編集 #4:イベント ハンドラでスリープを削除 (コメント アウト) しました。イベント ハンドラーの実行中にスリープしていたため、マイクロコントローラーが送信するものを何も受信できませんでした。コードは期待どおりに正常に動作します。