簡體   English   中英

C#與Arduino的串行通信

[英]C# Serial Communication to Arduino

我正在開展一個項目,涉及我的客戶端軟件通過串行通信將數據發送到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)。 在這個過程中,當控制台輸出'^'兩次時,會以某種方式調用button3_click兩次。 之后,客戶端停止運轉,因為沒有收到任何信息。 請記住,一旦收到回旋('^'),Arduino將以&符號('&')作出響應。 Arduino代碼已經在Arduino IDE上進行了測試,似乎工作正常。 我相信button3_click被調用兩次的問題來自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只運行一次。 但是當它嘗試打開端口時,它會返回錯誤“ Access to Port X denied ”。 此外,我希望我不必像這樣關閉和打開端口,但是當調用事件處理程序時(在早期的代碼中),它返回了未打開COM端口的錯誤。 為了滿足該錯誤,我必須關閉它並在button3_click和事件處理期間重新打開它。

在我閱讀了許多處理串行通信線程問題的問題之后,我在代碼中添加了很多延遲。 我甚至試過了一分鍾的延遲,希望線程能夠解決問題。 但是,那里沒有運氣。

我還在MainForm設計器中指定了我的串口,而不是在代碼中聲明它(起初我做了兩個並且意識到它是多余的)。 我不確定這是否有助於解決這個問題,但我已經看到了這兩個問題的例子。

最后,無論何時進行串行連接(例如打開和關閉端口),它都可以處理Arduino自動復位。 總之,它似乎是通過串行發送數據,但無法從串行讀取傳入的數據。

感謝您閱讀本文,如果有人能指出我正確的方向,我將非常感激。

編輯#1:即使在代碼1中使用BeginInvoke之后,它仍然會死鎖,因為從未調用過事件處理程序。

編輯#2:根據新手的建議編輯代碼1。

編輯#3:添加了主窗體初始化並將代碼1更新為當前狀態。

編輯#4:在事件處理程序中刪除(注釋掉)睡眠。 我在事件處理程序期間正在睡覺,因此我無法收到微控制器發送給我的任何信息。 代碼工作正常,如預期。

確保您使用的是COM1 ,如果您沒有COM1串口,請通過計算機 - > 設備管理器 - > 端口(COM和LPT) - > 選擇要更改的COM - > 端口設置 - > 高級 - > ComPort編號 - > 選擇COM1

確保在COM1的 pin2pin3之間用螺絲刀安裝了跳線/連接器。

button1textBox1添加到Form並運行此程序

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);
            }
        }
    }
}

按照我的第4次編輯,刪除(注釋掉)事件處理程序的睡眠。 我在事件處理程序期間正在睡覺,因此我無法收到微控制器發送給我的任何信息。 代碼工作正常,如預期。 任何組件上的串行端口都沒有問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM