【Arduino】使用C#實現Arduino與電腦進行串行通訊


在給Arduino編程的時候,因為沒有調試工具,經常要通過使用串口通訊的方式調用Serial.print和Serial.println輸出Arduino運行過程中的相關信息,然后在電腦上用Arduino IDE的Serial Monitor來查看print出來的信息。Serial Monitor不僅可以接受Arduino發送到電腦的數據,還可以向Arduino發送數據,進行雙向通訊。但是這種通訊方式太過於簡陋,是純粹的手工方式,只適合調試。如果需要在電腦上通過可視化界面與Arduino進行交互,或者對Arduino發送到電腦上的數據進行處理,就需要在電腦上編程了。說的專業一點就是上位機與下位機的通訊。本文就介紹一下如何使用C#實現Arduino與電腦進行串行通訊。

1、C#串口編程基礎
在C#中有一個串口類System.IO.Ports.SerialPort,這個類的實例就對應設備管理器中的串口。
比如 SerialPort port = new SerialPort("COM4")
這句代碼就定義了一個串口實例,對應下圖中的USB Serial Port(COM4)
SerialPort常用方法包括Open, Close, Read, ReadLine, Write, WriteLine。這些方法通過名稱就很容易理解它們的用法。
 
2、Arduino串口編程基礎
Arduino中的Serial和C#的SerialPort用法類似,有available, begin, read, readBytes, write, print, println,從名稱上也很容易理解。具體用法可以參考官方文檔: http://arduino.cc/en/Reference/Serial
一般我們會在Arduino代碼的setup方法中添加Serial.begin(9600),然后在serialEvent方法中讀取接收到的數據。
 
3、實例
實例的場景為:
1、Arduino上接一個光線傳感器,通過模擬口周期性讀取亮度值。
2、在電腦上向Arduino發送一個開始發送數據的命令后,點亮Arduino上13號數字口的LED,然后Arduino通過串口向電腦發送亮度值。
3、在電腦上向Arduino發送一個停止發送數據的命令后,關閉Arduino上13號數字口的LED,然后Arduino停止通過串口向電腦發送亮度值。
這個場景包含了Arduino和電腦的雙向通訊。
示例采用WinForm,界面如下:

“串口列表”中自動加載電腦上的可用串口名稱。
點擊“開始讀取”按鈕,根據選擇的串口名稱實例化一個串口對象,指定串口的DataReceived事件處理方法。然后調用ChangeArduinoSendStatus方法向Arduino發送“serial start”命令。
點擊“停止讀取”按鈕,向Arduino發送“serial stop”命令,關閉串口並銷毀實例。
點擊“開始發送”或“停止發送”按鈕,調用ChangeArduinoSendStatus方法向Arduino發送“serial start”或“serial stop”命令,讓Arduino開始通過串口向電腦發送數據或停止向電腦發送數據。
串口在接收到數據后出發DataReceived事件,在事件處理方法中調用RefreshInfoTextBox方法,讀取串口的數據並追加到界面的文本框。注意:串口的DataReceived事件是由后台線程執行,要把讀取到的數據顯示在WinFrom界面,需要使用控件的Invoke方法才能刷新界面。
 
C#核心代碼如下:
private SerialPort port =  null;
/// <summary>
/// 初始化串口實例
/// </summary>
private  void InitialSerialPort()
{
     try
    {
         string portName =  this.cmbSerials.SelectedItem.ToString();
        port =  new SerialPort(portName, 9600);
        port.Encoding = Encoding.ASCII;
        port.DataReceived += port_DataReceived;
        port.Open();
         this.ChangeArduinoSendStatus( true);
    }
     catch (Exception ex)
    {
        MessageBox.Show("初始化串口發生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
}
 
/// <summary>
/// 關閉並銷毀串口實例
/// </summary>
private  void DisposeSerialPort()
{
     if (port !=  null)
    {
         try
        {
             this.ChangeArduinoSendStatus( false);
             if (port.IsOpen)
            {
                port.Close();
            }
            port.Dispose();
        }
         catch (Exception ex)
        {
            MessageBox.Show("關閉串口發生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }
}
 
/// <summary>
/// 改變Arduino串口的發送狀態
/// </summary>
/// <param name="allowSend">是否允許發送數據</param>
private  void ChangeArduinoSendStatus( bool allowSend)
{
     if (port !=  null && port.IsOpen)
    {
         if (allowSend)
        {
            port.WriteLine("serial start");
        }
         else
        {
            port.WriteLine("serial stop");
        }
    }
}
 
/// <summary>
/// 從串口讀取數據並轉換為字符串形式
/// </summary>
/// <returns></returns>
private  string ReadSerialData()
{
     string value = "";
     try
    {
         if (port !=  null && port.BytesToRead > 0)
        {
            value = port.ReadExisting();
        }
    }
     catch (Exception ex)
    {
        MessageBox.Show("讀取串口數據發生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
 
     return value;
}
 
/// <summary>
/// 在讀取到數據時刷新文本框的信息
/// </summary>
private  void RefreshInfoTextBox()
{
     string value =  this.ReadSerialData();
    Action< string> setValueAction = text =>  this.txtInfo.Text += text;
 
     if ( this.txtInfo.InvokeRequired)
    {
         this.txtInfo.Invoke(setValueAction, value);
    }
     else
    {
        setValueAction(value);
    }
}
 
Arduino代碼
代碼注釋很詳細,就不再做解釋。
int pinLed = 13;//定義連接LED的數字口,當允許通過串口發送數據時,點亮LED,否則關閉LED
boolean sendFlag =  false;//指示是否允許通過串口發送數據
boolean readCompleted =  false;//指示是否完成讀取串口數據
String serialString = "";//串口數據緩存字符串
 
//Author:Alex Leo, Email:conexpress@qq.com, Blog:http://conexpress.cnblogs.com/
//參考:http://arduino.cc/en/Reference/Serial
void setup()
{
  pinMode(pinLed,OUTPUT);
  Serial.begin(9600);
  serialString.reserve(200);//初始化字符串
}
 
void loop()
{
   int lightValue = analogRead(A0);//從A0口讀取光線傳感器的值
   if(readCompleted)//判斷串口是否接收到數據並完成讀取
  {
    Serial.print("read value:");
    Serial.println(serialString);//將讀取到的信息發送給電腦
     if(serialString == "serial start")//當讀取到的信息是"serial start"時,設置發送標志設置為true
    {
      sendFlag =  true;
    }
     else  if(serialString == "serial stop")//當讀取到的信息是"serial stop"時,設置發送標志設置為false
    {
      sendFlag =  false;
    }
    serialString = "";
    readCompleted =  false;
  }
 
   if(sendFlag)//如果允許通過串口發送數據,則點亮LED並發送數據,否則關閉LED
  {
    digitalWrite(pinLed, HIGH);
    Serial.print("light value:");
    Serial.println(lightValue);
  }
   else
  {
    digitalWrite(pinLed, LOW);
  }
  delay(1000);//延時1000ms
}
 
void serialEvent()//串口事件處理方法,參考:http://arduino.cc/en/Tutorial/SerialEvent
{
   while(Serial.available())//參考://arduino.cc/en/Serial/Available
  {
     char inChar = ( char)Serial.read();
     if(inChar != '\n')//以換行符作為讀取結束標志
    {
      serialString += inChar;
    }
     else
    {
      readCompleted =  true;
    }
  }
}
 
 
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM