Forum: Mikrocontroller und Digitale Elektronik ADC Ergebnisse Addieren


von Michael D. (Gast)


Angehängte Dateien:

Lesenswert?

Nabend.

Ich habe das Problem das die Ergebnisse des ADC nicht Addiert werden.

Sprich:

Im Programm messe ich 5mal und Addiere das Ergebniss dann immer auf die 
Variable "Summe".
Nach dem ich 5mal gemessen habe übertrage ich einmal das Ergebniss des 
Addition sowie das Ergebniss der letzten Wandlung im Low Register des 
ADC (Werte nicht größer gleich 256).

Nun mein Problem:
Ich bekomme als Ergebniss der Addition immer nur das Ergeniss "einer" 
Wandlung übertragen, und nicht wie gewünscht ungefähr das fünffache 
einer Wandlung.


Code ist im Anhang, kann jemand einen Fehler in meiner Denkweise / 
Ausführung erkennen?

von Karl H. (kbuchegg)


Lesenswert?

Machs nicht kompliziert

    Summe += ADCW;

und gut ists mit der Addition.

von Karl H. (kbuchegg)


Lesenswert?

Darf man fragen, warum du den ADC nicht einfach in der ISR ausliest? 
Dort wäre es am allereinfachsten.
ADC auslesen und zur Summe aufaddieren. Nach jeweils 5 Messungen wird 
die Summe in einer globalen Variablen für das Hauptprogramm 
bereitgestellt, und das Spiel beginnt beim nächsten ISR Aufruf von 
vorne.


-> die main() hat zu jedem beliebigen Zeitpunkt in einer Variablen 
'Summe' den letzten bekannten Messwert, der über 5 Messperioden 
realisiert wurde. Und 'magisch' aktualisiert sich die laufend, wenn 
wieder 5 Messungen gemacht wurden.

1
ISR(ADC_vect)
2
{
3
  static uint16_t SummeNeu = 0;
4
  static uint8_t  Messungen = 0;
5
6
  SummeNeu += ADCW;
7
8
  Messungen++;
9
  if( Messungen == 5 )
10
  {
11
    Summe = SummeNeu;
12
    SummeNeu = 0;
13
    Messungen = 0;
14
15
    Flag = 1;
16
  }
17
}

von Thomas E. (thomase)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Darf man fragen, warum du den ADC nicht einfach in der ISR ausliest?
> Dort wäre es am allereinfachsten.
Weil irgendwelche Hampel das zum Dogma erklären und ständig postulieren.
"Flag setzen und in der main abarbeiten."

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Thomas Eckmann schrieb:
> Karl Heinz Buchegger schrieb:
>> Darf man fragen, warum du den ADC nicht einfach in der ISR ausliest?
>> Dort wäre es am allereinfachsten.
> Weil irgendwelche Hampel das zum Dogma erklären und ständig postulieren.
> "Flag setzen und in der main abarbeiten."

(mehr an den TO gerichtet)

Was ja als grobe Richtlinie ja auch nicht schlecht ist. Aber wie bei 
allen Richtlinien gilt: Es sind nur Richtlinien, die die grobe Richtung 
vorgeben. Im Einzelfall, solange man sich im Rahmen dessen bewegt was 
mit der Richtlinie erreicht werden soll, kann man durchaus auch davon 
abweichen.
-> Man muss darüber nachdenken, warum es diese Richtlinie überhaupt 
gibt. Was ist es, was diese Richtlinie verhindern soll?

Und hier stellt sich eben raus: Die Richtlinie soll bewirken, dass ISR 
den Gesamtprozess nicht übermässig aufhalten. Exzessive Berechnungen 
oder gar Warten ist in einer ISR ein No-No. Aber ein bischen was darf 
man schon in einer ISR tun. Vor allen Dingen dann, wenn dadurch das 
Komplettprogramm einfacher wird.
2 Additionen sind nicht die Welt, die halten den µC nicht auf. Das ist 
nichts, weswegen man sich eine komplizierte Steuerung in der main() 
aufzwirbelt.

von Karl H. (kbuchegg)


Lesenswert?

1
ISR(TIMER2_OVF_vect) {  
2
     set_sleep_mode(SLEEP_MODE_ADC);
3
     sei();
4
     sleep_mode();
5
          
6
}

Ein sleep in einer ISR?
Keine gute Idee!
AUch dann nicht, wenn du einen sei() gemacht hast.


Wozu soll das gut sein? Braucht doch kein Mensch!
der sleep_mode() kommt in die Hauptschleife in main(). Und zwar nur dort 
hinein. WEnn es nichts mehr zu tun gibt, dann legt die main() den µC 
schlafen. Und nur die main().

von Karl H. (kbuchegg)


Lesenswert?

1
    ADMUX= 1<<REFS1 | 1<<REFS0 | 0<<ADLAR | 0<<MUX0 | 0<<MUX1 | 0<<MUX2 | 0<<MUX3;
2
     ADCSRA= 1<<ADEN | 0<<ADSC | 0<<ADFR | 1<<ADIF | 1<<ADIE | 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0;

Ich war eigentlich ursprünglich, beim schnellen Drüberlesen über den 
Code, davon ausgegangen, dass der Timer Interrupt immer wieder den ADC 
anstösst. Dem ist aber nicht so. Daher:

Wo wird der ADC eigentlich mal gestartet? Was überseh ich da? Laut ADC 
Konfiguration ist der ADC nicht auf Free-Running und ich sehe auch sonst 
nichts, wo der ADC angestossen werden würde. Im Moment würde ich sagen: 
du misst überhaupt nichts.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
>
1
>     ADMUX= 1<<REFS1 | 1<<REFS0 | 0<<ADLAR | 0<<MUX0 | 0<<MUX1 | 0<<MUX2
2
> | 0<<MUX3;
3
>      ADCSRA= 1<<ADEN | 0<<ADSC | 0<<ADFR | 1<<ADIF | 1<<ADIE | 1<<ADPS2
4
> | 1<<ADPS1 | 1<<ADPS0;
5
> 
6
>
>
> Ich war eigentlich ursprünglich, beim schnellen Drüberlesen über den
> Code, davon ausgegangen, dass der Timer Interrupt immer wieder den ADC
> anstösst. Dem ist aber nicht so. Daher:
>
> Wo wird der ADC eigentlich mal gestartet? Was überseh ich da? Laut ADC
> Konfiguration ist der ADC nicht auf Free-Running und ich sehe auch sonst
> nichts, wo der ADC angestossen werden würde. Im Moment würde ich sagen:
> du misst überhaupt nichts.

Ah. Das hier hab ich übersehen
1
SLEEP_MODE_ADC
2
3
If the ADC is enabled, a conversion starts automatically when this mode is entered.

OK.
Dann vergiss bitte meine Einwände von wegen Sleep und ADC.
Also ist es doch so, dass der Timer den ADC triggert.

von Thomas E. (thomase)


Lesenswert?

> ISR(TIMER2_OVF_vect) {
>      set_sleep_mode(SLEEP_MODE_ADC);
>      sei();
>      sleep_mode();
> }

Karl Heinz Buchegger schrieb:
> Dann vergiss bitte meine Einwände von wegen Sleep und ADC.
> Also ist es doch so, dass der Timer den ADC triggert.
Naja. Die Nackenhaare stellen sich aber schon auf, wenn man sowas sieht.
1
ISR(TIMER2_OVF_vect) 
2
{   
3
  set_sleep_mode(SLEEP_MODE_ADC);
4
}
5
6
ISR(ADC_vect)
7
{
8
  //Tu was...
9
  set_sleep_mode(SLEEP_POWER_SAVE);
10
}
11
12
int main(void)
13
{
14
//Init
15
   while(1)
16
   {
17
     sleepmode();
18
     if(Flag)
19
     {
20
       //Tu was...
21
     }
22
   }
23
}


mfg.

von Michael D. (etzen_michi)


Lesenswert?

Werde das mit dem "ADCW" sowie dem Addieren in der ISR heute Abend mal 
testen.
Das mit dem "ADCW" wusste ich nicht, werde mal das Datenblatt nochmal 
durchsuchen.

@Thomas Eckmann
Ich glaueb du verstehst das falsch:

ISR Timer2
Starte ADC Wandlung sobald 1sec abgelaufen ist

ISR ADC
Setzte Flag das Wandlung abgeschlossen

Main
Zähle Wandlungen und Addiere Ergebnisse.
Bei xWandlungen sende Ergebniss, und setze Register mit Ergebniss zurück
Gehe schlafe, bis sich der Timer2 wieder meldet, das die nächste Sekunde 
abgelaufen ist.

von Karl H. (kbuchegg)


Lesenswert?

Michael D. schrieb:
> Werde das mit dem "ADCW" sowie dem Addieren in der ISR heute Abend mal
> testen.
> Das mit dem "ADCW" wusste ich nicht, werde mal das Datenblatt nochmal
> durchsuchen.

Das findest du auch nicht im Datenblatt.
Das ist ein Service, den dir der GCC anbietet. Auf die meisten 
Pseudo-16-Bit Register, die in Hardware aus einem Low-Teil und einem 
High-Teil bestehen, kannst du im GCC ganz einfach zugreifen, als ob das 
ein 16 Bit Register wäre.

  OCR1A = 56734;

was kümmert mich, dass das in Wirklichkeit 2 Register sind? Dafür hab 
ich doch einen Compiler, dass sich der um so einen Kleinkram kümmert.

von Karl H. (kbuchegg)


Lesenswert?

Michael D. schrieb:

> Ich glaueb du verstehst das falsch:
>
> ISR Timer2
> Starte ADC Wandlung sobald 1sec abgelaufen ist
>
> ISR ADC
> Setzte Flag das Wandlung abgeschlossen

Es ist trotzdem Quatsch.
Gewöhn dir an, dass es nur eine Stelle gibt, an der der µC in den Sleep 
geschickt wird. Und das ist meistens am Ende der Hauptschleife in 
main().

> Bei xWandlungen sende Ergebniss, und setze Register mit Ergebniss zurück
> Gehe schlafe, bis sich der Timer2 wieder meldet

Es genügt völlig, wenn der Timerinterrupt die Hauptschleife aus dem 
Sleep holt.

von Thomas E. (thomase)


Lesenswert?

Michael D. schrieb:
> @Thomas Eckmann
> Ich glaueb du verstehst das falsch:
Nein.

Ein "sleep" gehört an eine Stelle ins Programm. Und zwar ins 
Hauptprogramm, wo die Interrupts frei sind und man nicht auf 
Hackermethoden, wie ein "sei" in einer ISR angewiesen ist.
Sowas ist grundsätzlich ein misratenes Design.

mfg.

von Michael D. (etzen_michi)


Lesenswert?

Bin nun wieder am µC aber nur noch stärker verwirrt.


1. Habe die Zählung der Messungen in die ISR des ADC genommen (Bekomme 
ungleichmäßig Werte übermittelt).

2. Habe die Zählung komplett ausgesetzt und Summe=123 in die ISR des ADC 
geschrieben (Bekomme immer 123 ausgegeben).

3. Habe die Zählung ausgesetzt und in die ISR des ADC fest 
reingeschrieben "Summe+=123;" (Bekomme unterschiedliche Werte, aber 
immer 123 oder ein vielfaches).

4. Habe den Inhalt der ISR des Timer2 durch "ADCSRA|= 1<<ADSC;" ersetzt 
(Bekomme immer 123 übermittelt, aber der aus ADCL ausgelesene Wert wird 
nicht aktualisiert).

5. Habe "temp=ADCH;" in die ISR des ADC eigefügt, keine Änderung.

. Habe den Inhalt der ISR des Timers wieder so gemacht wie sie war und 
die Stelle "Summe=0;" nach dem Übertragen der Summe und vor der 
Übertragung des letzten Messwertes geschrieben (Letzter Messwert wird 
richtig Angezeigt und auch aktualisiert. Summe weiterhin 123 oder ein 
vielfaches).


Wenn ich das richtig erkenne funktioniert irgendwas mit dem auf Null 
setzen des Wertes "Summe" nicht.
Volatile ist dieser.

von Michael D. (etzen_michi)


Angehängte Dateien:

Lesenswert?

15Minuten sind vorbei ...


7. Habe "Summe=0;" vor "Summe+=123;" gesetzt (Werte werden richtig 
ausgegeben).


.lss:
1
               Summe=0;
2
 4c2:  10 92 67 00   sts  0x0067, r1
3
 4c6:  10 92 66 00   sts  0x0066, r1
1
Summe=0;
2
 50a:  10 92 67 00   sts  0x0067, r1
3
 50e:  10 92 66 00   sts  0x0066, r1


Beide Löschungen werden in der .lss aber gleich ausgeführt ....


Was ggf. noch interessant sein könnte:
Die Daten kommen regelmäßig, aber die Höhe des Wertes springt, z.B. nach 
2x ein 10x und nicht 2x, 3x, 4x ...

von Michael D. (etzen_michi)


Lesenswert?

Nochmal ich... Fehler gefunden .. Ursach noch unbekannt.


Die AD Wandlung läuft mehrmals durch!

Habe vor dem Starten der Wandlung gesagt "temp=1" und beim auslesen
1
if(temp) { 
2
 Summe+= ADCW;
3
 temp=0;
4
}

Nun bekomme ich zweimal fast den gleichen Wert zurück.
Der Wert, welcher hier gespeichert wird, hängt dem welcher später aus 
ADCL ausgelesen wird nach.


Nun wo ich wohl nicht weiter komme (werde natürlich nebenbei weiterhin 
Datenblatt studieren):

- Warum macht der ADC mehr als eine Wandlung, obwohl ADFR nicht gesetzt 
ist?

- Warum wird der Wert des ADC nicht aktualisiert, wenn ich die Wandlung 
manuell starte und das ADCH Register auslese?

von Michael D. (etzen_michi)


Lesenswert?

Push

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.