C#做一個簡單的進行串口通信的上位機

2021-02-14 機器人配視覺

1、上位機與下位機

        上位機相當於一個軟體系統,可以用於接收數據、控制數據。即可以對接收到的數據直接發送操控命令來操作數據。上位機可以接收下位機的信號。下位機是一個控制器,是直接控制設備獲取設備狀況的計算機。上位機發出的命令首先給下位機,下位機再根據此命令解釋成相應時序信號直接控制相應設備。下位機不時讀取設備狀態數據(一般為模擬量),轉換成數位訊號反饋給上位機。上位機不可以單獨使用,而下位機可以單獨使用。

2、串口通信

        串口相當於硬體類型的接口。比如無線傳感節點發送信號到匯聚節點,匯聚節點通過串口將數據傳到計算機中的上位機中,上位機接收信息,並處理。

      串口是按位(bit)發送和接收字節。串口通信最重要的參數是波特率、數據位、停止位和奇偶校驗。對於兩個進行通信的埠,這些參數必須匹配。

    a,波特率:這是一個衡量符號傳輸速率的參數。

    b,數據位:這是衡量通信中實際數據位的參數。

    c,停止位:用於表示單個包的最後一位。典型的值為1,1.5和2位。

    d,奇偶校驗位:在串口通信中一種簡單的檢錯方式。

3、C#代碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Diagnostics;
namespace serial2
{
    public partial class Form1 : Form
    {
        SerialPort s = new SerialPort();    //實例化一個串口對象,在前端控制項中可以直接拖過來,但最好是在後端代碼中寫代碼,這樣複製到其他地方不會出錯。s是一個串口的句柄
        public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;   //防止跨線程訪問出錯,好多地方會用到
            button1.Text = "打開串口";
            int[] item = { 9600,115200};    //定義一個Item數組,遍歷item中每一個變量a,增加到comboBox2的列表中
            foreach (int a in item)
            {
                comboBox2.Items.Add(a.ToString());
            }
           
            comboBox2.SelectedItem = comboBox2.Items[1];    //默認為列表第二個變量
        }
        private void Form1_Load(object sender, EventArgs e)   //窗體事件要先配置埠信息。
        {
            string[] ports = SerialPort.GetPortNames();
            comboBox1.Items.AddRange(ports);
            comboBox1.SelectedItem=comboBox1.Items[0];
            //Array.Sort(ports); 
        }
        private void button1_Click(object sender, EventArgs e)   //下面講解中差不多已經講清楚了
        {
            try
            {
                if (!s.IsOpen)
                {
                    s.PortName = comboBox1.SelectedItem.ToString();
                    s.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString());
                    s.Open();
                    s.DataReceived += s_DataReceived;
                    button1.Text = "關閉串口";
                    //MessageBox.Show("串口已打開");
                }
                else
                {
                    s.Close();
                    s.DataReceived -= s_DataReceived;
                    button1.Text = "打開串口";
                }
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.ToString());
            }
        }
        void s_DataReceived(object sender, SerialDataReceivedEventArgs e)   //數據接收事件,讀到數據的長度賦值給count,如果是8位(節點內部編程規定好的),就申請一個byte類型的buff數組,s句柄來讀數據
        {
            int count =s.BytesToRead;    
            string str=null ;
            if (count == 8)
            {
                byte[] buff = new byte[count];
                s.Read(buff, 0, count);
                foreach (byte item in buff)    //讀取Buff中存的數據,轉換成顯示的十六進位數
                {
                    str += item.ToString("X2")+" ";
                }
                richTextBox1.Text =System.DateTime.Now.ToString()+": "+ str + "\n" + richTextBox1.Text;      //這是跨線程訪問richtextbox,原程序和DataReceived事件是兩個不同的線程同時在執行
                if (buff[0] == 0x04)   //如果節點是04發來的數據
                {
                    ID.Text = buff[0].ToString();   //這下面是上位機右邊那一段,用來顯示處理好的數據的溫度、溼度、光照、灰塵、ID信息的。buff【0】中存的是數據的ID信息,顯示在ID的Label上面
                    switch (buff[2])   //判斷數據類型  buff【0】和buff【1】代表ID的低位和高位,同理2和3代表數據類型的低位和高位,當2和3的值為1時,4和5代表溫度,6和7代表溼度;
     
         {  
                      case 0x01:       //當2和3的值為1,4和5是溫度,6和7是溼度
          {
                                Tem.Text = (buff[5] * 4 + buff[4] * 0.05 - 30).ToString();
                                Hum.Text = (buff[6]  + buff[7]).ToString();
                                break;
                            }
                        case 0x02://6和7是光照
                       {
                                Light.Text = (buff[6] + buff[7]).ToString();
                                break;
                            }
                        case 0x04://6和7是灰塵
                        {
                                Dust.Text = (buff[6] + buff[7]).ToString();
                                break;
                            }
                        default:
                            break;
                    }
                }
            
            }
            
        }
        private void button3_Click(object sender, EventArgs e)   //每次發一個字節
   {
            string[] sendbuff = richTextBox2.Text.Split();  //分割輸入的字符串,判斷有多少個字節需要發送
        Debug.WriteLine("發送字節數:"+sendbuff.Length);
            foreach (string  item in sendbuff)
            {
                int count = 1;
                byte[] buff = new byte[count];
                buff[0] = byte.Parse(item, System.Globalization.NumberStyles.HexNumber);//格式化字符串為十六進位數值
              s.Write(buff, 0, count);
            }
        }
        private void button2_Click(object sender, EventArgs e)//刷新右邊的數值
      {
            int count = 1;
            byte[] buff = new byte[count];
            buff[0] = byte.Parse("04", System.Globalization.NumberStyles.HexNumber);//這裡只顯示04節點的信息
        s.Write(buff, 0, count);
        }
    }
}

 (以上規則均是本實驗室節點內部自定義規則,測試的,外面的相應要改)

4、結果

5、補充四點知識

  1)在程序可能會遇到錯誤的地方,用try+兩個Tab鍵,將代碼寫入try中。比如本例子中的代碼:

 private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (!s.IsOpen)
                {
                    s.PortName = comboBox1.SelectedItem.ToString();
                    s.BaudRate = Convert.ToInt32(comboBox2.SelectedItem.ToString());
                    s.Open();
                    s.DataReceived += s_DataReceived;
                    button1.Text = "關閉串口";
                    //MessageBox.Show("串口已打開");
                }
                else
                {
                    s.Close();
                    s.DataReceived -= s_DataReceived;
                    button1.Text = "打開串口";
                }
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.ToString());
            }
        }

如果代碼沒有寫入try中,則可能出現的一種情況是比如有兩個上位機,同時佔用同一個串口,則就會衝突,會出錯。程序就會終止,整個進程結束。而如果寫入try中,並且把拋出異常的catch代碼實例化,即捕獲異常要實例化一個句柄,這樣程序遇到error就不會終止,而會出現報錯的原因。如下圖,我的這個上位機和網上下載的一個上位機同時佔用COM3串口(網上下載的先佔用COM3),這時我的上位機在打開串口時會出現報錯。

2)就我這個上位機而言,需要有打開串口和關閉串口兩個button按鈕,但是考慮到佔地方,當然最重要的還是如果用兩個按鈕來表示,當你按下打開串口,如果忘了是否打開,則是看不出來是不是打開的,所以可以合併為一個button控制項。(代碼還是用上面那一段的代碼)。(感覺很神奇啊)。在button1_Click事件中,先點擊button,如果串口是關閉的,則打開串口,然後把button1.Text的值賦值為「關閉串口」,如果串口本來是關閉的,則點擊按鈕會把button1.Text的值賦值為「打開串口」,同時把接收的數據清空。

3)當輸入一個變量或方法什麼的,它所有有的會自動出現在一個列表,這時,「正方體」代表「方法」,「小鉗子」代表「變量」,「閃電」代表「事件」。

4) 產生對象的事件時

比如輸入s.自動會出現DataReceived事件,再輸入「+=」就會有如上圖提示,按Tab鍵。然後又會如下圖提示

再次按tab鍵,就會自動生成DataReceived事件處理函數。

文章來源:綜合網絡,如有侵權,聯繫刪除。

相關焦點

  • 曲線繪製還在用串口助手?來用Qt寫一個!
    上次我們基於小熊派光強傳感器項目實現了光強讀取並在LCD上顯示,文章連結如下:基於小熊派光強傳感器BH1750狀態機驅動項目升級(帶LCD屏顯示)這一節,我們再次對這個項目升級下,配個帶可縮放曲線的上位機讀取光強進行顯示吧
  • 【花式玩轉小熊派 】 上位機顯示光強變化曲線
    上次我們基於小熊派光強傳感器項目實現了光強讀取並在LCD上顯示,文章連結如下:基於小熊派光強傳感器BH1750狀態機驅動項目升級(帶LCD屏顯示)這一節,我們再次對這個項目升級下,配個帶可縮放曲線的上位機讀取光強進行顯示吧
  • 條碼器除了USB還有哪些常用的通信方式(接口類型)?
    有線條碼器通常使用一條線材連接條碼器和上位機設備進行數據通信,根據通信協議的不同,通常可以分為:USB接口,串口接口,鍵盤口接口以及其他類型接口。而無線條碼器也可以根據無線傳輸協議分為下面幾類:無線2.4G,無線藍牙,無線433,無線zegbee,無線WiFi。
  • 8051單片機串口通信中的檢錯方法
    1 檢錯方式基於8051的串口數據通信系統的硬體開發平臺框圖如圖1所示。利用該平臺進行數據傳輸時,通常有三種數據檢錯方式。在發送端和接收端同時檢測奇偶位,若得到相同的結果,則說明數據傳輸過程無錯誤發生;若得到不同的結果,則說明數據傳輸過程中有錯誤發生,此時8051會發送一個錯誤重傳的信號,讓PC端再次發送數據。1.2 循環冗餘校驗(CRC)CRC是利用除法和餘數的原理來進行錯誤檢測(Error Detecting)。
  • 大牛分享 | 動手做一個物聯網大棚智能管理系統(免費領取開發板)
    LM393是一個比較器,通過R1設置一個標準值,當溼度大時,OUT端輸出低電平,相反輸出高電平。OUT信號可以直接用來粗略估算溼度大小,具體電路如圖6所示。1.6 Wi-Fi無線通信模塊無線通信模塊採用esp8266串口無線AP+STA」(COM-AP+STA)模式,既可以被其他的Wi-Fi設備連接,又可以連接到其他的無線網絡,實現串口與其他設備之間的無線數據互傳[6],具有低功耗、高集成度、超寬的工作溫度的優點。
  • RS232,RS485,RS422 接口的區別 串口通信基礎知識 JMDM系列串口控制器組網引線示意圖 附圖
    一、RS232通訊的基礎知識: RS232通訊又叫串口通訊方式。是指計算機通過RS232國際標準協議用串口連接線和單臺設備(控制器)進行通訊的方式。 通訊距離:9600波特率下建議在13米以內。【備註】:一般臺式機會自帶1-2個串口插座(公頭 (9針插頭上帶針的俗稱公頭,帶針孔的俗稱母頭)),現在的筆記本一般不帶串口插座,可以購買 USB串口轉換器,具體請參考 怎樣使用USB串口轉換器? 公頭 接線端子排序圖 母頭 接線端子排序圖 一般只用 2 3 5 號三根線。
  • STM32 串口詳解
    USART是通用異步收發傳輸器(UniversalAsynchronousReceiver/Transmitter),通常稱作UART,是一種異步收發傳輸器,是設備間進行異步通信的關鍵模塊。UART負責處理數據總線和串行口之間的串/並、並/串轉換,並規定了幀格式;通信雙方只要採用相同的幀格式和波特率,就能在未共享時鐘信號的情況下,僅用兩根信號線(Rx和Tx)就可以完成通信過程,因此也稱為異步串行通信。通信結構2.1、數據傳輸模型
  • Arduino入門15: 串口監視器的使用
    不要小看串口監視器,用好了,它就是幫你解決大多數煩惱的Swiss Army Knife(瑞士軍刀)。Arduino和電腦是通過串口連接的,所有的數據通信都通過這個通道,所以串口監視器就像是這個通道上安裝的安全攝像頭一樣。然你可以查看通信數據。Arduino IDE沒有像其它高級IDE提供比較全面的debug工具,所以合理利用好串口監視器是Arduino代碼debug的主要途徑。
  • 乾貨 | STM32串口波特率大小計算
    在STM32中,有個波特率寄存器USART_BRR,如下:STM32串口波特率通過USART_BRR進行設置,STM32的波特率寄存器支持分數設置,以提高精確度。USART_BRR的前4位用於表示小數,後12位用於表示整數。但是它還不是我們想要設置的波特率,想要設置我們串口的波特率大小還需要進行計算。其實有關波特率的計算是下面這一條表達式:
  • 串口下載與調試、STC-ISP軟體使用詳解
    硬體準備STC系列單片機使用STC-ISP軟體進行下載, 在進行下載之前需要用線連接單片機的UART0 (P3.0 P3.1)和運行STC-ISP程序的PC機的串口。根據單片機系統的電平轉換情況和PC機的接口類型有多種硬體連接情況。
  • 串口通訊作業概述
    串口通訊的概念極為簡單。串行埠將同時傳送並接收 1 個位 (Bit) 的信息字節 (Byte)。雖然此傳輸量低於並行通訊作業,卻可傳輸完整的字節;適用於較長距離的通訊作業。以 IEEE 488 規格的平行通訊作業為例,設備之間的接線總長度不得超過 20米(65英尺);任兩組裝置之間的長度不超過 2米(6.5英尺)。而串口卻可達最長 1200米(4000英尺)。
  • 機載大屏幕顯示器高速通信系統設計
    接口支持x1和x4模式,通信帶寬分別可達3.125 Gb/s和12.5 Gb/s。本文提出一種基於MPC8548E的機載顯示器通信系統,使用MPC8548E內部集成的PCIE和RapidIO總線接口,分別通過相應的交換機進行多埠擴展,實現顯示器外部數據高速通信和內部模塊間高速組網互聯,可以滿足大屏幕一體化顯示器高實時性通信的需求。
  • 無人艇遠距離通信技術
    OFDM是一種特殊的多載波調製技術,傳輸的信息通過串並轉換,在多個子信道上傳輸,不像傳統的調製在一個時刻只能傳輸一個頻率的信號,OFDM可以在正交的頻率上同時傳送多路信號,能夠充分的利用信道的帶寬。在OFDM系統中,每個傳輸符號速率的大小大約在幾十bit/s到幾十bit/s之間,必須進行串並轉換,將輸入的串行比特流轉換成可以傳輸的OFDM符號。
  • C# OfType(IEnumerable)的使用
    OfType關鍵字主要用在非泛型到泛型之間的轉化,在有些場合還是很有用的;比如:在使用非泛型的時候,想使用LINQ表達式進行結果查詢.
  • 上位機儀錶盤實時顯示機器人速度
    後臺留言,大家一起支持原創,推動機器人使用和發展本公眾號對各類ABB機器人應用,仿真,畢業設計提供技術支持,詳細後臺留言本公眾號誠摯希望與各機器人培訓機構,機器人使用單元合作,提供技術支持,詳細後臺留言點擊文章最後的閱讀原文,即可獲得完整上位機儀錶盤實時顯示機器人速度