@Sternthaler
Ein Beispiel braucht man nicht weit suchen, bleiben wir doch beim Asuro.
Ich erlaube mir die erweiterte Bibliothek von Weja zu zitieren,
SIG_ADC Routine für Odometrie, in Encoder_Init() wird adc Freerunning
eingeschaltet
Ich brauche Dir das wohl nicht näher zu erklären, was hier passiert, aber klar, bei jedem Interrupt wird der Kanal umgeschaltet und es klappt, das habe ich schon öfters umgesetzt und keine Problemme mit gehabt...Code:SIGNAL (SIG_ADC) { static unsigned char tmp[2],flag[2],toggle; if (autoencode){ tmp[toggle]= ADCH; if (toggle) ADMUX = (1 <<ADLAR) | (1 <<REFS0) | WHEEL_RIGHT; else ADMUX = (1 <<ADLAR) | (1 <<REFS0) | WHEEL_LEFT; if ( (tmp[toggle] <= 160) && (flag[toggle] == TRUE)) { encoder[toggle] ++; flag[toggle] = FALSE; } if ( (tmp[toggle] > 160) && (flag[toggle] == FALSE)) { encoder[toggle] ++; flag[toggle] = TRUE; } toggle ^= 1;
@castle
klar fühlst Du Dich pudelwohl, wahrscheinlich geht Dir immer einer ab, wenn Du jemanden niedermachen kannst...
Gruß Sebastian
aber klar, bei jedem Interrupt wird der Kanal umgeschaltet und es klappt...
nicht immer...he.....aber immer öfter.... und das ist mir zu unsicher und schalte darum den mux3 dazwischen und erst dann habe ich die 100%
Punkt 1 ist klar, hier soll ADFR gesetzt sein.Zitat von Auf Seite 197 in der ATmega8-Doku
Punkt 2 ist ein Timing um der S/H-Schaltung Zeit zu geben. Kein Einflus, da das Timing ja über den ADC-Interrupt kommt und wir dort ja den MUX 'umschalten' wollen. Und zwar möglichst schnell. ABER: 'Once the conversion starts, the channel and reference selection is locked' dies wird bestimmt auf das Timing achten!?!?
Punkt 3. Hier stehe ich etwas im Regen. Ich verstehe das so: Conversion ist fertig; Interrupt noch nicht ausgelösst; Unser Programm löscht das ADIF-Flag. Das aber kann nicht im Interrupt passieren, da er ja nicht ausgelösst wurde, und somit verstehe ich es so, das 'aus versehen' ein loopendes Hauptprogramm das Flag 'so nebenbei' zurücksetzt.
Das sollte unsere Loop also nicht unbedingt machen.
Gut; soweit lese ich hieraus, was im internen Ablauf in der CPU, zu welchem Zeitpunkt passiert, um die in ADMUX gesetzten Bits überhaupt zu berücksichtigen.
Nun folgendes aus der Doku:
Nicht dass ihr denkt, ich hätte das selbst geschrieben. Englisch war nicht unbedingt mein Lieblingsfach. Das lesen ist aber noch OK, so hoffe ich. Manchmal hapert es halt an der Interpretation.Zitat von Auf Seite 198 in der ATmega8-Doku
Frage:
Warum läuft Weja's Bibliothek-Funktion? (Hier habe ich leider tatsächlich eine Vermutung. Trotz meiner Vermutung, ist sie aber in genau der vorliegenden Form funktionsfähig. Später mehr dazu bei Bedarf.)
Aber es kann ja noch folgende Frage beantwortet werden:
Was habe ich nicht an der Doku verstanden?
Lieber Asuro programieren als arbeiten gehen.
Hi,
kann mir wer schnell alle die register erklären. kurz und bündig. reicht ein kleiner satz zu jeden register, was eben dass wichtigste ist bei ihnen.
Ob das Geht?Zitat von Superhirn
Kleiner Versuch:
Du solltest also immer erst in das Register ADMUX schreiben.Code:Register: ADMUX Bit 7: REFS1 Bit 6: REFS0 Bit 5: ADLAR Bit 4: - Bit 3: MUX3 Bit 2: MUX2 Bit 1: MUX1 Bit 0: MUX0 REFS-Bit-Kombinationen wählt die Referenzspannung (Gut im Asuro ist AVCC) REFS1 REFS0 0 0 AREF 0 1 AVCC 1 0 Nicht erlaubt 1 1 Interne 2.5V Referenz ADLAR-Bedeutung 0 ADC-Ergebniss in den Registern ADCL und ADCH steht so: ADCH: Bits 1 und 0: Höchste Bits der Wandlung ADCL: Bits 7 bis 0: Die niedriegen Bits der Wandlung 1 In den Registern ADCL und ADCH steht das Ergebniss nun so: ADCH: Bits 7 bis 0: Die höchsten 8 Bit vom Ergeniss ADCL: Bits 7 und 6: Die beiden niedrigsten Ergebnissbits MUX-Bits 0000 wählt ADC-Kanal 0 0001 wählt ADC-Kanal 1 0010 wählt ADC-Kanal 2 0011 wählt ADC-Kanal 3 0100 wählt ADC-Kanal 4 0101 wählt ADC-Kanal 5 0110 wählt ADC-Kanal 6 0111 wählt ADC-Kanal 7 1000 1001 1010 1011 1100 1101 1110 1.23 Volt wird gemessen 1111 0 Volt werden gemessen Register: ADCSRA Bit 7: ADEN Bit 6: ADSC Bit 5: ADFR Bit 4: ADIF Bit 3: ADIE Bit 2: ADPS2 Bit 1: ADPS1 Bit 0: ADPS0 ADEN: 1 schaltet den ADC-Wandler erst ein ADSC: Eine 1 startet die Wandlung, oder das 'freerunning' ADFR: 1 erlaubt das 'freerunning' ADIF: Wird von der CPU auf 1 gesetzt, wenn eine Wandlung fertig ist ADIE: 1 erlaubt der CPU eine Interrupt-Funktion aufzurufen ADPS2 bis ADPS0: Wählt einen Vorteiler, der die Wandlergeschwindigkeit und damit allerdings wohl auch die Genauigkeit steuert. Großer Vorteilerwert ergibt eine langsamere Wandlung. Damit wird dann aber auch das laufende Programm nicht so häufig unter- brochen und somit läuft es 'etwas' schneller. ADPS2 ADPS1 ADPS0 0 0 0 Vorteilteiler 2 0 0 1 Vorteilteiler 2 (Ja, nochmal 2) 0 1 0 Vorteilteiler 4 0 1 1 Vorteilteiler 8 1 0 0 Vorteilteiler 16 1 0 1 Vorteilteiler 32 1 1 0 Vorteilteiler 64 1 1 1 Vorteilteiler 128
Dann in das ADCSRA-Register schreiben.
z.B.:
ADMUX = 0b01000000; /* AVCC-Referenz; Kanal 0 */
ADCSRA = 0b11101111 /* Enable; ADC-Start; freerunning; Interrupt enable; Vorteiler 128
Um den Interrupt überhaupt nutzen zu können benötigst du eine Funktion.
z.B.
Damit liefert dir der 'freerunning' ADC-Wandler nun automatisch immer den gemessenen Wert vom Kanal 0 in die Variable adc_wert.Code:volatile unsigned int adc_wert; SIGNAL (SIG_ADC) { adc_wert = ADCL + (ADCH << 8); }
Diesen Wert kannst du in deinem Hauptprogramm immer lesen.
P.S.: Kürzer schaffe ich leider nicht![]()
Lieber Asuro programieren als arbeiten gehen.
Danke. Kürzer gehts sicher nicht. jetzt weiß ich alles was ich wissen muss. (derzeit)
- Das ADC-Register sollte unbedingt als 16-Bit-Wert gelesen werden, damit der Zugriff in der richtigen Reihenfolge gemacht wird.
- ausserdem ist der Wert darin unsigned.
- das Lesen muss atomar erfolgen, da sonst während des Auslesens ein ADC-IRQ auftreten kann, und man dann einen korrupten Wert liest (passiert zwar selten, aber es passiert)
Code:#include <avr/io.h> #include <avr/signal.h> #include <avr/interrupt.h> uint16_t volatile adc_wert; SIGNAL (SIG_ADC) { adc_wert = ADC; } // Lesen: ... uint16_t wert; uint8_t sreg; ... sreg = SREG; cli(); wert = adc_wert; SREG = sreg; ...
Disclaimer: none. Sue me.
Muss das so kompliziert gemacht werden wie es Sprinter sagte? Es reicht ja dass man die register setzt, den wert evt über interrupt ausließt und sofort in eine variable schreibt und dann im normalen programm weitergeht. Oder?
Es kann natürlich auch einfacher gemacht werden, wenn er Code nicht korrekt zu sein braucht.
Disclaimer: none. Sue me.
Lesezeichen