mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Anfänger ADC Frage


Autor: ADC_Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>      
#include <inttypes.h>
#ifndef F_CPU
#define F_CPU           8000000UL                   // processor clock frequency 8Mhz
#endif
#define Referenzspannung    5          // 5 Volt Referenzspannung
#define LED                 PA1        // Pin LED active low

int main(void){
//variablen für das Programm
uint16_t ADCWert;            // ADC-Wert in ADC Skalierung 0...1024
uint16_t ADCWertmV;            // ADC-Wert in milli Volt

uint16_t readADCWert (uint8_t mux);      // Liest den ADC-Wert ein und gibt den Wert zurück

DDRA = 0x00;
DDRA |= (1 < <DDA1);
PORTA |= (1 << LED);
ADCWert = readADCWert (0);                // liest den eingestellten ADC-Wert ein an ADC0 = PA0 ein
  ADCWertmV = ( (uint32_t) ADCWert*Referenzspannung*1000)/1024;    // Umrechnung des ADC-Wertes in mV (Faktor 1000)
  if (ADCWertmV >= 2500){
    PORTA &= ~( 1 << LED );    // LED einschalten
    for (y=0; y < 10; y++)
        {
            _delay_ms(100);
        }
    PORTA |= ( 1 << LED );    // LED einschalten
  }
}

// Funktion readADCWert

int16_t readADCWert (uint8_t mux) {

  uint8_t i;                    // Schleifenzähler 
  uint16_t result;              

  ADMUX = mux;                 
  ADMUX &= (~(1<<REFS1) | (1<<REFS0));       // VCC als Ref
 
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS2);  // ADC wird aktiviert, Vorteiler wird eingestellt
                               
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
   
  ADCSRA |= ( 1 << ADSC );                   // startet eine ADC-Wandlung 
  while ( ADCSRA & (1<<ADSC) ) {
    ;                         // auf Abschluss der Konvertierung warten, 
  }
  result = ADCW;                    // ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen.
 
  /* Eigentliche Messung */
  result = 0;                     // Dummy Readout Messwert verwerfen und result zu 0 setzen für neue Messung
  
  for( i=0; i<4; i++ ){        // Schleife für 4 aufeinanderfolgende Werte die in result zunächst aufaddiert werden
    ADCSRA |= (1<<ADSC);                   // eine Wandlung "single conversion" startet
    while ( ADCSRA & (1<<ADSC) ){
      ;                     // auf Abschluss der Konvertierung warten
    }
    result += ADCW;                    
  }
  ADCSRA &= ~(1<<ADEN);                     // ADC deaktivieren
  result /= 4;                       // Summe durch 4 teilen = arithm. Mittelwert

  return result;                  
}

Achja, noch eine Frage: Ich habe gemerkt, dass es ohne diesen cast gar 
nicht geht:
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?

Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
>
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

Autor: Micha H. (mlh) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.