erstellt  30.05.2014
Temperatur geregelter  12 Volt Lüfter
Durch den Kauf eines neuen Netzteil mit einen internen Lüfter der aber in keiner Weise irgendwie geregelt war und so ständig auf Hochtouren lief und mir meinen Nerv klaute, sah ich mich mehr oder weniger gezwungen einen geregelten Lüfter einzubauen .
Nun gab es natürlich die Möglichkeit eine fertige Steuerung zu kaufen , aber wie meistens in solchen Fällen werden die Erwartungen nicht  so ganz zufrieden gestellt, also beschloss ich selber eine Regelung zu erstellen.
Nun gibt es mehrere Möglichkeiten einen Lüfter Temperaturabhängig zu regeln, und alle haben den ein oder anderen Vor-oder Nachteil.
Also beschloss ich mit dem Mikroprozessor "Atmega 8 " diese Aufgabe zu bewältigen, so das ich die Möglichkeit habe auch andere im Moment nicht vorgesehenen Lüfter später eventuell einmal anzuschließen und dann hoffentlich nur die Software ändern muss.
Die Regelung soll als Pulsweitenregelung ( PWR) entwickelt werden , die Sollwerte für die Hysterese also dann wann der Lüfter bei minimaler Temperatur anfangen soll zu regeln , bis zu dem  Punkt  wo er seine maximale Drehzahl abgibt sollen über einen Drehgeber eingegeben werden .
Die  Temperaturerfassung geschieht mit einem IC2 Temperatur Fühler DS 1820.
Der Temperaturfühler arbeitet mit einer Genauigkeit von maximal 0,5°C, das reicht für eine Lüfterregelung allemal aus.
Unten sieht man eine Standard Schaltung mit dem Atmega 8 und ein 2X16 Zeichen Display sowie Programmierschnittstelle .


Um die Solltemperatur einzugeben und zwar einmal die Minimale und einmal die Maximale entschied ich mich für einen Drehgeber,
der außer der Drehfunktion auch noch eine tastende Eigenschaft beinhaltet indem man die Achse hereindrückt.
Ein Drehgeber ist nichts anderes als zwei um einen gewissen Winkelgrad versetzte Taster die durch die Rotation einer  Achse abwechselnd betätigt werden.
Wenn der Mikroprozessor jetzt feststellt welcher der beiden Taster zuerst betätigt wird, weiß er auch in welcher Richtung gedreht wird,
und hat somit die Möglichkeit die Tastimpulse zu zählen und auszuwerten.

Hier die Schaltung mit angeschlossenen Drehgeber



Der Drehgeber ist angeschlossen an PIN 4 (Interrupt 0) und Pin 5 (Interrupt 1) zusätzlich hat der Drehgeber
noch eine
tastende Funktion ( S2) wenn man die Achse reindrückt.
Abfrage des Drehgeber über IO Pin
Die Eingabe des Drehgebers über die normale Abfrage der Eingangspins gestaltet sich nicht so einfach, wenn der Prozessor nur mit seinen Standardtakt
arbeitet also seinen internen 1 MHz .
Dann benötigt er für eine Programmschleife wenn dort nur eine Led  angeschaltet  und beim nächsten Schleifendurchlauf wieder ausgeschaltet werden soll
in etwa 6us (Mikrosekunden),  wenn in dieser Schleife noch ein Unterroutine aufgerufen werden soll, welches das Display aktualisiert so benötigt die
Programmschleife  schon  5 ms (Millisekunden) vorausgesetzt das Display arbeitet im 4 Bit Modus.
Sollte jetzt das Display bei jedem Aufruf auch noch gelöscht werden so benötigt eine Programmschleife schon 12ms ( Millisekunden).
Hinzu kommt jetzt noch der benötigte Programm Code somit eine Schleife deutlich länger als 12 ms dauert.
Die Kontakte des Drehgeber schließen in Abhängigkeit der Drehgeschwindigkeit in etwa für 5ms bis ca. 120ms.
Es wird so also im ungünstigen Fall der Kontakt des Drehgebers geschlossen und auch wieder geöffnet sein bevor die Programmschleife zeitlich die Möglichkeit der Abfrage hat.
Es besteht jetzt die Möglichkeit das Display im 8 Bit Modus anzuschließen um so die Geschwindigkeitsverluste der Programmierschleife geringer zu halten ,
oder man benutzt eine höhere Taktfrequenz.
Beides kommt hier aber nicht zum tragen , weil das Display neu verlötet werden müsste, und die Frequenz erhöhen ginge zwar ist aber wegen Platzmangel auf der Platine schlecht auszuführen.
Also versuche ich den Drehgeber über Interrupts abzufragen.
Was ist nun ein Interrupt?
Ein Interrupt ist eine kleine Unterbrechung, es wird damit das Hauptprogramm unterbrochen damit eine andere Funktion ausgeübt werden kann.
Beim eintreten eines externen Interrupts beim Atmega 8, nur an zwei festgelegten Pins möglich ,wird das laufende Programm angehalten
und im Hardware Stack ( festgelegter Interner Speicher ) die Information abgelegt an welcher Stelle das laufende Programm unterbrochen wurde.
Dann wird in die sogenannte ISR ( Interrupt Service Routine ) gesprungen quasi ein kleines Unterprogramm und dieses abgearbeitet.
Danach wird das eigentliche Programm wieder an der zuvor im Stack Speicher gesicherten Adresse fortgesetzt.
Während diese Routine abläuft werden alle anderen Interrupts deaktiviert bis die Routine beendet ist.
Dadurch gehen aber evtl. auftretende Ereignisse am gleichen sowie an anderen Interrupt Eingängen nicht verloren sondern sie werden in einem sogenannten
Flag zwischen gespeichert,allerdings kann jeweils nur ein Ereignis pro Interrupt Eingang zwischen gepuffert werden .
Sollten mehrere auftreten ,können so einige verloren gehen deswegen sollte man diese Routine so klein wie möglich halten, damit im Bedarfsfall auch kein Interrupt vernachlässigt wird.
Konfiguration des Interrupts
Unter Bascom gibt es mehrer Möglichkeiten die Konfiguration bzw. das Verhalten der Interrupteingänge festzulegen.
Ich beschränke mich hier auf die Anweisungen die direkt im Register gemacht werden , es ist vielleicht nicht immer die komfortabelste  Möglichkeit
hat aber den Vorteil das diese Registeranweisungen alle im Atmel Datenblatt beschrieben sind und somit  auch alle der Einstellmöglichkeiten bietet.
Die dafür zuständigen Register sind folgende:

MCUCR Register
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0






ISC11 oder ISC01 ISC10 oder ISC00






0 0 Interrupt 0 solange L Pegel anliegt






0 1 Interrupt 0 wird ausgelöst bei wechsel von H nach L oder L nach H






1 0
Interrupt 0 bei wechsel von H nach L






1 1 Interrupt 0 bei wechsel von L nach H




0 0

Interrupt 1 solange L Pegel anliegt




0 1

Interrupt 1 wird ausgelöst bei wechsel von H nach L oder L nach H




1 0

Interrupt 1 bei wechsel von H nach L




1 1

Interrupt 1 bei wechsel von L nach H
Im MCUCR Register wird festgelegt welcher Eingang bzw welcher Interrupt also 1 oder 0 benutzt werden soll, und auf welches Ereignis er reagieren soll, Als Pegel von Plus nach Minus oder Minus nach Plus usw.

GICR Register






ISC11 oder ISC01 ISC10 oder ISC00
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0









1






Interrupt 1 freigeben

1





Interrupt 0 freigeben
Eine 1 im Bit 6 wäre notwendig um den Interrupt 0 zu aktivieren dementsprechend eine  0 um ihn  zu deaktivieren.

SREG Register









Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
1






Freigab der Interrupts Global
Mit Bit 7  werden alle Interrupts generell gesperrt oder frei gegeben.

GIFR Register
INTF1 INTF0






Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
INTF1 INTF0







1






Bit 6 (INTF0) wird auf 1 gesetzt wenn ein Ereignis am Interrupt 0 Eingang statt gefunden hat und erst dann wieder auf Null gesetzt wenn die Interrupt Routine beendet wurde.
Bei der Erfassung der Impulse mittels Interrupt würden  aber auch das Kontaktprellen  des Taster mitgezählt was hier natürlich nicht erwünscht ist.
Nun geht es also erst einmal darum diese mehrfach Zählung zu unterdrücken.
Wie kommt nun eine Mehrfachzählung zustande ?
Bei einem Interruptvorgang an Pin 4  also INT0 wird in die (ISR) Interrupt Sub Routine gesprungen und dort eine Led eingeschaltet die sich nach 10 Millisekunden
wieder ausschaltet.
Sollte innerhalb dieser Sekunde ein weiterer Interrupt ausgelöst werden, geht dieser nicht etwa verloren , sondern wird zwischengespeichert,
und erst wenn die laufende Interrupt Sub Routine Routine beendet ist, wird ein weiteres mal diese Routine aufgerufen.
Damit ist sichergestellt das auf keinen Fall ein Interrupt Ereignis verloren geht.
Das hat natürlich auch den Nachteil das wenn ein Taster prellt, also kurz mehrfache Impulse abgibt, diese auch alle gezählt werden,
abhängig davon wie schnell man den Drehgeber dreht, oder auch wie seine Mechanische Beschaffenheit ist.
Beispiel
Interrupt soll ausgelöst werden bei  einen Wechsel  von H nach L
MCUCR = &B00000010
zusätzlich muss bei der Benutzung von Interrupts diese Freigegeben also aktiviert werden, dies geschieht im Register  "GICR" .Folgende Register Anweisung schaltet den Interrupt 0 frei
GICR=B&01000000
desweiteren muss der Interrupt noch Global freigegeben werden, also eine generelle Freigabe von Interrupts überhaupt.Das passiert im Register SREG
SREG=B&10000000

Wichtig
Interrupt Routinen sollen generell so kurz wie möglich gehalten werden , und sollten auf jeden Fall kürzer sein als die Zeit der anfallenden zu erfassenden Impulse. Andernfalls kann es passieren das Interrupts einfach verloren gehen was natürlich je nach Funktion der Routine fatale Folgen haben könnte.
Ein aktivierte Interrupt Routine schaltet solange alle anderen Interrupts ab. Jeweils ein Ereignis pro Interrupteingang wird aber zwischengespeichert in einen sogenannte Flag und steht somit anschließend noch zu Verfügung. Diese Flag steht im Register GIFR.
Wenn also ein Ereignis an INT0 eintritt wird als erstes das BIT 6 ( INTF0 ) im GIFR Register auf 1 gesetzt ,aber nur wenn auch das Bit7 im Sregister also die Globale Interrupt Freigabe und das Bit 6 im GICR Register die Freigabe für Interrupt 0 auf eins gesetzt sind.
Temperaturerfassung
Um die Temperatur zu erfassen benutze ich den IC2 Temperatursensor der Firma Dallas von Typ DS1820.
Zum auswerten diese Sensor genügt ein Digitaler Eingang des Mikroprozessors.
Der Sensor hat einmal die Betriebsspannung von 5 Volt , Masse an Pin1 und +5V an Pin 3, und den Digitalen Ausgang an Pin 2.
Der Mikroprozessor Eingang für die Temperaturerfassung kann individuell ausgewählt werden , hier der Pin 14 (Pin B0).
Der Sensor gibt in Abhängigkeit der aktuell erfassten Temperatur ein Digitales Signal ab.
Datenblatt : DS1820
Mit einer Auflösung von 9 Bit das 0,5 ° C Schritte zulässt.
Wichtig ist beim Anschluss das ein 4,7 K Widerstand nach Plus notwendig ist.
Der DS 1820 ist ein sogenannter 1Wire Device, was soviel heißt das er in der Regel 3 Anschlüsse besitzt .
1. Plus
2. Masse
3. Datenleitung
, es gibt aber auch Typen die nur zwei Anschlüsse aufweisen nämlich
1. Masse
2. Datenleitung
bei diesen Typen holt sich der Sensor ( I-Button , oder 1Wire Device) seine Positive Betriebsspannung über die Datenleitung,
die weil sie über einen Widerstand zu Positiven Spannungsversorgung verfügt den im  Sensor enthaltenen Kondensator in den Datenpausen mit Spannung auflädt.
(Siehe Sinnbild unten.)



Als erstes sag ich dem Atmega an welchen Eingang sich der Temperaturfühler befindet, dazu dient folgender Befehl in Bascom:


Config 1Wire=Portc.5
damit wird dieser Pin als I2C Schnittstelle konfiguriert.
Mögliche Probleme:
Problem
Mögliche Ursache
Im Display werden immer nur Null Grad angezeigt
  • Möglicherweise fehlt der 4,7 Kilo Widerstand, oder er ist nicht richtig angeschlossen , evtl Plus und Minus vertauscht
Piepsen wenn Lüfter langsam dreht
  • Es handelt sich um Oberwellen durch die Pulsweitenmodulation, kann evtl verhindert werden, indem die Frequenz so hoch gesetzt wird , das die Geräusche durch das Menschliche Hörvermögen nicht mehr wahr genommen werden kann, also ca. > 16 Khz
  • Parallel zum Lüfter einen Elko setzen, die Größe kann am besten ausprobiert werden.
Temperaturanzeige springt
  • Wenn die Temperaturanzeige spinnt, also schnell auf Unrealistische Werte springt, dann kann es am unsauberen Signal ( siehe Signal  an Pin 2  Temperatursensor liegen. Abhilfe schafft meist ein ca. 100 Nf Kondensator, möglichst nahe an die Versorgungsspannung des Sensors anzuschließen.








Programmcode in Blau
Beschreibung
$regfile "m8def.dat"
Definiert den Atmega als Atmega8
$crystal = 1000000 Gibt die Quarzfrequenz an in Herz
$hwstack = 64 
Default use 32 Hardware reservierte Speicher
$swstack = 50
Default Software resvierung Speicher

Config Lcd = 16 * 2 Display Größe definieren
Config Lcdpin = Pin , Db4 = Portb.5 , Db5 = Portb.4 , Db6 = Portb.3 , _
 Db7 = Portb.2 , Rs = Portd.1 , E = Portd.0
Display Anschlüsse definieren

Config 1wire = Portc.5 
Schnitstelle Festlegen Für Temp Sensor
Dim Ds1820 As Integer 
Integer Variabel für Ds1820 setzen kann Daten - 32768 bis+32768 aufnehmen
Dim T_wert As Byte
Textzeichen erstellen
Deflcdchar 1 , 14 , 17 , 17 , 14 , 32 , 32 , 32 , 32    
Zeichen für Grad °°
Cls
I/O
Ddrd.5 = 1 
Als Ausgang setzen   Led Blau
Ddrd.6 = 1 Als Ausgang setzen   Led Rot
Ddrd.2 = 0 Als Eingang setzen Interrupt 0
Ddrd.3 = 0 Als Eingang setzen Interrupt 1
Ddrd.4 = 0  
Als Eingang setzen Drehgeber Taster
Ddrc.3 = 1
Als Ausgang setzen für Summer
Portd.2 = 1 PullUp setzen für Portd.2
Portd.3 = 1
PullUp setzen für Portd.3
Portd.4 = 1 Pull Up setzen für Taster am drehgeber
Config Portb.1 = Output
Variable
Dim Drehwert As Byte
Dim Temp_min As Byte Speicher für Sollwert der minimale Temperatur
Dim Temp_min_eprom As Eram Byte Epromspeicher für Sollwert min Temperatur
Dim Temp_max As Byte
Dim Temp_max_eprom As Eram Byte
Dim A As Byte  
Für Störungsanzeige schleife für Led Blinker
Dim Temperatur_differenz As Word
Dim Bit_grad As Byte
Dim B As Byte für schrittweite beim erhöhenn und verringen des tastverhältnis
Dim Aus As Byte
Dim Stufe As Byte
Dim Sektor As Byte
Dim Temperatur As Byte
Dim C As Byte
Dim Tastverhaeltnis As Byte
Timer 1 Konfiguration
Tccr1a = &B10000001
Tccr1b = &B00000001   voller Takt wird genutzt

On Int0 Kanal0
On Int1 Kanal1
Mcucr = &B00001010      
beide Interrupt 's  reagieren auf Wechsel von H nach L
Gicr = &B11000000      
INT1 +  INT0 freigeben
Sreg = &B10000000       
Global Interrupt freigeben

Temp_min = Temp_min_eprom holt die gespeicherten sollwert vorgabe aus dem Eprom und kopiert
' sie in ramspeiche
Waitms 20
Temp_max = Temp_max_eprom
Waitms 20

Cls
Locate 1 , 1
Lcd "Drehgeber"
Locate 2 , 1
Lcd "Version 1N"
Wait 3
Cls
 Vorgabewerte

Temperatur = 10

If Pind.4 = 0 Then Gosub Sollwert Else Goto Hauptprogramm Wenn Taster beim einschalten gedrückt dann ins Menü wechseln
wenn Taster nicht gedrückt dann ins Hauptprogramm springen
H a u p  t p r o g r a m m
Deflcdchar ?,14,17,17,14,32,32,32,32' replace ? with number (0-7)

Lcd "Fan Speed"
Portd.5 = 1 Ventilator mit Voller Drehzahl anlaufen lassen im Startmoment
Tastverhaeltnis = 250
Compare1a = Tastverhaeltnis
Wait 2
Portd.5 = 0
Do
Compare1a = Tastverhaeltnis
Waitms 10
Temperatur = Ds1820
Toggle Portd.6
Cls
Locate 1 , 1
Lcd Temp_min
Locate 1 , 5
Lcd Chr(1)
Locate 1 , 11
Lcd Temp_max
Locate 1 , 16
Lcd Chr(1)
Locate 2 , 1
Lcd "Temp.=" ; Ds1820 ; Chr(1)
Locate 2 , 11
Lcd "Tv=" ; Tastverhaeltnis
Temperatur Sensor abfragen
1wreset Der Bus wird resetiert
1wwrite &HCC 
Übersprimge Rom weil nur ein sensor angeschlossen
1wwrite &H44
Starte Temperaturmessung
Waitms 600  
Pause von 600 Millisekunden ' wenn pause zu kurz gibts falsche Temperaturwerte aber nur beim einschalten
  z.B 85°
1wreset    
Reset DS1820
1wwrite &HCC Überspringe Rom
1wwrite &HBE 
sende inhalt der register AAH und 00h
Waitms 10
Ds1820 = 1wread(1)  
lese die empfangenen Daten
Waitms 10
1wreset 
Reset Ds1820
Shift Ds1820 , Right
entferne letztes bit
Ende Temp Sensor Abfrage
Temperatur_differenz = Temperatur - Temp_min

If Temperatur_differenz < 1 Then Tastverhaeltnis = 1

If Temperatur_differenz > 0 Then Tastverhaeltnis = 2
If Temperatur_differenz > 1 Then Tastverhaeltnis = 4
If Temperatur_differenz > 2 Then Tastverhaeltnis = 5
If Temperatur_differenz > 3 Then Tastverhaeltnis = 10

If Temperatur_differenz > 4 Then Tastverhaeltnis = 20


If Temperatur_differenz > 5 Then Tastverhaeltnis = 50


If Temperatur_differenz > 6 Then Tastverhaeltnis = 240

If Temperatur_differenz > 100 Then Tastverhaeltnis = 1        negativer wert
 If Tastverhaeltnis > 253 Then Tastverhaeltnis = 254
If Tastverhaeltnis < 2 Then Tastverhaeltnis = 1
If Ds1820 > Temp_max And Tastverhaeltnis > 230 Then Gosub Stoerung
Loop
Return
Störungsanzeige bei Übertemperatur ausgeben
Stoerung:
For A = 1 To 3 Blaue Led soll aufblitzen und Meldung auf Display ausgeben + summer
Portc.3 = 1
Summer an
Waitms 500 Led Blau an
  Portd.5 = 1  
Pause
Waitms 20  

Portd.5 = 0 

Portc.3 = 0
Summer aus' Led Blau aus
Waitms 100
Next A
Cls   
Display löschen
Locate 1 , 1
Lcd " Uebertemperatur"
Locate 2 , 1
Lcd " ! ! ! ! ! ! ! ! "
Waitms 999
Return
Interrupt 0
Kanal0:
If Pind.2 = 0 And Pind.3 = 1 Then Drehwert = Drehwert -1

Portd.6 = 1 
 Led grün an
Waitms 20
Portd.6 = 0
Return
Interrupt 1
Kanal1: für rechtsdrehung
If Pind.3 = 0 And Pind.2 = 1 Then Drehwert = Drehwert + 1
Portb.0 = 1 Led Orange an
Waitms 20
Portb.0 = 0
Return
Sollwerte eingeben 
Sollwert:
Cls
Locate 1 , 1
Lcd "Sollwerte eingeben"
Wait 2
Do
Cls
Temp_min = Drehwert    
Wert vom Drehgeber in Variable
Temp_unten kopieren
Locate 1 , 1
Lcd "unter Temp."
Locate 2 , 1
Lcd Drehwert ; Chr(1)
Waitms 30
If Pind.4 = 0 Then Waitms 5
If Pind.4 = 0 Then Exit Do     
Schleife verlassen bei Tastendruck
Loop
Daten sichern

Temp_min_eprom = Drehwert    
 kopiert min. Temperatur  vorgabe im
eprom
Waitms 20
Portb.0 = 1
Waitms 200
Portb.0 = 0
Sollwert Temperatur maximum
Cls
Locate 1 , 1
Lcd "Sollwerte eingeben"
Wait 2
Do
Cls
Temp_max = Drehwert
Locate 1 , 1
Lcd "obere Temp."
Locate 2 , 1
 Lcd Drehwert ; Chr(1)
Waitms 30
If Pind.4 = 0 Then Waitms 5
If Pind.4 = 0 Then Exit Do
Loop
Daten sichern
Temp_max_eprom = Drehwert     
kopiert temp.max vorgabe im
eprom
Waitms 20
Portb.0 = 1
Waitms 200
Portb.0 = 0
E N D E

Und so sieht die Schaltung aus


Bascom Datei Download hier

Aktualisiert 11.10.2020

Copyright by Manfred Schrod 2009