C# 編程實現串口通信


http://blog.sina.com.cn/s/blog_6c67dab30101p3vn.html

-------------------------------------------------------------------------------

public partial class Form1 : Form
    {
        int k = 0;
        int[] crc_data1 = { 0, 0 };
        int[] crc_data2 = { 0, 0, 0, 0, 0 };
        int[] crc_data3 = { 0, 0, 0, 0, 0 };
        int x = 0;
        short qtemp;
        byte[] new_byte1 = { 0, 0, 0, 0, 0, 0, 0 };
        SolidBrush bush1 = new SolidBrush(Color.Red);
        SolidBrush bush2 = new SolidBrush(Color.Green);
        public Form1()
        {
            InitializeComponent();
        }

        //串口初始化
        private void Form1_Load(object sender, EventArgs e)
        {
            serialPort1.PortName = "COM3";
            serialPort1.BaudRate = 9600;
            serialPort1.DataBits = 8;
            serialPort1.StopBits = System.IO.Ports.StopBits.One;
            serialPort1.Parity = System.IO.Ports.Parity.None;
            serialPort1.Open();
        }
 
        //向水浸傳感器發送讀指令
        private void timer1_Tick(object sender, EventArgs e)
        {
            byte[] boutdata1 = { 0x01, 0x04, 0x01, 0xE3 };
            serialPort1.Write(boutdata1, 0, 4);
        }

        //觸發事件,讀取溫度傳感器返回數據
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            System.Threading.Thread.Sleep(100);
            int byte_num1 = serialPort1.Read(new_byte1, 0, 7);
            this.Invoke(new EventHandler(DisplayText));
        }

        private void DisplayText(object sender, EventArgs e)
        {
            if (new_byte1[0] == 1) //水浸傳感器
            {
                for (int i = 0; i < 2; i++)
                    crc_data1[i] = (int)new_byte1[i];
                int[] crc1 = crc16(crc_data1);
                if (crc1[0] == new_byte1[2] && crc1[1] == new_byte1[3]) //校驗CRC
                     alarm1(); //顯示,紅燈報警,綠燈正常
                else
                    MessageBox.Show("校驗碼錯誤,數據無效!", "");
                byte[] boutdata2 = { 0x02, 0x03, 0x00, 0x01, 0x00, 0x01, 0xD5, 0xF9 }; //發送溫度傳感器數據
                serialPort1.Write(boutdata2, 0, 8);
            }
            if (new_byte1[0] == 2 && new_byte1[1] == 3) //溫度傳感器
            {
                for (int i = 0; i < 5; i++)
                    crc_data2[i] = (int)new_byte1[i];
                int[] crc2 = crc16(crc_data2);
                if (crc2[0] == new_byte1[5] && crc2[1] == new_byte1[6])
                    DisplayText2(); //顯示溫度並畫出溫度曲線
                else
                    MessageBox.Show("校驗碼錯誤,數據無效!", "");
                byte[] boutdata3 = { 0x50, 0x03, 0x00, 0x03, 0x00, 0x01, 0x79, 0x8B }; //發送煙感傳感器數據
                serialPort1.Write(boutdata3, 0, 8);
            }
            if (new_byte1[0] == 80 && new_byte1[1] == 3) //煙感傳感器
            {
                for (int i = 0; i < 5; i++)
                    crc_data3[i] = (int)new_byte1[i];
                int[] crc3 = crc16(crc_data3);
                if (crc3[0] == new_byte1[5] && crc3[1] == new_byte1[6])
                    alarm3(); //顯示,紅燈報警,綠燈正常
                else
                    MessageBox.Show("校驗碼錯誤,數據無效!", "");
            }
        }

        //關閉串口,退出程序
        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            Close();
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (serialPort1.IsOpen) serialPort1.Close();
        }  
    }

 

-----------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

其實這是很簡單的工作,只是我初次接觸而已,做做筆記,方便以后使用時調用~

 
本來的背景是之前的B/S架構的網站,基於ASP.NET做的,但怎么都查不到直接用asp.net做串口通信,有的方法又太高級,我一時半會兒也學不會,所以還是轉戰最容易的serialPort控件了。
 
進行串口通訊時,需要設置一些相關參數,可以通過設置SerialPort 類的屬性來進行。串口屬性主要包括:
.PortName 串口名稱,COM1, COM2等。
.BaudRate 波特率,也就是串口通訊的速度,進行串口通訊的雙方其波特率需要相同,如果用PC連接其他非PC系統,一般地,波特率由非PC系統決定。
.Parity 奇偶校驗。可以選取枚舉Parity中的值
.DataBits 數據位
.StopBits 停止位,可以選取枚舉StopBits中的值
.Handshake 握手方式,也就是數據流控制方式,可以選取枚舉Handshake中的值。
這些可以賦值,也可以由窗口設置確定~
 
同一台電腦做測試時,可以使用VSPD軟件進行虛擬串口,很好用哦!!
 
設置打開串口:
private void Com_Start_Click(object sender, EventArgs e)
        {
            serialPort1.Open();
            if (serialPort1.IsOpen)
                portstate.Text = "串口已經成功打開!";
            else
                portstate.Text = "串口打開失敗!";
        }
引用:
在創建一個SerialPort 對象,設置串口屬性后,可以通過 Open()方法打開串口。數據讀寫完成后,可以通過Close()方法關閉串口。根據經驗,對於有些系統,在打開串口后,還需要將RtsEnable設置為True,這樣才能讀寫數據,否則不能正常讀寫數據。
 
 
設置關閉串口:
 private void Com_Stop_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            portstate.Text = "串口已經關閉!";
        }
數據接收:
先選擇控件,然后在 事件 中,選datareceived,於是就定義了一個函數,在函數中添加:
 string datareceive = serialPort1.ReadLine();
           Recive_Text.Invoke(new MethodInvoker(delegate
          {
              try
              {
                  Recive_Text.Text = datareceive;
              }
              catch (Exception ex)
              {
                  //MessageBox.Show(ex.ToString(), "1", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
              }
 
          }));
 
z注意: readline() 是一直讀取到輸入緩沖區中的 NewLine 值,即輸入需要換行才響應。
其它的相關函數是:

Close

關閉端口連接,將 IsOpen 屬性設置為False,並釋放內部 Stream 對象

Open

打開一個新的串行端口連接

Read

從 SerialPort 輸入緩沖區中讀取數據字節數

ReadByte

從 SerialPort 輸入緩沖區中同步讀取一個字節

ReadChar

從 SerialPort 輸入緩沖區中同步讀取一個字符

ReadLine

一直讀取到輸入緩沖區中的 NewLine 值

ReadTo

一直讀取到輸入緩沖區中指定 value 的字符串

Write

已重載。將數據寫入串行端口輸出緩沖區

WriteLine

將指定的字符串和 NewLine 值寫入輸出緩沖區

DiscardInBuffer

DiscardOutBuffer

清空接收緩沖區數據

清空輸出緩沖去數據

還有一些屬性說明:

屬性說明

名  稱

說  明

BaseStream

獲取 SerialPort 對象的基礎 Stream 對象

BaudRate

獲取或設置串行波特率

BreakState

獲取或設置中斷信號狀態

BytesToRead

獲取接收緩沖區中數據的字節數

BytesToWrite

獲取發送緩沖區中數據的字節數

CDHolding

獲取端口的載波檢測行的狀態

CtsHolding

獲取“可以發送”行的狀態

DataBits

獲取或設置每個字節的標准數據位長度

DiscardNull

獲取或設置一個值,該值指示 Null 字節在端口和接收緩沖區之間傳輸時是否被忽略

DsrHolding

獲取數據設置就緒 (DSR) 信號的狀態

DtrEnable

獲取或設置一個值,該值在串行通信過程中啟用數據終端就緒 (DTR) 信號

Encoding

獲取或設置傳輸前后文本轉換的字節編碼

Handshake

獲取或設置串行端口數據傳輸的握手協議

IsOpen

獲取一個值,該值指示 SerialPort 對象的打開或關閉狀態

NewLine

獲取或設置用於解釋 ReadLine( )和WriteLine( )方法調用結束的值

Parity

獲取或設置奇偶校驗檢查協議

ParityReplace

獲取或設置一個字節,該字節在發生奇偶校驗錯誤時替換數據流中的無效字節

PortName

獲取或設置通信端口,包括但不限於所有可用的 COM 端口

ReadBufferSize

獲取或設置 SerialPort 輸入緩沖區的大小

ReadTimeout

獲取或設置讀取操作未完成時發生超時之前的毫秒數

ReceivedBytesThreshold

獲取或設置 DataReceived 事件發生前內部輸入緩沖區中的字節數

RtsEnable

獲取或設置一個值,該值指示在串行通信中是否啟用請求發送 (RTS) 信號

StopBits

獲取或設置每個字節的標准停止位數

WriteBufferSize

獲取或設置串行端口輸出緩沖區的大小

WriteTimeout

獲取或設置寫入操作未完成時發生超時之前的毫秒數

 
 
 
讀寫行數據

雙方通訊時,一般都需要定義通訊協議,即使最簡單的通過串口發送文本聊天的程序。

通常是在當一方按下回車時,將其所數據的文本連同換行符發給另一方。在這個通訊事例中,協議楨是通過換行符界定的,每一楨數據都被換行符隔開,這樣就很容易識別出通訊雙發發送的信息。

在以上的例子中,可以用WriteLine()來發送數據,用ReadLine()來讀取數據。WriteLine發送完數據后,會將換行符作為數據也發送給對方。ReadLine()讀取數據時,直至遇到一個換行符,然后返回一個字符串代表一行信息。換行符可以通過SerialPort 的屬性NewLine來設置。一般地,Windows將CrLn作為換行符,而在Linux下,換行符則只用一個Ln表示。

ReadLine()方法是阻塞的,直至遇到一個換行符后返回。在讀取數據時,如果一直沒有遇到換行符,那么在等待ReadTimeout時間后,拋出一個TimeoutException。默認情況下,ReadTimeout為InfiniteTimeout。這樣,ReadLine一直處於阻塞狀態,直至有新一行數據到達。

WriteLine()方法也是阻塞的,如果另一方不能及時接收數據,就會引起TimeoutException異常。

由於ReadLine()和WriteLine()方法都是阻塞式的,在程序使用SerialPort 進行串口通訊時,一般應該把讀寫操作交由其他線程處理,避免因為阻塞而導致程序不響應。

讀寫字節或字符數據

對於字節或字符數據,用Read()方法來讀數據,該方法需要一個字節或字符數組作為參數來保存讀取的數據,結果返回實際讀取的字節或字符數。寫數據使用Write()方法,該方法可以將字節數組、字符數據或字符串發送給另一方。

如果通訊雙方交換的數據位字節流數據,要構建一個使用的串口通訊程序,那么雙方應該定義數據楨格式。通常數據楨由楨頭和楨尾來界定。

發送數據比較簡單,只需要將構造好的數據用Write()方法發送出去即可。

接收數據則比較復雜,通訊是以字節流的形式到達的,通過調用一次Read()方法並不能確保所讀取的數據就是完整一楨。因此需要將每次讀取的數據整合在一起,對整合后的數據進行分析,按照定義的楨格式,通過楨頭和楨尾,將楨信息從字節流中抽取出來,這樣才能獲取有意義的信息。

除了利用Read()方法來讀數據,還可以使用ReadExisting()方法來讀取數據。該方法讀取當前所能讀到的數據,以字符串的形式返回。


免責聲明!

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



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