Nabend,
ich habe ein Problem mit meinem ADC am Atmega8.
Das Problem ist, dass der ADC dem Poti nicht linear folgt. Um die Frage
vorweg zu klären, das Poti ist ein linear Poti Spindeltrimmer,
Präzisions-Poti 10k (25 Gänge).
Habe das Poti unbelastet ohmisch mit dem Multimeter durchgemessen
zwischen einem Pin und Schleifer. Das Poti ist definitiv linear und
verhält sich beim ohmischen durchmessen auch so.
Am ADC verhält es sich ganz anders. Ich habe hierzu ein Display an Port
C und teilweise Port D angeschlossen. Das Display zeigt mir den
eingelesenen ADC-Wert an. Steht das Poti nahe 0 kann ich 6-8 Gänge
drehen und der ADC-Wert steigt nur langsam am. Die Spannung am Poti ist
entsprechend auch sehr gering (gemessen mit dem Multimeter). Doch dann
steigt der ADC-Wert rapide an. Eine halbe Umdrehungen weiter und der
Wert ist bereits bei 200. Noch eine halbe Umdrehung und er ist bei 600.
Noch eine Umdrehung weiter und ich lande dann schon am Ende bei 1020.
Verwendet wird die Spannung an AVcc, welche = VCC = 5V ist aus einem
Festspannungsregler. Prozessortakt ist 8Mhz, Vorteiler ADC auf 64, d.h.
Abtastfrequenz 125kHz.
Anbei auch die Schaltung dazu. Ich muss dazu sagen, die Spule habe ich
weggelassen, stattdessen AVcc direkt an Vcc. Das ich dadurch evtl ein
Rauschen habe ok, aber die "Sprünge" bzw. das nicht-lineare Verhalten
sollte das aber nicht ausmachen. Alle 100nF Kondensatoren sind dran wie
gezeichnet und sämtliche sonstigen Anschlusse (also alle *GND und *Vcc
sind entsprechend beschaltet).
Prozessor habe ich auch schon getauscht gegen einen anderen Atmega8,
sogar ein Atmega88 und Atmega168 veruscht. Alle reagieren gleich.
Hat jemand eine Erklärung? ADC-Auslese-Funktion ist aus dem Tutorial
(vorherige Version).
Und hier die main.c
1
#include<avr/io.h> // avr Header File für IO Ports
2
#include<avr/pgmspace.h> // Markos für PGM Space
3
4
// INCLUDES für Display
5
#include<stdio.h>
6
#include<stdlib.h>
7
#include<string.h>
8
#include"main.h"
9
#include"lcd.h"
10
#include<util/delay.h>
11
12
#ifndef F_CPU
13
#define F_CPU 8000000UL // processor clock frequency 8Mhz
14
#endif
15
16
17
uint16_treadADCWert(uint8_tmux);// Liest den ADC-Wert ein und gibt den Wert zurück von mikrocontroller.net
18
voidinit_ports(void);// Ports initialisieren
19
20
21
intmain(void)
22
23
{
24
25
charbuffer[12];
26
uint16_tADCWert=0;
27
28
// Ports initialisieren
29
init_ports();
30
31
// Display initialisieren
32
lcd_init();
33
lcd_clear();
34
35
36
while(1){
37
38
ADCWert=readADCWert(0);// ADC-Wert einlesen
39
40
// ADC-Wert ausgeben
41
lcd_setcursor(0,0);
42
lcd_string_P(PSTR("ADC-Wert:"));
43
utoa(ADCWert,buffer,10);
44
lcd_string(buffer);
45
46
}
47
}
48
49
50
51
52
voidinit_ports(void){
53
// Port B ungenutzt
54
DDRB=0x00;
55
PORTB=0xFF;// alle Pullups ein
56
57
58
// ADC Port als Eingang, Pullups sicher ausschalten
59
DDRC=(1<<DDC0);
60
PORTC&=~(1<<PC0);
61
62
return;
63
}
64
65
uint16_treadADCWert(uint8_tmux){
66
67
uint8_ti;// Schleifenzähler für die 4-fach Messung (bildet Durchschnitt)
68
uint16_tresult;// Speichert das Ergebnis der Funktion und gibt dieses zurück. Wert zwischen 0...1023 (10-bit)
69
70
ADMUX=mux;// wird der Funktion übergeben, entspricht dem Kanal der ausgelesen werden soll (0=ADC0, 1ADC1, etc.)
71
ADMUX|=(1<<REFS0);// Spannung am Pin AVcc dient als Referenz
72
73
ADCSRA=(1<<ADEN)|(1<<ADPS1)|(1<<ADPS2);// ADC wird aktiviert, Vorteiler 64 wird eingestellt
74
75
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
76
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
77
78
ADCSRA|=(1<<ADSC);// startet eine ADC-Wandlung
79
while(ADCSRA&(1<<ADSC)){
80
;// auf Abschluss der Konvertierung warten, das bit im ADSC Register wird nach erfolgreicher Wandlung gelöscht, Schleife somit beendet
81
}
82
result=ADCW;// ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen. (Ergebnis wird im Register ADCW gespeichert)
83
84
/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
85
result=0;// Dummy Readout Messwert verwerfen und result zu 0 setzen für neue Messung
86
87
for(i=0;i<4;i++){// Schleife für 4 aufeinanderfolgende Werte die in result zunächst aufaddiert werden
88
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion" startet
89
while(ADCSRA&(1<<ADSC)){
90
;// auf Abschluss der Konvertierung warten
91
}
92
result+=ADCW;// Wandlungsergebnisse aufaddieren
93
}
94
ADCSRA&=~(1<<ADEN);// ADC deaktivieren
95
result/=4;// Summe durch anzahl_messungen teilen = arithm. Mittelwert
96
97
returnresult;// Funktion gibt bei Aufruf die Variable "result" zurück. Diese enthält den Mittelwert aus den ADC Messungen
Hallo Martin,
ja das ist so, bitte lies mal die entsprechnden Notes von Atmel dazu:
AVR120: Characterization and Calibration of the ADC on an AVR
AVR121: Enhancing ADC resolution by oversampling
Martin schrieb:> // ADC Port als Eingang, Pullups sicher ausschalten> DDRC = (1 << DDC0);> PORTC &= ~(1 << PC0);
Damit machst du den Pin zum Ausgang, nicht zum Eingang.
Und
> Abtastfrequenz 125kHz.
dürfte auch Auflösung kosten, in Anbetracht dessen, daß das Datenblatt
über den ADC sagt: "Up to 15 kSPS at Maximum Resolution"
Rolf Magnus schrieb:> Martin schrieb:>> // ADC Port als Eingang, Pullups sicher ausschalten>> DDRC = (1 << DDC0);>> PORTC &= ~(1 << PC0);>> Damit machst du den Pin zum Ausgang, nicht zum Eingang.
Oh mein Gott, natürlich. So ist es, wenn man sich darauf verlässt, was
man in das Kommentar schreibt, dann findet man den Fehler nicht.
Habe es geändert und siehe da, ADC verhält sich linear.
Vielen Dank!
Rolf Magnus schrieb:>> Abtastfrequenz 125kHz.>> dürfte auch Auflösung kosten, in Anbetracht dessen, daß das Datenblatt> über den ADC sagt: "Up to 15 kSPS at Maximum Resolution"
Dazu hätte ich aber noch eine Frage. Im Tutorial steht nämlich
folgendes:
"Der ADC-Takt sollte zwischen 50 und 200kHz liegen.
Der Vorteiler muss also so eingestellt werden, dass CPU-Taktfrequenz
dividiert durch den Teilungsfaktor einen Wert im Bereich (50-200)kHz
ergibt"
Daran habe ich mich gehalten und für meine 8Mhz eben 125kHz eingestellt,
sprich Vorteiler 64.
Martin schrieb:> Daran habe ich mich gehalten und für meine 8Mhz eben 125kHz eingestellt,> sprich Vorteiler 64.
Das ist die ADC Frequenz und nicht die Abtastfrequenz.