Dennis schrieb:
>> Jedes Mal doppelt wandeln und mit Busy-Wait warten?
>
> Im Datenblatt steht das man einmal wandeln soll damit er sich
> stabilisiert.
Nein, im Datenblatt steht, dass man die erste Wandlung nach dem Wechseln
der Referenz verwerfen sollte, da steht nicht drin, dass die erste
Wandlung nach dem Wechseln des Kanals fehlerhaft ist.
Das kann man einmal zur Initalisierung machen aber doch nicht immer
wieder wenn man nur einen Kanal lesen will.
> Muss ich dann nicht auch auf die Wandlung warten?
Nein, muss man nicht, die Wandlung wird auch fertig wenn der Controller
noch nebenbei was sinnvolles macht, das erfordert aber auch
grundsätzliches Umdenken zur Struktur eines Mikrocontroller-Programms.
1 | while(1)
|
2 | {
|
3 | PORTB |= (1<<PB7); // test!
|
4 |
|
5 | triplock = roundtrip;
|
6 |
|
7 | if( (ADCSRA & (1<<ADSC)) == 0) // letzte Wandlung fertig? - nächste Wandlung wird mit dem Sleep angestossen
|
8 | {
|
9 | switch((ADMUX & 0x1f))
|
10 | {
|
11 | case 1: // ADC1 war ausgewählt
|
12 | strom1 = ADC;
|
13 | ADMUX = (1<<REFS0) | (1<<MUX1); // Referenz = VCC, Input = ADC2
|
14 | break;
|
15 | case 2: // ADC2 war ausgewählt
|
16 | strom2 = ADC;
|
17 | ADMUX = (1<<REFS0) | (1<<MUX1) | (1<<MUX0); // Referenz = VCC, Input = ADC3
|
18 | break;
|
19 | case 3: // ADC3 war ausgewählt
|
20 | strom3 = ADC;
|
21 | ADMUX = (1<<REFS0) | (1<<MUX0); // Referenz = VCC, Input = ADC1
|
22 | break;
|
23 | default: // Fehler, ADC auf falschem Kanal
|
24 | calc = ADCH; // einmal lesen um ADC freizuschalten
|
25 | calc = calc; // Compiler-Warnung loswerden
|
26 | ADMUX = (1<<REFS0) | (1<<MUX0); // ADC1 als nächstes
|
27 | break;
|
28 | }
|
29 | ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // re-konfigurieren ohne zu starten, Wandlung wird mit Sleep gestartet
|
30 | }
|
31 |
|
32 | if(roundtrip == 0)
|
33 | {
|
34 | }
|
35 |
|
36 | if(roundtrip == 1)
|
37 | {
|
38 | }
|
39 |
|
40 | if(roundtrip == 2)
|
41 | {
|
42 | }
|
43 |
|
44 | if(roundtrip == 3)
|
45 | {
|
46 | }
|
47 |
|
48 | while(triplock == roundtrip) // verhindern, das IRQs den Controller wach machen
|
49 | {
|
50 | /* für den Rest der Zeit-Scheibe schlafen legen */
|
51 | cli();
|
52 | sleep_enable();
|
53 | sei();
|
54 | sleep_cpu();
|
55 | sleep_disable();
|
56 | }
|
57 | }
|
Dazu läuft bei mir ein Timer der den Controller alle 250µs aus dem
Schlaf holt und die Variable Roundtrip von 0-3 zählt, mit drei AD-Werten
wird also jeder Messwert alle 750µs aktualisiert.
Wenn einer der vier Blöcke einen der Werte braucht nimmt er einfach den
aktuellen.
Alternativ kann man auch einen ADC-Interrupt anlegen und dort die Daten
wegspeichern und den Kanal umstellen, damit würde man mehr Wandlungen
pro Sekunde machen können.
Da ich die Messwerte in aller Regel aber nicht so schnell brauche wie
der AD-Wandler sie selbst mit größtem Prescaler zur Verfügung stellen
kann und andererseits der AD-Interrupt sich mit der Nutzung des
Sleep-Modus ein wenig beisst, bevorzuge ich das wie oben dargestellt.