Elektroda.pl
Elektroda.pl
X
SterControlSterControl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Step7 s7-300 problem ze wskaznikami i adresowaniem posrednim

15 Cze 2007 14:18 17554 35
  • Poziom 13  
    Witam
    Chcialbym zrobic aby do db15 poczawszy od bajtu 0 co 2 do 8 byly zapisywane odczyty pomiaru czujnikiem analogowym.
    Najpierw przy inicjacji robie LAR1 P#0.0
    Ponizej jest wycinek czesci programu wykonywany cyklicznie 5 razy, zeby zapisac 5 pomiarow do db
    Code:

          A     #odczytano
          OPN   "AnalogDane"
          L     "OdczytAnalog"
          T     DBW [AR1,P#0.0]
          +AR1  P#2.0 //tutaj powinno byc przesuniecie adresu o 2 bajty?
          S     #zapisanodoDB
          R     #odczytano

    Problem jest taki ze wszystkie 5 pomiarow jest zapisywanych do db15.dbw0 nadpisujac poprzedni(wskaznik nie jest przesuwany o 2?) zamiast db15.dbw0, db15.dbw2, db15.dbw4, db15.dbw6, db15.dbw8

    Chcialem to zrobic tez w taki sposob
    Prtzed petla:
    L P#0.0
    T "AdresDBDlaAnalog"
    a w petli
    Code:


          A     #odczytano
          OPN   "AnalogDane"
          L     "OdczytAnalog"
          T     DBW ["AdresDBDlaAnalog"]
          L     "AdresDBDlaAnalog"
          L     2
          +D
          T     "AdresDBDlaAnalog"       //gdy jest ta linijka, cpu przechodzi w stan stop
          S     #zapisanodoDB
          R     #odczytano

    Jednak cpu wywala sie przy zaznaczonej linijce, gdy jej brak to cpu sie nie wywala.
    "AdresDBDlaAnalog" to zmienna typu MD 110

    Bede wdzieczny za wszelkie uwagi
    Darmowe szkolenie: Ethernet w przemyśle dziś i jutro. Zarejestruj się za darmo.
  • SterControlSterControl
  • Poziom 11  
    Co do pierwszego kodu - sprzwdź czy przypadkiem nie inicjalizujesz za każdym razem wskaźnika P#0.0. Jeżeli za każdym razem wykonyqwana jest instrukcja LAR1 P#0.0, sterownik powróci do adresu inicjalizacji

    w drugim kodzie sterownik przechodzi w stan stop prawdopodobnie dlatego że w komórce pamięci zawarty jest adres który nie istnieje w podanym DB - wyskakuje poza blok danych.

    osobiście proponowałbym zrobić to na zasadzie rejestru przesuwnego - przesuwać dane tak, aby najstarsze były pod najwyższym adresem w DB, należy to robić od końca

    Powodzenia
  • Poziom 13  
    LAR1 P#0.0 jest inicjowane poza glowna petla, swiadczy o tym nawet to ze w tym samym networku co LAR1 P#0.0 mam zerowanie licznika petli, ktory zlicza tak jak ma zliczac, gdyby LAR1 P#0.0 bylo wykonywane, to mialbym takze reset licznika petli a tak nie jest.
    Cos tu nie tak jest w tym kodzie, chyba?
    Moze chodzi o to ze OPN "AnalogDane" jest za LAR1 P#0.0 a powinno byc przed?
    Chociaz probowalem i zrobic tak i nie dzialalo.

    Co do Twojej propozycji to nie bardzo rozumiem o co chodzi, mozesz jakos bardziej to naswietlic, chociaz wolalbym zrobic to wykorzystujac wskazniki.
  • Poziom 11  
    chyba sie troche zapedzilem:) W drugim kodzie jest blad adresacji. jezeli w MD110 masz wskaznik
    P#0.0
    nastepnie wykonasz instrukcje
    L 2
    otrzymasz wskaznik
    P#0.2
    jezeli chcesz przesunac wskaznik o wartosc #2.0 nalezy dodac instrukcje
    SLD 3
    przed transferem

    Dodano po 14 [minuty]:

    Co do mojej propozycji z rejestrem przesuwnym
    robie to w tem sposob, ze zawsze do adresu pierwszego przypisuje wartosc rzeczywista, natomiast w petli umieszczam przesuniecie wartosci poprzednich (od najstarszej):
    L DBD[AR1,P#0.0]
    T DBD[AR1,P#2.0]
    potem zmniejszasz wartosc indeksu o 2.0 az do uzyskania indeksu zerowego w ktorym zawarta jest wartosc rzeczywista, wtedy opuszczasz petle
  • SterControlSterControl
  • Poziom 13  
    Ale z SLD 3 nie bedzie dzialalo tak jak chce, gdyz za pierwszym razem owszem bedzie wskazywalo na drugi element, ale juz za drugim przejsciem petli bedzie wskazywalo na 16 element.
    Tu chodzi o samo dodanie do wskaznika wartosci przesuniecia o 2 slowa(word), tak aby za kazdym przejsciem petli wskaznik przesuwal sie stale o 2 slowa.
  • Poziom 15  
    Witam

    Zamiast
    L 2
    +D

    Powinno być

    L P#2.0
    +D
    dodajemy wskaźnik

    lub

    L 2
    SLD 3
    L "AdressDBDlaAnalog"
    +D

    Pozdrawiam
  • Poziom 13  
    witam,
    nie rozumiem do końca tych wskaźników ale....
    chcę zwiększyć wskaźnik "Area" o 2 bajty,
    robię tak:

    L P##Area //Area - wskaznik typu ANY
    L P#2.0
    +D

    i gdzie to załadować ?? chciałbym ponownie do wskaźnika "Area"....
  • Specjalista Automatyk
    tu roi aż się od błędów i od błędnego rozumowania.
    1. rozkaz "L" zostaje zawsze wykonywany,niezależnie od VKE (wyniku logicznego powyżej) tzn. w każdym cyklu (co kilka-dziesiąt ms) będzie odczytywana wartość na wejściu.
    2. pomieszane są tu dwie metody adresowania pośredniego (SLD3 z poinerem)
    3. co ma być warunkiem odczytu (impuls czasu )?
    4.jak wygląda pętla zliczająca pomiary ?
    5. co ma oznaczać:
    A #odczytano
    ........
    S #zapisanodoDB
    R #odczytano
  • Poziom 13  
    nie wiem co chciał uzyskać autor tematu ale patrząc na datę pierwszego postu to już to zrobił albo zaniechał,
    dołączyłem się do rozmowy ponieważ ostatni post traktował o inkrementacji wskaźnika i z tym mam problem,

    używam funkcji która zwraca mi wskaźnik typu ANY, chcę teraz żeby wskazywał o np. 3 bajty do przodu, zamierzam go inkrementować cyklicznie,

    b. proszę o pomoc
  • Specjalista Automatyk
    przede wszystkim pytanie: sam napisałeś tą funkcję lub jest to funkcja standardowa -siemensa. ANY-Poiner to 10 bytów.
    To powinno chodzić:

    LAR1 P##Quelle //Lade die Anfangsadresse des ANY–Pointers in AR1.

    L LD [AR1,P#6.0]
    L P#3.0
    +AR1
    T LD [AR1,P#6.0]



    Ten podprogram musisz umieścić po funkcji ,której wynikiem jest ANY (Quelle). ANY będzie wtedy przepisywany w pamięci z uwzględnieniem nowego adresu podwyższonego o trzy bajty.
  • Poziom 13  
    używam funkcji z przykładu Siemens'a,
    ta funkcja to:
    Code:
          L     P##Area_pointer             //Load start address
    
          LAR1                              //Loadin address register AR1
          L     W#16#10                     //Load syntax-ID and transfere
          T     B [AR1,P#0.0]               //to the actual start address 0
          L     #Type_of_data               //Load type of data and transfere
          T     B [AR1,P#1.0]               //to actual start address 1
          L     #Number_of_data             //Load Number_of_data and transfere
          T     W [AR1,P#2.0]               //to actual start address 2
          L     #DB_No                      //Load DB_No and transfere
          T     W [AR1,P#4.0]               //to actual start address 4
          L     P##Area_start               //Load area start address
          LAR2                              //Load in address register AR2
          L     #Offset                     //Load the offset
          SLD   3
          +D                                //Addition of area start address and offset
          L     DW#16#FFFFFFF8              //Masking the rest of data
          AD   
          LAR2                              //Load in address register AR
          T     D [AR1,P#6.0]               //Output of new calculated start address
          BEU   

    @andy1955, to co podałeś niestety nie działa :cry:
  • Specjalista Automatyk
    poniżej mój program, za pomocą którego kopiuję ilość zdefiniowanych bajtów ze zdefiniowanego DB oraz ze zdefiniowanego adresu początkowego do zdefiniowanego celu.Program pracuje w 100%. Rozpakować Stepem7.
    Programem tym da się praktycznie wszystko z DB skopiować (String,Word,Time) ,najważniesze - podanie odpowiedniej ilości bajtów do skopiowania.
    (Mnemonika niemiecka):
    Wejścia funkcji wymagają zmiennych w postaci "Integer", a więc łatwo można dodać wartość offsetu.
  • Poziom 12  
    Proponuje użyć funkcji BLOCK MOV :)
    Możesz sobie kopiować do woli wszystko wszędzie jeżeli jest ciągły obszar :)
    Natomiast jeżeli chcesz kopiować fragmenty DB np. co drugi rejestr to zrób to w pętli. Inicjujesz na P#0.0 przed pętlą apotem w pętli inkrementujesz go o P#2.0. Proste :)
  • Specjalista Automatyk
    Oskarr, ja także wykorzystałem w moim programie funkcję BLOKMOV z biblioteki Step7. Samą funkcją BLOKMOV możesz skopiować dane adresując bezpośrednio źródło i cel.
    Chcąc kopiować dane z jednego DB (numer DB zależny np. od numeru narzędzia) do drugiego DB, którego numer zależny jest od np. typu materiału
    musisz stworzyć ANY POINTER adresując pośrednio. I to właśnie robi mój program (zamiast stałych wartości podstawić tylko zmienne typu Integer) .
  • Poziom 12  
    Gadzam sie że do BLOCK MOV nalezy użyć formatu ANY nie da sie inaczej.
    Tylko nie bardzo wiem co u Ciebie oznaczo to urządzenie :/
  • Specjalista Automatyk
    Cytat:
    Tylko nie bardzo wiem co u Ciebie oznaczo to urządzenie :/

    Nie bardzo wiem o co chodzi ale nie szkodzi.
    Napisz krótki program, który będzie kopiował 70 bajtów z DB [xx] do DB[yy] przy czym xx = wartość, która zmienia się od 0 do 50 ; wartość yy = wartość od 51 do 100 . Adres początkowy i docelowy DBW zz może się zmieniać w czasie procesu np. od 0 do 256. Również zmienne xx i yy mogą przybierać różne wartości podczas procesu.
    Jeśli tą funkcję zaprogramujesz to będziesz wiedział o co mi chodzi .:D
  • Poziom 10  
    Witam,
    Chciałbym wrócić jeszcze raz do tematu zapisywania wyników do bloków danych z wykorzystaniem wskaźnika.
    W moim programie chciałbym zapisywać aktualną prędkość obrotową silnika do DB tylko jakoś nie udaje mi się tego zrobić.
    Przy wywołaniu funkcji zapisującej do DB
    Code:

     OPN   DB    10
          L     MW    12
          T     DBD [DBD 2]
          L     DBD    2
          L     P#2.0
          +D   
          T     DBD    2

    zostaje wykonany zapis do bloku danych tylko, tylko że jest to ostani wynik pomiaru.
    Zostaje zapisany zgodnie z wartością wskaźnika, czyli co wywołanie funkcji zapisującej co drugi bajt do bloku danych. W efekcie w DB mam same zera tylko na ostatnie pozycji jest ostatnia zapisana wartość prędkości.
    Funkcja zapisująca jest wywoływana cyklicznie co 200ms i przy jedynce logicznej na odpowiednim wyjściu cyfrowym. W DBD2 mam zapisaną początkową wartość wskaźnika (P#10.0), czyli miejsce gdzie powinien zostać zapisany pierwszy wynik.
    Może ktoś już miał podobny problem i mógłyby podzielić się swoją wiedzą.
    Może błąd tkwi w sposobie wywoływania funkcji zapisu ?
    Czy na kasowanie poprzednich danych w tym bloku może miec wpływ to, że w w funkcji wywołującej zapis do tego bloku danych jest wywoływana drugi blok danych ?
  • Poziom 11  
    Witam,
    popełniasz błąd zapisując WORD do DOUBLE, a następnie przesuwając o 2 Bajty = 1 WORD. Zmodyfikuj kod następująco:

    OPN DB 10
    L MW 12
    T DBW [DBD 2] // bylo: T DBD[DBD 2]
    L DBD 2
    L P#2.0
    +D
    T DBD 2

    Powinno być ok.
  • Specjalista Automatyk
    Cytat:
    Powinno być ok.

    sprawdzałeś ? Pomyśl jeszcze raz.
  • Poziom 11  
    Cytat:
    sprawdzałeś ? Pomyśl jeszcze raz


    Sprawdziłem przed chwilą i działa. Nie wiem jak funkcjonuje reszta programu, ale adresowanie pośrednie jest rozwiązane poprawnie.
    Nawiasem mówiąc, wydaje mi się, że kolega mariusz.sek nie zauważyłby błedu w kodzie, gdyby kolejność bajtów nie była w Simaticu zamieniana. Tak wynika z opisanego zachowania sterownika.
  • Specjalista Automatyk
    sprawdziłem symulatorem i wyskakuje mi błąd SF. Dziwne,że u ciebie wszystko hula.
    Adres jest zapamiętywany w DB10.DBD2 tzn. DBD2 = DBW2+DBW4.
    Po przetransferowaniu pointera #2.0 do DBD2
    wartość z MW12
    L MW 12
    T DBW [DBD 2] = T DB10.DBW2 zostaje wpisana do obszaru adresowego !! i tutaj wyskakuje błąd.
  • Poziom 11  
    >Po przetransferowaniu pointera #2.0 do DBD2

    Początkowa wartość DBD2 była P#10.0 , dalej transferujemy inkrementację (o P#2.0) wartości początkowej. Zakładam, że odpowiednio zainicjowałeś wcześniej DBD2, więc zastanawiam się czy może to być problem z symuatorem. Ja symulatora nie używam i nie posiadam. Sprawdzałem na sterowniku.
  • Poziom 10  
    Cytat:
    Początkowa wartość DBD2 była P#10.0

    I cały czas jest. Jutro sprawdzę na sterowniku i zobaczymy czy chodzi po prostu o błędne przypisanie DWord'a do Worda.
  • Poziom 10  
    Witam,
    dyskutujecie na temat jaki by mnie troche interesował. Otóż potrzebuje uzupełnić DB zmiennymi przykładowo wartością timera w kolejnych chwilach.
    FB wygląda następująco:

    L 100
    T MB 1
    L P#20.0
    petl: T MD 100
    OPN DB 2
    L T 1
    T DBB [MD 100]
    L MD 100
    L P#3.0
    -I
    JP petl

    funkcja niby działa, z jednym błędem uzupełnia cały określony w FB zakres DB tymi samymi danymi.
    Step7 s7-300 problem ze wskaznikami i adresowaniem posrednim

    Tu jest ten problem jak wymusić jakieś przerwanie, nie ważne od czego: timer, jakiś bit, żeby zapis do DB w różnych wierszach miał różne wartości.
    Poza tym ta pętla której użyłem jakoś nie działa ale tylko ona nie powoduje mi zatrzymania symulatora.
  • Specjalista Automatyk
    dlaczego P#3.0 ?
    Cytat:
    L MD 100
    L P#3.0
    -I

    spróbuj:
    L MD 100
    L P#3.0
    -D
    zmodyfikowałem twój program dla sprawdzenia i działa:
    Cytat:
    L 100
    T MB 1
    L P#20.0
    petl: T MD 100
    AUF DB 2
    L MB 1
    T DBB [MD 100]

    L MB 1
    L 1
    -I
    T MB 1
    L MD 100
    L P#1.0
    -D
    SPP petl

    użyłem zamiast T1 MB1 i za każdym razem odjąłem od MB1 wartość 1 .
    Problemem jest czas przebiegu całej pętli.
    Będziesz musiał zdefiniować warunek przy którym zostanie odczytania T1
  • Poziom 12  
    wystarczy cyklicznie wywoływać tą funkcje nap w OB35 i problem z głowy. Nie trzeba wtedy patrzeć na czas pętli.
  • Specjalista Automatyk
    Cytat:
    wystarczy cyklicznie wywoływać tą funkcje nap w OB35 i problem z głowy. Nie trzeba wtedy patrzeć na czas pętli.

    moim zdaniem to nie pomoże ponieważ czas trwania pętli - czas zapisu 20 wartości będzie może trwać 1ms i jest to obojętne gdzie się tą funkcję wywoła(pętla musi przebiec do końca). Co innego przerywać pętlę impulsem z OB35 ale można od razu zamiast pętli zastosowań skoki warunkowe i będzie po problemie.
  • Poziom 12  
    Z tego co ja zrozumiałem należy wpisywać do rejestrów DB wartość jednego rejestru. Jeżeli zapisywać będzie się ten rejestr co czas T1 a pętla programowa będzie trwać T2 (pamiętając że zapisywany rejestr jest odświeżany na końcu pętli programowej a więc co czas T2). W takiej sytuacji zapis zmiennej do rejestrów DB powinien odbywać się z częstotliwością T1=T2, lub T1>=T2
  • Specjalista Automatyk
    przebieg całej pętli (20x) zostanie załatwiony w jednym cyklu, czyli 20 wartości zostanie w przeciągu np. 500µs zapisane do DB. A jaka jest rozdzielczość timera ? Czy można ustawić czas w microsekundach ??
  • Poziom 12  
    Jeżeli chcemy zapisywać cyklicznie wartość pewnego rejestru (zapisywać jego wartość co określony czas) celem tego ma być zarejestrowanie zmian tego rejestru.
    To co koledzy opisują nie ma jakiegokolwiek sensu!!! Jeżeli w jednym cyklu programowym zapisuje się 20 próbek to każda próbka będzie miała tą samą wartość, dlatego że zapisywany rejestr jest uaktualniany co cykl programowy, a więc zapis 20 próbek (podejrzewam że z użyciem metody LOOP) spowoduje zapełnienie DB tymi samymi wartościami.
    Jeżeli chce się monitorować zmiany jakiegoś rejestru należy zapisywać go minimum co cykl programowy, a więc bez komendy LOOP. Mam nadzieje że dobrze was zrozumiałem.
    Chętnie pomogę w rozwiązaniu problemu jeżeli przedstawicie go w całości :))

    Dodano po 3 [minuty]:

    Zapisywanie wartości w pętli LOOP ma sens jeżeli odwołujemy się przez peryferia PLC. Wtedy w pętli programowej korzystamy z komendy LOOP ma to sens tylko wtedy jeżeli zapisujemy wartość np. PIW