Forum: Mikrocontroller und Digitale Elektronik ADC Problem beim Atmega32


von Voldemort (Gast)


Angehängte Dateien:

Lesenswert?

Hallo liebe Leute,

ich bin Anfänger in Sachen Mikrocontroller-Programmierung und benötige 
Hilfe bei der Verwendung des AD Wandlers. Die Suchfunktion hat mir 
leider keine Threads mit ähnlichen Problemen beschert.

Erstmal zu meiner Hardware:
Ich benutze das RN Control 1.4 Board mit Atmega32 und 16MHz Quarz. 
(Schaltplan angehängt)

Ich möchte mittels AD-Wandlung (PA7) die 5 eingebauten Taster (PC0 bis 
PC5) abfragen. Die Taster sind über einen Spannungsteiler angeschlossen. 
Jedem Taster ist eine LED zugeordnet, welche bei Betätigung leuchtet. 
Wenn kein Taster betätigt wird soll keine LED leuchten.

Der erste Teil der Aufgabe funktioniert auch gut ganz, jeder Taster 
lässt die entsprechende LED leuchten. Das eigentlich Problem ist, wenn 
ich keinen Taster drücke flackern die LEDs wahllos. Es scheint irgendein 
hochfrequentes/kapazitives Problem zu sein. Nähere ich mich dem Board 
mit der Hand oder einem Gegenstand verändert sich die Stärke des 
Flackerns. Je nach dem wie man das Board hält Flackern verschiedene 
LEDs. Ich verstehe nicht wie das Zustande kommt.

Für die Auswertung des ADC Signales benutze ich die 8 Bit des 
ADCH-Registers. Das ADCL-Register wird nicht abgefragt.

Für den Spannungsteiler über den die Taster angeschlossen sind habe ich 
folgende Werte ausgerechnet (und im Code verwendet):

           Spannung   ADC-Messwert(8 Bit)
o. Taster   3,33        170,67
Taster 1    1,           85,33
Taster 2    1,3          68,27
Taster 3    1,00         51,20
Taster 4    0,67         34,13
Taster 5    0,33         17,07



Hier der zugehörige Code:
1
#define F_CPU 1600000UL
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
6
7
double voltage;
8
double wert;
9
10
11
int main(void)
12
{
13
   DDRC = 0xFF;
14
  
15
16
    //ADC CONFIG
17
    ADMUX   = (1<<ADLAR); //linksbündige Ausgabe des Ergebnisses
18
    ADMUX  |= (1<<REFS0); ///Festlegung der Referenzspannung auf Extern
19
    ADMUX  |= (1<<MUX2) | (1<<MUX1) | (1<<MUX0); // ADC7 (PA7) als ADC Eingang
20
    ADCSRA  = (1<<ADEN); // AD-Wandlung Enable
21
    ADCSRA |= (1<<ADPS1) |(1<<ADPS2) |(1<<ADPS0); // Prescaler-Teilfaktor 128
22
    ADCSRA |= (1<<ADIE); // ADC Interrupt Enable auf 1
23
24
  
25
        
26
  while (1)
27
    {    
28
  voltage = 0;
29
  for(int i=0; i<6; i++)
30
  {
31
    ADCSRA |= (1<<ADSC); //Single Conversion
32
    while(ADCSRA&(1<<ADSC)); //Warten auf Wandlung
33
    voltage+= ADCH; //Aufaddieren der Messwerte
34
    
35
  }
36
  
37
  wert = voltage/6;
38
  
39
40
    
41
         if ((78<wert)&&(wert<=94))   PORTC = 0b11101111; //Taster 1 - LED5
42
    else if ((60<wert)&&(wert<=77))   PORTC = 0b11110111; //Taster 2 - LED4
43
    else if ((44<wert)&&(wert<=59))   PORTC = 0b11111011; //Taster 3 - LED3
44
    else if ((26<wert)&&(wert<=43))   PORTC = 0b11111101; //Taster 4 - LED2
45
    else if ((10<wert)&&(wert<=25))   PORTC = 0b11111110; //Taster 5 - LED1
46
    else PORTC = 0b11111111; //LEDs AUS 
47
48
    
49
  }
50
  return 0;
51
}


Bitte helft mir.
Tipps zur Verbesserung meines Programmierstils nehme ich gerne entgegen. 
:)

von Felix Adam (Gast)


Lesenswert?

Das ist normal, da der Eingang des ADC in der Luft hängt, wenn kein 
Taster gedrückt ist. Eine Lösung wäre, einen Widerstand (z. B. 220k oder 
größer) zwischen PA7 und +5V zu schalten. Oder zwischen PA7 und Masse.

Erstere Lösung würde den ADC auf Maximum aussteuern, wenn kein Taster 
gedrückt ist, die zweite würde 0V am ADC anliegen lassen, wenn kein 
Taster gedrückt ist.

von Max M. (jens2001)


Lesenswert?

Voldemort schrieb:
> wenn
> ich keinen Taster drücke flackern die LEDs wahllos. Es scheint irgendein
> hochfrequentes/kapazitives Problem zu sein.

Wenn keine Taste gedrückt ist hängt der ADC-Eingang "in der Luft".
Dadurch wirkt er wie eine Antenne.
Häng mal einen 1Mohm vom ADC zu GND.

von Voldemort (Gast)


Lesenswert?

Danke für eure Hilfe.

Wieso hängt der ADC eigentlich "in der Luft"? Wenn ich den 
Spannungsteiler der dort verwendet wird (1x 10kOhm, 5x 1kOhm) richtig 
verstanden habe, müssten doch immer 3,33V (5V * 10kOhm/15kOhm) an PA7 
liegen wenn kein Taster gedrückt wird. Oder?

Aus welchem Grund wurde den herstellerseitig kein größerer Widerstand 
als 10kOhm dort verbaut? Bisher schien mir das Board an allen stellen 
sehr durchdacht zu sein. Dann gibt es sicher dafür auch eine gute 
Begründung.

Gibt es irgendeine eine Software Lösung um dieses Flackern zu 
unterbinden?

von Max M. (jens2001)


Lesenswert?

Voldemort schrieb:
> Bisher schien mir das Board an allen stellen
> sehr durchdacht zu sein

Für mich sieht die Art wie die Taster angeschlossen sind eher suboptimal 
aus!


> Dann gibt es sicher dafür auch eine gute
> Begründung.

Die Begründung ist vermutlich dass man so an den JP2/8 alles 
anschliessen kann.

von Max M. (jens2001)


Lesenswert?

[Kopfklatsch]

Schalt einfach mal den internen Pullup ein!

von M. K. (sylaina)


Lesenswert?

Voldemort schrieb:
> Wieso hängt der ADC eigentlich "in der Luft"? Wenn ich den
> Spannungsteiler der dort verwendet wird (1x 10kOhm, 5x 1kOhm) richtig
> verstanden habe, müssten doch immer 3,33V (5V * 10kOhm/15kOhm) an PA7
> liegen wenn kein Taster gedrückt wird. Oder?

Nein, der Spannungsteiler hängt an PA6, schau mal genau hin. PA7 hängt 
in der Luft wenn kein Taster gedrückt wird.

Voldemort schrieb:
> Aus welchem Grund wurde den herstellerseitig kein größerer Widerstand
> als 10kOhm dort verbaut?

Wegen eventueller Leckströme und ähnliches. Je kleiner der Widerstand 
desto mehr Strom kann fließen (will man ggf ja gar nicht). Macht man den 
Widerstand aber zu groß können sich z.B. Leckströme unangenehm bemerkbar 
machen. 100 nA erzeugen an 1 MegΩ schon 100 mV Spannungsfall, man will 
aber vielleicht 0 V. Die 10 kΩ sind also ein Kompromiss. Man hätte auch 
20 kΩ oder 50 kΩ nehmen können. Das ist dann eher eine 
Bauchentscheidung. 10 kΩ sind halt am leichtesten zu bekommen, gibts 
besser als Sand am Meer.

von Voldemort (Gast)


Lesenswert?

Max M. schrieb:
> Schalt einfach mal den internen Pullup ein!

Jaaa. Danke das hat es gebracht. ;)
Ich wusste bisher nicht dass es möglich ist den ADC mit den internen 
Pullup Widerständen zu kombinieren. Schön blöd von mir.


Wie berechnet man denn am leichtesten welchen Spannungswert den der ADC 
misst? Durch die Zuschaltung der Pullups haben sich die Messwerte 
gegenüber den oben angegebenen verändert.
Ich habe durch probieren heraus gefunden welche Werte ich in die 
If-Abfrage eintragen muss. Würde jedoch gerne wissen wie man es 
berechnet.

Danke für eure Unterstützung! :)

von M. K. (sylaina)


Lesenswert?

Voldemort schrieb:
> Wie berechnet man denn am leichtesten welchen Spannungswert den der ADC
> misst? Durch die Zuschaltung der Pullups haben sich die Messwerte
> gegenüber den oben angegebenen verändert.
> Ich habe durch probieren heraus gefunden welche Werte ich in die
> If-Abfrage eintragen muss. Würde jedoch gerne wissen wie man es
> berechnet.

Hö? Was meinst du damit?

Die Spannung am ADC-Pin, die gemessen wurde, ist:

Je nachdem welche Referenzquelle du halt ausgesucht hast, ob du ADLAR 
und 8 bit nutzt oder 10 bit usw. Also das ist doch nun wirklich kein 
Hexenwerk und wird im Datenblatt des Atmegas32 ausführlich beschrieben.

: Bearbeitet durch User
von Paul B. (paul_baumann)


Lesenswert?

Michael K. schrieb:
> Hö? Was meinst du damit?

Er meint damit, daß der nun eingeschaltete interne Pull-up-Widerstand 
von seinem Wert her in die Rechnung eingeht, er aber den Wert nicht 
kennt.

Da hilft nur: Den internen Ziehwiderstand nicht einschalten und 
stattdessen draußen einen "echten" Widerstand dranmachen, dessen Wert 
bekannt ist.

MfG Paul

von Voldemort (Gast)


Lesenswert?

Michael K. schrieb:
> Hö? Was meinst du damit?
>
> Die Spannung am ADC-Pin, die gemessen wurde, ist:
>
> Je nachdem welche Referenzquelle du halt ausgesucht hast, ob du ADLAR
> und 8 bit nutzt oder 10 bit usw. Also das ist doch nun wirklich kein
> Hexenwerk und wird im Datenblatt des Atmegas32 ausführlich beschrieben.

Sorry falls ich mich unverständlich ausgedrückt habe.

Ich habe die Spannung am ADC-Eingang bisher über die Verhältnisse am 
Spannungsteiler berechnet.
Also Referenzspannung * Widerstand/Gesamtwiderstand.

Für Taster T1 heißt das beispielsweise 5V * 5kOhm/15kOhm = 1,67 V
Und diese 1,67V entsprechen bei 8 Bit auslesen einem Wert von 85. (1,67 
* 256/5 = 85) Daher wusste ich, dass das bei einem Messwert am ADC von 
etwa 85 der erste Taster betätigt wird.

Jetzt wo ich die Pullup Widerstände eingeschaltet habe funktioniert 
diese Rechnung jedoch nicht mehr. Die Messwerte habe sich verändert. Der 
erste Taster erzeugt nun einen Wert von 98, statt wie vorher 85.

von M. K. (sylaina)


Lesenswert?

Paul B. schrieb:
> Er meint damit, daß der nun eingeschaltete interne Pull-up-Widerstand
> von seinem Wert her in die Rechnung eingeht, er aber den Wert nicht
> kennt.

Achso, ja da ist was dran.

Voldemort schrieb:
> Jetzt wo ich die Pullup Widerstände eingeschaltet habe funktioniert
> diese Rechnung jedoch nicht mehr. Die Messwerte habe sich verändert. Der
> erste Taster erzeugt nun einen Wert von 98, statt wie vorher 85.

Beachte was Paul geschrieben hat. Du hast jetzt einen kleinen Vorteil: 
Du kennst deinen Spannungsteiler und hast den ADC-Wert. Mit diesen 
Mitteln kannst du nun den internen Pullup ausrechnen. Wie das? Ganz 
einfach: Oben hab ich ja schon geschrieben wie du die Spannung am Pin 
aus dem ADC-Wert ausrechnen kannst.

Deine Schaltung bei geschlossenem Taster schaut so aus:

     Ub   Ub
      o    o
      |    |
      |    |
      -    -
     | |  | |interner
   R1| |  | |Pullup
      -    -
      |    |
      |    |
      |    |
      +----+--- ADC
      |
      -
     | |
   R2| |
      -
      |
      |
      -
     GND

Bis auf den Pullup kennst du alle Werte (R1 und R2 ergeben sich aus dem 
Taster, den du gedrückt hast), damit kannst du dir den Pullup ausrechnen 
;)

von Paul B. (paul_baumann)


Lesenswert?

Michael K. schrieb:
> Du hast jetzt einen kleinen Vorteil:
> Du kennst deinen Spannungsteiler und hast den ADC-Wert. Mit diesen
> Mitteln kannst du nun den internen Pullup ausrechnen.

Das kann er machen, aber wenn er einen anderen Atmega32 aus der Kiste 
nimmt, dann ist der Ziehwiderstand in diesem wieder (wahrscheinlich 
geringfügig) ein Anderer. So müßte er das Programm für jeden Kontroller
einzeln mit den entsprechenden Werten versehen.

Da ist es doch besser, draußen einen separaten Widerstand dranzumachen, 
denke ich.

MfG Paul

von Voldemort (Gast)


Lesenswert?

Danke Paul und Michael für eure Tipps. :)


Die Auswertung von Analog Signalen scheint leider ganz schön umständlich 
zu sein. Nach dem das mit den LEDs geklappt hat (jeder Taster betätigt 
jeweils eine LED) habe ich einen PC Lüftermotor angeschlossen. Die 
Drehzahl des Motors wird über PWM gesteuert. Jedem Taster wurde eine 
bestimmte Drehzahl zugeordnet.

Die Werte die der ADC misst sind für den Motor wiederum andere als für 
die LEDs. Anscheinend muss man je nach Verbraucher die ADC Werte 
anpassen, sonst ist die Zuordnung zu den Tastern korrekt.

von M. K. (sylaina)


Lesenswert?

Paul B. schrieb:
> Da ist es doch besser, draußen einen separaten Widerstand dranzumachen,
> denke ich.

Natürlich ist das besser die Schaltung entsprechend zu ändern. Man muss 
ja schon so genügend von Controller zu Controller vermessen wenn man 
will, dass sie gleich sind (z.B. die interne VREF-Spannung)

von Karl H. (kbuchegg)


Lesenswert?

Voldemort schrieb:
> Danke Paul und Michael für eure Tipps. :)
>
>
> Die Auswertung von Analog Signalen scheint leider ganz schön umständlich
> zu sein.

Nicht wirklich.

> Die Werte die der ADC misst sind für den Motor wiederum andere als für
> die LEDs. Anscheinend muss man je nach Verbraucher die ADC Werte
> anpassen, sonst ist die Zuordnung zu den Tastern korrekt.

Vor allen Dingen wäre es wichtig, dass die Spannungen nicht je nach 
Verbraucher einbrechen und der Verbraucher keinen Schmutz auf die 
Spannungen einkoppelt. So wie immer halt. Je sauberer gearbeitet wird, 
desto besser sind die Ergebnisse.

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.