I must confess that the location of variables in the memory and their addresses had been until recently a complete black magic. I was raised on simple programming languages like Basic or JavaScript and if I needed to declare a variable I wrote "var Variable". I never had to know where the program stores the new value. Such an information is normally redundant.
In case of a PLC the addressing became important. If one knows the variable's address, one can read it via a webserver using the READPI command. If I declare "myVariable AT MB0 : BYTE" and use the command "READPI ADR=MB0&FORMAT=%d" (by, for example, creating a SSI file placed in the PLC memory and entering into the browser address bar: "http://PLCaddress/READPI?ADR=MB0&FORMAT=%d) I will get the current value of myVariable.
What are the differences between different type of variables? What is the difference between MX0.2 od MB2 i MW2? You can find my explanation below.
My WAGO 750-841 has 8kB of addressable memory, which can be used to store and exchange values. That memory is, naturally, built of individual bits (accepting value 0 or 1). Those bits, when connected into groups of 8 turn into bytes (accepting values from 0 to 255), which connected into pairs store WORD values (accepting values from 0 to 65 536), which in turn, when connected into pairs store DWORD values. One can imagine that the memory is like a tape, which can be cut into individual bits or larger bytes etc.
Once a variable is defined in CoDeSys and it receives a fixed address, the compiler is told where it should reach to read/write a value to that variable. If a BOOL variable receives a MX0.0 address, it is placed in the 1st bit of our addressable memory. If a BYTE variable is defined under MB0, it will be placed in the 1st byte.
Here is the first thing, which surprised me: by addressing different variables, one can assign them to overlapping parts of memory. A change of a BOOL variable stored at MX0.0 will change the value of a BYTE variable stored at MB0.
To show how it all functions I prepared a simple program using many different variables:
V_BOOL AT %MX0.0 : BOOL; V_BYTE AT %MB0 : BYTE; V_WORD AT %MW0 : WORD; V_DWORD AT %MD0 : DWORD; V_STRING AT %MD0 : STRING(4);
In the programming part just one line is sufficient:
V_STRING:='abcd'
Once we compile such a program in the simulation mode, this is what we will see:
Once we run the program (F5), the values will change:
What happened? Where do those numbers come from?
On program start the variable V_STRING receives the value 'abcd'. The 'a' is stored in the 1st byte of the memory, 'b' in the 2nd etc. Letter 'a' in ASCI code is equal to 97, so V_BYTE addressed to the 1st memory byte (so also to the first character of the V_STRING) is equal to 97. 97 in binary form is equal to 0110001, so the value of V_BOOL, addressed to the first bit of the memory is equal to 1 = TRUE.
The letter 'b' in the ASCI code is 98, so the 2nd byte of the memory stores the value 98. Consequently the V_WORD is equal to 97+256*98 = 25 185. The value of the V_DWORD comes from 97+256*98+2562*99+2563*100 (where 99 is the letter 'c' and 100 is 'd').
Here is a link to a simple program with the above-presented example. You can enter any value you want via a visualization and see how it affects the value of the remaining variables.
Now a few words about the addressing convention. Here is an example taken from the PLC manual:
Bit | %MX11.0 ... 15 | %MX12.0 ... 15 | ||
Byte | %MB22 | %MB23 | %MB24 | %MB25 |
Word | %MW11 | %MW12 |
Which means:
Furthermore, the address itself is built of 4 parts, which we can call „ABCD”:
Position | Allowed values | Description |
A | % | Address Mark |
B |
I |
Inputs |
C |
X |
Single Bit |
D | Address | Address number |
That's all! That is how the inputs and outputs are addressed. I used it previously by reading for example a status of an output: by READPI?ADR=IX8.2. Now I know that I red a 3rd bit from the 8th word from the memory part dedicated to outputs.
The main lessons from it all are: