Siemens General + TIA Portal + EPLAN Electrical Drawing Video Recordings for Sale at Low Prices!
ChuangKong Education Siemens General Class Course Introduction

We know that there are various storage areas in PLCs for different purposes, such as Physical I/O Area P, Image Input Area I, Image Output Area Q, Bit Storage Area M, Timer T, Counter C, Data Block DB, and L, etc. At the same time, we also know that each area can be measured with bits (BIT), bytes (BYTE), words (WORD), or double words (DWORD) to specify exact sizes. Of course, timers T and counters C do not have this measurement system; they are measured only in bits. Thus, we can conclude that to describe an address, at least two elements should be included:
1. The area of storage
2. The specific position within that area
For example: A Q2.0
Here, A is the instruction symbol, and Q2.0 is the operand of A, which is the address. This address consists of two parts:
Q: refers to the image output area
2.0: indicates the 0th bit of the second byte of this image output area.
Thus, we conclude that a precise address composition should be:
〖Storage Area Symbol〗〖Storage Area Size Symbol〗〖Size Value〗.〖Bit Value〗, for example: DBX200.0.
DB X 200 . 0
Among them, we also refer to the two parts of 〖Storage Area Symbol〗〖Storage Area Size Symbol〗 as: Address Identifier. In this way, a precise address composition can also be written as:
Address Identifier + Precise Value Unit
【Concept of Indirect Addressing】
Addressing is the method of specifying the address where the instruction is to operate. The method of addressing the address for a given instruction is called the addressing method.
Before discussing indirect addressing, let’s briefly understand direct addressing. Direct addressing, simply put, is directly providing the exact operand of the instruction, as mentioned above, A Q2.0 is direct addressing; for the instruction A, Q2.0 is the address it operates on.
Thus, indirect addressing is indirectly providing the exact operand of the instruction. Yes, that’s the concept.
For example: A Q[MD100], A T[DBW100]. The content indicated by the square brackets [ ] in the program statement indirectly specifies the address where the instruction is to operate; in these two statements, MD100 and DBW100 are referred to as pointers, which point to the values they contain, which is the exact location of the address area that the instruction is really going to execute. Hence the name indirect.
Siemens has two main types of indirect addressing: Memory Indirect Addressing and Register Indirect Addressing.
【Memory Indirect Addressing】
The address format for memory indirect addressing is: Address Identifier + Pointer. The value contained in the memory unit indicated by the pointer is the exact value unit of the address.
Memory indirect addressing has two pointer formats: Single Word and Double Word.
Single word pointer is a 16-bit structure, from 0-15 bits, indicating a value from 0-65535, which is the number of the addressed storage area.
Double word pointer is a 32-bit structure, from 0-2 bits, with three bits indicating the bit number to be addressed, which is 0-7; and from 3-18 bits, with 16 bits indicating a value from 0-65535, which is the byte number to be addressed.
Pointers can be stored in M, DI, DB, and L areas, which means that the contents of these areas can be used as pointers.
Single word pointers and double word pointers have significant differences in usage. Here are some examples to illustrate:
L DW#16#35 // Store the 32-bit hexadecimal number 35 into ACC1
T MD2 // This value is then stored in MD2, which is a 32-bit bit storage area
L +10 // Store the 16-bit integer 10 into ACC1, 32-bit hexadecimal number 35 automatically moves to ACC2
T MW100 // This value is then stored in MW100, which is a 16-bit bit storage area
OPN DBW[MW100] // Open DBW10. Here, [MW100] is a single word pointer, and the area storing the pointer is the M area,
The value in MW100, 10, is the address indirectly specified by the pointer, which is a 16-bit value!
——–
L L#+10 // In 32-bit form, put 10 into ACC1, at this time, the content in ACC2 is: 16-bit integer 10
T MD104 // This value is then stored in MD104, which is a 32-bit bit storage area
A I[MD104] // Perform AND logic operation on I1.2!
=DIX[MD2] // Assign background data bit DIX6.5!
——–
A DB[MW100].DBX[MD2] // Read DB10.DBX6.5 data bit status
=Q[MD2] // Assign to Q6.5
——–
A DB[MW100].DBX[MD2] // Read DB10.DBX6.5 data bit status
=Q[MW100] // Error!! No Q10 component
————————————————————————————————–
From the above series of examples, we can at least see one point:
Single word pointers are only applied when the address identifier is non-bit. Indeed, as previously described, the determined value of a single word pointer is 0-65535, while for specific bit structures like byte.bit, only double word pointers can be used. This is the first difference; another limitation of single word pointers is that they can only address T, C, DB, FC, and FB, in simple terms, single word pointers can only be used to refer to the numbers of these storage areas.
In contrast, double word pointers do not have such limitations; they can address both bit addresses and BYTE, WORD, DWORD without area restrictions. However, there is always a trade-off; when addressing non-bit areas, it must be ensured that the 0-2 bits are all 0!
To summarize:
Single word pointers in memory indirect addressing can only be used when the address identifier is non-bit; double word pointers, due to the presence of bit format, have no restrictions on address identifiers. It is precisely because double word pointers are pointers with bits that when addressing byte, word, or double word storage area addresses, it must be ensured that the content of the double word pointer is a multiple of 8.
Now, let’s analyze why the example A I[MD104] ultimately performs an AND logic operation on I1.2.
Through L L#+10, we know that the value stored in MD104 should be:
MD104: 0000 0000 0000 0000 0000 0000 0000 1010
When used as a double word pointer, it should be determined according to the 3-18 bits specifying the byte and the 0-2 bits specifying the bit to determine the final address that the instruction is to operate on, thus:
0000 0000 0000 0000 0000 0000 0000 1010 = 1.2
【Address Register Indirect Addressing】
In the previously mentioned memory indirect addressing, the indirect pointer is directly specified by M, DB, DI, and L, meaning that the content of the storage area pointed to by the pointer is the exact address value unit that the instruction is to execute. However, in register indirect addressing, the exact address value unit that the instruction is to execute is not the content of the storage area pointed to by the register, meaning that the register itself is also indirectly pointing to the actual address value unit. From the register to derive the actual address value unit, Siemens provides two ways:
1. Intra-area Register Indirect Addressing
2. Inter-area Register Indirect Addressing
The general format for address register indirect addressing is:
〖Address Identifier〗〖Register,P#byte.bit〗, for example: DIX[AR1,P#1.5] or M[AR1,P#0.0].
〖Register,P#byte.bit〗 is collectively referred to as: Register Addressing Pointer, while 〖Address Identifier〗 has been discussed in the previous post, which contains 〖Storage Area Symbol〗 + 〖Storage Area Size Symbol〗. However, here, the situation changes. Comparing with the previous examples:
DIX [AR1,P#1.5]
X [AR1,P#1.5]
DIX can be considered as the address identifier we typically define; DI is the background data block storage area, X is the size symbol of this storage area, referring to the bits in the background data block. But what about M in the next example? X only specifies the size symbol of the storage area; where is the storage area symbol? Without a doubt, it is in AR1!
DIX [AR1,P#1.5] in this example, the address area to be addressed has already been determined, and AR1 can only change the exact value unit within that area, so we call this: Intra-area Register Indirect Addressing method, correspondingly, here [AR1,P#1.5] is called the intra-area addressing pointer.
X [AR1,P#1.5] in this example, the address area and the exact value unit to be addressed have not been determined in advance; only the storage size is determined, which means we can address different address value units in different areas with the given storage size, so it is called: Inter-area Register Indirect Addressing method, correspondingly, here [AR1,P#1.5] is called the inter-area addressing pointer.
Since there is a distinction between intra-area and inter-area addressing, similarly, in AR1, there are different contents, representing different meanings.
【Format of AR】
Address registers are a special pointer area specifically used for addressing; Siemens’ address registers are two: AR1 and AR2, each 32 bits.
When used in intra-area register indirect addressing, we know that the content in AR simply indicates the value unit, therefore, in intra-area register indirect addressing, the content of the register is equivalent to the double word pointer mentioned in memory indirect addressing, which is:
Its 0-2 bits specify the bits, and the 3-18 bits specify the bytes. The 31st bit is fixed at 0.
AR:
0000 0000 0000 0BBB BBBB BBBB BBBB BXXX
This specification means that the value of AR can only be: 0.0 —65535.7
For example: When AR=D4 (hex)=0000 0000 0000 0000 0000 0000 1101 0100 (b), it actually equals 26.4.
And in inter-area register indirect addressing, since the area to be addressed must also be specified in AR, obviously, the content in AR at this time must differ from the requirements for AR content in intra-area indirect addressing, or the regulations differ.
AR:
1000 0YYY 0000 0BBB BBBB BBBB BBBB BXXX
Comparing the differences between the two formats, we find that here the 31st bit is fixed at 1, and the 24th, 25th, and 26th bits have a range of values. Smart as you are, you can definitely think of this as being used to specify the storage area. Yes, the values of bits 24-26 determine the area to be addressed; its value is defined as follows:
Area Identifier
26, 25, 24 bits
P (External I/O)
000
I (Input Image Area)
001
Q (Output Image Area)
010
M (Bit Storage Area)
011
DB (Data Block)
100
DI (Background Data Block)
101
L (Temporary Storage Area, also called Local Data)
111
If we express such AR content in HEX, we have:
When addressing the P area, AR=800xxxxx
When addressing the I area, AR=810xxxxx
When addressing the Q area, AR=820xxxxx
When addressing the M area, AR=830xxxxx
When addressing the DB area, AR=840xxxxx
When addressing the DI area, AR=850xxxxx
When addressing the L area, AR=870xxxxx
Through enumeration, we have a preliminary conclusion: if the content in AR starts with 8, then it must be inter-area addressing; if we want to address within the DB area, we just need to follow 8 with a 40. 84000000-840FFFFF specifies that the addressing range is:
DB area 0.0——65535.7.
For example: When AR=840000D4 (hex)=1000 0100 0000 0000 0000 0000 1101 0100 (b), it actually equals DBX26.4.
We see that in the register addressing pointer [AR1/2,P#byte.bit] structure, what is P#byte.bit?
【P# Pointer】
P# in P# is Pointer, which is a 32-bit direct pointer. The so-called direct means that the value or storage unit following # in P# is directly given by P. Thus, pointers of the form P#XXX can be treated as a “constant” in instruction addressing; this “constant” may or may not contain storage areas. For example:
● L P#Q1.0 // Store the pointer Q1.0 into ACC1, at this time ACC1’s content = 82000008 (hex) = Q1.0
★ L P#1.0 // Store the pointer 1.0 into ACC1, at this time ACC1’s content = 00000008 (hex) = 1.0
● L P#MB100 // Error! Must specify the pointer according to the byte.bit structure.
● L P#M100.0 // Store the pointer M100.0 into ACC1, at this time ACC1’s content = 83000320 (hex) = M100.0
● L P#DB100.DBX26.4 // Error! DBX has already provided the storage area, cannot be specified again.
● L P#DBX26.4 // Store the pointer DBX26.4 into ACC1, at this time ACC1’s content = 840000D4 (hex) = DBX26.4
We find that when only specifying a value for P#, the value in the accumulator is the same as the format specified by the intra-area addressing pointer (and also the same as the memory indirect addressing double word pointer format); when specifying P# with a storage area, the content in the accumulator is exactly the same as that of the inter-area addressing pointer content. In fact, what kind of value is passed to AR determines what kind of method will be used for register indirect addressing. In practical applications, we utilize this feature of P# to specify the P# pointer according to different needs and then pass it to AR to determine the final addressing method.
In register addressing, P#XXX serves as the offset of the AR pointer, used to perform addition operations with the AR pointer, and the result of the operation is the exact address value unit that the instruction actually operates on!
Whether in intra-area or inter-area addressing, the storage area where the address is located has been specified; therefore, P#XXX here can only specify pure numerical values, such as the ★ in the previous example.
【Pointer Offset Operation Rules】
In the register addressing pointer [AR1/2,P#byte.bit] structure, how does P#byte.bit participate in operations to arrive at the final address?
The operation rule is: AR1 and the value in P# are added according to BYTE bits and BIT bits classification. BIT bits are added according to octal rules, while BYTE bits are added according to decimal rules.
For example: The register addressing pointer is: [AR1,P#2.6], we analyze AR1=26.4 and DBX26.4 in two cases.
When AR1 equals 26.4,
AR1: 26.2
+ P#: 2.6
—————————
= 29.7 This is the final exact address value unit for intra-area register indirect addressing
When AR1 equals DBX26.4,
AR1: DBX26.2
+ P#: 2.6
—————————
= DBX29.7 This is the final exact address value unit for inter-area register indirect addressing
【Data Assignment to AR】
Through the previous introduction, we know that to correctly use register addressing, the most important thing is to assign values to the AR register. Similarly, distinguishing between intra-area and inter-area addressing is also based on the assignment of values in AR.
The assignment of values to AR typically has the following methods:
1. Direct Assignment Method
For example:
L DW#16#83000320
LAR1
You can directly assign values using hexadecimal, integers, or binary, but it must ensure that it is 32-bit data. After assignment, the AR1 stores both the address value and specifies the storage area, so the register addressing method at this time must be inter-area addressing.
2. Indirect Assignment Method
For example:
L [MD100]
LAR1
You can assign AR1 content using memory indirect addressing pointers. The specific content is stored in MD100.
3. Pointer Assignment Method
For example:
LAR1 P#26.2
Using the P# 32-bit “constant” pointer to assign to AR.
In summary, regardless of the assignment method used, due to the clear regulations on the data format stored in AR, it is necessary to confirm whether the assigned value complies with the addressing specifications before assignment.
The main purpose of using indirect addressing is to allow the execution results of instructions to have dynamic changes; simplifying the program is the primary goal. In some cases, such addressing methods are necessary, such as traversing data in a certain storage area. In addition, indirect addressing can make the program more flexible; in other words, it can be standardized.
Below, we will analyze how to flexibly use these addressing methods through practical application:
【Application Example of Memory Indirect Addressing】
Let’s first look at a sample program:
L 100
T MW 100 // Transfer 16-bit integer 100 into MW100
L DW#16#8 // Load double word hexadecimal number 8, when used as a double word pointer, according to BYTE.BIT structure,
The result evolution process is: 8H=1000B=1.0
T MD 2 // MD2=8H
OPN DB [MW 100] // OPN DB100
L DBW [MD 2] // L DB100.DBW1
T MW[MD2] // T MW1
A DBX [MD 2] // A DBX1.0
= M [MD 2] // =M1.0
In this example, our central idea is actually: to transfer the content of DB100.DBW1 into MW1. Here we used two pointers of memory indirect addressing—single word pointer MW100 to specify the DB block number, and double word pointer MD2 to specify the DBW and MW storage area word address.
————————————————————————–—————-
For the forum friend’s proposal that DB[MW100].DBW[MD2] is an incorrect addressing, here is an explanation:
DB[MW100].DBW[MD2] such an addressing structure can be understood in terms of addressing principles, but from the execution mechanism of the SIEMENS program, it is illegal. In actual programs, for such addressing, the program statement should be written as:
OPN DBW[WM100], L DBW[MD2]
——————————————————————————————–—
In fact, from the central idea of this example, there is no need to be so complicated. But why use indirect addressing?
To clarify the advantages of using indirect addressing, let’s find the answer through comparison.
The example tells us that it ultimately executes the transfer of data from a specific word in the DB to a specific word in the bit storage area. This is a specific operation to transfer the 1 data word of data block 100 to the first word of the bit storage area. If we now need to transfer multiple words (continuous or non-continuous) of the same data block, the direct method is to write such specific operations one by one. The more words to be transferred, the more such statements need to be written. Undoubtedly, even without understanding the principles of indirect addressing, one should realize that such programming methods are unreasonable. However, if we use the method of indirect addressing, the statements become much simpler.
【Structural Analysis of the Example Program】
I will distinguish the example program from the structure and re-enter it as follows:
=========================== Input 1: Variable specifying data block number
|| L 100
|| T MW 100
=========================== Input 2: Variable specifying word address
|| L DW#16#8
|| T MD 2
=========================== Main Program
OPN DB [MW 100]
L DBW [MD 2]
T MW[MD2]
Clearly, there is no need to simply and repeatedly rewrite the main program (red part), and we only need to change the assignment of MW100 and MD2 (green part) to meet application requirements.
Conclusion: By modifying the content of the indirect addressing pointer, the execution result of the main program can be changed; this modification can be dynamic or static.
It is precisely because no changes are made to the actual target program (main program), and the addressing pointer is the only part that needs to be modified, it can be regarded as the input parameter of the main program, just like the input parameters of function blocks. Thus, it can standardize the program, making it portable and universal.
So how do we dynamically rewrite the assignment of pointers? It shouldn’t be another simple and repetitive rewrite.
Let’s complete this example program with a specific application:
Transfer data words 1-11 from DB100 to MW1-11
Before designing the program to complete this task, let’s understand some background knowledge.
【Rules for Dividing Data Object Sizes】
Data object sizes are divided into: bits (BOOL), bytes (BYTE), words (WORD), double words (DWORD). This seems to be a simple concept, but if MW10=MB10+MB11, does that mean MW11=MB12+MB13? If your answer is affirmative, I suggest you continue watching, don’t skip, because neglecting this will lead to errors in the final program.
When dividing data object sizes by bits and bytes, it is offset by the bits of the data object. This means that after 0 bits, it is 1 bit, after 1 bit it is certainly 2 bits, and so on until 7 bits, completing the specification of a byte size. One more bit offset, and we enter the next byte’s 0 bit.
When dividing data object sizes by words and double words, it is offset by the bytes of the data object! This means that MW10=MB10+MB11 does not mean MW11=MB12+MB13, the correct statement is MW11=MB11+MB12, then MW12=MB12+MB13!
The importance of this concept is that if you use MW10 in the program, you cannot perform any operations on MW11, because MB11 is the intersection of MW10 and MW11.
That is to say, for the specific task of “transferring data words 1-11 from DB100 to MW1-11”, we only need to perform 6 transfer operations on DBW1, DBW3, DBW5, DBW7, DBW9, and DBW11. This is the purpose of separately explaining the rules for dividing data object sizes, which seems simple.
【Loop Structure】
To “transfer data words 1-11 from DB100 to MW1-11”, we need to sequentially point the pointer content to the corresponding data words; this dynamic modification of pointer content is actually traversal. For traversal, the simplest method is a loop.
A loop includes the following elements:
1. Initial loop pointer
2. Increment or decrement of the loop pointer
2. Condition judgment to continue or exit the loop body
The program body being looped must be located after the initial loop pointer and before the increment or decrement of the loop pointer.
For example:
Initial loop pointer: X=0
Loop start point M
Program body being looped:——-
Loop pointer increment/decrement: X+1=X
Loop condition judgment: X≤10, False: GO TO M; True: GO TO N
Loop exit point N
If we treat X as the content of the indirect addressing pointer, the operation on the loop pointer is equivalent to dynamically and cyclically modifying the content of the addressing pointer.
【Transfer data words 1-11 from DB100 to MW1-11】
L L#1 // Initialize loop pointer. Here the loop pointer is the addressing pointer we need to modify
T MD 102
M2: L MD 102
T #COUNTER_D
OPN DB100
L DBW [MD 102]
T MW [MD 102]
L #COUNTER_D
L L#2 // +2, because the offset of data words is based on bytes.
+D
T MD 102 // Increment loop pointer, this is the key to dynamically modifying the addressing pointer
L L#11 // Loop count=n-1. n=6. This is because the first entry into the loop is unconditional, but it has in fact executed once.
<=D
JC M2
For detailed analysis of T MD102, L L#11, <=D, please derive according to the previous content.
【Transfer data words 1-11 from DB1-10 to MW1-11】
Here we increase the addressing of DB data blocks, using single word pointer MW100 to store the addressing address, and also use a loop, nested outside the data word transfer loop, thus to complete the task of “transferring data words 1-11 from DB1-10 to MW1-11”, it takes M1 loop 10 times × M2 loop 6 times =60 times.
L 1
T MW 100
L L#1
T MD 102
M1: L MW 100
T #COUNTER_W
M2: For the data word loop transfer program, same as above
L #COUNTER_W
L 1 // Here is not the offset of data words, just a simple increment of numbers, so +1
+I
T MW 100
L 9 // Loop count=n-1, n=10
<=I
JC M1
Through the example analysis, the program traverses the addressing pointer within the range of data objects to be operated on. We see that this traversal of memory indirect addressing pointers is based on bytes and words; how to traverse bits?
This is the content to be analyzed in the next post about examples of register indirect addressing.
L [MD100]
LAR1
And
L MD100
LAR1
What is the difference?
When MD100 is represented in this [MD100] form, you must consider whether the value assigned to MD100 complies with the specifications of the memory indirect addressing double word pointer when assigning, and whether using this addressing format as part of the statement complies with the syntax specifications.
In the first statement of the first example: L [MD100], we see that it commits the latter error.
The memory indirect addressing pointer is used as the exact value unit of the specified storage area. In other words, the pointer does not contain area identifiers; it only indicates a value. Therefore, when adding storage area and size identifiers, consider that the accumulator loading instruction L cannot operate on bit addresses, so it can only specify non-bit addresses.
To compare with the following register addressing method, we modify it to: L MD[MD100]. Assume MD100=8Hex, and we also assume MD1=85000018Hex.
When using MD100 as a double word pointer, its stored value of 0-18 bits will be re “translated” according to the double word pointer structure Byte.bit, and the result of the “translation” is the address pointed to by the pointer, so MD100 with 8Hex=1000B=1.0, thus the following statement:
L MD[MD100]
LAR1
After “translation,” it becomes:
L MD1
LAR1
We have already assumed MD1=85000018; similarly, when MD1 is used as a pointer, the 0-18 bits should undergo “translation” according to the Byte.bit structure. Since it is assigned to the AR address register, it must also “translate” bits 24-31 for area addressing. Thus, we obtain the final value in LAR1 = DIX3.0. This means that we have stored a pointer in the address register AR1 that points to DIX3.0.
—————————–
L MD100
LAR1
This statement directly transfers the value of MD100 to AR, and of course, it also needs to undergo “translation”; the result is AR1=1.0. This means we have stored a pointer in the address register AR1 that points to 1.0, which is directly assigned by MD100.
It seems that the two statements only differ in the results assigned to AR1; however, this is not the case. The values we assumed were specified for comparative purposes. What if MD100=CHex?
In the previous statement, since CHex=1100, its 0-3 bits are non-zero, the program will immediately error and cannot execute. (Because there is no MD1.4 address!!)
The latter statement, after translation, equals 1.4, and the program can execute normally.
(Content sourced from the internet, copyright belongs to the original author)
Disclaimer: If there are copyright issues, please contact for deletion! No individual or organization assumes relevant legal responsibility.
Siemens General + TIA Portal + EPLAN Electrical Drawing Video Recordings for Sale at Low Prices!
ChuangKong Education Siemens General Class Course Introduction
