Modbus TCP&modbus rtu协议库 上位机开发/修复04功能码

axuanup 3月前 775

import win.ui;
import sys.comPort;
import modbus.modbustcp;
import wsock.tcp.client;
/*DSG{{*/
mainForm = win.form(text="zmodbus";right=663;bottom=623)
mainForm.add(
button={cls="button";text="01功能码";left=8;top=568;right=96;bottom=600;db=1;dl=1;z=68};
button2={cls="button";text="02功能码";left=128;top=568;right=216;bottom=600;db=1;dl=1;z=69};
button3={cls="button";text="03功能码";left=248;top=568;right=336;bottom=600;db=1;dl=1;z=70};
button4={cls="button";text="04功能码";left=360;top=568;right=448;bottom=600;db=1;dl=1;z=71};
["button_COM_断开"]={cls="button";text="断开连接";left=456;top=208;right=544;bottom=240;dr=1;dt=1;z=67};
["button_COM_连接"]={cls="button";text="连接从机";left=352;top=208;right=440;bottom=240;dr=1;dt=1;z=66};
["button_TCP_断开"]={cls="button";text="断开连接";left=152;top=208;right=240;bottom=240;dl=1;dt=1;z=65};
["button_TCP_连接"]={cls="button";text="连接从机";left=48;top=208;right=136;bottom=240;dl=1;dt=1;z=64};
["button_写单个寄存器"]={cls="button";text="写单个寄存器";left=384;top=488;right=472;bottom=520;db=1;dr=1;z=52};
["button_写单个线圈"]={cls="button";text="写单个线圈";left=64;top=488;right=152;bottom=520;db=1;dl=1;z=34};
["button_写多个寄存器"]={cls="button";text="写多个寄存器";left=544;top=488;right=632;bottom=520;db=1;dr=1;z=59};
["button_写多个线圈"]={cls="button";text="写多个线圈";left=224;top=488;right=312;bottom=520;db=1;dl=1;z=41};
["button_读单个寄存器"]={cls="button";text="读单个寄存器";left=384;top=448;right=472;bottom=480;db=1;dr=1;z=51};
["button_读单个线圈"]={cls="button";text="读单个线圈";left=64;top=448;right=152;bottom=480;db=1;dl=1;z=33};
["button_读多个寄存器"]={cls="button";text="读多个寄存器";left=544;top=448;right=632;bottom=480;db=1;dr=1;z=58};
["button_读多个线圈"]={cls="button";text="读多个线圈";left=224;top=448;right=312;bottom=480;db=1;dl=1;z=40};
["combobox_串口号"]={cls="combobox";left=352;top=96;right=432;bottom=120;dr=1;dt=1;edge=1;items={};mode="dropdown";z=18};
["combobox_停止位"]={cls="combobox";left=352;top=168;right=432;bottom=192;dr=1;dt=1;edge=1;items={};mode="dropdown";z=27};
["combobox_数据位"]={cls="combobox";left=352;top=136;right=432;bottom=160;dr=1;dt=1;edge=1;items={};mode="dropdown";z=26};
["combobox_校验位"]={cls="combobox";left=488;top=136;right=568;bottom=160;dr=1;dt=1;edge=1;items={};mode="dropdown";z=23};
["combobox_波特率"]={cls="combobox";left=488;top=96;right=568;bottom=120;dr=1;dt=1;edge=1;items={};mode="dropdown";z=19};
edit_COM_id={cls="edit";text="1";left=352;top=64;right=432;bottom=88;dr=1;dt=1;edge=1;num=1;z=14};
edit_COM_timer={cls="edit";text="200";left=488;top=168;right=568;bottom=192;dr=1;dt=1;edge=1;num=1;z=25};
edit_TCP_id={cls="edit";text="1";left=72;top=56;right=216;bottom=80;dl=1;dt=1;edge=1;num=1;z=6};
edit_TCP_ip={cls="edit";text="192.168.1.143";left=72;top=96;right=216;bottom=120;dl=1;dt=1;edge=1;z=7};
edit_TCP_port={cls="edit";text="502";left=72;top=136;right=216;bottom=160;dl=1;dt=1;edge=1;num=1;z=8};
edit_TCP_timer={cls="edit";text="200";left=72;top=168;right=216;bottom=192;dl=1;dt=1;edge=1;num=1;z=9};
["edit_单个线圈值"]={cls="edit";text="0";left=88;top=344;right=152;bottom=368;db=1;dl=1;edge=1;num=1;z=32};
["edit_单个线圈地址"]={cls="edit";text="0";left=88;top=312;right=152;bottom=336;db=1;dl=1;edge=1;num=1;z=31};
["edit_单寄存器值"]={cls="edit";text="0";left=408;top=344;right=472;bottom=368;db=1;dr=1;edge=1;num=1;z=50};
["edit_单寄存器地址"]={cls="edit";text="0";left=408;top=312;right=472;bottom=336;db=1;dr=1;edge=1;num=1;z=49};
["edit_多寄存器地址"]={cls="edit";text="0";left=576;top=312;right=632;bottom=336;db=1;dr=1;edge=1;num=1;z=56};
["edit_多寄存器地址个数"]={cls="edit";text="2";left=576;top=344;right=632;bottom=368;db=1;dr=1;edge=1;num=1;z=57};
["edit_多寄存器地址值1"]={cls="edit";text="0";left=576;top=376;right=632;bottom=400;db=1;dr=1;edge=1;num=1;z=62};
["edit_多寄存器地址值2"]={cls="edit";text="0";left=576;top=408;right=632;bottom=432;db=1;dr=1;edge=1;num=1;z=63};
["edit_多线圈值1"]={cls="edit";text="0";left=248;top=376;right=312;bottom=400;db=1;dl=1;edge=1;num=1;z=44};
["edit_多线圈值2"]={cls="edit";text="0";left=248;top=408;right=312;bottom=432;db=1;dl=1;edge=1;num=1;z=45};
["edit_多线圈地址"]={cls="edit";text="0";left=248;top=312;right=312;bottom=336;db=1;dl=1;edge=1;num=1;z=38};
["edit_多线圈数量"]={cls="edit";text="2";left=248;top=344;right=312;bottom=368;db=1;dl=1;edge=1;num=1;z=39};
groupbox={cls="groupbox";text="以太网主机";left=8;top=16;right=256;bottom=248;dl=1;dt=1;edge=1;z=1};
groupbox2={cls="groupbox";text="串口主机";left=272;top=16;right=640;bottom=248;dl=1;dr=1;dt=1;edge=1;z=10};
groupbox3={cls="groupbox";text="单个线圈操作";left=8;top=272;right=160;bottom=528;db=1;dl=1;edge=1;z=28};
groupbox5={cls="groupbox";text="多个线圈操作";left=168;top=272;right=320;bottom=528;db=1;dl=1;edge=1;z=35};
groupbox6={cls="groupbox";text="单个寄存器操作";left=328;top=272;right=480;bottom=528;db=1;dr=1;edge=1;z=46};
groupbox7={cls="groupbox";text="多个寄存器操作";left=488;top=272;right=640;bottom=528;db=1;dr=1;edge=1;z=53};
radiobutton_ASCII={cls="radiobutton";text="ASCII";left=576;top=64;right=632;bottom=88;dr=1;dt=1;z=16};
radiobutton_RTU={cls="radiobutton";text="RTU";left=512;top=64;right=568;bottom=88;dr=1;dt=1;z=15};
static={cls="static";text="ID";left=32;top=56;right=56;bottom=80;center=1;dl=1;dt=1;transparent=1;z=2};
static10={cls="static";text="工作方式";left=440;top=64;right=496;bottom=88;center=1;dr=1;dt=1;transparent=1;z=20};
static11={cls="static";text="波特率";left=440;top=96;right=480;bottom=120;center=1;dr=1;dt=1;transparent=1;z=21};
static12={cls="static";text="校验位";left=440;top=136;right=480;bottom=160;center=1;dr=1;dt=1;transparent=1;z=22};
static13={cls="static";text="超时";left=440;top=168;right=480;bottom=192;center=1;dr=1;dt=1;transparent=1;z=24};
static14={cls="static";text="线圈地址";left=16;top=312;right=72;bottom=336;center=1;db=1;dl=1;transparent=1;z=29};
static15={cls="static";text="线圈值";left=16;top=344;right=64;bottom=368;center=1;db=1;dl=1;transparent=1;z=30};
static18={cls="static";text="线圈地址";left=176;top=312;right=232;bottom=336;center=1;db=1;dl=1;transparent=1;z=36};
static19={cls="static";text="线圈个数";left=176;top=344;right=232;bottom=368;center=1;db=1;dl=1;transparent=1;z=37};
static2={cls="static";text="IP";left=32;top=96;right=56;bottom=120;center=1;dl=1;dt=1;transparent=1;z=3};
static20={cls="static";text="线圈(1)值";left=176;top=376;right=232;bottom=400;center=1;db=1;dl=1;transparent=1;z=42};
static21={cls="static";text="线圈(2)值";left=176;top=408;right=232;bottom=432;center=1;db=1;dl=1;transparent=1;z=43};
static22={cls="static";text="寄存器地址";left=336;top=312;right=400;bottom=336;center=1;db=1;dr=1;transparent=1;z=47};
static23={cls="static";text="寄存器值";left=336;top=344;right=400;bottom=368;center=1;db=1;dr=1;transparent=1;z=48};
static26={cls="static";text="寄存器地址";left=496;top=312;right=568;bottom=336;center=1;db=1;dr=1;transparent=1;z=54};
static27={cls="static";text="寄存器个数";left=496;top=344;right=568;bottom=368;center=1;db=1;dr=1;transparent=1;z=55};
static28={cls="static";text="寄存器(1)值";left=496;top=376;right=568;bottom=400;center=1;db=1;dr=1;transparent=1;z=60};
static29={cls="static";text="寄存器(2)值";left=496;top=408;right=568;bottom=432;center=1;db=1;dr=1;transparent=1;z=61};
static3={cls="static";text="端口号";left=32;top=136;right=56;bottom=160;center=1;dl=1;dt=1;transparent=1;z=4};
static4={cls="static";text="超时";left=32;top=168;right=64;bottom=192;center=1;dl=1;dt=1;transparent=1;z=5};
static5={cls="static";text="ID";left=296;top=64;right=320;bottom=88;center=1;dl=1;dt=1;transparent=1;z=11};
static7={cls="static";text="数据位";left=296;top=136;right=336;bottom=160;center=1;dl=1;dr=1;dt=1;transparent=1;z=12};
static8={cls="static";text="停止位";left=296;top=168;right=336;bottom=192;center=1;dl=1;dr=1;dt=1;transparent=1;z=13};
static9={cls="static";text="串口号";left=296;top=96;right=336;bottom=120;center=1;dl=1;dr=1;dt=1;transparent=1;z=17}
)
/*}}*/

mainForm.combobox_串口号.items = sys.comPort.list()

mainForm.combobox_串口号.selIndex = 1;

mainForm.edit_TCP_ip.text = "127.0.0.1"
var handle;
var m = modbus.modbustcp();

mainForm.button_TCP_连接.oncommand = function(id, event) {
    var ip = mainForm.edit_TCP_ip.text;
    var port = mainForm.edit_TCP_port.text;
    var timeout = mainForm.edit_TCP_timer.text;
    
    var v = wsock.tcp.client.test(ip);
    
    if (type(v) == "string") {
        if handle
        return;
        handle = m.tcpConnect(ip, port, timeout);
        if (handle) {
            win.msgbox("连接成功")
        }
        else {
            win.msgbox("连接失败")
        }
    }
    else {
        win.msgbox("连接失败")
    }
}

mainForm.button_TCP_断开.oncommand = function(id, event) {
    
    if (handle) {
        m.closeConnect();
        handle = null;
        win.msgbox("断开成功")
    }
    
}

mainForm.button_读单个线圈.oncommand = function(id, event) {
    var id = mainForm.edit_TCP_id.text
    var addr = mainForm.edit_单个线圈地址.text;
    var v = m.readCoils(id, addr, 1)
    mainForm.edit_单个线圈值.text = v[1];
}

mainForm.button_写单个线圈.oncommand = function(id, event) {
    var id = mainForm.edit_TCP_id.text
    var addr = mainForm.edit_单个线圈地址.text;
    var v = mainForm.edit_单个线圈值.text;
    m.writeSingle(id, addr, v)
    
}

mainForm.button_读多个线圈.oncommand = function(id, event) {
    
    var addr = mainForm.edit_多线圈地址.text;
    var num = mainForm.edit_多线圈数量.text;
    var id = mainForm.edit_TCP_id.text
    var v = m.readCoils(id, addr, num)
    console.dump(v)
    mainForm.edit_多线圈值1.text = v[1];
    mainForm.edit_多线圈值2.text = v[2];
    
}

mainForm.button_写多个线圈.oncommand = function(id, event) {
    
    var id = mainForm.edit_TCP_id.text
    var addr = mainForm.edit_多线圈地址.text;
    var v1 = mainForm.edit_多线圈值1.text;
    var v2 = mainForm.edit_多线圈值2.text;
    m.writeMultipleCoils(id, addr, 2, {
        v1;v2
    })
    
}

mainForm.button_读单个寄存器.oncommand = function(id, event) {
    var addr = mainForm.edit_单寄存器地址.text;
    var regValue = mainForm.edit_单寄存器值.text;
    var id = mainForm.edit_TCP_id.text
    var v = m.readHoldingRegisters(id, addr, 1)
    mainForm.edit_单寄存器值.text = tonumber(v[1], 16);
}

mainForm.button_写单个寄存器.oncommand = function(id, event) {
    var addr = mainForm.edit_单寄存器地址.text;
    var regValue = mainForm.edit_单寄存器值.text;
    var id = mainForm.edit_TCP_id.text
    m.writeSingleRegister(id, addr, tonumber(regValue))
}

mainForm.button_读多个寄存器.oncommand = function(id, event) {
    var addr = mainForm.edit_多寄存器地址.text;
    var regValue = mainForm.edit_多寄存器地址个数.text;
    var id = mainForm.edit_TCP_id.text
    var v = m.readHoldingRegisters(id, addr, regValue)
    console.dump(v)
    mainForm.edit_多寄存器地址值1.text = tonumber(v[1], 16)
    mainForm.edit_多寄存器地址值2.text = tonumber(v[2], 16)
}

mainForm.button_写多个寄存器.oncommand = function(id, event) {
    var v1 = tonumber(mainForm.edit_多寄存器地址值1.text);
    var v2 = tonumber(mainForm.edit_多寄存器地址值2.text);
    var id = mainForm.edit_TCP_id.text
    m.writeMultipleRegisters(id, 0, 2, {
        v1;v2
    })
}


mainForm.button.oncommand = function(id,event){
	//01功能码读
	console.dump(m.readCoils(1,0,10));
}

mainForm.button2.oncommand = function(id,event){
	//02功能码读
	console.dump(m.readDiscreteInputs(1,0,10))
}

mainForm.button3.oncommand = function(id,event){
	//03功能码读
	console.dump(m.readHoldingRegisters(1,0,10))
}

mainForm.button4.oncommand = function(id,event){
	//04功能码读
	console.dump(m.readInputRegisters(1,0,10))
}

mainForm.show();
return win.loopMessage();

1、修复04功能码获取不到数据问题

感谢@13500720415 朋友的反馈

上传的附件:
最新回复 (27)
  • 13500720415 3月前
    0 2

  • 13500720415 3月前
    0 3
    很遗憾,本次修改仍未成功,按04按钮,出现的问题和以前的一模一样
  • 13500720415 3月前
    0 4
    另外,第95行:var v = wsock.tcp.client.test(ip); 点击连接按钮,出现“连接2失败”,第109行;我填上(ip,port,timeout)后,就链接成功了。
  • axuanup 3月前
    0 5
    可以的
  • axuanup 3月前
    0 6

  • axuanup 3月前
    0 7
    自己研究吧
  • 小光芒 3月前
    0 8
    顶一个
  • 13500720415 3月前
    0 9

    是不是我的环境出现了问题?请帮忙指导一下

    错误行号:#77  为     self.ZMB_ReadInputReg(this.handle, id, addr, count, buff, 0)   

    错误参数:@5 为  buff  

    整个程序均为在论坛上复制的,数据是从现场实际得到的

    除04功能码以外,其他按钮全部正常。


  • 13500720415 3月前
    0 10
    你用的证明04功能码好用的软件,不是你提供的这个案例,
  • axuanup 3月前
    0 11
    你提供你的案例工程,以及读的寄存器。
  • axuanup 3月前
    0 12
    你把库替换掉呀
  • axuanup 3月前
    0 13
    或者是你自己用仿真软件测试
  • 13500720415 3月前
    0 14
    咱俩搞误会了,我这儿有一个远程遥测的实际现场,用组态软件一直在正常运转好多年了,出于好奇心,我这个编程的老白照葫芦画瓢,用python的modbus_tk.modbustcp编程来采集modbus数据,居然很成功,去年末在做桌面界面时 发现了aardio ,这个软件对我们初学者简直太友好了,当看到你这个工程案例特别高兴,就将你的这个案例套在上位机上用了一下,于是就发现了我提出来的问题,因为是初学,还没有能力把库换掉,我曾试过用aardio + python 结合起来,但是不太会用,目前我正在学习这方面的知识,希望能得到你的帮助。
  • 13500720415 3月前
    0 15
    此楼层已删除
  • 13500720415 3月前
    0 16
    python 目前主流使用操作modbus协议的库有三个: pymodbus 使用twisted实现的modbus完整协议(支持异步通讯); MinimalModbus 只支持modbusrtu ;modbus_tk 完整modbus协议栈的实现,支持modbus tcp/rtu{1.提供slave模拟器,即模拟modbus server:502), web-based hmi master支持}。 aardio 的 modbus 库,我只见到你引用的这个库 import modbus.modbustcp; 而 import wsock.tcp.client; 我认为是客户端的库,我没有再见到aardio里的另外的modbus的库可替换。
  • 13500720415 3月前
    0 17

    终于发现了一点端倪,

    从下面的语句中,可以看到 #77 和 #64 是完全相同的,只是寄存器的名称不同,程序报告,问题出在 #77 的 @5 参数上。

    而在后面中 @5 又出现了不同的参数

    我不知道如何去处理,估计问题出在这里,请帮忙解决为盼



  • 13500720415 3月前
    0 18

    周立功的modbus 协议关于#03,#04的 @5 参数是这样写的:

    参见《 ZModbusSdk 配置函数库使用手册    V 1.07  》

    视乎与 aardio 的 modbus 协议中,@5参数 略有不同

    self.ZMB_ReadHoldReg(this.handle, id, addr, count, buff, 0)

    self.ZMB_ReadInputReg(this.handle, id, addr, count, buff, 0)


    ZMB_ReadHoldReg = dll.api( /*03功能码读保持寄存器*/ "ZMB_ReadHoldReg", "int( INT hand, BYTE serID, int nStart, int nCount, string &bRet, WORD TranID)");

    ZMB_ReadInputReg = dll.api( /*04功能码读输入寄存器*/ "ZMB_ReadInputReg", "int( INT hand, BYTE serID, int nStart, int nCount, WORD & Ret, WORD TranID)");


    long ZMB_ReadHoldReg ( HANDLE hand, BYTE serID, int nStart, int nCount, WORD * bRet/*arr of reg*/, WORD TranID);

    long ZMB_ReadInputReg ( HANDLE hand, BYTE serID, int nStart, int nCount, WORD * Ret/*arr of reg*/, WORD TranID);

        总的来说,对于#03指令,可以正常运行。

    而对于#04号指令,aardio 的 modbus 协议,@5参数在上下文有不同,而且与周立功的modbus y也有区别。

    供参考。


  • 13500720415 2月前
    0 19

    再啰嗦几句,我用aardio标准库的modbustcp协议库,和用aardio通过python的第三方库modbus_tk,进行采集现场数据对比,感觉速度上前者要比后者快很多,只可惜我们的标准库#04指令有问题,无法运行,以下是我的测试程序:

    import win.ui;

    /*DSG{{*/

    var winform = win.form(text="aardio form";right=759;bottom=469)

    winform.add(

    button={cls="button";text="调用 python 执行 modbus 数据采集";left=24;top=64;right=376;bottom=144;border=1;color=14120960;db=1;dr=1;font=LOGFONT(h=-14);note="每次点击都会重绘一次";z=2};

    button2={cls="button";text="aardio 执行 modbus 数据采集";left=392;top=64;right=744;bottom=144;border=1;color=14120960;db=1;dr=1;font=LOGFONT(h=-14);z=3};

    edit={cls="edit";left=24;top=176;right=376;bottom=432;edge=1;hscroll=1;multiline=1;vscroll=1;z=1};

    edit3={cls="edit";left=392;top=176;right=744;bottom=432;edge=1;hscroll=1;multiline=1;vscroll=1;z=4}

    )

    /*}}*/


    //以下是借用python的modbus_tk库

    import py3;   //aardio调用python

    import process.python;

    //import process.python.pip;

    var pyCode = /**

    import time

    import datetime

    import modbus_tk.modbus_tcp as mt

    import modbus_tk.defines as md

    ip = "10.168.4.75"

    port = 502 

    master = mt.TcpMaster(ip, 502)

    master.set_timeout(50.0)

    tn=datetime.datetime.now()    # 返回当前的datetime日期类型

    aa = master.execute(1,md.READ_HOLDING_REGISTERS,100,8)

    bb = master.execute(1,md.READ_INPUT_REGISTERS,0,3)

    aa1 = list(aa)

    for j, item  in  enumerate(aa1):

        aa1[j] = round(aa1[j]/100,2)    # 工程数据,小数点后2位

    bb1 = list(bb)

    for k, item in enumerate(bb1):

        bb1[k] = round(bb[k]/10000,2)   #数字改变,小数点2位 

    print("时间:",tn)

    print("输入寄存器",bb1)

    print("保持寄存器",aa1)

    print("---------------------")

    **/

    py3.exec(pyCode);

    winform.button.oncommand = function(id,event) { 

       var reslist = process.python.exec(pyCode);  // 执行Python脚本

        reslist.logResponse(winform.edit);     //第二种:python程序的执行方法!!

        }



    //以下是用aardio 自带的modbus库完成同一功能的


    import modbus.modbustcp;  //取寄存器的值

    var m = modbus.modbustcp();

    var ip = "10.168.3.75";

    var port = 502;

    var timeout = 50;

    var handle = m.tcpConnect(ip, port, timeout);


    winform.button2.oncommand = function(id,event){

    var v = m.readHoldingRegisters(1, 100, 8);      //用modbus读取寄存器的值

    //var w = m.readInputRegisters(1, 0, 3);     //w = 预期得到 number,实际获取为 buffer,错误!!

    var currDT = tostring(time(time.now(),"%Y-%m-%d %H:%M:%S"));  //当前日期

        winform.edit3.print(currDT);

        winform.edit3.print("输入寄存器无法运行");

        winform.edit3.print("保持寄存器=");

      for(i=1;8;1){

            winform.edit3.print(tonumber(v[i],16)/100);

             }

        //winform.edit3.print(v);

        winform.edit3.print("--------------"); 

       }


    winform.show();

    win.loopMessage();


    /**

    aardio语言简单明了,运行速度还很快。

    如果把自身的modbus库解决好,

    完全不必通过python的第三方库费力的去处理。

    **/

    这是监测站的两个虚拟局域网的地址,正常运行时,用的是组态软件进行的。

    另外,如何将数据竖排改成横排,改成左边的方式,请提示。

    拜个晚年,祝阖家团圆,工作愉快。

  • 光庆 2月前
    0 20

    这种东西吧,就是因为大家没有硬件环境,不方便帮你测试,所以解决起来相对麻烦点。上次帮一个朋友搞串口库,人家直接把板子给我寄过来,我很快就搞定了。如果没有板子,就真不好测试了,就算搞一个库出来,运行结果对不对自己都不知道。

返回