StarterPack

ftComputing : Programme für die fischertechnik-Interfaces und -konstruktionskästen
  
ftComputing.de
Home
Back
Sitemap
Index
Links
Impressum
Mail
 

Computing Starter Pack : Temperaturregelung

Temperaturregelung Aufgabe

"Die Heizung wird simuliert durch die Linsenlampe M2, Als Kühlaggregat dient das Gebläse am Ausgang M1. Zur Temperaturmessung verwenden wir den NTC-Widerstand am Eingang EX. Programmiere das Modell so , daß oberhalb einer bestimmten Temperatur die Heizung aus- und das Gebläse einschaltet. Dieses soll so lange kühlen, bis ein unterer Grenzwert erreicht ist. Dann soll das Gebläse aus- und die Heizung eingeschaltet werden." Soweit das Zitat aus Computing Starter Begleitheft. Wenn man den Kasten nicht besitzt, dann kann man auch bei www.knobloch-gmbh.de die Bauanleitung 30434 und das Begleitheft 30435 erwerben (zusammen ca. 30 DM).

Lösung mit LLWin 3.0

von der LLWin 3.0 CD-ROM

LLWin 3.0 : Temperaturregelung

Visual Basic 6 & FishFa50.OCX

Zu Delphi gehts hier lang

tempar3.jpg (13894 Byte)Die beiden Grenzwerte werden in den Textboxen txtHeiß und txtKalt angezeigt über die sie auch modifiziert werden können. Der aktuelle Temperaturwert wird in lblTemperatur angezeigt. Die Namen mHeizung, mKühlung, aFühler ... sind Konstanten denen die entsprechenden Ein- und Ausgänge des Interfaces zugeordnet sind.

Es werden drei Lösungen vorgestellt :

1. Eine Lösung, die der LLWin-Lösung möglichst nahe ist : "Goto Label"-Lösung.
2. Eine Lösung, die die modernen sprachlichen Möglichkeiten von Visual Basic nutzt : "Select Case"-Lösung
3. Eine Lösung, die das Programm bedienungssicher macht : "Enabled"-Lösung.
Der eigentliche Programmablauf ist bei allen Programmversionen gleich.
Die vollständigen Sources zu den Programmen sind in Starter.ZIP zu finden. Zusätzlich ist das Päckchen FishFa50.ZIP erforderlich.

Tempar1 : "Goto Label"-Lösung

Private Sub cmdAction_Click()

ft.AnalogScan = True
ft.OpenInterface "COM1"
Start:
If ft.Finish(0) Then GoTo Ende
Kühlen:
If Temperatur >= Val(txtHeiß) Then GoTo Heizen
ft.SetMotor mHeizung, ftiAus
ft.SetMotor mKühlung, ftiEin
GoTo Start
Heizen:
If Temperatur <= Val(txtKalt) Then GoTo Start
ft.SetMotor mHeizung, ftiEin
ft.SetMotor mKühlung, ftiAus
GoTo Start
Ende:
ft.CloseInterface
End Sub

Private Sub tmrTemperatur_Timer()

Temperatur = ft.GetAnalog(aFühler)
lblTemperatur = Temperatur
End Sub

cmdAction_Click ist die Prozedur, die dem Klick-Ereignis des START-Buttons zugeordnet ist.  Hier wird der Ablauf der Reglung gesteuert :

  1. ft.AnalogScan = True
    Die Analog-Eingänge EX und EY sollen regelmäßig abgefragt werden
    ft.OpenInterface "COM1"
    Herstellen der Verbindung zum Intelligent Interface an COM1 (ggf. ändern). Bei LLWin werden diese Punkte innerhalb der Entwicklungs Umgebung erledigt.
  2. Start:
    If ft.Finish(0) then GoTo Ende

    Start markiert den Beginn der Regelungsschleife (das grüne Männchen)
    Finish erlaubt ein Beenden der Regelungsschleife durch die ESC-Taste, wenn dem Modelle ein zusätzlicher Ende-Taster spendiert wird kann hier anstelle des Parameters 0 die Nummer seines E-Einganges angegeben werden.
  3. Kühlen:
    If Temperatur >= Val(txtHeiß) Then GoTo Heizen
    ft.SetMotor mHeizung, ftiAus
    ft.SetMotor mKühlung, ftiEin
    GoTo Start
    Hier wird abgefragt, ob die aktuelle Temperatur noch nicht zu hoch ist (LLWin fragt ab, ob die akt. Temp. zu hoch ist, das wurde hier geändert um die If-Ausgänge zu vertauschen). Mit SetMotor werden die M-Ausgänge für die Linsenbirne aus- und für den Kühlermotor eingeschaltet. Mit Start gehts wieder in die Regelungsschleife.
  4. Heizen:
    Analog Kühlen. Abgefragt wird, ob die Temperatur noch ausreichend hoch ist.
  5. Ende:
    ft.CloseInterface
    Sprungziel für das Beenden der Regelungsschleife.
    CloseInterface schließt die Verbindung zum Interface.
  6. tmrTemperatur_Timer
    Hier wird unabhängig von der Regelungsschleife der aktuelle Temperaturwert abgefragt und angezeigt (zweites grünes Männchen).

Tempar2 : "Select Case"-Lösung

Private Sub cmdAction_Click()

ft.AnalogScan = True
ft.OpenInterface "COM1"
Do
Temperatur = ft.GetAnalog(aFühler)
lblTemperatur = Temperatur
Select Case Temperatur
Case Is < Val(txtHeiß)
ft.SetMotor mHeizung, ftiAus
ft.SetMotor mKühlung, ftiEin
Case Is > Val(txtKalt)
ft.SetMotor mHeizung, ftiEin
ft.SetMotor mKühlung, ftiAus
End Select
Loop Until ft.Finish(0)
ft.CloseInterface
End Sub

Hier die gleiche Funktionalität nochmal. Anstelle GoTo und Label wurden hier aber das Select Case Konstrukt verwendet außerdem wurde einfachheitshalber die Abfrage des Temperaturwertes in die Regelungsschleife aufgenommen.

  1. Select Case Temperatur
    Case Is < Val(txtHeiß)
    Case Is > Val(txtKalt)
    End Select

    Kann man als ein kompaktes Mehrfach-If verstehen bei dem der erste zutreffende Fall (case) aus geführt wird, der Rest des Select Case wird dann übersprungen.
    Is < Val(txtHeiß) fragt, ob die Temperatur kleiner als der Heiß-Grenzwert ist.
  2. Do
    Loop Until ft.Finish(0)

    markiert die Regelungsschleife, sie wird solange (Until) durchlaufen bis die ESC-Taste erkannt wurde.
  3. Val(txtHeiß)
    Der Grenzwert für Heiß wird in der Form als Text eingeben. Hier wird er in eine Zahl umgewandelt. Bei unzulässigen Zeichen in der Zahl wird nur bis zu dem unzul. Zeichen umgewandelt, ist schon das erste Zeichen unzul. gibt das dann eine Null.

Tempar3 : "Enabled"-Lösung

Private Sub cmdAction_Click()

Dim Temperatur&
ft.AnalogScan = True
If ft.OpenInterface("COM1") = ftifehler Then
MsgBox "Interfaceproblem", vbOKOnly
Exit Sub
End If
cmdAction.Enabled = False
cmdEnde.Caption = "HALT"
Do
Temperatur = ft.GetAnalog(aFühler)
lblTemperatur = Temperatur
Select Case Temperatur
Case Is < Val(txtHeiß)
ft.SetMotor mHeizung, ftiAus
ft.SetMotor mKühlung, ftiEin
Case Is > Val(txtKalt)
ft.SetMotor mHeizung, ftiEin
ft.SetMotor mKühlung, ftiAus
End Select
ft.Pause 500
Loop Until ft.Finish(0)
ft.ClearMotors
ft.CloseInterface
cmdEnde.Caption = "ENDE"
cmdAction.Enabled = True
cmdEnde.SetFocus
End Sub


Private Sub cmdEnde_Click()

If cmdEnde.Caption = "HALT" Then
ft.NotHalt = True
Else
Unload Me
End If
End Sub


Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)

If cmdEnde.Caption = "HALT" Then Cancel = 1
End Sub

Die Regelungsschleife entspricht der von Tempar2. Hier wurde zusätzlicher Code eingefügt um das Programm bedienungssicherer (robuster) zu machen. In den bisherigen Lösungen kann man z.B. den START-Button (und auch den ENDE-Button) drücken während die Regelungsschleife läuft, das stiftet dann Verwirrung. Ebenso kann man vergessen vor dem START das Interface mit der Stromquelle zu verbinden, das produziert dann Ratlosigkeit. Das Beenden eines Programmes ist gar nicht so einfach, wenn eine Endlosschleife (die Regelschleife) läuft. LLWin kümmert sich da diskret selber drum, wenn man auf die Ampel klickt :

  1. If ft.OpenInterface("COM1") = ftiFehler Then
    Msgbox "Interfaceproblem", vbOKOnly
    Exit Sub
    End If
    OpenInterface liefert einen Rückgabewert (Returncode), der anzeigt, ob das Open erfolgreich war. Hier wird abgefragt, ob der Returncode = ftiFehler war, das wird dann gemeldet und die Routine schlagartig verlassen.
  2. cmdAction.Enabled = False
    cmdEnde.Caption = "HALT"
    Wenn OpenInterface erfolgreich war, soll die Regelungsschleife anlaufen, dazu wird der START-Button verriegelt um einen erneuten START zu verhindern, die Beschriftung des ENDE-Buttons wird in HALT geändert, er soll jetzt nicht mehr das Programm beenden, sondern nur die Regelungsschleife (wie das bisher nur durch die ESC-Taste geschah).
  3. If cmdEnde.Caption = "HALT" Then
    ft.NotHalt = True
    Else
    Unload Me
    End If
    Der ENDE-Button hat jezt eine zweite Aufgabe bekommen : das Beenden der Regelungsschleife. Das geschieht, wenn seine Beschriftung (caption) HALT lautet, dann wird ft.NotHalt = True gesetzt. Mehr geschieht hier nicht. ft.Finish(0) am Ende der Regelungsschleife wertet das aus (neben der ESC-Tast und ggf. einem Ende-Taster).
  4. ft.ClearMotors
    ft.CloseInterface
    cmdEnde.Caption = "ENDE"
    cmdAction.Enabled = True
    cmdEnde.SetFocus
    Am Ende der Regelungsschleife wird aufgeräumt. ClearMotors löscht alle M-Ausgänge. Motor und Lampe werden hier also gezielt abgeschaltet und nicht erst irgendwann beim Beenden der Verbindung durch CloseInterface. Außerdem bekommt der ENDE-Button seine angestammte Beschriftung wieder und der START-Button wird reaktiviert.
  5. Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    If cmdEnde.Caption = "HALT" Then Cancel = 1
    End Sub
    Und dann ist da noch das Kreuz mit dem Kreuz rechts oben am Fensterrahmen mit dem man so schön ein Programm beenden kann, hier nicht : Bei dem Versuch die Form zu entladen (QueryUnload) wird geblockt und der Rückgabeparameter auf 1 gesetzt (Form entladen abgelehnt).

Wenn man schon bei Form-Ereignissen ist und es dumm findet, daß bei jedem START eine Verbindung zum Interface hergestellt und wieder abgebrochen wird, kann man das natürlich auch in die Form_Load und Form_Unload Ereignisprozeduren legen ......

Und wenn man mit den "umgekehrten" Temperaturen , die der NTC liefert, auf Kriegsfuß steht kann man sie natürlich auch umrechnen : Temperatur = 600 - ft.GetAnalog(aFühler) wäre da schon mal ein Anfang und dann die Vergleiche umdrehen .......

Wie kommt es eigentlich, daß sich manchmal gar nichts rührt, wenn man das Programm startet. Es heizt nicht, es kühlt nicht, es tut einfach nichts und wird erst aktiv, wenn der Temperaturfühler (NTC) kalt genug ist. Wobei es sonst doch so unermüdlich kühlt und heizt. Wie wäre es mit einem zusätzlichen Case Val(txtHeiß) To Val(txtKalt) ? ....

Und dann gibt es da noch das Projekt Tempar4, das ist aber reine Spielerei, man sollte es sich deswegen sofort ansehen.

Delphi 4 und umFishEx / umFish20Ex

tempardelphi.jpg (12965 Byte)Damit die Delphi-Anhänger nicht zu kurz kommen, hier - als Kontrast - eine Delphi-Lösung auf Basis von umFish.DLL und umFishEx.PAS. Die Sources sind ebenfalls in Starter.ZIP enthalten, Zusätzlich ist umFishU.ZIP erforderlich. Es ist eine Lösung, die schon etwas Komfort bietet, dies mal aber nur mit einem Button, Ende über das Kreuz (x) rechts oben :

 

 

procedure TForm1.cmdActionClick(Sender: TObject);
const

mKuehlung = 1; mHeizung = 2; aFuehler = 0;
var
Temperatur, Heiss, Kalt: LongInt;
begin

if cmdAction.Caption = 'HALT' then begin ftiNotHalt := True; exit end;
cmdAction.Caption := 'HALT';
ftiOpenInterface('COM1');
Heiss := StrToInt(txtHeiss.Text);
Kalt := StrToInt(txtKalt.Text);
repeat
Temperatur := ftiGetAnalog(aFuehler);
lblTemperatur.Caption := IntToStr(Temperatur);
if Temperatur < Heiss then
begin
ftiSetMotor(mHeizung, ftiAus);
ftiSetMotor(mKuehlung, ftiEin);
end
else if Temperatur > Kalt then
begin
ftiSetMotor(mHeizung, ftiEin);
ftiSetMotor(mKuehlung, ftiAus);
end;
until ftiFinish(0);
ftiClearMotors();
ftiCloseInterface;
cmdAction.Caption := 'START';
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if cmdAction.Caption = 'HALT' then CanClose := False;
end;

Zusätzlich noch bei den uses am Anfang ein umFishEx /umFish20Ex einfügen.

  1. ftiOpenInterface('COM1') stellt die Verbindung zum Interface her (ggf. anderen Parameterwert angeben. Ein if ftiOpenInterface('COM1') = ftiFehler then ... würde zusätzlich noch Nachricht geben, wenn die Verbindungsbemühungen erfolglos waren. ftiClearMotors schaltet die M-Ausgänge aus und ftiCloseInterface trennt dann die Verbindung zum Interface wieder. Hier werden auch die aktuellen Grenzwerte für Heiß und Kalt von der Form übernommen.
  2. Die Regelungsschleife selber ist in einer repeat ... until Konstruktion geklammert. Beendet wird sie durch die ESC-Taste oder durch ftiNotHalt = True.   Beides wird in ftiFinish(0) abgefragt, bei einem Parameterwert > 0 würde zusätzlich noch der entsprechende E-Eingang abgefragt.
  3. Gleich zu Beginn der repeat-Schleife wird über ftiGetAnalog der aktuelle Temperaturwert abgefragt und in lblTemperatur auf der Form angezeigt.
  4. Bei if Temperatur < Heiss ist die erlaubte Temperatur überschritten (NTC : negative temparature coefficient, je heißer - je kleiner) und mit ftiSetMotor mHeizung die Lampe ausgeschaltet und mit ftiSetMotor mKühlung der Ventilator eingeschaltet.
  5. Bei if Temperatur > Kalt ist zu kalt, da gehts umgekehrt.
  6. Zu Beginn der procedure wird abgefragt, ob die Regelungsschleife schon läuft (if cmdAction.Caption = 'HALT') dann wird über NotHalt := True ein Ende-Wunsch angemeldet (der Button hat jetzt ja die HALT-Beschriftung) und und die procedure gleich wieder verlassen. Der Ende-Wunsch wird durch ftiFinish(0) ausgewertet. Man sieht : die gleiche procedure kann auch aufgerufen werden wenn sie noch läuft (ftiGetAnalog ... schalten intern diese Unterbrechungsmöglichkeit (Application.ProcessMessages um auch andere dran zu lassen z.B. den HALT-Button).
  7. Deswegen wird mit cmdAction.Caption := 'HALT' am Beginn und := 'START' am Ende der Procedure für einen zweiten Aufruf gesperrt und gleichzeitig für das Ende beschriftet.
  8. Und dann gibt es da noch die procedure TForm1.FormCloseQuery, die - nach einem Blick auf die Button-Beschriftung - auf die Frage : Dürfen wir schließen? schlicht Nein sagt, wenn sie HALT lautet.