PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] ADC-Interrupt springt nicht an



-schumi-
03.10.2011, 21:52
Hallo zusammen,

ich mache im Moment etwas mit vielen Timern und Interrupts. Der Overflow-Interrupt funktioniert auch, Code:


ISR(TIMER1_OVF_vect) // Timer1 Überlauf
{
TCNT1 = 64202; //64202 vorladen
POS_LED_TOGGLE ();
}

Das "POS_LED_TOGGLE ();" kann ich wunderbar auf dem Oszi sehen, die Zeiten stimmen auch (83µs)

Jetzt soll der ADC bei jedem Überlauf gestartet/getriggert werden und wenn er fertig ist soll er einen Interrupt auslösen:


void POS_LDR_INIT (void)
{
ADCSRA |= (1 << ADEN) | (1 << ADATE) | (1 << ADIF); // ADC enable + triggern enable + interrupt wenn fertig
SFIOR |= (1 << ADTS2) | (1 << ADTS1); // triggern bei timer1 überlauf
sei();
}


Das LED_TOGGLE hab ich aus dem Timer1-Interrupt rausgeschmissen, dafür hier hinein gepackt:


ISR(ADC_vect)
{
POS_LED_TOGGLE ();
}

Ich hab aber auf dem Oszi ein dauerhaftes high (<- kommt vom INIT). Nix Rechteck... :-(

Weis jemand warum? Hab ich irgend ein Register beim ADC vergessen?

Viele Grüße und vielen Dank schonmal
-schumi-

PS: µC = Atmega32, Compiler = AVR-GCC

EDIT: Hier gibts alle Sources als Zip: http://dl.dropbox.com/u/19005544/RN-ADC-Interrupt.zip

Kampi
03.10.2011, 22:28
Benutz mal diese Zeilen hier um den ADC zu initialisieren


void ADC_Init(void) // ADC initalisieren
{
ADMUX = (1<<REFS1) | (1<<REFS0); // Interne Referenzspannung nutzen
ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
ADCSRA |= (1<<ADEN); // ADC aktivieren
ADCSRA |= (1<<ADSC); // Eine ADC-Wandlung

while (ADCSRA & (1<<ADSC)) // Warten bis Wandlung abgeschlossen ist

Ergebniss = ADCW; // Ergebniss der ersten Wandlung speichern
}


Du musst nämlich nachdem initialisieren erstmal eine Wandlung machen um das Register leer zu räumen.
Und das hier brauchste natürlich auch:

SREG = (1<<7); // Global Interrupt Enable

Anschließend setzt du in der Timer-ISR nur noch das Enable Bit von dem ADC und ließt ihn aus.

-schumi-
03.10.2011, 22:55
Das ist ja so, wie man es "normal" macht?

Sprich 1:1 wie du es da schreibst hat es nicht hingehauen, weil der ADC ja nicht weis, dass er bei einem Überlauf von Timer1 starten und wenn er fertig ist selbst einen Interrupt auslösen soll. Ich habe das dann noch dazugefügt (So wies oben steht), hat aber keine Verbesserung gebracht.

* Die Refferenzspg hatte ich ehrlich gesagt vergessen einzustellen, auf AVCC zu stellen hat aber keine Verbesserung gebracht
* Frequenzvorteiler hab ich alles auf 0 gelassen (Teiler = 2) weil der ADC verdammt schnell sein muss *g*
* ADC aktivierung hab ich oben auch
* Eine ADC-Wandlung machen bringt leider auch keine Verbesserung...
* "SREG = (1<<7);" (Bzw. "SREG |= (1<<7);") hat auch nichts gebracht... (Ist das nicht das selbe, wie "sei();" ?)


Anschließend setzt du in der Timer-ISR nur noch das Enable Bit von dem ADC und ließt ihn aus.
* Ich wollte aber das der ADC selbst startet wenn Timer1 überläuft (Das geht laut Seite 218 vom Datasheet ( http://www.atmicroprog.com/download/atmel/atmega32.pdf ))
* Der ADC soll nicht abgefragt werden ob er fertig ist, sondern selbst nen Interrupt reinknallen (Es muss alles sehr schnell gehen)


Das Problem kann ja theoretisch von 2 Stellen kommen:
* Entweder der ADC startet nicht wenn Timer1 überläuft
* Oder der ADC löst keinen Interrupt aus wenn er fertig ist...

Vielen Dank für deine Hilfe :-D
-schumi-

-schumi-
03.10.2011, 23:12
LÖSUNG:


JUCHU - Es funzt!!!

Zitat aus dem Datenblatt:


Bit 4 – ADIF: ADC Interrupt Flag
This bit is set when an ADC conversion completes and the Data Registers are updated. The
ADC Conversion Complete Interrupt is executed if the ADIE bit and the I-bit in SREG are set.
ADIF is cleared by hardware when executing the corresponding interrupt handling vector. Alter-
natively, ADIF is cleared by writing a logical one to the flag. Beware that if doing a Read-Modify-
Write on ADCSRA, a pending interrupt can be disabled. This also applies if the SBI and CBI
instructions are used.


In den Quellcode mit rein:


void POS_LDR_INIT (void)
{
ADMUX |= (1 << REFS0); // AVCC als Refferenz
ADCSRA |= (1 << ADEN) | (1 << ADATE) | (1 << ADIF) | (1 << ADIE); // ADC enable + triggern enable + ISR wenn fertig + enable interrupt
SFIOR |= (1 << ADTS2) | (1 << ADTS1); // triggern bei timer1 überlauf
sei();
}


Und schon geht es :-D

(Und zu allem Überfluss schafft es der ADC doch glatt, in weniger als 83µs zu Wandeln -> Angst unbegründet -> PERFEKT :-D )

Viele Grüße und vielen Dank!
-schumi-

PS: Den Sourcen-Download oben habe ich aktualisiert und funzt jetz - Wer abgucken möchte^^