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
intmain(void){
13
//variablen für das Programm
14
uint16_tADCWert;// ADC-Wert in ADC Skalierung 0...1024
15
uint16_tADCWertmV;// ADC-Wert in milli Volt
16
17
uint16_treadADCWert(uint8_tmux);// 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_treadADCWert(uint8_tmux){
37
38
uint8_ti;// Schleifenzähler
39
uint16_tresult;
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
returnresult;
69
}
Achja, noch eine Frage: Ich habe gemerkt, dass es ohne diesen cast gar
nicht geht:
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:>
> 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
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.