====== 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 ==== 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 0x02 Start of Text Start eines neuen Commands 0x03 End of Text Ende eines Commands 0x10 Data Link Escape folgendes byte ist ein Wert und _kein_ Steuerzeichen (wenn < 0x20 !) 0x06 Acknowledge Command wurde verstanden 0x15 Not Acknowledge Command wurde nicht verstanden 0x16 Syncronisation Status Nachricht des µControllers 0x18 Cancel Command not Implemented 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: [] Jedem Wert der kleiner als 0x20 ist und einem CMD übergeben werden soll muss ein 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 ()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 escaped werden, für evt. Erweiterungen sind die anderen Steuerzeichen aber auch zu escapen! === 3.1.2 Antworten Format === Generelles Antwort Telegramm: (||) [([] )*||] Das erste Byte kennzeichnet folgende Zustände: Der CMD wurde verstanden Der CMD wurde nicht verstanden 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 oder ein ohne vorheriges emfangen handelt es sich um die folgenden Fehler: CMD wurde ausgeführt, dabei ist ein Fehler aufgetreten CMD ist [noch] nicht implementiert Ein kennzeichnet das Ende eines Antwort Telegramms. == 3.1.2.1 Antwort Beispiele == Der CMD wurde verstanden und erfolgreich ausgeführt. <0x10> <0x54> <0x34> <0x20> <0x01> <0x00> Der CMD wurde verstanden und erfolgreich ausgeführt. 0x10 0x54 0x34 0x20 0x01 0x00 ist die Antwort. Der CMD wurde nicht verstanden (exisitert nicht) 0x24 Der Status CMD mit dem Wert 0x24 wurde Empfangen (in diesem Fall hat sich die Temperatur auf 0x24 geändert) Der CMD wurde ausgeführt, dabei ist ein Fehler aufgetreten 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 () übergeben werden (dabei ein eventuelles 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: <0x24> <0x05> 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.\\ CurrentTemp / NominalTemp / StartTemp / StopTemp / OldTemp / DeltaTemp / TempCheckTime / FanState / FanSpeed / FanMinSpeed / FanMaxSpeed / FanDeltaSpeed / FanStartSpeed / FanAfterstartSpeed / FanStartTime / LedsOn / LedsBlinkfast / LedsBlinkslow / LedSlowblinkTime / PowerState / AliveMsgTime / MsgStates \\ Selbstverständlich sind Werte < 0x20 durch ein vorangestelltes 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 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)\\