Moin,
ich habe einen ATMega88p, der mit externem Quarz auf 7.37MHz betrieben
wird. Um Strom zu sparen ist die CKDIV8-Fuse gesetzt, so dass er mit
921kHz startet.
Während der Laufzeit gibt es dann ein Event an einem Pin und darauf hin
schalte ich den Takt hoch, lese für 20ms einen ADC aus und schalte
danach wieder runter. Das Hochschalten des Prozessortakts funktioniert
und auch die Timer werden angepasst und laufen danach mit der richtigen
Geschwindigkeit.
Wenn ich den ADC abfrage, solange ich noch langsam bin, bekomme ich
einen Wert von 60. Nachdem ich hochgeschaltet habe, messe ich 80.
Die Quelle, die ich messe, ist in beiden Fällen konstant bei 0.3V. Meine
Referenz (VCC mit 100nF an AVCC) schwankt von einer Situation zur
anderen um 50mV. Rechnerisch sollte das 1-2 ADC-Punkte ausmachen, aber
nicht 20.
Die AD-Wandlung wird bei Bedarf gestartet und erst dann wird das
ADEN-Bit gesetzt. Wenn die Messung beendet ist, wird dieses Bit zurück
gesetzt. Der Wechsel des ADC-Prescalers passiert zu einem Zeitpunkt, an
dem der ADC nicht läuft.
ADC-Modul:
1
__monitorvoidInitADC(TProzessorTaktProzessorTakt)// IAR-Compiler: __monitor = nicht durch Interrupts unterbrechbar
2
{
3
BYTEn;
4
5
//Variablen rücksetzen
6
for(n=0;n<ANZAHL_ADC_KANAELE;n++)
7
ADCWerte[n]=0;
8
9
WandlungszyklusAbgeschlossenFlag=false;
10
11
//ADC initialisieren
12
ADCSetProzessorTakt(ProzessorTakt);
13
14
//AD-Pins von der normalen Eingangsverarbeitung abtrennen, um Strom zu sparen
15
for(n=0;n<ANZAHL_ADC_KANAELE;n++)
16
DIDR0|=(1<<(ADCReihenfolge[n]));
17
18
//ADC deaktivieren
19
PRR_Bit0=1;
20
}
21
22
23
//Setzt die Einstellungen für einen bestimmten Prozessortakt
Um Effekte durch das Hin- und Herschalten auszuschließen, habe ich das
"SetzeTaktrate(PTAKT_921kHz);", also das Runterschalten auskommentiert.
Ich messe trotzdem die ganze Zeit den falschen Wert von 80.
Ich vermute, dass ich irgendwas ganz Dummes übersehen habe (irgendwelche
Flags zurücksetzen, bevor Prescaler geändert wird, oder so) und der ADC
nun mit falschen Einstellungen auf der zu schnellen Prozessorclock
läuft. Im Datenblatt finde ich aber nichts, was mir hilft und
Codebeispiele aus dem Internet sehen auch alle ähnlich aus.
Hat jemand von euch eine Idee, über welchen Fallstrick ich hier gerade
falle?
Danke
Daniel
Daniel S. schrieb:> Hat jemand von euch eine Idee, über welchen Fallstrick ich hier gerade> falle?
Nicht unbedingt, aber die erste Messung verwerfen und erst die zweite
Messung verwenden, hat noch nie geschadet...
Es gibt beim ADC zwei Typen in Funktion die du vorher setzten musst.
Freerunning mode und single. Zudem kannst du die interne Referenz nutzen
und umschalten! AVCC, INTERNAL, EXTERNAL, INTERNAL_1.1, INTERNAL_2.56
etc. Das steht abe im DB welchen du hast...
S. Landolt schrieb:>> Ha, zwei Dumme - ein Gedanke.> Hier kommt der Dritte: ich finde nicht einmal die Stellen, an denen der> ADC gestartet und ausgelesen wird.
Dito... Und ich dachte, ich wäre der einzige dumme...
Oder der Code ist nicht vollständig.
Stefan S. schrieb:> Oder der Code ist nicht vollständig.
Der Code ist natürlich nicht komplett. Ich wollte es möglichst kurz
halten, weil es eh keiner liest, wenn ich 1000 Zeilen Code poste.
Stefan U. schrieb:> Sinf alle ADC Werte falsch, oder nur der erste?
Die Werte sind immer dann falsch, wenn ich den Takt über SetzeTaktrate()
hochgeschaltet habe. Dann durchgängig, also spätestens bei der zweiten
Messung sollte sich das wieder "eingependelt" haben. (aber ja, ich
stimme euch da zu)
Heißt aber auch: solange ich langsam laufe sind die Werte richtig. Das
spricht für mich dafür, dass das eigentliche Starten und Auslesen des
ADCs funktioniert.
Außerdem: wenn ich die CKDIV8 rausnehme und von vornherein das komplette
Programm mit dem schnellen Takt laufen lasse und nie runterschalte, dann
stimmen die Ergebnisse auch. Es muss also irgendwas damit zu tun haben,
dass ich den ADC in der Init() langsam einstelle und dann später
hochschalte.
> 1000 Zeilen Code
Dann wäre es doch, auch im eigenen Interesse, sinnvoll, das Programm auf
die vielleicht zwei Dutzend Zeilen mit dem Problemumfeld zu reduzieren.
Ähm...
Jetzt mal ganz am Rande:
Du startest den µC mit 921khz (7,37Mhz/CKDIV8) - richtig.
Aber da bleibt er auch! Du setzt ausschließlich den Prescaler / 8 bei:
1
if(ProzessorTakt==PTAKT_921kHz){
2
CLKPR=0x80;//Enable Prescalere setting
3
CLKPR=0x03;//8-fach Prescaler
4
__no_operation();
5
}
Dadurch läuft der µC auf 921.250hz / 8 = 115khz.
Um dann den Prozessor bei:
1
else{
2
CLKPR=0x80;//Enable Prescalere setting
3
CLKPR=0x00;//kein Prescaler
4
__no_operation();
5
}
... wieder auf 921khz zu setzen und nicht wie du annimmst auf 7370kHz.
Die CKDIV8 hat m.M.n nichts mit dem CLKPR Register zu tun.
EDIT:
Ahh.. Sorry, da hab ich falsch gelegen:
"The CKDIV8 Fuse determines the initial value of the CLKPS bits. If
CKDIV8 is unprogrammed, the
CLKPS bits will be reset to “0000”. If CKDIV8 is programmed, CLKPS bits
are reset to “0011”, giving a
division factor of 8 at start up."
Daniel S. schrieb:> Während der Laufzeit gibt es dann ein Event an einem Pin und darauf hin> schalte ich den Takt hoch, lese für 20ms einen ADC aus
Warum geht das Auslesen nicht mit der niedrigen Taktfrequenz?
> Wenn ich den ADC abfrage, solange ich noch langsam bin, bekomme ich> einen Wert von 60. Nachdem ich hochgeschaltet habe, messe ich 80. Die> Quelle, die ich messe, ist in beiden Fällen konstant bei 0.3V.
Misst du nur diese Quelle oder schaltest du den Multiplexer
zwischendurch um? Falls das Zweitere: welche Spannung misst du vorher?
"Verschleppt" sich eine Änderung dieser vorher gemessenen Spannung auf
die nachfolgend gemessene?
Daniel S. schrieb:> lese für 20ms einen ADC aus
Also du liest eine Periode eines 50Hz Wechselspannungssignals aus?
Hast du einen 100p oder 1nF Kondensator an den ADC-Pin gehängt?
Wie groß sind deine Spannungsteiler-Widerstände?