'*************************************************************** '* Wohnwagen-Kühlschrank-Temperatur-Regelung '* '* Außerdem werden die Temperatur im Kühlschrank, auf der Platine, '* die Außtentemperatur und die Spannung '* an der Batterie angezeigt. '* Die Kühlschrank-Einschalttemperatur sowie die Hysterese lassen sich '* im Betrieb nachregeln. Die Displaybeleuchtung schaltet bei Batterieladung '* (U>13,5 V) ein, läßt sich aber per Taster ausschalten, und schaltet bei '* Batteriebetrieb (U<13 V) aus, läßt sich aber per Taster für 3 Sekunden einschalten. '* Außerdem gibt es einen Watchdog, der einen Neustart macht, wenn die Hauptschleife '* 30 Sekunden nicht durchlaufen wurde. '* Das könnte z.B. der Fall sein, wenn man versehentlich per Tastendruck ins '* Nachregel-Unterprogramm gegangen ist. '* Außerdem gibt es einen Lüfter, der bei Batterie-Ladung eingeschaltet werden kann. '*************************************************************** $regfile = "m168def.dat" 'Atmega 168 $hwstack = 120 $swstack = 50 $framesize = 50 $crystal = 5120000 'Quartzoszillator 'Display-Konfiguration Config Lcdpin = Pin , Db4 = Portc.1 , Db5 = Portc.2 , Db6 = Portc.3 , Db7 = Portc.4 , E = Portc.5 , Rs = Portd.0 Config Lcd = 16 * 2 'Display-Typ Dim Ee_startzaehler As Eram Integer 'Neustarts kontrollieren. Eram ist ein EEprom-Wert, der spannungslos gespeichert bleibt. Dim Startzaehler As Integer Config Portb.7 = Output 'Schaltausgang für Kühlschrank Portb.7 = 0 'default ausgeschaltet Config Watchdog = 16 '= ca. 16 ms Sekunden Timeout ' Timer: Dim Ticks As Word 'Ticks sind die Timer-Überläufe Dim Sekunden As Word Config Timer0 = Timer , Prescale = 1024 'Die Quartzfrequenz zusammen mit dem Prescaler ergeben eine Frequenz von 5kHz On Ovf0 Tim0_isr 'Wenn Timer überläuft, löse den Interrupt "Tim0_isr" aus Enable Timer0 Enable Interrupts Dim Ds18b20_scratchpad_k(9) As Byte 'Kühlschrankfühler Dim Ds18b20_scratchpad_p(9) As Byte 'Platinenfühler Dim Ds18b20_scratchpad_a(9) As Byte 'Außenfühler Dim Kuehlschrank_integer_temp As Integer At Ds18b20_scratchpad_k Overlay 'Kühlschrankfühler - zunächst eingelesener Wert Dim Platine_integer_temp As Integer At Ds18b20_scratchpad_p Overlay 'Platinenfühler - zunächst eingelesener Wert Dim Aussen_integer_temp As Integer At Ds18b20_scratchpad_a Overlay 'Außenfühler - zunächst eingelesener Wert Dim Single_temp_kuehlschrank As Single 'Kühlschrankfühler - Kommazahl zur Multiplikation mit Faktor 0.0625 Dim Single_temp_platine As Single 'Platinenfühler - Kommazahl zur Multiplikation mit Faktor 0.0625 Dim Single_temp_aussen As Single 'Außenfühler - Kommazahl zur Multiplikation mit Faktor 0.0625 Dim I As Byte 'Laufindex für for-Schleife 'Der Einschaltbuffer hat die Aufgabe, das erst geschaltet wird, wenn drei Messungen nacheinander dies ergeben. Dim Einschaltbuffer As Byte 'Zwischenspeicher zur Kontrolle vor dem Schaltvorgang Dim Ausschaltbuffer As Byte 'Zwischenspeicher zur Kontrolle vor dem Schaltvorgang Einschaltbuffer = 0 'erstmal auf 0 setzen Ausschaltbuffer = 0 'erstmal auf 0 setzen Config Portd.7 = Output 'Port für Lüfter Portd.7 = 0 Config Portd.4 = Output 'unbenutzer Pin, sicherheitshalber definieren Portd.4 = 0 'Kühlschrank nachregeln: Dim Ee_int_ein As Eram Integer 'EEprom-Variable für oberen Temperatur-Sollwert - geht nur als Integer Dim Int_ein As Integer 'Zwischenvariable NUR zur Wertübergabe von EEprom nach Single_ein und zurück Dim Single_ein As Single 'oberer (Einschalt-) Sollwert mit dem gearbeitet wird Int_ein = Ee_int_ein 'einlesen aus dem EEprom (beide Integer) Single_ein = Int_ein 'den Integer-Wert dem Single zuweisen 'Mit "Hysterese" ist der Abstand zwischen dem Ein- und dem Ausschaltwert für den Kühlschrank gemeint Dim Ee_hysterese As Eram Integer 'EEProm-Wert Hysterese Dim Hysterese As Integer 'Kühlschrank Hysterese Dim Single_aus As Single 'Kühlschrank Ausschalt-Temperatur Hysterese = Ee_hysterese 'Abstand zwischen Ein- und Ausschalttemperatur Dim Nachreg_toggle As Bit 'Toggle-Wert für Nachregel-Schleife Nachreg_toggle = 1 'Dieser Toggel-Wert hat die Aufgabe, das man damit in das Unterprogramm zum Nachregeln 'und wieder aus diesem heraus springen kann Config Adc = Single , Prescaler = 128 , Reference = Aref 'AD-Wandler einschalten (Spannungsmessung) Dim Wandlerwert As Word 'Variablen für AD-Wandler Dim Zwischenergebnis As Single 'Variablen für AD-Wandler Config Pinb.0 = Input 'Taster rechts (zum nachregeln) Portb.0 = 1 'internen Pullup einschalten Config Portb.2 = Output 'Displaybeleuchtung Pinb.2 = 0 'default: Licht aus Dim Licht As Byte 'Der Datentyp muß Byte sein obwohl Bit reichen würde, weil ? Dim Ladevorgang As Bit 'als Ergebnis der Spannungsmessung wird festgestellt, ob die Batterie gerade geladen wird. Dim Taster_1_toggle As Bit 'Toggel-Variable für Taster 1, um Displaybeleuchtung ein- und auszuschalten Taster_1_toggle = 1 'default: ein Config Pinb.1 = Input '4. Taster von rechts: Toggle-Taster für Licht Portb.1 = 1 'Pullup ein Config Pind.5 = Input 'Taster Nr. 2 Portd.5 = 1 'Pullup ein Config Pind.6 = Input 'Taster Nr. 3 Portd.6 = 1 'Pullup ein 'Unterprogramme, die durch Tastendruck (Taster rechts) ausgelöst werden Declare Sub Nachregeln ' Declare Sub Licht_toggel '******************************************************************** '* '* Programm - Beginn: Startzähler anzeigen um Neustarts überwachen zu können '* '******************************************************************** initlcd 'Display initialisieren, da es beim Start manchmal zu Störungen kommt (nutzlos) Cls 'Display löschen Cursor Off Startzaehler = Ee_startzaehler 'Startzähler-Wert aus EEprom laden Lcd "Startzaehler= " ; Startzaehler 'anzeigen Incr Startzaehler 'um 1 erhöhen Ee_startzaehler = Startzaehler 'neuen Wert ins EEprom schreiben Wait 3 'einen Moment anzeigen Cls 'Display löschen '****************************************************************************** '* '* Hauptschleife '* '****************************************************************************** Do Sekunden = 0 'Timer zurücksetzen '****************************************************************************** '* '* Kühlschrank-Fühler: Einlesen, bis CRC-Code des Kühlschrankfühlers stimmt. '* '****************************************************************************** Do 'Schleife wiederholen, bis CRC des Kühlschrankfühlers stimmt. 'Temperaturmessungen vorbereiten For I = 1 To 3 1wreset Pind , I 'Bus in Grundzustand versetzen 1wwrite &HCC , 1 , Pind , I 'alle angeschlossenen Sensoren ansprechen 1wwrite &H44 , 1 , Pind , I 'Meßvorgang anstoßen next Waitms 1000 'extra langsam zum Beobachten 'Zwischendurch nachsehen, ob jemand eine Taste gedrückt hat 'Kühlschranktemperatur nachregeln: Debounce Pinb.0 , 0 , Nachregeln , Sub 'prüfen ob 1. Tester von rechts gedrückt; wenn ja, in Unterroutine "Nachregeln" springen 'Displaybeleuchtung schalten: Debounce Pinb.1 , 0 , Licht_toggel , Sub 'prüfen, ob linker Taster gedrück; wenn ja, in Unterroutine "Licht_toggel" springen ' warten bis Messung fertig Waitms 1000 'extra langsam zum Beobachten 1wreset Pind , 1 'Bus in Grundzustand versetzen 1wwrite &HCC , 1 , Pind , 1 'alle angeschlossenen Sensoren ansprechen 1wwrite &HBE , 1 , Pind , 1 'auslesen des Scratchpad-Speichers Ds18b20_scratchpad_k(1) = 1wread(9 , Pind , 1 ) '9 Bytes in das Array "Ds18b20_scratchpad_k" ab Adresse "Ds18b20_scratchpad_k(1)" Loop Until Ds18b20_scratchpad_k(9) = Crc8(ds18b20_scratchpad_k(1) , 8) 'Schleife wiederholen, bis CRC des Kühlschrankfühlers stimmt. Single_temp_kuehlschrank = Kuehlschrank_integer_temp * 0.0625 'Faktor für 12-Bit-Auflösung multiplizieren und weiter mit Kommazahl Locate 1 , 2 'An den Anfang des Display gehen (erste Zeile, zweites Zeichen) Lcd "K:" ; Fusing(single_temp_kuehlschrank , "#.#") ; " " 'Ausgabe Kühlschranktemperatur, auf 2 Nachkommastellen gerundet '****************************************************************************** '* '* Kühlschrank regeln '* '* MOSFET abhängig von der Kühlschranktemperatur schalten: '* '****************************************************************************** 'Einschalttemperatur ist die obere Grenze, 'Ausschalttemperatur ist die untere Grenze. 'Es wird nur geschaltet, wenn dies aus drei aufeinanderfolgenden Messungen hervorgeht. ' Prüfen, ob Kühlschrank eingeschaltet werden muß If portb.7=0 then 'wenn Kühlschrank ausgeschaltet ist If Single_temp_kuehlschrank > Single_ein Then 'gemessene Temperatur > Einschalt-Temperatur: also zu warm! Incr Einschaltbuffer 'Einschaltbuffer um 1 hochzählen 'locate 2,1 'Wert des Einschaltbuffers anzeigen 'lcd "Einb:"; Einschaltbuffer Ausschaltbuffer = 0 'locate 2,9 'Wert des Ausschaltbuffers anzeigen 'lcd "AusB:"; Ausschaltbuffer If Einschaltbuffer > 2 Then 'Kühlschrank einschalten und im Display anzeigen Portb.7 = 1 'MOSFET durchschalten Locate 1 , 1 'in die erste Stelle der ersten Zeile des Display Lcd "e" ' "e" für "eingeschaltet" schreiben ' Portb.2 = 1 'Displaybeleuchtung als Kühlschrank EIN 'Einschaltbuffer zurücksetzen und im Display anzeigen Einschaltbuffer = 0 'Einschaltbuffer zurücksetzen ' locate 2,1 'Wert des Einschaltbuffers anzeigen ' lcd "Einb:"; Einschaltbuffer 'Ausschaltbuffer zurücksetzen und im Display anzeigen Ausschaltbuffer = 0 'Ausschaltbuffer zurücksetzen ' locate 2,9 'Wert des Ausschaltbuffers anzeigen ' lcd "AusB:"; Ausschaltbuffer End If end if End If '############### ausschalten ? If portb.7=1 then 'wenn Kühlschrank eingeschaltet ist If Single_temp_kuehlschrank < Single_aus Then 'gemessene Temperatur > Einschalt-Temperatur: also zu warm! Incr Ausschaltbuffer 'Ausschaltbuffer um 1 hochzählen 'locate 2,9 'Wert des Ausschaltbuffers anzeigen 'lcd "AusB:"; Ausschaltbuffer Einschaltbuffer = 3 'Einschaltbuffer zurücksetzen 'locate 2,1 'Wert des Einschaltbuffers anzeigen 'lcd "Einb:"; Einschaltbuffer If Ausschaltbuffer > 2 Then 'Kühlschrank ausschalten und im Display anzeigen Portb.7 = 0 'MOSFET ausschalten Locate 1 , 1 'in die erste Stelle der ersten Zeile des Display Lcd "a" ' "a" für "ausgeschaltet" schreiben 'Portb.2 = 0 'Displaybeleuchtung als Kühlschrank AUS 'Einschaltbuffer zurücksetzen und im Display anzeigen Einschaltbuffer = 0 'Einschaltbuffer zurücksetzen 'locate 2,1 'Wert des Einschaltbuffers anzeigen 'lcd "Einb:"; Einschaltbuffer 'Ausschaltbuffer zurücksetzen und im Display anzeigen Ausschaltbuffer = 0 'Ausschaltbuffer zurücksetzen 'locate 2,9 'Wert des Ausschaltbuffers anzeigen 'lcd "AusB:"; Ausschaltbuffer End If end if end if If Single_temp_kuehlschrank < Single_ein Then 'gemessene Temperatur kleiner als Einschalttemperatur, d.h. kein Grund zum einschalten Einschaltbuffer = 0 'Einschaltbuffer zurücksetzen 'locate 2,1 'Wert des Einschaltbuffers anzeigen 'lcd "Einb:"; Einschaltbuffer End If If Single_temp_kuehlschrank > Single_aus Then 'gemessene Temperatur größer als Ausschalttemperatur, d.h. kein Grund zum ausschalten Ausschaltbuffer = 0 'Ausschaltbuffer zurücksetzen 'locate 2,9 'Wert des Ausschaltbuffers anzeigen 'lcd "AusB:"; Ausschaltbuffer End If ' Ende Kühlschrankregelung '****************************************************************************** 'Kühlschranktemperatur nachregeln: Debounce Pinb.0 , 0 , Nachregeln , Sub 'prüfen ob 1. Tester von rechts gedrückt; wenn ja, in Unterroutine "Nachregeln" springen 'Displaybeleuchtung schalten: Debounce Pinb.1 , 0 , Licht_toggel , Sub 'prüfen, ob linker Taster gedrück; wenn ja, in Unterroutine "Licht_toggel" springen '****************************************************************************** '* '* Platinen-Fühler: Temperatur anzeigen, wenn CRC-Code stimmt. '* '****************************************************************************** 1wreset Pind , 2 ' Platinen-Fühler 1wwrite &HCC , 1 , Pind , 2 ' überspringe ROM-Befehl 1wwrite &HBE , 1 , Pind , 2 ' Temperatur auslesen Ds18b20_scratchpad_p(1) = 1wread(9 , Pind , 2 ) ' Außenfühler: Daten in ein Array lesen If Ds18b20_scratchpad_p(9) = Crc8(ds18b20_scratchpad_p(1) , 8) Then 'CRC-Code prüfen 'Wenn der CRC-Code stimmt, wird die Temperatur berechnet und angezeigt Single_temp_platine = Platine_integer_temp * 0.0625 ' for 12-bit res. Locate 1 , 11 'Außenfühler Lcd "P:" ; Fusing(single_temp_platine , "#.#") ; " " 'Meßwert anzeigen, auf eine Nachkommastelle gerundet End If '****************************************************************************** '* '* Außen-Fühler: Temperatur anzeigen, wenn CRC-Code stimmt. '* '****************************************************************************** 1wreset Pind , 3 ' Außenfühler 1wwrite &HCC , 1 , Pind , 3 ' überspringe ROM-Befehl 1wwrite &HBE , 1 , Pind , 3 ' Temperatur auslesen Ds18b20_scratchpad_a(1) = 1wread(9 , Pind , 3 ) ' Außenfühler: Daten in ein Array lesen If Ds18b20_scratchpad_a(9) = Crc8(ds18b20_scratchpad_a(1) , 8) Then 'CRC-Code prüfen 'Wenn der CRC-Code stimmt, wird die Temperatur berechnet und angezeigt Single_temp_aussen = Aussen_integer_temp * 0.0625 ' for 12-bit res. Locate 2 , 1 'Außenfühler in zweite Zeile, erste Stelle Lcd "A:" ; Fusing(single_temp_aussen , "#.#") ; " " 'Meßwert anzeigen, auf eine Nachkommastelle gerundet End If '****************************************************************************** '* '* Batteriespannung messen '* Display und Lüfter danach schalten '* '****************************************************************************** Zwischenergebnis = 0 'Variable zurücksetzen For I = 1 To 20 'Zählschleife, um 20 Ergebnisse zu mitteln Wandlerwert = Getadc(0) 'Meßwert abfragen von AD-Wandler 0 Zwischenergebnis = Zwischenergebnis + Wandlerwert 'aufsummieren Next 'Zählschleife zuende Zwischenergebnis = Zwischenergebnis * 0.78513 'berechnen. Der Faktor ist ein Abgleichwert. Zwischenergebnis = Zwischenergebnis / 1000 Locate 2 , 9 'in Zeile 2, Stelle 9 des Display gehen Lcd "U:" ; Fusing(zwischenergebnis , "#.##") ; "V" 'Spannung runden und ausgeben If Zwischenergebnis > 13.5 Then 'feststellen, ob Batterie geladen wird Ladevorgang = 1 'Flag für Ladevorgang setzen If Ladevorgang = 1 Then Portd.7 = 1 'Lüfter einschalten End If End If If Zwischenergebnis < 13 Then 'Batteriebetrieb, d.h. Batterie wird nicht geladen Ladevorgang = 0 If Ladevorgang = 0 Then 'Lüfter ausschalten Portd.7 = 0 End If End If If Ladevorgang = 0 Then 'Bei Umschalten auf Batteriebetrieb soll die Displaybeleuchtung wieder auf default Taster_1_toggle = 1 'zurückschalten, d.h. sobald Ladung erfolgt leuchten. End If Licht = Ladevorgang * Taster_1_toggle 'Licht einschalten, sofern nicht ausgetoggelt Portb.2 = Licht 'Displaybeleuchtung schalten Reset Watchdog Loop End '____________________________________________________________ Ende Hauptschleife '************************************************************** '* '* Kühlschrank Einschalt-Temperatur nachregeln ! '* '************************************************************** Nachregeln: 'Unterroutine "Nachregeln" Cls 'Display löschen Nachreg_toggle = 1 'Variable zum Ausstieg aus dieser Nachregel-Schleife Wait 1 'Verzögung, um nicht sofort wieder hier rauszuspringen Locate 1 , 1 'in Zeile 1 des LCD Lcd "K ein jetzt:" ; Int_ein ; " C" ; " " 'bisherigen Sollwert anzeigen While Nachreg_toggle = 1 'Nachregel-Schleife mit Ausstiegsmöglichkeit If Pind.5 = 0 Then 'wenn Plus-Taste gedrückt ist Do Loop Until Pind.5 = 1 'Warten bis Taster losgelassen Incr Int_ein 'Solltemperatur erhöhen End If If Pind.6 = 0 Then 'wenn Minus-Taste gedrückt ist Do Loop Until Pind.6 = 1 'Warten bis Taster losgelassen Decr Int_ein 'Solltemperatur reduzieren End If Locate 2 , 1 'in Zeile 2 des LCD Lcd "K ein neu:" ; Int_ein ; " C" ; " " 'neuen Wert anzeigen 'Ausstieg aus dieser Nachregelschleife: If Pinb.0 = 0 Then 'Wenn rechter Taster gedrückt wird Do Loop Until Pinb.0 = 1 'Warten bis Taster losgelassen Toggle Nachreg_toggle 'wenn toggle-Wert verändert wird Schleife verlassen If Ee_int_ein <> Int_ein Then 'wenn der Wert verändert wurde ... Ee_int_ein = Int_ein '... den neuen Wert ins EEprom schreiben Single_ein = Int_ein End If Locate 2 , 1 Lcd "EEprom gesp." ; Int_ein ; " " 'Rückmeldung in der 2. Zeile Single_aus = Int_ein - Hysterese 'Berechnung der Ausschalttemperatur Wait 1 'stattdessen den echten EEprom-Wert anzuzeigen akzeptiert Bascom nicht End If Wend '************************************************************ '* '* Hysterese nachregeln ! '* '************************************************************ Cls Nachreg_toggle = 1 'Variable zum Ausstieg aus dieser Nachregel-Schleife Wait 1 'Verzögung, um nicht sofort wieder hier rauszuspringen Locate 1 , 1 Lcd "Hyst jetzt: " ; Hysterese ; " " 'bisherigen Sollwert anzeigen While Nachreg_toggle = 1 'Nachregel-Schleife mit Ausstiegsmöglichkeit If Pind.5 = 0 Then 'Temperatur-Schaltpunkt erhöhen: Do Loop Until Pind.5 = 1 'Warten bis Taster losgelassen Incr Hysterese 'Solltemperatur erhöhen End If If Pind.6 = 0 Then 'Temperatur-Schaltpunkt reduzieren: Do Loop Until Pind.6 = 1 'Warten bis Taster losgelassen Decr Hysterese 'Solltemperatur reduzieren End If Locate 2 , 1 Lcd "Hyst neu: " ; Hysterese ; " " 'neuen Wert anzeigen If Pinb.0 = 0 Then 'Ausstieg aus dieser Nachregelschleife: Do Loop Until Pinb.0 = 1 'Warten bis Taster losgelassen Toggle Nachreg_toggle 'wenn toggle-Wert verändert wird Schleife verlassen If Ee_hysterese <> Hysterese Then 'wenn der Wert verändert wurde ... Ee_hysterese = Hysterese 'zum Schluß den neuen Wert ins EEprom schreiben End If Locate 2 , 1 Lcd "EEprom gesp.:" ; Hysterese ; " " 'Rückmeldung in der 2. Zeile Single_aus = Int_ein - Hysterese 'Berechnung der Ausschalttemperatur Wait 1 'stattdessen den echten EEprom-Wert anzuzeigen akzeptiert Bascom nicht End If Wend 'Ende der while-Schleife - zurück zum Normalbetrieb Cls Return '************************************************************ '* '* Displaybeleuchtung schalten ! '* '************************************************************ Licht_toggel: 'Bei Batteriebetrieb gibt es Licht immer nur für 3 Sekunden If Ladevorgang = 0 Then Licht = 1 Portb.2 = Licht Wait 3 Licht = 0 End If If Ladevorgang = 1 Then Toggle Taster_1_toggle 'Bei Ladebetrieb läßt sich das Licht aus- und einschalten Licht = Ladevorgang * Taster_1_toggle 'Licht einschalten, sofern nicht ausgetoggelt Portb.2 = Licht 'Displaybeleuchtung schalten End If Return '************************************************************ '* '* Timer / Watchdog '* '************************************************************ Tim0_isr: 'Der Interrupt: Timer0 = 6 'Der Timer hat 8 Bit (256). Mit dem Startwert von 6 zählt er bis 250. 'Bei einer Eingangsfrequenz von 5 KHz (=Quarzfrequenz/10 Bit Prescaler = 5120000/1024=5000 Hz) 'ergibt sich damit eine Überlauffrequenz von 20 Hz (=5000/250). Ticks = Ticks + 1 'Ticks sind Timer-Überläufe If Ticks = 20 Then '20 Ticks sind eine Sekunde Ticks = 0 'Ticks zurücksetzen Sekunden = Sekunden + 1 'Sekunden hochzählen If Sekunden = 30 Then 'nach 30 Sekunden ... Sekunden = 0 'Sekunden auf Null zurücksetzen ... Start Watchdog 'Wenn der Watchdog aufgerufen wird soll er auch auslösen Waitms 20 ' End If End If Return