Siemens S7-1200 modbus understanding.

leem2209

Lifetime Supporting Member
Join Date
May 2015
Location
Wirral, UK
Posts
210
In a project I've been working on, I am taking data from a Siemens PLC datablock and storing it in a SQL database.

The PC is communicating with a S7-1212C CPU via modbus.

I'm trying to setup the Modbus Communications and prove it's working.

In the S7 program, I have inserted the MB_SERVER block and the MB_HOLD_REG is DB2.

I have a move command to copy the data from the required datablock (DB101) into the holding register datablock (DB2). I have also inserted code to make DB101.DBX0.0 flash true for 1 second. I have done this to test the comms and I should be able to read it on my PC program if all is well.

Reading up on the Siemens Documentation for Modbus TCP using MB_server and MB_Client, it shows that the first modbus address (40001) is read from the Holding Register Datablock word 4 (DB2.DBW4).

Does this mean that the first 3 words of the holding register datablock isn't read? In which case my flashing bit, DB2.DBX0.0 will not be read, hence I cannot see it on the PC?

If I re-program to flash DB2.DBX8.0 (4th word, 1st bit) then I can see it on the PC using Modbus address 40001.... something - how is an individual bit addressed on Modbus? according to http://www.csimn.com/CSI_pages/Modbus101.html, "You cannot read just one bit from a holding register. There is no way to do that..."

In my PC program, I have set a basic indicator (using advanced HMI by the way) which I want to flash according to my flashing datablock bit. So I need to address that as a Modbus bit.

Many thanks...
 
OK, lets start by making sure my PC IP address is correct shall we.... :doh

Looking back at the MB_SERVER help file, and seeing the address mapping table again, I could see that Modbus addresses 00001 to 09999 are = PLC addresses Q0.0 to Q1023.7

Whereas I was looking at modbus registers 40001 which are all word data.

So, I will use the output coils Q0.0 to Q62.3 for my 500 bits of data.

Had a little play and now my flashing bit, DB101.DBX0.0 through Modbus to the (correct IP) PC now makes my indicator (Modbus address 10001) flashes in sync! Great!

This does cause me to loose my actual CPU built in outputs on the 1212C CPU. But I don't really need them anyway.

Now, how to move DB data to Q data? I cannot do a DB -> MOVE -> Q...
I could do DBW -> MOVE -> QW and repeat again and again until all words of data are transferred, but there must be an easier way?

I'll keep on Googling for now!

PS... this is how rock'n'roll my Saturday nights are!!!! Joys of shift work!
 
Continued Googling:

Objective: Move 500 bits of data starting from DB101.DBX0.0 to 500 bits of outputs starting Q0.0

I found the POKE function. Reading up on it (and never having used SCL before) I'm wondering if the following would work?

POKE_BLK(
area_src := 16#84, // 16#84 is DB Area
dbNumber_src := 101, // Source datablock number
byteOffset_src := 0, // structure address start in source DB
area_dest := 16#82, // 16#82 is Output (Q) area
dbNumber_dest := 0, // Target datablock number
byteOffset_dest := 0, // structure address start in destination Q
count := 64 // Number of total bytes to copy
);

Any thoughts? Or am I missing something super simple?
 
Pack your bits to word and move to modbus registers 40000x-, on PC sidde you can read packet bits individually from word registers (400001.x bits)

https://www.google.fi/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwiv4qvuqOjNAhWKXhQKHevoCqcQFgggMAA&url=http%3A%2F%2Fwww.eurotec.co.kr%2Fbbs%2Fdownload.php%3Fbo_table%3Dsimatic%26wr_id%3D12%26no%3D2%26..&usg=AFQjCNFcds6PEIhOB-WTGe9B2Q84kOLc9Q

system manual page 197. It is showing master communication on PLC side. You can use array of bools also for DB2/MB_server. (slave)
 
Last edited:
Pack your bits to word and move to modbus registers 40000x-, on PC sidde you can read packet bits individually from word registers (400001.x bits)

https://www.google.fi/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwiv4qvuqOjNAhWKXhQKHevoCqcQFgggMAA&url=http%3A%2F%2Fwww.eurotec.co.kr%2Fbbs%2Fdownload.php%3Fbo_table%3Dsimatic%26wr_id%3D12%26no%3D2%26..&usg=AFQjCNFcds6PEIhOB-WTGe9B2Q84kOLc9Q

system manual page 197. It is showing master communication on PLC side. You can use array of bools also for DB2/MB_server. (slave)

Thanks Lare,

So let me get this straight:

I have in my s7-1212C CPU a MB_SERVER block. The details for that are:
Disconnect: FALSE
Connect ID: 1
IP_Port: 502
MB_HOLD_REG: DB2 (I'm assuming the contents of DB2 are transferred into modbus holding registers 40001 onwards?)

So, as I had previously read elsewhere, and in that link you sent, the first 16 bits of data in DB2 are reserved for system functions for the MB_SERVER, meaning my first usable address for transfer is DB2.DBX2.0... correct?

So if I write my flashing bit to DB2.DBX2.0 this will be transferred to Modbus address 40001.0 and I can then read that in my AdvancedHMI project by setting a lamp colour to be active with PLC Address 40001.0... correct? (PS I'm assuming modbus addressing goes from bit 0 to bit 7?)

It would be much easier to move my data to another DB rather than to Q output bits, especially when I come to expand the system.
 
Modbus holding register start from 400001 address. If you link DB2 to MB_server, then DB2.DBW0 = 400001 (if you don't use HR_start offset parameter)

HR_Start_offset is parameter of instance DB of MB_server block. Default value for that is 0, so modbus registers starts from 40001. You can check offset value at online view. (system blocks, program resources, MB_server_db...)

You need to use array of bools, it is easier than setting dbx addresses directly, because Siemens uses dbx bits on different order than modbus.

If you set db2.dbx0.0 directly on program, you need to look MB 40001.8 address.
(db2.dbx0.1 = mb 40001.9 )
(db2.dbx0.2 = mb 40001.10 )
(db2.dbx1.0 = mb 40001.0 )
(db2.dbx1.1 = mb 40001.1 )

But if you make array of bools to DB2 then bits are on same order than on modbus

array_bool[0]= MB 400001.0
array_bool[15]= MB 400001.15
 
I don't remeber that there would be system functions on first value of MB2 for MB_server. Maybe you mix master and slave functions on PLC.
 
Modbus holding register start from 400001 address. If you link DB2 to MB_server, then DB2.DBW0 = 400001 (if you don't use HR_start offset parameter)

HR_Start_offset is parameter of instance DB of MB_server block. Default value for that is 0, so modbus registers starts from 40001. You can check offset value at online view. (system blocks, program resources, MB_server_db...)

You need to use array of bools, it is easier than setting dbx addresses directly, because Siemens uses dbx bits on different order than modbus.

If you set db2.dbx0.0 directly on program, you need to look MB 40001.8 address.
(db2.dbx0.1 = mb 40001.9 )
(db2.dbx0.2 = mb 40001.10 )
(db2.dbx1.0 = mb 40001.0 )
(db2.dbx1.1 = mb 40001.1 )

But if you make array of bools to DB2 then bits are on same order than on modbus

array_bool[0]= MB 400001.0
array_bool[15]= MB 400001.15

Awesome Lare, thank you!

I'm going to go back to my PG in a bit and play! As long as these other darn machines behave themselves!!!
 
I haven't played much with Siemens TCP modbus, but bits are that way on siemens RTU modbus (serial)
TCP and RTU shouldn't not make any difference for these bit orders...

easiest way would be to set values

DB2.DBW0 = 10 (because zero is not good)
DB2.DBW2 = 2
DB2.DBW4 = 4

Then on PC side read modbus registers 400001..3 you should see same values. After you know that communication is working, you can start to use packed bits on words.
 
Last edited:
OK... so I've done as you suggested using holding register addresses, and I'm getting closer each time!!! So I appreciate your help!

DB2 is now made of arrays in the following style.

DB2
Word_0 Array [0 .. 15] of bool
Word_1 Array [0 .. 15] of bool
Word_2 Array [0 .. 15] of bool
etc

I've now created my MOVE_BLK to transfer my real database into DB2 (the Holding Register Database) - I've set it to write data from DB101.DBX0.0 for 31 WORDS, but it only seems to write data into the first word of DB2 (DB2.DBW0) - is this because the structure is now different?

Anyway, in that first word of DB2, I can see the first bit is flashing as per my set logic (DB2.DBX0.0) - on my PC I set my indicator lamp address to 40001.0 but it did not flash. I tried different addresses according to some TRUE bits. No joy.
I created 16 lamps on the PC, and addressed each one from 40001.0 to 40001.15, and as per what you stated earlier, 40001.8 was flashing.

I had forgot about siemens word MSB order... but I have set up DB2 in arrays as suggested. Any further ideas?

Should I set up in Array [0 .. 7] of bool to create bytes of data instead?
 
damn, I should test before writing.

Looks like that array of bool don't make difference. Bits will be different order still than on modbus.

o_O Use bytes and swap bytes (and bits) to different order on PLC side before copying to DB-block. On some modbus clients there is setting that you can change byte also on PC side, but that would affect to word values also 🔨
 
Last edited:
Reading up on this a little more and Siemens uses a "Big Endian" structure while x86 intel PC's uses a "Little Endian" structure.

I did also find that there is a conversion STL commands CAW and CAD (Swap bytes in Word/Double Word) but this would mean running STL commands many times in order to convert all the words needed.

So I looked at your suggestion of the Modbus client on the PC having a setting to swap the bytes... and I found it! In the ModbusTCP communications setting parameters it has options of Bytes Swap and Word Swap. Bytes Swap was set to true and Word Swap was set to false. I had to change them both to false, and now looking at my 16 lamps, the first one is now flashing! Wooooooohooooooo!

So I thought that was it! I'm ready to start recording my data into my SQL server... but alas noooooooooo! another obstacle...

In my AdvancedHMI code, I was given a piece of VB code by AdvHMI creator, Archie, which subscribed to the Modbus input data and scanned for changes then setting the changed address to write a piece of code to the SQL server, thus recording the data.

I'm writing to the holding register, not the input register, so the code isn't scanning for changes in the holding register.... grrrr....

I found where the modbus address is read ("0000i" where i=1 to 500) scanning for 500 bits of change. I tried changing it to "4000i" but it didn't like it, possibly because that means its trying to scan for 500 words not bits.

I have two options here;
1.) Go back to trying to move my DB data into Q data (Still not sure how to do this unless I move DBD to QD many times for all the DoubleWords required)
2.) See if Archie can help me adjust the VB code to scan for Holding Register changes instead of input register.
 
Maybe. Continuous modbus register read is limited to 125 words/one query and writing was 100 or 125?

I'm not sure about this.

Archie has given me some altered code to try which I will do when back in work on Friday.

As proof of concept, and my desire to see some results from start to finish, I decided to use a load of Move commands to move Double words from my Datablock to the Output required for the Modbus communications.

My test data block is using 500 bits (set to show error_msg_001 to error_msg_500) so it required 16 move commands.

The programming looks a bit messy at the moment with everything thrown in and testing signals created, but when ran in this way, I had fully working communications from my S7-315 CPU (which is basically going to be the live machine monitored) via profinet to my S7-1212 CPU (used as a data collection and conversion to modbus) and onto my data recorder PC running Visual Basic AdvancedHMI to collect that modbus data and write it into the SQL database.

Using a single button connected to my S7-315 CPU generates an almost random number (basically a counter running from 0 to 500 and when I press the button it stores the current number in a Memory Word) that number then turns the relevant data bit to true, emulating a fault.

That bit is then true in the 1212CPU and the PC scans a change in the modbus input, and cross references the input to a reference table, then writes the text from that table into the error data log.

It took a little more adjustment after that to write the correct code as in the PLC's, bit 0.0 (first bit) is error_msg_000 which is transferred to the first modbus input (00001) which cross references to the first line of the reference table which is ref number 1, error_text_001.

I needed to make amends to the reference table as I couldn't start the reference ID at 0. So reference ID 1 is error_text_000. Now they match up!

I'm really pleased at this point because I am now at a point where it works! Yes it may not be the best way and could do with lots of improvement, but I can now start to implement this to retrieve real live machine data and show it's worth to my bosses!

Couldn't have done this without your assistance Lare, and a few others on here, so wanted to offer my thanks. :D
 

Similar Topics

Hi all, Currently having trouble getting a speed reference to write over modbus to an Omron M1... I can successfully write a run command and...
Replies
6
Views
252
I have 3 control panels made by an OEM, they are all identical and have a Siemens S7-1200 PLC with a Siemens CB-1241 Modbus card talking to 2...
Replies
8
Views
4,529
Hi All, I have a closed loop stepper motor (Nanotec make), https://en.nanotec.com/products/2512-pd4-e601l42-e-65-4. This uses MODBUS TCP for...
Replies
4
Views
3,863
Hello; i'm having some troubles with a com test i'm handling. i have another end for it, but for now i would like to have : M241 in io_scanning...
Replies
4
Views
3,484
Replies
3
Views
2,364
Back
Top Bottom