3

私は、シリアル通信を介して 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:イベント ハンドラでスリープを削除 (コメント アウト) しました。イベント ハンドラーの実行中にスリープしていたため、マイクロコントローラーが送信するものを何も受信できませんでした。コードは期待どおりに正常に動作します。

4

2 に答える 2

0

COM1を使用していることを確認してください。COM1 シリアル ポートを使用していない場合は、 [コンピューター] -> [デバイス マネージャー] -> [ポート (COM & LPT) ] -> [変更する COM を選択] - > [ポート設定] -> [詳細設定] -> [ ComPort 番号] - > COM1 を選択します

COM1ピン 2とピン 3 の間にジャンパーが取り付けられているか、ドライバーで接続されていることを確認してください

button1textBox1フォームに追加し、このプログラムを実行します

using System;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.Text;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {

        const int MAX_BUFFER = 100;

        int i = 0;
        byte[] DataReceived = new byte[MAX_BUFFER];
        SerialPort serialPort = new SerialPort();

        public Form1() {
            InitializeComponent();
            serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
        }

        void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {
            // wait data ready
            Thread.Sleep(500);

            // while data ready in buffer
            while (serialPort.IsOpen && serialPort.BytesToRead > 0) {
                // read data serial
                DataReceived[i] = Convert.ToByte(serialPort.ReadByte());

                // counter data
                i++;

                // reset conter if more then maxvalue
                if (i >= MAX_BUFFER) {
                    i = 0;
                }
            }

            if (i == 1 && DataReceived[0] == ASCIIEncoding.ASCII.GetBytes("^")[0]) {
                this.textBox1.Invoke(new Action(() => {
                    this.textBox1.Text = ASCIIEncoding.ASCII.GetString(DataReceived, 0, 1);

                }));
            }

        }

        public void InitSerialPort() {
            serialPort.PortName = "COM1";
            serialPort.BaudRate = 9600;
            serialPort.Parity = Parity.None;
            serialPort.DataBits = 8;
            serialPort.StopBits = StopBits.One;
            serialPort.ReceivedBytesThreshold = 1;
        }

        private void Form1_Load(object sender, EventArgs e) {
            // initialize serial port
            InitSerialPort();

            // assure port is closed before open it
            if (serialPort != null && serialPort.IsOpen) {
                serialPort.Close();
            }
            serialPort.Open();
        }

        private void button1_Click(object sender, EventArgs e) {
            if (serialPort.IsOpen) {
                serialPort.Write("^");
                // wait data sent
                Thread.Sleep(500);
            }
        }
    }
}
于 2013-04-06T08:26:36.470 に答える
0

私の4番目の編集に従って、イベントハンドラーでスリープを削除(コメントアウト)しました。イベント ハンドラーの実行中にスリープしていたため、マイクロコントローラーが送信するものを何も受信できませんでした。コードは期待どおりに正常に動作するようになりました。どちらのコンポーネントのシリアル ポートにも問題はありませんでした。

于 2013-04-17T06:54:21.713 に答える