Forum: Mikrocontroller und Digitale Elektronik ADC Wert ungenau


von Curby (Gast)


Lesenswert?

Moin,

ich hab ein Programm, welches bei einem Tastendruck (Hardwaremäßig 
entprellt) den Spannungswert eines Potis wandeln soll und dann ADCH über 
Usart an den PC (putty) senden soll.

Im Prinzip funktioniert die Schaltung, jedoch frage ich mich, warum nur 
auf dem letzten Millimeter vom regelbaren Bereich des Potis ein Wert >0 
erfasst wird.

Das Poti ist an Masse und AREF angeschlossen, der ADC hat seine 100nF 
Kondensatoren, das übliche halt.

Es handelt sich um ein lineares Poti, mit Multimeter nachgemessen.
Weiß jemand Rat?

mfg,
Nils

Hier der Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define F_CPU 7372800
5
#define baud 460800
6
7
8
inline void write(unsigned char x){
9
  SPDR = x;
10
  while(!(SPSR & (1<<SPIF)));
11
}
12
13
inline unsigned char getch(){
14
  while(!(UCSRA & (1<<RXC)));
15
  return UDR;
16
}
17
18
inline void putch(unsigned char x){
19
  while(!(UCSRA & (1<<UDRE)));
20
  UDR = x;
21
}
22
23
inline unsigned char read(unsigned char x){
24
  SPDR = x;
25
  while(!(SPSR & (1<<SPIF)));
26
  return SPDR;
27
}
28
29
inline void send(unsigned char x){
30
  unsigned char y;
31
  for(y=7;y>0;y--){
32
    putch(0x30+(1&(x>>(y-1))));
33
    if(y==0) break;
34
  }
35
}
36
37
inline void poti(){
38
  unsigned char x;
39
  ADCSRA |= (1<<ADSC);
40
  while(ADCSRA & (1<<ADSC));
41
42
  x = ADCL;
43
  send(ADCH);
44
}
45
46
int main(){
47
  unsigned char x;
48
49
  UBRRH = 0;                  //Usart initialisieren
50
  UBRRL = F_CPU/(8*baud) -1;          //--
51
  UCSRA = (1<<U2X);              //--
52
  UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);    //Usartinterrupt freigeben
53
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  //--
54
  x = UDR;
55
56
  DDRA = 0xFF;
57
  DDRB = 0b11111110;
58
  DDRC = 0xFF;
59
  DDRD = 0xFF;
60
61
  
62
  ADMUX = (1<<REFS0)|(1<<ADLAR);
63
  ADCSRA = (1<<ADEN)|(1<<ADPS2);
64
    ADCSRA |= (1<<ADSC);
65
  while(ADCSRA & (1<<ADSC));
66
  x=ADCL;
67
  x=ADCH;
68
69
  x=0;
70
  while(1){
71
    if(PINB & 1){
72
      if(x==0){
73
        x=1;
74
        putch('T');
75
        putch(':');
76
        putch(' ');
77
        poti();
78
        putch(' ');
79
      }
80
    }else x = 0;
81
  }
82
83
  return 0;
84
}

von Volkmar D. (volkmar)


Lesenswert?

Curby schrieb:
> Das Poti ist an Masse und AREF angeschlossen, der ADC hat seine 100nF
> Kondensatoren, das übliche halt.

Wenn es nicht funktioniert, immer genau angeben, was wo angeschlossen 
ist (und nicht nur 'das übliche').

Aber an AREF soll doch nur ein Kondensator angeschlossen werden. Wenn Du 
die Referenzspannung belastest, wird sie verändert und das ganze 
funktioniert nicht. Also das Poti an Masse und VCC anschließen.

Volkmar

von Uwe (Gast)


Lesenswert?

AREF mit Impedanzwandler puffern und erst dann an Poti. Aber da du 
warscheilich kein so genaues Ergebnis brauchst gehts wohl auch wenn du 
VCC an das Poti anschließt.

von Michael (Gast)


Lesenswert?

Das ganze wird genau, wenn du eine ratiometrische Messung machst, indem 
du AVCC als Referenz selektierst und das Poti ebenfalls an AVCC hängst.

von Curby (Gast)


Lesenswert?

Ich hab gemeint, dass ich die genaue Beschaltung wie hier im Tutorial 
verwendet habe. Statt der Spule einen 47Ohm Widerstand.

Genauso wurde da gesagt, dass wenn ich quasi die Stellung des Potis 
ermitteln möchte, ich dieses an AVCC anschließen soll. Tut mir leid ich 
hab es eben mit AREF in der Schnelle verwechselt.

von Hannes L. (hannes)


Lesenswert?

Curby schrieb:
> Statt der Spule einen 47Ohm Widerstand.

Warum das?
47 Ohm in der Versorgung eines Ports sind tödlich...

...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Curby schrieb:
> Ich hab gemeint, dass ich die genaue Beschaltung wie hier im Tutorial
> verwendet habe.
Soso.
> Statt der Spule einen 47Ohm Widerstand.
Wenn das GENAU ist, dann will ich nicht wissern, was bei dir UNGEFÄHR 
oder ANNÄHERND GLEICH bedeuten könnte...

Mach mal ein Foto von deinem Aufbau.

Du kannst z.B. auch einfach mal am Portpin messen, welche Spannung da 
anliegt. Und dann mit den Formeln im Datenblatt zurückrechnen, ob das 
passen kann.

von Curby (Gast)


Lesenswert?

"Die 10uH Spule L1 kann man meist auch durch einen 47 Ohm Widerstand 
ersetzen."

Klingt für mich auch soweit in Ordnung. Ich baue ja keinen Kurzschluss 
oder so.

Nochmal zusammenfassend:
Ich verwende den Aufbau wie im Tutorial mit beschriebenem 47Om 
Widerstand, statt Spule. Dann habe ich einen entprellten Taster, bei dem 
auf Druck eine Wandlung durchgeführt wird und über Usart an putty 
gesendet wird. Dort lese ich dann auch tatsächlich einen Wert zwischen 
00000000 und 11111111.

Nur eben ist dieser Wert nur größer 0, auf dem letzten Millimeter des 
Potis. Das Poti ist linear und mit Multimeter durchgemessen.
Das Poti geht an AVCC, GND und mit dem Mittelpin an PortA0.

Die grundlegende Schaltung scheint zu funktionieren, Usart sendet, der 
Taster entprellt und auf Tastendruck, wird die Aktion durchgeführt. Aber 
warum ist die Wandlung so .. ungenau?

Ich kann jetzt nochmal meinen Aufbau durchgehen, dennoch erwarte ich, 
dass bei dem Tutorialaufbau, eine halbwegs vernünftige Wandlung 
durchgeführt wird.

Ich werde demnächst mal messen, ob die anliegenden Spannungen alle 
messen, das habe ich tatsächlich noch nicht gemacht.

mfg
Nils

von Hannes L. (hannes)


Lesenswert?

Curby schrieb:
> "Die 10uH Spule L1 kann man meist auch durch einen 47 Ohm Widerstand
> ersetzen."
>
> Klingt für mich auch soweit in Ordnung. Ich baue ja keinen Kurzschluss
> oder so.

Ich weiß ja nicht welchen AVR Du verwendest, aber beim Mega8 z.B. ist 
AVcc nicht nur die Stromversorgung für den ADC, sondern auch für den 
gesamten Port C. Da würde ich nicht auf die Idee kommen, 47 Ohm in die 
Plusleitung zu hängen. Dann lieber ein Stück Draht, einen Kurzschluss 
baust Du damit nicht.

...

von Curby (Gast)


Lesenswert?

Ich benutze den Atmega16. Ich hatte das auch schonmal mit Drahtbrücke 
aufgebaut, da war das Ergebnis das Gleiche, habe ich aber auch nicht 
anders erwartet :(.

von MWS (Gast)


Lesenswert?

Gute Idee auf dem ADC-Port die internen Pullups zu aktivieren, hilft der 
Präzision ungemein :D

von Ralf E. (r_e)


Lesenswert?

Hallo,

welchen Wert hat den dein Poti?

von MWS (Gast)


Lesenswert?

Curby schrieb:
> DDRA = 0xFF;

Korrektur, als Ausgang zu beschalten :D

von Peter R. (pnu)


Lesenswert?

Na und?

Die Kennlinie eines Poti endet nicht bei Null am linken Anschlag, 
sondern bei einem Restwert.

Auf den letzten mm des Schleiferweges ist immer noch ein Stück Kohlebahn 
bis zur Anschlussniete des Poti. In diesem Bereich hat man einen 
konstanten Widerstand. Auch der Widerstand des Schleifers, ein 
Kohleinsatz in der Metallfeder, trägt eventuell zu diesem Restwert bei.

Außerdem: Wie groß ist "ungenau"?  ein bit, zwanzig bit, hundert bit des 
Wandlungsbereichs?

von Curby (Gast)


Lesenswert?

MWS schrieb:
> Curby schrieb:
>> DDRA = 0xFF;
>
> Korrektur, als Ausgang zu beschalten :D

Vielen dank, stimmt jetzt wo ich PORTA0 als Eingang aktiviert habe und 
die Wandlergeschwindigkeit etwas heruntergesetzt habe, funktioniert der 
ADC bestens :D.

Danke dafür.

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.