Forum: Compiler & IDEs Warum funktioniert das nicht? Mittelwert, AD_wandler


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Dirk S. (fusebit)


Lesenswert?

Moin Leute,

ich komme mit meinem Code nicht auf einen grünen Zweig. Wenn die Abfrage 
des AD-Wandlers nur einmal durchläuft, dann bekomme ich einen sinnvollen 
und schwankenden Wert. Daher möchte ich einige Werte mitteln, aber das 
klappt einfach nicht. Dann bekomme ich falsche Werte...
1
//TLC4545 Ansteuerung
2
int adc(void)
3
{
4
  unsigned int abfrage;
5
  //unsigned long int summe;
6
  
7
  //for(int k=0;k<64;k++)
8
  //{
9
    CLRBIT(PORTD,5);            //CS auf 0
10
    
11
    for(int i=0;i<16;i++)
12
    {
13
      SETBIT(PORTD,7);          //CLK auf 1
14
      asm volatile ("nop");
15
      asm volatile ("nop");
16
      asm volatile ("nop");
17
      asm volatile ("nop");
18
      asm volatile ("nop");
19
      asm volatile ("nop");
20
      asm volatile ("nop");
21
      asm volatile ("nop");
22
      asm volatile ("nop");
23
      CLRBIT(PORTD,7);          //CLK auf 0
24
      abfrage=(abfrage<<1);
25
      asm volatile ("nop");
26
      if (bit_is_set(PIND,6)) abfrage|=1;  //DATA abfragen
27
    }
28
    SETBIT(PORTD,5);            //CS auf 1
29
    //summe = summe + (unsigned long int) abfrage;
30
    //abfrage=0;
31
  //}
32
  //abfrage = (unsigned int) (summe/64);
33
  
34
  //summe=0;
35
  return(abfrage);
36
}

So funktioniert es, wenn ich das rauskommentierte aktiviere ergibt es 
Blödsinn :-(

von Magnus Müller (Gast)


Lesenswert?

Du summierst 16 "abfrage"-Werte und teilst die Summe dann durch 64? Du 
solltest mal versuchen durch 16 zu teilen.

By the way: kannst du "Blödsinn" etwas näher definieren?

Gruß,
Magnetus

von pumpkin (Gast)


Lesenswert?

Hallo,

dein Rückgabetyp der Funktion adc() ist nicht unbedingt kompatibel zu 
deiner Rechnung:
1
unsigned int adc(void) { /*...*/ }

Manchmal funktioniert das, manchmal nicht. Wie äußert sich 'Blödsinn' 
denn genau?

pumpkin

von Magnus Müller (Gast)


Lesenswert?

Oh shit... hab mich da im Code vertan... Du summierst ja 64 
"abfrage"-Werte a 16Bit... mein Fehler ;)

von Dirk S. (fusebit)


Lesenswert?

@Magnus
Nein, weiter oben ist die 64er Schleife. Die 16er Schleife ist das 
Bitweise abfragen des ADC.

@pumpkin
Das werde ich mal ändern!

Definition Blödsinn:
Der ausgegeben Wert ist deutlich zu hoch. Es liegt von Drucksensor etwa 
4,03 V an. Mit einfacher Wandlung passt der Wert sehr gut. Mit 
Mittelwertbildung liege ich bei 4,2 V.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Schreib doch mal Deine gemessenen Werte in ein Array und sieh Dir den 
Inhalt dieses Arrays an - vielleicht erkennst Du dann, woran es bei der 
Mittelwertbildung scheitert.

von pumpkin (Gast)


Lesenswert?

Mmmmh, ist schwierig zu sagen. Mein Gedanke ist z.Zt., dass der Wandler 
evtl. etwas zu schnell beackert wird:
1
CLRBIT(PORTD,5);            //CS auf 0
2
    
3
for(int i=0;i<16;i++)
4
{
5
6
// ...

Du sagst 'wandle!' und holst sofort deine Daten ab. Was für einen 
Wandler nutzt du (Flash, Sigma-Delta, Approx, ...)? Deine 
Shiftregisterkonstruktion scheint ja zu funktionieren.

pumpkin

von Magnus Müller (Gast)


Lesenswert?

> Du sagst 'wandle!' und holst sofort deine Daten ab. Was für einen
> Wandler nutzt du (Flash, Sigma-Delta, Approx, ...)? Deine
> Shiftregisterkonstruktion scheint ja zu funktionieren.

Er benutzt scheinbar einen TLC4545 (siehe Beginn des Codes)
1
//TLC4545 Ansteuerung
2
int adc(void)
3
{

Gruß,
Magnetus

von Dirk S. (fusebit)


Angehängte Dateien:

Lesenswert?

Das ist ein TLC4545, 200 kSPS.

Der AVR läuft mit 8 MHz, wie bekomme ich denn raus wie lange der AVR für 
das aufsummieren benötigt? Das muss ich wohl mal das genaue Timing 
zwischen den Wandlungen berechnen...

von pumpkin (Gast)


Lesenswert?

Ok, hab' es nicht gesehen. Das Datenblatt sagt ~17ns nach /CS und ~3µs 
conversion time. Guck dir mal das datasheet auf Seite 12 (conversion) 
an. Dort wird beschrieben wie man ungültige Ergebnisse erkennt.

pumpkin

von Magnus Müller (Gast)


Lesenswert?

Du solltest dir das Datenblatt nochmal genauer ansehen. Speziell ab 
Seite 12 "Principles of Operation". Siehe Anhang.
1
sampling
2
3
The converter sample time is 20 SCLKs in duration, beginning on the 5th
4
SCLK received during an active signal on the CS input (or FS input for
5
the TLC4541.)
6
7
conversion
8
9
Each device completes a conversion in the following manner. The
10
conversion is started after the 24th falling SCLK edge. The CS input
11
can be released at this point or at any time during the remainder of
12
the conversion cycle. The conversion takes a maximum of 2.94 μs to
13
complete. Enough time (for conversion) should be allowed before the
14
next falling edge on the CS input (or rising edge on the FS input for
15
the TLC4541) so that no conversion is terminated prematurely. If the
16
conversion cycle is terminated early, the data presented on SDO during
17
the following cycle is FF00h. This predefined output code is helpful in
18
determining if the cycle time is not long enough to complete the
19
conversion. The same code is also used to determine if a reset cycle
20
is valid.
21
22
For all devices, the SDO data presented during a cycle is the result of
23
the conversion of the sample taken during the previous cycle. The
24
output data format is shown in the following table.

von pumpkin (Gast)


Lesenswert?

>> Der AVR läuft mit 8 MHz, wie bekomme ich denn raus wie lange der AVR für
>> das aufsummieren benötigt?

Im Debug kannst du dir die clock cycles anschauen (irgendwo linkes 
Fenster, Unterpunkt CPU wenn ich mich recht entsinne). Eine 'Stoppuhr' 
ist auch eingebaut, aber die braucht das richtige #define F_CPU (auch im 
makefile?!?).

pumpkin

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Gibt's eigentlich einen Grund, warum du nicht die SPI-Hardware
benutzt?

Je nach Taktfrequenz kann 3 µs lang genug sein, als dass es sich lohnt,
das nächste Auslesen mit einem Timer anzustoßen.

von yalu (Gast)


Lesenswert?

Die Initialisierung
1
  summe = 0;
sollte am Anfang der Routine stehen, nicht am Ende. Dort ist sie 
unwirksam.

von pumpkin (Gast)


Lesenswert?

Habe es gerade einmal durchgerechnet. Angenommen du verwendest das 
fehlerhafte Wort 0xFF00 63 mal zur Mittelwertbildung, dann rutscht dein 
Wert gegen ~4,95V (Referenz 5V). Wahrscheinlich sind nicht alle Werte 
fehlerhaft, so dass dein leicht erhöhter Wert plausibel scheint. Ist nur 
eine Möglichkeit, aber die würde ich erstmal abklopfen.

pumpkin

von Dirk S. (fusebit)


Lesenswert?

Vielen Dank erstmal! Ich werde mal ein paar nops einfügen und sehen ob 
es klappt.

Leider muss ich wohl erstmal den SMD-Mega auslöten und ersetzen, er wird 
plötzlich nicht mehr erkannt und das obwohl ich nichts an den Fuses 
gemacht habe. So ein Mist...

von Frank J. (frajo)


Lesenswert?

Wenn Du 64 Messungen aufsummierst und dann durch 64 dividierst 
vergrößerst Du den Fehler. Das nieder-niederwertigste Bit (das unter 
Bit0) könnte bei jeder Messung 0 oder 1 sein da der zu messende Wert ja 
analog vorliegt. Statistisch gesehen also 32 mal 0 und 32 mal 1. Addiere 
vor der Division durch 64 noch die Hälfte der Anzahl der Messungen (32), 
und Du gleichst diesen Fehler wieder aus.

von Dirk S. (fusebit)


Lesenswert?

Kurze Rückmeldung:

Manchmal hilft halt Däumchendrehen. Ein paar Nopse eingefügt und schon 
stimmt der Wert.

Die 32 addiere ich jetzt auch noch hinzu.


Vielen Dank an Alle...

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.