1. 程式人生 > >【Arduino】使用C#實現Arduino與電腦進行串行通訊

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

可視化 action 指示 追加 停止 format reads 接受 按鈕

在給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。這些方法通過名稱就很容易理解它們的用法。 具體類信息可以參考MSDN:http://msdn.microsoft.com/zh-cn/library/vstudio/System.IO.Ports.SerialPort(v=vs.100).aspx 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:[email protected], 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;
}
}
} 完整代碼下載:http://files.cnblogs.com/files/conexpress/Arduino%E5%92%8CCSharp%E9%80%9A%E8%AE%AF.rar

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