Forum: Mikrocontroller und Digitale Elektronik AVR Poti an ADC mit AVCC


von Phillip H. (philharmony)


Lesenswert?

Hallo, ich habe schon einige alte Beiträge durchstöbert, aber mir ist 
immernoch nicht so ganz klar, wie genau ich ein 10KR-schiebepoti an den 
ADC anschließe.
Im Tutorial hier steht ja, wenn man AREF benutzt, sollte man, um den PIN 
nicht zu sehr zu belasten Werte um 100KR benutzen, ansonsten sollte man 
AVCC benutzen.
Ich habe jetzt also das Poti an einer Seite an AVCC gehängt, an der 
anderen an GND.
Der Schieber hängt am PINC0 wo der ADC channel 0 ist.
Im ADMUX-register habe ich REFS0 gesetzt um AVCC als refferenz zu 
nehmen.
Ist das alles so richtig?
Ich bekomme nämlich immer nur 10mal die 0 als Ergebnis der conversion.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

1. Avcc auf Vcc legen.
2. Aref mit 100nF auf GND legen. //Nicht super wichtig aber besser...
3. Poti zwischen Vcc und GND, Schieber auf ADC0.
4. ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS2) | 
(1<<ADPS1);
5. ADMUX |= (1<<REFS0);

Btw: Um welchen Controller handelt es sich? Hab einfach mal nen Mega16 
angenommen...

von Phillip H. (philharmony)


Lesenswert?

Ach sooooo geht das, ok kein Wunder daß es nicht geklappt hat.
Müßen das denn eignetlich exakt 100nF sein oder würden es auch 22 tun?
Weil von denen hab ich etliche hier rumliegen...
Dankeschön ;)
Is ein Atmega 8535

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Schau dir mal das Datenblatt vom 8535 an: 
http://www.atmel.com/dyn/resources/prod_documents/doc2502.pdf

Dort aus Seite 207 findest Du das Blockschaltbild des ADC. Wenn Refs0 
gesetzt ist liegt an AREF also AVCC oder die interne 2,56V Referenz 
abhänig davon ob Refs1 gesetzt ist. Offene Enden neigen zum Schwingen, 
darum wird dies mit dem Kondensator an AREF unterbunden, der genaue Wert 
des Kondensators ist dabei nicht so kritisch. Ich hatte 100nF angeführt 
da diese von den meisten Leuten eh als Abblockkondensatoren benutzt 
werden.

von Phillip H. (philharmony)


Lesenswert?

Ich habe hier jetzt noch ein Problem:
Ich habe 11 Potis, angeschlossen über 3.5mm Klinkenkabel an meinem Board 
hängen.
Diese switche ich über einen CD4067BE-16Kanal Multiplexer jeweils auf 
den ADC0.
Mein Prog. auf dem Atmega ließt diese nach einander aus, verpackt sie zu 
einem String und sendet diesen per uart an den Rechner.
Allerdings soll er nur senden, wenn sich seit dem letzten senden etwas 
verändert hat, damit ich keinen unendlichen Datenstrom habe.
Das problem ist jetzt: wenn nich alle Potis angeschlossen sind, dann 
hängen die entsprechenden Buchsen ja in der Luft und ich habe riesig 
zittern auf dem ADC, folglich ist der Wert nach jeder Messung anders und 
ich habe wieder meinen Datenfluss.
Wie könnte ich dafür sorgen, daß dieser Fall abgefangen wird?

von Gast123 (Gast)


Lesenswert?

Es wird nur gesendet, wenn sich der Wert um mehr als 1% (oder wieviel 
auch immer) von vorherigen Wert unterscheidet. Problem hierbei wären 
schleichende Änderungen, die so nicht registriert werden.

Also als Ereignis zum Senden des Strings
- Änderung > Schwellwert
- zusätzlich alle 1s (oder wie oft auch immer) senden

Letzteres könnte man beispielsweise realisieren indem man eine Variable 
alle 1ms um 1 herunter zählt. Bei Null wird gesendet, egal was ist. Nach 
dem Senden wird die Variable wieder auf 1.000 oder was auch immer 
gesetzt. Wird wegen Änderung > 1% gesendet, wird die Variable auch 
wieder hochgesetzt.

Es gibt sicherlich hübschere Verfahren, aber ich denke so sollte das 
relativ einfach zu realisieren sein. Statt mit den rohen ADC-Daten zu 
arbeiten, könntest du ja auch sagen wir 4 oder 8 Messungen durchführen 
und den Mittelwert bilden. Das würde das Rauschen wahrscheinlich auch 
etwas vermindern.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Fallen mir spontan 3 Möglichkeiten ein:

1. Leg die nicht benutzten Buchsen auf GND.
2. Schieb die 2 LSB ins Nirvana.
3. Stell halt die Anzahl benutzter Buchsen am MC ein und sende nur die 
gewünschten.

Wie stark zitterts denn?

von Kai F. (kai-) Benutzerseite


Lesenswert?

wenn du einen 100k Widerstand nach Masse legst, floated dir der Eingang 
nicht mehr durch die Gegend. Wenn du ein 1k Poti benutzt, fällt dieser 
auch nicht ins Gewicht. Oder du legst den Pin direkt auf Masse und löst 
die Verbinduing sobald du das Poti anschließt

von Falk B. (falk)


Lesenswert?

@ Kai Franke (kai-) Benutzerseite

>wenn du einen 100k Widerstand nach Masse legst, floated dir der Eingang
>nicht mehr durch die Gegend. Wenn du ein 1k Poti benutzt, fällt dieser

Oder die interen Pull-Ups verwenden. Sind in etwas auch 100K.

MFG
Falk

von Jörg B. (manos)


Lesenswert?

Kai Franke wrote:
> Oder du legst den Pin direkt auf Masse und löst
> die Verbinduing sobald du das Poti anschließt
Also z.B. Klinkenbuchsen mit Öffner verwenden (z.B. Pollin 450823 oder 
450013)

von Phillip H. (philharmony)


Lesenswert?

Ich brauche 10Bit auflösung, sonst kriegt mein Programmierer die Krise 
wenn ich ihm mit nem 8Bit Signal ankomme ;)
Ich lass mir schon den Mittelwert aus 10Messungen ausgeben.
Naja, ich werd morgen mal den empfohlenen Kondensator zw AREF und GND 
löten, mal schauen wieviel der noch bringt...
Ich denke ich werde mir ein paar Dummy-Stecker löten, mit nem Festen 
Widerstand drin, dann sollte ruhe sein.
Das Board ist nämlich eignetlich soweit schon fertig.
Danke für die Tips...

von Kai F. (kai-) Benutzerseite


Lesenswert?

>> Ich denke ich werde mir ein paar Dummy-Stecker löten

wieso denn? Falk hatte doch eine gute Idee mit den Pullups, dann musst 
du nur schnell im Programm was ändern anstatt den Lötkolben 
anzuschmeißen

von Phillip H. (philharmony)


Lesenswert?

Das hatte ich gar nicht gesehn, wie is das gemeint?
Kann ich am PortA den Pullup einfach einschalten, auch wenn der ADC 
aktiviert ist?
Also PORTA |= (1<<PA0) ?

von Falk B. (falk)


Lesenswert?

@ Phillip Hommel (Firma hs-bremen) (philharmony)

>Kann ich am PortA den Pullup einfach einschalten, auch wenn der ADC
>aktiviert ist?
>Also PORTA |= (1<<PA0) ?

AFAIK ja.

MFG
Falk

von Phillip H. (philharmony)


Lesenswert?

Hmm, allerdings geht der ADC jetzt nicht mehr durch den vollen Bereich 
von 0-1023 sonder fängt irgendwo bei 30 an...
Ist nicht SOOO wild, aber wenn man das noch korrigieren könnte wärs 
natürlich super...

von Phillip H. (philharmony)


Lesenswert?

Ich habe jetzt die internen Pull Ups an, habe 100nF zwischen AREF und 
GND und lass zwischen 10 Mesungen mitteln und habe immernoch Zittern im 
letzten bit...Ne lösung?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

sleep während der Messung.

von Phillip H. (philharmony)


Lesenswert?

hm, hab ich noch nie was mit gemacht, wie aufwändig is das?

von Falk B. (falk)


Lesenswert?

@ Phillip Hommel (Firma hs-bremen) (philharmony)

>GND und lass zwischen 10 Mesungen mitteln und habe immernoch Zittern im
>letzten bit...Ne lösung?

Damit leben. Das ist bei einem ADC prinzipbedingt so.

MfG
Falk

von Phillip H. (philharmony)


Lesenswert?

Ich denke ich werd das softwaremäßig abfangen.
Ich werd die beiden Datenarrays nicht einfach nur vergleichen sondern 
von einander abziehen und nur bei einer Differenz von mehr als 2 soll er 
senden.
Geht in C array1 - array2 ?

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel wrote:
> Ich denke ich werd das softwaremäßig abfangen.
> Ich werd die beiden Datenarrays nicht einfach nur vergleichen sondern
> von einander abziehen und nur bei einer Differenz von mehr als 2 soll er
> senden.
> Geht in C array1 - array2 ?

Grundlagen!

Nein. Du musst Schleifen drüber legen.

von Phillip H. (philharmony)


Lesenswert?

Habe das mal probiert
1
//Compare_Memory
2
char compare_memory(void)
3
{
4
unsigned char i = 0;
5
unsigned char result = 0;
6
for (i=0; i<11; i++)
7
  {
8
  if (((data_act[(i*2+1)] - data_old[(i*2+1)])^2)>25) result = 1;
9
  }
10
return result;
11
}
Es soll also jedes zweite Byte der beiden pakete verglichen werden und 
sobald einmal eine Abweichung von mehr als 5 vorliegt (quadratisch wegen 
vorzeichen, oder kann ich das weglassen?) soll result eine 1 werden, 
sonst bleibt sie null.

Aufruf sieht so aus:
1
if(compare_memory()) sende_daten (...) ;

...
Läuft, allerdings nur bis zum ersten mal wenn das Low Byte über 255 
wieder auf 0 geht.
Dann reagiert er auf diese Achse gar nicht mehr, aber dafür auf alle 
anderen.
Sobald ich eine andere Achse bewegt habe, geht die erste wieder...???

von Karl H. (kbuchegg)


Lesenswert?

Phillip Hommel wrote:

> Es soll also jedes zweite Byte der beiden pakete verglichen werden und
> sobald einmal eine Abweichung von mehr als 5 vorliegt (quadratisch wegen
> vorzeichen, oder kann ich das weglassen?)

quadratisch ist wohl so ziemlich die schlechteste Lösung dafür.
Wenn du tatsächlich die abs Funktion in C nicht kennst, ist
es ziemlich simpel da selbst eine zu schreiben.

int my_abs( int i )
{
  if( i < 0 )
    return -i;
  return i;
}

.....

  if( my_abs( data_act[i*2+1] - data_old[i*2+1] ) )
    result = 1;
.....

> Läuft, allerdings nur bis zum ersten mal wenn das Low Byte über 255
> wieder auf 0 geht.

?
welches Low-byte?

Machst du da byteweise Vergleiche? Warum liest du denn
die ADC Ergebnisse nicht einfach mal in ein Int Array ein.
Das vereinfacht doch die Sache beträchtlich.
Jetzt versteh ich auch, warum du nur jedes 2.te Byte vergleichst.
Das ist doch Unsinn und gehört in die Kategorie: Wie schiesse ich
mir selber ins Bein.
Also: Die beiden Bytes vom ADC holen und zu einem int zusammenfügen.
Der gcc macht das schon ganz von alleine, wenn man das ADCW Pseudo-
register ausliest. Ab dort hast du dann int und kannst damit
wunderbar operieren.

von Phillip H. (philharmony)


Lesenswert?

Ich bin in C noch nicht so fit, aber ich lerne jeden tag was neues ;)
Mit Abs funktioniert es.
Vielen Dank erstmal!

Der hintergrund warum ich byteweise arbeite ist der, daß ich per UART 
byteweise sende, und daher auch das Wertearray entsprechend byteweise 
aufbaue.
Ich hole mir sogar den int-Wert aus dem ADCW, teile ihn aber dann in low 
und high part auf und füge dem High-Part dann noch eine Numerierung in 
die ersten 4 der 6 ungenutzten Bits ein.
Würde ich als Int speichern, müßte ichs beim senden wieder zerpflücken, 
außerdem krieg ich ein Problem beim vergleichen wenn ich die 
Nummerierung da schon drin habe.
Ich hoffe damit ich hab mich jetzt rausgeredet ;)

von Martin (Gast)


Lesenswert?

Hi

Ich hab meinen Mega16 an einem 1KOhm Poti, und nach ner weile ist er 
schon ziemlich warm geworden... ist das normal?

Gruß

von Phillip H. (philharmony)


Lesenswert?

Eigentlich sollte das nicht sein.
Wird er auch warm wenn du das Poti wegnimmst?
Ist die Schaltung auf einem Steckboard, Rasterplatine, ...?
Wieviel strom zieht die Schaltung und was hängt sonst noch am Controller 
dran?

von Martin (Gast)


Lesenswert?

steckt auf so nem Steckbrett/Experimentierboars...
Die Schaltung zieht 50mA
Und am Controller hängt nur noch eine Duo LED....
Ohne Poti hab ich noch nicht versucht... aber ich denk nicht dass er da 
noch warm wird, sonst hängt ja nichts weiter dran...

Gruß

von Phillip H. (philharmony)


Lesenswert?

Eben das wäre ja damit herauszufinden.
Wenn er ohne Poti trotzdem warm wird, dann haste eventuell einen Kurzen 
irgendwo auf dem Steckboard.
50mA ist recht viel für den AVR, was zieht denn die LED alleine? Was 
zieht die Schaltung ohne die LED?
Hast Du das Poti vielleicht falsch angeschlossen? Verändert sich der 
Stromverbrauch wenn Du das Poti verstellst?
Sollte nämlich VCC bzw GND fälschlicherweise auf dem Abnehmerpin des 
Poti liegen und der Schieber ganz zu, dann hast du quasi einen 
Kurzschluss (oder zumindest recht niederohmige Verbindung) von VCC auf 
GND in die eine oder andere Richtung...

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.