C#中串口通信编程 收藏
C#中串口通信編程 收藏
本文將介紹如何在.NET平臺(tái)下使用C#創(chuàng)建串口通信程序,.NET 2.0提供了串口通信的功能,其命名
空間是System.IO.Ports。這個(gè)新的框架不但可以訪問計(jì)算機(jī)上的串口,還可以和串口設(shè)備進(jìn)行通信。
我們將使用標(biāo)準(zhǔn)的RS 232 C 在PC間通信。它工作在全雙工模式下,而且我們不打算使用任何的握手
或流控制器,而是使用無(wú)modem連接。
命名空間
System.IO.Ports命名空間中最重用的是SerialPort 類。
創(chuàng)建SerialPort 對(duì)象
通過創(chuàng)建SerialPort 對(duì)象,我們可以在程序中控制串口通信的全過程。
我們將要用到的SerialPort 類的方法:
ReadLine():從輸入緩沖區(qū)讀一新行的值,如果沒有,會(huì)返回NULL
WriteLine(string):寫入輸出緩沖
Open():打開一個(gè)新的串口連接
Close():關(guān)閉
Code:
//create a Serial Port object
SerialPort sp = new SerialPort ();
默認(rèn)情況下,DataBits 值是8,StopBits 是1,通信端口是COM1。這些都可以在下面的屬性中重新設(shè)置
:
BaudRate:串口的波特率
StopBits:每個(gè)字節(jié)的停止位數(shù)量
ReadTimeout:當(dāng)讀操作沒有完成時(shí)的停止時(shí)間。單位,毫秒
還有不少其它公共屬性,自己查閱MSDN。
串口的硬件知識(shí)
在數(shù)據(jù)傳輸?shù)臅r(shí)候,每個(gè)字節(jié)的數(shù)據(jù)通過單個(gè)的電纜線傳輸。包包括開始位,數(shù)據(jù),結(jié)束為。一旦
開始位傳出,后面就會(huì)傳數(shù)據(jù),可能是5,6,7或8位,就看你的設(shè)定了。發(fā)送和接收必須設(shè)定同樣
的波特率和數(shù)據(jù)位數(shù)。
無(wú)貓模式
沒有Modem模式的電纜只是簡(jiǎn)單地交叉?zhèn)魉秃徒邮站€。同樣DTR & DSR, 和 RTS & CTS也需要交叉。
RS232針圖
這里,我們?nèi)龡l線。互連2和3(一段的2pin連接3pin),連接兩端的5pin。
[示例程序]
主程序
如果想使用默認(rèn)屬性,按“Save Status”按鈕,如果想改變屬性按“Property”。它會(huì)彈出下圖:
設(shè)定好之后,可以通信了。
主窗口的代碼
Code:
#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.IO.Ports;
#endregion
namespace Serialexpample
{
??? partial class Form1 : Form
??? {
??????? //create instance of property page
??????? //property page is used to set values for stop bits and
??????? //baud rate
??????? PropertyPage pp = new PropertyPage();
??????? //create an Serial Port object
??????? SerialPort sp = new SerialPort();
??????? public Form1()
??????? {
??????????? InitializeComponent();
??????? }
???????????
??????? private void propertyButton_Click(object sender, EventArgs e)
??????? {
??????????? //show property dialog
??????????? pp.ShowDialog();
??????????? propertyButton.Hide();
??????? }
??????? private void sendButton_Click(object sender, EventArgs e)
??????? {
??????????? try
??????????? {
??????????????? //write line to serial port
??????????????? sp.WriteLine(textBox.Text);
??????????????? //clear the text box
??????????????? textBox.Text = "";
??????????? }
??????????? catch (System.Exception ex)
??????????? {
??????????????? baudRatelLabel.Text = ex.Message;
??????????? }
??????? }
??????? private void ReadButton_Click(object sender, EventArgs e)
??????? {
??????????? try
??????????? {
??????????????? //clear the text box
????????????? ??textBox.Text = "";
??????????????? //read serial port and displayed the data in text box
??????????????? textBox.Text = sp.ReadLine();
??????????? }
??????????? catch(System.Exception ex)
??????????? {
??????????????? baudRatelLabel.Text = ex.Message;
? ??????????}
??????? }
??????? private void Form1_Load(object sender, EventArgs e)
??????? {
??????? }
??????? private void Form1_FormClosing(object sender, FormClosingEventArgs e)
??????? {
??????????? MessageBox.Show("Do u want to Close the App");
?????? ?????sp.Close();
??????? }
??????? private void startCommButton_Click(object sender, EventArgs e)
??????? {
??????????? startCommButton.Hide();
??????????? sendButton.Show();
??????????? readButton.Show();
??????????? textBox.Show();
??????? }
??????? //when we want to save the status(value)
??????? private void saveStatusButton_Click_1(object sender, EventArgs e)
??????? {
??????????? //display values
??????????? //if no property is set the default values
??????????? if (pp.bRate == "" && pp.sBits == "")
??????????? {
??????????????? dataBitLabel.Text = "BaudRate = " + sp.BaudRate.ToString();
??????????????? readTimeOutLabel.Text = "StopBits = " + sp.StopBits.ToString();
??????????? }
??????????? else
??????????? {
??????????????? dataBitLabel.Text = "BaudRate = " + pp.bRate;
??????????????? readTimeOutLabel.Text = "StopBits = " + pp.sBits;
??????????? }
??????????? parityLabel.Text = "DataBits = " + sp.DataBits.ToString();
??????????? stopBitLabel.Text = "Parity = " + sp.Parity.ToString();
??????????? readTimeOutLabel.Text = "ReadTimeout = " +
????????????????????? sp.ReadTimeout.ToString();
??????????? if (propertyButton.Visible == true)
??????????????? propertyButton.Hide();
??????????? saveStatusButton.Hide();
??????????? startCommButton.Show();
??????? ????try
??????????? {
??????????????? //open serial port
??????????????? sp.Open();
??????????????? //set read time out to 500 ms
??????????????? sp.ReadTimeout = 500;
??????????? }
??????????? catch (System.Exception ex)
??????????? {
??????????????? baudRatelLabel.Text = ex.Message;
??????????? }
??????? }
??? }
}
屬性設(shè)置對(duì)話框代碼:
Code:
#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
#endregion
namespace Serialexpample
{
??? partial class PropertyPage : Form
??? {
??????? //variables for storing values of baud rate and stop bits
??????? private string baudR="";
??????? private string stopB="";
??????? //property for setting and getting baud rate and stop bits
??????? public string bRate
??????? {
??????????? get
??????????? {
??????????????? return baudR;
??????????? }
??????????? set
??????????? {
??????????????? baudR = value;
??????????? }
??????? }
??????? public string sBits
??????? {
??????????? get
??????????? {
????????????? ??return stopB;
??????????? }
??????????? set
??????????? {
??????????????? stopB = value;
??????????? }
??????? }
??????? public PropertyPage()
??????? {
??????????? InitializeComponent();
??????? }
??????? private void cancelButton_Click(object sender, EventArgs e)
??????? {
??????????? this.bRate = "";
??????????? this.sBits = "";
??????????? //close form
??????????? this.Close();
??????? }
??????? private void okButton_Click_1(object sender, EventArgs e)
??????? {
??????????? //here we set the value for stop bits and baud rate.
??????????? this.bRate = BaudRateComboBox.Text;
??????????? this.sBits = stopBitComboBox.Text;
??????????? //
??????????? this.Close();
??????? }
??? }
}
?
一.概述
在Visual Studio 6.0中編寫串口通訊程序,一般都使用Microsoft Communication Control(簡(jiǎn)稱MSComm)的通訊控件,只要通 過對(duì)此控件的屬性和事件進(jìn)行相應(yīng)編程操作,就可以輕松地實(shí)現(xiàn)串口通訊。但在Microsoft.Net技術(shù)廣泛應(yīng)用的今天,Visual Studio.Net沒有將此控件加入控件庫(kù),所以人們采用了許多方法在Visual Studio.Net來(lái)編寫串口通訊程序:第一種方法是通過采用Visual Studio 6.0中原來(lái)的MSComm控件這是最簡(jiǎn)單的,最方便的方法,但需要注冊(cè);第二種方法是采用微軟在.NET推出了一個(gè)串口控件,基于.NET的P/Invoke調(diào)用方法實(shí)現(xiàn);第三種方法是自己用API寫串口通信,雖然難度高,但可以方便實(shí)現(xiàn)自己想要的各種功能。
現(xiàn)在微軟推出了最新版本的Visual Studio 2005開發(fā)工具,可以不再采用第三方控件的方法來(lái)設(shè)計(jì)串口通訊程序。NET Framework 2.0 類庫(kù)包含了SerialPort 類,方便地實(shí)現(xiàn)了所需要串口通訊的多種功能,為了使MSComm編程方法快速轉(zhuǎn)換到以SerialPort類為核心的串口通訊的設(shè)計(jì)方法,本文著重討論了Visual Studio 6.0的MSComm控件和SerialPort 類設(shè)計(jì)方法的異同點(diǎn)。
二.SerialPort常用屬性、方法和事件
1.命名空間
System.IO.Ports命名空間包含了控制串口重要的SerialPort類,該類提供了同步 I/O 和事件驅(qū)動(dòng)的 I/O、對(duì)管腳和中斷狀態(tài)的訪問以及對(duì)串行驅(qū)動(dòng)程序?qū)傩缘脑L問,所以在程序代碼起始位置需加入U(xiǎn)sing System.IO.Ports。
2.串口的通訊參數(shù)
串口通訊最常用的參數(shù)就是通訊端口號(hào)及通訊格式(波特率、數(shù)據(jù)位、停止位和校驗(yàn)位),在MSComm中相關(guān)的屬性是CommPort和Settings。SerialPort類與MSComm有一些區(qū)別:
a.通訊端口號(hào)
[PortName]屬性獲取或設(shè)置通信端口,包括但不限于所有可用的 COM 端口,請(qǐng)注意該屬性返回類型為String,不是Mscomm.CommPort的short類型。通常情況下,PortName正常返回的值為COM1、COM2……,SerialPort類最大支持的端口數(shù)突破了CommPort控件中CommPort屬性不能超過16的限止,大大方便了用戶串口設(shè)備的配置。
b. 通訊格式
SerialPort類對(duì)分別用[BaudRate]、[Parity]、[DataBits]、[StopBits]屬性設(shè)置通訊格式中的波特率、數(shù)據(jù)位、停止位和校驗(yàn)位,其中[Parity]和[StopBits]分別是枚舉類型Parity、StopBits,Parity類型中枚舉了Odd(奇)、Even(偶)、Mark、None、Space,Parity枚舉了None、One、OnePointFive、Two。
SerialPort類提供了七個(gè)重載的構(gòu)造函數(shù),既可以對(duì)已經(jīng)實(shí)例化的SerialPort對(duì)象設(shè)置上述相關(guān)屬性的值,也可以使用指定的端口名稱、波特率和奇偶校驗(yàn)位數(shù)據(jù)位和停止位直接初始化 SerialPort 類的新實(shí)例。
3.串口的打開和關(guān)閉
SerialPort類沒有采用MSComm.PortOpen=True/False設(shè)置屬性值打開關(guān)閉串口,相應(yīng)的是調(diào)用類的Open()和Close()方法。
4. 數(shù)據(jù)的發(fā)送和讀取
Serial類調(diào)用重載的Write和WriteLine方法發(fā)送數(shù)據(jù),其中WriteLine可發(fā)送字符串并在字符串末尾加入換行符,讀取串口緩沖區(qū)的方法有許多,其中除了ReadExisting和ReadTo,其余的方法都是同步調(diào)用,線程被阻塞直到緩沖區(qū)有相應(yīng)的數(shù)據(jù)或大于ReadTimeOut屬性設(shè)定的時(shí)間值后,引發(fā)ReadExisting異常。
5.DataReceived事件
該事件類似于MSComm控件中的OnComm事件,DataReceived事件在接收到了[ReceivedBytesThreshold]設(shè)置的字符個(gè)數(shù)或接收到了文件結(jié)束字符并將其放入了輸入緩沖區(qū)時(shí)被觸發(fā)。其中[ReceivedBytesThreshold]相當(dāng)于MSComm控件的[Rthreshold]屬性,該事件的用法與MsComm控件的OnComm事件在CommEvent為comEvSend和comEvEof時(shí)是一致的。? ?
三.SerialPort的使用
對(duì)于熟悉MSComm控件的程序設(shè)計(jì)者,SerialPort類是相當(dāng)容易上手的。在進(jìn)行串口通訊時(shí),一般的流程是設(shè)置通訊端口號(hào)及波特率、數(shù)據(jù)位、停止位和校驗(yàn)位,再打開端口連接,發(fā)送數(shù)據(jù),接收數(shù)據(jù),最后關(guān)閉端口連接這樣幾個(gè)步驟。
數(shù)據(jù)接收的設(shè)計(jì)方法在這里比較重要,采用輪詢的方法比較浪費(fèi)時(shí)間,在Visual Basic中的延時(shí)方法中一般會(huì)調(diào)用API并用DOEvents方法來(lái)處理,但程序不易控制,建議采用DataReceived事件觸發(fā)的方法,合理的設(shè)置ReceivedBytesThreshold的值,若接收的是定長(zhǎng)的數(shù)據(jù),則將ReceivedBytesThreshold設(shè)為接收數(shù)據(jù)的長(zhǎng)度,若接收數(shù)據(jù)的結(jié)尾是固定的字符或字符串則可采用ReadTo的方法或在DataReceived事件中判斷接收的字符是否滿足條件。
SerialPort類讀取數(shù)據(jù)的許多方法是同步阻塞調(diào)用,盡量避免在主線程中調(diào)用,可以使用異步處理或線程間處理調(diào)用這些讀取數(shù)據(jù)的方法。
由于DataReceived事件在輔線程被引發(fā),當(dāng)收到完整的一條數(shù)據(jù),返回主線程處理或在窗體上顯示時(shí),請(qǐng)注意跨線程的處理,C#可采用控件異步委托的方法Control.BeginInvoke及同步委托的方法Invoke。
四.結(jié)束語(yǔ)
在.NET平臺(tái)下熟練使用SerialPort 類,可以很好地開發(fā)出串口通訊類程序,對(duì)于過去使用MSComm控件設(shè)計(jì)了一些通訊程序,也可以將MSComm控件替換為SerialPort類,當(dāng)然為了避免對(duì)以前的項(xiàng)目做大的改動(dòng),可以使用SerialPort類設(shè)計(jì)一些與MSComm控件具有相同接口的類,在今后工業(yè)控制中,SerialPort類將廣泛地應(yīng)用于串口通訊程序的設(shè)計(jì)中,發(fā)揮著與MSComm控件一樣的作用。
2.以類的方式
?? VB:
1)???????? 定義SerialPort類實(shí)例
????? Dim SpCom As New System.IO.Ports.SerialPort()
2)???????? 設(shè)置通訊端口號(hào)及波特率、數(shù)據(jù)位、停止位和校驗(yàn)位。
??????? SpCom.PortName = "COM1"
??????? SpCom.BaudRate = 9600
??????? SpCom.Parity = IO.Ports.Parity.None
??????? SpCom.DataBits = 8
??????? SpCom.StopBits = IO.Ports.StopBits.One
??????? 或是定義時(shí)直接初始化
???????? Dim SpCom As New System.IO.Ports.SerialPort("COM1", 9600, IO.Ports.Parity.Even, 8,?
??????? IO.Ports.StopBits.None)
3)???????? 發(fā)送數(shù)據(jù)
???? SpCom.Write(TextSendData.Text)
4)?????? ??添加接受事件
a)??????? 在運(yùn)行時(shí)將事件與事件處理程序相關(guān)聯(lián)
AddHandler SpCom.DataReceived, AddressOf EventReceiveData
說(shuō)明:
AddressOf 創(chuàng)建引用特定過程的過程委托實(shí)例
AddressOf 運(yùn)算符可以用作委托構(gòu)造函數(shù)的操作數(shù),或可以用在編譯器能夠確定委???? 托類型的上下文中。
b)??????? 添加事件處理程序(簽名一定要一致)
????????????? Sub EventReceiveData(ByVal sender As Object, ByVal e As
??????????? System.IO.Ports.SerialDataReceivedEventArgs)
5)???????? 讀取數(shù)據(jù)
??????? Dim strT As String
???? strT = SpCom.ReadExisting()
C#:
1)???????? 添加引用
???? using System.IO.Ports;
2)???????? 定義SerialPort類實(shí)例
????? private SerialPort SpCom2 = new SpCom ("COM2", 9600,Parity.None, 8, StopBits.One);
3)???????? 設(shè)置通訊端口號(hào)及波特率、數(shù)據(jù)位、停止位和校驗(yàn)位。
??????? SpCom.PortName = "COM1";
??????? SpCom.BaudRate = 9600;
??????? SpCom.Parity = IO.Ports.Parity.None;
??????? SpCom.DataBits = 8;
??????? SpCom.StopBits = IO.Ports.StopBits.One;
??????? 或是定義時(shí)直接初始化
???????? private SerialPort SpCom2 = new SpCom ("COM2", 9600,Parity.None, 8, StopBits.One);
4)???????? 發(fā)送數(shù)據(jù)
???? SpCom.Write(TextSendData.Text);
5)???????? 添加接受事件
a)??????? 在運(yùn)行時(shí)將事件與事件處理程序相關(guān)聯(lián)(通過委托實(shí)現(xiàn))
SpCom.DataReceived += new SerialDataReceivedEventHandler(SpCom2_DataReceived);
說(shuō)明:
SerialDataReceivedEventHandler 委托 表示將處理 SerialPort 對(duì)象的 DataReceived 事件的方法
b)??????? 添加事件處理程序(簽名一定要一致)
????????????? private void SpCom_DataReceived(object sender, SerialDataReceivedEventArgs e)
6)???????? 讀取數(shù)據(jù)
??????? string data = SpCom .ReadExisting();
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/shengyongwang/archive/2009/05/19/4202154.aspx
usingSystem;
usingSystem.IO.Ports;
usingSystem.Threading;
?
publicclass PortChat
{
?????staticbool _continue;
?????static SerialPort _serialPort;
??????publicstaticvoid Main()
?????{
?????????string name;
?????????stringmessage;
?????????StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
?????????Thread readThread =newThread(Read);
??????????// Create a new SerialPort object with default settings.
??????????_serialPort =new SerialPort();
??????????// Allow the user to set the appropriate properties.
??????????_serialPort.PortName = SetPortName(_serialPort.PortName);
?????????_serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
?????????_serialPort.Parity = SetPortParity(_serialPort.Parity);
?????????_serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
?????????_serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
?????????_serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);
??????????// Set the read/write timeouts
??????????_serialPort.ReadTimeout = 500;
?????????_serialPort.WriteTimeout = 500;
??????????_serialPort.Open();
?????????_continue =true;
?????????readThread.Start();
??????????Console.Write("Name: ");
?????????name =Console.ReadLine();
??????????Console.WriteLine("Type QUIT to exit");
??????????while(_continue)
?????????{
?????????????message=Console.ReadLine();
??????????????if(stringComparer.Equals("quit",message))
?????????????{
?????????????????_continue =false;
?????????????}
?????????????else
??????????????{
?????????????????_serialPort.WriteLine(
?????????????????????String.Format("<{0}>: {1}", name,message));
?????????????}
?????????}
??????????readThread.Join();
?????????_serialPort.Close();
?????}
??????publicstaticvoid Read()
?????{
?????????while(_continue)
?????????{
?????????????try
??????????????{
?????????????????stringmessage= _serialPort.ReadLine();
?????????????????Console.WriteLine(message);
?????????????}
?????????????catch(TimeoutException){}
?????????}
?????}
??????publicstaticstring SetPortName(string defaultPortName)
?????{
?????????string portName;
??????????Console.WriteLine("Available Ports:");
?????????foreach(string s in SerialPort.GetPortNames())
?????????{
?????????????Console.WriteLine(" {0}", s);
?????????}
??????????Console.Write("COM port({0}): ", defaultPortName);
?????????portName =Console.ReadLine();
??????????if(portName =="")
?????????{
?????????????portName = defaultPortName;
?????????}
?????????return portName;
?????}
??????publicstaticint SetPortBaudRate(int defaultPortBaudRate)
?????{
?????????string baudRate;
??????????Console.Write("Baud Rate({0}): ", defaultPortBaudRate);
?????????baudRate =Console.ReadLine();
??????????if(baudRate =="")
?????????{
?????????????baudRate = defaultPortBaudRate.ToString();
?????????}
??????????returnint.Parse(baudRate);
?????}
??????publicstatic Parity SetPortParity(Parity defaultPortParity)
?????{
?????????string parity;
??????????Console.WriteLine("Available Parity options:");
?????????foreach(string s inEnum.GetNames(typeof(Parity)))
?????????{
?????????????Console.WriteLine(" {0}", s);
?????????}
??????????Console.Write("Parity({0}):", defaultPortParity.ToString());
?????????parity =Console.ReadLine();
??????????if(parity =="")
?????????{
?????????????parity = defaultPortParity.ToString();
?????????}
??????????return(Parity)Enum.Parse(typeof(Parity), parity);
?????}
??????publicstaticint SetPortDataBits(int defaultPortDataBits)
?????{
?????????string dataBits;
??????????Console.Write("Data Bits({0}): ", defaultPortDataBits);
?????????dataBits =Console.ReadLine();
??????????if(dataBits =="")
?????????{
?????????????dataBits = defaultPortDataBits.ToString();
?????????}
??????????returnint.Parse(dataBits);
?????}
?????
?????publicstatic StopBits SetPortStopBits(StopBits defaultPortStopBits)
?????{
?????????string stopBits;
??????????Console.WriteLine("Available Stop Bits options:");
?????????foreach(string s inEnum.GetNames(typeof(StopBits)))
?????????{
?????????????Console.WriteLine(" {0}", s);
?????????}
??????????Console.Write("Stop Bits({0}):", defaultPortStopBits.ToString());
?????????stopBits =Console.ReadLine();
??????????if(stopBits =="")
?????????{
?????????????stopBits = defaultPortStopBits.ToString();
?????????}
??????????return(StopBits)Enum.Parse(typeof(StopBits), stopBits);
?????}
??????publicstatic Handshake SetPortHandshake(Handshake defaultPortHandshake)
?????{
?????????string handshake;
??????????Console.WriteLine("Available Handshake options:");
?????????foreach(string s inEnum.GetNames(typeof(Handshake)))
?????????{
?????????????Console.WriteLine(" {0}", s);
?????????}
??????????Console.Write("Stop Bits({0}):", defaultPortHandshake.ToString());
?????????handshake =Console.ReadLine();
??????????if(handshake =="")
?????????{
?????????????handshake = defaultPortHandshake.ToString();
?????????}
??????????return(Handshake)Enum.Parse(typeof(Handshake), handshake);
?????}
}
?
總結(jié)
以上是生活随笔為你收集整理的C#中串口通信编程 收藏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 飞鸽传书 再次报道,回到90年代中期的业
- 下一篇: C++常用函数