当前位置:   article > 正文

C#上位机-简易版温室监测

c#上位机

目录

前言

上位机

下位机

需要实现的功能

上位机代码部分

下位机代码

个人心得


前言

        本学期我的上位机课程已经结束了,那么这次分享一下期末考核所做的一个简易版温室监测。首先先给大家介绍一下什么是上位机以及下位机。

上位机

        上位机是指控制系统中通过人机接口与操作者进行交互的计算机。它般用于监控、控制和调试下机(如工业机器人自动化设备等)的运行和行为。上位机可以通过图形界面、命令行或者其他形式提供给操作者一些控制和操作选项,同时也能够接收和显示下位机的数据和反馈信息。上位机通常具备一定的计算能力,能够处理和分析从下位机传输来的数据,并作出相应的决策和控制命令。

下位机

        下位机是指控制系统中与上位机相对应的计算机或者部件。它负责执行上位机发送的控制命令,并将执行结果或者反馈信息传输给上位机。下位机通常是一些嵌入式设备或者控制器,其主要任务是实时控制和操作外部设备,例如机器人的关节控制器、传感器读取器或者执行器。下位机一般采用专用硬件和实时操作系统,以保证稳定和准确的控制执行。上位机通过与下位机的连接,可以对下位机进行配置和监控,实时获取相关数据、调整控制参数,并对下位机进行控制。这次做的温室监测,也是用到下位机,我这边用的是一个51单片机。

需要实现的功能

        本次的温室监测,需要实现的功能有:喷灌(利用一个直流电机转动来模拟)、通风(利用一个直流电机转动来模拟)、采光(点亮单片机上的LED灯来模拟)、显示温度、声光报警。

 以上就是我们C#上位机的界面布局.

上位机代码部分

        首先是串口数据的接收

 在串口的接收事件里面编写以下代码

Thread.Sleep(20);//每间隔20ms接收一次数据
            this.Invoke(new EventHandler(delegate
            {
                try
                {
                    if (serialPort1.BytesToRead > 0)//当串口缓存区中有数据时
                    {
                        //以字符串方式读取所有接收到的数据
                        string Str = serialPort1.ReadExisting();
                        //将接收到的所有0x00替换成\0显示在界面上,因为0x00是一个控制字符,不会在文本框中显示
                        Str = Str.Replace("\0", "\\0");
                        //把16进制字符串转换成整数以字符串输出
                        txtTemperature.Text = Str + "℃";//把温度显示在文本框中
                                                        //在信息框中追加接收的数据,其中包括接收时间和接收内容
                        AppendTextToInfoBox("[" + DateTime.Now.ToString("HH:mm:s") + "]" + "收" + "<-", txtReceive);
                        AppendTextToInfoBox(Str + "℃" + "\r\n", txtReceive);
                        temp = float.Parse(Str);//获取温度
                    }

                }
                catch (Exception ex)
                {
                    //在信息框中追加异常信息
                    AppendTextToInfoBox("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "收" + "< -", txtReceive);
                    AppendTextToInfoBox(ex.Message + "\r\n", txtReceive);
                    AppendTextToInfoBox("数据接收错误!\r\n", txtReceive);
                }

            }));

 这部分是先从下位机接收到温度之后,把温度显示在文本框中。

喷灌按钮实现:

//判断串口是否打开
            if (serialPort1.IsOpen)
            {
                try
                {
                    if (SprayIrrigation == true)
                    {
                        btnSprayIrrigation.Text = "停止喷灌";
                        SprayIrrigation = false;
                        byte[] instruct = new byte[] { 0x06 };//创建数组存字节数组数据
                        serialPort1.Write(instruct, 0, instruct.Length); //数据写入端口

                    }
                    else
                    {
                        btnSprayIrrigation.Text = "喷灌";
                        SprayIrrigation = true;
                        byte[] instruct = new byte[] { 0x07 };//创建数组存字节数组数据
                        serialPort1.Write(instruct, 0, instruct.Length); //数据写入端口
                    }
                }
                catch (Exception ex)
                {
                    //在信息框中追加异常信息
                    AppendTextToInfoBox("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "收" + "< -", txtReceive);
                    AppendTextToInfoBox(ex.Message + "\r\n", txtReceive);
                }
            }
            else
            {
                //出现错误 提示
                MessageBox.Show("出现错误:\r\n串口是否打开!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

 按下按钮给下位机发送我们自定义的一个指令。

采光按钮实现:

 //判断串口是否打开
            if (serialPort1.IsOpen)
            {
                try
                {
                    if (Lighting == true)
                    {
                        btnLighting.Text = "停止采光";
                        Lighting = false;
                        byte[] instruct = new byte[] { 0x02 };//创建数组存字节数组数据
                        serialPort1.Write(instruct, 0, instruct.Length); //数据写入端口

                    }
                    else
                    {
                        btnLighting.Text = "采光";
                        Lighting = true;
                        byte[] instruct = new byte[] { 0x03 };//创建数组存字节数组数据
                        serialPort1.Write(instruct, 0, instruct.Length); //数据写入端口
                    }
                }
                catch (Exception ex)
                {
                    //在信息框中追加异常信息
                    AppendTextToInfoBox("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "收" + "< -", txtReceive);
                    AppendTextToInfoBox(ex.Message + "\r\n", txtReceive);
                }
            }
            else
            {
                //出现错误 提示
                MessageBox.Show("出现错误:\r\n串口是否打开!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

通风按钮实现:

//判断串口是否打开
            if (serialPort1.IsOpen)
            {
                try
                {
                    if (Ventilate == true)
                    {
                        btnVentilate.Text = "停止通风";
                        Ventilate = false;
                        byte[] instruct = new byte[] { 0x04 };//创建数组存字节数组数据
                        serialPort1.Write(instruct, 0, instruct.Length); //数据写入端口

                    }
                    else
                    {
                        btnVentilate.Text = "通风";
                        Ventilate = true;
                        byte[] instruct = new byte[] { 0x05 };//创建数组存字节数组数据
                        serialPort1.Write(instruct, 0, instruct.Length); //数据写入端口
                    }
                }
                catch (Exception ex)
                {
                    //在信息框中追加异常信息
                    AppendTextToInfoBox("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "收" + "< -", txtReceive);
                    AppendTextToInfoBox(ex.Message + "\r\n", txtReceive);
                }
            }
            else
            {
                //出现错误 提示
                MessageBox.Show("出现错误:\r\n串口是否打开!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

 那么这三个按钮的代码部分其实基本差不多,唯一不同的就是我们的指令,这个指令是根据我们自定义的指令,来选择发送,然后下位机接收到,进行判断是否为我们需要的一个指令,在进行下一步操作。

声光报警:

        

 //判断串口是否打开
            if (serialPort1.IsOpen)
            {
                try
                {  
                    if (txtUpperLimit.Text == "" || txtLowerLimit.Text == "")//文本框为空 提示错误
                    {
                        MessageBox.Show("出现错误:\r\n请检查文本框是否为空", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        txtUpperLimit.Text = "0"; //赋初始值
                        txtLowerLimit.Text = "0"; //赋初始值
                    }
                    else if (Lock_Unlock == true && txtUpperLimit.Text != "" && txtLowerLimit.Text != "")//按键按下
                    {
                        upper_limit = float.Parse(txtUpperLimit.Text); //获取上限温度
                        Lower_Limit = float.Parse(txtLowerLimit.Text); //获取下限温度
                        btnLock.Text = "已锁定";
                        txtUpperLimit.Enabled = false; //关闭文本框
                        txtLowerLimit.Enabled = false; //关闭文本框
                        Lock_Unlock = false; //按键状态
                        timer2.Start();//启动温度报警
                    }
                    else
                    {
                        Lock_Unlock = true;//按键状态
                        btnLock.Text = "锁定";
                        txtUpperLimit.Enabled = true; //文本框打开
                        txtLowerLimit.Enabled = true;//文本框打开
                        timer2.Stop();//关闭温度报警
                    }
                }
                catch (Exception ex)
                {
                    //在信息框中追加异常信息
                    AppendTextToInfoBox("[" + DateTime.Now.ToString("HH:mm:ss") + "]" + "收" + "< -", txtReceive);
                    AppendTextToInfoBox(ex.Message + "\r\n", txtReceive);
                    MessageBox.Show("出现错误:\r\n请检查文本框是否为空或者输入的不是数字!\r\n", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    btnLock.Text = "锁定";
                    txtUpperLimit.Enabled = true;//文本框打开
                    txtLowerLimit.Enabled = true;//文本框打开
                    txtUpperLimit.Text = ""; //清空
                    txtLowerLimit.Text = ""; //清空
                    timer1.Stop();//关闭串口工具异常检测
                    timer2.Stop();//关闭温度报警
                }
            }
            else
            {
                //出现错误 提示
                MessageBox.Show("出现错误:\r\n串口是否打开!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

这边是按下锁定按钮之后,然后把我们在文本框输入的上下限温度提取出来,然后打开定时器,那么定时器是干什么用的呢,这边是在定时器里面进行一个判断,当我们锁定之后,我们会在定时器里面进行判断,判断有没有超过上限或者低于下限,如果达成某一个条件,则定时器会给下位机一直发送一个指令,这个指令就是打开我们的蜂鸣器以及一个LED,来实现声光报警功能。

定时器代码部分:

 /当温度超过上限低于下限,发出声光警报指令给下位机
            if (temp > upper_limit || temp < Lower_Limit)
            {
                byte[] instruct = new byte[] { 0x01 };//创建数组存字节数组数据
                serialPort1.Write(instruct, 0, instruct.Length); //数据写入端口
            }

最后是利用注册表获取可用串口的部分:

 打开串口按钮部分:

        

下位机代码

         主函数:

串口中断部分:

 

 下位机通过在串口接收中断里面判断,接收的数据是否为我们需要的一个指令,是就存进一个数组,然后在数组里面判断我们的指令,来实现功能,而在主函数里面,我们首先要获取到我们的温度数据,然后通过公式计算出真正的温度值,通过串口发送给上位机,上位机接收到,通过转换成字符串,显示在文本框中。

个人心得

        我们的考核项目大概就那么多内容,经过这一次的考核之后,我也意识到自己的不足,我们自定义的指令,其实是最简单粗暴的,这部分的代码还可以优化的更好,做的更加精密,总的来说,上位机作为控制系统中重要的一环,为用户提供了方便快捷的操作界面和功能,使得用户可以方便地进行监控、调试和控制,提高了系统的灵活性和效率。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/398516
推荐阅读
相关标签
  

闽ICP备14008679号