工控机上位机软件的开发历程(五)

工控机上位机软件的开发历程(五)


思绪中断了,博客更新也中断了。现在补上。前面说了一些架构方面的事情,现在说一些具体一点的。

设备信息和因子信息

设备和因子是两个比较核心的概念,它们的结构设计,关系到整个系统。我们先来看设备信息的结构:

/// <summary>
/// 设备信息
/// </summary>
public class DeviceInfo
{
    /// <summary>
    /// 设备ID
    /// </summary>
    public int DeviceID { get; set; }
 
    /// <summary>
    /// 设备名称
    /// </summary>
    public string DeviceName { get; set; }
 
    /// <summary>
    /// 传输类型
    /// </summary>
    public TransferType TransferType { get; set; }
 
    #region 串口信息
 
    /// <summary>
    /// 串口号
    /// </summary>
    public string PortName { get; set; }
 
    /// <summary>
    /// 波特率
    /// </summary>
    public int BaudRate { get; set; }
 
    /// <summary>
    /// 校验位
    /// </summary>
    public Parity Parity { get; set; }
 
    /// <summary>
    /// 停止位
    /// </summary>
    public StopBits StopBits { get; set; }
 
    /// <summary>
    /// 数据位
    /// </summary>
    public int DataBits { get; set; }
 
    /// <summary>
    /// 从机地址
    /// </summary>
    public int SlaveAddr { get; set; }
 
    #endregion
 
    #region 网络传输信息
 
    /// <summary>
    /// 服务端IP地址
    /// </summary>
    public string ServerIP { get; set; }
 
    /// <summary>
    /// 服务端端口号
    /// </summary>
    public int ServerPort { get; set; }
 
    /// <summary>
    /// 客户端IP
    /// </summary>
    public string ClientIP { get; set; }
 
    /// <summary>
    /// 客户端端口号
    /// </summary>
    public int ClientPort { get; set; }
 
    #endregion
 
    /// <summary>
    /// 附加信息1
    /// </summary>
    public string Addition1 { get; set; }
 
    /// <summary>
    /// 附加信息2
    /// </summary>
    public string Addition2 { get; set; }
 
    /// <summary>
    /// 是否启用
    /// </summary>
    public bool IsEnable { get; set; }
 
    /// <summary>
    /// 使用协议
    /// </summary>
    public string UseProtocol { get; set; }
 
    /// <summary>
    /// 设备索引
    /// </summary>
    public int DeviceIndex { get; set; }
 
    /// <summary>
    /// 因子列表
    /// </summary>
    public List<FactorInfo> FactorList { get; set; }
}

传输类型是一个枚举类型,如下:

/// <summary>
/// 传输类型
/// </summary>
public enum TransferType
{
    /// <summary>
    /// 无传输
    /// </summary>
    None = 0,
 
    /// <summary>
    /// 串口传输
    /// </summary>
    Com = 1,
 
    /// <summary>
    /// TCP客户端
    /// </summary>
    Client = 11,
 
    /// <summary>
    /// TCP服务端
    /// </summary>
    Server = 12,
 
    /// <summary>
    /// UDP
    /// </summary>
    UDP = 22,
}

看到这里,可能有人会有疑问,为什么会有一个无传输的传输类型。实际上,在应用的时候有一种虚拟设备,只用来计算采集到的数据,它自己是不需要采集的。例如有一台流量计,它采集到的是瞬时流量。有时候我们需要累计流量的时候,就需要有这样一台不传输的设备。

串口信息应该不用解释。网络传输信息因为考虑到UDP,所以需要有两个IP和端口。

附加信息是一些特殊的设备,你根本想不到它还有一些什么属性,多两个这样的信息,可以避免不断修改类结构。

是否启用是在仪器维护的时候使用的。

设备索引是在设备表格里排序用的,实际上没什么作用。

在使用的时候,实际上很多时候我们要用到仪器的状态。例如串口断开了,我们应该有一个串口通信的状态。但我们可以看到,在上面的类结构里面,并没有这样的信息。其实,我们把所有状态都做成了因子,因子列表里总有一项代表仪器的某个状态。

接下来,我们看一下因子信息的设计:

/// <summary>
/// 因子信息
/// </summary>
public class FactorInfo
{
    /// <summary>
    /// 因子ID
    /// </summary>
    public int FactorID { get; set; }
 
    /// <summary>
    /// 因子名称
    /// </summary>
    public string FactorName { get; set; }
 
    /// <summary>
    /// 因子地址
    /// </summary>
    public string FactorAddr { get; set; }
 
    /// <summary>
    /// 表达式
    /// </summary>
    public string Expression { get; set; }
 
    /// <summary>
    /// 存储格式
    /// </summary>
    public StorageFormat StorageFormat { get; set; }
 
    /// <summary>
    /// 指令集
    /// </summary>
    public string CommandSet { get; set; }
 
    /// <summary>
    /// 因子值
    /// </summary>
    public double FactorValue { get; set; }
 
    /// <summary>
    /// 存储字段
    /// </summary>
    public string ValueField { get; set; }
 
    /// <summary>
    /// 数据库单位
    /// </summary>
    public short BaseUnit { get; set; }
 
    /// <summary>
    /// 显示单位
    /// </summary>
    public short DisplayUnit { get; set; }
 
    /// <summary>
    /// 显示小数位数
    /// </summary>
    public int DecimalDigit { get; set; }
 
    /// <summary>
    /// 报警上限
    /// </summary>
    public float AlarmUpper { get; set; }
 
    /// <summary>
    /// 报警下限
    /// </summary>
    public float AlarmLower { get; set; }
 
    /// <summary>
    /// 是否显示
    /// </summary>
    public bool IsDisplay { get; set; }
 
    /// <summary>
    /// 是否报表显示
    /// </summary>
    public bool IsReportDisplay { get; set; }
 
    /// <summary>
    /// 顺序索引
    /// </summary>
    public int FactorIndex { get; set; }
 
    /// <summary>
    /// 类型编码
    /// </summary>
    public string TypeCode { get; set; }
 
    /// <summary>
    /// 状态解析
    /// </summary>
    public string StateParser { get; set; }
 
    /// <summary>
    /// 附加信息1
    /// </summary>
    public string Addition1 { get; set; }
 
    /// <summary>
    /// 附加信息2
    /// </summary>
    public string Addition2 { get; set; }
}

因子信息其实更加复杂。在前面,我们提到过有五种因子,分别是实际因子、计算因子、状态因子、反控因子和模拟量因子。但在我们新的设计里,这样的概念变得模糊。我们遇到了很多新的问题,例如:

(1)实际因子并不一定是双寄存器浮点数。

(2)状态因子有可能也需要存储。

(3)在Modbus协议里面,离散量有两种,寄存器也有两种。

(4)没有固定的信息表示自动启动的类型。

(5)之前的状态解析需要额外加一个XML文件。

(6)量程并没有多大用处。

在说明之前,上面还有一个结构体需要列出来:

/// <summary>
/// 存储类型
/// </summary>
public enum StorageFormat
{
    /// <summary>
    /// 离散量只读
    /// </summary>
    BOOL_R = 1,
    /// <summary>
    /// 离散量只写
    /// </summary>
    BOOL_W = 2,
    /// <summary>
    /// 离散量读写
    /// </summary>
    BOOL_RW = 3,
 
    /// <summary>
    /// 单寄存器INT只读
    /// </summary>
    REGISTER_R = 301,
    /// <summary>
    /// 单寄存器INT只写
    /// </summary>
    REGISTER_W = 302,
    /// <summary>
    /// 单寄存器INT读写
    /// </summary>
    REGISTER_RW = 303,
 
    /// <summary>
    /// 单寄存器BOOL只读
    /// </summary>
    REGISTER_BOOL_R = 401,
    /// <summary>
    /// 单寄存器BOOL只写
    /// </summary>
    REGISTER_BOOL_W = 402,
    /// <summary>
    /// 单寄存器BOOL读写
    /// </summary>
    REGISTER_BOOL_RW = 403,
 
    /// <summary>
    /// 双寄存器REAL只读
    /// </summary>
    REAL_R = 201,
    /// <summary>
    /// 双寄存器REAL只写
    /// </summary>
    REAL_W = 202,
    /// <summary>
    /// 双寄存器REAL读写
    /// </summary>
    REAL_RW = 203,
 
    /// <summary>
    /// 其他
    /// </summary>
    OTHER = 101,
}

我们不再区分实际因子、计算因子和模拟量因子。在之前,这些因子默认的存储类型是双寄存器REAL只读,但实际上类型很多。之前的解决办法是先添加一个状态因子,然后再添加一个计算因子去读这个状态因子的值。这样实在有点累赘。在新的设计里面,因子默认类型是双寄存器REAL只读,当然这个类型是可以修改的。

实际因子和计算因子的区分,就是有没有填写表达式。如果表达式为空,则使用因子地址。否则,就使用表达式去计算。

量程这一概念,其实就是模拟量因子才用的。我们去掉了模拟量因子,同时去掉了量程。只需要在表达式里填入公式,就能实现模拟量因子。

我们来看看指令集CommandSet的设计。它解决了两个问题:

(1)有些设备用保持寄存器(03读),有些设备用输入寄存器(04)读。

(2)有些设备写一个要用06,有些一定要用10。

CommandSet默认是这样的:01,03,06,代表了离散量默认用01,寄存器读默认用03,寄存器写默认用06。遇到上面的问题,修改这里的值就行。

在之前的设计里面,只有实际因子、计算因子和模拟量因子是会存到数据库里面的,状态因子是一个过眼云烟。实际上一些状态因子也需要保存。这次设计引入了是否保存的概念。如果ValueField不为空,即是会存到数据库里的因子。

状态解析StateParser解决了每次都要外加一个XML文件的问题。我们知道,状态读取回来,是1、2、3、4这样的数字,它代表了什么呢?可能1代表待机,2代表测试中,3代表停止中,等等。这些文字我们之前是保存在一个XML文件里面,每次读取到数据时,用过这个文件去解析。有了StateParser,维护就方便多了。StateParser的格式大概如下:1:待机;2:测试中;3:停止中。

类型编码TypeCode是比较复杂的。它需要表示下面几种内容的东西:

(1)状态的类型,有些状态是普通的状态,有些是需要报警的状态,有些是设备的主要状态。通过在TypeCode里面输入T1、T2、T3完成。

(2)自动启动类型,在反控因子里使用。例如流程在运行的时候,到了整点,需要自动按下水样测试的按钮。那哪个反控因子是水样测试呢?通过名字去找?很多时候填写名字并没有那么认真。所以我们需要在TypeCode里输入:S1(水样测试)、S2(停止测试)、S3(标样核查)等等。

(3)发送什么数据,在反控因子里使用。我们点击按钮的时候,一般是向某个地址发送1的。但有些设备并不是1。那么我们可以在TypeCode里输入发送的内容,例如是N206、N0等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机开发说明简易工控机
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值