Forum: Mikrocontroller und Digitale Elektronik Anfänger ADC Frage


von ADC_Anfänger (Gast)


Lesenswert?

Hallo,

ich bin ein Anfänger in Sachen µC und beschäfitge mich gerade mit dem 
ADC Wandler.
Simpler Versuchsaufbau:
Attiny44 an ADC0 ein 10k Poti als Spannungsteiler (max. VCC), um dort 
eine Spannung drauf zu geben.
Als Referenzspannung wurde VCC gewählt (geht beim Attiny44). Wenn ich 
mit dem Multimeter messe, liegt am Attiny44 VCC=4,73V an. Diese werden 
aus 12V mit einem 7805 erzeugt.
Ich habe nun ein einfaches Programm mit dem angepassten Sourcecode aus 
dem Tutorial geschrieben (Mittelwertbildung aus 4 Ergebnissen).
Die Funktion habe ich readADCWert genannt.
Nun rechne ich diese in mV um und prüfe testweise, ob bei einer Spannung 
< 2500mV auch eine LED angeht.
Nun geht diese LED aber schon bei gemessenen 2,37V an. Liegt das daran, 
dass die Referenzspannung nur gemessen 4,73V ist? Oder warum ist der ADC 
"so ungenau"? Wenn ich mit dem Taschenrechner rechne und nehme anstelle 
von 5V V_Ref nur 4,73V, käme ich auf 2,365V, ws den gemessenen 2,37V 
sehr Nahe kommt.

Sourcecode:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>      
5
#include <inttypes.h>
6
#ifndef F_CPU
7
#define F_CPU           8000000UL                   // processor clock frequency 8Mhz
8
#endif
9
#define Referenzspannung    5          // 5 Volt Referenzspannung
10
#define LED                 PA1        // Pin LED active low
11
12
int main(void){
13
//variablen für das Programm
14
uint16_t ADCWert;            // ADC-Wert in ADC Skalierung 0...1024
15
uint16_t ADCWertmV;            // ADC-Wert in milli Volt
16
17
uint16_t readADCWert (uint8_t mux);      // Liest den ADC-Wert ein und gibt den Wert zurück
18
19
DDRA = 0x00;
20
DDRA |= (1 < <DDA1);
21
PORTA |= (1 << LED);
22
ADCWert = readADCWert (0);                // liest den eingestellten ADC-Wert ein an ADC0 = PA0 ein
23
  ADCWertmV = ( (uint32_t) ADCWert*Referenzspannung*1000)/1024;    // Umrechnung des ADC-Wertes in mV (Faktor 1000)
24
  if (ADCWertmV >= 2500){
25
    PORTA &= ~( 1 << LED );    // LED einschalten
26
    for (y=0; y < 10; y++)
27
        {
28
            _delay_ms(100);
29
        }
30
    PORTA |= ( 1 << LED );    // LED einschalten
31
  }
32
}
33
34
// Funktion readADCWert
35
36
int16_t readADCWert (uint8_t mux) {
37
38
  uint8_t i;                    // Schleifenzähler 
39
  uint16_t result;              
40
41
  ADMUX = mux;                 
42
  ADMUX &= (~(1<<REFS1) | (1<<REFS0));       // VCC als Ref
43
 
44
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS2);  // ADC wird aktiviert, Vorteiler wird eingestellt
45
                               
46
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
47
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
48
   
49
  ADCSRA |= ( 1 << ADSC );                   // startet eine ADC-Wandlung 
50
  while ( ADCSRA & (1<<ADSC) ) {
51
    ;                         // auf Abschluss der Konvertierung warten, 
52
  }
53
  result = ADCW;                    // ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen.
54
 
55
  /* Eigentliche Messung */
56
  result = 0;                     // Dummy Readout Messwert verwerfen und result zu 0 setzen für neue Messung
57
  
58
  for( i=0; i<4; i++ ){        // Schleife für 4 aufeinanderfolgende Werte die in result zunächst aufaddiert werden
59
    ADCSRA |= (1<<ADSC);                   // eine Wandlung "single conversion" startet
60
    while ( ADCSRA & (1<<ADSC) ){
61
      ;                     // auf Abschluss der Konvertierung warten
62
    }
63
    result += ADCW;                    
64
  }
65
  ADCSRA &= ~(1<<ADEN);                     // ADC deaktivieren
66
  result /= 4;                       // Summe durch 4 teilen = arithm. Mittelwert
67
68
  return result;                  
69
}

Achja, noch eine Frage: Ich habe gemerkt, dass es ohne diesen cast gar 
nicht geht:
1
ADCWertmV = ( (uint32_t) ADCWert*Referenzspannung*1000)/1024;
Ich hatte Anfangs die Variable ADCWertMV als uint32_t deklariert ohne 
cast. Das ging aber nicht. Kann mir das jemand erklären?

von Heiko (Gast)


Lesenswert?

ADC_Anfänger schrieb:
> Nun geht diese LED aber schon bei gemessenen 2,37V an. Liegt das daran,
> dass die Referenzspannung nur gemessen 4,73V ist?

Ja. Schau mal ins Datenblatt, da steht sowas drin wie ADC_Wert = V_Ref * 
1023 / V_Mess.

ADC_Anfänger schrieb:
> Achja, noch eine Frage: Ich habe gemerkt, dass es ohne diesen cast gar
> nicht geht:
>
1
ADCWertmV = ( (uint32_t) ADCWert*Referenzspannung*1000)/1024;
> Ich hatte Anfangs die Variable ADCWertMV als uint32_t deklariert ohne
> cast. Das ging aber nicht. Kann mir das jemand erklären?

Es wird zuerst gerechnet, dann zugewiesen. Und beim Rechnen werden nach 
bestimmten Regeln alle Operanden auf den gleichen Datentyp gebracht, 
nämlich den größten, den einer der Operanden hat, mindestens aber int. 
Konstanten haben dabei einen Typ, in den ihr Wert möglichst genau 
hineinpasst (wimre, für Details such dir den C-Standard...).

Außer bei der Promotion auf int werden aber auch keine größeren 
Datentypen verwendet als einer der Operanden hat.

Auf dem AVR hat int nun nur 16 Bit. ADCWert ist ein uint16_t, 
Referenzspannung sogar nur ein uint8_t (Konstante), 1000 und 1024 passen 
ebenfalls in 16 Bit. Also wird alles in 16 Bit gerechnet.

Mit dem Typecast wird ADCWert auf 32 Bit aufgeblasen, also werden auch 
alle anderen Operanden promotet und es wird mit 32 Bit gerechnet.

MfG, Heiko

von Micha H. (mlh) Benutzerseite


Lesenswert?

ADC_Anfänger schrieb:
> Nun geht diese LED aber schon bei gemessenen 2,37V an. Liegt das daran,
> dass die Referenzspannung nur gemessen 4,73V ist? Oder warum ist der ADC
> "so ungenau"? Wenn ich mit dem Taschenrechner rechne und nehme anstelle
> von 5V V_Ref nur 4,73V, käme ich auf 2,365V, ws den gemessenen 2,37V
> sehr Nahe kommt.

Du kennst ja die Lösung schon.

Es heißt deshalb Referenzspannung, weil sich die Messung darauf bezieht.
Oder anders betrachtet, wenn Du genau 2500mV messen willst, brauchst Du 
auch eine genaue Referenzspannung, nicht mehr oder weniger irgendwas um 
die 5V.

Alternativ kannst Du in Deine Umrechnung freilich auch 4,73V als 
Referenz einsetzen, dann stimmts wieder, jedenfalls solange die 4,73V 
konstant bleiben.

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.