Hallo Liebe Gemeinde,
Ich probiere den ADC meines 1284p im free run mode laufen zu lassen und
gegebenenfalls Werte zu von ihm abzurufen. Allerdings scheint er nicht
korrekt zu laufen, da ich ihn nach jedem Messen selbst wieder Triggern
muss. Er läuft mit 22118400Hz.
Iniziallisieren tue ich ihn wie folgt. 1 | void Microphone::init()
| 2 | {
| 3 | ADMUX |= (1 << REFS0); //select AVcc as reference
| 4 | //setup prescaler of 128 => ~200khz
| 5 | ADCSRA |= (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2);
| 6 | ADCSRA |= (1 << ADATE); //enable auto trigger
| 7 | ADCSRB |= (1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2); // free run mode
| 8 |
| 9 | //Disable the digital input
| 10 | DIDR0 |= (1 << ADC7D); // on pin 7
| 11 | //enable ADC
| 12 | ADCSRA |= (1 << ADEN);
| 13 | //start one convention which is needed for autotrigger
| 14 | ADCSRA |= (1 << ADSC);
| 15 | while(ADCSRA & (1 << ADSC))
| 16 | {
| 17 | }
| 18 | }
|
Lesen würde tue ich dann so: 1 | int16_t Microphone::sample()
| 2 | {
| 3 | //select chanel7 ADC7
| 4 | ADMUX |= (1 << MUX0) | (1 << MUX1) | (1 << MUX2);
| 5 | //wait till next is done
| 6 | while(ADCSRA & (1 << ADSC))
| 7 | {
| 8 | } //check till ADSC is 0
| 9 | return ADCW; // return the current value
| 10 | }
|
Wohingegen er problemlos läuft sofern ich selbst ADCSRA |= (1 << ADSC)
aufrufe, was bei Free Run ja nicht sein sollte.
Welches Bit habe ich übersehen?
Viele Grüße
BennX
Hallo,
Ich habe da mal einige Frage, warum "free run mode" wenn die Daten nicht
per ADC-Interrupt gelesen werden?
Wenn ich eine Funktion nutzen würde, wie sample() und auch noch den
Kanal auswähle, dann starte ich eine Wandlung selbst, nach dem setzen
des Kanals.
Also alles tuti so.
Vielen Dank für die schnelle Antwort,
Der Grund ist eigentlich der, dass ich mit der Funktion Musik Sampeln
will und das nur nach Bedarf und in eigener Geschwindigkeit. Dafür würde
ich aber ungerne immer selbst triggern müssen sobald ich Anfrage. Die
Wahl des Mux kann auch in die init ja. Tue ich dies, ändert sich nichts
daran, dass ich keinerlei "neuen" Werte erhalte. Lediglich der zuerst
gemessen Wert wird ausgegeben. (Den ich in der init selbst ja triggern
muss)
Da sich der Kanal voraussichtlich nicht ändern wird, ist das so auch
okay. (Zumindest wird er das nicht on run time) 1 | void Microphone::init()
| 2 | {
| 3 | ADMUX |= (1 << REFS0); //select AVcc as reference
| 4 | //select chanel7 ADC7
| 5 | ADMUX |= (1 << MUX0) | (1 << MUX1) | (1 << MUX2);
| 6 | //..
|
Grüße
BennX
Hallo,
diese Zeile spiegelt nicht deinen Kommentar wieder: 1 | ADCSRB |= (1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2); // free run mode
|
Das ist also der Fehler, den hätte man auch mit Hilfe des Datenblattes
finden können ! 1 | ADTS2 ADTS1 ADTS0 Trigger Source
| 2 | 0 0 0 Free Running mode
| 3 | 0 0 1 Analog Comparator
| 4 | 0 1 0 External Interrupt Request 0
| 5 | 0 1 1 Timer/Counter0 Compare Match
| 6 | 1 0 0 Timer/Counter0 Overflow
| 7 | 1 0 1 Timer/Counter1 Compare Match B
| 8 | 1 1 0 Timer/Counter1 Overflow
| 9 | 1 1 1 Timer/Counter1 Capture Event
|
Und ich würde 1 | ADCSRA |= (1 << ADATE); //enable auto trigger
|
erst nach dem Setzen der "Trigger Source" aktivieren.
Ja das ist richtig. Es muss lauten: 1 | ADCSRB &= ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2));
|
oder auch einfach = 0x00;
So bleibt er aber in dieser init Stehen: 1 | void Microphone::init()
| 2 | {
| 3 | ADMUX |= (1 << REFS0); //select AVcc as reference
| 4 | //select chanel7 ADC7
| 5 | ADMUX |= (1 << MUX0) | (1 << MUX1) | (1 << MUX2);
| 6 | //should be between 50 and 200khz
| 7 | // 22118400/200 = ~110 so 128 is fine
| 8 | //setup prescaler of 128 => ~200khz
| 9 | ADCSRA |= (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2);
| 10 | ADCSRB &= ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2));
| 11 | ADCSRA |= (1 << ADATE); //enable auto trigger
| 12 |
| 13 | //Disable the digital input
| 14 | DIDR0 |= (1 << ADC7D); // on pin 7
| 15 | //enable ADC
| 16 | ADCSRA |= (1 << ADEN);
| 17 | //start one convention which is needed for autotrigger
| 18 | ADCSRA |= (1 << ADSC);
| 19 | while(ADCSRA & (1 << ADSC))
| 20 | {
| 21 | }
| 22 | }
|
Ich habe auch das auto trigger wie gesagt verschoben.
Hallo Ben,
dies kann man so schreiben ist aber umständlich. 1 | ADMUX |= (1 << MUX0) | (1 << MUX1) | (1 << MUX2);
|
Warum nicht
[c]ADMUX = (ADMUX and ~(0b11111)) & (channel & 0b11111);
Hallo,
naja die Anweisung bewirkt nach einen RESET ! nichts, da die Bits alle
=0 sind. 1 | ADCSRB &= ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2));
|
Für den Leser wär dies als ZEICHEN besser, der Compiler entfernt diese
Zeile dann auch wieder und erzeugt keinen Code. 1 | ADCSRB |= ((0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0));
|
Uwe S. schrieb:
> Hallo Ben,
>
> dies kann man so schreiben ist aber umständlich.ADMUX |= (1 << MUX0) |
> (1 << MUX1) | (1 << MUX2);
> Warum nicht
> [c]ADMUX = (ADMUX and ~(0b11111)) & (channel & 0b11111);
Das habe ich so geschrieben, damit ich selbst den Überblick behalte was
ich gesetzt habe und was nicht. (Bin noch nicht so lange dabei mit der
AVR Programmierung und da ist es gut den Überblick zu behalten)
Aber wie gesagt, er bleibt so in der init und hängt dementsprechend in
der while. Kommentiere ich ADCSRA |= (1 << ADATE); aus, so bleibt er
nicht hängen aber erzeugt weiterhin keine Werte automatisch.
Uwe S. schrieb:
> Hallo,
>
> naja die Anweisung bewirkt nach einen RESET ! nichts, da die Bits alle
> =0 sind.ADCSRB &= ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2));
> Für den Leser wär dies als ZEICHEN besser, der Compiler entfernt diese
> Zeile dann auch wieder und erzeugt keinen Code.ADCSRB |= ((0 << ADTS2) |
> (0 << ADTS1) | (0 << ADTS0));
Das ist richitg. Ich hatte zu beginn einfach ein ADCSRB = 0x00; drinnen.
"Der Form halber"
Grüße
BennX
Hallo Ben,
Karl-Heinz schreibt an dieser Stelle, dass dies dann nicht der Code sein
kann, der ein Problem beinhaltet.
Uwe S. schrieb:
> Hallo Ben,
>
> Karl-Heinz schreibt an dieser Stelle, dass dies dann nicht der Code sein
> kann, der ein Problem beinhaltet.
Dann verstehe ich nicht warum er nicht hängen bleibt sobald ich ADATE
nicht setze, aber hängen bleibt wenn ich es setzte.(?!)
Hallo,
Ja mein Fehler, es ist ein logisches Problem, bei der Dummywandlung den
ADC anstoßen und warten und dann erst in den Auto-Tigger-Modus wechseln. 1 | //Disable the digital input
| 2 | DIDR0 |= (1 << ADC7D); // on pin 7
| 3 | //enable ADC
| 4 | ADCSRA |= (1 << ADEN);
| 5 | //start one convention which is needed for autotrigger
| 6 | ADCSRA |= (1 << ADSC);
| 7 | while(ADCSRA & (1 << ADSC)) ;
| 8 |
| 9 | ADCSRA |= (1 << ADATE); //enable auto trigger
| 10 | ADCSRA |= (1 << ADSC);
|
Danach kann eine ADC-Wandlung nur über die Abfrage des ADC
Interrupt-Flags erfolgen, dies muss DU auch selbst löschen.
Uwe S. schrieb:
> Hallo,
>
> Ja mein Fehler, es ist ein logisches Problem, bei der Dummywandlung den
> ADC anstoßen und warten und dann erst in den Auto-Tigger-Modus
> wechseln.//Disable the digital input
> DIDR0 |= (1 << ADC7D); // on pin 7
> //enable ADC
> ADCSRA |= (1 << ADEN);
> //start one convention which is needed for autotrigger
> ADCSRA |= (1 << ADSC);
> while(ADCSRA & (1 << ADSC)) ;
>
> ADCSRA |= (1 << ADATE); //enable auto trigger
> ADCSRA |= (1 << ADSC);
> Danach kann eine ADC-Wandlung nur über die Abfrage des ADC
> Interrupt-Flags erfolgen, dies muss DU auch selbst löschen.
Vielen Dank für die Antwort.
Müsste ich aber nicht dementsprechend auch ADIE setzen?
Also würde das Sample dann wie folgt aussehen? 1 | int16_t Microphone::sample()
| 2 | {
| 3 | //wait till next is done
| 4 | while(ADCSRA & (1 << ADIF))
| 5 | {
| 6 | } //check till ADSC is 0
| 7 | ADCSRA |= (1 << ADIF); //reset flag by writing a 1 to it.
| 8 | return ADCW; // return the current value
| 9 | }
|
Hallo,
Hast Du eine ADC Interrupt Routine definiert -> nein.
Ich würde es so machen: 1 | ADCSRA = ADCSRA; //reset flag by writing a 1 to it.
|
Uwe S. schrieb:
> Hallo,
>
> Hast Du eine ADC Interrupt Routine definiert -> nein.
>
> Ich würde es so machen:ADCSRA = ADCSRA; //reset flag by writing a 1 to
> it.
Vielen Dank für die Hilfe,
Nachdem ich bemerkt habe, dass das ADIF flag logischerweise nicht
gesetzt sein darf Funktioniert es nun auch.
Scheint nicht sonderlich genau zu sein aber es Funktioniert schonmal.
Vielen Dank!
Grüße
Ben
Hier noch einmal in Total: 1 | void Microphone::init()
| 2 | {
| 3 | ADMUX |= (1 << REFS0); //select AVcc as reference
| 4 | //select chanel7 ADC7
| 5 | ADMUX |= (1 << MUX0) | (1 << MUX1) | (1 << MUX2);
| 6 |
| 7 | //should be between 50 and 200khz
| 8 | // 22118400/200 = ~110 so 128 is fine
| 9 | //setup prescaler of 128 => ~200khz
| 10 | ADCSRA |= (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2) ;
| 11 | ADCSRB &= ~((1 << ADTS0) | (1 << ADTS1) | (1 << ADTS2));
| 12 |
| 13 | //Disable the digital input
| 14 | DIDR0 |= (1 << ADC7D); // on pin 7
| 15 | //enable ADC
| 16 | ADCSRA |= (1 << ADEN);
| 17 | //start one convention which is needed for autotrigger
| 18 | ADCSRA |= (1 << ADSC);
| 19 | while(ADCSRA & (1 << ADSC)) ;
| 20 |
| 21 | ADCSRA |= (1 << ADATE); //enable auto trigger
| 22 | ADCSRA |= (1 << ADSC);
| 23 | }
| 24 |
| 25 | int16_t Microphone::sample()
| 26 | {
| 27 | //wait till next is done
| 28 | while(!(ADCSRA & (1 << ADIF)))
| 29 | {
| 30 | } //check till ADSC is 0
| 31 | ADCSRA = ADCSRA;
| 32 | return ADCW; // return the current value
| 33 | }
|
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|