How to force register on slave

218 views
Skip to first unread message

Nico Blanc

unread,
Mar 8, 2014, 11:43:18 PM3/8/14
to modb...@googlegroups.com
Hi,

I'm working for a while on different possibility to implement a Modbus Slave on TCP, in order to make a kind of PLC for my house
Thanks to this great lib, my work has seen some progress, but I'm not a good programmer and I'm not habitued to Python so it's hard for me ...

My Modbus Master is made with Mango from Serotonine Software.
On the slave I'm writing in Python, I've been able to reflect coils values into a register that the master can successfully read but I don't understand how to force the Data of the slave register when sending a Write Holding Register (func 06) from the master. In fact I don't know how to read this value on the slave.

I guess, this can be done with the get_values function of my object but I can't see any change.

here is my code :

#!/usr/bin/env python
import Adafruit_BBIO.GPIO as GPIO
import threading
import time
import modbus_tk
import modbus_tk.modbus_tcp as modbus_tcp
import modbus_tk.defines as mdef
 
        
class Scan_GPIO(threading.Thread):
    def __init__(self, nom = ''):
        threading.Thread.__init__(self)
        self.nom = nom
        self.Terminated = False

    def run(self):
        pin8_13 = 0;
        register = 0
        GPIO.output("P8_42", GPIO.HIGH)
        slave1.set_values("a", 0, register)
        while not self.Terminated:
            # before reflecting local changes, I try to catch the value sent by the master ...
            register2 = slave1.get_values("b", 1); 
            print "Register2 : ",register2
            time.sleep(1)
            if (GPIO.input("P8_13") and not pin8_13):
                pin8_13 = 1;
                #print "P8_13 Pressed !"
                if GPIO.input("P8_42"):
                    GPIO.output("P8_42", 0)
                    print "GPIO P8_42 LOW"    
                    register |= 0x01
                else:   
                    GPIO.output("P8_42", 1)
                    print "GPIO P8_42 HIGH"
                    register &= 0xfe
            elif ( not GPIO.input("P8_13") and pin8_13):
                pin8_13 = 0;
            
            slave1.set_values("a", 0, register)
            time.sleep(0.02)   
    def stop(self):
        self.Terminated = True
    
logger = modbus_tk.utils.create_logger(name="console", record_format="%(message)s")
server = modbus_tcp.TcpServer(address='172.16.17.173')
slave1 = server.add_slave(1)
slave1.add_block("a", mdef.HOLDING_REGISTERS, 0, 1)#address 0, length 1
slave1.add_block("b", mdef.HOLDING_REGISTERS, 1, 1)#address 1, length 1

j = 0
slave1.set_values("a", 0, j)   
server.set_verbose(1)
server.start()
GPIO.setup("P8_13", GPIO.IN)
GPIO.setup("P8_42", GPIO.OUT)
a = Scan_GPIO('GPIO Scan')
a.start()
while not GPIO.input("P8_41"):
    # Do nothing
    b = 1
a.stop()
server.stop()
GPIO.cleanup()

And here a en extract of the requests :


('172.16.17.250', 55628) is connected with socket 9...
-->3-192-0-0-0-6-1-3-0-0-0-1 <- Function 3, to read the data on the slave
<--3-192-0-0-0-5-1-3-2-0-0

('172.16.17.250', 55629) is connected with socket 9...
-->3-193-0-0-0-6-1-6-0-0-0-2 <- Function 6, When forcing coil2 from the master
<--3-193-0-0-0-6-1-6-0-0-0-2 <- The slave answer is good ...
Register2 :  (0,) <- ... but I can't see the change on the local register
9 is disconnected

Register2 :  (0,)
GPIO P8_42 LOW
Register2 :  (0,)
Register2 :  (0,)
('172.16.17.250', 55664) is connected with socket 10...
-->3-228-0-0-0-6-1-3-0-0-0-1 <- Function 3, to read the data on the slave
<--3-228-0-0-0-5-1-3-2-0-1<- When changing state of coil1 on the slave, the information is well sent to the master
10 is disconnected

Can anybody tell me how to read the result of the Function 6 frmae sent by the master to force local registers ?

Thanks,

Nicolas

Nico Blanc

unread,
Mar 9, 2014, 6:55:01 AM3/9/14
to modb...@googlegroups.com
Well, despite I've spent hours to find a solution before asking this group, it seems that witing my problem did help myself ... :-)

I think I have found the solution.
In fact I can deal with only one register in the databank, no need to use a second one dedicated to the orders receives from the master.

The answer is so simple.
At the begginning of the loop (of the "run" procedure), I copy the "a" register to a local copy so that with few bitwise operation I can update the Coil of my slave, acting like this I'm sure that at any beggining of the loop, the master will be able to force local Coils .
As you saw in the loop I always look for a change in the Input pins. So when a change is detected, I can :
- reflect the change to the corresponding coil (so that when à push a switch, a light can toggle its state)
- update the "a" register so that the master will be informed of the change , until itself make a new change ...

For those who could be interested, my code is now (for 4 Input and 4 coils):

#!/usr/bin/env python
import Adafruit_BBIO.GPIO as GPIO
import threading
import time
import modbus_tk
import modbus_tk.modbus_tcp as modbus_tcp
import modbus_tk.defines as mdef
 
        
class Scan_GPIO(threading.Thread):
    def __init__(self, nom = ''):
        threading.Thread.__init__(self)
        self.nom = nom
        self.Terminated = False

    def run(self):
        pin8_13 = 0;
        pin8_14 = 0;
        pin8_16 = 0;
        pin8_17 = 0;
        register = 0
        GPIO.output("P8_42", GPIO.HIGH)
        GPIO.output("P8_43", GPIO.HIGH)
        GPIO.output("P8_44", GPIO.HIGH)
        GPIO.output("P8_45", GPIO.HIGH)

        # initial update
        slave1.set_values("a", 0, register)
        while not self.Terminated:
            # for the first COIL, copy the modbus "a" register to a local one
            a = slave1.get_values("a", 0)[0]
            a &= 0x01
            # force  the first COIL
            if a:
                GPIO.output("P8_42", GPIO.HIGH)
            else:
                GPIO.output("P8_42", GPIO.LOW)
            # same thing for the second COIL
            a = slave1.get_values("a", 0)[0]
            a &= 0x02
            if a:
                GPIO.output("P8_43", GPIO.HIGH)
            else:
                GPIO.output("P8_43", GPIO.LOW)
            a = slave1.get_values("a", 0)[0]
            a &= 0x04
            if a:
                GPIO.output("P8_44", GPIO.HIGH)
            else:
                GPIO.output("P8_44", GPIO.LOW)
            a = slave1.get_values("a", 0)[0]
            a &= 0x08
            if a:
                GPIO.output("P8_45", GPIO.HIGH)
            else:
                GPIO.output("P8_45", GPIO.LOW)
                
            if (GPIO.input("P8_13") and not pin8_13):
                pin8_13 = 1;
                print "P8_13 Pressed !"
                register = slave1.get_values("a", 0)[0]
                if GPIO.input("P8_42"):
                    register &= 0xfe
                    GPIO.output("P8_42", GPIO.LOW)
                    print "GPIO P8_42 LOW"                        
                else:   
                    register |= 0x01
                    GPIO.output("P8_42", GPIO.HIGH)
                    print "GPIO P8_42 HIGH" 
                # update the "a" register because a change has been made localy
                slave1.set_values("a", 0, register)
            elif (not GPIO.input("P8_13") and pin8_13):
                pin8_13 = 0;
            
            if (GPIO.input("P8_14") and not pin8_14):
                pin8_14 = 1;
                print "P8_14 Pressed !"
                register = slave1.get_values("a", 0)[0]
                if GPIO.input("P8_43"):
                    register &= 0xfd
                    GPIO.output("P8_43", GPIO.LOW)
                    print "GPIO P8_43 LOW"    
                    
                else:   
                    register |= 0x02
                    GPIO.output("P8_43", GPIO.HIGH)
                    print "GPIO P8_43 HIGH"
                print "register : ",bin(register)
                slave1.set_values("a", 0, register)   
            elif ( not GPIO.input("P8_14") and pin8_14):
                pin8_14 = 0;
            
            if (GPIO.input("P8_16") and not pin8_16):
                pin8_16 = 1;
                print "P8_16 Pressed !"
                register = slave1.get_values("a", 0)[0]
                if GPIO.input("P8_44"):
                    register &= 0xfb
                    GPIO.output("P8_44", GPIO.LOW)
                    print "GPIO P8_44 LOW"    
                else:   
                    register |= 0x04
                    GPIO.output("P8_44", GPIO.HIGH)
                    print "GPIO P8_44 HIGH"
                slave1.set_values("a", 0, register)
            elif ( not GPIO.input("P8_16") and pin8_16):
                pin8_16 = 0;
                
            if (GPIO.input("P8_17") and not pin8_17):
                pin8_17 = 1;
                print "P8_17 Pressed !"
                register = slave1.get_values("a", 0)[0]
                if GPIO.input("P8_45"):
                    register &= 0xf7
                    GPIO.output("P8_45", GPIO.LOW)
                    print "GPIO P8_45 LOW"    
                else:   
                    register |= 0x08
                    GPIO.output("P8_45", GPIO.HIGH)
                    print "GPIO P8_45 HIGH"
                slave1.set_values("a", 0, register)
            elif ( not GPIO.input("P8_17") and pin8_17):
                pin8_17 = 0; 
            
            time.sleep(0.02)
    def stop(self):
        self.Terminated = True
    


logger = modbus_tk.utils.create_logger(name="console", record_format="%(message)s")

server = modbus_tcp.TcpServer(address='172.16.17.173')
slave1 = server.add_slave(1)
slave1.add_block("a", mdef.HOLDING_REGISTERS, 0, 1)#address 0, length 1

j = 0
slave1.set_values("a", 0, j)   
server.set_verbose(1)
server.start()

GPIO.setup("P8_13", GPIO.IN)
GPIO.setup("P8_14", GPIO.IN)
GPIO.setup("P8_15", GPIO.IN)
GPIO.setup("P8_16", GPIO.IN)
GPIO.setup("P8_17", GPIO.IN)
GPIO.setup("P8_18", GPIO.IN)
GPIO.setup("P8_19", GPIO.IN)
GPIO.setup("P8_41", GPIO.IN)

GPIO.setup("P8_42", GPIO.OUT)
GPIO.setup("P8_43", GPIO.OUT)
GPIO.setup("P8_44", GPIO.OUT)
GPIO.setup("P8_45", GPIO.OUT)
GPIO.setup("P8_46", GPIO.OUT)
GPIO.setup("P9_11", GPIO.OUT)
GPIO.setup("P9_12", GPIO.OUT)


a = Scan_GPIO('GPIO Scan')

a.start()
while not GPIO.input("P8_41"):
    b = 1
a.stop()
server.stop()
GPIO.cleanup()


The result is much more intersting :

A normal query from the master
-->78-77-0-0-0-6-1-3-0-0-0-1
<--78-77-0-0-0-5-1-3-2-0-0

The master update the first Coil
-->78-116-0-0-0-6-1-6-0-0-0-1
<--78-116-0-0-0-6-1-6-0-0-0-1

then the second one : 0x01 + 0x02 = 0x03 (0000 0011):
-->78-155-0-0-0-6-1-6-0-0-0-3
<--78-155-0-0-0-6-1-6-0-0-0-3

the slave localy toggle the first COIL, the result is now 0x02 (0000 0010):

-->78-226-0-0-0-6-1-3-0-0-0-1
<--78-226-0-0-0-5-1-3-2-0-3
P8_13 Pressed !
register 1:  0b11
GPIO P8_42 LOW
register 2:  0b10
register :  0b10
-->78-227-0-0-0-6-1-3-0-0-0-1
<--78-227-0-0-0-5-1-3-2-0-2

You know what ? I'm Happy (not yet a hero ... :-) )

Luc JEAN

unread,
Mar 10, 2014, 2:35:11 AM3/10/14
to modb...@googlegroups.com
Congratulations and welcome to modbus-tk user group. :-)
Happy to know that you dit it :-)
Best
luc


--
You received this message because you are subscribed to the Google Groups "modbus-tk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to modbus-tk+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages