【Arduino】使用C#实现Arduino与电脑进行串行通讯
生活随笔
收集整理的這篇文章主要介紹了
【Arduino】使用C#实现Arduino与电脑进行串行通讯
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
在給Arduino編程的時候,因為沒有調(diào)試工具,經(jīng)常要通過使用串口通訊的方式調(diào)用Serial.print和Serial.println輸出Arduino運行過程中的相關(guān)信息,然后在電腦上用Arduino IDE的Serial Monitor來查看print出來的信息。Serial Monitor不僅可以接受Arduino發(fā)送到電腦的數(shù)據(jù),還可以向Arduino發(fā)送數(shù)據(jù),進(jìn)行雙向通訊。但是這種通訊方式太過于簡陋,是純粹的手工方式,只適合調(diào)試。如果需要在電腦上通過可視化界面與Arduino進(jìn)行交互,或者對Arduino發(fā)送到電腦上的數(shù)據(jù)進(jìn)行處理,就需要在電腦上編程了。說的專業(yè)一點就是上位機(jī)與下位機(jī)的通訊。本文就介紹一下如何使用C#實現(xiàn)Arduino與電腦進(jìn)行串行通訊。 1、C#串口編程基礎(chǔ) 在C#中有一個串口類System.IO.Ports.SerialPort,這個類的實例就對應(yīng)設(shè)備管理器中的串口。 比如 SerialPort port = new SerialPort("COM4") 這句代碼就定義了一個串口實例,對應(yīng)下圖中的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串口編程基礎(chǔ) Arduino中的Serial和C#的SerialPort用法類似,有available, begin,?read, readBytes,?write, print, println,從名稱上也很容易理解。具體用法可以參考官方文檔:http://arduino.cc/en/Reference/Serial 一般我們會在Arduino代碼的setup方法中添加Serial.begin(9600),然后在serialEvent方法中讀取接收到的數(shù)據(jù)。 3、實例 實例的場景為: 1、Arduino上接一個光線傳感器,通過模擬口周期性讀取亮度值。 2、在電腦上向Arduino發(fā)送一個開始發(fā)送數(shù)據(jù)的命令后,點亮Arduino上13號數(shù)字口的LED,然后Arduino通過串口向電腦發(fā)送亮度值。 3、在電腦上向Arduino發(fā)送一個停止發(fā)送數(shù)據(jù)的命令后,關(guān)閉Arduino上13號數(shù)字口的LED,然后Arduino停止通過串口向電腦發(fā)送亮度值。 這個場景包含了Arduino和電腦的雙向通訊。 示例采用WinForm,界面如下: “串口列表”中自動加載電腦上的可用串口名稱。 點擊“開始讀取”按鈕,根據(jù)選擇的串口名稱實例化一個串口對象,指定串口的DataReceived事件處理方法。然后調(diào)用ChangeArduinoSendStatus方法向Arduino發(fā)送“serial start”命令。 點擊“停止讀取”按鈕,向Arduino發(fā)送“serial stop”命令,關(guān)閉串口并銷毀實例。 點擊“開始發(fā)送”或“停止發(fā)送”按鈕,調(diào)用ChangeArduinoSendStatus方法向Arduino發(fā)送“serial start”或“serial stop”命令,讓Arduino開始通過串口向電腦發(fā)送數(shù)據(jù)或停止向電腦發(fā)送數(shù)據(jù)。 串口在接收到數(shù)據(jù)后出發(fā)DataReceived事件,在事件處理方法中調(diào)用RefreshInfoTextBox方法,讀取串口的數(shù)據(jù)并追加到界面的文本框。注意:串口的DataReceived事件是由后臺線程執(zhí)行,要把讀取到的數(shù)據(jù)顯示在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("初始化串口發(fā)生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
????}
}
?
/// <summary>
/// 關(guān)閉并銷毀串口實例
/// </summary>
private void DisposeSerialPort()
{
????if (port != null)
????{
????????try
????????{
????????????this.ChangeArduinoSendStatus(false);
????????????if (port.IsOpen)
????????????{
????????????????port.Close();
????????????}
????????????port.Dispose();
????????}
????????catch (Exception ex)
????????{
????????????MessageBox.Show("關(guān)閉串口發(fā)生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
????????}
????}
}
?
/// <summary>
/// 改變Arduino串口的發(fā)送狀態(tài)
/// </summary>
/// <param name="allowSend">是否允許發(fā)送數(shù)據(jù)</param>
private void ChangeArduinoSendStatus(bool allowSend)
{
????if (port != null && port.IsOpen)
????{
????????if (allowSend)
????????{
????????????port.WriteLine("serial start");
????????}
????????else
????????{
????????????port.WriteLine("serial stop");
????????}
????}
}
?
/// <summary>
/// 從串口讀取數(shù)據(jù)并轉(zhuǎn)換為字符串形式
/// </summary>
/// <returns></returns>
private string ReadSerialData()
{
????string value = "";
????try
????{
????????if (port != null && port.BytesToRead > 0)
????????{
????????????value = port.ReadExisting();
????????}
????}
????catch (Exception ex)
????{
????????MessageBox.Show("讀取串口數(shù)據(jù)發(fā)生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
????}
?
????return value;
}
?
/// <summary>
/// 在讀取到數(shù)據(jù)時刷新文本框的信息
/// </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代碼 代碼注釋很詳細(xì),就不再做解釋。 int pinLed = 13;//定義連接LED的數(shù)字口,當(dāng)允許通過串口發(fā)送數(shù)據(jù)時,點亮LED,否則關(guān)閉LED
boolean sendFlag = false;//指示是否允許通過串口發(fā)送數(shù)據(jù) boolean readCompleted = false;//指示是否完成讀取串口數(shù)據(jù)
String serialString = "";//串口數(shù)據(jù)緩存字符串 //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)//判斷串口是否接收到數(shù)據(jù)并完成讀取
??{
????Serial.print("read value:");
????Serial.println(serialString);//將讀取到的信息發(fā)送給電腦
????if(serialString == "serial start")//當(dāng)讀取到的信息是"serial start"時,設(shè)置發(fā)送標(biāo)志設(shè)置為true
????{
??????sendFlag = true;
????}
????else if(serialString == "serial stop")//當(dāng)讀取到的信息是"serial stop"時,設(shè)置發(fā)送標(biāo)志設(shè)置為false
????{
??????sendFlag = false;
????}
????serialString = ""; readCompleted = false;
??}
?
??if(sendFlag)//如果允許通過串口發(fā)送數(shù)據(jù),則點亮LED并發(fā)送數(shù)據(jù),否則關(guān)閉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')//以換行符作為讀取結(jié)束標(biāo)志
????{
??????serialString += inChar;
????}
????else
????{
??????readCompleted = true;
????}
??}
} 完整代碼下載:http://files.cnblogs.com/files/conexpress/Arduino%E5%92%8CCSharp%E9%80%9A%E8%AE%AF.rar
/// <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("初始化串口發(fā)生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
????}
}
?
/// <summary>
/// 關(guān)閉并銷毀串口實例
/// </summary>
private void DisposeSerialPort()
{
????if (port != null)
????{
????????try
????????{
????????????this.ChangeArduinoSendStatus(false);
????????????if (port.IsOpen)
????????????{
????????????????port.Close();
????????????}
????????????port.Dispose();
????????}
????????catch (Exception ex)
????????{
????????????MessageBox.Show("關(guān)閉串口發(fā)生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
????????}
????}
}
?
/// <summary>
/// 改變Arduino串口的發(fā)送狀態(tài)
/// </summary>
/// <param name="allowSend">是否允許發(fā)送數(shù)據(jù)</param>
private void ChangeArduinoSendStatus(bool allowSend)
{
????if (port != null && port.IsOpen)
????{
????????if (allowSend)
????????{
????????????port.WriteLine("serial start");
????????}
????????else
????????{
????????????port.WriteLine("serial stop");
????????}
????}
}
?
/// <summary>
/// 從串口讀取數(shù)據(jù)并轉(zhuǎn)換為字符串形式
/// </summary>
/// <returns></returns>
private string ReadSerialData()
{
????string value = "";
????try
????{
????????if (port != null && port.BytesToRead > 0)
????????{
????????????value = port.ReadExisting();
????????}
????}
????catch (Exception ex)
????{
????????MessageBox.Show("讀取串口數(shù)據(jù)發(fā)生錯誤:" + ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
????}
?
????return value;
}
?
/// <summary>
/// 在讀取到數(shù)據(jù)時刷新文本框的信息
/// </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代碼 代碼注釋很詳細(xì),就不再做解釋。 int pinLed = 13;//定義連接LED的數(shù)字口,當(dāng)允許通過串口發(fā)送數(shù)據(jù)時,點亮LED,否則關(guān)閉LED
boolean sendFlag = false;//指示是否允許通過串口發(fā)送數(shù)據(jù) boolean readCompleted = false;//指示是否完成讀取串口數(shù)據(jù)
String serialString = "";//串口數(shù)據(jù)緩存字符串 //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)//判斷串口是否接收到數(shù)據(jù)并完成讀取
??{
????Serial.print("read value:");
????Serial.println(serialString);//將讀取到的信息發(fā)送給電腦
????if(serialString == "serial start")//當(dāng)讀取到的信息是"serial start"時,設(shè)置發(fā)送標(biāo)志設(shè)置為true
????{
??????sendFlag = true;
????}
????else if(serialString == "serial stop")//當(dāng)讀取到的信息是"serial stop"時,設(shè)置發(fā)送標(biāo)志設(shè)置為false
????{
??????sendFlag = false;
????}
????serialString = ""; readCompleted = false;
??}
?
??if(sendFlag)//如果允許通過串口發(fā)送數(shù)據(jù),則點亮LED并發(fā)送數(shù)據(jù),否則關(guān)閉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')//以換行符作為讀取結(jié)束標(biāo)志
????{
??????serialString += inChar;
????}
????else
????{
??????readCompleted = true;
????}
??}
} 完整代碼下載:http://files.cnblogs.com/files/conexpress/Arduino%E5%92%8CCSharp%E9%80%9A%E8%AE%AF.rar
轉(zhuǎn)載于:https://www.cnblogs.com/conexpress/p/Arduino_Connecte_Compute_With_SerialPort.html
總結(jié)
以上是生活随笔為你收集整理的【Arduino】使用C#实现Arduino与电脑进行串行通讯的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再谈并发
- 下一篇: c# 编程学习(二)