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
voidMicrophone::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_tMicrophone::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
returnADCW;// 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)
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
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_tMicrophone::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.
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
voidMicrophone::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