AVR Poti an ADC mit AVCC

OP #764289
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.
Gast #764295
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...
Gast #764442
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.
OP #764682
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?
Gast #764685
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.
Gast #764687
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?
OP #764785
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...
#766052
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.
OP #766083
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...???
#766099
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.
OP #766104
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 ;)
Gast #793900
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ß
OP #793963
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...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren