c#:vs2019制作温度上位机详细教程

  • Post author:
  • Post category:其他


所用的软件:vs2019

1、创建一个新项目

打开vs2019,选择创建一个新项目,点击下一步:

搜索“窗体”,找到“Windows窗体应用(.NET Framework)”w项目,点击下一步:

更改项目名称和位置(可不做更改),最后点击创建:

最后生成这样一个界面:

然后修改窗口的名字,点击窗口,在右侧属性里找到“Text”,修改文字:

2、在窗口中添加控件

点击左侧的工具箱,并搜索添加button、label、comboBox、GroupBox、panle和serialPort这几个控件:

在添加的控件上点击右键,进入属性,找到“Text”属性,将button1~button3改成搜索串口、打开串口和关闭串口;将label1~label6改为串口号、波特率、校验位、数据位和停止位;

添加comboBox2中的元素,选中控件,右键,在属性中找到“Item”属性:

点击,并添加波特率元素:

相似的,然后在comboBox3~comboBox5中分别添加校验位、数据位和停止位的元素:

校验位:

数据位:

停止位:

接下来,双击搜索串口按钮,进入到Form1.cs进行编程:

在该事件下面编写下面程序,搜索并获取当前可用的串口:

string[] portname = SerialPort.GetPortNames();//定义一个字符串来获取串口
this.comboBox_port.Items.Clear();//清空comboBox1中的值
foreach (string port in portname)//遍历串口
{
var serialPort = new SerialPort();//把串口赋给定义的var变量
serialPort.PortName = port;
serialPort.Open();//打开串口
this.comboBox_port.Items.Add(port);//打开成功,则添加至下拉框
serialPort.Close();//关闭串口
}

同样的,双击打开串口:

if (serialPort1.IsOpen)//如果串口是打开的
{
     try
     {
          serialPort1.Close();//先判断运行之前串口是否打开,若打开则要先关闭
     }
     catch
     {

     }
}
else
{
     try
     {
         serialPort1.PortName = comboBox_port.Text;//选中串口
         serialPort1.Open();//打开选中的串口
         button_openport.Enabled = false;//此时打开串口按钮失效
         comboBox_port.Enabled = false;//选择串口下拉框失效
         comboBox_baud.Enabled = false;//选择波特率下拉框失效
         comboBox_parity.Enabled = false;//选择校验位下拉框失效
         comboBox_data.Enabled = false;//选择数据位下拉框失效
         comboBox_stop.Enabled = false;//选择停止位下拉框失效
         button_searchport.Enabled = false;//搜索串口按钮失效
         button_closeport.Enabled = true;//关闭串口按钮可用
     }
     catch//若上面有错误操作,则返回下面的信息
     {
           MessageBox.Show("串口打开失败", "错误");
     }
}

双击关闭串口按钮:

            try
            {
                serialPort1.Close();//关闭串口
                button_openport.Enabled = true;//可用
                comboBox_port.Enabled = true;//可用
                comboBox_baud.Enabled = true;//可用
                comboBox_parity.Enabled = true;//可用
                comboBox_data.Enabled = true;//可用
                comboBox_stop.Enabled = true;//可用
                button_searchport.Enabled = true;//可用
                button_closeport.Enabled = false;//失效
                
            }
            catch (Exception err)//一般情况下关闭串口不会出错,加上以防万一
            {
                MessageBox.Show(err.Message);
            }

接下来,双击窗体,配置默认参数:

接下来,添加下图中的控件,其中实时温度为label;发送、停止和修改温度为按钮,按照上面的方法添加就好;这里面多了一个显示实时温度的Text文本框和二选一的RadioButton按钮:

接下来就是重点了,双击发送按钮:

private void button_sendorder_Click(object sender, EventArgs e)//(button_sendorder就是添加的发送按钮)
{
     this.sendCommand();//声明一个函数,用来执行发送按钮命令
}

private void sendCommand()//构造发送指令函数
{
    if (this.serialPort1.IsOpen == true && (!radioButton2.Checked||!radioButton1.Checked ))//判断串口是否打开  与上  (获取测量实时温度 
   或   修改温度的设定值),若为真,则执行下面代码
    {
        try
        {
            //81 81 52 00 00 00 53 00(读指令:地址(基础值+仪表地址)+地址+固定格式+参数代号+默认值+默认值+CRC校验码(注:该读指令是根据自己所要控制的仪器的通讯协议而定,例如我的就是一个测量温度的仪表,该仪表的读指令就是上面的值)
            string[] commandString = new string[] { "81", "81", "52", "00", "00", "00", "53", "00" };//将读指令或写指令传入字符串commandString中
            byte[] commandByte = new byte[commandString.Length];//定义一个与commandString长度相同的字节数组
            try
            {
                 for (int i = 0; i < commandString.Length; i++)//以十六进制发送
                 {
                      commandByte[i] = Convert.ToByte(commandString[i], 16);//将字符串变成字节数组
                 }
            }

            catch (Exception er)//若上面有错误,则返回以下信息
            {
                  MessageBox.Show(er.Message);//这个信息是系统自返回的
            }
            this.serialPort1.Write(commandByte, 0, commandByte.Length);//转换完成之后,发送给下位机指令
            System.Threading.Thread.Sleep(this.delayTime);//线程睡眠
            if (this.serialPort1.BytesToRead <= 10)//接收仪表返回的数据,并判断数据长度
            {
                 byte[] byteReceive = new byte[this.serialPort1.BytesToRead];//定义字节数据接收数据
                 this.serialPort1.Read(byteReceive, 0, byteReceive.Length);//读取缓冲区中的数据
                 string text_R = "";//定义一个字符串
                 text_R = Convert.ToString((byteReceive[0] + byteReceive[1] * 256) * 0.1).ToString() ;//只读取测量温度(该仪表返回的前两个字节为温度字节,所以只用到了byteReceive[0] 和 byteReceive[1])
         
                 textBox_RT.Text = text_R.ToUpper();//显示并大写 实时温度的文本框的内容(textBox_RT就是添加的TextBox)
                        
              }
        }
        catch
        {
             //MessageBox.Show(er.Message);
        }
    }
 }

至此,读取数据编码已完成。接下来把读取的数据以实时曲线的方式展现出来。

在这里,先在工具箱添加一个JYTEK工具;具体添加步骤可在B站视频查看:


SeeSharp基础篇 — 第一个 C# WinForm 程序_哔哩哔哩_bilibili

添加好上述工具之后,我们在窗体中添加listbox、EasyChartX、folderBrowserDialog这三个控件:

然后在,发送按钮指令下,添加以下代码用来在listbox中显示实时温度;在EasyChartX中绘制实时曲线:(注:这里要先添加

这个是B站简仪科技的一个GUI图像,跟着视频添加引用,这里不再赘述)

listBox1.Items.Add ( text_R.ToUpper());//在listBox中显示实时数据
listBox1.SelectedIndex = listBox1.Items.Count - 1;//使滚动条一直在最下方
foreach(var item in this.listBox1.Items)
{
temp.Add(item.ToString());//将listBox中的数组赋值给定义的列表数组temp(temp为自己定义的一个列表数组:List<string> temp = new List<string>();)
}
int len = listBox1.Items.Count;
string[] str = new string[len];
for (int i = 0; i < len; i++)
{
    str[i] = listBox1.Items[i].ToString();
}
double[] doubleArray = Array.ConvertAll<string, double>(str, delegate (string s) { return double.Parse(s); });
easyChartX1.Plot(doubleArray);//EasyChartX绘制实时曲线

最后生成excel报表,来记录历史数据温度,在窗体中添加label1、label2并改为“写入温度数据”、”路径“;添加一个按钮button1、button2并改为“开始”、”浏览“;添加一个Textbox文本框用来显示保存路径:

双击开始按钮,添加如下代码:(注这里要先添加

这个是B站简仪科技的一个报表生成,跟着视频添加引用,这里不再赘述)

if(textBox_path.Text == string.Empty)
            {
                MessageBox.Show("请选择保存路径");
                return;
            }
            excel = new ExcelReport();
            //excel.Show();//显示创建的表格
            excel.WriteTextToReport("A1", DateTime.Now.Date.ToLongDateString());

            int len = listBox1.Items.Count;
            string[] str = new string[len];
            for (int i = 0;i<len;i++)
            {
                str[i] = listBox1.Items[i].ToString();
            }
            
            excel.WriteArrayToReport("A2", str);
            excel.SaveAs(textBox_path.Text + @"\dataReport", ExcelSaveFormat.xlsx);
            excel.Close();

然后,双击浏览按钮:

if(folderBrowserDialog1.ShowDialog() ==DialogResult.OK)
            {
                textBox_path.Text = folderBrowserDialog1.SelectedPath;//设置保存路径
            }

添加好之后的界面如下图所示:

这里可根据自己的需要来添加定时器(是否需要实时采集温度数据)。

运行界面如下图所示:

最后附上完整程序代码:

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.Windows.Forms.DataVisualization.Charting;
using SeeSharpTools.JY.Report;
using SeeSharpTools.JY.ArrayUtility;

namespace 第一个优化的温度测量程序
{
    public partial class Form1 : Form
    {
        int count;//定义一个整型count,用于定时器1
        ExcelReport excel;
        public Form1()
        {
            InitializeComponent();
            button_closeport.Enabled = false;
            button_sendorder.Enabled = false;
            
        }

        List<string> temp = new List<string>();
        private int delayTime = 200;

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox_port.Text = "COM1";
            comboBox_baud.Text = "9600";
            comboBox_parity.Text = "None";
            comboBox_data.Text = "8";
            comboBox_stop.Text = "Two";
            timer1.Stop();//暂停计时   
        }
        
        private void button_searchport_Click(object sender, EventArgs e)//搜索可用串口
        {
            string[] portname = SerialPort.GetPortNames();//定义一个字符串来获取串口
            this.comboBox_port.Items.Clear();//清空comboBox1中的值
            foreach (string port in portname)//遍历串口
            {
                var serialPort = new SerialPort();//把串口赋给定义的var变量
                serialPort.PortName = port;
                serialPort.Open();//打开串口
                this.comboBox_port.Items.Add(port);//打开成功,则添加至下拉框
                serialPort.Close();//关闭串口
            }
        }

        private void button_openport_Click(object sender, EventArgs e)//打开所选择的串口
        {
            if (serialPort1.IsOpen)//如果串口是打开的
            {
                try
                {
                    serialPort1.Close();//先判断运行之前串口是否打开,若打开则要先关闭
                }
                catch
                {

                }
            }
            else
            {
                try
                {
                    serialPort1.PortName = comboBox_port.Text;//选中串口
                    serialPort1.Open();//打开选中的串口
                    button_openport.Enabled = false;//此时打开串口按钮失效
                    comboBox_port.Enabled = false;//选择串口下拉框失效
                    comboBox_baud.Enabled = false;//选择波特率下拉框失效
                    comboBox_parity.Enabled = false;//选择校验位下拉框失效
                    comboBox_data.Enabled = false;//选择数据位下拉框失效
                    comboBox_stop.Enabled = false;//选择停止位下拉框失效
                    button_searchport.Enabled = false;//搜索串口按钮失效
                    button_closeport.Enabled = true;//关闭串口按钮可用
                }
                catch//若上面有错误操作,则返回下面的信息
                {
                    MessageBox.Show("串口打开失败", "错误");
                }
            }
        }

        private void button_closeport_Click(object sender, EventArgs e)//关闭所选择的串口
        {
            try
            {
                serialPort1.Close();
                button_openport.Enabled = true;
                comboBox_port.Enabled = true;
                comboBox_baud.Enabled = true;
                comboBox_parity.Enabled = true;
                comboBox_data.Enabled = true;
                comboBox_stop.Enabled = true;
                button_searchport.Enabled = true;
                button_closeport.Enabled = false;
                
            }
            catch (Exception err)//一般情况下关闭串口不会出错,加上以防万一
            {
                MessageBox.Show(err.Message);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)//定时器
        {
            button_sendorder_Click(button_sendorder, null);
            if (serialPort1.IsOpen)   //如果串口已经打开
            {
                count++;    
            }

        }

        private void button_sendorder_Click(object sender, EventArgs e)
        {
            this.sendCommand();
            button_sendorder.Enabled = false;
            timer1.Start();
            timer2.Start();
        }

        private void sendCommand()//构造发送指令函数
        {
            if (this.serialPort1.IsOpen == true && (!radioButton2.Checked||!radioButton1.Checked ))
            {
                try
                {
                    //81 81 52 00 00 00 53 00(读指令:地址(基础值+仪表地址)+地址+固定格式+参数代号+默认值+默认值+CRC校验码
                    string[] commandString = new string[] { "81", "81", "52", "00", "00", "00", "53", "00" };//将读指令或写指令传入字符串commandString中

                    byte[] commandByte = new byte[commandString.Length];//将字符串变成字节数组
                    try
                    {
                        for (int i = 0; i < commandString.Length; i++)//以十六进制发送
                        {
                            commandByte[i] = Convert.ToByte(commandString[i], 16);

                        }
                    }

                    catch (Exception er)
                    {
                        MessageBox.Show(er.Message);
                    }
                    this.serialPort1.Write(commandByte, 0, commandByte.Length);
                    System.Threading.Thread.Sleep(this.delayTime);
                    if (this.serialPort1.BytesToRead <= 10)
                    {
                        byte[] byteReceive = new byte[this.serialPort1.BytesToRead];//定义字节数据接收数据
                        this.serialPort1.Read(byteReceive, 0, byteReceive.Length);//读取缓冲区中的数据
                        string text_R = "";
                        text_R = Convert.ToString((byteReceive[0] + byteReceive[1] * 256) * 0.1).ToString() ;//只读取测量温度

                        textBox_RT.Text = text_R.ToUpper();
                        listBox1.Items.Add ( text_R.ToUpper());
                        listBox1.SelectedIndex = listBox1.Items.Count - 1;
                        foreach(var item in this.listBox1.Items)
                        {
                            temp.Add(item.ToString());
                        }
                        int len = listBox1.Items.Count;
                        string[] str = new string[len];
                        for (int i = 0; i < len; i++)
                        {
                            str[i] = listBox1.Items[i].ToString();
                        }
                        double[] doubleArray = Array.ConvertAll<string, double>(str, delegate (string s) { return double.Parse(s); });
                        easyChartX1.Plot(doubleArray);
                    }
                }
                catch
                {
                    //MessageBox.Show(er.Message);
                }
            }
        }

        private void chart1_Click(object sender, EventArgs e)//双击chart事件来显示滑动条
        {
            
        }


        private void timer2_Tick(object sender, EventArgs e)
        {
            //series = chart1.Series[0];
            //foreach (var item in this.listBox1.Items)
            //{
            //    temp.Add(item.ToString());
            //}
            //chart1.Series[0].Points.DataBindXY(DateTime.TryParseExact,temp);            
        }

        private void button_modifytemperature_Click(object sender, EventArgs e)//声明修改参数函数
        {
            this.modifyTemperature();
            button_sendorder.Enabled = true;

        }
        private void modifyTemperature()//构造修改参数函数
        {
            if (this.serialPort1.IsOpen == true && !radioButton1.Checked)
            {
                try
                {
                    //81 81 43 00 00 00 44 00(写指令:地址(基础值+仪表地址)+地址+固定格式+参数代号+低字节(要改写参数值的低字节)+高字节(要改写参数值的高字节)+CRC校验码
                    double modifydata = Convert.ToInt32(textBox_modify.Text);
                    byte modifyhigh = 0xff, modifylow = 0xff, crchigh = 0xff, crclow = 0xff;
                    modifyhigh = (byte)((int)modifydata * 10 / 256);
                    modifylow = (byte)((int)modifydata * 10 % 256);
                    crchigh = (byte)((68 + modifydata * 10) / 256);
                    crclow = (byte)((68 + modifydata * 10) % 256);
                    //string[] commandString = new string[] { "81", "81", "43", "00", "modifylow", "modifyhigh", "crclow", "crchigh" };//将读指令或写指令传入字符串commandString中
                    //byte[] commandByte = new byte[commandString.Length];//将字符串变成字节数组
                    byte[] commandByte = new byte[] { 0x81, 0x81, 0x43, 0x00, modifylow, modifyhigh, crclow, crchigh };


                    this.serialPort1.Write(commandByte, 0, commandByte.Length);
                    serialPort1.DiscardOutBuffer();
                    System.Threading.Thread.Sleep(this.delayTime);
                }
                catch
                {
                    //MessageBox.Show(er.Message);
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            button_sendorder.Enabled = true;
            timer1.Stop();
        }

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            button_sendorder.Enabled = true;
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void button_writedata_Click(object sender, EventArgs e)
        {
           if(textBox_path.Text == string.Empty)
            {
                MessageBox.Show("请选择保存路径");
                return;
            }
            excel = new ExcelReport();
            //excel.Show();//显示创建的表格
            excel.WriteTextToReport("A1", DateTime.Now.Date.ToLongDateString());

            int len = listBox1.Items.Count;
            string[] str = new string[len];
            for (int i = 0;i<len;i++)
            {
                str[i] = listBox1.Items[i].ToString();
            }
            
            excel.WriteArrayToReport("A2", str);
            excel.SaveAs(textBox_path.Text + @"\dataReport", ExcelSaveFormat.xlsx);
            excel.Close();
            
        }

        private void button_browse_Click(object sender, EventArgs e)
        {
            if(folderBrowserDialog1.ShowDialog() ==DialogResult.OK)
            {
                textBox_path.Text = folderBrowserDialog1.SelectedPath;
            }
        }
    }
}



版权声明:本文为Zzzz_zzzZzz_zz原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。