Keresés

Új hozzászólás Aktív témák

  • Szirty

    őstag

    válasz horvathcsaba #225 üzenetére

    Helló horvathcsaba!

    Ennek programozásához egy Sipro nevű szoftvert használunk.
    [...]
    Kerestem már angol nyelvű verziót. De nem találtam. Tudtok ebben segíteni?

    Nem ismerem a sipro-t, de azért rákerestem.
    Szerintem pontosítani kellene a szoftver nevét, mert ilyen nevű villanykapcsoló, valami Simoreg Digital Converter Cabinet Unit, meg IP telefon van. De olyan siprot, aminek köze van az S5-höz nem nagyon lelt.

  • Szirty

    őstag

    válasz horvathcsaba #240 üzenetére

    Hali Csaba!

    És napi időpontokat szeretnék összehasonlítani. Pl. elmúlt-e már 7 óra. És ezt csak hihetetlen mennyiségű rendszerfunkcióval sikerült elérnem.
    Van ennek vmi egyszerű módja?

    Van. 1 rendszerhívás. Persze akkor neked is csinálni kell valamit :)
    Én úgy szoktam, hogy az SFC1-el másodpercenként egyszer kiolvasom a rendszer órát:

    A fenti példában az idő a Date_And_Time típusú #CPUIDO lokális változóban landol, ahonnan már úgy olvasod és használod fel, ahogy akarod.
    A DATE_AND_TIME típus így néz ki:

    Mivel tudod melyik byte-on van az óra, a perc, stb, összehasonlítod közönséges komparátor utasítással. De ne feledd, a DATE_AND_TIME típus PCD adatokat tartalmaz!

    Lehet ennél is egyszerűbben, méghozzá a Time-of-day interrupt. Ez arról szól, hogy egy általad meghatározott időpontban a CPU önállóan meghív egy OB-t. Az a funkció CPU függő, a CPU hw konfigjában találod.
    Ezzel arra kell vigyázni, hogy ha a CPU órát átállítod (pl. daylight saving) úgy, hogy az állítás időben előre történik és a time of day interruptnak megadott időt pont átugorja, akkor egy exception keletkezik, amit külön kezelned kell a time error OB-ban!

  • Szirty

    őstag

    válasz horvathcsaba #245 üzenetére

    Hali Csaba!

    Csak azért gondoltam, hogy lennie kellene vmilyen "standard" megoldásnak, mert pl. Telemecanique Zelio Logic eszközhöz (ez egy kis egyszerű család) adott fejlesztőkörnyezetben vannak nagyon jó dátumkezelő modulok.

    Vannak. Nézz szét az IEC funkcióblokkok között. De erre nyilván megint azt mondanád, hogy ezerféle funkcióval kell konvertálni. De írhatsz is ha akarsz ilyen blokkokat, és akkor használhatod máskor is. Kérdés mit is szeretnél pontosan.
    Nem hinném hogy CMP-nél találsz egyszerűbb megoldást konkrétan erre.

  • Szirty

    őstag

    válasz horvathcsaba #249 üzenetére

    Helló Csaba!

    Én ezt szeretném csinálni:
    T DB1.DBD [MD30]
    De nem engedi, mondván "Fully qualified access is not permitted with DI or indirect addresses."
    Ezt viszont engedi:
    T DBD [MD30]
    Csak innen honnan tudom, illetve hogy tudom meghatározni melyik DB.

    Így csináld:
    OPN DB1
    T DBD [MD30]

    Az OPN DB1 "megnyitja" a DB-t. Innentől kezdve a DB számára már nem kell hivatkoznod.
    De két dologra nagyon kell figyelni:
    A DB-t az ún DB regiszterrel címzi. Az OP gyakorlatilag a DB regiszterbe teszi bele a megnyitott DB számát.
    Fully qualifyed access esetén, amikor kiírod a teljes címet, a DB regisztert akkor is használja. Ha tehát ezt csinálod hogy:

    OPN DB1
    L DBW4
    ...
    L DB6.DBW2
    ...
    L DBW8

    Akkor az első load a DB1-ből, a második természetesen a DB6-ból, de a harmadik nem a DB1-ből, ahnem a DB6-ból fog betölteni egy értéket (ha sikerül neki).

    A másik amire vigyázni kell az az indirekt címzésmód:
    T DBD [MD30]
    Itt MD30 címzi ugye a DB-t, de nagyon fontos, hogy az MD30-ban egy pointer (P#x.y) van, és nem egy sima index!!!
    A helpben érdemes utánanézni a "Using the Parameter Type POINTER" című résznél.
    A pointer alsó 3 bitje pedig bit cím. Hoyg úgy működjön ahogy szeretnéd, így csináld:

    OPN DB1
    L idebetöltöd az indexet
    SLD 3
    T MD30
    T DBD [MD30]

    Írtam erről az oldalamon, ha gondolod nézd meg:
    [link]
    Jóval kezded te is, pont az indirekt címzéssel :)

  • Szirty

    őstag

    válasz horvathcsaba #249 üzenetére

    Helló Csaba!

    Jah eegen. Azt elfelejtettem írni, hogy az indirekt címzéssel vigyázni kell. Nagyon könnyen elcímzi magát a program és akkor jön az Area length error, aminek a következménye egy szép kövér CPU stop.
    Nagyon körültekintően kell csinálni nagyon alaposan tesztelni és telerakni védelemmel ami megakadályozza az elcímzést. Csúnya dolgokat tud csinálni.

    Én pont most szívtam egy gyári blokkal (Read Danfoss VLT parameter) amiben volt egy ilyen szép kis meglepetés.

  • Szirty

    őstag

    válasz horvathcsaba #252 üzenetére

    Helló Csaba!

    A kódhoz lenne hozzáfűzni valóm ha nem gond. Kizárólag építő jelleggel, nehogy cseszegetésnek vagy okoskodásnak vedd!

    - A ciklusmagon belül, vagy a blokkon belül használt átmeneti értékeket szerintem lokális változókban tárold, de globálisban. (A merkerek és a shared DB minden eleme globálisak). Ennek töb előnye van:
    1. Másik blokk, a program egyéb részei nem tudnak véletlenül se belenyúlni, nehezebben rontod el a programot (pl. nem emlékszel, hogy az MW10-et már felhasználtad az egyik blokkban ciklusváltozó ként és egy másik blokkban is fel akarod használni).
    2. Miután a blokk lefut, a változóra nincs szükség.
    Az ilyen változókat tehát lokálisként érdemes deklarálni (TEMP).

    És az az érdekes dolog állt elő, hogy csak az utolsó megcímzett elem utáni elem tartalmazott értéket. Na de rájöttem!

    Hát igen, ha alacsony (2 byte-on is ábrázolható) értékeket duplaszavakba pakolsz és azokat 2 byte-os átfedéssel rakod le, akkor a következő dupla szó felső 2 byte-ján lévő 00 mindig felülírja az előzőleg lerakott duplaszó alsó két byte-jén lévő nem nulla értéket.

    VAn-e arra lehetőség, hogy dinamikusan foglaljak le memóriaterültet? Pl 'x' elemű tömb kellene, de az 'x' a program betöltésekor még nem ismert. Vmilyen felhasználói interakció lévén derül ki.

    Tanulmányozd a "STEP 7 - System and Standard Functions for S7-300 and S7-400" címűPDF-et (a Step7 alapból feltelepíti).
    Abban is a következő rendszerhívásokat:
    - Creating a Data Block with SFC 22 "CREAT_DB"
    - Deleting a Data Block with SFC 23 "DEL_DB"
    - Generating Data Blocks in Load Memory with SFC 82 "CREA_DBL"
    - Reading from a Data Block In Load Memory with SFC 83 "READ_DBL"
    - Writing a Data Block in Load Memory with SFC 84 "WRIT_DBL".
    - Creating a Data Block with SFC 85 "CREA_DB"

    Szerintem ezekkel meg tudod oldani. De arra számítani kell, hogy egy csomó folyománya lesz az ügynek. Pl. ellenőrizni kell, hogy a létrehozandó adatblokk egyáltalán elfér-e a szabad memóriában, stb.

    vagy ezt úgy érdemes csinálni, hogy jó nagy területet foglalok le és csak bizonyos részét használom?

    Igen, sokszor ez az egyszerűbb, és nem utolsó sorban biztonságosabb.

    Azonban ez pazarlásnak tűnik.

    Bizonyos értelemben igen. De gondolj arra, hogy a PLC memóriája adott. Ha ennek a memóriaterületnek egy részét takarékosságból szabadon hagyod, az ugyanolyan pazarlás, mint az, hogy lefoglalod az egészet, de értelmes adatot valószínűleg nem töltesz bele.
    :)

  • Szirty

    őstag

    válasz horvathcsaba #264 üzenetére

    Helló horvathcsaba!

    Nos az általad idézett PID controler hívás szerintem a következők miatt nem úgy működik mint ahogy várod:

    1.
    I_ITL_ON:=TRUE
    Ez az integráló tag inicializálását kapcsolja be, és mivel TRUE értéket adtál neki, nálad ez aktív. Az inicializálás azt csinálja, hogy ha az I_ITL_ON:=TRUE, akkor az integráló tagbe beírja az I_ITL_VAL értékét, ami a te hívásodnál 0. Ezzel gyakorlatilag hatástalanítod az integráló tagot, mivel az nem lesz képes kimozdulni 0 értékről (amennyire tudom az I_ITL_ON nem élvezérelt).

    2.
    CYCLE :=T#10S
    A nagyobb gond szerintem ezzel lesz. A PID controller hívásának van egy olyan szabálya, hogy konstans időközönként kell meghívni! Tehát nem tehetd bele simán a programban, ahol minden PLC ciklusban lefut, mivel a PLC ciklusok hossza nem konstans. Két kézenfekvő hívási mód kínálkozik:
    - Egy élvezérelt cycle memory bittel hívod.
    - Cyclic interruptból hívod (pl. OB35)
    Mindkét megoldás biztosítja a fenti feltételt. A PID CYCLE paraméterében pedig pontosan ugyanezt az időt kell megadnod amennyi időnként hívod (ms pontossággal). Ebből tudja a PID "belül", hogyan telik az idő, ennek alpján számolja az integrálási és diff időket stb. Ezért ha ez a paraméter nem jól van megadva, akkor a PID rendszerint kiakad vagy nem megfelelően működik.
    A dolog folyománya hogy a PID legkisebb reakcióideje a hívási ciklusidőnél semmiképp nem lehet kisebb.
    A fenti 10s tehát valószínűleg nem jó, hacsak nem 10 másodpercenként hívod a PID-et.

    3.
    PVPER_ON:=TRUE
    Ha a PVPER_ON be van kapcsolva, akkor a PID-nek a mért értéket (process variable) perifériaszó formában adod meg és a PID-re bízod az érték normalizálását (0-100% tartományra konvertálását), amit a PV_FAC mint szorzó és PV_OFF mint eltolás értéke alapján számol ki. Ezek nálad 1 és 0. Tehát ettől működhet ugyan, de a PIW 256-ban 0-100 tartományban kell tartani az értéket. A Step7 alapból feltelepít egy doksit ami angolul ugyan, de elég jól leírja mi merre meddig. Ebben van is egy blokk diagram a PID-ről, ami segít áttekinteni a paramétereket:

  • Szirty

    őstag

    válasz horvathcsaba #264 üzenetére

    horvathcsaba

    Azaz bizonyos szelepnyitottságot tartanom kell. Ezt statikusan az LMN_OFF-fal tudom beállítani.

    Hátőő.. nos igen. Kétségtelen, hogy az LMN_OFF hatással van a beavatkozó értékre, de az csak a beavtkozó érték offsetjét (eltolását adja). A legtöbb esetben ezt 0 állítjuk.

    Azonban ha a víz fogyása időben dinamikusan változik, mit tudok tenni?

    Nos ha a szintet "fokozatmentesen" akarod szabályozni, akkor a fokozatmentes mennyiségszabályzáson kívül (szelep) kell egy mérés is, ami a kád szintjével arányos értéket ad. Ezután a kád szintjével arányos mért jelet a PID PV_PER bemenetén adod meg, bekapcsolod a PVPER_ON-t és a PV_FAC, PV_OFF paramétereket úgy állítod be, hogy maximális szintnél 100, minimálisnál 0 érték keletkezzen ormalizálás után (PV kimenet).
    Vagy a mért értéket a PV_IN bemenetre adod és a PVPER_ON-t kikapcsolod. Ekkor a PV_PER-re adott értéknek 0-100 tartományba kell esnie.

    Az SP_INT bemeneten megadod neki mekkora szintet akarsz tartani a kádban (0-100 között).
    Az LMN kimeneten pedig megjelenik (0-100 tartományban) a beavatkozó jel, ami közvetlenül megadja hogy a szelepnek mennyire kell kinyitnia ahhoz, hogy a kád szintjét az SP_INT-nél megadott szinten tartsa.
    A többi paraméter beállításával pedig be lehet hangolni, hogy a kádban aszint állandó legyen attól függetlenül, hogy az elfolyó mennyiség közben hogyan változik.

    Az előző üzenetben hivatkozott PID leírás [a neten is megtalálható]
    Illetve valamennyit én is rizsáltam róla [itt]

  • Szirty

    őstag

    válasz horvathcsaba #267 üzenetére

    Helló horvathcsaba

    Ok, én nem tudhattam mit olvastál már a témában, elnézést ha már ismert forrást ajánlottam.

    Szintén a példa hozta. Igazából az OB35-be tettem a PID-et. A S7 help az OB35-re 100ms intervallumot ír.

    Az jó lehet. Én is 100ms-re szoktam tenni a PID-et. (néha 500-ra).
    Egyébként az OB35 hívási gyakorisága állítható a hardver konfigban (de a dolog CPU-tól is függ).

    Akkor a CYLE is 100ms kell legyen? Legalábbis így értem.

    Pontosan! Tehát: CYCLE :=T#100MS

    Nekem ebből az jön le, hogy a %-ra alakítás miatt a PIW 256 nem kell, hogy 0 és 100 között legyen.

    Ez így igaz, de azt is odaírtam előtte, hogy a PVPER_ON értékét további két paraméter szerint, a PV_FAC mint szorzó és PV_OFF mint eltolás értéke szerint skálázza.
    Ezeket az értékeet azonban az általad idézett példa defaulton hagyta, vagyis aszorzó 1, az eltolás pedig 0. Tehát így NEM végez skálázást.
    Ennélfogva a PV értéke csak akkor marad 0-100 tartományban, ha a PVPER_ON-nak megadott perifériaszavad is azon belül marad.
    Egyébként a skálázás lényege az amit le is írtál. Én csak azért említettem mert minek tetted skálázós bemenetre, ha aztán meg mégsem skáláztad.

    Nekem ebből az jön le, hogy a %-ra alakítás miatt a PIW 256 nem kell, hogy 0 és 100 között legyen. Mert PIW 256 = 0 -> 0% és PIW 256 = 27648 -> 100%.

    PIW256 = 27648 csak akkor lesz 100%, ha a PV_FAC paraméterbe nem egyet teszel, hanem 0.003616898148148148-at, vagyis: PV_FAC :=3.616898e-003
    De egyébként úgy van, ahog írtad!

Új hozzászólás Aktív témák