上位机软件_上位机软件测试 - CSDN
精华内容
参与话题
  • 上位机软件开发入门

    万次阅读 2017-03-25 18:23:53
    上位机是指:人可以直接发出操控命令的计算机,一般是PC,屏幕上显示各种信号变化(液压,水位,温度等)。 下位机是直接控制设备获取设备状况的的计算机,一般是PLC/单片机之类的。 上位机发出的命令首先给下位机,...

    1、上位机是指:人可以直接发出操控命令的计算机,一般是PC,屏幕上显示各种信号变化(液压,水位,温度等)。
    下位机是直接控制设备获取设备状况的的计算机,一般是PLC/单片机之类的。

    上位机发出的命令首先给下位机,下位机再根据此命令解释成相应时序信号直接控制相应设备。下位机不时读取设备状态数据(一般模拟量),转化成数字信号反馈给上位机。上下位机都需要编程,都有专门的开发系统。
    两机如何通讯,一般取决于下位机。TCP/IP一般是支持的。通常上位机和下位机通讯可以采用不同的通讯协议,可以有RS232的串口通讯,或者采用RS485串行通讯,
    
    展开全文
  • 点击上方「嵌入式大杂烩」,选择「置顶公众号」第一时间查看编程笔记!本次分享一个很酷的上位机软件——伏特加。伏特加简介 伏特加是一款通用的数据调试工具,它让图形化调试变得像串口调试一样简单...

    点击上方「嵌入式大杂烩」,选择「置顶公众号」第一时间查看编程笔记!

    本次分享一个很酷的上位机软件——伏特加

    伏特加简介

    伏特加是一款通用的数据调试工具,它让图形化调试变得像串口调试一样简单。通过打印字符串,或者发送十六进制数字的方式,就能完成数据的可视化操作。

    并且拥有强大的实时统计功能,以往需要保存数据转移到Matlab才能进行直方统计,频谱分析,有了伏特加,这些都能在接收到数据的那一刻实时完成。伏特加是一个通用的串口助手、通用的网络调试助手。

    其界面如下:

    很简洁、美观。

    伏特加功能演示

    (1)伏特加与下位机数据交互

    下位机(我们这里用的是STM32)与伏特加的数据交互可以是下位机往伏特加发送数据,也可以是伏特加往下位机发送数据。

    这里演示下位机发送数据至伏特加进行波形显示(使用串口通信)。我们要往伏特加发送数据进行波形显示,当然要遵循一些数据协议。

    伏特加支持  FireWater(烈酒)协议 、  JustFloat协议RawData协议,这些都是自定义协议。我们 按照协议格式发送数据,软件自动解析数据数量,生成波形。

    这里我们选用的是 FireWater(烈酒)协议:

    下位机的代码编写很简单,例如我们要从下位机发送数据,显示两个正弦波,只需调用printf函数发送协议格式数据即可,代码:

    主函数更简单:

    下载程序,打开伏特加,设置串口参数,就可以看到对应波形了:

    (2)伏特加作为TCP客户端

    FireWater协议:

    JustFloat协议:

    这就是本次的分享,希望各位喜欢。

    最后,重点来了。伏特加软件及使用教程,可在后台回复关键词:伏特加,进行获取。

    温馨提示:第一次打开可能会出现未响应的情况,稍微等一些就好,因为其正在自动激活。

    猜你喜欢:

    C语言、嵌入式位操作精华技巧大汇总

    基于Linux、C、JSON、Socket的编程实例(附代码)

    一个超轻量级的JSON解析器

    STM32网址大全(快速定位网址查找资料)

    手册在手,bug不再有,分享一个超级强大的软件

    教你写一个定时关机程序

    展开全文
  • 所以接下来我们将继续一步一步来编写上位机软件的程序部分。 首先,我谈一下自己所理解的C#上位机软件程序编写的中心思想。以串口助手(简洁版)为例,所有程序都是以 “事件” 为核心来进行的,对应的 “事件”...

            在上篇博客中,我们完成了串口助手(简洁版)可视化窗体的设计,并且单击启动后可以运行。但是光有外壳,没有灵魂。所以接下来我们将继续一步一步来编写上位机软件的程序部分。

            首先,我谈一下自己所理解的C#上位机软件程序编写的中心思想以串口助手(简洁版)为例,所有程序都是以    “事件”   为核心来进行的,对应的  “事件”发生了,那软件就去执行 我们自己编写的 对应事件中的 程序。

            按键按下,算一个事件吧    -----》》》》 执行这个按键按下对应的程序

            串口突然收到数据 ,算一个事件吧   -----》》》执行串口收到数据时对应的程序

            定时器中断来了,也是个事件    ----》》》》执行定时器中断发生时对应的程序

    不知道这样讲符不符合C#上位机真正的编程方式,但是对于初学者应该会有种豁然开朗的感觉。如果错了,先就错着看吧,哈哈。。。

    咱们下面就一个事件,一个事件的写代码,代码后都有详细的注释,大家不要心虚。。。。。

    1.窗口加载时事件(程序)

    窗体刚刚加载出来,就是弹出软件窗口的一瞬间,算个事件吧。那怎么去编写这一段的程序呢?我们到上一章编好的可视化窗体中,去双击窗体的空白处,就跳转到对应的事件发生程序中去了。比如双击这里:

    然后就跳转到这个代码段中来了:

    、、、 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;
    
    namespace 串口助手_简洁版_
    {
        public partial class Form1 : Form
        {
            /*默认存在*/
            public Form1()
            {
                InitializeComponent();
            }
    
            /*窗体加载时被调用*/
            private void Form1_Load(object sender, EventArgs e)
            {
    
            }
    
        }
    }
    

    函数  Form1_Load()  就会在窗体加载的时候被调用一次。上方的 Form1()   函数会默认存在,暂时不用理会。在其中加入代码:

    ''' C#
    
            /*窗体加载时被调用*/
            private void Form1_Load(object sender, EventArgs e)
            {
                Updata_Serialport_Name(comboBox1);  //调用更新可用串口函数,comboBox1为 端口 组合框名字
    
                radioButton1.Checked = true;   //函数中选择发送模式 为“数值”发送模式。 radioButton1为单选按钮属性(name)名字
                radioButton3.Checked = true;   //函数中选择接收模式 为“数值”接收模式。 radioButton3为单选按钮属性(name)名字
    
                button2.Text = "打开串口";     // 确保 “打开串口”按键文本属性为 “打开串口”
            }
    
            /*用户自定义更新可用串口函数*/
            private void Updata_Serialport_Name(ComboBox MycomboBox)
            {
                string[] ArryPort = SerialPort.GetPortNames();  //定义字符串数组,数组名为 ArryPort
                                                                //SerialP ort.GetPortNames()函数功能为获取计算机所有可用串口,以字符串数组形式输出
                MycomboBox.Items.Clear();       //清除当前组合框下拉菜单内容                  
    
                for (int i = 0; i < ArryPort.Length; i++)
                {
                    MycomboBox.Items.Add(ArryPort[i]);   //将所有的可用串口号添加到  端口 对应的组合框中
                }
            }

      总结: 1.在窗体加载事件中,我们设置  发送和接收模式都默认选择 “”数值“”模式,  同时 调用自定义的串口号更新函数 Updata_Serialport_Name (), 来更新一下 “端口”   组合框下拉菜单中的串口信息。

                  2. SerialPort.GetPortNames()  函数,用来查询所有的可用串口号。

    2.定时器中断事件(程序)

    上一章在可视化窗体编辑过程中,我们添加并使能了定时器控件,并设定时周期为500ms。所以在程序中,我们需要为其添加定时器中断处理程序。同上一样,我们需要正在GUI窗口中双击Timer图标。便可创建 和 进入 定时器中断事件代码段。

    双击此处:

    编辑函数如下:

    ''' C#   
    
            /*定时器500ms中断调用*/
            private void timer1_Tick(object sender, EventArgs e)
            {
                Updata_Serialport_Name(comboBox1);   //依然是调用更新可用串口函数
                                                     //目的是在软件使用过程中,时刻刷新串口信息
            }
    

    总结:  间隔500ms产生一次定时器中断事件,在中断事件中调用用户自定义的更新串口号函数,来实现串口号的动态更新。

    3.串口开关按键按下事件(程序)

    在GUI界面中,我们做了一个“”打开串口“”按键,用于打开上位机串口。同样双击按键图标进入事件对应的程序段。事件对应的代码如下:

     

    ''' C#        
    
           /*打开串口按键按下调用*/
            private void button2_Click(object sender, EventArgs e)
            {
    
                if (button2.Text == "打开串口")     //如当前是串口设备是关闭状态
                {
                    try                             //try 是尝试部分  ,如果尝试过程中出现问题,进入 catch部分,执行错误处理代码  
                    {
                        serialPort1.PortName = comboBox1.Text;                   //将串口设备的串口号属性设置为  comboBox1复选框中选择的串口号
                        serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);  //将串口设备的波特率属性设置为  comboBox2复选框中选择的波特率
                        serialPort1.Open();     //打开串口,如果打开了继续向下执行,如果失败了,跳转至catch部分
    
                        comboBox1.Enabled = false;   //串口已经打开了,将comboBox1设置为不可操作
                        comboBox2.Enabled = false;   //串口已经打开了,将comboBox2设置为不可操作
    
                        button2.BackColor = Color.Red;   //将串口开关按键的颜色,改为红色
                        button2.Text = "关闭串口";      //将串口开关按键的文字改为  “关闭串口”
                    }
                    catch
                    {
                        MessageBox.Show("打开串口失败,请检查串口", "错误");   //弹出错误对话框
                    }
                }
                else              //如果当前串口设备是打开状态
                {
                    try
                    {
                        serialPort1.Close();    //关闭串口
    
                        comboBox1.Enabled = true;   //串口已经关闭了,将comboBox1设置为可操作
                        comboBox2.Enabled = true;   //串口已经关闭了,将comboBox2设置为可操作
    
                        button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
    
                        button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
                    }
                    catch
                    {
                        MessageBox.Show("关闭串口失败,请检查串口", "错误");   //弹出错误对话框
                    }
    
                }
            }
    

    总结:1.Convert.ToInt32(comboBox2.Text);  意思是将comboBox2中选中的波特率字符串,转化为int 32位的数值数据。

               2.try 和  catch  是C#中特有的,用来进行错误处理的语句。出错了就跳至catch部分补救处理。如果没有catch,一旦出错程序就崩掉了。

              3.打开串口后,串口开关按键的颜色和文字就已经在程序中被修改了,而且还让两个组合框发灰,变成不可操作状态

     

    4.发送按钮按下事件(程序)

      当按下串口发送按键后,就需要将发送文本框中的数据通过串口发出。并且要通过判断单选按钮的按下状态来判断该以什么样的数据形式发送。同样双击发送按键  ,进入发送按钮按下代码段,并写入代码如下:

    '''C#
      
            /*发送按键按下调用*/
            private void button1_Click(object sender, EventArgs e)
            {
                if (serialPort1.IsOpen)    //如果串口设备已经打开了
                {
                    if (radioButton2.Checked)  //如果是以字符的形式发送数据
                    {
                        char[] str = new char[1];  //定义一个字符数组,只有一位
    
                        try
                        {
                            for (int i = 0; i < textBox1.Text.Length; i++)
                            {
                                str[0] = Convert.ToChar(textBox1.Text.Substring(i, 1));  //取待发送文本框中的第i个字符
                                serialPort1.Write(str, 0, 1);     //写入串口设备进行发送
                            }
                        }
                        catch
                        {
                            MessageBox.Show("串口字符写入错误!", "错误");   //弹出发送错误对话框
    
                            serialPort1.Close();             //关闭串口
    
                            button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
    
                            button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
                        }
                    }
                    else  //如果以数值的形式发送
                    {
                        byte[] Data = new byte[1];   //定义一个byte类型数据,相当于单片机中的  unsigned char 类型
    
                        int flag = 0;   //定义一个标志,标志这是第几位
    
                        try
                        {
                            for (int i = 0; i < textBox1.Text.Length; i++)
                            {
                                if (textBox1.Text.Substring(i, 1) == " " && flag == 0)   //如果是第一位,并且为空字符
                                {
                                    continue;
                                }
    
                                if (textBox1.Text.Substring(i, 1) != " " && flag == 0)  //如果是第一位,但不为空字符
                                {
                                    flag = 1;   //标志转到第二位数据去
    
                                    if (i == textBox1.Text.Length - 1)   //如果这是文本框字符串的最后一个字符
                                    {
                                        Data[0] = Convert.ToByte(textBox1.Text.Substring(i, 1), 16);  //转化为byte类型数据,以16进制显示
                                        serialPort1.Write(Data, 0, 1);   //通过串口发送
                                        flag = 0;    //标志回到第一位数据去
                                    }
                                    continue;
                                }
    
                                else if (textBox1.Text.Substring(i, 1) == " " && flag == 1)  //如果是第二位 ,且第二位字符为空
                                {
                                    Data[0] = Convert.ToByte(textBox1.Text.Substring(i - 1, 1), 16);  //只将第一位字符转化为byte类型数据,以十六进制显示
                                    serialPort1.Write(Data, 0, 1);    //通过串口发送
                                    flag = 0;    //标志回到第一位数据去
                                    continue;
                                }
                                else if (textBox1.Text.Substring(i, 1) != " " && flag == 1)  //如果是第二位字符,且第一位字符不为空
                                {
                                    Data[0] = Convert.ToByte(textBox1.Text.Substring(i - 1, 2), 16);  //将第一,二位字符转化为byte类型数据,以十六进制显示
                                    serialPort1.Write(Data, 0, 1);  //通过串口发送
                                    flag = 0;  //标志回到第一位数据去
                                    continue;
                                }
                            }
                        }
                        catch
                        {
                            MessageBox.Show("串口数值写入错误!", "错误");
    
                            serialPort1.Close();
    
                            button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
    
                            button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
    
                        }
                    }
    
    
                }
    
            }
    

    总结:1. serialPort1.Write(str, 0, 1); 是向串口发送缓冲区中写数据,第一位是待写入数组名,第二位是数组起始位置,第三位是数据长度。

              2.textBox1.Text.Substring(i, 1);是字符串截取函数,截取完后形成一个子字符串,第一位是首字符地址,第二位是字符串长度。

             3.串口发送函数分为按数值方式,和按字符方式。需要根据单选按钮控件的按下状态来决定。

            4.数值发送方式写的有点复杂,目的是要从字符串中,两两抠出16进制数据,如0x46,但同时又要考虑空格作为分隔符的存在。虽然代码复杂了,但是相对用户来说,就没有了输入格式要求,随心所欲的输都可以。

    5. 串口接收到数据事件(程序)

      当串口接收到数据时,会调用串口接收到数据的事件函数,串口接收代码段的打开方式和其他的有所不同,双击图标并不会进行代码段的创建,需要注意一下。这里需要这样来进行创建和打开。

    在串口属性窗口中,单击这个像闪电一样的图标。

     


    然后双击   DataREceived 属性栏,才会创建 并打开串口接收代码段:

    填入代码如下:

    ''' C#
    
            /*串口接收到*/
            private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
    
                if (radioButton4.Checked)  //如果以字符串形式读取
                {
                    string str = serialPort1.ReadExisting();   //读取串口接收缓冲区字符串
    
                    textBox2.AppendText(str + "");             //在接收文本框中进行显示
                }
                else   //以数值形式读取
                {
                    int length = serialPort1.BytesToRead;    // 读取串口接收缓冲区字节数
    
                    byte[] data = new byte[length];          //定义相同字节的数组
    
                    serialPort1.Read(data, 0, length);       //串口读取缓冲区数据到数组中
    
                    for (int i = 0; i < length; i++)   
                    {
                        string str = Convert.ToString(data[i], 16).ToUpper();          //将数据转换为字符串格式
                        textBox2.AppendText("0X" + (str.Length == 1 ? "0" + str + " " : str + " "));   //添加到串口接收文本框中
                    }
                }
    
            }
    

    总结: 1.serialPort1.ReadExisting();以字符串的形式读取串口接收缓冲区内的数据。

                2. (str.Length == 1 ? "0" + str + " " : str + " ")三目运算符,跟C语言一样。

     

    6.清空数据按键按下事件(代码)

    现在来说这个就比较简单了,直接上代码:

      ''' C#
     
    
         /*清除按键按下*/
            private void button3_Click(object sender, EventArgs e)
            {
                textBox2.Text = "";
            }

     

    到此为止,串口助手就已经开发完毕。按启动按钮后,可以对软件进行测试。

    如果想要将软件拷贝出来,直接定位到工程文件夹下的obj目录,将其中的.exe文件拷贝出来即可。

    再附上程序整图:

    ''' 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;
    
    
    namespace 串口助手_简洁版_
    {
        public partial class Form1 : Form
        {
            /*默认存在*/
            public Form1()
            {
                InitializeComponent();
            }
    
            /*窗体加载时被调用*/
            private void Form1_Load(object sender, EventArgs e)
            {
                Updata_Serialport_Name(comboBox1);  //调用更新可用串口函数,comboBox1为 端口 组合框名字
    
                radioButton1.Checked = true;   //函数中选择发送模式 为“数值”发送模式。 radioButton1为单选按钮属性(name)名字
                radioButton3.Checked = true;   //函数中选择接收模式 为“数值”接收模式。 radioButton3为单选按钮属性(name)名字
    
                button2.Text = "打开串口";     // 确保 “打开串口”按键文本属性为 “打开串口”
            }
    
            /*用户自定义更新可用串口函数*/
            private void Updata_Serialport_Name(ComboBox MycomboBox)
            {
                string[] ArryPort = SerialPort.GetPortNames();  //定义字符串数组,数组名为 ArryPort
                                                                //SerialP ort.GetPortNames()函数功能为获取计算机所有可用串口,以字符串数组形式输出
                MycomboBox.Items.Clear();       //清除复选框                  
    
                for (int i = 0; i < ArryPort.Length; i++)
                {
                    MycomboBox.Items.Add(ArryPort[i]);   //将所有的可用串口号添加到  端口 对应的组合框中
                }
            }
    
    
            /*定时器500ms中断调用*/
            private void timer1_Tick(object sender, EventArgs e)
            {
                Updata_Serialport_Name(comboBox1);   //依然是调用更新可用串口函数
                                                     //目的是在软件使用过程中,时刻刷新串口信息
            }
    
    
    
            /*开关串口按键按下调用*/
            private void button2_Click(object sender, EventArgs e)
            {
    
                if (button2.Text == "打开串口")     //如当前是串口设备是关闭状态
                {
                    try                             //try 是尝试部分  ,如果尝试过程中出现问题,进入 catch部分,执行错误处理代码  
                    {
                        serialPort1.PortName = comboBox1.Text;                   //将串口设备的串口号属性设置为  comboBox1复选框中选择的串口号
                        serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);  //将串口设备的波特率属性设置为  comboBox2复选框中选择的波特率
                        serialPort1.Open();     //打开串口,如果打开了继续向下执行,如果失败了,跳转至catch部分
    
                        comboBox1.Enabled = false;   //串口已经打开了,将comboBox1设置为不可操作
                        comboBox2.Enabled = false;   //串口已经打开了,将comboBox2设置为不可操作
    
                        button2.BackColor = Color.Red;   //将串口开关按键的颜色,改为红色
                        button2.Text = "关闭串口";      //将串口开关按键的文字改为  “关闭串口”
                    }
                    catch
                    {
                        MessageBox.Show("打开串口失败,请检查串口", "错误");   //弹出错误对话框
                    }
                }
                else              //如果当前串口设备是打开状态
                {
                    try
                    {
                        serialPort1.Close();    //关闭串口
    
                        comboBox1.Enabled = true;   //串口已经关闭了,将comboBox1设置为可操作
                        comboBox2.Enabled = true;   //串口已经关闭了,将comboBox2设置为可操作
    
                        button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
    
                        button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
                    }
                    catch
                    {
                        MessageBox.Show("关闭串口失败,请检查串口", "错误");   //弹出错误对话框
                    }
    
                }
            }
    
    
       
            /*发送按键按下调用*/
            private void button1_Click(object sender, EventArgs e)
            {
                if (serialPort1.IsOpen)    //如果串口设备已经打开了
                {
                    if (radioButton2.Checked)  //如果是以字符的形式发送数据
                    {
                        char[] str = new char[1];  //定义一个字符数组,只有一位
    
                        try
                        {
                            for (int i = 0; i < textBox1.Text.Length; i++)
                            {
                                str[0] = Convert.ToChar(textBox1.Text.Substring(i, 1));  //取待发送文本框中的第i个字符
                                serialPort1.Write(str, 0, 1);     //写入串口设备进行发送
                            }
                        }
                        catch
                        {
                            MessageBox.Show("串口字符写入错误!", "错误");   //弹出发送错误对话框
    
                            serialPort1.Close();             //关闭串口
    
                            button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
    
                            button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
                        }
                    }
                    else  //如果以数值的形式发送
                    {
                        byte[] Data = new byte[1];   //定义一个byte类型数据,相当于单片机中的  unsigned char 类型
    
                        int flag = 0;   //定义一个标志,标志这是第几位
    
                        try
                        {
                            for (int i = 0; i < textBox1.Text.Length; i++)
                            {
                                if (textBox1.Text.Substring(i, 1) == " " && flag == 0)   //如果是第一位,并且为空字符
                                {
                                    continue;
                                }
    
                                if (textBox1.Text.Substring(i, 1) != " " && flag == 0)  //如果是第一位,但不为空字符
                                {
                                    flag = 1;   //标志转到第二位数据去
    
                                    if (i == textBox1.Text.Length - 1)   //如果这是文本框字符串的最后一个字符
                                    {
                                        Data[0] = Convert.ToByte(textBox1.Text.Substring(i, 1), 16);  //转化为byte类型数据,以16进制显示
                                        serialPort1.Write(Data, 0, 1);   //通过串口发送
                                        flag = 0;    //标志回到第一位数据去
                                    }
                                    continue;
                                }
    
                                else if (textBox1.Text.Substring(i, 1) == " " && flag == 1)  //如果是第二位 ,且第二位字符为空
                                {
                                    Data[0] = Convert.ToByte(textBox1.Text.Substring(i - 1, 1), 16);  //只将第一位字符转化为byte类型数据,以十六进制显示
                                    serialPort1.Write(Data, 0, 1);    //通过串口发送
                                    flag = 0;    //标志回到第一位数据去
                                    continue;
                                }
                                else if (textBox1.Text.Substring(i, 1) != " " && flag == 1)  //如果是第二位字符,且第一位字符不为空
                                {
                                    Data[0] = Convert.ToByte(textBox1.Text.Substring(i - 1, 2), 16);  //将第一,二位字符转化为byte类型数据,以十六进制显示
                                    serialPort1.Write(Data, 0, 1);  //通过串口发送
                                    flag = 0;  //标志回到第一位数据去
                                    continue;
                                }
                            }
                        }
                        catch
                        {
                            MessageBox.Show("串口数值写入错误!", "错误");
    
                            serialPort1.Close();
    
                            button2.BackColor = Color.Lime;   //将串口开关按键的颜色,改为青绿色
    
                            button2.Text = "打开串口";    //将串口开关按键的文字改为  “打开串口”
    
                        }
                    }
    
    
                }
    
            }
    
    
            /*串口接收到*/
            private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
    
                if (radioButton4.Checked)  //如果以字符串形式读取
                {
                    string str = serialPort1.ReadExisting();   //读取串口接收缓冲区字符串
    
                    textBox2.AppendText(str + "");             //在接收文本框中进行显示
                }
                else   //以数值形式读取
                {
                    int length = serialPort1.BytesToRead;    // 读取串口接收缓冲区字节数
    
                    byte[] data = new byte[length];          //定义相同字节的数组
    
                    serialPort1.Read(data, 0, length);       //串口读取缓冲区数据到数组中
    
                    for (int i = 0; i < length; i++)   
                    {
                        string str = Convert.ToString(data[i], 16).ToUpper();          //将数据转换为字符串格式
                        textBox2.AppendText("0X" + (str.Length == 1 ? "0" + str + " " : str + " "));   //添加到串口接收文本框中
                    }
                }
    
            }
    
            /*清除按键按下*/
            private void button3_Click(object sender, EventArgs e)
            {
                textBox2.Text = "";
            }
    
        }
    }
    

    看看最后效果:

     

    重要:如果程序运行时出现线程间访问出错,记得在Form1()函数中加一段代码,即可完美解决:

    '''C#   
    
            /*默认*/
            public Form1()
            {
                InitializeComponent();
                System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//设置该属性 为false
            }

     

    展开全文
  • C#写的上位机软件

    热门讨论 2020-07-29 14:21:03
    完全没有问题的上位机软件,用C#编写,能进行串口通信校验
  • 1.3-原来这才是大家常用的上位机开发平台

    千次阅读 多人点赞 2020-03-30 18:35:03
    一、有哪些上位机开发平台(优缺点和使用场景) 由于上位机概念的广泛性,所以上位机开发平台可以是任何开发平台。这里介绍几个常用的经典的上位机开发平台及其特性。 VB(Visual Basic) 开发语言:Basic(BASIC是...

    一、有哪些上位机开发平台(优缺点和使用场景)

    由于上位机概念的广泛性,所以上位机开发平台可以是任何开发平台。这里介绍几个常用的经典的上位机开发平台及其特性。

    1. VB(Visual Basic)
      开发语言:Basic(BASIC是一种直译式的编程语言,在完成编写后不须经由编译及连接等步骤即可执行,类似脚本语言)
      开发工具:Visual Basic(语言简单易用,对面向对象编程和多线程编程支持不完整)
      适用平台:WINDOWS ALL
      平台特点:以面向对象的思想开发可视化图形界面的应用程序。采用面向对象程序设计方法(Object-Oriented Programming),把程序和数据封装起来作为一个对象,每个对象都是可视的。开发人员在界面设计时,可以直接用Visual Basic 6.0的工具箱在屏幕上"画"出窗口、菜单、命令按键等不同类型的对象,并为每个对象设置属性。在流行的时候有大量功能库可以使用,比如典型的数据库管理控件。VB属于在刚刚出现图形界面开发阶段的开发平台。由于平台老旧以及basic编程语言的缺点,现在已经没有人使用了。虽然现在有了“Visual Basic .NET”但是使用的人很少。

    2. VC(Virtual C++)
      开发语言:面向对象语言C++(微软更具C++标准实现的微软版本, 编译器采用cl.exe)
      开发工具:Visual C++
      适用平台:WINDOWS ALL
      平台特点:以面向对象的思想开发可视化图形界面的应用程序。最大的亮点是MFC框架。是微软公司提供的一个类库,以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。框架比较精简,对于初学者理解电脑软件开发框架有很大帮助。这也成了他的缺点,导致使用MFC开发软件效率相对很低(程序猿要做大量界面编码工作)。MFC开发出来的软件界面也很简陋,主要原因是要想美化需要程序猿自己做大量美化工作(量大到不适合个人开发者做这个美化工作)。当然在电脑端刚刚出现图形界面开发时候,MFC这个框架简直大量简化了程序猿的工作量,并且提高了程序的质量。因此一度非常流行,以至于现今(2020年)还有这个MFC开发平台的身影(大多处于维护阶段的老项目)。

    3. Delphi
      开发语言:Object Pascal
      开发工具:delphi7
      适用平台:WINDOWS ALL
      平台特点:Delphi 拥有一个可视化的集成开发环境(IDE),采用面向对象的编程语言ObjectPascal和基于部件的开发结构框架。Delphi它提供了非常多个可供使用的构件,利用这些部件,开发人员可以快速地构造出应用系统。开发人员也可以根据自己的需要修改部件或用Delphi本身编写自己的部件。和VC相比,Delphi更简单、更易于掌握,而在功能上却丝毫不逊色;和VB相比,Delphi则功能更强大、更实用。 Delphi确实功能丰富开发效率高,到目前也还有人用。只是绝大多数是在做老项目的开发了,新项目基本上不会再用Delphi写。主要原因是Delphi不是微软自家的孩子。随着微软系统大量的系统更新,以及微软自己的C#开发平台兴起,使得Delphi跟不上节奏了(Pascal编程语言本身也很少在其他开发平台使用)。

    4. WinForm
      开发语言:C#
      开发工具:Visual Studio
      适用平台:WINDOWS ALL
      平台特点:WinForm是目前很流行的Windows应用程序开发平台,现在大部分windows应用程序都是使用WinForm开发,提供对最新windows系统特性的支持,且拥有大量的第三方类库。全面支持各种开发技术。开发的程序对windows所有系统都有非常好的兼容性和不俗的性能。属于微软的.net开发,拥有强大齐全的各种封装好的成熟类库。借助优秀的C#开发语言。是现阶段Windows应用程序开发的不二之选。由于使用的人和公司多,Winform开发有大量博客可以参考,工作机会也很多,相比于其他开发平台更好找工作。(至于担心发布软件还需要安装net运行库,没有担心的必要,微软在系统中就自带来常用的net运动库,同时安装包安装程序的时候还可以检测是否缺net运行库,并引导安装)。

    5. WPF
      开发语言:C#
      开发工具:Visual Studio
      适用平台:WINDOWS ALL
      平台特点:WPF是在Winform的基础上,重新使用新框架开发的应用程序编程平台。对winform开发完全兼容。wpf引入了全新的界面布局框架XAML,可以轻松的创建出丰富美观的界面,同时可以使用高级的动画和特效,对屏幕自适应比winform更好。wpf使用DirectX来绘制控件(使用显卡绘制),winform使用GDI来绘制控件(使用CPU绘制),因此wpf现实效果好,且不会大量占用cpu。由于WPF比Winform所使用的技术新,目前还是使用Winform的多一些。当然想要软件最终效果好,更炫酷一点,那么你就选择WPF。

    6. Qt
      开发语言:C++ (编译器:linux: g++、macos: clang、win32: mingw、msvc)
      开发工具:Qt Creater、Visual Studio
      适用平台:WINDOWS ALL、Linux、 MacOS
      平台特点:Qt是一个跨平台应用程序开发框架,用于开发桌面程序、嵌入式程序和手机app。支持的操作系统平台包括:Linux, OS X, Windows, VxWorks, QNX, Android, iOS, BlackBerry, Sailfish OS等。Qt最大的特点是跨平台开发,即:一次编码多系统编译。就是说只写一次代码,然后把这个代码拿到各个系统上分别编译。即可生成各个系统下的原生应用程序(并不是java那种依赖运行库的跨平台)。因此Qt开发的应用程序在各个系统下都可以获得和原生应用程序同样的性能。其次Qt使用面向对象语言C++开发,因此运行效率比C#高。适用于开发一些需要大量运算的应用程序。比如图像处理软件,特效制作软件等。由于Qt使用C++语言编程,因此以前使用VC++写的老项目可以轻松使用
      Qt重新开发(C++库可以直接使用,之前C++代码写的逻辑函数可以复制过来直接使用)。这么好的平台为什么用的人和公司不太多呢。因为之前Qt是收费的,用于开发商业软件避免不了要交这个费用(不交钱法律上吃官司)。现在Qt支持LGPL协议,意味着可以免费开发商业软件了。qt也支持拖拽添加控件和布局软件页面。同时还支持使用qss动态修改控件样式。再加上Qt的layout动态布局功能。可以实现非常好看的软件。这一点比winform好。外观高度定制修改和wpf是一个水平。这里需要说明Qt编写程序跨平台编码的前提是统一使用Qt提供的系统库函数,如果你直接使用了Windows的系统库函数,那么这个程序就只能在windows下编译并使用了,除非你在其他系统上编译时候替换成其他系统相应功能的系统库函数。一般功能开发来说Qt提供的库函数足够丰富,除非是系统特有的功能需要Qt开发中特别处理。

    7. Android
      开发语言:Java
      开发工具:Android Studio
      适用平台:安卓手机、安卓平板、安卓电视等
      平台特点:安卓开发官方的开发平台就是Android Studio,是开发安卓app的官方指定平台。其他各个开发平台虽然也能开发安卓app,但是实际开发效果和Android Studio没法相比。因此你需要开发安卓的上位机客户端,就不要用杂七杂八的开发平台了,安心学习java和Android Studio吧。虽然现在的混合app开发技术很火爆,但是如果你的安卓app是配合硬件使用的,就不建议使用混合app开发技术了,因为使得项目使用的技术变复杂了,即便是你能搞定,对于后续接手的程序猿维护开发就不方便了(对于以硬件为主的公司而言)。需要任意一台电脑和测试手机或平板即可开发。

    8. IOS
      开发语言:Object-C、swift
      开发工具:Xcode
      适用平台:苹果手机、苹果平板
      平台特点:Xcode是开发IOS软件的唯一且官方的开发平台。如你公司的硬件设备需要开发IOS的app。那么这个开发平台几乎是唯一也是最好的选择。开发需要一台苹果电脑、一个公司或个人开发者账号(按年收费)、一台苹果手机或平板。

    9. LabVIEW
      开发语言:拖拽图形开发
      开发工具:LabVIEW
      适用平台:Wondows、MacOS、Linux
      平台特点:LabVIEW是一种程序开发环境,由美国国家仪器(NI)公司研制开发,LabVIEW与其他计算机语言的显著区别是:其他计算机语言都是采用基于文本的语言产生代码,而LabVIEW使用的是图形化编辑语言编写程序,产生的程序是框图的形式。LabVIEW开发环境集成了工程师和科学家快速构建各种应用所需的所有工具,旨在帮助工程师和科学家解决问题、提高生产力和不断创新。也就是说LabVIEW是帮助硬件开发工程师测试硬件的工具。通过拖拽画图即可运行出一个相当于上位的客户端。其集成的众多控件都是和硬件相关的,因此只适用于硬件开发测试,不适合其他任何上位软件开发。LabVIEW开发的软件也可以打包成独立的安装包。

    10. MATLAB
      开发语言:MATLAB
      开发工具:MATLAB
      适用平台:Wondows、MacOS、Linux
      平台特点:MATLAB是工程师和科学家使用的一个高级数学工具软件。虽然是个工具但是他具有开发图形交互界面以及计算机通信的全部功能。因此也在这里稍微介绍一下。MATLAB主要用于计算机视觉、信号处理、机器人等控制系统、模型设计以及算法验证。提供了Python、Java、C、C++等外部语言接口,可以供外部其他程序调用(用于调试与验证算法)。因此在开发特殊行业的上位机软件时候需要用到MATLAB。可以利用MATLAB单独开发一个测试上位机端,也可以和其他开发平台联合开发上位端。MATLAB支持把MATLAB算法转换成C/C++代码、HDL、和CUDA代码,便于算法的应用。

    二、硬件工程师做简单的上位机软件,应该选择哪个平台

    对于硬件开发工程师来说,想要做一个上位机软件无论你选哪个开发平台都不简单,就像要上位机程序猿开发嵌入式硬件一样难,都需要深入学习。除非你使用LabVIEW。

    由于硬件工程师做一个上位机一般需求也不会太复杂,他的需求就是“怎样用最少的精力开发一个基本能用的上位工具软件,我也不打算深入去开发专业的上位机软件”。

    根据这个需求,从最简单到复杂依次推荐的开发平台如下:

    1. LabVIEW:
    • 优点:投入最少的精力即可学会,而且可以快速开发出可用的上位机软件
    • 缺点:仅适合硬件特别相关的功能,不方便定制开发常用软件
    1. Qt:
    • 优点:可以满足所有高级软件功能开发。使用C++语言开发,与硬件开发者使用的C最接近,相对容易上手开发。这里不推荐GTK+,是因为GTK+虽然是使用C语言编程,更加方便硬件工程师开发,但是因为可参考的文档和例子太少,让硬件开发人员去读GTK官方文档并理解软件开发上的一些概念,实在不理智。这里不推荐VC++,是因为VC++毕竟老旧了各种类库也不如qt丰富,且学习VC++所需要的精力和学习Qt所用的精力没有多少区别。因此还不如学习更好的qt。现在也可以在网上找到很多qt的例子和博客,不用像以前担心参考示例太少。
    • 缺点:除了学习C++语法之外,还需要学习电脑软件开发的一些概念,以及学习Qt框架知识和Qt库函数使用方法
    1. C#WinForm:
    • 优点:可以满足所有高级软件功能开发。使用高级语言C#开发,开发效率高
    • 缺点:需要全新学习C#语言,以及电脑软件开发概念以及图形界面库函数功能

    三、开发商业软件应该选择哪个开发平台

    商业公司开发的软件是给众多客户使用的,软件的好坏对应着公司的收益。因此,开发商业软件要选择开发平台的时候,就比个人开发者面临的限制多很多。一般面临的限制如下:

    • 开发平台的普遍性:是否有很多人用,是否能随时招聘到对应平台的程序猿
    • 开发平台的稳定性:开发出来的软件是否稳定、安全、易用
    • 开发平台是否收费:是否收费也很重要,有些平台收费很贵,每卖一个软件都有交使用费用就很不合算
    • 开发平台是否持久:开发平台的公司是否对这个开发平台做持续维护和新技术更新

    以上为一个公司选择开发平台基本考虑要素。除此之外,所选平台只要能满足功能需求即可。

    目前满足以上基本考虑要素的PC软件(偏上位机软件)开发平台有:

    • C#_WinForm
    • C#_WPF
    • C++_QT
    展开全文
  • 2019年即将过去,这一年最值得开心、高兴的事就是我参与研发的“全自动生化分析仪”终于上市...因为这是我的第一个基于linux的商用上位机软件。虽然以前在windows平台折腾过java、C#、MFC的小上位机,但那些上位机无...
  • 所以本文则介绍一下使用visual studio软件,进行C#上位机软件的开发入门。以同学们常用的串口助手(简洁版)为例,来着手进行学习和入门。由于笔者知识有限,且是第一次写博客,有不足或错误之处,还...
  • 工控机上位机软件的开发历程(一)

    万次阅读 多人点赞 2018-10-17 16:56:02
    本人就职于一家环境监测公司,上位机软件的主要功能是采集各仪器的数据,然后存储起来,并传送到环保局平台。 刚到公司的时候,公司使用的是组态软件(用以显示流程图),然后再开发了报表软件、数据上传软件。因为...
  • 仪器归一化设计 这是具体内容的第一篇,我们先来讲述仪器的归一化设计。 仪器是各种功能都有的,我只举我们在环境监测这方面所用到的仪器。我们要测试水是不是有污染物质,污染到什么程度,我们要测试水体的高锰酸...
  • 1.7-工控上位机软件开发平台介绍

    千次阅读 2020-07-19 14:57:47
    前面几章一直没有提到上位机的另一个主要使用场合,即“工业上位机软件”。主要是因为本人没有接触过,不敢贸然发表见解类的文章。最近在机缘巧合下,对“工业上位机软件”有了一些初步的了解。在这里和大家分享一下...
  • C++实现串口通信上位机软件

    千次阅读 2018-08-08 15:12:41
    串口使用的是RS232总线进行通信,通信方式是半双工。有两种方式可以实现串口通信,一种是通过ActiveX控件这种方法程序简单,但欠灵活。第二个是可以通过调用Windows的API函数,本例程通过第二种方式。...
  • 工控上位机软件开发

    千次阅读 2019-05-31 12:05:50
    工控上位机软件开发全流程自研-上位机软件开发-工业级控制系统一、上位机软件开发底层设计二、上下位机通信的安全性三、上位机软件接收与存储研发四、数据清洗与图形展示研发五、上位机软件发送指令与回调六、上位机...
  • 1.参考文档:VC++-串口上位机编程实例 2文档地址:http://wenku.baidu.com/link?url=mokADmedzI2CD7b4hu8L3kTgTYKlxG52TcNdcfmbxceMXWipW95QEaQl959DJGmYBY7icMgw0dJSkIioeiut9xgtEwNrnamEOiOSNfkCq-C 制作的...
  • 上位机与三菱PLC通信

    千次阅读 2017-11-23 17:13:18
    这里着重介绍通过Mx Compment 软件通信: 首先打开下图这个软件 当设置链接完成后可以通过各种语言区链接与PLC通信了 可以区安装目录下C:\MELSEC\Act\Samples 找适合自己的开发语言来运行示例文件以便读写寄存器
  • Python上位机软件图形界面实战(1)

    千次阅读 2020-05-30 11:45:18
    引言 今天开始用python实战利用qt5开发软件图形界面 1 环境配置 在Pycharm界面左下角点击如图所示,打开终端分别输入pip install pyqt5,和pip install pyqt5-tools进行下载安装。 ...
  • C#上位机开发(一)—— 了解上位机

    万次阅读 多人点赞 2019-12-01 10:42:18
    在单片机项目开发中,上位机也是一个很重要的部分,主要用于数据显示(波形、温度等)、用户控制(LED,继电器等),下位机(单片机)与 上位机之间要进行数据通信的两种方式都是基于串口的: USB转串口 —— ...
  • VC++编写简单串口上位机程序

    万次阅读 多人点赞 2017-11-01 20:36:02
    VC++编写简单串口上位机程序 串口通信,MCU跟PC通信经常用到的一种通信方式,做界面、写上位机程序的编程语言、编译环境等不少,VB、C#、LABVIEW等等,我会的语言很少,C语言用得比较多,但是还没有找到如何用...
  • vs2013开发上位机软件和单片机通信

    千次阅读 2014-08-01 16:16:58
    3、设置上位机软件和单片机串口通信协议,主要是波特率,其他参数默认 4、调试 在单片机程序中设置一个提示,有上位机下发命名控制单片机 5、小结 上位机下发数据实现,单片机上传数据还要研究
  • RFID-上位机软件界面设计

    千次阅读 2017-12-20 13:51:34
    RFID-上位机软件界面设计
  • 很久没出没了,写了个上位机程序,主要体现3D效果,软件才学了一个月,做的不好,希望大家多提意见。。。。
1 2 3 4 5 ... 20
收藏数 11,115
精华内容 4,446
关键字:

上位机软件