Forum: Mikrocontroller und Digitale Elektronik Mal wieder ADC Mittelwert


von Sebastian S. (audionaut)


Lesenswert?

Hallo liebe Leute.
Ich weiß dieses Thema gibts hier schon oft. Aber ich stehe irgendwie 
gerade voll auf'm Schlauch.
Der Betreff sagt's ja schon. Und die ADCResult auf dem LCD funktioniert 
auch von 0-1023 wie sie soll. Doch sobald ich die Mittelwertberechnung 
mache geht die Zahl nur noch von 0-255 und das dann eben 4 mal 
nacheinander.
Bin mir auch nicht sicher ob das vom Timing her überhaupt passt. Denn 
die Mittelwertberechnung zieht sich ja unabhängig vom ADC den ADCResult 
wert. Aber ich komm da auch nich drauf wie man das am Besten koppeln 
könnte...

Habt ihr vielleicht ne fuchsige Idee?
1
#define F_CPU 8000000UL            // 8 MHz-Takt
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <stdlib.h>
6
#include <avr/delay.h>
7
#include "lcd-routines.h"
8
9
int i;
10
uint16_t ADCMittel=0;
11
char ADCString[4];
12
uint16_t ADCResult;
13
14
int main ()
15
{  
16
lcd_init();                    // Initialisierung des LCD    
17
lcd_string("ADC Result:");
18
                  
19
//////ADC Einstellen
20
ADMUX  = 0b01000000;              //Interne Referenz = AVCC - Rechtsbündig - Pin ist PC0
21
ADCSRA = 0b10001110;              //ADEN, ADIE, Geschwidigkeit des ADC festlegen 125kHz, Vorteiler 64 - Interrupt - ADC einschalten
22
  
23
sei();                      //Set interrupt enable
24
  
25
ADCSRA |= 1<<ADSC;                //Starte Messung
26
  
27
  while(1)
28
  {
29
  //////ADC MITTELWERT
30
    
31
    for (i=0;i<256;i++)
32
    {      
33
    ADCMittel=ADCMittel+ADCResult;      //Aufsummieren
34
    }
35
          
36
    if (i=256)
37
    {
38
    ADCMittel=ADCMittel/256;        //Mittelwert bilden
39
    
40
    //ADCmittel = ADCmittel;        //Umrechnung für PT100
41
42
    itoa(ADCMittel, ADCString, 10 );    //Umwandlung
43
    lcd_setcursor(12,1);          //Ausgabe
44
    lcd_string(ADCString);
45
    lcd_string("    ");
46
    _delay_ms(100);
47
    }    
48
  }    
49
  
50
}
51
ISR (ADC_vect)                  //Interrupt routine: ADC
52
{                
53
54
uint8_t lowADC = ADCL;              //Lese unteres Byte ADC
55
ADCResult = ADCH<<8 | lowADC;          //Schiebe oberes ADC-Byte 8 nach links und füge unteres Byte hinzu
56
57
ADCSRA |= 1<<ADSC;                //Starte eine Messung
58
}

von Norbert (Gast)


Lesenswert?

Wieviele 10Bit ADC Werte kann man denn in einem unsigned int16 
unterbringen?

von Ingo (Gast)


Lesenswert?

Du hast einen überlauf ...

von Hunt W. (hunt_work_er)


Lesenswert?

Warum "if (i=256)..." in deiner while(1)?

von Sebastian S. (audionaut)


Lesenswert?

2^16=65535
2^10=1023

65535/1023=64,...

Ah ok. Also passen maximal 64 Werte rein ja?

von Sebastian S. (audionaut)


Lesenswert?

Hunt Worker schrieb:
> Warum "if (i=256)..." in deiner while(1)?

Um die Mittelwertberechnung erst dann zu starten wenn dementsprechend 
viele Werte gespeichert wurden.

Ok mit den 64 Werten klappt's schonmal. 4 Augen sehen einfach mehr als 
zwei...

Aber mit dem Timing bin ich mir mir halt echt nicht sicher.

von Spess53 (Gast)


Lesenswert?

Hi

>    for (i=0;i<256;i++)
>    {
>    ADCMittel=ADCMittel+ADCResult;      //Aufsummieren
>    }

Woher weiß dein Controller daß ein neuer Wert vorliegt? In der Zeit, in 
der die Schleife abgearbeitet wird dürften max. 1 bis zwei Messungen 
ablaufen.

MfG spess

von Karl H. (kbuchegg)


Lesenswert?

Sebastian Schubert schrieb:
> Hunt Worker schrieb:
>> Warum "if (i=256)..." in deiner while(1)?
>
> Um die Mittelwertberechnung erst dann zu starten wenn dementsprechend
> viele Werte gespeichert wurden.

SChön.
Dazu brauchst du aber einen Vergleich.
Du hast aber keinen Vergleich geschrieben, sondern eine Zuweisung.
(Und die Compilerwarnung ignoriert)

von Karl H. (kbuchegg)


Lesenswert?

Spess53 schrieb:
> Hi
>
>>    for (i=0;i<256;i++)
>>    {
>>    ADCMittel=ADCMittel+ADCResult;      //Aufsummieren
>>    }
>
> Woher weiß dein Controller daß ein neuer Wert vorliegt? In der Zeit, in
> der die Schleife abgearbeitet wird dürften max. 1 bis zwei Messungen
> ablaufen.

Jep.

@Sebastian
In einer Anwendung wie dieser bringt der ganze Interrupt-Quatsch nichts.
Machs klassisch konventionell und gut ists. Wandlung starten, Warten bis 
sie fertig ist, auslesen. Und das in einer Schleife 64 mal. Und am 
besten gleich ab in eine eigene Funktion damit.(*)

Mit deinem Interrupt Ansatz handelst du dir mehr Probleme ein, als dir 
lieb ist. Zb. dass man eine ISR-main gesharte Variable volatile machen 
muss und wenn es sich um was größeres als einen uint8_t handelt, dann 
musst du auch noch für atomares Auslesen sorgen.

(*) womit wir genau bei den im AVR-GCC-Tutorial beschriebenen Funktionen 
wären.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Sebastian Schubert schrieb:
>> Hunt Worker schrieb:
>>> Warum "if (i=256)..." in deiner while(1)?
>>
>> Um die Mittelwertberechnung erst dann zu starten wenn dementsprechend
>> viele Werte gespeichert wurden.
>
> SChön.
> Dazu brauchst du aber einen Vergleich.
> Du hast aber keinen Vergleich geschrieben, sondern eine Zuweisung.
> (Und die Compilerwarnung ignoriert)

Im übrigen ist das Quatsch.
Welchen Wert soll denn i nach diesem Konstrukt
1
int i;
2
3
...
4
    for (i=0;i<256;i++)
5
    {      
6
    ADCMittel=ADCMittel+ADCResult;      //Aufsummieren
7
    }
8
          
9
    if (i=256)

sonst haben, ausser 256?
Die for-Schleife wurde beendet, WEIL i bei der Zählerei den Wert 256 
erreicht hat! Das muss man nicht testen.

von Sebastian S. (audionaut)


Lesenswert?

Ach mist stimmt da muss eigentlich ein == hin... Kein Wunder...
Danke für die Erleuchtung!

Aber das ganze ohne Interrupt zu machen werde ich dann auch nochmal 
überdenken. Danke für eure Hilfe! =)

von Karl H. (kbuchegg)


Lesenswert?

Sebastian Schubert schrieb:
> Ach mist stimmt da muss eigentlich ein == hin... Kein Wunder...
> Danke für die Erleuchtung!
>
> Aber das ganze ohne Interrupt zu machen werde ich dann auch nochmal
> überdenken. Danke für eure Hilfe! =)


AVR-GCC-Tutorial/Analoge Ein- und Ausgabe: Nutzung des ADC

Die Funktion, die du benutzen willst, nennt sich ADC_Read_Avg()

von phantom (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Welchen Wert soll denn i nach diesem Konstrukt
> ...
> sonst haben, ausser 256?
> Die for-Schleife wurde beendet, WEIL i bei der Zählerei den Wert 256
> erreicht hat! Das muss man nicht testen.

Sebastian Schubert schrieb:
> Ach mist stimmt da muss eigentlich ein == hin... Kein Wunder...
> Danke für die Erleuchtung!

Sorry, aber da musste ich schon ein wenig schmunzeln.

Mal abgesehen davon, dass du "=" und "==" vertauscht hast(passiert jedem 
mal) hat "i" nach dieser for-Schleife immer den Wert 256.
Wahrscheinlich ist der Compiler so intelligent, und optimiert den 
Vergleich mit raus.
Der Code wäre zu jetzigem äquivalent auch ohne if-Abfrage...

von Sebastian S. (audionaut)


Lesenswert?

Ok also ich werde das Programm jetzt mit der ADC_Read_Avg() nochma neu 
bauen. Das is wirklich das Einfachste und wenn man diesen Ablauf in ein 
ADC.c oderso schreibt kann man den Readout ja auch in zwei Zeilen 
abhaken. Danke Karl Heinz Buchegger =)

Muss auch dazu sagen, dass das mein erstes richtiges Projekt is. Bin 
gerade mit den Gundsachen wie Taster, LED und LCD durch und wollte jetzt 
eben mal was umsetzen.

Also nochma danke an alle Helfer und nen schönen nichtmehr ganz so 
extrem heißen Tag! =)

von Timbo (Gast)


Lesenswert?

ist sowas mit arrays nicht weniger Fehleranfällig?

von eProfi (Gast)


Lesenswert?

Außerdem hast Du vergessen, das ADC-Mittel vor der for-Schleife auf Null 
zu setzen.

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.