指令配置文件说明

指令配置文件说明

1.1 数据指令

数据指令分为三种,获取地址、控制指令和采集指令。
每个数据指令包括六个项,ID,名称、发送指令、接收指令、表示、单位。例如:

def command0:[68 11 68 76 00 04 00 33 78 01 03 1f 90 01 BA 16]
def command1:[68 11 68 76 00 04 00 33 78 81 16 1F 90 01 00 01 00 00 2C 00 00 00 00 2C 00 00 00 00 00 00 00 00 00 A6 16]

#ID  名称     发送指令        接收指令   表示    单位
0101 计量数据 $command0     $command1    1    m3

前面两行def 开头的表示定义函数。使用时可以用冒号前面的command0 代表冒号后面的指令。
第三行的’#’ 表示这一行是注释。后面分别注释对应各自的数据项,ID,名称、发送指令、接收指令、表示、单位.
第四行开始为数据指令,数据项之间用空格隔开。

  • ID: 为了统一定义了不同数据指令的ID,设备地址的指令ID为0000,上面的水表计量数据的ID是0101,高位的01 表示水表,02表示电表,03表示能量表,地位的01是水表计量数据。
  • 名称: 数据指令的名称,可以自己定义,尽量统一。
  • 发送指令 : 是指获取这条数据需要发送给仪表设备的指令
  • 接收指令: 是指获取这条数据接收到的指令。上面为方便理解写的是静态指令,实际中比较复杂。具体定义参考后面函数说明。
  • 表示: 是指这条数据实际表示。目前默认都写1。
  • 单位: 这条数据的单位,地址和控制指令没有单位可以写none,也可以不写。

但是仅定义数据项,只能使用静态的指令,这样无法在程序中获取数据,因此必须定义许多关键字和函数来提取其中的有效数据,达到一种协议只需要一个配置文件就可以解决所有问题的目的。

1.2 常量

主要包括16进制数字和10进制数字。16进制数字用0x 开头或H结尾,比如0x86 和 86H 都表示16进制的86。 如果是10进制,直接写成数字即可。10进制可以使用小数,16进制暂时不支持小数。

1.3 运算符号

  • []
    []表示将中间的数字合成指令,比如:
    [68H 11H 68H 76H 00H 04H 00H 33H 78H 01H 03H 1fH 90H 01H BAH 16H] 就是一条指令。
  • $
    表示后面是函数、变量或参数。例如:
    def func: ($1*$1 )%$2
    上面是定义了一个函数func,$1、$2 表示func的第一和第二个参数。在使用func时 需要这样: $func(16,256),这样$1 就是16, $2就是256代入表达式进行运算。
  • &
    与$ 相对,它后面跟的一般是函数或变量。但不立马进行计算,而是整个的作为参数。比如:

    def acount: $1%256
    $data(&acount,255)

    其中data 是关键字,它表示把255进行某种运算得出一个结果。这里传入acount 表示把255 作为acount的参数进行运算。
    而如果前面是$,必须这样调用 $acount(255) 得到的结果是一样的。
  • ()
    参数列表,比如:$func(16,256),参数之间用空格或逗号隔开。或者是一个表达式需要优先计算。比如 (2+3)*4

  • +,-,*,/,%
    分别是加减乘除,模运算。

1.4 函数

1.4.1 函数定义和使用

通过上面数据指令可以知道,仅仅靠数据指令有很多东西无法解决。比如设备地址、校验码、接收指令时数据的长度、数据内容都是不确定的,必须写成动态的指令格式。而且考虑到一种型号或同一种协议的设备只需要一个指令配置文件,写成静态指令会导致每个设备需要一个配置指令,会增加工作量。因此必须定义函数。
函数格式 def func: 表达式
函数调用 $func(参数1,参数2,…)
例如:

def  func: $bcd(($1)%$2  
def command0:[68H 11H $1 33H 78H 01H 07H $2 $func($ditch(4),256)  01H  $sum($group(0,$pos)) 16H]
$command0($addr,[1fH 90H 01H])

这个例子看起来比较复杂,但是了解了各个运算符号和内置函数的定义也并不难理解。
$command0($addr,[1fH 90H 01H]) 这是调用了command0 函数,有两个参数分别是$addr 和 [1fH 90H 01H] ,代入command0中的 $1 $2 ,$addr 是仪表地址,这由系统自动补充。
再来看 c o m m a n d 0 func 在上面已经定义,它是把第一个参数转化成bcd码与第二个参数求余,$ditch(4) 是关键字不是函数,后面会讲,$ditch(4)表示把接收到的指令从当前位置挖出4个字节作为$func的第一个参数。

后面还有sum,group pos 都是内置函数或变量。

1.4.2 内置函数

函数可以是用def 自定义的函数,也可以使用内置的函数。这些函数目前主要有以下几个:

  • reverse: 反转指令顺序,比如$reverse([01H 90H]) 得到的是[90H 01H],一般指令都是高位在前低位在后,但有时候可能是地位在前高位在后,这时候可以使用reverse
  • assign: 赋值运算 。 比如$assign(&len,5),表示把5赋值给一个变量len。第一个参数必须是&接的变量。assign 也起到了定义变量的作用。例如:
    def command: [16H $addr 78H 83H $assign(&length,$ditch(1)) $data($length,&sum) $ditch(2)]
    这里面 $assign 里定义了length的值,在$data 里就使用了length 。但要注意定义必须在使用之前。

以下函数有一个或三个参数,第一个参数是多字节指令,第二、三个参数(m,n)分别表示取出指令的从第m位开始的n个字节。
- int: 将指令转换成整数,例如int([01H 90H]),表示将指令[01H 90H] 转换成整数是400(计算01*16*16+9*16)
- float: 将指令转换成浮点数,即IEEE 754规范的浮点数,也是计算机本身的浮点数标准,例如float([01H 90H]),转换成浮点数是0.400
- sum: 将指令从第一个字节到最后一个进行累加求和。
- product: 将指令从第一个字节到最后一个进行累乘求积。
- bcd: 指令转换成BCD编码
- rbcd: bcd编码转换成指令

1.3 关键字

### 1.2.1 def
定义函数关键字,行开头使用def 表示定义函数。格式如下:
def func: ($1*$1)%$2
就表示定义了一个名称为func的函数,它至少应该有两个参数,分别用$1,$2代替。比如:func(16,256) $1就是16,$2就是256,那么,func(16,256)=16*16%256=1
需要注意不要在表达式内部有空格,为避免这个问题可以加上括号。比如 def func: (($1*$1)%$2)
### 1.2.2 ditch
本意表示挖。它的形式是$ditch(m,$do), 即挖出m个字节的指令,进行\$do运算,这里面的do可以是任何函数。
ditch用于接收指令分析。比如接收的指令是:

[68 11 68 76 00 04 00 33 78 81 16 1F 90 01 00 01 00 00 2C 00 00 00 00 2C 00 00 00 00 00 00 00 00 00 A6 16]

根据协议知道,第一个16 是它的数据长度,1F 90 01 后面的13个字节是其数据部分,我们需要把前4个字节提取出来转化成我们需要的计量数值,那么解析指令可以这样定义:

def measure: $bcd($1,0,4)/100.0
def command1: [68H 11H $ditch(8) $ditch(1,$assign(&len,$1-3)) $ditch(3) $ditch(4,$data(&measure,$1)) $ditch($len-4+2)]

command1里用到了多个ditch,第一个ditch(8),表示挖出8个字节的指令,但不做任何处理,即[68 76 00 04 00 33 78 81] 相当于被忽视。第二个ditch带两个参数,第一个参数是1,第二个嵌套了一个函数assign, 它表示挖出一个字节,即16H,然后将16H 减去3 赋值给len, 这时得到的len=13H。
紧接着又是ditch(3),即忽视接下来的三个字节。
再后面是挖出4个字节[00 01 00 00]交给data并作为$measure的参数进行运算就可以得到我们需要的结果。具体见data部分。

### 1.2.3 data
data 只能用于接收指令提取数据,比如水表的计量数据。它的第一个参数是一个&接的函数,第二个参数是第一个参数的参数。例如:
$ditch(4,$data(&measure,$1))

表示挖出4个字节的指令,作为data的第二个参数,第一个参数是自定义的函数measure,他是把一个多字节的指令转化成bcd码,然后除以100. measure的参数是data的第二个参数,即$1,也就是$ditch 挖到的4个字节指令[00 01 00 00]。计算的结果是100.00
注意: 发送指令不能使用ditch ,data 关键字

1.2.4 chk

用于校验。它有两个参数,即比较这两个参数是否相等,如果不相等会返回错误。

1.2.5 group

组合指令。是指对现有指令进行组合。在校验码字段进行累加求和时用到比较多。比如对从第0个字节开始到校验码之前所有的指令进行累加和,这时就可以使用$group(0,$pos) 得到从0到校验码之前的所有合并的指令。$pos 表示当前关键字在整个指令中的索引,从0开始计算,所以这里$pos 也表示指令的长度。即从0开始的连续$pos 个字节的指令进行合并。

1.2.5 pos

当前在指令中的位置。例如:
[86H 11H $group(1,$pos) 16H]
因为pos 是group的参数,group 在指令中的位置是2,那么pos=2. group(1,$pos) = [11H]

1.2.5 addr

仪表地址。

2.1 完整例子

这时hed型号仪表的完整指令配置

#型号HED09E3Y/C 

def crc16: $crc($1,0x8005,0xffff,0x0000,0)
def charge:$bcd($1)*0.1
#读寄存器   :地址      功能号   起始地址     长度           校验(crc16_modbus)
def command0: [$1        03H     $itom(2,$2)  $itom(2,$3)    $crc16($group(0,$pos))]

#应答       : 地址      功能号   数据长度                        数据                  校验
def command1: [$addr     03H     $ditch(1,$assign(&len,$1))     $data($1,$ditch($len)) $crc16($group(0,$pos))]
#01 03 04 00 00 00 00 FA 33 
def command2: [01H       03H     02H     $ditch(2,$assign(&addr,$int($1))) $crc16($group(0,$pos))]
#获取地址应答

0000   设备地址       $command0(01H 45H 1)   $command2           1  none

0110   正向有功电度   $command0($addr 36H 2) $command1(&charge)  1  kwh
0111   反向有功电度   $command0($addr 38H 2) $command1(&charge)  1  kwh
0112   正向无功电度   $command0($addr 3CH 2) $command1(&charge)  1  kvarh
0113   反向无功电度   $command0($addr 3EH 2) $command1(&charge)  1  kvarh

猜你喜欢

转载自blog.csdn.net/myxuan475/article/details/79849022