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

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

上位机界面

PLCDB块

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

项目目录

2:主要代码

2.1 View层

<hc:Window x:Class="HandyControlProject1.MainWindow"

        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"> 

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="50" />

            <RowDefinition />

            <RowDefinition Height="20" />

        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Orientation="Horizontal">

            <Button x:Name="button" Click="button_Click" Content="Connect" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Center" Width="75" />

            <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="5" TextWrapping="Wrap" Text="192.168.1.140" VerticalAlignment="Center" Width="120"/>

            <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="5" TextWrapping="Wrap" Text="" VerticalAlignment="Center"/>

        </StackPanel>

        <Grid Grid.Row="1">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="5*" />

                <ColumnDefinition Width="*" />

            </Grid.ColumnDefinitions>

            <DataGrid Grid.Column="0" SelectedItem="{Binding SelectedTag}" ItemsSource="{Binding DB103TagList}" />

            <Border Grid.Column="1" Background="Gray" BorderBrush="White" BorderThickness="1" CornerRadius="5">

                <StackPanel Orientation="Vertical">

                    <TextBlock Foreground="Yellow" FontSize="18" Text="{Binding SelectedTag.TagName}"></TextBlock>

                    <TextBox Margin="0,5" x:Name="txtTagValue"></TextBox>

                    <Button Margin="0,5" x:Name="WriteTagValue" Content="写入" Click="WriteTagValue_Click"></Button>

                </StackPanel>

            </Border>

        </Grid>       

        <StackPanel Grid.Row="2" Orientation="Horizontal">

            <TextBlock x:Name="cputime"></TextBlock>

            <TextBlock x:Name="debugmsg" Margin="10,0"></TextBlock>

        </StackPanel>

    </Grid>

</hc:Window>

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<MainViewModel>();

            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

{

    /// <summary>

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

    /// <para>

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

    /// </para>

    /// <para>

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

    /// </para>

    /// <para>

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

    /// </para>

    /// </summary>

    public class MainViewModel : ViewModelBase

    {

        /// <summary>

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

        /// </summary>

        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<Tags>();

            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<Tags> _DB103TagList;

        public List<Tags> 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);

            }

        }



作者:7b8b7b0e4e65
链接:https://www.jianshu.com/p/d917cba22543
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值