# Analog Demultiplexer ILC 150/Oscat



## Portisch (11 November 2011)

Hallo zusammen!

Ich habe eine Frage zu einer Umsetzung eines Selberbau Multiplexers an der SPS!

Und zwar ist meine Idee:
SPS:
1 analog Input
1 digital Output

Multiplexer:
1 digital Input
1 analog Output

Auf dem Multiplexer ist nun ein AVR mit einem Binär Counter. Sind die Impulse inerhalb 1 Sekunde zählt er rauf.
Kommt 2 Sekunden kein Puls setzt sich der Counter wieder auf 0 zurück.

Somit bräuchte ich einen Funktionsblock, der einen analog Input hat und diesen mit einem eigenen Counter auf einen analogen Ausgang für die SPS liegt:




D.h. beim ersten Puls gibt der AVR A0 auf AI, beim nächsten Puls (inerhalb 1s) den A1 auf AI,.....
Wenn 2 Sekunden lang kein Puls kommt springt der Zähler zurück.

Der FB sollte somit die Pulse (8 STK) im Sekundentakt ausgeben und dann 2 Sekunden Pause machen.
gleichzeitig soll der Analoge AI Wert an dem zugehörigen Ax ausgegeben werden. Die anderen Ax Werte sollten auf dem letzten Wert gehalten werden.

Kann mir mit diesem Funktionsblock einer Helfen!?

Die AVR Umsetzung ist das kleinere Problem und würde ich dann auch hier zur Verfügung stellen!
Beim AVR kann man dann definieren ob PTC, Strom oder Spannungsmonitor verwendet werden soll.

Danke!


----------



## Zefix (11 November 2011)

Warum nichts fertiges und mit 4 bit steuerst direkt deinen MPX AI:

http://www.ese.at/download/pt1000mux8.pdf
oder
http://www.rinck-electronic.de/rinck2001/pdf/B390_D_MUX-U16.PDF
http://www.rinck-electronic.de/rinck2001/pdf/AN_B391_2_D_Anschluss_MUX_PT1000.PDF


----------



## SCM (13 November 2011)

Zefix schrieb:


> Warum nichts fertiges und mit 4 bit steuerst direkt deinen MPX AI:
> 
> http://www.ese.at/download/pt1000mux8.pdf
> oder
> ...



Das ist sicher die bessere Wahl!
Also ich kann nur vom Rinck Multiplexer berichten und der funktioniert perfekt!
Hab mir dazu einen Baustein geschrieben der die Adressierung,Temperaturübernahme und Min/Max Auswertung macht!

Mfg


----------



## benjo (6 Januar 2012)

Hallo,
genau so ein Programmbeispiel suche ich.
Habe Rinck-Multiplexer im Einsatz, bin aber in der SPS -PRogrammierung noch nicht zu 100 % fit und suche entsprechendes Programmbeispiel, um 16 PT1000 (Raumtemperaturen) auf einen Analogeingang zu mulitplexen.

Gibt es die Möglichkeit, den Baustein als Quellcode zu bekommen ?


----------



## SCM (6 Januar 2012)

benjo schrieb:


> Hallo,
> genau so ein Programmbeispiel suche ich.
> Habe Rinck-Multiplexer im Einsatz, bin aber in der SPS -PRogrammierung noch nicht zu 100 % fit und suche entsprechendes Programmbeispiel, um 16 PT1000 (Raumtemperaturen) auf einen Analogeingang zu mulitplexen.
> 
> Gibt es die Möglichkeit, den Baustein als Quellcode zu bekommen ?



Hallo!

Also wie gesagt hab da einen Baustein geschreiben!Der kann aber nur einen Multiplexer Abfragen also Disable funktion kann der "noch" nicht!

Kurze Anleitung:
Du gibst an wie viele Känäle eingelesenw erden sollen (0-15)
Es wedren nur die eingestellen eingelesen um unnötige Zeit zu ersparen!
Du kannst einen Offset angeben wenn du die PT1000 direkt auf ein RTD Modul legst benötigst du den!Wenn du 0-10V gehst gibts ja von Rinck einen Signalumsetzer der hat den Offset Onboard zum einstellen!
Dann die Hardware Adresse des Analogeinganges!

Er gibt einen Error aus wenn die Kanäle die Abgefragt werden sollen auser bereich sind!Dann wedren alle Werte Abgenullt!Aber nur Aktual werte die Min Max nicht!

Sodale jetzt schau dir den Baustein mal an!Einfach die Quelle übersetzen!


```
TYPE UDT 10005
AUTHOR : SCM
NAME : FUNC
VERSION : 0.1


  STRUCT     
   ACT : ARRAY  [0 .. 15 ] OF //Aktuelle Temperatur
   INT ;    
   MIN : ARRAY  [0 .. 15 ] OF //Minimale Temperatur
   INT ;    
   MAX : ARRAY  [0 .. 15 ] OF //Maximale Temperatur
   INT ;    
  END_STRUCT ;    
END_TYPE

FUNCTION_BLOCK FB 1544
TITLE =SYS TEMP MULTI V3
AUTHOR : SCM
NAME : FUNC
VERSION : 0.1


VAR_INPUT
  ACTIVE : INT ;    //Anzahl der aktiven Kanäle 0-15 kleiner 0 bzw. größer 15 =Baustein reset
  INPUT : WORD ;    //Temperatureingang
  OFFSET : INT ;    //Offset zum Eingang [1/10] °C
  TAKT : BOOL ;    //Takteingang für Erfassungszyklus (bei Rinck >1s)
END_VAR
VAR_OUTPUT
  CHANNEL : BYTE ;    //Kanal der eingelesen werden soll
  ERROR : BOOL ;    //Kanalfehler
END_VAR
VAR_IN_OUT
  TEMP : UDT 10005;    
END_VAR
VAR
  _flanke : ARRAY  [1 .. 8 ] OF BOOL ;    
  CNT : INT ;    //Zähler aktueller Wert
END_VAR
VAR_TEMP
  RETTAR1 : DWORD ;    //Adressregister 1
  RETTAR2 : DWORD ;    //Adressregister 2
  LOOPCNT : INT ;    //Anzahl aktiver Kanäle
  DB_NMB : WORD ;    
  QPOINTER : DWORD ;    
END_VAR
BEGIN
NETWORK
TITLE =Anzahl übernehmen

      L     #ACTIVE; 
      T     #LOOPCNT; 
NETWORK
TITLE =Grenzen prüfen und ggf. abnullen

      O(    ; 
      L     #LOOPCNT; 
      L     15; 
      >I    ; 
      )     ; 
      O(    ; 
      L     #LOOPCNT; 
      L     0; 
      <I    ; 
      )     ; 
      =     #ERROR; 
      U     #ERROR; 
      SPBN  ok; 
      L     0; 
      T     #TEMP.ACT[0]; 
      T     #TEMP.ACT[1]; 
      T     #TEMP.ACT[2]; 
      T     #TEMP.ACT[3]; 
      T     #TEMP.ACT[4]; 
      T     #TEMP.ACT[5]; 
      T     #TEMP.ACT[6]; 
      T     #TEMP.ACT[7]; 
      T     #TEMP.ACT[8]; 
      T     #TEMP.ACT[9]; 
      T     #TEMP.ACT[10]; 
      T     #TEMP.ACT[11]; 
      T     #TEMP.ACT[12]; 
      T     #TEMP.ACT[13]; 
      T     #TEMP.ACT[14]; 
      T     #TEMP.ACT[15]; 
      T     #CHANNEL; 
      T     #CNT; 
      BEA   ; 
ok:   NOP   0; 
NETWORK
TITLE =Werte übernehmen und auswerten

      L     #CNT; //Aktueller Schrittzähler
      T     #CHANNEL; //Ausgang für Adressierung Multiplexer
      U     #TAKT; //Abtasttakt
      FP    #_flanke[1]; 
      SPBN  m001; 

      TAR1  #RETTAR1; //Adressregister retten
      TAR2  #RETTAR2; //Adressregister retten

      LAR1  P##TEMP; //Pointer auf erste relevante Daten setzen
      L     #RETTAR2; //Adressregister 2 addieren für Multiinstanzfähigkeit
      +AR1  ; 
      L     W [AR1,P#0.0]; //DB nummer auslesen
      T     #DB_NMB; //Eintragen
      L     D [AR1,P#2.0]; //Pointer auslesen
      T     #QPOINTER; //Eintragen

      AUF   DB [#DB_NMB]; //DB aufschlagen
      L     #CNT; //Aktueller Schritt bzw. Temperaturwert
      L     2; //Schrittweite 2 weil die Werte INT sind
      *I    ; //Multiplizieren
      ITD   ; //Auf Doppel umwandeln
      SLD   3; //Ins Pointerformat wandeln
      L     #QPOINTER; //Quelle für Pointer Laden
      +D    ; //Addieren
      LAR1  ; //Offset aktueller schritt mit einrechnen und in AR1 laden
      L     #INPUT; //Eingangswert einlesen
      L     #OFFSET; //Offset zu Eingangswert
      +I    ; //Abziehen
      T     W [AR1,P#0.0]; //Auf Position schreiben die im AR1 steht
      L     W [AR1,P#32.0]; //Min auswerten
      <I    ; 
      SPBN  min; 
      TAK   ; 
      T     W [AR1,P#32.0]; 
min:  L     W [AR1,P#0.0]; //Max auswerten
      L     W [AR1,P#64.0]; 
      >I    ; 
      SPBN  max; 
      TAK   ; 
      T     W [AR1,P#64.0]; 
max:  L     #CNT; //Schrittzähler laden
      INC   1; //um eins erhöhen
      T     #CNT; //wieder in schrittzähler variable schreiben

      LAR1  #RETTAR1; //Adressregister restaurieren
      LAR2  #RETTAR2; //Adressregister restaurieren

m001: L     #CNT; //Schrittzähler auf überlauf prüfen
      L     #LOOPCNT; 
      >I    ; 
      SPBN  ende; 
      L     #CNT; 
      L     0; 
      T     #CNT; 
ende: SET   ; //Baustein immer mit vke 1 verlassen damit ENO immer 1 ist
      SAVE  ; 
END_FUNCTION_BLOCK
```


Mfg Mario


----------



## benjo (6 Januar 2012)

Hallo Mario,
vielen Dank für deine promte Anwort.
Hab versucht, das ganze auf codesys umzustricken, die Datenstruktur bekomme auch noch hin, aber spätesten beim Abschnitt
Title Network hört es bei meinen Umsetzungsfähigkeiten auf.
Hat vielleicht jemand das ganze als codesys -programmschnipsel
Wäre echt super


----------



## SCM (6 Januar 2012)

Hallo!

Aha hättest dazu sagen müssen das du nicht auf S7 Programmierst!


Mfg


----------



## benjo (6 Januar 2012)

Sorry,
ich hatte nur oscat gelesen und nicht
aufs "kleingedruckte" geschaut.

Aber vielleicht gibt es jemanden, der das ganze schon mal auf codesys umgesetzt hat

Gruß


----------



## Ferengi (14 Januar 2012)

Hallo,

schon jemand erfolg gehabt? könnte den FB auch gut gebrauchen (codesys)

Christian


----------



## dalbi (15 Januar 2012)

Hi,

hab das ganze mal in SCL (ST) umgeschrieben:


```
TYPE UDT_TEMP
  STRUCT
    ACT : ARRAY[0 .. 15] OF INT; (* Aktuelle Temperatur *)
    MIN : ARRAY[0 .. 15] OF INT; (* Minimale Temperatur *)
    MAX : ARRAY[0 .. 15] OF INT; (* Maximale Temperatur *)
  END_STRUCT
END_TYPE


FUNCTION_BLOCK SYS_TEMP_MULTI

TITLE = 'SYS TEMP MULTI'

VAR_INPUT
  ACTIVE : INT;        (* Anzahl der aktiven Kanäle 0-15 kleiner 0 bzw. größer 15 =Baustein reset *)
  INPUT : WORD;        (* Temperatureingang *)
  OFFSET : INT;        (* Offset zum Eingang [1/10] °C *)
  TAKT : TIME := T#2s; (* Taktzeit für Erfassungszyklus (bei Rinck >1s) *)
END_VAR

VAR_OUTPUT
  CHANNEL : BYTE;      (* Kanal der eingelesen werden soll *)
  ERROR : BOOL;        (* Kanalfehler *)
END_VAR

VAR_IN_OUT
  TEMP : UDT_TEMP;    
END_VAR

VAR
  CNT : INT;           (* Zähler aktueller Wert *)
  TTAKT : TON;         (* Timer für Takt *)
END_VAR

VAR_TEMP
  i : INT;
END_VAR

BEGIN

(*********************************************************)    
(* Grenzen prüfen und ggf. abnullen                      *)
(*********************************************************)    

  ERROR := (ACTIVE > 15) OR (ACTIVE < 0);

  IF ERROR THEN
    FOR i := 0 TO 15 DO 
      TEMP.ACT[i] := 0;
    END_FOR;
    CHANNEL := 0;
    CNT := 0;
    RETURN;
  END_IF;

(*********************************************************)    
(* Werte übernehmen und auswerten                        *)
(*********************************************************)    

  (* Ausgang für Adressierung Multiplexer *)
  CHANNEL := INT_TO_BYTE(CNT);

  (* Timer für Takt *)
  TTAKT(IN:= NOT TTAKT.Q, PT:= TAKT);

  IF TTAKT.Q THEN
    (* Eingangswert einlesen, Offset zu Eingangswert *)
    TEMP.ACT[CNT] := WORD_TO_INT(INPUT) + OFFSET;
    (* Min auswerten *)
    IF TEMP.ACT[CNT] < TEMP.MIN[CNT] THEN
      TEMP.MIN[CNT] := TEMP.ACT[CNT];
    END_IF;
    (* Max auswerten *)
    IF TEMP.ACT[CNT] > TEMP.MAX[CNT] THEN
      TEMP.MAX[CNT] := TEMP.ACT[CNT];
    END_IF;
    (* Schrittzähler um eins erhöhen *)
    CNT := CNT + 1; 
  END_IF;
  
  (* Schrittzähler auf überlauf prüfen *)
  IF CNT > ACTIVE THEN
    CNT := 0;
  END_IF;
  
END_FUNCTION_BLOCK
```

Für Takt hab ich eine TON genommen. Sollte der Offset nicht für jeden Kanal separat Einstellbar sein?

Gruss Daniel


----------



## Ferengi (15 Januar 2012)

*Danke!!!*

hallo,

vielen dank für die schnelle Hilfe, endlich eine Sprache die ein normaler Mensch auch lesen kann ;-)

musste nur MIN und MAX neue namen geben da die schon von der oscat benutzt werden, sonst stehts gut aus, multiplexer kommt nächste Woche, dann werd ichs mal testen.

Sicher währe ein eigener Offset pro Kanal besser, aber ich denke für die Heizungs/Raumtemperaturablesung sollte es auch so genügen, falls nicht kann man ja die werte im Array vor der Weiterverarbeitung bearbeiten. Alternativ kann ich ja jetzt auch am FB basteln.

also nochmal vielen Dank!

Christian


----------



## SCM (15 Januar 2012)

Hallo!

Also ich hab den Baustein für meine Anwendung geschreiben!Ich verwende lauter PT1000 fühler mit annähernd den selben Leitungslängen!
Von dem her reichte da der Offset für den gesamten Bereich!Ansonsten kannst ja dann auch noch auf den abgespeicherten Wert einen Offset verrechnen!
Wenn man bei der Rinck Homepage schaut gibt es ja auch die Anwendung wo nach dem Multiplexer ein Umsetzer ist der 0-10V draus macht!(Bei mir wie gesagt gehts ja direkt auf ein RTD Modul!)
Und da kann man auch eine Offset einstellen!Zur Kompensation des Innenwiderstandes vom Rinck Multiplexer!Genau das stellt mein Offset auch dar der auf jeden Kanal verrechnet wird!

Mfg Mario


----------

