mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik 200kOhm Poti an Mega8 auslesen


Autor: NathanIon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi!

Ausgangslage:

-Mega8 Controller
-200kOhm Poti an PC4 (Wiper/Schieber an ADC, ein Ende an GND, andere 
Ende an 5V+)

Problem:

Trotz Tutorial-Studium Verständnisprobleme - da Anfänger. Das Poti soll 
im Controller eine Zahl zwischen 0 und 350 regeln. Die am Poti 
eingestellte Spannung muss also in eine Zahl gewandelt werden. Und ich 
weiß nicht, welche Teile der vielen Beispiele im Internet für meine 
Anwendung gebraucht werden.

Die Abfrage muss permanent laufen, darum darf der ADC glaube ich nicht 
abgeschaltet werden nach der Abfrage.

Als Grudgerüst habe ich das hier stehen:
uint16_t ReadChannel(uint8_t mux)
{
uint8_t i;
uint16_t result;
ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); 

ADMUX = mux;
ADMUX |= (1<<REFS1) | (1<<REFS0);
ADCSRA |= (1<<ADSC);
while ( ADCSRA & (1<<ADSC) ) {
;
}
result = ADCW; 

result = 0;
for( i=0; i<4; i++ )
{
ADCSRA |= (1<<ADSC);
while ( ADCSRA & (1<<ADSC) ) {
; 
}
result += ADCW; 
}
ADCSRA &= ~(1<<ADEN);
result /= 4;
return result;
}

Wo muss ich den Eingangsport angeben, also PC4??? Und wie muss die 
Umrechnung aussehen, damit ich auf eine Zahl zwischen 0 und 350 komme???

Danke!!!

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Umrechnungsfunktion ist eine Geradenfunktion der Bauart

   y = ax + b

Die Gerade schneidet den Nullpunkt, also ist (0, 0) auf der Geraden und 
das b in der Geradengleichung ist 0.

Damit ist bereits ein Punkt bekannt und du brauchst nur noch einen 
zweiten Punkt, um die Zweipunkteform der Geradengleichung aufzustellen.

Vom zweiten Punkt ist ist bekannt, daß y 350 ist. Du brauchst also nur 
noch den x-Wert - in diesem Fall den Ausgabewert des ADC - und du kannst 
die Geradengleichung aufstellen.

http://de.wikipedia.org/wiki/Geradengleichung

Autor: NathanIon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Plausibel...danke!

Weißt Du auch, wie ich zu dem Punkt komme, an dem man die Formel im Code 
berechnen kann?

Taster abfragen habe ich schon geschafft. Poti noch nicht, da ich im 
Beispielcode keine Anpassungsmöglichkeiten finde. Poti ist korrekt an 
PC4 verschaltet.

Autor: kiara (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Funktion gibt dir einen Wert zwischen 0 und 1023 zurück, was du 
ändern solltes ist:
//falsch
ADMUX |= (1<<REFS1) | (1<<REFS0);
// richtig
ADMUX |= (1<<REFS0);
Sonst hast du die internen 2,ungradV als Referenzspannung und keine 5 
Volt.
uint16_t wert;
wert = ReadChannel(4); // PC4 als Channel ausgewählt
wert = wert / (1023 / 350); // 1023/350 ist 2,922... Problem!!
Wenn du deinen Wert durch 3 teilst, dann bekommst du 0-341, durch 2 
0-511...

Ziemlich nahe würdest du hiermit an deine 350 kommen ( 0-355 ):
uint16_t wert;
wert = ReadChannel(4);
wert *= 8; 
wert /= 23;
Bzw.: du teilst result am ende von ReadChannel() nicht durch 4, sondern 
nimmst result mal 2, spart zeit :-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmehr Zeit spart, garnicht zu dividieren:
wert = (wert * 44) >>7;
if( wert > 350 ) wert = 350;

Peter

Autor: NathanIon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@kiara

Die Referenzspannung habe ich so gesetzt wie Du es geschrieben hast. Mit 
den anderen Teilen komm ich aber nicht klar weil ich nicht weiß, wo ich 
diese Zeilen positionieren soll.

Und bei

wert = ReadChannel(4); // PC4 als Channel ausgewählt

wird ja nur die Nummer gewählt und nicht die Bank oder? Weil das könnte 
ja auch PD4 sein...

So sieht es jetzt aus:
uint16_t ReadChannel(uint8_t mux)
{
uint8_t i;
uint16_t result;
ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); 
ADMUX = mux; 
ADMUX |= (1<<REFS0);

ADCSRA |= (1<<ADSC); 
while ( ADCSRA & (1<<ADSC) ) {
;
}
result = ADCW;
result = 0;
for( i=0; i<4; i++ )
{
ADCSRA |= (1<<ADSC);
while ( ADCSRA & (1<<ADSC) ) {
;
}
result += ADCW;
}
ADCSRA &= ~(1<<ADEN);
result *= 2;
return result;
}

@Peter, kiara und alle:
Mein Ziel ist eine Zahl die in einer Variable gespeichert wird damit ich 
damit später weiterlernen/-arbeiten kann. Der Code ist aber für mich 
nicht ganz nachvollziehbar. Kann mir jemand aus obigen Informationen es 
so zusammenkopieren, damit es am Ende stimmt - also als gesamtes?

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mein Ziel ist eine Zahl die in einer Variable gespeichert wird damit ich
> damit später weiterlernen/-arbeiten kann. Der Code ist aber für mich
> nicht ganz nachvollziehbar. Kann mir jemand aus obigen Informationen es
> so zusammenkopieren, damit es am Ende stimmt - also als gesamtes?


Selten so gelacht...

Wie wärs denn, wenn du dir einfach mal die Beschreibung des ADC 
vornimmst und nachsiehst, was die einzelnen Bits in den Controlregistern 
bedeuten?

Das macht zwar ein bischen Arbeit, führt aber doch erstaunlich schnell 
zu netten Aha-Effekten.

Autor: NathanIon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das habe ich gemacht. Es tauchen aber keine Sachen auf, die ich wieder 
erkenne. Den Syntax von C verstehe ich, aber bei Potis gibt es mehr als 
high oder low und nach 4 Stunden Google-Suche darf ich doch vorsichtig 
fragen, woran es scheitert?!

ReadChannel(4); - meiner hat aber mehrere Bänke...

Ich mach das nunmal nicht beruflich und ich bin nur auf Probleme mit 
Code-Wirrwar gestoßen. Ein kleines und kompaktes Beispiel, in dem am 
Ende eine regelbare Zahl rauskommt, gabs bei meinen Suchbegriffen nicht. 
Entweder etwas, was nicht funktionierte oder nur eine allgemeine 
Erkärung der Register. Oder undokumentierter Code, mit dem ich als 
Einsteiger nichts anfangen kann.

Autor: kiara (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wert = ReadChannel(4) bedeutet, dass ADC4 als Ananlogeingang ausgewählt 
wird und das ist der Pin PC4 (Datenblatt). Wenn du die Funktion so 
verwendest wie oben darfst du halt nicht vergessen, dass sie den 8fachen 
Analog-wert zurückgibt...
Da ist der code von peda besser, !! result muss hier am Ende von 
ReadChannel durch 4 geteilt werden!!

Also ich würds dann so machen:
uint16_t ReadChannel(uint8_t mux)
{
uint8_t i;
uint16_t result;
ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); 
ADMUX = mux; 
ADMUX |= (1<<REFS0);

ADCSRA |= (1<<ADSC); 
while ( ADCSRA & (1<<ADSC) ) {
;
}
result = ADCW;
result = 0;
for( i=0; i<4; i++ )
{
ADCSRA |= (1<<ADSC);
while ( ADCSRA & (1<<ADSC) ) {
;
}
result += ADCW;
}
ADCSRA &= ~(1<<ADEN);
result /= 4;
return result;
}

// aufruf (in main() oder sonstwo..

uint16_t wert;
wert = ReadChannel(4);
wert = (wert*44) >> 7;
if (wert > 350) 
{
wert = 350;
}

Autor: NathanIon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@kiara

So muss es also aussehen. Ich teste es so schnell wie möglich. Mit dem 
ADC war es dann ein Missverständnis, ich habe nämlich soeine kostenlose 
Eagle-Version installiert und dort weicht die Portbeschreibung vom 
Datenblatt ab.

Danke für die Hilfe und ich melde mich mit dem Ergebnis!

Autor: Durchblicker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist ist auch nicht peinlich, wenn man

uint16_t wert = (uint16_t)((ReadChannel(4) * 22422UL) >> 16);

rechnet, also einen long für erhöhte Genauigkeit konsultiert.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.