Utilizarea limbajului de programare ANCI C in mediul WinCC

1.Controale de intrare-iesire


    Aplicatiile SCADA simple se pot crea in principiu fara a utiliza notiuni de programare. Aplicatiile mai complexe nu pot fi realizate decat utilizand facilitatile oferite de limbajele de programare ANSI C si VB incluse in mediul de dezvoltare WinCC

Controale de tipul on/off

    Folosind Graphics Designer vom crea o pagina grafica "led1" pentru a simula comanda de alimentare cu energie a unui proces. Alimentarea va fi semnalizata in pagina grafica prin aprinderea unui LED. LED-ul va avea doua stari. Starea stins de culore gri si starea aprins, de culoare verde.

    Se va defini un Internal Tag -L1 de tip boolean care va fi modificat de Toggle button si afisat de un cerc caruia i se va seta Background color in functie de L1

    Display Library -- Operation -- Toggle Buttons -- On_Off_1
       - se seteaza Properties -- Tag -- Assignment -- Dynamic -- Tag -- L1 --Update 250 ms
    Standard Objects -- Circle
       - se seteaza Properties -- Efects -- Global Color Scheme -- No
       - se seteaza Properties -- Colors -- Background color -- Dynamic -- Dynamic Dialog -- Tag -- L1 -- Bolean



    Se observa ca nu se poate seta Update Time, acesat fiind setat implicit la 2 s. Vom folosi alta metoda prin utilizarea Smart Objects-ului -- Status Display in urmatoarea pagina grafica "led2"
    Smart Objects -- Status Display
      -se atribuie Tag -- L1 -- Update 250 ms
      -se atribuie imagini pentru 0 si pentru 1 corespunzatoare lui L1



    Se pot utiliza simbolurile existente in biblioteca. Pentru a realiza un Set simbol de vane controlat de doua butoane on respectiv off. In continuare se vor alege doua simboluri din biblioteca atfel: un simbol pentru vana on si un simbol pentru vana off si se vor plasa pe Layer-uri diferite in urmatoarea pagina grafica "c_led3"

    Pentru valva off, se seteaza
      -- Properties -- Miscellaneus -- Display -- No

    Se plaseaza doua butoane unul On si altul Off
    Windows Objects -- Button -- Text -- On
      -- Properties -- Events -- Mouse -- Action -- C Action

#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
SetVisible(lpszPictureName,"Gruppe43", 1 );
SetVisible(lpszPictureName,"Gruppe45", 0 );
}

    Windows Objects -- Button -- Text -- Off
      -- Properties -- Events -- Mouse -- Action -- C Action

#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
SetVisible(lpszPictureName,"Gruppe43", 0 );
SetVisible(lpszPictureName,"Gruppe45", 1 );
}




Controale alfanumerice de intrare/iesire

    Vom crea o noua pagina grafica "c_afisd_01" ,in care vom afisa un text la apasarea unui buton.
    Afisarea textului se face utilizand un obiect standard
    Standard Objects -- Static Text -- Text=Loc mesaj
    Windows Objects -- Button
       - se seteaza Properties -- Font -- Text=Start
       - se completeaza Events -- Mouse -- Mouse Action cu urmatoarea procedura:

#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
SetText(lpszPictureName,"Static Text1","Ati actionat START");
}




    Se poate folosi pe post de consola Smart Object-ul Applications Windows
    Vom crea o noua pagina grafica "c_afisd_02" ,in care vom afisa valoarea tag-urilor Temp si L1
    Plasam urmatoarele elemente:
    Smart Objects -- Applications Windows
       - se seteaza Global Script -- GSC Diagnostics
    Windows Objects -- Button
       - se seteaza Properties -- Font -- Text=Start
       - se completeaza Events -- Mouse -- Mouse Action cu urmatoarea procedura:

#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
int Tag_T ;
int Tag_L1;

Tag_T=GetTagWord("Temp");
Tag_L1=GetTagWord("L1");
printf("\n\tTemperatura: %d  grade\n",GetTagWord("Temp"));
printf("\n\tValoarea tag-ului L1:%d\n",Tag_L1);

}




    Pentru afisari in format binar se poate folosi controlul 8 bit Display +I/O Field aflat in Global Library
    Vom crea o noua pagina grafica "afisn_03" ,in care vom afisa valoarea tag-ului Temp in format binar. Plasam urmatoarele elemente:

    Display Library -- Displays -- Displays -- 8 bit Display +I/O Field
       - se seteaza Properties pentru 8 bit Display -- User Defined2 -- Byte Value -- Tag -- Temp --Update 250 ms
       - se seteaza Properties pentru I/O Field -- InputOutput -- OutputValue -- Tag -- Temp --Update 250 ms
    Windows Objects -- Slider Obiect -- Tag -- Temp -- Update 250ms


    Vom crea o noua pagina grafica "c_afisd_04" ,in care vom introduce valoarea tag-ului Temp de la tastatura folosind un Smart Object I/O Field. Plasam urmatoarele elemente:
    Standard Objects -- Static Text
    Smart Objects -- I/O Field
       - se seteaza: Tag -- Temp -- Update 250ms
       - se completeaza Events -- Keyboard -- Press cu urmatoarea procedura:

#include "apdefap.h"
void OnKeyDown(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName, UINT nChar, UINT nRepCnt, UINT nFlags)
{
char*   val_i;
val_i=GetInputValueChar(lpszPictureName,"I/O Field2");
SetText(lpszPictureName,"Static Text1",val_i);

}




Controale grafice de intrare/iesire

    Vom crea o noua pagina grafica "afis_01" , care permite modificarea valorii tag-uli Temp de tipul Unsigned 8-biti predefinit anterior.
    Pentru modificarea dinamica a valorii tag-ului Temp se va folosi un Slider Object.
    Afisarea valorii tag-ului se face prin intermediul unui control de tip Meter.

    Display Library -- Meters -- Meter2
       - se seteaza Properties -- User Defined2 -- Process --Dynamic -- Tag -- Temp --Update 250 ms
    Windows Objects -- Slider Obiect -- Tag -- Temp -- Update 250ms



    Vom crea o noua pagina grafica "afis_02" , care contine:

    Controls -- Activx Controls -- Wincc Gauge Control
       - se seteaza Properties -- Control Properties -- Value -- Tag -- Temp -- -- Update 250ms

    Controls -- Activx Controls -- Wincc Slider Control
       - se seteaza Properties -- Control Properties -- Position -- Tag -- Temp -- -- Update 250ms

    Windows Objects -- Rectangle
      -- Properties -- Rectangle -- Filing -- Fill Level -- Tag -- Temp --Update 250 ms

    Display Library -- Meters -- Meter2
       - se seteaza Properties -- User Defined2 -- Process --Dynamic -- Tag -- Temp --Update 250 ms



    

2. Instructiuni decizionale
Instructiunea if / else:

    Instructiunea if / else se foloseste pentru a executa o instructiune sau o secventa de instructiuni cand valoare logica a unei expresii este adevarata si alta instructiune sau o secventa de instructiuni pentru cazul cand valoarea logic a aceleiasi expresii nu este adevarata.

  • Formatul instructiunii:

        if (expresie logica) {
          instructiuni;
    }
        else{
          instructiuni;
    }


  • Aplicatii care utilizarea instructiuni decizionale

        Vom incerca sa utilizam in continuare instructiunea if / else pentru a controla functionarea butonului Pornit/ Oprit.

       Vom realiza aplicatia "c_if_01" vom implementa on buton on/off.

        Vom plasa un Smart Objects -- Status Display
          -setam -- Tag -- L1 -- Update 250 ms
          -tribuim imagini pentru 0 si pentru 1 corespunzatoare lui L1
       Se plaseaza un buton start din Windows Objects -- Button -- Text = On/Off
           -se completeaza -- Properties -- Events -- Mouse -- Action -- C Action -- cu urmatoarea procedura

    #include "apdefap.h"
    void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    	BOOL  x;
    	x=GetTagWord("L1");
    	if (x==1) {
    		SetTagBit("L1",0);
    	}
    	else{
    		SetTagBit("L1",1);
    	}
    }
    


       Urmatoarea aplicatie "c_if_02" vom implementa on buton on/off din simboluri.
       Se plaseazadoua simboluri pe Layer-uri diferite
           -se completeaza pentru fiecare simbol -- Properties -- Events -- Mouse -- Action -- C Action -- cu urmatoarea procedura

    #include "apdefap.h"
    void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    	BOOL x;
    	x=GetTagWord("L1");
    	if   (x==1){
    		SetTagBit("L1",0);
    		SetVisible(lpszPictureName,"Poligon4", 0 );
    		SetVisible(lpszPictureName,"Poligon5", 1 );
    	}
    	else{
    		SetTagBit("L1",1);
    		SetVisible(lpszPictureName,"Poligon4", 1 );
    		SetVisible(lpszPictureName,"Poligon5", 0 );
    	}
    }
    


       In acest moment dublul simbol functioneaza, insa la actionarea, dar la apasarea Toggle Button-ului, simbolul valvei ramane nemodificat. Va trebui sa mai scriem o procedura declansata pe unul din evenimentele paginii grafice care sa actualizeze in permanenta starea valvei cand tag-ul corespunzator valvei este actionat din alta parte



       Am folosit proprietatea Picture Obiect al paginii grafice -- Geometry -- Picture Width -- C Action, urmatorul script

    #include "apdefap.h"
     long _main(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    	int x;
    	x=GetTagWord("L1");
    	if   (x==1){
    		SetVisible(lpszPictureName,"Polygon4", 1 );
    		SetVisible(lpszPictureName,"Polygon5", 0 );
    	}
    	else{
    		SetVisible(lpszPictureName,"Polygon4", 0 );
    		SetVisible(lpszPictureName,"Polygon5", 1 );
    	}
    return 0;
    }
    


       Dupa care am setat Triger-ul la 250 ms

        Sa reluam aplicatia afis_01 dar de data aceasta sa nu mai modificam manual valoarea tag-ului Temp, sa modificam dinamic valoarea.
        Realizam o noua pagina grafica "c_if_03" pe care plasam toate elementele de pe afis_01 si in plus:
       Folosim din nou proprietatea Picture Obiect al paginii grafice -- Geometry -- Picture Width -- C Action, scriptul de jos si setam Triger-ul la 250 ms.

    #include "apdefap.h"
     long _main(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    int tmp;
    tmp=GetTagWord("Temp");
    tmp=tmp+10;
    if (tmp>100){
    tmp=1;
    }
    SetTagByte("Temp",tmp);
    
    return 600;
    }
    


    3. Istructiuni repetitive

    Instructiunea while

        Instructiunea while Se foloseste pentru a executa repetitiv o instructiune sau o secventa de instructiuni atata timp cat o expresie este adevarata.
  • Formatul instructiunii:

        Formatul instructiunii
        while (expresie) {
          instructiuni; }

        Instructiunea se executa repetat atīta timp cīt valoarea expresiei este adevarata. Testul are loc īnaintea fiecarei executii a instructiunii. Modul de functionare al instructiunii este urmatorul:
  •      Se testeaza expresia din paranteze. Daca ea este adevarata (sau expresia din paranteze are o valoare diferita de zero)
  •      Se executa corpul instructiunii while
  •      Se reia testarea si executia pana expresia devine falsa (sau valoarea expresiei din paranteze este zero)
  •      Se continua executia cu instructiunea de dupa corpul instructiunii while, deci instructiunea while se termina.


  • Aplicatii care utilizeaza instructiunea while

        Sa realizam un program care afiseaza primele 10 numere naturale.

        Folosind Smart Object-ul Applications Windows vom afisa primele 10 de numere naturale
        Vom crea o noua pagina grafica "c_while_01" ,in care afisam primele 10 de numere naturale
        Plasam urmatoarele elemente:
        Smart Objects -- Applications Windows
           - se seteaza Global Script -- GSC Diagnostics
        Windows Objects -- Button
           - se seteaza Properties -- Font -- Text=Start
           - se completeaza Events -- Mouse -- Mouse Action cu urmatoarea procedura:

    
    #include "apdefap.h"
    void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    	int i;
    	i=1;
    	while (i <= 10){
    		printf("\n\tI=: %d \n",i);
    		i=i+1;
    	}
    }
    
    


    Instructiunea for

        Instructiunea For se foloseste pentru a executa repetitiv o instructiune sau o secventa de instructiuni. De obicei implementeaza structura ciclica cu numar cunoscut de pasi.
  • Formatul instructiunii:

        Instructiunea for are urmatorul format:

        For (expresie1 ,expresie2, expresie3){
            instructiuni; } expresie2 specifica testul care controleaza ciclul. El se executa īnaintea fiecarei iteratii. Daca conditia din test este adevarata atunci se executa corpul ciclului, dupa care se executa expresie3, care consta de cele mai multe ori īn modificarea valorii variabilei de control al ciclului. Se revine apoi la reevaluarea conditiei.
         expresie1 constituie initializarea ciclului si se executa o singura data īnaintea ciclului.
         expresie2 specifica testul care controleaza ciclul. El se executa īnaintea fiecarei iteratii. Daca conditia din test este adevarata atunci se executa corpul ciclului.
         se executa expresie3, care consta de cele mai multe ori īn modificarea valorii variabilei de control al ciclului.
         se incrementeaza variabila din expresie1
         se revine apoi la reevaluarea conditiei.


  • Aplicatii care utilizeaza instructiunea for

       Vom realiza aplicatia "c_for_01" in care afisam random 10 dreptunghiuri de inaltimi diferite.
       Se plaseaza 10 dreptunghiuri cu numele Rectangle1, Rectangle2,...,Rectangle 10 din Standard Objects -- Rectangle
           -se seteaza -- Properties -- Color -- Background Color -- la culoarea dorita
           -se seteaza -- Properties -- Effects -- Global Color Scheme = No
       Se plaseaza un buton start din Windows Objects -- Button -- Text = Start
           -se completeaza -- Properties -- Events -- Mouse -- Action -- C Action -- cu urmatoarea procedura

    #include "apdefap.h"
    void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    	char  fig[20];
    	char* nr_fig;
    	int nr=1;
    	int k=1;
    	int x;
    	for (k=1;k<11;k++){
    		SetTagDWord("i",nr);
    		nr_fig=GetTagChar("i");
    		strcpy(fig,"Rectangle");
    		strcat(fig,nr_fig);
    		x=15*k;
    		SetHeight(lpszPictureName,fig, x);
    		SetTop(lpszPictureName,fig, 290-x);
    		nr=nr+1;
    	}
    }
    
    




        Folosind Smart Object-ul Applications Windows vom afisa primele 25 de numere naturale
        Vom crea o noua pagina grafica "c_for_02" ,in care primele 25 de numere naturale
        Plasam urmatoarele elemente:
        Smart Objects -- Applications Windows
           - se seteaza Global Script -- GSC Diagnostics
        Windows Objects -- Button
           - se seteaza Properties -- Font -- Text=Start
           - se completeaza Events -- Mouse -- Mouse Action cu urmatoarea procedura:

    #include "apdefap.h"
    void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    	int i;
    	for (i=1;i <= 25;i++){
    		printf("\n\tI=: %d \n",i);
    	}
    }
    




    Instructiunea do while

        Formatul instructiunii
        do
          instructiuni
        while(expresie)

        Instructiunea se executa repetat pana cand valoarea expresiei devine adevarata.
        Testul are loc īnaintea fiecarei executii a instructiunii.
        Instructiunea Do Until se foloseste atunci cand se cunoaste conditia finala pana la care se repeta secventa de instructiuni


  • Aplicatii care utilizeaza instructiunea do while

        Folosind Smart Object-ul Applications Windows vom afisa primele 25 de numere naturale
        Vom crea o noua pagina grafica "c_while_01" ,in care primele 25 de numere naturale
        Plasam urmatoarele elemente:
        Smart Objects -- Applications Windows
           - se seteaza Global Script -- GSC Diagnostics
        Windows Objects -- Button
           - se seteaza Properties -- Font -- Text=Start
           - se completeaza Events -- Mouse -- Mouse Action cu urmatoarea procedura:

    #include "apdefap.h"
    void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    	int i;
    	i=1;
    	do{
    		printf("\n\tI=: %d \n",i);
    		i++;
    	}
    	while(i <= 25);
    }
    


    4.Functii


        Functiile sunt des utilizate pentru realizarea aplicatiilor SCADA. Majoritatea butoanelor, prin intermediul evenimentelor lanseaza secvente de cod impachetate in cadrul unor functii. Exista o varietate mare de functii astfel avem functii cu sau fara parametri, functii care returneaza sau nu valori.

    Definitia unei functii


        O functie poate fi deci descrisa mai general astfel:

    tip_val_return nume_func (lista_declaratiilor_param_ formali)
    {
    	declaratii_variabile_locale
    	instructiuni
    	return valoare
    }
    

        Prima linie reprezinta antetul functiei, īn care se indica: tipul functiei, numele acesteia si lista declaratiilor parametrilor formali. La fel ca un operand sau o expresie, o functie are un tip, care este dat de tipul valorii returnate de functie īn functia apelanta. Daca functia nu īntoarce nici o valoare, īn locul tip_vali_return se specifica void. In acest caz avem de-a face cu o procedura
        Daca tip_val_return lipseste, se considera, implicit, ca acesta este int. Nume_functie este un identificator.
        Lista_declaratiilor_param_formali (īncadrata īntre paranteze rotunde) consta īntr-o lista (enumerare) care contine tipul si identificatorul fiecarui parametru de intrare, despartite prin virgula. Daca lista parametrilor formali este vida, īn antet, dupa numele functiei, apar doar parantezele ( ), sau (void).
        Corpul functiei este un bloc, care implementeaza algoritmul de calcul folosit de catre functie. Īn corpul functiei apar (īn orice ordine) declaratii pentru variabilele locale si instructiuni. Daca functia īntoarce o valoare, se foloseste instructiunea return valoare. La executie, la īntālnirea acestei instructiuni, se revine īn functia apelanta.

    Aplicatii care utilizeaza functii definite de utilizator

        
        In pagina grafica "func_00" plasam urmatoarele obiecte:
        Standard Objects -- Static Text
        2 elemente de tipul Controls -- Activx Controls -- Wincc Slider Control
           - se completeaza la ambele slidere Events -- Object Events -- Change cu urmatoarea procedura:

    #include "apdefap.h"
    void Change(char* lpszPictureName, char* lpszObjectName ,  long Position)
    {
    int sld1;
    int sld2;
    int pw;
    char* pwr;
    sld1=GetPosition(lpszPictureName,"Control1");
    sld2=GetPosition(lpszPictureName,"Control2");
    pw=c_power(sld1,sld2);
    SetTagDWord("val_d",pw);
    pwr=GetTagChar("val_d");
    SetText(lpszPictureName,"Static Text1",pwr);
    }
    


       Vom integra functia de jos in Global -- Script --Project Module

    double c_power(int u,int i)
    {
    	double p;
    	p=u*i;
    	return p;
    }
    




    5. Tablouri de elemente

        Variabilele utilizate pana acum puteau contine o singura valoare. De multe ori e nevoie sa folosim variabile care pot stoca mai multe valori. Cu alte cuvinte se simte nevoia utilizarii tablourilor. Un tablou permite folosirea unei singure variabile pentru a stoca mai multe valori. Valorile sunt stocate la adrese consecutive cu alte cuvinte, la indecsi consecutivi incepand cu 0 . Utilizarea tablourilor ar un mare avantaj, care consta in posibilitatea utilizarii instructiunilor repetitive pentru a relucra toate valorile stocate in tablouri. Din acest motiv, tablourile mai sunt numite si "masive de date"

  • Declararea unui tablou

        Un tablou este similar cu o variabila, deci el trebuie declarat inainte de a putea fi folosit.

    tip nume_tablou[nr_elemente]
    


         Toate valorile dintr-un tablou trebuie sa fie de acelasi tip.

    Aplicatii care utilizeaza tablouri

       Vom realiza aplicatia "c_matr_01" in care afisam random 10 dreptunghiuri de inaltimi diferite.
       Se plaseaza 10 dreptunghiuri cu numele Rectangle1, Rectangle2,...,Rectangle 10 din Standard Objects -- Rectangle
           -se seteaza -- Properties -- Color -- Background Color -- la culoarea dorita
           -se seteaza -- Properties -- Effects -- Global Color Scheme = No
       Se plaseaza un buton start din Windows Objects -- Button -- Text = Start
           -se completeaza -- Properties -- Events -- Mouse -- Action -- C Action -- cu urmatoarea procedura

    #include "apdefap.h"
    void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
    {
    	int x;
    	int i;
    	char* s_i[10]={"Rectangle1", "Rectangle2","Rectangle3","Rectangle4", "Rectangle5","Rectangle6","Rectangle7", "Rectangle8","Rectangle9","Rectangle10"};
    	int v_bar;
    	for(i=0;i<=9;i++){
    		x=300*rand()/65535;
    		SetTop(lpszPictureName,s_i[i], 290-x);
    		SetHeight(lpszPictureName,s_i[i], x);
    	}
    }