c#与西门子PLC1500基于sharp7通信学习2.利用WPF MVVM 读写DB块

1、利用wpf+mvvm作为上位机开发技术,通过读写分离的形式,启动一个线程来进行对DB块数据的读取显示;通过按钮事件对选中的字段向PLCDB块写入数据。


上位机界面



PLCDB块


复制DB块的文本到EXCEL中作为基础配置文件供上位机读取



项目目录

2:主要代码

2.1 View层

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:hc="https://handyorg.github.io/handycontrol"

        mc:Ignorable="d"

        DataContext="{Binding Source={StaticResource Locator},Path=Main}"

        Title="MainWindow"

          Loaded="Window_Loaded"

        WindowStartupLocation="CenterScreen"

        Style="{StaticResource WindowWin10}"

        ShowTitle="True"

        Height="450"

        Width="800"> 

   

       

           

           

           

       

       

           

               

           

               

       

           

           

       

   


using System;

using System.Collections.Generic;

using System.IO;

using System.Net;

using System.Runtime.InteropServices;

using System.Runtime.Serialization;

using System.Runtime.Serialization.Formatters.Binary;

using System.Threading;

using System.Threading.Tasks;

using CommonServiceLocator;

using HandyControlProject1.ViewModel;

using Sharp7;

namespace HandyControlProject1

{

    public partial class MainWindow

    {

        private CancellationTokenSource TokenSource;

        private Task CurrentTask;

        MainViewModel Main;

        S7Client client;

        S7Client.S7CpuInfo s7CpuInfo;

        S7Client.S7OrderCode s7OrderCode;   


        public MainWindow()

        {

            InitializeComponent();

            Main= ServiceLocator.Current.GetInstance();

            client = new Sharp7.S7Client();

            s7CpuInfo = new S7Client.S7CpuInfo();

            s7OrderCode = new S7Client.S7OrderCode();


            //PDU大小为默认为480,1500为960,1200、300为240,400为480,

            //此处用1500测试设置960。配置文件中的lenght长度应该小于Pdu-18,1500的length最大为942,

            //如果读取的长度大于942,可以拆分为多个包读取

            client.PduSizeRequested = 960;//设置pdu

            //默认为PG连接,设置为基本连接

            client.SetConnectionType(3);

        }


        private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e)

        {

        }     

        private void button_Click(object sender, System.Windows.RoutedEventArgs e)

        {

            if (!client.Connected)

            {

                //连接Plc

                var result = client.ConnectTo(this.textBox.Text, 0, 0);

                if (result == 0)

                {                 

                    client.GetCpuInfo(ref s7CpuInfo);

                    client.GetOrderCode(ref s7OrderCode);

                    this.textBlock.Text = ($"Connected to {this.textBox.Text},CPU类型:{s7CpuInfo.ModuleTypeName},订货号:{s7OrderCode.Code}");

                    this.button.Content = "断开连接";

                    //启动界面刷新线程

                    // create the cancellation token

                    TokenSource = new CancellationTokenSource();

                    CancellationToken token = TokenSource.Token;

                    // create the task

                    CurrentTask = Task.Factory.StartNew(() =>

                    {

                        while (true)

                        {

                            if (token.IsCancellationRequested)

                            {

                                setmessage("Task cancel detected");

                                break;

                            }

                            else

                            {

                                byte[] buffer = new byte[310];

                                int res= client.DBRead(3, 0, buffer.Length, buffer);

                                Console.WriteLine(client.ErrorText(res));

                                foreach (var item in Main.DB103TagList)

                                {

                                    switch (item.TagType)

                                    {

                                        case "Int":

                                            item.TagValue = S7.GetIntAt(buffer, (int)item.TagAddress).ToString();

                                            break;

                                        case "Bool":

                                            string[] address = item.TagAddress.ToString("0.0").Split('.');

                                            item.TagValue = S7.GetBitAt(buffer, int.Parse(address[0]), int.Parse(address[1])).ToString();

                                            break;

                                        default:

                                            break;

                                    }

                                }

                                setmessage(client.ExecutionTime.ToString());

                            }

                            Thread.Sleep(100);

                        }


                    }, token);                 

                }

                else

                {

                    this.textBlock.Text = (client.ErrorText(result));

                }

            }

            else

            {

                var result = client.Disconnect();

                if (result == 0)

                {

                    if (CurrentTask != null)

                    {

                        if (CurrentTask.Status == TaskStatus.Running) { }

                        {

                            TokenSource.Cancel();

                            setmessage("Task cancel");

                        }

                    }

                    this.textBlock.Text = ($"Disconnected from {this.textBox.Text}");

                    this.button.Content = "连接";

                }

                else

                {

                    this.textBlock.Text = (client.ErrorText(result));

                }

            }       

        }

        void setmessage(string message)

        {

            this.Dispatcher.Invoke(() =>

            {

                this.debugmsg.Text = message;

                this.cputime.Text = DateTime.Now.ToString();

            });

        }

        private void WriteTagValue_Click(object sender, System.Windows.RoutedEventArgs e)

        {

            if (Main.SelectedTag != null)

            {

                string[] address = Main.SelectedTag.TagAddress.ToString("0.0").Split('.');

                int zhengshu = int.Parse(address[0]);

                int xiaoshu = int.Parse(address[1]);

                int gewei = int.Parse(address[0]) % 10;             

                switch (Main.SelectedTag.TagType)

                {

                    case "Int":

                        byte[] buff = new byte[2];

                        int res= client.DBRead(3, zhengshu, buff.Length, buff);

                        if (res == 0)

                        {

                            S7.SetIntAt(buff, 0, short.Parse(this.txtTagValue.Text));

                            client.DBWrite(3, zhengshu, buff.Length, buff);

                        }                       

                        break;

                    case "Bool":

                        byte[] buffbit = new byte[1];

                        int resbit = client.DBRead(3, zhengshu, buffbit.Length, buffbit);

                        if (resbit == 0)

                        {

                            S7.SetBitAt(ref buffbit, 0, xiaoshu, this.txtTagValue.Text == "1" ? true : false);

                            client.DBWrite(3, zhengshu, buffbit.Length, buffbit);

                        }                       

                        break;

                    default:

                        break;

                }               

            }

        }

    }

}

2.2 ViewModel层

using GalaSoft.MvvmLight;

using HandyControlProject1.Model;

using System.Collections.Generic;

using System.Diagnostics;

using System.IO;

namespace HandyControlProject1.ViewModel

{

    ///

    /// This class contains properties that the main View can data bind to.

    ///

    /// Use the mvvminpc snippet to add bindable properties to this ViewModel.

    ///

    ///

    /// You can also use Blend to data bind with the tool's support.

    ///

    ///

    /// See http://www.galasoft.ch/mvvm

    ///

    ///

    public class MainViewModel : ViewModelBase

    {

        ///

        /// Initializes a new instance of the MainViewModel class.

        ///

        public MainViewModel()

        {

            ////if (IsInDesignMode)

            ////{

            ////    // Code runs in Blend --> create design time data.

            ////}

            ////else

            ////{

            ////    // Code runs "for real"

            ////}

            ///

            string appStartupPath = System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);

            string filePath = appStartupPath+@"\DB103.csv";

            FileStream fileStream = new FileStream(filePath,FileMode.Open,FileAccess.Read);

            StreamReader reader = new StreamReader(fileStream, System.Text.Encoding.Default);         

            string str = null;

            DB103TagList = new List();

            while ((str = reader.ReadLine()) != null)

            {

                Tags tag = new Tags();

                string[] strs = str.Split(',');

                if (strs.Length == 3)

                {

                    tag.TagName = strs[0].ToString();

                    tag.TagType = strs[1].ToString();

                    tag.TagAddress = double.Parse(strs[2].ToString());

                    DB103TagList.Add(tag);

                }                             

            }

            reader.Close();

            fileStream.Close();

        }

        private List _DB103TagList;

        public List DB103TagList

        {

            get { return _DB103TagList; }

            set { _DB103TagList = value;

                RaisePropertyChanged();

            }

        }

        private Tags _SelectedTag;

        public Tags SelectedTag

        {

            get { return _SelectedTag; }

            set { _SelectedTag = value;

                RaisePropertyChanged();

            }

        }

    }

}

2.3 Model

using GalaSoft.MvvmLight;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace HandyControlProject1.Model

{

    public class Tags:ObservableObject

    {

        private string _TagName;

        public string TagName

        {

            get { return _TagName; }

            set { _TagName = value;

                RaisePropertyChanged(()=>TagName);

            }

        }

        private string _TagType;

        public string TagType

        {

            get { return _TagType; }

            set { _TagType = value;

                RaisePropertyChanged(() => TagType);

            }

        }

        private double _TagAddress;

        public double TagAddress

        {

            get { return _TagAddress; }

            set { _TagAddress = value;

                RaisePropertyChanged(() => TagAddress);

            }

        }

        private string _TagValue;

        public string TagValue

        {

            get { return _TagValue; }

            set { _TagValue = value;

                RaisePropertyChanged(() => TagValue);

            }

        }

    }

}


3.需要注意的问题

当多线程进行数据读取和数据写入时,会出现线程交叉访问导致数据读写异常的情况,可以修改sharp7源代码在DBRead和DBWrite函数中加锁处理该问题。

         private static object objlock = new object();

        public int DBRead(int DBNumber, int Start, int Size, byte[] Buffer)

        {

            lock (objlock)

            {

                return ReadArea(S7Consts.S7AreaDB, DBNumber, Start, Size, S7Consts.S7WLByte, Buffer);

            }


        }

        public int DBWrite(int DBNumber, int Start, int Size, byte[] Buffer)

        {

            lock (objlock)

            {

                return WriteArea(S7Consts.S7AreaDB, DBNumber, Start, Size, S7Consts.S7WLByte, Buffer);

            }

        }

你可能感兴趣的:(c#与西门子PLC1500基于sharp7通信学习2.利用WPF MVVM 读写DB块)