Hallo zusammen, wie der Titel schon aussagt, entwerfe ich gerade eine Temperaturgesteuerte Lüfterregelung für den PC. Und ja, ich weiß solche Steuerungen gibt es fertig zu kaufen, aber es geht um die Lust am selbermachen :-) Nun zum Punkt: Ich will mir durch die PWM möglichst keine Störungen auf dem Mikrocontroller einfangen, bzw. auch keine Störungen an das PC-Netzteil abgeben, und nun wäre die Frage, wie ich das ganze Bauteilmäßig dimensionieren sollte. Sinn der ganzen späteren Platine soll sein, dass der Lüfter bis zu einer gewissen Gehäusetemperatur, meinetwegen 25 oder 30 Grad, auf einem voreingestelltem Wert dahinsäuselt, und dann der PWM duty cycle mit steigender Temperatur bis 100 % erhöht wird. Ich habe in mühevoller Kleinarbeit das ganze mal auf dem Steckbrett aufgebaut, aber da zeigt sich, dass sich zwar der Trimmer ohne Fehler auslesen lässt, der für die Grunddrehzahl des Lüfters verantwortlich ist, aber der Onboard-Temperatursensor (Philips KTY81-210) macht da anscheinend etwas Probleme, offensichtlich fängt sich der ADC-Eingang, an dem der Temperatursensor hängt, viele PWM-Störungen ein. Warum auch immer. Wenn ich den Lüfter mit dem Finger anhalte, sind die Störungen immer noch da. Störungen heißt: Bei Raumtemperatur sollte der ADC-Wert um die 510 liegen, wenn ich aber zur Kontrolle den ADCW-Wert auf einem freien Portpin ausgebe und nachzähle, liegt der Wert bei einigen Tausend. Der Temp-Sensor lässt sich nur dann vernünftig auslesen, wenn ich den PWM-Ausgang (OC0A) komplett abschalte, und der Lüfter nicht läuft. Am Testpin habe ich dann zwischen 500 und 520 Impulse, je nach dem ob ich den Finger auf den Sensor lege, oder nicht... Die Schaltung an sich scheint also schonmal zu klappen. Sobald der Lüfter dann eingeschaltet ist, kommt nur Rotz und Müll am ADC vom Temperatursensor an. Aber: Ist jedoch der PWM-Ausgang auf 100 %, und laut Oszi keine "PWM" sondern ein durchgehendes Signal erkennbar, lässt sich der Onboardsensor wieder ohne Probleme auslesen und die Störungen am ADC Eingang sind weg. Aber es betrifft eben nur den Temp-Sensor-ADC-Pin, nicht den Trimmer-ADC-Pin, nur warum...? Nun die Frage aller Fragen: Verschwinden diese Probleme dann mal später auf der fertigen Platine, oder gibt's da ein grundlegendes Problem? Die Leitungen sind eh schon sehr kurz. Wo soll ich mit suchen/verbessern anfangen? Anbei mal zwei Fotos vom Schaltplan und vom Board-Entwurf. Danke, Christian
Hast du schon mal probiert dem ADC eine Stützkapazität zu geben? sagen wir mal ein paar hundert nF ? Mit welcher Frequenz läuft deine PWM?
Christian W. schrieb: > und dann der PWM duty cycle mit steigender Temperatur bis > 100 % erhöht wird verschaltet hast du es so, dass die am ADC gemessene Spannung sinkt, wenn die Temperatur steigt. ist das gewollt?
Mir scheint es so, daß einige Lötpads sehr klein sind.
Henny schrieb: > Hast du schon mal probiert dem ADC eine Stützkapazität zu geben? sagen > wir mal ein paar hundert nF ? Ja, habe ich eben mit verschiedenen Werten getestet, leider keine Veränderung Henny schrieb: > Mit welcher Frequenz läuft deine PWM? Der Timer läuft mit einem Prescaler von 2, das wären dann 15625 Hz. Henny schrieb: > verschaltet hast du es so, dass die am ADC gemessene Spannung sinkt, > wenn die Temperatur steigt. ist das gewollt? Nein eigentlich nicht gewollt, aber das lässt sich ja Softwareseitig einfach auswerten. Thomas der Bastler schrieb: > Mir scheint es so, daß einige Lötpads sehr klein sind. Bei den Widerständen usw. meinst du? Bisher hat das Löten mit kleiner Lötspitze immer gut geklappt. Grüße, Christian
Hallo, R2 ist zu klein, mach da mal >200 Ohm rein
Was passiert, wenn du den KTY mal durch einen 2kOhm Widerstand ersetzt? Wie sieht die Software zum Einstellen des ADC's aus?
> wenn ich aber zur Kontrolle den ADCW-Wert auf einem freien Portpin ausgebe und
nachzähle, liegt der Wert bei einigen Tausend.
Bei einigen Tausend?
Das kann nicht sein.
Da hast du einen Programmfehler.
Der Wert kann nicht größer als 1023 werden.
Ich habe den Gatewiderstand mal von 10 Ohm auf 220 Ohm vergrößert, und siehe da, die Störungen sind schon deutlich geringer, und der KTY-Sensor lässt sich, zumindest jetzt schon jedes 2. Mal, fehlerfrei auslesen. Ich probier gleich noch mal einen 470er. Hier mal der Entwurf vom kompletten Programm.
1 | // Definitionen
|
2 | // ------------
|
3 | #define FAN_PORT PORTB
|
4 | #define FAN_PIN PB2
|
5 | #define F_CPU 8000000UL
|
6 | |
7 | |
8 | #include <avr/io.h> |
9 | #include <util/delay.h> |
10 | |
11 | |
12 | // ADC initialisieren
|
13 | // ------------------
|
14 | void Init_ADC(void) |
15 | {
|
16 | // ADC Prescaler 2
|
17 | ADCSRA |= (1<<ADPS0); |
18 | |
19 | // ADC einschalten
|
20 | ADCSRA |= (1<<ADEN); |
21 | |
22 | // Erste Konvertierung starten
|
23 | ADCSRA |= (1<<ADSC); |
24 | |
25 | // Warten, bis Konvertierung beendet
|
26 | while(ADCSRA & (1<<ADSC)) |
27 | {
|
28 | // ...
|
29 | }
|
30 | }
|
31 | |
32 | |
33 | // PWM-Ausgang PB2 initialisieren
|
34 | // ------------------------------
|
35 | void Init_PWM(void) |
36 | {
|
37 | // OC0A bei Compare Match aus
|
38 | TCCR0A |= (1<<COM0A1); |
39 | |
40 | // Waveform Generation Mode 7, Fast PWM
|
41 | TCCR0A |= (1<<WGM00); |
42 | TCCR0A |= (1<<WGM01); |
43 | TCCR0A |= (1<<WGM02); |
44 | |
45 | OCR0A = 0; |
46 | TCNT0 = 0; |
47 | }
|
48 | |
49 | |
50 | // PWM on/off
|
51 | // ----------
|
52 | void Status_PWM(unsigned char status) |
53 | {
|
54 | // Timer/Counter 0 Prescaler, einschalten/ausschalten
|
55 | if (status) TCCR0B |= (1<<CS00); |
56 | if (!status) TCCR0B &=~(1<<CS00); |
57 | }
|
58 | |
59 | |
60 | // Lüfter initialisieren
|
61 | // ---------------------
|
62 | void Init_FAN(void) |
63 | {
|
64 | // Kurzzeitig auf Vollgas als Anlaufhilfe und Staubbeseitigung
|
65 | FAN_PORT |= (1<<FAN_PIN); |
66 | for (uint16_t pause=0; pause<5000; pause++) _delay_ms(1); |
67 | FAN_PORT &=~(1<<FAN_PIN); |
68 | }
|
69 | |
70 | |
71 | // ADC abfragen (Temperatursensor extern)
|
72 | // --------------------------------------
|
73 | uint16_t Read_Ext_Temp_Sens(void) |
74 | {
|
75 | // VCC-Referenz und PA0
|
76 | ADMUX = 0b00000000; |
77 | |
78 | // Mehrere Konvertierungen durchführen, um Störungen auszubügeln
|
79 | uint16_t adcsumme = 0; |
80 | |
81 | for(unsigned char i=0; i<10; i++) |
82 | {
|
83 | // Konvertierung starten
|
84 | ADCSRA |= (1<<ADSC); |
85 | |
86 | // Warten, bis Konvertierung beendet
|
87 | while(ADCSRA & (1<<ADSC)) |
88 | {
|
89 | // ...
|
90 | }
|
91 | |
92 | // Ergebnis zum Gesamtwert hinzufügen
|
93 | adcsumme += ADCW; |
94 | }
|
95 | |
96 | // Durchschnittswert bilden, umkehren, und zurückgeben
|
97 | return 1023 - (adcsumme / 10); |
98 | }
|
99 | |
100 | |
101 | // ADC abfragen (Temperatursensor intern)
|
102 | // --------------------------------------
|
103 | uint16_t Read_Int_Temp_Sens(void) |
104 | {
|
105 | // Interne 1.1-V-Referenz und ADC8
|
106 | ADMUX = 0b10100010; |
107 | |
108 | // Mehrere Konvertierungen durchführen, um Störungen auszubügeln
|
109 | uint16_t adcsumme = 0; |
110 | |
111 | for(unsigned char i=0; i<10; i++) |
112 | {
|
113 | // Konvertierung starten
|
114 | ADCSRA |= (1<<ADSC); |
115 | |
116 | // Warten, bis Konvertierung beendet
|
117 | while(ADCSRA & (1<<ADSC)) |
118 | {
|
119 | // ...
|
120 | }
|
121 | |
122 | // Ergebnis zum Gesamtwert hinzufügen
|
123 | adcsumme += ADCW; |
124 | }
|
125 | |
126 | // Durchschnittswert bilden, und zurückgeben
|
127 | return (adcsumme / 10); |
128 | }
|
129 | |
130 | |
131 | // ADC abfragen (Trimmer)
|
132 | // ----------------------
|
133 | uint16_t Read_Trimmer(void) |
134 | {
|
135 | // VCC-Referenz und ADC5
|
136 | ADMUX = 0b00000101; |
137 | |
138 | // Mehrere Konvertierungen durchführen, um Störungen auszubügeln
|
139 | uint16_t adcsumme = 0; |
140 | |
141 | for(unsigned char i=0; i<10; i++) |
142 | {
|
143 | // Konvertierung starten
|
144 | ADCSRA |= (1<<ADSC); |
145 | |
146 | // Warten, bis Konvertierung beendet
|
147 | while(ADCSRA & (1<<ADSC)) |
148 | {
|
149 | // ...
|
150 | }
|
151 | |
152 | // Ergebnis zum Gesamtwert hinzufügen
|
153 | adcsumme += ADCW; |
154 | }
|
155 | |
156 | // Durchschnittswert bilden, umkehren, und zurückgeben
|
157 | return 1023 - (adcsumme / 10); |
158 | }
|
159 | |
160 | |
161 | // PWM Duty Cycle festlegen
|
162 | // ------------------------
|
163 | void Set_PWM_Duty_Cycle(unsigned char n) |
164 | {
|
165 | // Output Compare Register beschreiben (0 - 255)
|
166 | OCR0A = n; |
167 | }
|
168 | |
169 | |
170 | // Hauptprogramm
|
171 | // -------------
|
172 | int main(void) |
173 | {
|
174 | // Ausgang PB2 MOSFET
|
175 | // Ausgang PB0 Testpin (Ticks)
|
176 | // Ausgang PB1 Testpin (Reset)
|
177 | DDRB = 0b00000111; |
178 | |
179 | // Pause...
|
180 | for (uint16_t pause=0; pause<1000; pause++) _delay_ms(1); |
181 | |
182 | // Lüfter initialisieren
|
183 | Init_FAN(); |
184 | |
185 | // ADC initialisieren
|
186 | Init_ADC(); |
187 | |
188 | // PWM initialisieren, einschalten
|
189 | Init_PWM(); |
190 | Status_PWM(1); |
191 | |
192 | while(1) |
193 | {
|
194 | // Einfluss des OnBoardTempSens auf PWM-Regelung
|
195 | |
196 | // Temperatur ADCW
|
197 | // ab 20 501
|
198 | // ab 30 522
|
199 | // ab 40 541
|
200 | // ab 50 560
|
201 | |
202 | // Bis zu einem ADC-Wert von 511 (unter 25 °C) holt sich die PWM-Regelung die "Drehzahl" von der Trimmereinstellung, und der OnBoardTempSens hat keinen Einfluss.
|
203 | // Ab einem ADC-Wert von 512 (25 °C) "übernimmt" der OnBoardTempSens die PWM-Regelung.
|
204 | // Ab 25 °C: Dem gemessenen ADC-Wert werden 512 abgezogen, und die Differenz mit 2 multipliziert, und dieser Wert dem Trimmerwert aufaddiert.
|
205 | |
206 | // Beispiel: ADC-Wert 522. 30 °C. 522 - 512 = 10. 10 * 2 = 20. Minimal-Trimmerwert = 5 %. 5 + 20 = 25. PWM-Wert bei 30 °C = 25 % (oder höher, je nach Trimmerposition).
|
207 | // Beispiel: ADC-Wert 541. 40 °C. 541 - 512 = 29. 29 * 2 = 58. Minimal-Trimmerwert = 5 %. 5 + 58 = 63. PWM-Wert bei 40 °C = 63 % (oder höher, je nach Trimmerposition).
|
208 | // Beispiel: ADC-Wert 560. 50 °C. 560 - 512 = 48. 48 * 2 = 96. Minimal-Trimmerwert = 5 %. 5 + 96 entspricht 100. PWM-Wert bei 50 °C = 100 %.
|
209 | |
210 | // Trimmer auslesen
|
211 | uint16_t trimmerwert = Read_Trimmer(); |
212 | |
213 | // Mindestdrehzahl festlegen (5 % PWM), da ansonsten der Fan bei Trimmer-Linksanschlag stehenbleibt
|
214 | if(trimmerwert < 51) trimmerwert = 51; |
215 | |
216 | // Update von OCR, "umwandeln" von 10 auf 8 bit (1023 entspricht 255)
|
217 | Set_PWM_Duty_Cycle(trimmerwert / 4); |
218 | |
219 | // Warten, um nervöse Drehzahländerungen zu eliminieren...
|
220 | for (uint16_t pause=0; pause<2000; pause++) _delay_ms(1); |
221 | |
222 | // Debug: Reset des externen Impulszählers
|
223 | PORTB &=~(1<<PB1); _delay_ms(10); |
224 | PORTB |= (1<<PB1); _delay_ms(10); |
225 | |
226 | // Debug: Ausgabe auf den externen Impulszähler
|
227 | uint16_t tempsens = Read_Ext_Temp_Sens(); |
228 | for(uint16_t ausgabe=0; ausgabe < tempsens; ausgabe++) |
229 | {
|
230 | PORTB &=~(1<<PB0); _delay_us(10); |
231 | PORTB |= (1<<PB0); _delay_us(10); |
232 | }
|
233 | |
234 | // Pause...
|
235 | for (uint16_t pause=0; pause<2000; pause++) _delay_ms(1); |
236 | |
237 | }
|
238 | }
|
Update: Eben einen 470-Ohm Widerstand am Gate probiert, bringt leider auch nix. Hat das eventuell was damit zu tun, dass am ADC0 vom ATtiny24 zugleich auch AREF liegt? Ist zwar intern ausgeschaltet, aber würde eventuell erklären, warum der Trimmer an ADC5 einwandfrei ausgelesen werden kann... Ich habe jetzt mal den KTY Sensor von ADC0 auf ADC1 gelegt, und die Störungen wurden wieder etwas weniger, nun sind nur noch bei jeder 10. Messung Fehler, da springt der Wert plötzlich von 510 auf 261 oder sonstwas runter. Hab auch noch einen KTY81-220 probiert, derselbe Fehler. Mal eine ganz andere Idee: Würde es etwas bringen, wenn ich die Gate-Ansteuerung durch einen Optokoppler vom Controller-Pin trenne?
:
Bearbeitet durch User
Christian W. schrieb: > Mal eine ganz andere Idee: Würde es etwas bringen, wenn ich die > Gate-Ansteuerung durch einen Optokoppler vom Controller-Pin trenne? Normal bringt das nichts. Wie hoch ist deine PWM-Frequenz? Kommt der Mess-Fehler auch, wenn du R2 raus nimmst?
Christian W. schrieb: > Hat das eventuell was damit zu tun, dass am ADC0 vom ATtiny24 > zugleich auch AREF liegt? Ist im Datenblatt etwas versteckt. Aber
1 | Internal voltage reference options may not be used if an external |
2 | voltage is being applied to the AREF pin. |
und im Anhang
1 | AREF: External Analog Reference for ADC. Pullup and output driver |
2 | are disabled on PA0 when the pin is used as an external |
3 | reference or Internal Voltage Reference with external |
4 | capacitor at the AREF pin by setting (one) the bit REFS0 |
5 | in the ADC Multiplexer Selection |
> werden kann... Ich habe jetzt mal den KTY Sensor von ADC0 auf ADC1 > gelegt, und jetzt hängst du noch 100nF gegen Masse an AREF.
:
Bearbeitet durch User
tom69 schrieb: > Wie hoch ist deine PWM-Frequenz? Die Frequenz liegt um die 32 kHz. Geringere Werte habe ich auch schon getestet, aber da gibt der Lüfter ein ekelhaftes Pfeifen von sich. Der Fehler bleibt aber. Karl Heinz schrieb: > und jetzt hängst du noch 100nF gegen Masse an AREF. ...und siehe da, es gibt keine Auslesefehler mehr. Danke :-)
Zu deinen aktuellen EMV Problemen möchte ich nichts beitragen, aber vielleicht darf ich ja eine Anregung für ein Redesign machen. 1. Verwendung eines 4-pin Lüfters, diese sind wesentlich gedeihlicher anzusteuern als die klassische PWM Grütze http://www.formfactors.org/developer%5Cspecs%5CREV1_2_Public.pdf 2. Verwendung eines besseren Temperatursensors, entweder analog der LM75 oder digital so etwas wie der DS18B20 EMV-Probleme wirst Du mit diesem Ansatz kaum haben, darüber hinaus wird die Gesamtschaltung etwas kleiner.
Harald schrieb: > 1. Verwendung eines 4-pin Lüfters, diese sind wesentlich gedeihlicher > anzusteuern als die klassische PWM Grütze > http://www.formfactors.org/developer%5Cspecs%5CREV1_2_Public.pdf Werd ich mal im nächsten Projekt testen. Danke. Warum besser anzusteuern? Laufen ja auch mit PWM...
Bei einem klassischen 2(3)-Pin Lüfter erzeugt man eine variable Spannung, die den Lüfter "irgendwie" undefiniert langsamer laufen lässt. Wann der Lüfter tatsächlich anläuft oder stehen bleibt ist nicht nur modellabhängig sondern unterliegt auch noch der Serienstreuung, Alterung, Dreck, Temperatur, etc. Bei einem 4-pin Lüfter gibt man über die (unbelastete) 25kHz PWM nur die Solldrehzahl vor, die Ansteuerung des eigentlichen Motors macht die Lüfterelektronik. Das Verhalten ist dabei recht genau und vor allem reproduzierbar unabhängig von obigen Einflüssen. Man braucht auch hier keinen MOSFET, die PWM kann man direkt per Portpin ausgeben.
Achso... Übrigens: Ich habe den Prescaler vom ADC nochmal angepasst, und statt einem Vorteiler von 2 verwende ich jetzt 128, damit sind jetzt praktisch keine Störungen mehr feststellbar und die Analogwerte werden einwandfrei ausgelesen.
Habe mir vor längerer Zeit auch wegen nerviger Lüfter Lautstärke ein neues „Silent PC-Netzteil“ zugelegt. Mein PC (i5 ohne extra GK) benötigt im Leerlauf ~25W unter Volllast ca. ~100W. Die Lüfter Regelung bläst wie ein Föhn und ist trotz 140mm Lüfter gut hörbar. Bei der Überprüfung hab ich festgestellt, dass der Lüfter beim einschalten und 20°C schon 9,5V bekommt. Nach weiteren 5 min. sind es dann schon 11V. Der Messfühler ist in einer der Netzteil Sek.-Drossel / 5V Zweig eingeklebt. Diese wurde in meinem Fall nicht wärmer als 24°C. Hab ein paar Messungen zum Lüfter angestellt. Unhörbar ist er bis ca. 6V, wobei er schon ordentlich Luft schaufelt. Meine Temperatursteuerung regelt hinunter bis 4V bei <=23°C und hoch bis 12V bei 45°C. Beim Einschalten bekommt der Lüfter für 5 sec. 12V (Das soll mich an das ursprüngliche Geräusch erinnern;-) , dann wird innerhalb von 2 min. Auf den Sollwert ab-geregelt. Bin jetzt mit der neuen Geräuschsituation voll zufrieden. Zu Einsatz kam ein PIC mit PWM → Analog OP Mosfet Regelung Im Anhang noch ein paar Daten / Messwerte zum 140mm NT-Lüfter wenn es jemanden Interessieren sollte. MfG
tom69 schrieb: > Die Lüfter Regelung bläst wie ein Föhn und ist trotz 140mm Lüfter gut > hörbar. Bei mir auch, ich bin nach etwas Suchen auch dahintergekommen, dass den meisten Lärm der Fan produziert, der eigentlich aufgrund der Größe am leisesten sein sollte. Ist aber nicht so. Der im Vergleich dazu winzige CPU-Fan ist im Leerlauf so gut wie unhörbar. Ich habe die letzten zwei Tage noch etwas am Schaltplan herum-designt, und das Layout von der Platine nochmal komplett überarbeitet. Unter anderem gibt es jetzt drei getrennte Masseflächen, damit mir der EMV-Geist nicht herum-spuken kann, und die MOSFET-Ansteuerung ist über einen Optokoppler realisiert, da mir laut Oszi der µC-Pin zu sehr gelitten hat, das Signal war da ziemlich verzerrt. Anbei mal der neue Schaltplan und das Boardlayout, mit der Bitte um Beurteilung. Danke! Frage 1: Wie verbinde ich die Masseflächen GND und AGND? (Am Pin 14 von Controller, rechts oben) Ich habe das durch eine kurze Brücke auf dem Top-Layer gelöst, ist aber wahrscheinlich auch nicht das gelbe vom Ei, weil wenn ich beim Ausdrucken den Top-Layer vergesse, ist auch die Brücke nicht da. Gibt's da elegantere Lösungen zum Masseflächen verbinden? Frage 2: Muss an AREF VCC? Ich hab Pin 1 und 13 gebrückt. Grüße, Christian
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.