Hallo alle,
ich bitte wieder mal um Hilfe.
Projektziel: Bei meinem Labornetzteil (KORAD KA3005D) soll der Lüfter nur bei Bedarf geschaltet werden, aktuell läuft er ständig. Den Bedarf definiere ich dann, wenn die Temperatur am Kühlkörper der Leistungsstufe 40°C erreicht oder überschreitet. Dann soll bis etwa 70°C die Drehzahl des Lüfters bis zu dessen Maximum ansteigen.
Der Lüfter - zweidrahtig - wird aktuell mit ca. 13V versorgt. Die Drehzahl ist anfangs eher "mittel" und steigt mit steigendem Strombedarf auf "hoch". Die Geräuschkulisse stört mich aber auch im Standby-Betrieb.
Lösung: Ein NTC (ca. 47k bei RT, Anschluss an Vcc) bildet mit einem Festwiderstand (47k gegen GND) einen Spannungsteiler, dessen Mittelanschluss an den ADC geht. Es sind mit steigender Temperatur steigende ADC-Werte im Bereich von ca. 500 bis 800 feststellbar (Testaufbau mit mega328 - ermittelt durch UART-Ausgabe). Oberhalb eines bestimmten Grenzwertes soll der Motor drehen und mit steigender Temperatur auch die Drehzahl steigern. Arbeitsbereich und Funktion wurden ohne Controller ausgemessen. Die PWM soll also die Drehzahl temperaturabhängig mit variabler Einschaltdauer steuern. Motortreiber ist ein A4950, VIN ca. 13V, über einen Spannungswandler werden die 5,0V für Controller und Spannungswandler erzeugt (Controllerversorgung und Spannungsteiler abgepuffert mit ELKO 10uF und Kerko 100nF).
Arbeitsweise: Der zugrundeliegende ADC-Werte-Bereich wurde mit dem mega328 ermittelt. Mit diesem Bereich soll der tiny13 die entsprechende Motordrehzahl über den A4950 steuern. Ein Testlauf ohne ADC-Betrieb bestätigt die Funktion des Testaufbaues auf dem Steckbrett. Dieser Testlauf wird in einer for-Schleife mit 254 Schritten realisiert. Funktion gut, Ergebnis ist auch der ungefähr bestimmbare Einsatz der Motorfunktion. Siehe dazu Codeausschnitt "main".
Problem: Der vom ADC generierte Messwert - free running - kann nicht für die Steuerung der PWM übernommen werden, ein entsprechender Befehl wird nicht ausgeführt. Weder wird die Ansteuerung des Timers in der ISR des ADC berücksichtigt - siehe Codebeispiel "ADC" - noch eine Ansteuerung aus dem "main". Auch eine Ansteuerung der Hardware-PWM aus der Timer-ISR zeigt keine Motorfunktion - siehe Codebeispiel "Timer". Zur Kontrolle der jeweiligen Varianten wird in den entsprechenden Routinen das Anspringen der ISR jeweils über ein Toggeln einer Kontroll-LED bestätigt. Um Probleme der beschränkten Flash- und RAM-Kapazität des tiny13 auszuschalten wurde ein fast identischer (ISR-Namen) Code auf dem tiny85 getestet. In beiden Fällen kein Erfolg.
Anmerkung:
a) Die entsprechenden Variablen sollten korrekt angepasst sein (uint8_t oder uint16_t) - es geht ja auch im Betrieb ohne ADC.
b) Die verschiedenen Varianten laufen jeweils alternativ - nicht gleichzeitig *gg*
Bitte kann mir jemand Tipps geben ob mein Code falsch ist - und wo - oder ob ne Stelle in der Dokumentation der Controller diese Funktion - ADC-Wert steuert Hardware-PWM - verneint? Oder was läuft da schief. Derzeit butter ich seit Tagen in Magermilch :-/
Programmcode-Ausschnitt "main"
Code:
// ============================================================================= =
sei(); // ### Globalen Interrupt freigeben <<<<<#####
// - - - - - - - - - - - - - - - -
//##>> Init ADC ==>>>> wird erst nach der Motor-Probefahrt initialisiert
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// T E S T Motor mal schneller (PWM 0=>254), dann langsamer
PORTB |= (1 <<PB4); // LED ein
for ( uint8_t n=0; n<=254; n++ )
{ OCR0A = n; wms ( 10); }
PORTB &= ~(1 <<PB4); // LED aus
wms ( 1000);
PORTB |= (1 <<PB4); // LED ein
for ( uint8_t n=254; n>0; n-- )
{ OCR0A = n; wms ( 10); }
PORTB &= ~(1 <<PB4); // LED aus
//
// ============================================================================= =
cli ( ); // Globalen Interrupt sperren, ADC initialisieren
// - - - - - - - - - - - - - - - -
ADC3_10free ( ); // Init ADC Kanal 3, 10 Bit, free running adc
// zur Messung der Temperatur mittels NTC
adccnt = 0; // Nulle Anzahl der Messungen des ADC
// ============================================================================= =
sei(); // ### Globalen Interrupt freigeben <<<<<#####
//
// ============================================================================= =
// Es folgt der eigentliche Betrieb des Motors durch Auswertung des NTC
while ( 1 ) //
{ //
cli ( ); //
// pwm = ADCH; //
pwm = ADCMW8; // ADCMW8 : unsigned integer 8
sei ( ); //
OCR0A = pwm - 200; //
wms ( 1);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
return 0; //
} //
// ===== Ende des Testabschnittes, er kann aus mehreren Abschnitten bestehen ====
Programmcode-Ausschnitt "Timer"
Code:
// ============================================================================= =
// === Initialisierung Timer0 ATtiny13/@9,6 MHz für ISR TIM0_COMPA
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TC0_init (void) // Init Tmr/Cntr 0, 8-Bit;
{ //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TCCR0A |= (1<<COM0A1); // Clear OC0A/OC0B = PB0/~1 71/72
// ... on Compare Match, set on TOP
TCCR0A |= (1<<WGM01)|(1<<WGM00); // Fast PWM, Mode3 TOP=0xFF=dez255 79
// das ergibt aus 9,6 MHz mit Prescaler clk/1 37,5 kHz, siehe u.
TCCR0B |= (1<<CS00); // clk/1 <=> No prescaling 74
// => bei 9,6 MHz mit Prescaler clk/1 37,5 kHz
// Gemessen mit DISCO2: 35,7 .. 36,1 kHz
TIMSK0 |= (1<<TOIE0); // Tmr/Cntr0 Overflow interrupt enabled
OCR0A = 0; // HW-PWM default setzen
} // Ende void TC0_init (void)
// ============================================================================= =
// ============================================================================= =
// === Nicht unterbrechbare ISR für Timer0, COMPA =========================== =
// Vector No. 11, Program Address 0x000A, Source TIMER0_COMPA,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ISR(TIM0_OVF_vect) // Vector No. 11, PrgAddr 0x000A
{ //
Izeit_A --; //
if ( Izeit_A ) return; // Zeit noch nicht abgelaufen => gleich return
Izeit_A = Izthrznt; //
return; //
} // Ende ISR(TIMER0_COMPA_vect), Vector No. 11, PrgAddr 0x000A
// ============================================================================= =
Programmcode-Ausschnitt "ADC"
Code:
// ============================================================================= =
// === Initialisierung fuer ADC#3/tiny13 @ 9,6Mhz, Interrupt free running
// ATtiny13_doc8126F_komplett_05-12_-neu-..-neu.pdf ==> 8126F-AVR-05/12
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ADC3_10free (void) // Init m328/ADC4, 10 Bit, free runn. Interrupt
{ //
// - - - - - - - - - - - - - - -
ADMUX |= (1<<REFS0); // Referenzspannung ist AVcc 92
ADMUX |= (1<<MUX1)|(1<<MUX0); // => Messungen auf Kanal 3 93
ADMUX |= (1<<ADLAR); // ADC Left Adjust Result 92
ADCSRA |= (1<<ADATE); // Auto Triggering Enable 93
ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // ==> Prescal clock/128
// 9,6 MHz: clk/128 => 75 kHz bzw 13cykl entsprechend 183 µs
ADCSRA |= (1<<ADEN); // ADC Enable x
ADCSRA |= (1<<ADSC); // starte gleich die erste Wandlung x
ADCSRA |= (1<<ADIE); // ADC Interrupt Enable x
} // Ende von void ADC_in_10free(void)
// ============================================================================= =
// ============================================================================= =
// === ISR für ADC3, übernimmt ADC-Wert aktuell free running
// bei 9,6 MHz: clk/128 => 75 kHz bzw 13cykl entsprechend 183 us (siehe oben)
// ============================================================================= =
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ISR(ADC_vect) //
{ //
// - - - - - - - - - - - - - - - -
PORTB ^= (1 <<PB4); // LED toggeln für Test
ADCMW8 = ADCH; // ADCMW8 : unsigned integer 8
} // Ende ISR(ADC_vect)
// ============================================================================= =
Danke im Voraus
Lesezeichen