c#串口調試助手溫度曲線的顯示-上位機的開發-串口參數介紹

c#串口調試助手、上位機

簡介
此串口調試助手是在windows下開發的,工具是Visual Studio 2017開發的,串口調試助手支持600~~115200波特率,端口號是CMO1~~CMO9,支持數據位、停止位、奇偶位,支持數據的接收與發送,接收方式十六進制、字符的選擇,對接收端數據的清空,並能對溫度傳感器數據進行接收與繪折線圖,並且能設置正常溫度現實的區間,及時判斷溫度是否顯示正常與否,並能對曲線的顯示進行刷新重新繪製。
實驗問題與修正
在這篇博客中我會把我所遇到的問題、自己寫的代碼、與解決的方法分享出來
先上一下實驗圖片
在這裏插入圖片描述

串口參數介紹

簡介
典型地,串口用於ASCII碼字符的傳輸。通信使用3根線完成:(1)地線,(2)發送,(3)接收。由於串口通信是異步的,端口能夠在一根線上發送數據同時在另一根線上接收數據。
波特率
這是一個衡量符號傳輸速率的參數。它表示每秒鐘傳送的符號的個數。例如300波特表示每秒鐘發送300個符號。當我們提到時鐘週期時,我們就是指波特率,例如如果協議需要4800波特率,那麼時鐘是4800Hz。這意味着串口通信在數據線上的採樣率爲4800Hz。通常電話線的波特率爲14400,28800和36600。波特率可以遠遠大於這些值,但是波特率和距離成反比。高波特率常常用於放置的很近的儀器間的通信,典型的例子就是GPIB設備的通信。
數據位
數據位表示一組數據實際包含的數據位數。數據位緊跟在起始位之後,是通信中的真正有效信息。數據位的位數由通信雙方共同約定,一般可以是6位、7位或8位,比如標準的ASCII碼是0—127(7位),擴展的ASCII碼是0—255(8位)。傳輸數據時先傳送字符的低位,後傳送字符的高位,即低位(LSB)在前,高位(MSB)在後。
奇偶位
奇偶校驗通常用在數據通信中來保證數據的有效性。奇偶校驗位是一個表示給定位數的二進制數中 1 的個數是奇數還是偶數的二進制數。奇偶校驗位是最簡單的錯誤檢測碼。
停止位
用於表示單個包的最後一位。典型的值爲1,1.5和2位。由於數據是在傳輸線上定時的,並且每一個設備有其自己的時鐘,很可能在通信中兩臺設備間出現了小小的不同步。因此停止位不僅僅是表示傳輸的結束,並且提供計算機校正時鐘同步的機會。適用於停止位的位數越多,不同時鐘同步的容忍程度越大,但是數據傳輸率同時也越慢。

串口通信模塊(SerialPort)

  • 配置IO文件

using System.IO;
using System.IO.Ports;

  • 圖標
    在這裏插入圖片描述
屬性 介紹
BaudRate 波特率
DataBits 數據位
Parity 奇偶校驗位
PortName 端口號
StopBits 停止位
ByteToRead 獲取輸入緩衝區的
IsOpen 獲取是否開啓串口
  • Serialport通信模塊的事件
    在這裏插入圖片描述
    在這裏我們只用到DataReceived串口接收函數,如需瞭解另外兩個請自己查閱
事件 介紹
DataReceived 串口接收函數
ErrorReceived 串口數據接收錯誤
PinChanged 串口號發生改變

串口窗口介紹

在這裏插入圖片描述
由圖可以看出正常溫度區間設置的是20-25度之間,測試溫度的過程中溫度曲線黃色的爲正常的曲線,紅色的曲線爲溫度異常。溫度刷新,溫度曲線重新讀取畫線

在窗體上添加4個Groupbox控件
第一個:串口設置
第二的:接收數據
第三個:發送數據
第四個:溫度曲線顯示

代碼編寫

  1. 串口初始化函數
private void button_open_Click(object sender, EventArgs e)
        {
           // if(Button_on == 1)
            if (!serialPort1.IsOpen)//如果串口是開
            {
                serialPort1.PortName = comboBox1.Text;//端口號
                serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text, 10);//波特率
                float f = Convert.ToSingle(comboBox3.Text.Trim());//trim去除字符串前後的空格
                if (f == 0)//設置停止位
                    serialPort1.StopBits = StopBits.None;
                else if (f == 1.5)
                    serialPort1.StopBits = StopBits.OnePointFive;
                else if (f == 1)
                    serialPort1.StopBits = StopBits.One;
                else if (f == 2)
                    serialPort1.StopBits = StopBits.Two;
                else
                    serialPort1.StopBits = StopBits.One;
                //設置數據位
                serialPort1.DataBits = Convert.ToInt32(comboBox4.Text.Trim());
                //設置奇偶校驗位
                string s = comboBox5.Text.Trim();
                if (s.CompareTo("無") == 0)
                    serialPort1.Parity = Parity.None;
                else if (s.CompareTo("奇校驗") == 0)
                    serialPort1.Parity = Parity.Odd;
                else if (s.CompareTo("偶校驗") == 0)
                    serialPort1.Parity = Parity.Even;
                else
                    serialPort1.Parity = Parity.None;
                try
                {
                    serialPort1.Open();     //打開串口
                    button_open.Text = "關閉串口";
                    comboBox1.Enabled = false;//關閉使能
                    comboBox2.Enabled = false;
                    comboBox3.Enabled = false;
                    comboBox4.Enabled = false;
                    comboBox5.Enabled = false;
                    comboBox6.Enabled = false;
                    comboBox7.Enabled = false;
                }
                catch
                {
                    MessageBox.Show("串口打開失敗!");
                }
            }
            else//如果串口是打開的則將其關閉
            {
                serialPort1.Close();
                button_open.Text = "打開串口";
                comboBox1.Enabled = true;//使能配置
                comboBox2.Enabled = true;
                comboBox3.Enabled = true;
                comboBox4.Enabled = true;
                comboBox5.Enabled = true;
                comboBox6.Enabled = true;
                comboBox7.Enabled = true;
            }

        }
  1. 畫座標圖
    在這裏插入圖片描述
  • 畫座標時用到頭文件

using System.Drawing;
using System.Drawing.Drawing2D;

  • 畫線時用到類graphics

graphics是抽象函數不能實例化,並且畫線的時候編輯器是以左上角爲座標原點畫的,想要把它改成左下角,只能自己計算座標點,根據自己的需求把它畫成稱自己想要的,如上圖我把(50,218)這個座標表示成原點

注意:Graphics是在控件Groupbox控件下事件Paint下寫的

private void groupBox4_Paint(object sender, PaintEventArgs e)
        {
            FontFamily family = new FontFamily("Arial");//實例化字體的類型
            int fontstyle = (int)FontStyle.Italic;//設置字體的樣式
            GraphicsPath gp = new GraphicsPath();
            string Str;
            //Draw y縱向軸繪製
            for (int i = 0; i <= 14; i++)
            {
                e.Graphics.DrawLine(TablePen, StartPrint + i * Unit_length, StartPrint - 32, StartPrint + i * Unit_length, 10 * Unit_length + 18);//畫線
                gp.AddString((i * 10).ToString(), family, fontstyle, 8, new RectangleF(StartPrint + i * Unit_length - 7, 10 * Unit_length + 18 + 4, 400, 50), null);//添加文字
            }
            gp.AddString("時間(s)", family, fontstyle, 12, new RectangleF(groupBox4.ClientRectangle.Width / 2 , 9 * Unit_length + 55, 400, 50), null);
            ////Draw X 橫向軸繪製
            for (int i = 0; i <= 10; i++)
            {
                e.Graphics.DrawLine(TablePen, StartPrint, i * Unit_length + 18, StartPrint + 14 * Unit_length, i * Unit_length + 18);//畫線
                Str = Convert.ToString((10 - i) * 5);
                if (i == 0)
                    Str = "50";
                if (i == 10)
                    break;
                gp.AddString(Str, family, fontstyle, 8, new RectangleF(20, i * Unit_length +16, 400, 50), null);//添加文字
            }
            gp.AddString("溫", family, fontstyle, 12, new RectangleF(0, groupBox4.ClientRectangle.Height / 2 - StartPrint, 400, 50), null);
            gp.AddString("度", family, fontstyle, 12, new RectangleF(0, groupBox4.ClientRectangle.Height / 2 + 18 - StartPrint, 400, 50), null);
            gp.AddString("°C", family, fontstyle, 12, new RectangleF(0, groupBox4.ClientRectangle.Height / 2 + 32 - StartPrint, 400, 50), null);
            e.Graphics.DrawPath(Pens.White, gp);//寫文字
        }
  • 方法介紹
    DrawLine(Pen pen, int x1, int y1, int x2, int y2);

pen:定義線條的寬度、顏色、樣式
畫線由(x1,y1)向(x2,y2)畫

public void AddString(string s, FontFamily family, int style, float emSize, RectangleF layoutRect, StringFormat format);

s:繪製的字符
family:繪製的字體類型
style:字體的樣式
emsize:方形塊的高度
layoutRect:文本的矩形
format:文本格式設置信息

  1. c#延時函數
public static void Delay(int milliSecond)
        {
            int start = Environment.TickCount;
            while (Math.Abs(Environment.TickCount - start) < milliSecond)//毫秒
            {
                Application.DoEvents();//可執行某無聊的操作
            }
        }

關於Math.Abs():
  Environment.TickCount,內部API是用DWORD GetTickCount()來實現的,該屬性的值從系統計時器派生,並以 32 位有符號整數的形式存儲。因此,如果系統連續運行,TickCount 將在約 24.9 天內從零遞增至 Int32. MaxValue ,然後跳至 Int32. MinValue (這是一個負數),再在接下來的 24.9 天內遞增至零。DWORD是無符號的,而 Environment.TickCount屬性返回的值是有符號的,所以有一半的值用負數表示!

  1. 串口寫函數
private void button_send_Click(object sender, EventArgs e)
        {//發送數據
            if(serialPort1.IsOpen)
            {//如果串口開啓
                if (textBox_send.Text.Trim() != "")//如果框內不爲空則
                {
                    serialPort1.Write(textBox_send.Text.Trim());//寫數據
                }
                else
                {
                    MessageBox.Show("發送框沒有數據");
                }
            }
            else
            {
                MessageBox.Show("串口未打開");
            }
        }
  1. 串口讀函數(如果是溫度傳感器並選擇溫度傳感器畫溫度曲線)
private void post_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            float Up, Dw,t;
            Graphics graphics = groupBox4.CreateGraphics();
            if (!radioButton1.Checked)
            {
                string str = serialPort1.ReadExisting();//字符串方式讀
                if(!radioButton3.Checked)
                {
                    //提取字符串中的數字
                    string result = System.Text.RegularExpressions.Regex.Replace(str, @"[^0-9]+", "");
                    Console.WriteLine(result);
                    //設置正常溫度上限下限
                    Dw = Convert.ToSingle(comboBox6.Text);
                    Up = Convert.ToSingle(comboBox7.Text);
                    if(Dw<Up)
                    {
                        t = Dw;
                        Dw = Up;
                        Up = t;
                    }
                    dstr2 = Convert.ToSingle(result);//字符串的轉換成float
                    textBox_T.Text = result + "度";
                    textBox_receive.AppendText(str);
                    //正常溫度的曲線
                    if(dstr2>=Up&&dstr2<=Dw)
                    {
                        graphics.DrawLine(LinesPen, Origin_x + i * Unit_length, dstr1, Origin_x + (i+0.1f) * Unit_length, Origin_y - dstr2 * 4);
                    }
                    else//異常溫度的曲線
                    {
                        graphics.DrawLine(LinesEpen, Origin_x + i * Unit_length, dstr1, Origin_x + (i + 0.1f) * Unit_length, Origin_y - dstr2 * 4);
                    }
                    i += 0.1f;
                    dstr1 = Origin_y - dstr2 * 4;
                    Delay(1000);//不延時的話不顯示
                    //textBox_T.Clear();無所謂
                }
                else
                {
                    textBox_receive.AppendText(str);
                }
            }
            else
            {
                byte data;
                data = (byte)serialPort1.ReadByte();
                string str = Convert.ToString(data, 16).ToUpper();//
                textBox_receive.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + "  ");

            }
        }

想要源代碼的可以關注公衆號回覆:上位機
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章