Változók és típusok (rácímzés)

STL és LAD/FBD

Az STL alacsonyabb szintű nyelv mint a LAD vagy az FBD, kevésbé érzékeny az adattípusok keverésére (kevésbé "tipizált").
Mit is jelent ez?
LAD/FBD-ben szigorúbb szabályok vannak a típusok kezelésére. Ezért ha létrhozunk egy INT (egész) típusú változót, azzal csak olyan műveleteket enged elvégezni, amelyek egész számmal végezhetőek el. Ezért pl. egy WORD típusú számot nem tudunk hozzáadni egy egészhez, nem engedi hogy két BYTE típusú adatot hasonlítsunk össze, stb.
Ha megpróbáljuk, hibát jelez:



Mindez nem meglepő, ha figyelembe vesszük, hogy a példában szer eplő utasítások, ahogy az a nevükben is benne van, csak INT típusú adattal képesek műveletet végezni (CMP ==I.és ADD_I).
A baj az, hogy ilyen utasítások nem léteznek BYTE és WORD típusokra (csak REAL, INT és DINT típusokra).
Mit tehetünk tehát, ha növelni, csökkenteni kell egy byte értékét? Vagy ha netán össze akarjuk hasonlítani valamivel?

Megpróbálhatjuk átkonvertálni pl. egésszé, majd vissza. Sajnos nincs BYTE-INT vagy WORD-INT konverzió. De ezzel nem fogytunk ki a lehetőségekből, hiszen akár hagyhatjuk is az egészet a fenébe :)
Valamivel tudományosabb, ám kevésbé elegáns megoldás, ha eltérő típusú változók között mozgatjuk az adatot. Ezt az a tény teszi lehetővé, hogy a MOVE utasítás LAD/FBD-ben is, univerzális. Nem finnyás a típusokra. Sajnos a módszerhez mindkét példánál szükség van egy átmeneti tárolóra. Mivel ennek tartalmára nincs szükségünk a művelet után, célszerű lokális változót használni erre a célra:

Byte növelése 1-el:


A fenti példa Az MB8 merker byte-ot átmásolja az #AT lokális változóba, amit INT típussal hoztunk létre. Ehhez hozzáad 1-et, majd visszamásolja MB8 byte-ba. Az eredmény: MB8-hoz hozzáadtunk 1-et. Körülményes, de működik.
Az STL fordító nem végez típus ellenőrzést, ezért STL-ben a byte növelését egy menetben, átmeneti változó nélkül is elvégezhetjük:

 

Byte összehasonlítása:


Az összehasonlítás STL-ben:



Mire jó ez a szigor LAD/FBD-ben?
Nos mivel a BYTE és az INT típusok nem teljesen kompatibilisek egymással, lehet néhány mellékhatása az STL nagy szabadságának.
Az ok az ábrázolási tartományban keresendő. A byte ugyanis 0-255 értéket tartalmazhat, az integer viszont -32768 - 32767.
Ha tehát egy byte-tal úgy végzünk műveletet, hogy integer-é konvertáljuk, elvégezzük a műveletet majd az eredményt visszarakjuk a byte-ba, akkor adatvesztés történhet, ha a művelet eredménye nem fér bele a byte ábrázolási tartományába. Ha a művelet kivonás, a művelet eredménye negatív lesz, a byte-ba erőltetés miatt szintén hamis eredményt kapunk.
Pl. ha 4-ből kivonunk 25-öt, az eredmény még integer formában -21 lesz. A -21-et  2-es komplemens formában tárolja, ami binárisan: 1111111111101011. Amikor ezt a transfer utasítással byte-ba tesszük, csak az alsó 8 bit kerül át, vagyis a bináris 11101011. Ez decimálisan 235-nek felel meg. Az eredmény tehát hibás lesz, mert 4-25=235 nem helyes.
Az összehasonlítás szintén elővigyázatosságot követel, ha konstanssal hasonlítjuk össze a byte tartalmát, az nem lehet negatív, vagy 255-nél nagyobb!
Mivel LAD/FBD-ben a fordító nem engedi a típuskeveredést (kivéve Move) ilyen hibát ott nehezebb elkövetni, ám STL-ben a programozónak kell figyelnie ezekre a kivételekre.

Változó elérése bitenként

Néha szükség van arra, hogy bizonyos változókat bitenként címezzünk. Pl. amikor valamelyik perifériáról olvasunk be állapot biteket (a PI nem címezhető bitenként) vagy egy word-ot léptetünk jobbra vagy balra.
Ennek is több módja van. A legegyszerűbb az, ha egy MOVE utasítással egy MW-be másoljuk az adatot, az MW-t ezután bitenként címezhetjük.
Pl. ha a PIW 3-as bitje érdekel minket, akkor bemásolva egy merker word-be, ami legyen pl. MW12, akkor a 3-as bitet az M13.3-ban érhetjük el. (Ne feledjük, hogy a word-ben, a byte-ok sorrendje fordított).
Természetesen DB word-be is tehetjük. De használhatunk byte-ot vagy duplaszót is, amire épp szükség van. A módszer hátránya, hogy "elpazarolunk" vele néhány byte-ot a másolat létrehozásához.

Ha a másolatot a bitenkénti elérés érdekében lokális változóba tesszük, nincs pazarlás, a lokális változók (L terület) címezhető bitenként.



Létrehoztuk a #TEMP lokális változót, ami  a 0-ás címre került. Ez látható az Address oszlopban. A MOVE utasítás belemásolta a PIW256-ot, aminek a 3-as bitje bekapcsolja az M1.0 merker bitet. Deklaráltunk tehát egy változót és közvetlen címzéssel értük el benne az egyik bitet.
Ennek miért is ne lenne hátránya? Nézzük mi az:
Ha egy újabb lokális változót hozunk létre, kapunk egy figyelmeztető üzenetet:



Az üzenet emlékeztet bennünket, hogy az L területet abszolút módon címezzük. Ha egy új változót hozunk létre ezen a területen, akkor a címzett változó címe eltolódhat. Amikor ez megtörténik, akkor a címzett területen már másik változó lesz, így az abszolút címzésünk hibás lesz. Mindez akkor történik meg, ha a közvetlenül címzett változó elé szúrunk be újabb változókat vagy onnan törlünk egyet, vagy úgy változtatjuk meg előtte egy másik változó típusát, hogy az általa elfoglalt byte-ok száma megváltozik (pl. INT-et átírjuk DINT-re).

Ezt a problémát elkerülhetjük pointer használatával.
Nem közvetlenül címezzük meg a #TEMP lokális változót, hanem annak valós címén keresztül, indirekt módon:



Ezt a módszert használva, a #TEMP akárhol lehet a lokális változóterületen belül, annak címét a program futás közben lekérdezi majd a kapott cím alapján címzi meg a szükséges bitet.

Vigyázat! A TEMP lokális változóterület nem keverendő össze az FB blokkok STAT változóterületével. Az utóbbi terület ugyanis az FB blokkhoz hozzárendelt instance adatblokkba kerül, ezért L helyett DI terület azonosítóval címezhető (DIX, DIB, DIW, DID)!



Szirty