Dobrý den,
rád bych si uložil informace, známé v čase inicializace tak, abych je později nemusel do dalších funkčních bloků předávat.
Ve funkčním bloku Init mám OUT proměnnou datovou strukturu, kterou v ST mohu použít v dalším funkčním bloku jako IN_OUT, tím se předává do bloku ukazatel na datovou strukturu. To ale v CFC nelze - viz 1. screenshot. Tak jsem jedinou cestu našel, že ukazatel na začátek každé takové proměnné / pole musím předávat i do dalších funkčních bloků - viz 2. snímek obrazovky níže.
Další varianta (než IN_OUT) mě napadlo uložit pointer do datové struktury, takovou deklaraci ale Mosaic nedovolí.
Původně to bylo vyřešeno globálními proměnnými (kdysi se kvůli tomu upravoval Mosaic, aby šlo glob. var z knihovny použít v programu), ale zákazník požaduje více instancí komunikace a tím pádem globální proměnné nejsou možné.
Je nějaká elegantnější cesta než několik ADR(var_array) na vstupu funkčních bloků?
Děkuji za odpověď.
Dušan Ferbas
Odpovědi 5
Dobrý den,
nejjednodušší řešení bude asi to, když funkční blok naplní při inicializaci strukturu nebo pole daty a bude předávat na výstupu pointer na strukturu/pole jako UDINT. V tomto případě půjde instance funkčních bloků navázat na sebe, protože proměnnou typu UDINT už můžeme navázat jako zdroj pro VAR_IN_OUT a uvnitř toho druhého bloku převedeme UDINT na pointer a můžeme přes něj na příslušnou strukturu / pole přistupovat.
FUNCTION_BLOCK fbInit VAR_OUTPUT out : REAL; ptrOut : UDINT; END_VAR ptrOut := PTR_TO_UDINT(ADR(out)); END_FUNCTION_BLOCK FUNCTION_BLOCK fbSmRead VAR_INPUT ptrTest : UDINT; END_VAR VAR pTest : PTR_TO REAL; END_VAR pTest := UDINT_TO_PTR(ptrTest); END_FUNCTION_BLOCK PROGRAM prgMainCfc VAR Init : fbInit; Read1 : fbSmRead; Read2 : fbSmRead; END_VAR
Děkuji za tip.
Koukám, že UDINT byl vybrán jako zástupce za ukazatel, protože jiné funkce pro převod z / na PTR nejsou :-).
Nicméně pak podle mě postrádá mysl striktní kontrola na typ proměnných, když je mohu takto přetypovat. Něco jako void * v jazyce C.
Vidím další nevýhodu - pokud mám VAR_IN typu UDINT, tak v CFC tam klidně dám ADR(smInit.Instance) /tedy PTR_TO/ a Mosaic ani neškytne a program sestaví.
Nač mi je potom striktní kontrola v ST, když v CFC tam uživatel knihovny pak může strčit leccos. To by podle mě byl zdroj chyb.
V podstatě se přimlouvám za vylepšení Mosaicu - co jde v ST, aby šlo v CFC a co nejde v ST, aby nešlo v CFC. Přijde mi to konzistentní.
Jen ze zvědavosti: Nešlo by inicializační data definovat jako samostatnou globální proměnnou, která by se předávala do fbInit i fbSmRead jako IN_OUT? Tj. knihovna by definovala jen typ takové proměnné, aplikační program by deklaroval její globální instance.
Dobrý den,
upozornění na Vaši odpověď mi přišlo až dnes :-).
V podstatě tak jsem to udělal - je definována struktura, proměnná s touto strukturou je pak použita jako IN_OUT, proměnná nemusí být globální.
Má to ovšem několik nectností:
- Tím, že obsah struktury (proměnné) je definován až po 1. průchodu funkčním blokem, musí být tento blok v POU jako první. Pokud není, ostatní funkční bloky pracují s ještě nenainicializovanými údaji.
- Strukturu nejde staticky nadefinovat, protože to Mosaic nedovolí - viz screenshot níže. Struktura bude vždy stejná, pouze velikost polí Inverter atd. je jiná, ale to řeší překladač.
- Tuším byl nějaký problém s předáváním do vnořeného bloku, nakonec jsem zvolil variantu s ADR(té_proměnné_se_strukturou) - něcona způsob 2. screenshotu v 1. příspěvku.
- Zajímavé bylo, že jsem omylem nadefinoval (V záhlaví CFC) typ proměnné IN_OUT jako funkční blok, Mosaic nezařval, že tp je jiý typ a vše fungovalo :-).
Šla by udělat alespoň ta statická inicializace?
Tento dotaz je vyřešený.