Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Seite 1 von 4 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 38

Thema: ADS-protokoll in Python 2.7 implementieren

  1. #1
    Registriert seit
    14.08.2004
    Beiträge
    824
    Danke
    45
    Erhielt 73 Danke für 66 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Ich will versuchen das ADS-Protokoll in Python 2.7 zu implementieren. Die Doku ist auch nicht schwer zu verstehen, nur hab ich früher immer per .NetADS-Dll auf die SPS zugegriffen und da war es möglich per Name auf Variablen zuzugreifen. Die Alternative wäre Idx und ein Offset. Wo ist dokumentiert, wie ich an die Variablen-Symbole komme?

    Ändert sich der Offset bei globalen Variablen?

    Der Hintergrund ist der, dass Python genau richtig für Datenbanken, Webanwendungen und GUI ist. Insbesondere hat es mir web2py angetan.
    Zitieren Zitieren ADS-protokoll in Python 2.7 implementieren  

  2. #2
    Registriert seit
    24.04.2008
    Ort
    Lübeck
    Beiträge
    324
    Danke
    8
    Erhielt 63 Danke für 62 Beiträge

    Standard

    Hallo drfunfrock,

    wie Handles erzeugt werden usw. findest du in der ADS Device Description: http://infosys.beckhoff.com/index.ph...AdsService.htm

    Gruß, Neals

  3. Folgender Benutzer sagt Danke zu Neals für den nützlichen Beitrag:

    drfunfrock (09.05.2012)

  4. #3
    Registriert seit
    27.04.2010
    Beiträge
    5
    Danke
    3
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Das Projekt finde ich sehr interessant. Ich kann Dir zwar nicht weiterhelfen, aber eine Frage habe ich. Bleiben deine Ergebnisse bzw. der Code nur bei Dir oder willst Du sie auch als (Open Source?) veröffentlichen?

  5. #4
    drfunfrock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    14.08.2004
    Beiträge
    824
    Danke
    45
    Erhielt 73 Danke für 66 Beiträge

    Standard

    Kann ich noch nicht sagen. Ich versuche die Basics wie das Lesen und Schreiben der Variablen Öffentlich zu machen. Es kommt darauf an, ob das was in Form von Ideen zurückkommt, wenn ich mehr öffentlich machen sollte

  6. #5
    Registriert seit
    29.03.2004
    Beiträge
    5.731
    Danke
    143
    Erhielt 1.685 Danke für 1.225 Beiträge

    Standard

    Zottel hatte doch auch mal eine ADS-Bibliothek angefangen. Leider sind die Quellen bei Sourceforge nicht mehr verfügbar. Ich würde einfach mal anfragen(User Lettoz) wie weit er damit war. Ist aber bestimmt auch wieder in C (für eine Bibliothek finde ich C persönlich schon besser, da man eine C-dll eigentlich in so gut wie allen Sprachen verwenden kann).

    Warum willst du eigentlich nicht Python 3 verwenden? Für neue Projekte bietet sich das doch an. Ich habe letztens noch ein kleines Projekt auf 3 umgestellt. Da ging zwar alles mit einem automatischen Skript, aber ob das auch bei komplexeren Sachen funktioniert...

  7. #6
    drfunfrock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    14.08.2004
    Beiträge
    824
    Danke
    45
    Erhielt 73 Danke für 66 Beiträge

    Standard

    Ja, ich hab die Quellen von Zottel noch . Ich fand sie vor ein paar Tagen auf meinem kleinem Server. Seitdem ich aber Python kenne, will ich mit C nur noch wenig zu tun haben, weil es viel besser für meine Sachen passt und vor allem, dass ist dann auch portabel. Der Code ist auch wesentlich kürzer. Python 3 ist klasse, aber ich hab einige Dinge, die funktionieren damit nicht, weil die noch nicht portiert wurden, wie z.B. web2py oder OpenCV.

    So lesen kann ich ohne Probleme. Ich übergebe einfach eine Liste mit Variablen und deren Typen, sowie den Gruppenindex und den Offset. Die Variablen müssen auf der SPS hintereinander liegen. Ich habe den Ansatz gewählt, weil er die SPS kaum belastet und damit besser für die kleinen SPS ist. Damit kann ich direkt per groupidx und offset lesen. Zurück kommt ein Dictionary mit den Variablennamen, den Werten und dem Statuscode. Zudem brauche ich bei einem Disconnect keine neuen Handles zu holen. Das ganze belastet weder SPS noch den lesenden PC, ganz im Gegensatz, zu der .Net-Geschichte, die ich mal hatte.

    Beim Schreiben hab ich Probleme, weil ich bekomm den Statuscode 1793 und der heisst, dass der Service nicht zur Verfügung steht. Ich weiss noch nicht ob es an den ADS-Daten liegt. ich versuche auf den Index 0xF030, Offset 0 zu schreiben. Da liegen die Variablen mit typ %I<> Ich werd wohl erstmal die Status-Abfrage für Twincat machen müssen.

    Der Router bei Twincat ist nichts anderes als ein Prozess, der für einen Client mit einer bestimmten IP einen Socket öffnet. Ich finde das etwas albern. Nun ja.

    Dann hab ich einen Fehler beim Design der Klassen gemacht. Ich hab eine Klasse, die das AMSPacket im Konstruktor zusammenbaut und dazu das Kommando mit seinen Parametern bekommt, welches ebenfalls eine Klasse ist. Das funkt, wenn es ums Lesen geht, aber beim Kommando Schreiben, brauche ich einen extra aufruf, um die Variablen-Daten einzufügen, der hässlich aussieht. Ich weiss noch nicht, wie das endgültig aussehen soll.

  8. #7
    drfunfrock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    14.08.2004
    Beiträge
    824
    Danke
    45
    Erhielt 73 Danke für 66 Beiträge

    Standard

    Ich beschreibe dann mal, was ich gemacht habe:

    Python kommt ohne Klammern aus und braucht statt dessen Einrückungen. Das erspart so manche Klammerzählerei. Python kennt auch keine Arrays und hat statt dessen Listen und Dictionaries. Ein Dict ist so etwas ähnliches wie ein Array, dass mit beliebigen Indizes indexiert werden kann. Z.B.

    Code:
    > print worterbuch['Tag'] 
    Day
    worterbuch[1] = 'one'
    Ein Dict-Element kann wieder ein Dict-Element oder eine Liste enthalten. Für Listen gilt das gleiche. Listen werden über einen nummerischen Index indiziert.

    Kontakt zur SPS:

    Code:
    import socket
    
    AMSIDd = '10.2.2.88.1.1'
    AMSIDs = '192.168.17.50.1.1'
    
    HOST=socket.gethostbyname('SPS-PC')
    PORT = 48898
    
    print 'Get socket'
    csocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    csocket.settimeout(5.0)
    print 'connect....'
    csocket.connect((HOST, PORT))
    print 'connected ....'
    
    # Sende daten
    csocket.send('Hallo Welt!')
    
    # Empfange Daten
    data = csocket.recv(1024)
    csocket.close()
    Wie man schnell sieht, werden einfach strings über TCP/IP gesendet. Das ist leicht. Da aber Python keine Bytes kennt und auch keine Strukturen muss man jetzt sich einen String zusammenbasteln, der einem AMSpacket entspricht. Das wird mit dem Modul struct gemacht, dass eine eine etwas bessere Version von Peek und Poke ist. Hier werden 3 Integer mit Intel-Byteorder in den string cmddata kopiert. Das geht genauso mit 32Bit float, 64bit float und anderen datentypen.

    Code:
            struct.pack_into('<L', cmddata, 0, group)
            struct.pack_into('<L', cmddata, 4, offset)
            struct.pack_into('<L', cmddata, 8, self.length)
    Der nächste Gedanke ist, wie baue ich ein AMS-Packet zusammen? Da gibt es einen Teil, der ist immer gleich, während ein anderer vom Kommando abhängig ist. Also gibt es eine Klasse Ams-Packet, welche den AMS-TCP-header und den AMS-Header zusammenbaut und den Rest von der Klasse und seinen Erben ADSCommand bekommt.

    Code:
    class amsPacket
     |  Class to format a packet for the AMS protocol
     |  dID         : AMS addr for the dest
     |  dPort       : AMS port for the dest
     |  sID         : AMS addr for the source 
     |  sPort       : AMS port for the source
     |  cmdManager  : reference to class ADScmdHandler for
     |                for processing received data and format
     |                cmd specific data
     |  
     |  Methods defined here:
     |  
     |  __init__(self, dID, dPort, sID, sPort, cmd, idcode=0)
     |  
     |  changeCMDData(self, data)
     |  
     |  getPacket(self)
     |  
     |  processResponse(self, data)
    Die Klasse für den Command-Manager sieht ebenso einfach aus. Ich hab hier mal Beispielsweise die Klasse für das Schreib-Kommando aufgeführt. ADSCmdWrite.process wird von der Klasse amsPacket aufgerufen, wenn Daten kommen und liefert dann eine Liste mit den Resultaten zurück. ADSCmdWrite sorgt auch dafür, dass die Kommandoabhängigen Daten and amsPacket geliefert werden.

    Code:
    class ADSCmdWrite(ADSCmdHandler)
     |  Write data from to a PLC with group and offset
     |  
     |  Method resolution order:
     |      ADSCmdWrite
     |      ADSCmdHandler
     |      __builtin__.object
     |  
     |  Methods defined here:
     |  
     |  __init__(self, group, offset, varlist)
     |      varlist is a list of tuples, each with 2 values, the name
     |      of the variable and the format code for pack
     |  
     |  changeData(self, data)
     |      data  is a list of tuples, each with 2 values, the name
     |      of the variable and the value
     |  
     |  process(self, data)
    Anwendungsbeispiel:

    Code:
    # Lese 3 Variable ab Offset 0. Die 1. var ist vom Typ Int, die 2. und 3. vom Typ 32bit float
    cmd = ams.ADSCmdRead(group=0xF030, offset=0, varlist=[('counter', 'i'), ('c2', 'f'), ('c3', 'f')])
    packet = ams.amsPacket(AMSIDd, 801, AMSIDs, 801, cmd)
    
    #Sende das Packet
    csocket.send(packet.getPacket())
    
    # Hole die Resultate
    res = csocket.recv(1024)
    
    # Resultate verarbeiten und ausgeben
    print packet2.processResponse(res)   
    
    Resultat ist ein dictionary: {'c3': 10.0, 'c2': 41.65073776245117, 'counter': 6, 'ADSstatus': 0}
    Das Modul AMS hat 220 Zeilen. Ich baue das weiter aus, um eine Struktur zu erreich die in etwa so aussieht:

    [Processs: Data collector and writer] <--> [Process: Data Manager] <--> [HMI with GUI or Web/database]

    Das ist aus meiner Sicht ein schönes Beispiel, dass mit Pyhton effizient gearbeitet werden kann. Insbesondere das Lesen von Konfiguration (XML, Ini-file) ist einfach. Damit werden komplexere Systeme nicht zu Grossprojekten, nur weil man es Idiotensicher bauen muss.
    Geändert von drfunfrock (16.05.2012 um 11:58 Uhr)

  9. #8
    drfunfrock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    14.08.2004
    Beiträge
    824
    Danke
    45
    Erhielt 73 Danke für 66 Beiträge

    Standard

    Teil1
    Ich mach mal den Kern des Codes öffentlich. Es sind 2 Teile. Das erste ist ein Modul mit allen benötigten Klassen, welches per Import im Hauptprogramm benutzt wird. Die Variablenlisten bestehen aus Tuples, die jeweils den Variablennamen beinhalten und den Typ gemäss der Doku des Modules struct (www.python.org). Das AMS-Modul baut keine Netzwerkverbindungen auf, sondern formatiert nur die Daten in einen String, der dann per socket.send() gesendet wird. Viel Spass noch.

    Code:
    """
    AMS modul to form a ADS packet for a Beckhoff PLC.
    """
    import struct
    import array
    import re
    
    cmd_list = {'Read Device Info':1, 'Read':2, 'Write':3,  'Read State':4, \
                'Write Control':5, 'Add D evice Notification':6, \
                'Delete Device Notification':7,  'Device Notification':8, \
                'Read Write':9}
    
    ads_states  = ['Idle', 'Reset',  'Init', 'Start',  'Run',  'Stop',  'Save CFG', \
                    'Load CFG',  'Power failure',  'Power good', 'Error', 'Shutdown', 'Suspend', \
                    'Resume', 'Config', 'Reconfig']
      
      
    class amsError(Exception):
        """Base class for exceptions"""
        def __init__(self, value=''):
            self.value = value
        def __str__(self):
            return repr(self.value)
        
    class amsID(object):
        
        reexpr = re.compile('(\d+)\.(\d+)\.(\d+)\.(\d+)\.(\d+)\.(\d+)')
        
        def __init__(self,  id):
            """
            Construct a list of bytes values from a string id    
            """
            # Test format
            matches = amsID.reexpr.match(id)
            if not matches:
                raise amsError('Malformed amsID')
            self.amsID      = id
            self.amsIDlist  = [int(x) for x in matches.groups()]
            self.amsIDbin   = self._makeBinary()
            
        def _makeBinary(self):
            buff = array.array('c',6*'\0')
            for p, byte in enumerate(self.amsIDlist):
                struct.pack_into("!B", buff, p, byte)
            return buff
    
            
    class amsPacket:
        """
        Class to format a packet for the AMS protocol
        dID         : AMS addr for the dest
        dPort       : AMS port for the dest
        sID         : AMS addr for the source 
        sPort       : AMS port for the source
        cmdManager  : reference to class ADScmdHandler for
                      for processing received data and format
                      cmd specific data
                      
        The method getPacket is delivering the data for the socket.send function. 
        The method processResponse processes the data received by socket.recv() and
        deliver a dict() with the command data.
        """
        amsHeaderSize = 6+32
        def __init__(self, dID, dPort, sID,  sPort, cmd,  idcode = 0):
            self.dID = amsID(dID)
            self.sID = amsID(sID)
            if not (dPort>0 and sPort>0):
                raise amsError('Portnumber must be integer and greater than 0')
            self.sPort = sPort
            self.dPort = dPort        
            
            # Reserve buffer
            try:
                self.buffer = array.array('c', (len(cmd.cmddata)+6+32)*'\0')
                self._insertBytes(cmd.cmddata, 6+32)
            except (TypeError, AttributeError):
                self.buffer = array.array('c', (6+32)*'\0')         
            self.cmd = cmd
            self.idcode = idcode
            
            # build packet
            struct.pack_into('<H', self.buffer, 0, 0)               # 2 bytes with 0
            try:
                struct.pack_into('<L', self.buffer, 2, 32+len(cmd.cmddata)) # length of AMS header + data
                struct.pack_into('<L', self.buffer, 6+20, len(cmd.cmddata))    
            except (TypeError, AttributeError):
                struct.pack_into('<L', self.buffer, 2, 32)          # length of AMS header + data
                struct.pack_into('<L', self.buffer, 6+20, 0)    
            self._insertBytes(self.dID.amsIDbin, 6+0)               # insert amsid for destination
            struct.pack_into('<H', self.buffer, 6+6, self.dPort)    # insert port for destination
            self._insertBytes(self.sID.amsIDbin, 6+8)               # insert amsid for source
            struct.pack_into('<H', self.buffer, 6+14, self.dPort)   # insert port for source
            struct.pack_into('<H', self.buffer, 6+16, self.cmd.cmd)     # insert cmd
            struct.pack_into('<H', self.buffer, 6+18, 0x04)         # state = send cmd and request
            struct.pack_into('<L', self.buffer, 6+24, 0)            # Error = 0    
            struct.pack_into('<L', self.buffer, 6+28, self.idcode)  # Invoke ID
        
        def _insertBytes(self,  bytes,  offset):
            """
            Insert bytes into the buffer by overwriting old values.
            """
            for idx in range(0, len(bytes)):
                self.buffer[idx+offset] = bytes[idx]
                
        def _printPacket(self):
            for i, b in enumerate(self.buffer):
                if not i%8:
                    print '\n{0:02d}:'.format(i), 
                print '{0:02X}'.format(ord(b)), 
            print
            
        def processResponse(self, data):
            """
            Process the response of the PLC
            """
            return self.cmd.process(data)
            
        def changeCMDData(self, data):
            """
            For a wrote command, the data must modified after initializing
            """
            self.cmd.changeData(data)
            self._insertBytes(self.cmd.cmddata, 6+32)
    
        def getPacket(self):
            """
            Get packet data as string
            """
            return self.buffer.tostring()
            
            
    class ADSCmdHandler(object):
        def __init__(self):
            self.cmd = 0
            
        def process(self, data):
            self.respdata = array.array('c', data[amsPacket.amsHeaderSize:])
    
        def _printData(self,  data):
            for i, b in enumerate(data):
                if not i%8:
                    print '\n{0:02d}:'.format(i), 
                print '{0:02X}'.format(ord(b)), 
            print
    
    class ADSCmdReadDeviceInfo(ADSCmdHandler):
        """
        Get the response of Read Device Info and decompose the data
        """
        def __init__(self):
            ADSCmdHandler.__init__(self)
            self.cmd = cmd_list['Read Device Info']
                    
        def process(self, data):
            ADSCmdHandler.process(self, data)
            t = struct.unpack_from('<LBBH', self.respdata)
            self.result = t[0]
            self.major_version = t[1]
            self.minor_version = t[2]
            self.version_build = t[3]
            self.name = ''
            for c in self.respdata[8:]:
                if ord(c)>0:
                    self.name += c
            ret = {'ADSstatus':self.result, 'major_version': self.major_version,  'minor_version': self.minor_version,  \
                   'version_build':self.version_build, 'name':self.name}
            return ret
            
    class ADSCmdRead(ADSCmdHandler):
        """
        Store data from a PLC with group and offset
        """
        def __init__(self, group,  offset, varlist):
            """
            varlist is a list of tuples, each with 2 values, the name
            of the variable and the format code from unpack.
            """
            ADSCmdHandler.__init__(self)
            self.cmd = cmd_list['Read']
            self.varlist = varlist
            self.types ='<'
            for t, type in self.varlist:
                self.types += type
            self.length = struct.calcsize(self.types)+12
            self.cmddata = array.array('c', self.length*'\0')
            struct.pack_into('<L', self.cmddata, 0, group)
            struct.pack_into('<L', self.cmddata, 4, offset)
            struct.pack_into('<L', self.cmddata, 8, self.length)
            
            
        def process(self,  data):
            ADSCmdHandler.process(self, data)
            t = struct.unpack_from('<LL', self.respdata)
            self.ADSstatus = t[0]
            self.length = t[1]
            ret = {'ADSstatus':self.ADSstatus}
            if self.ADSstatus==0:
                list = struct.unpack_from(self.types, self.respdata, 8)
                for (var, t), val  in zip(self.varlist,  list):
                    ret[var] = val
            return ret
            
    class ADSCmdWrite(ADSCmdHandler):
        """
        Write data from to a PLC with group and offset
        """
        def __init__(self, group,  offset, varlist):
            ADSCmdHandler.__init__(self)
            self.cmd = cmd_list['Write']
            self.types ='<'
            self.variables = {}
            for var, type in varlist:
                self.variables[var] = (type, struct.calcsize(self.types))
                self.types += type
            self.length = struct.calcsize(self.types)
            self.cmddata = array.array('c', (self.length+12)*'\0')
            struct.pack_into('<L', self.cmddata, 0, group)
            struct.pack_into('<L', self.cmddata, 4, offset)
            struct.pack_into('<L', self.cmddata, 8, self.length)
    
            
        def changeData(self,  data):
            """
            data  is a list of tuples, each with 2 values, the name
            of the variable and the value
            """        
            for var,  val in data:
                struct.pack_into('<'+self.variables[var][0], self.cmddata, self.variables[var][1]+12, val)
            
        def process(self,  data):
            ADSCmdHandler.process(self, data)
            t = struct.unpack_from('<L', self.respdata)
            self.ADSstatus = t[0]
            ret = {'ADSstatus':self.ADSstatus}
            return ret
    
    class ADSCmdReadState(ADSCmdHandler):
        """
        Get the response of ReadState and decompose the data
        """
        def __init__(self):
            ADSCmdHandler.__init__(self)
            self.cmd = cmd_list['Read State']
                    
        def process(self, data):
            ADSCmdHandler.process(self, data)
            t = struct.unpack_from('<LHH', self.respdata)
            ret = {'ADSstatus':t[0], 'ADSstate': t[1],  'DeviceState': t[2]}
            return ret
    
    if __name__ == '__main__':
        # Test a well formed id
        aid = amsID('1.2.3.4.1.2')
        
        try:
            aid = amsID('1.1.1.1.1x2')
        except amsError as e:
            print 'Malformed amsID detected {0}'.format(e)
            
        packet = amsPacket('1.1.1.1.1.1', 801, '10.11.12.13.1.2',  801, cmd_list['Read Device Info'], '',1)
        print packet.buffer.tolist()

  10. Folgende 2 Benutzer sagen Danke zu drfunfrock für den nützlichen Beitrag:

    e6o5 (16.08.2012),ohm200x (22.05.2012)

  11. #9
    drfunfrock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    14.08.2004
    Beiträge
    824
    Danke
    45
    Erhielt 73 Danke für 66 Beiträge

    Standard

    Hauptprogramm:

    Code:
    import socket
    import ams
    
    AMSIDd = '1.1.1.1.1.1'
    AMSIDs = '2.2.2.2.1.1'
    
    HOST=socket.gethostbyname('XXXPC')
    PORT = 48898
    
    
    print 'Get socket'
    csocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    csocket.settimeout(5.0)
    try:
        print 'connect....'
        csocket.connect((HOST, PORT))
    except:
        print 'timeout'
        csocket.close()
        exit()
    print 'connected ....'
    
    cmd1 = ams.ADSCmdReadDeviceInfo()
    packet1 = ams.amsPacket(AMSIDd, 801, AMSIDs, 801, cmd1,  1)
    print 'Send packet 1 ', csocket.send(packet1.getPacket())
    res = csocket.recv(1024)
    print packet1.processResponse(res) 
    
    cmd2 = ams.ADSCmdRead(group=0x4020, offset=0, varlist=[('counter', 'i'), ('c2', 'f'), ('c3', 'f')])
    packet2 = ams.amsPacket(AMSIDd, 801, AMSIDs, 801, cmd2,  2)
    print 'Send packet 2 ', csocket.send(packet2.getPacket())
    res = csocket.recv(1024)
    print packet2.processResponse(res)     
    
    cmd3 = ams.ADSCmdWrite(group=0xF020, offset=4, varlist=[('x1', 'f'),  ('x2', 'f')])
    packet3 = ams.amsPacket(AMSIDd, 801, AMSIDs, 801, cmd3,  3)
    packet3.changeCMDData([('x1', 3.2), ('x2', 34.2)])
    print 'Send packet 3 ', csocket.send(packet3.getPacket())
    res = csocket.recv(1024)
    print packet3.processResponse(res)     
    
    cmd4 = ams.ADSCmdReadState()
    packet4 = ams.amsPacket(AMSIDd, 801, AMSIDs, 801, cmd4,  4)
    print 'Send packet 4 ', csocket.send(packet4.getPacket())
    res = csocket.recv(1024)
    print packet4.processResponse(res) 
    
    print 'close'
    csocket.close()
    
    print 'EXIT'

  12. Folgende 2 Benutzer sagen Danke zu drfunfrock für den nützlichen Beitrag:

    e6o5 (16.08.2012),ohm200x (22.05.2012)

  13. #10
    drfunfrock ist offline Erfahrener Benutzer
    Themenstarter
    Registriert seit
    14.08.2004
    Beiträge
    824
    Danke
    45
    Erhielt 73 Danke für 66 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Ach ja, ich würde mir durchaus eine Diskussion erwünschen, was gefällt und was nicht

Ähnliche Themen

  1. Matlab Code auf S7 implementieren
    Von T-Rex22 im Forum Simatic
    Antworten: 18
    Letzter Beitrag: 22.11.2011, 09:07
  2. Offenes ADS Protokoll
    Von s.murauer im Forum CODESYS und IEC61131
    Antworten: 17
    Letzter Beitrag: 19.09.2011, 07:50
  3. ADS Protokoll in Visual Studio 08
    Von td97 im Forum CODESYS und IEC61131
    Antworten: 5
    Letzter Beitrag: 17.03.2009, 21:07
  4. SM331 implementieren HILFE
    Von BOBZ im Forum Simatic
    Antworten: 6
    Letzter Beitrag: 18.01.2007, 13:52
  5. Beckhoff ADS-Protokoll
    Von drfunfrock im Forum Feldbusse
    Antworten: 5
    Letzter Beitrag: 01.07.2005, 17:01

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •