最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#中SerialPort的使用教程詳解

 更新時(shí)間:2023年12月11日 10:21:25   作者:記憶留櫻  
SerilPort是串口進(jìn)行數(shù)據(jù)通信的一個(gè)控件,這篇文章主要為大家詳細(xì)介紹了C#中SerialPort的使用,具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

最近在學(xué)習(xí)C#的SerialPort ,關(guān)于SerialPort 的使用,做如下總結(jié):

1.可以通過函數(shù)System.IO.Ports.SerialPort.GetPortNames() 將獲得系統(tǒng)所有的串口名稱。C#代碼如下:

string[] sPorts = SerialPort.GetPortNames();
foreach(string port in sPorts)
{
   var serialPort = new SerialPort();
   serialPort.PortName =  port;
   serialPort.Open();
   serialPort.WriteLine("ATI"); // this will ask the port to issue an ident string which you can match against 
}

2.列出所有的串口:

private void comboBox1_Click(object sender, EventArgs e)
        {
            string[] portNamesArray = SerialPort.GetPortNames();
            this.comboBox1.Items.Clear();
            foreach (var item in portNamesArray)
            {
                this.comboBox1.Items.Add(item);
            }
            this.comboBox1.Items.Add("");

        }



        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            selectedPortName = this.comboBox1.SelectedItem.ToString();//獲取選中的port

        }

3. 打開/關(guān)閉串口:

SerialPort port = new SerialPort();
            port.BaudRate = 1200;//波特率
            port.PortName = "COM1";
            port.Parity = Parity.None;//校驗(yàn)法:無
            port.DataBits = 8;//數(shù)據(jù)位:8
            port.StopBits = StopBits.One;//停止位:1
            try
            {
                port.Open();//打開串口
                port.DtrEnable = true;//設(shè)置DTR為高電平
                port.RtsEnable = true;//設(shè)置RTS位高電平

            }
            catch (Exception ex)
            {
                //打開串口出錯(cuò),顯示錯(cuò)誤信息
                MessageBox.Show(ex.Message);
            }

            if (port.IsOpen)
            {
                port.Close();//關(guān)閉串口
            }

4.寫數(shù)據(jù):

函數(shù)說明
void Write(byte[] buffer, int offset, int count);
void Write(char[] buffer, int offset, int count);
寫二進(jìn)制數(shù)據(jù)
void Write(string text);寫文本數(shù)據(jù)
void WriteLine(string text); 寫一行數(shù)據(jù)

(1)寫二進(jìn)制數(shù)據(jù):

void Write(byte[] buffer, int offset, int count);和void Write(char[] buffer, int offset, int count);用于寫二進(jìn)制數(shù)據(jù)。它們的區(qū)別僅僅在于第一個(gè)參數(shù)不同:byte[]是無符號的,char[]是有符號的。對于二進(jìn)制數(shù)據(jù)而言,byte、char沒有實(shí)質(zhì)的區(qū)別。

下面的C#代碼,將寫1024個(gè)00H:

if (port.IsOpen)
            {
                byte[] bt = new byte[1024];
                port.Write(bt, 0, bt.Length);//寫1024個(gè)00H                
            }

注意:

1、Write函數(shù)是同步的。以上面的代碼為例,1024個(gè)00H在發(fā)送完之前,Write函數(shù)是不會返回的。波特率1200,發(fā)送1024個(gè)字節(jié)大概要耗時(shí)9秒。如果這段代碼在主線程里,那么這9秒內(nèi)整個(gè)程序?qū)⑻幱诩偎罓顟B(tài):無法響應(yīng)用戶的鍵盤、鼠標(biāo)輸入;

2、WriteTimeout屬性用于控制Write函數(shù)的最長耗時(shí)。它的默認(rèn)值為System.IO.Ports.SerialPort.InfiniteTimeout,也就是-1。其含義為:Write函數(shù)不將所有數(shù)據(jù)寫完絕不返回??梢孕薷拇藢傩?,如下面的代碼:

if (port.IsOpen)
            {
                byte[] bt = new byte[1024];
                port.WriteTimeout = 5000;//Write 函數(shù)最多耗時(shí) 5秒
                port.Write(bt, 0, bt.Length);//寫1024個(gè)00H                
            }

上面的代碼中,設(shè)置WriteTimeout屬性為5秒。所以Write寫數(shù)據(jù)時(shí)最多耗時(shí)5秒,超過這個(gè)時(shí)間未發(fā)的數(shù)據(jù)將被舍棄,Write函數(shù)拋出異常TimeoutException后立即返回。

(2)寫文本數(shù)據(jù)

void Write(string text)的示例:

if (port.IsOpen)
            {
                port.Encoding = System.Text.Encoding.GetEncoding(936);
                port.Write("串行通訊");
            }

首先設(shè)置代碼頁為936(即GBK碼),Write(string text)函數(shù)根據(jù)代碼頁把字符串"串行通訊"轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),如下所示:

字符串
內(nèi)碼B4 AED0 D0CD A8D1 B6

然后把二進(jìn)制數(shù)據(jù)B4 AE D0 D0 CD A8 D1 B6發(fā)送出去。

函數(shù)void WriteLine(string text);等價(jià)于void Write(text + NewLine)。參考下面的代碼:

if (port.IsOpen)
            {
                port.Encoding = System.Text.Encoding.GetEncoding(936);
                port.NewLine = "\r\n";
                port.WriteLine("串行通訊");
            }

代碼port.NewLine = "\r\n";設(shè)置行結(jié)束符為回車(0DH)換行(0AH)。port.WriteLine("串行通訊");等價(jià)于port.Write("串行通訊"+port.NewLine);也就是port.Write("串行通訊\r\n");

最終,發(fā)送出去的二進(jìn)制數(shù)據(jù)為B4 AE D0 D0 CD A8 D1 B6 0D 0A。

5.讀數(shù)據(jù):

System.IO.Ports.SerialPort用于讀串口數(shù)據(jù)的成員函數(shù)有七個(gè),如下所示:

函數(shù)說明
int ReadByte();讀取一個(gè)字節(jié)
int ReadChar(); 讀取一個(gè)字符
int Read(byte[] buffer, int offset, int count);
int Read(char[] buffer, int offset, int count);
讀取二進(jìn)制數(shù)據(jù)
string ReadExisting();讀取全部文本
string ReadTo(string value); 讀取文本到某個(gè)字符串
string ReadLine(); 讀取一行文本

(1)讀二級制

讀取 3 個(gè)字節(jié)的串口數(shù)據(jù):

try
                {
                    byte[] b = new byte[3];
                    int n = port.Read(b, 0, 3); //返回值是讀取到的字節(jié)數(shù)
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }

注意:

1、Read函數(shù)是同步的。以上面的代碼為例,3個(gè)字節(jié)的數(shù)據(jù)被讀取之前,Read函數(shù)是不會返回的。如果這段代碼在主線程里,那么整個(gè)程序?qū)⑻幱诩偎罓顟B(tài);

2、ReadTimeout屬性用于控制Read函數(shù)的最長耗時(shí)。它的默認(rèn)值為System.IO.Ports.SerialPort.InfiniteTimeout,也就是-1。其含義為:Read函數(shù)未讀取到串口數(shù)據(jù)之前是不會返回的??梢孕薷拇藢傩?,如下面的代碼:

byte[] b = new byte[3];
                    port.ReadTimeout = 2000;
                    int n = port.Read(b, 0, 3); //返回值是讀取到的字節(jié)數(shù)

上面的代碼中,設(shè)置ReadTimeout屬性為2秒。所以Read函數(shù)讀數(shù)據(jù)時(shí)最多耗時(shí)2秒。超過這個(gè)時(shí)間未讀取到數(shù)據(jù),Read函數(shù)將拋出異常TimeoutException,然后返回。

(2) 讀一個(gè)字節(jié)

int ReadByte();與int Read(byte[] buffer, int offset, int count);類似,它的特點(diǎn)就是只讀取一個(gè)字節(jié)的串口數(shù)據(jù)。

(3) 讀一個(gè)字符

int ReadChar();是讀取一個(gè)字符,這個(gè)稍微復(fù)雜些。它可能讀取1~3個(gè)字節(jié)的數(shù)據(jù),然后合為一個(gè)字符。

如:port.Encoding = System.Text.Encoding.GetEncoding(936);即字符串編碼為GBK。給port發(fā)送"串"的GBK編碼B4 AE。ReadChar首先讀取一個(gè)字節(jié)得到B4H。這是一個(gè)漢字的區(qū)碼,還得讀取一個(gè)字節(jié)得到位碼。最終ReadChar讀取的是B4 AE。ReadChar的返回值是Unicode編碼,即返回前會把GBK編碼B4 AE轉(zhuǎn)換為Unicode編碼0x4E32。

再如:port.Encoding = System.Text.Encoding.UTF8;即字符串編碼為UTF8。給port發(fā)送"串"的UTF8編碼E4 B8 B2。ReadChar會讀取三個(gè)字節(jié)的串口數(shù)據(jù)E4 B8 B2,然后將其轉(zhuǎn)換為Unicode編碼0x4E32,并返回這個(gè)數(shù)值。

(4) 讀全部文本

函數(shù)string ReadExisting();讀取串口輸入緩沖區(qū)中的所有二進(jìn)制數(shù)據(jù),然后將其轉(zhuǎn)換為字符串,最后返回字符串。

注意:

1、ReadExisting會立即返回。如果輸入緩沖區(qū)內(nèi)沒有數(shù)據(jù),直接返回長度為零的空字符串;

2、ReadExisting讀取輸入緩沖區(qū)后,有時(shí)會留幾個(gè)字節(jié)。參考下面的代碼:

port.Encoding = System.Text.Encoding.GetEncoding(936);
                    string s = port.ReadExisting();
                    int nn = port.BytesToRead; //輸入緩沖區(qū)剩余的字節(jié)數(shù)

"串"、"行"的GBK編碼分別為 B4 AE和D0 D0。

首先發(fā)送 B4 AE D0 給port,運(yùn)行上述代碼。ReadExisting將獲得B4 AE D0,"B4 AE"會被解釋為"串",D0是漢字的區(qū)碼,所以ReadExisting會將D0保留在輸入緩沖區(qū)內(nèi)。上述代碼的運(yùn)行結(jié)果就是:s為"串",n為1;

然后發(fā)送D0 給port,運(yùn)行上述代碼。ReadExisting將獲得D0 D0,"D0 D0"會被解釋為"行"。上述代碼的運(yùn)行結(jié)果就是:s為"行",n為0。

(5) 讀文本到某個(gè)字符串

函數(shù)string ReadTo(string value);將在串口輸入緩沖區(qū)內(nèi)查找字符串value。找到了,就返回value之前的字符串,同時(shí)清除緩沖區(qū)內(nèi)value及其之前的數(shù)據(jù);未找到,就一直等待,直至超時(shí)。

(6) 讀一行文本

函數(shù)string ReadLine();等價(jià)于ReadTo(NewLine)。使用前,請?jiān)O(shè)置NewLine屬性,指定行結(jié)束符。

(7) DataReceived事件

串口輸入緩沖區(qū)獲得新數(shù)據(jù)后,會以DataReceived事件通知System.IO.Ports.SerialPort對象,可以在此時(shí)讀取串口數(shù)據(jù)。請參考下面兩段代碼:

port.ReceivedBytesThreshold = 1;
                    port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived);
void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            int nRead = port.BytesToRead;
            if (nRead > 0)
            {
                byte[] data = new byte[nRead];
                port.Read(data, 0, nRead);
            }
        }

port.ReceivedBytesThreshold = 1;的含義:串口輸入緩沖區(qū)獲得新數(shù)據(jù)后,將檢查緩沖區(qū)內(nèi)已有的字節(jié)數(shù),大于等于ReceivedBytesThreshold就會觸發(fā)DataReceived事件。這里設(shè)置為1,顯然就是一旦獲得新數(shù)據(jù)后,立即觸發(fā)DataReceived事件。

port.DataReceived+=new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived);的含義:對于DataReceived事件,用函數(shù)port_DataReceived進(jìn)行處理。

回調(diào)函數(shù)port_DataReceived用于響應(yīng)DataReceived事件,通常在這個(gè)函數(shù)里讀取串口數(shù)據(jù)。它的第一個(gè)參數(shù)sender就是事件的發(fā)起者。上面的代碼中,sender其實(shí)就是port。也就是說:多個(gè)串口對象可以共用一個(gè)回調(diào)函數(shù),通過sender可以區(qū)分是哪個(gè)串口對象。

回調(diào)函數(shù)是被一個(gè)多線程調(diào)用的,它不在主線程內(nèi)。所以,不要在這個(gè)回調(diào)函數(shù)里直接訪問界面控件。如下面的代碼將將讀取到的串口數(shù)據(jù)轉(zhuǎn)換為字符串,然后顯示在按鈕Open上。紅色代碼處將產(chǎn)生異常。

void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            int nRead = port.BytesToRead;
            if (nRead > 0)
            {
                byte[] data = new byte[nRead];
                port.Read(data, 0, nRead);
                btnOpen.Text = System.Text.Encoding.Default.GetString(data);
            }
        }

可使用Invoke或BeginInvoke改進(jìn)上面的紅色代碼:

this.Invoke(new MethodInvoker(() =>
                {
                    btnOpen.Text = System.Text.Encoding.Default.GetString(data);
                }));
BeginInvoke(new Action<string>((x) => { btnOpen.Text = x; }), new Object[] { System.Text.Encoding.Default.GetString(data) });

6.流控制

串行通訊的雙方,如果有一方反應(yīng)較慢,另一方不管不顧的不停發(fā)送數(shù)據(jù),就可能造成數(shù)據(jù)丟失。為了防止這種情況發(fā)生,需要使用流控制。

流控制也叫握手,System.IO.Ports.SerialPort的Handshake屬性用于設(shè)置流控制。它有四種取值:

取值說明
System.IO.Ports.Handshake.None
System.IO.Ports.Handshake.XOnXOff軟件
System.IO.Ports.Handshake.RequestToSend硬件
System.IO.Ports.Handshake.RequestToSendXOnXOff硬件和軟件

(1) 軟件流控制(XON/XOFF)

串口設(shè)備A給串口設(shè)備B發(fā)送數(shù)據(jù)。B忙不過來時(shí)(B的串口輸入緩沖區(qū)快滿了)會給A發(fā)送字符XOFF(一般為13H),A將暫停發(fā)送數(shù)據(jù);B的串口輸入緩沖區(qū)快空時(shí),會給A發(fā)送字符XON(一般為11H),A將繼續(xù)發(fā)送數(shù)據(jù)。

軟件流控制最大的問題在于:通訊雙方不能傳輸字符XON和XOFF。

(2)硬件流控制(RTS/CTS)

RTS/CTS流控制是硬件流控制的一種,需要按下圖連線:

串口設(shè)備A給串口設(shè)備B發(fā)送數(shù)據(jù)。B忙不過來時(shí)(B的串口輸入緩沖區(qū)快滿了)會設(shè)置自己的RTS為低電平,這樣A的CTS也變?yōu)榈碗娖?。A發(fā)現(xiàn)自己的CTS為低電平后,會停止發(fā)送數(shù)據(jù);B的串口輸入緩沖區(qū)快空時(shí),會設(shè)置自己的RTS為高電平,這樣A的CTS也變?yōu)楦唠娖健發(fā)現(xiàn)自己的CTS為高電平后,會繼續(xù)發(fā)送數(shù)據(jù)。

相同的道理,DTR/DSR也可以做硬件流控制。

以上就是C#中SerialPort的使用教程詳解的詳細(xì)內(nèi)容,更多關(guān)于C# SerialPort的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#基礎(chǔ)之異步調(diào)用實(shí)例教程

    C#基礎(chǔ)之異步調(diào)用實(shí)例教程

    這篇文章主要介紹了C#中的異步調(diào)用,對比同步調(diào)用分析了異步調(diào)用的原理及特點(diǎn),并以實(shí)例形式給出了實(shí)現(xiàn)方法,需要的朋友可以參考下
    2014-09-09
  • ZooKeeper 實(shí)現(xiàn)分布式鎖的方法示例

    ZooKeeper 實(shí)現(xiàn)分布式鎖的方法示例

    這篇文章主要介紹了ZooKeeper 實(shí)現(xiàn)分布式鎖的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-06-06
  • C# StreamReader類實(shí)現(xiàn)讀取文件的方法

    C# StreamReader類實(shí)現(xiàn)讀取文件的方法

    這篇文章主要介紹了C# StreamReader類實(shí)現(xiàn)讀取文件的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • C#中Attribute特性的用法

    C#中Attribute特性的用法

    這篇文章介紹了C#中Attribute特性的用法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • C#獲取U盤序列號的方法

    C#獲取U盤序列號的方法

    這篇文章主要介紹了C#獲取U盤序列號的方法,涉及C#針對硬件底層信息操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • 輕松學(xué)習(xí)C#的foreach迭代語句

    輕松學(xué)習(xí)C#的foreach迭代語句

    輕松學(xué)習(xí)C#的foreach迭代語句,  C#語言提供了一個(gè)for語句循環(huán)的捷徑,而且還促進(jìn)了集合類的更為一致,就是本文提到的foreach語句,感興趣的小伙伴們可以參考一下
    2015-11-11
  • C#模擬MSN窗體抖動的實(shí)現(xiàn)代碼

    C#模擬MSN窗體抖動的實(shí)現(xiàn)代碼

    這篇文章主要介紹了C#模擬MSN窗體抖動的實(shí)現(xiàn)代碼,非常實(shí)用的一個(gè)功能,需要的朋友可以參考下
    2014-08-08
  • 詳解如何使用C#獲取計(jì)算機(jī)信息

    詳解如何使用C#獲取計(jì)算機(jī)信息

    這篇文章主要為大家詳細(xì)介紹了如何使用C#實(shí)現(xiàn)獲取計(jì)算機(jī)信息,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下
    2024-10-10
  • C#實(shí)現(xiàn)谷歌翻譯API示例代碼

    C#實(shí)現(xiàn)谷歌翻譯API示例代碼

    本篇文章主要介紹了C#實(shí)現(xiàn)谷歌翻譯API示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • C#中多線程使用CancellationTokenSource進(jìn)行線程管理

    C#中多線程使用CancellationTokenSource進(jìn)行線程管理

    本文主要介紹了C#中多線程使用CancellationTokenSource進(jìn)行線程管理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-09-09

最新評論

新河县| 胶州市| 灵台县| 瓮安县| 兰西县| 南江县| 通江县| 延寿县| 大名县| 泽库县| 海林市| 枝江市| 扎兰屯市| 德令哈市| 勃利县| 开平市| 云南省| 南昌县| 桐柏县| 侯马市| 鹤岗市| 新建县| 佛山市| 小金县| 乡城县| 绿春县| 西畴县| 秦皇岛市| 松江区| 吴江市| 苍南县| 启东市| 营口市| 随州市| 漳浦县| 榆树市| 平山县| 淳化县| 兴业县| 桓台县| 廊坊市|