FanControl

1. Funktionsbeschreibung

Das Projekt „temp_fan_control“ dient der Temperaturgesteuerten Überwachung der Geschwindigkeit eines Lüfters. Da noch Port Ein-/Ausgänge frei waren wurden auch noch 6 LEDs sowie 4 schaltbare 12V Spannungen implementiert. Für evt. Erweiterungen stehen immer noch ca. 4-6 I/Os zur Verfügung.

1.1 PIC-Firmware

Die Regelung der Lüftergeschwindigkeit wird dabei vollkommen autag vom µController (PIC16F886) übernommen. Die Parameter für die Regelung können über die serielle Schnittstelle eingestellt werden. Auch können über bestimmte Befehle (siehe Commands) die LEDs eingschaltet werden, langsam blinken oder schnell blinken, wobei die Blinkfrequenz für langsames Blinken auch einstellbar ist. Genauso können auch die 12V Spannungen Ein- oder Ausgeschaltet werden. Um eine Kontrolle über die Verbindung zu haben wird ausserdem in einem definierten Zeitabstand eine „alive“ Nachricht vom PIC gesendet, bleibt diese aus liegt irgendein Fehler beim PIC oder der seriellen Schnittstelle vor.

1.2 controlPICd

Da die serielle Schnittstelle nur von einem Programm zur Zeit genutzt werden kann wurde ein Control Daemon geschrieben der im Hintergrund läuft und über den system-DBus anderen Anwendungen die Funktionalität des µControllers zur Verfügung stellt. Der controlPICd übernimmt somit die Kommunikation mit dem PIC, filtert die entsprechenden Antworten und schickt sie der Anwendung zurück die sie angefordert hat.

2. Regelverhalten des µControllers

Die Geschwindigkeit des Lüfters wird nach der folgenden Formel berechnet: (Punkt vor Strich wird bei der Berechnung beachtet!)

diff_set = Differenz zur eingestellten Soll-Temperatur
diff_old = Differenz zur vorherigen Messung
speed = Geschwindigkeit des Lüfters
Temp_diff = Einstellbarer Regelparameter (siehe Formel)
Speed_diff = Einstellbarer Regelparameter (siehe Formel)

speed = speed + (diff_set * Temp_diff + diff_old * Temp_diff) * Speed_diff

Es ergibt sich ein PI-Regler und somit keine bleibende Regelabweichung!

speed stellt den 8-Bit Wert für einen DAC dar dessen Ausgangsspannung wiederrum über einen Operations-Verstärker um den Faktor 2,5 verstärkt wird und dann die Spannung für den Lüfter ausgibt. Wobei ein LSB ca. 60mV der Lüfterspannung entspricht.

Angenommen die aktuelle Lüfter Geschwindigkeit beträgt 0x80 und es wird eine Temperatur von 36°C als Soll vorgegeben. Wenn die Ist-Temperatur nun 37°C beträgt und als Temp_diff ein Wert von 4 und für Speed_diff ein Wert von 3 eingestellt ist, ergibt sich für jeden durchlauf der Temperaturprüfung eine Erhöhung der Lüftergeschwindigkeit von 1°C * 4 * 3 = 12 (0x0C).

Durch die Integration der Differenz zur vorherigen Temperaturprüfung wird, wenn sich die Temperatur von einem stabilen Wert aus erhöht hat, der Lüfter erst einmal etwas mehr erhöht. Wenn sich die Temperatur dann bei der nächsten Messung noch nicht wieder verringert hat wird der Lüfter wieder im „normalem“ Intervall erhöht. Somit wird schnell auf Temperaturänderungen reagiert und langsam versucht die soll Temperatur wieder zu erreichen.

Auch die Zeit die zwischen den Temperaturprüfungen liegen soll kann eingestellt werden.

Bei nahezu allen Zeiten die Einstellbar sind handelt es sich um vielfache von ~524ms, dies ist die Zeit nach der der Timer1 einen Interrupt auslöst (zumindest bei 4MHz).

3. Interface Beschreibung

3.1 PIC Firmware

<CMD> steht für den entsprechenden Befehl, mögliche Werte folgen später. Der PIC wertet die Empfangenen Bytes anhand deren Wert und deren Position im Telegramm aus. Folgende Steuerzeichen werden dabei beim Empfang und beim Senden von Telegrammen verwendet:

Byte 	Hex   Bezeichnung	Verwendung
<STX>	0x02  Start of Text	Start eines neuen Commands
<ETX>	0x03  End of Text	Ende eines Commands
<DLE>	0x10  Data Link Escape	folgendes byte ist ein Wert und _kein_ Steuerzeichen (wenn < 0x20 !)
<ACK>	0x06  Acknowledge	Command wurde verstanden
<NAK>	0x15  Not Acknowledge	Command wurde nicht verstanden
<SYN>	0x16  Syncronisation	Status Nachricht des µControllers
<CAN>	0x18  Cancel		Command not Implemented
<NUL>	0x00  Null character	Command fehlerhaft

3.1.1 Command (CMD) Format

Jeder CMD der an den PIC übertragen wird muss in einem definierten Telegramm übertragen werden! Generelles CMD Telegramm:

<STX> <CMD> [<DLE>] <VALUE> <ETX>

Jedem Wert der kleiner als 0x20 ist und einem CMD übergeben werden soll muss ein <DLE> vorangestellt werden, dadurch wird dem PIC mitgeteilt dass das folgende Byte als Wert und nicht als Steuerzeichen interpretiert werden soll. Ansonsten wäre es z.B. nicht möglich 0x03 (<ETX>)als Wert zu übertragen, da der PIC dies als CMD Ende verstehen würde! Streng genommen müssen nur die oben aufgeführten Werte mit einem vorherigen <DLE> escaped werden, für evt. Erweiterungen sind die anderen Steuerzeichen aber auch zu escapen!

3.1.2 Antworten Format

Generelles Antwort Telegramm:

(<ACK>|<NAK>|<SYN>) <CMD> [([<DLE>] <VALUE>)*|<NUL>|<CAN>]<EOT>

Das erste Byte kennzeichnet folgende Zustände:

<ACK>	Der CMD wurde verstanden
<NAK>	Der CMD wurde nicht verstanden
<SYN>	Status Telegramm des µControllers (wird ohne vorherige Aufforderung gesendet)

Das zweite Byte ist der CMD der ausgeführt werden sollte.

Danach können unentlich viele oder keine Werte folgen. Wird ein <NUL> oder ein <CAN> ohne vorheriges <DLE> emfangen handelt es sich um die folgenden Fehler:

<NUL>	CMD wurde ausgeführt, dabei ist ein Fehler aufgetreten
<CAN>	CMD ist [noch] nicht implementiert

Ein <EOT> kennzeichnet das Ende eines Antwort Telegramms.

3.1.2.1 Antwort Beispiele
<ACK> <CMD> <EOT>

Der CMD wurde verstanden und erfolgreich ausgeführt.

<ACK> <CMD> <DLE> <0x10> <0x54> <0x34> <0x20> <DLE> <0x01> <DLE> <0x00> <EOT>

Der CMD wurde verstanden und erfolgreich ausgeführt. 0x10 0x54 0x34 0x20 0x01 0x00 ist die Antwort.

<NAK> <CMD> <EOT>

Der CMD wurde nicht verstanden (exisitert nicht)

<SYN> <CMD> 0x24 <EOT>

Der Status CMD mit dem Wert 0x24 wurde Empfangen (in diesem Fall hat sich die Temperatur auf 0x24 geändert)

<ACK> <CMD> <NUL> <EOT>

Der CMD wurde ausgeführt, dabei ist ein Fehler aufgetreten

<ACK> <CMD> <CAN> <EOT>

Der CMD ist [noch] nicht implementiert

3.2 Commands

In der Datei „command_defines.h“ sind alle möglichen Befehle und die Steuerzeichen per #define definiert. Wenn nach dem CMD ein 0x__ steht muss bei diesem CMD zwingend ein Wert (<VALUE>) übergeben werden (dabei ein eventuelles <DLE> nicht vergessen!). Wird kein Wert übertragen sondern gleich das Command-Ende Zeichen wird ein undefinierter Wert für den Command verwendet!

CMD_SET_* Commands setzen einen Wert im µController und CMD_GET_* Commands senden den oder die angeforderten Wert(e) zurück.

3.2.1 Generelle Befehle

CMD_RESET
Löst ein reset aus und der PIC startet von vorne.

3.2.2 Commands zur Einstellung des Regelverhaltens

siehe auch Kapitel 2. Regelverhalten des µControllers

CMD_SET_TEMP_NOMINAL 0x__
CMD_GET_TEMP_NOMINAL
Stellt die Soll-Temperatur ein bzw. gibt diese zurück.

CMD_SET_TEMP_START 0x__
CMD_GET_TEMP_ON
not implementet yet. Stellt die Temperatur ein bei der der Lüfter eingeschaltet wird bzw. gibt diese zurück.

CMD_SET_TEMP_STOP 0x__
CMD_GET_TEMP_OFF
not implementet yet. Stellt die Temperatur ein bei der der Lüfter ausgeschaltet wird bzw. gibt diese zurück.

CMD_SET_TEMP_DELTA 0x__
CMD_GET_TEMP_DELTA
Stellt den Delta-Temperatur-Wert ein.

CMD_SET_TIME_TEMPCHECK 0x__
CMD_GET_TIME_TEMPCHECK
Stellt die Anzahl der Timer1 Intterupts ein, die vergehen müssen bevor eine neue Temperaturprüfung stattfindet.

CMD_SET_FAN_MIN_SPEED 0x__
CMD_GET_FAN_MIN_SPEED
Stellt den minimalen DAC-Wert für die Lüfterspannung ein.

CMD_SET_FAN_MAX_SPEED 0x__
CMD_GET_FAN_MAX_SPEED
Stellt den maximalen DAC-Wert für die Lüfterspannung ein.

CMD_SET_FAN_DELTA_SPEED 0x__
CMD_GET_FAN_DELTA_SPEED
Stellt den Wert für die Änderung des DAC-Wertes ein.

CMD_SET_FAN_START_SPEED 0x__
CMD_GET_FAN_START_SPEED
Stellt den DAC-Wert ein der beim Einschalten des Lüfters verwendet wird.

CMD_SET_FAN_AFTERSTART_SPEED 0x__
CMD_GET_FAN_AFTERSTART_SPEED
Stellt den DAC-Wert ein, der nach der Startphase des Lüfters verwendet wird.

CMD_SET_TIME_FANSTART 0x__
CMD_GET_TIME_FANSTART
Stellt die Anzahl der Timer1 Interrupts ein, die vergehen müssen bis der Lüfter als sicher eingeschaltet betrachtet wird.

3.2.3 Commands zur Überprüfung des Regelverhaltens

CMD_GET_FAN_STATE
Gibt den Status des Lüfters zurück. 0=Off / 1=On / 2=startet

CMD_GET_FAN_CURR_SPEED
Gibt den aktuellen DAC-Wert für die Lüfterspannung zurück.

CMD_GET_TEMPERATURE
Löst ein auslesen der Temperatur aus und gibt diese zurück. Dabei werden 2 Bytes übertragen, das erste Byte gibt den Wert vor dem Komma an und das zweite den Wert nach dem Komma. (Es wird nur zwischen X,0 und X,5 unterschieden!)
Beispiel:

<ACK> <CMD_GET_TEMPERATURE> <0x24> <DLE> <0x05> <EOT>  für 36,5°C

CMD_GET_RPM
not implement yet.
Gibt die aktuelle Drehzahl des Lüfters zurück.

CMD_GET_ALL_VALUES
Gibt alle Eingestellten Werte in der folgenden Reihenfolge zurück.
<ACK> <CMD> CurrentTemp / NominalTemp / StartTemp / StopTemp / OldTemp / DeltaTemp / TempCheckTime / FanState / FanSpeed / FanMinSpeed / FanMaxSpeed / FanDeltaSpeed / FanStartSpeed / FanAfterstartSpeed / FanStartTime / LedsOn / LedsBlinkfast / LedsBlinkslow / LedSlowblinkTime / PowerState / AliveMsgTime / MsgStates <EOT>
Selbstverständlich sind Werte < 0x20 durch ein vorangestelltes <DLE> gekennzeichnet.

CMD_GET_TEMP_OLD
Gibt die Temperatur der vorherigen Temperaturmessung zurück.

3.2.4 Commands zur Steuerung der LEDs

Die LEDs sind wie folgt plaziert und kodiert:

				L1 = 0x01 = Blau rechts
	--------------		L2 = 0x02 = Blau mitte
	| L3  L2  L1 |		L3 = 0x04 = Blau links
	| L6  L5  L4 |		L4 = 0x08 = rot
	--------------		L5 = 0x10 = gelb
				L6 = 0x20 = grün

Über eine UND-Verknüpfung der einzelnen Wertigkeiten können auch mehrere LEDs gleichzeitig an einen CMD übergeben bzw. zurückgegeben werden z.B. 0x35 = blau_rechts & blau_links & gelb & grün. Dies ist aber nicht explizit notwendig, da die übergebenen LEDs zusätzlich zu den bereits gesetzten eingeschaltet werden. Wenn z.B. die rote und grüne LED leuchten und die blaue LED in der mitte langsam blinkt kann über 0x01 die Blaue LED rechts geändert werden ohne den Zustand der anderen LEDs zu ändern!

CMD_SET_LEDS_ON 0x__
CMD_GET_LEDS_ON
Schaltet die übergebenen LEDs ein oder gibt die aktuell eingeschalteten LEDs zurück.

CMD_SET_LEDS_BLINKFAST 0x__
CMD_GET_LEDS_BLINKFAST
Läst die übergebenen LEDs schnell blinken (~524ms an und dann ~524ms aus) bzw. gibt die aktuell schnell blinkenden LEDs zurück.

CMD_SET_LEDS_BLINKSLOW 0x__
CMD_GET_LEDS_BLINKSLOW
Läst die übergebenen LEDs langsam blinken (einstellbar) bzw. gibt die aktuell langsam blinkenden LEDs zurück.

CMD_SET_LEDS_OFF 0x__
Schaltet die übergebenen LEDs aus.

CMD_SET_TIME_LED_SLOWBLINK 0x__
CMD_GET_TIME_LED_SLOWBLINK
Legt die Geschwindigkeit für langsames Blinken fest.
(Diese Zeit ist kein fest definierbarer Wert, da einfach bei jedem durchlauf von MAIN eine Zählvariable decrementiert wird. Abhängig davon welche funktionen aus MAIN heraus gestartet werden kann dieses decrementieren mal schneller und mal langsamer geschehen (liegt aber im µs bis max. 1-2ms Bereich)).

3.2.5 Status Messages

Status Messages sind Nachrichten des µControllers die bei einer Änderung eines Wertes automatisch über die serielle Schnittstelle gesendet werden. Alle diese Nachrichten Telegramme beginnen, wie in Kapitel 3.1.2 beschrieben, mit <SYN> und können dadurch leicht erkannt und ausgewertet werden.

Folgenende Nachrichten sind möglich:

PIC_ALIVE
Dient der Überprüfung ob der PIC noch richtig funktioniert und wird periodisch, in einem einstellbaren Intervall, gesendet (WatchDog Reset funktionalität).

STATE_CHG_TEMP 0x__
Wird gesendet wenn sich die Temperatur geändert hat. Als Wert wird die neue Temperatur mit übertragen.

STATE_CHG_FAN 0x__
Wird gesendet wenn sich der Status des Lüfters geändert hat. Als Wert wird der neue Status des Lüfters mit übertragen. (0=Aus / 1=An / 2=startet)

STATE_CHG_SPEED
Wird gesendet wenn sich der DAC-Wert für die Spannung des Lüfters ändern. Als Wert wird der neue DAC-Wert für die Spannung des Lüfters mit übertragen.

Es können alle 4 möglichen Status Nachrichten des µControllers einzeln ein- oder ausgeschaltet werden, dabei gilt folgende zuweisung:

Bit 0 = STATE_CHG_TEMP
Bit 1 = STATE_CHG_FAN
Bit 2 = STATE_CHG_SPEED
Bit 3 = PIC_ALIVE

Wenn ein Bit gesetzt ist wird die entsprechende Status Nachricht gesendet, ansonsten nicht.

CMD_SET_STATE_MSGS 0x__
CMD_GET_STATE_MSGS
Schaltet die angegebenen Status Nachrichten ein bzw. aus. (0x0F schaltet alle ein)

CMD_SET_ALIVE_TIME 0x__
CMD_GET_ALIVE_TIME
Setzt die Anzahl der Timer1 Intterupts, die zwischen den PIC_ALIVE Nachrichten vergehen müssen.

3.2.6 Power State Commands

CMD_SET_POWER_ON 0x__
Schaltet die 12V der gesetzten Bits ein. Wenn bereits eingeschaltet wird keine Änderung durchgeführt.

CMD_SET_POWER_OFF 0x__
Schaltet die 12V der gesetzten Bits aus. Wenn bereits ausgeschaltet wird keine Änderung durchgeführt.

CMD_GET_POWER_STATE
Gibt die aktuell eingeschalteten 12V Bits zurück.

4. DBus Methods und Signals des controlPICd

muss noch ausführlich dokumentiert werden! Oder auf die doxygen Dokumentation verweisen?

signal void org.schmufu.ControlPICd.CommunicationWithPicLost(QString time)
signal void org.schmufu.ControlPICd.FanSpeedChanged(uchar newSpeed)
signal void org.schmufu.ControlPICd.FanStateChanged(uchar newState)
signal void org.schmufu.ControlPICd.TemperatureChanged(uchar newTemperature)
signal void org.schmufu.ControlPICd.fatalError(bool active)

method Q_NOREPLY void org.schmufu.ControlPICd.setFatalError()
method Q_NOREPLY void org.schmufu.ControlPICd.clearFatalError()

method int org.schmufu.ControlPICd.getAliveMsgTime()
method int org.schmufu.ControlPICd.getDeltaTemperature()
method int org.schmufu.ControlPICd.getFanAfterstartSpeed()
method int org.schmufu.ControlPICd.getFanCurrentSpeed()
method int org.schmufu.ControlPICd.getFanDeltaSpeed()
method int org.schmufu.ControlPICd.getFanMaximumSpeed()
method int org.schmufu.ControlPICd.getFanMinimumSpeed()
method int org.schmufu.ControlPICd.getFanRPM()
method int org.schmufu.ControlPICd.getFanStartSpeed()
method int org.schmufu.ControlPICd.getFanStartTime()
method int org.schmufu.ControlPICd.getFanState()
method int org.schmufu.ControlPICd.getLEDsBlinkfast()
method int org.schmufu.ControlPICd.getLEDsBlinkslow()
method int org.schmufu.ControlPICd.getLEDsOn()
method int org.schmufu.ControlPICd.getLedSlowblinkTime()
method int org.schmufu.ControlPICd.getNominalTemperature()
method int org.schmufu.ControlPICd.getOldTemperature()
method int org.schmufu.ControlPICd.getPowerState()
method int org.schmufu.ControlPICd.getStartTemperature()
method int org.schmufu.ControlPICd.getStateMsgs()
method int org.schmufu.ControlPICd.getStopTemperature()
method int org.schmufu.ControlPICd.getTemperatureCheckTime()
method QString org.schmufu.ControlPICd.getAllValues()
method QString org.schmufu.ControlPICd.getCurrentTemperature(uchar channel)

method bool org.schmufu.ControlPICd.setAliveMsgTime(uchar time)
method bool org.schmufu.ControlPICd.setDeltaTemperature(uchar temperature)
method bool org.schmufu.ControlPICd.setFanAfterstartSpeed(uchar speed)
method bool org.schmufu.ControlPICd.setFanDeltaSpeed(uchar speed)
method bool org.schmufu.ControlPICd.setFanMaximumSpeed(uchar speed)
method bool org.schmufu.ControlPICd.setFanMinimumSpeed(uchar speed)
method bool org.schmufu.ControlPICd.setFanStartSpeed(uchar speed)
method bool org.schmufu.ControlPICd.setFanStartTime(uchar time)
method bool org.schmufu.ControlPICd.setLED(uchar LED_Num, uchar state)
method bool org.schmufu.ControlPICd.setLED_blue_left(uchar state)
method bool org.schmufu.ControlPICd.setLED_blue_middle(uchar state)
method bool org.schmufu.ControlPICd.setLED_blue_right(uchar state)
method bool org.schmufu.ControlPICd.setLED_green(uchar state)
method bool org.schmufu.ControlPICd.setLED_red(uchar state)
method bool org.schmufu.ControlPICd.setLED_yellow(uchar state)
method bool org.schmufu.ControlPICd.setLedSlowblinkTime(uchar time)
method bool org.schmufu.ControlPICd.setNominalTemperature(uchar temperature)
method bool org.schmufu.ControlPICd.setPowerOff(uchar ports)
method bool org.schmufu.ControlPICd.setPowerOn(uchar ports)
method bool org.schmufu.ControlPICd.setStartTemperature(uchar temperature)
method bool org.schmufu.ControlPICd.setStateMsg(uchar msgs)
method bool org.schmufu.ControlPICd.setStopTemperature(uchar temperature)
method bool org.schmufu.ControlPICd.setTemperatureCheckTime(uchar time)

method Q_NOREPLY void org.schmufu.ControlPICd.quit(QString password)

Projektwerkzeuge