Forum: Mikrocontroller und Digitale Elektronik Keine ADC-Kanal Adressierung möglich ATMEGA8


von Stephan W. (kahlschlaechter)


Lesenswert?

Guten Tag,

leider habe ich kein passendes, bereits offenes, Thema hierzu gefunden. 
Zu meinem Problem.
Für meine Abschlussarbeit der Technikerschule entwickel ich ein Projekt 
bei dem ich mehrere ADC-Kanäle auswerten will. Verwendet wird ein 
ATMEGA8 im PDIP Gehäuse. An AREF ist ein Kondensator nach Masse 
geschaltet (laut Datenblatt). An PORT D ist ein LCD Display 
angeschlossen.

Funktion der entsprechenden Zeilen:

-es wird ein Sollwert (0-5V) ermittelt
-es werden nacheinander zwei weitere Werte ermittelt

Danach folgt die Verarbeitung und die Ausgabe an das LCD-Display.

Nun ist das Problem, dass, egal welchen Kanal ich im ADMUX Register 
eingebe, nur der ADC Kanal 0 arbeitet.

Codeausschnitt:

[c]
//Sollwerterfassung

ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1)|(1<<ADSC);
ADMUX=0x11;
ADMUX=(0<<REFS1)|1<<REFS0);
while (ADCSRA & (1<<ADSC));

Sollwert = ADCW;
[c]

Also ob ich im ADMUX eine 11 oder eine 01 usw. schreibe hat keine 
Auswirkung auf das Programm.Das heißt es wird immer Kanal 0, also ADMUX 
= 0x00, erfasst und an das LCD Display ausgegeben.

Ich habe schon diverse unterschiedliche Schreibweisen der Adressen sowie 
zwei ATMEGA 8 mit dem Programm getestet. Leider ohne Erfolg.

Hat hier jemand schon einmal ein ähnliches Problem gehabt / gelöst?
Im Augenblick komme ich nicht weiter.

Danke und viele Grüße
Stephan

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Stephan Winckler schrieb:
> ADMUX=0x11;
> ADMUX=(0<<REFS1)|1<<REFS0);

Du schreibst also erstmal 0x11 ins ADMUX. Dann überschreibst du das mit 
der 2ten Zeile.
Welche Technikerschule ist das denn? Etwa Beuth?

von egonotto (Gast)


Lesenswert?

Hallo,

"(0<<REFS1)"
was willst Du damit erreichen?

MfG
egonotto

von muhdow (Gast)


Lesenswert?

Stephan Winckler schrieb:
> ADMUX=(0<<REFS1)|1<<REFS0);
Anzahl der Klammern ist nicht ausgewogen

von Cyblord -. (cyblord)


Lesenswert?

> ADMUX=0x11;
> ADMUX=(0<<REFS1)|1<<REFS0);
Völliger Humbug

von egonotto (Gast)


Lesenswert?

Stephan Winckler schrieb:
> ADMUX=(0<<REFS1)|1<<REFS0);


Da fehlt doch eine Klammer. Das Programm darf doch gar nicht übersetzt 
werden.

MfG
egonotto

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ich würde gerne mal wissen, was für einen Abschluss man dann hat - und 
warum bin ich so früh geboren, das ich nicht auch mit so einem 
Sontagsvormittags-Picknick Projekt meinen Abschluss machen durfte. Das 
ist ungerecht - allerdings wird mir angst und bang, wenn ich darüber 
nachdenke, was für Controllerprogramme dann in meinem nächsten Auto 
laufen.

von Stephan W. (kahlschlaechter)


Lesenswert?

Hey Matthias mal ganz ruhig!

Ich habe von der Programmierung wenig bis keine Ahnung und lerne das 
auch nicht in der Schule!
Das ganze ist ein Projekt mit Praxisanteil und ausführlicher 
Dokumentation, eine Gsamtentwicklung neben der Abendschule. Das 
Programmieren ist nur ein winziger, unbedeutender Teil, der aber 
trotzdem funktionieren muss!

Nun mal zu den hilfreichen (auch deiner Matthias) Antworten.
Erstmal danke.

Die Klammer habe ich drin, die ist nur auf dem Weg ins Forum verschütt 
gegangen.

@ Matthias:

Um das Überschreiben zu umgehen, muss der Befehl also so aussehen?

ADMUX |= 0x11 | (1<<REFS0);

Oder raff ich da etwas nicht?

@egonotto:

Ich weiß, dass dieser Befehl nicht sein muss, habe es aber aus einem 
Beispiel zur Problemlösung mit übernommen.

von Cyblord -. (cyblord)


Lesenswert?

egonotto schrieb:
> Stephan Winckler schrieb:
>> ADMUX=(0<<REFS1)|1<<REFS0);
>
>
> Da fehlt doch eine Klammer. Das Programm darf doch gar nicht übersetzt
> werden.


Heutzutage haust du deinen Krempel (aka Krempel von anderen den du per 
Copy&Paste geklaut hast) erstmal ins Forum, dann übersetzt du ihn. Sonst 
kannst du ja nicht wissen ob er korrekt ist. Und der Compiler gibt keine 
so schönen Lösungsvorschläge wie das Forum.

gruß cyblord

von loller (Gast)


Lesenswert?

LOL
1. Forumssuche bemühen
2. Datenblatt lesen und versuchen zu verstehen
3. Verstandene Funktion des µC umsetzen
4. Ergebis testen, wenn nix funzt gehe zu 2.
5. Abliefern

von RV (Gast)


Lesenswert?

Tipp: Bit löschen Register&=~(1<<bitnr);

von Stephan W. (kahlschlaechter)


Lesenswert?

Und nochmal.
Danke für die Hilfe!

Ich habe in der Suche leider nichts Ähnliches gefunden.

@ cyblord:

Wodurch, kann ein Fehler der Art auftreten, das die Adressierung des 
Kanals nicht übernommen wird? Hat Matthias Recht mit seiner Aussage, 
dass das doppelte ADMUX die Adresse überschreibt und damit eine Änderung 
unwirksam macht?

@loller:

Wie suche ich denn, deiner Meinung nach, nach einem Adressierungproblem 
des ADC's in der Suche?

MfG
Stephan

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Stephan Winckler schrieb:
> ADMUX |= 0x11 | (1<<REFS0);
>
> Oder raff ich da etwas nicht?

Nein. Erstens ist Bit 4 ein reserviertes Bit im Mega8 und soll gar nicht 
angefasst werden (Seite 205 im Datenblatt). Und zweitens solltest du es, 
wenn schon denn schon, so schreiben:
1
ADMUX = (1<<REFS0)|(1<<MUX0);
Zugegeben, (1<<MUX0) schiebt gar nichts nach links, aber so ist es 
einfach, auch mal MUX1 oder MUX2 anzusprechen, ohne im Datenblatt 
rumzuwühlen.

von loller (Gast)


Lesenswert?

Stephan Winckler schrieb:
> @loller:
>
> Wie suche ich denn, deiner Meinung nach, nach einem Adressierungproblem
> des ADC's in der Suche?

Wenn Du Dir die Mühe gemacht hättest VORHER nachzusehen, hättest Du via 
Suche nach AVR ADC GCC Tutorial z.B. das gefunden:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe
Noch schneller wäre gewesen gleich direkt im GCC-Tutorial nachzusehen.

von Stephan W. (kahlschlaechter)


Lesenswert?

@ Matthias:

Den Befehl (1<<MUX0) kannte ich in der Form noch nicht.

Ich habe mit einem Lernbuch die am Anfang genannte Adressierung 
gelernt.
Jetzt machen auch die Tabellen im Datenblatt mehr Sinn :-)

@ loller:

Das Tutorial habe ich natürlich  Hilfe gezogen. allerdings hat es mir, 
aufgrund der oben geschriebenen "Lernanfänge", nicht sonderlich 
geholfen, da mir die Adressierung wie von Matthias beschrieben, 
unbekannt war.

Danke erstmal an alle.
Ich werde mich morgen früh da mal drauf stürzen  und die andere (Volt 
einzig richtige) Adressierung ausprobieren.

MfG

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Stephan Winckler schrieb:
> Ich habe mit einem Lernbuch die am Anfang genannte Adressierung
> gelernt.

Nur als abschreckendes Beispiel - nenn dieses Buch mal bitte, damit wir 
einen Shitstorm auslösen können, hehehe.

von Stephan W. (kahlschlaechter)


Lesenswert?

Das Buch heißt AVR. Autor : F. Schäffer. Verlag : Elektor.
Die Einstellungen des ADC des ATMEGA wird ca. ab Seite 158 sehr 
detailliert beschrieben. Die Kanalauswahl scheint mir jetzt aber ein 
wenig unglücklich.

MfG Stephan

von Cyblord -. (cyblord)


Lesenswert?

Das Problem ist doch, dass es dabei nicht um die Funktion des Registers 
geht, sondern grundsätzlich um Bitoperationen. Was der Register in 
Endeffetk bewirkt ist doch dann eine ganz andere Geschichte. Darum brigt 
doch hier ein Kapitel über den ADC gar nichts, wenn die Grundlagen nicht 
sitzen.

gruß cyblord

von Unwissender (Gast)


Lesenswert?

unsigned int convertanalog(unsigned cha channel)
{
ADMUX=(1<<REFS1)|(1<<REFS0)|(channel & 0x0f);


.....
bla bla
.....


}

Aufruf:
adc0val=convertanalog(0);

von asdcvb (Gast)


Lesenswert?


von Stephan W. (kahlschlaechter)


Lesenswert?

Die Biteinstellung für ADMUX ist mit

ADMUX = (1<<REFS0) usw.
ADMUX = 0x00

beschrieben. Da es sich um ein Buch von 0 Wissen an handelt, meine ich, 
sollte es so doch möglich sein.
Welcher Wert in das Register muss steht im Datenblatt. Also habe ich den 
Wert für den entsprechenden Kanal abgelesen und eingegeben.

Bis zu dem Punkt ist mir das Buch sehr verständlich und hilfreich 
gewesen. Hoffentlich komme ich noch dahinter, was ich da falsch 
verstehe. :-)

@ Unwissender:

Diese Form habe ich auch schon gesehen. Welche Vorteile bringt sie mit?


Danke für eure Hilfe. Ich werde mich morgen weiter mit dem Thema 
beschäftigen.

MfG

von Stefan E. (sternst)


Lesenswert?

Stephan Winckler schrieb:
> Hoffentlich komme ich noch dahinter, was ich da falsch
> verstehe. :-)

Ach komm, so kompliziert ist das doch nicht.

i = 2;
i = 4;
Was ist nach diesen beiden Zeilen der Inhalt von i?

von Stephan W. (kahlschlaechter)


Lesenswert?

:-)


Eigentlich müsste es 4 sein.

von Stefan E. (sternst)


Lesenswert?

Stephan Winckler schrieb:
> Eigentlich müsste es 4 sein.

Ganz genau.

Und nun schau dir noch mal die ADMUX-Zeilen an:
ADMUX=0x11;
ADMUX=(0<<REFS1)|1<<REFS0);
Was ist nun der Inhalt von ADMUX nach diesen beiden Zeilen?
Und was bedeutet das für die Kanalauswahl?
(dass 0x11 sowieso der falsche Wert ist, lassen wir mal außer Betracht)

von Stephan W. (kahlschlaechter)


Lesenswert?

Guten Morgen,

Das heisst dann steht 1<<REFS1 USW da drin und das 0x11,auch wenn es der 
falsche Wert ist, wird überschrieben.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mich wundert (nicht wirklich), das in einem Elektor Buch reservierte 
Bits beschrieben werden, normalerweise tut man das nicht.
Beim ADMUX ist ein Schreiben in einem Rutsch, also per ADMUX = blabla 
ganz sinnvoll. Interessant wird es halt beim Starten des ADC über 
ADCSRA.
Da ist verodern mit dem Originalwert des Registers interessant, vor 
allem zum löschen des IRQ Flags und zum Starten des ADC:
1
// Setze Vorteiler und gib den ADC frei.
2
// Man beachte das vorbesetzen mit =
3
ADCSRA = (1<<ADEN) | (1<<ADPS2);
4
// nu wird der ADMUX besetzt
5
ADMUX = (1<<REFS0)|(1<<MUX0);
6
// und jetzt starten wir. Um ADCSRA nicht zu zermanschen, mit |=
7
ADCSRA |= (1 << ADSC);
Die Technik der Veroderns und VerANDens ist beim AVR gang und gäbe. Du 
kannst so in C gezielt einzelne Bits löschen und setzen, im Prinzip das, 
was die Assemblerbefehle CBI und SBI bzw. SBR und CBR auch machen.
Zum Löschen eines Bits nimmst du die Komplementärfunktion in C.
1
 
2
ADCSRA &= ~(1<<ADFR); // als Beispiel mal das Freerun Bit löschen
Die Wellenlinie ~ ist die Komplementärfunktion und das &= ist dann das 
VerANDen mit dem Ziel.
Diese Technik und die ausführliche Schreibweise führen dazu, das du dein 
Program auch nach Jahren noch lesen kannst, ohne im Datenblatt 
nachzulesen. Ausserdem musst du beim Wechsel auf einen anderen Mega 
nicht immer wieder schauen, ob die Bits ihre Position geändert haben.

von Stephan W. (kahlschlaechter)


Angehängte Dateien:

Lesenswert?

Moin nochmal,

danke Matthias für die Erklärungen. Eine Sache erschließt sich mir 
allerdings noch nicht. Wenn ich mit bspw. (1<<MUX0) den ADC-Kanal 0 
auswähle, müsste ich ja mit (1<<MUX1) usw die nächsten Kanäle ansteuern 
können. In der datei im Anhang habe ich einmal die MUX-Tabelle aus dem 
ATMEGA8 Datenblatt angehängt. Dort ist MUX3..0 beschrieben, aber 6 ADC 
Kanäle.
Wie spreche ich denn dann die letzten beiden an?

MfG

von Karl H. (kbuchegg)


Lesenswert?

Wobei ich hier bei den MUX Bits ausnahmsweise nicht auf die MUX 
Bitbezeichnungen gehen würde, sondern das ganze so ansetzen würde

Am Beispiel zur 'Aktivierung' des Kanals 5
1
  ADMUX = (1<<REFS0) | 5;
der Vorteil dieser Schreibweise ist ziemlich offensichtlich. Im Code 
steht für jeden lesbar, dass hier der Kanal 5 aktiviert wird.

Die MUX Bits sind genau so angeordnet, dass ihre binäre Repräsentierung 
exakt der Kanalzahl entspricht. Und in diesem Fall ist mir diese bessere 
Lesbarkeit das dann auch wert ausgenutzt zu werden.

Hat man in einem Programm mehere ADC Kanäle im Einsatz, dann eben zb so
1
#define ADC_COMMON     (1<<RAFS0)   // die allen ADC Messungen gemeinsamen Einstellungen
2
#define ADC_SOLL       0            // Kanal 0 ist der Sollwert
3
#define ADC_COMPARE_1  2            // Der erste Vergleichswert am ADC Kanal 2
4
#define ADC_COPMARE_2  4            // Der zweite Vergleichswert am ADC Kanal 4
5
6
...
7
8
9
10
   ADMUX = ADC_COMMON | ADC_SOLL;     // Sollwert messen
11
   ...
12
13
   ADMUX = ADC_COMMON | ADC_COMPARE_1;   // ersten Vergleichswert
14
   ...
15
16
   ADMUX = ADC_COMMON | ADC_COMPARE_2;   // zweiten Vergleichswert
17
   ...
(*)

bzw. dann eben die entsprechenden Varianten, wenn die ADC Funktionalität 
in einer eigenen Funktion steckt.

Da hat man dann das beste aus 2 Welten. Auf der einen Seite eine leichte 
Anpassbarkeit und auf der anderen Seite einen lesbaren, 
selbsterklärenden Code.

(*) wobei es dann natürlich sinnlos ist, im Kommentar die Kanalnummer 
noch einmal zu nennen. Steht ja eh schon im Makro und wurde hier im 
Kommentar nur deshalb angeführt, damit man die Verständllichkeit des 
Makros sieht.

von Stephan W. (kahlschlaechter)


Lesenswert?

Um nocheinmal auf das Buch zu sprechen zu kommen. Da steht als Beispiel

ADMUX = 0x01; drin. Das vierte Bit wird nicht angesprochen. Allerdings 
wird so beschrieben, dass so die Kanalauswahl funktioniert.
Für welche Funktion ist das vierte Bit denn im ATMEGA8 denn vorgesehen?

von Karl H. (kbuchegg)


Lesenswert?

Stephan Winckler schrieb:
> Um nocheinmal auf das Buch zu sprechen zu kommen. Da steht als Beispiel
>
> ADMUX = 0x01; drin. Das vierte Bit wird nicht angesprochen. Allerdings
> wird so beschrieben, dass so die Kanalauswahl funktioniert.
> Für welche Funktion ist das vierte Bit denn im ATMEGA8 denn vorgesehen?

Du musst dir eines angewöhnen.

Deine absolute, uneingeschränkte, über jeden Zweifel erhabene, für dich 
während der AVR-Programmierung einzig zuständige 'Bibel' ist das 
Datenblatt des Prozessors. Dort stehen die Antworten für alle deine 
Fragen, die sich um die Funktionsweise deines Prozessors und seiner 
Steuerregister drehen.

Das kriegst du bei ATmel auf der Homepage.

Und ja. Du brauchst das Datenblatt. Ohne kannst du nicht vernünftig 
programmieren. Kein Mensch kennt alle Bits auswendig. Was denkst du, wo 
wir nachsehen, wenn du fragst, was Bit 4 im ADMUX Register macht?
Wenn wir im Datenblatt nachsehen, dann kannst du das genausogut auch 
gleich selber machen.


Deine Bibel ist immer das Datenblatt und nicht irgendein windiges 
Elektor Buch.

Und diese Zuweisung von Hex-Zahlen an ein Register, die vergisst du am 
besten gleich wieder. Das sollte man ausdrucken und dem Autor solange um 
die Ohren dreschen, bis nur noch Konfetti übrig bleiben.

von Dietrich L. (dietrichl)


Lesenswert?

Stephan Winckler schrieb:
> Wenn ich mit bspw. (1<<MUX0) den ADC-Kanal 0
> auswähle,

Falsch. Bei Kanal 0 sind sind alle Bits (MUX0...3) = 0
Kanal 1: (1<<MUX0)
Kanal 2: (1<<MUX1)
Kanal 3: (1<<MUX1) | (1<<MUX0)
Kanal 4: (1<<MUX2)
...

> Dort ist MUX3..0 beschrieben, aber 6 ADC Kanäle.

Der ATmega8 hat nur 6 Kanäle, nur das Register ist gleich wie bei den 
Typen mit 8 Kanälen.

Gruß Dietrich

von Dietrich L. (dietrichl)


Lesenswert?

Stephan Winckler schrieb:
> Für welche Funktion ist das vierte Bit denn im ATMEGA8 denn vorgesehen?

Schau mal im Datenblatt: da steht "-", was bedeutet soviel wie "nicht 
benutzt" bzw. "keine Funktion". Beim Lesen liefert es "0".

Gruß Dietrich

von Stephan W. (kahlschlaechter)


Lesenswert?

Jetzt hab ichs! Die Auswahl der Kanäle erfolgt über über das Setzen der 
Bits im MUX Register. und über die 4 MUX´s kann ich alle 8 (wenn 
vorhanden) Kanäle anwählen.

Kanal 5 : (1<<MUX2) | (1<<MUX0)

Jetzt kanns weiter gehen.

@  Karl Heinz:

Das Datenblatt habe und verwende ich bereits soweit es meine 
Möglichkeiten zulassen.

@ Dietrich und Karl heinz:

Eure Hinweise, auch die Schreibweise, sind großartig und haben mir auch 
bei zukünftigen Problemen sehr geholfen!
Danke.

MfG

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Stephan Winckler schrieb:
> Um nocheinmal auf das Buch zu sprechen zu kommen. Da steht als Beispiel
>
> ADMUX = 0x01; drin.

In diesem Moment, und das ist das Problem, wird zwar der Eingangskanal 
schon auf 1 gesetzt, aber auch REFS0 und REFS1 auf 0. Das ist nicht das, 
was du möchtest.
Karl Heinz hat das sehr gut gelöst, indem er die gemeinsame Einstellung 
(nämlich REFS0 auf 1) in den #define ADC_COMMON gepackt hat, und dann 
den gewünschten Kanal mit dieser Einstellung verodert und in das ADMUX 
schreibt.

Dietrich L. schrieb:
>> Für welche Funktion ist das vierte Bit denn im ATMEGA8 denn vorgesehen?
>
> Schau mal im Datenblatt: da steht "-", was bedeutet soviel wie "nicht
> benutzt" bzw. "keine Funktion". Beim Lesen liefert es "0".

Das ist typisch für so eine Prozessorfamilie, die Jungs behalten sich 
vor, bei Nachfolgemodellen dieses Bit zu benutzen. Spassigerweise 
benutzen die direkten Nachfolger Mega48/88 etc. dieses Bit immer noch 
nicht. Also schön auf 0 lassen :-P
Nochmal zur Bitmanipulation. Besonders sinnvoll ist das natürlich für 
I/O Ports, um einen Pin high oder low zu setzen:
1
#define LED_PORT PORTB
2
#define LED_DIR DDRB
3
#define LED_GREEN_PIN 5   // eine grüne LED an PB5 , Kathode am Pin, Anode an Plus
4
// Port init 
5
LED_DIR = (1<<LED_GREEN_PIN)
6
7
// grüne LED an
8
LED_PORT &= ~(1<<LED_GREEN_PIN);
9
// grüne LED aus
10
LED_PORT |= (1<<LED_GREEN_PIN);
Wenn du jemals auf die Idee kommen solltest, das die LED an einem 
anderen Pin/Port besser aufgehoben ist, änderst du nur die #defines und 
fertig.
Auch ein Prozessorwechsel oder eine Platinenänderung schockt dich dann 
nicht mehr.

von Stephan W. (kahlschlaechter)


Lesenswert?

So nun habe ich die variante von Karl Heinz in das mein Programm 
integriert.
Mit meinen Einstellungen sieht das wie folgt aus:

#define ADC_Einstellung    (1<<REFS0)   // interne Referenzspannung
                                           für alle Messungen
#define ADC_Sollwert    2            // Wert von Sollwert an Kanal 2
#define ADC_Sensor_1    1            // Wert von Sensor 1 an Kanal 1
#define ADC_Sensor_2    0            // Wert von Sensor 2 an Kanal 0


und im Text:

[c] ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);  // ADC
                                                     Voreinstellungen
                                                 vornehmen
ADMUX = ADC_Einstellung | ADC_Sollwert;    // REF-Spannung wählen,
                                                Sollwertkanal einstellen
ADCSRA |= (1<<ADSC);                           //Einzelumwandlung 
verODERt
while (ADCSRA & (1<<ADSC));

Sollwert = ADCW; [c]

Die Ausgabe des Sollwertes funktioniert tadelos.

Das gleiche Vorgehen verwende ich für die anderen Werte. Nun ist das 
Problem, dass mir für die drei Kanäle die gleichen Werte zurück gegeben 
werden.

Ich habe nun probiert mit
ADCW = 0;
nach jeder Wandlung den Wert zu überschreiben. Aber ich erhalte trotzdem 
immer den Wert des Sollwertes. Auch wenn ich diesen verändere, ändert 
sich der Wert für Sensor 1 und 2 mit.

Kann mir jemand veraten, wo mein Denkfehler liegt?

MfG

von Karl H. (kbuchegg)


Lesenswert?

Stephan Winckler schrieb:

> Das gleiche Vorgehen verwende ich für die anderen Werte. Nun ist das
> Problem, dass mir für die drei Kanäle die gleichen Werte zurück gegeben
> werden.

Beschreib nicht deinen Code, zeig ihn einfach. So umfangreich wird der 
schon nicht sein. Es gibt noch hunderte andere Möglichkeiten, was da 
alles passiert sein kann.

von pico (Gast)


Lesenswert?

Stephan Winckler schrieb:
> Kann mir jemand veraten, wo mein Denkfehler liegt?

ADCH und ADCL kann nur gelesen werden. Erkennt man im Datenblatt daran, 
daß bei Read/write immer nur ein R bei den entsprechenden Registern 
steht.

von Stephan W. (kahlschlaechter)


Lesenswert?

Ok, dass ich das Ausgaberegister nicht beschreiben kann, habe ich 
verstanden.

@ Karl Heinz:

Den Code darf ich, wegen der Prüfung, die damit in Zusammenhang steht 
nicht veröffentlichen. Hast du eine Mailadresse oder gibt es PN in 
diesem Forum?


Ich habe des Weiteren mal nur die einzelnen Umwandlungen im Code 
gelassen.
Wenn ich die Werte einzelnd abfrage stimmen Sie. Allerdings sobald es 
zwei oder drei sind, dann wird der Wert immer noch in die anderen 
Messungen übernommen.

von Karl H. (kbuchegg)


Lesenswert?

Stephan W. schrieb:
> Ok, dass ich das Ausgaberegister nicht beschreiben kann, habe ich
> verstanden.
>
> @ Karl Heinz:
>
> Den Code darf ich, wegen der Prüfung, die damit in Zusammenhang steht
> nicht veröffentlichen. Hast du eine Mailadresse oder gibt es PN in
> diesem Forum?


Du meinst du darfst
1
int main()
2
{
3
  lcd_init();
4
5
  while( 1 ) {
6
7
    ADMUX = ...
8
    ADCSRA |= ...
9
    while( ADCSRA ... )
10
      ;
11
    Soll = ADCW;
12
13
    ADMUX = ...
14
    ADCSRA |= ...
15
    while( ADCSRA ... )
16
      ;
17
    Ist1 = ADCW;
18
19
    ADMUX = ...
20
    ADCSRA |= ...
21
    while( ADCSRA ... )
22
      ;
23
    Ist2 = ADCW;
24
25
    zb
26
    sprintf( buffer, "%04d %04d %04d", Soll, Ist1, Ist2);
27
    lcd_gotoxy( 0, 0 );
28
    lcd_puts( buffer );
29
  }
30
}

nicht veröffentlichen?
Na dann.

Man kann IMMER eine Aufgabe soweit abspecken, dass sie sich nur auf 
einen Aspekt konzentriert und man trotzdem das rauskriegt, was man 
wissen will.

von Stephan W. (kahlschlaechter)


Lesenswert?

Ok da hast du natürlich Recht. Es klang danach, dass ich den ganzen Code 
einstellen soll und das geht leider nicht.

Die Abschnitte sehen wie folgt aus:

Die defines:

#define ADC_Einstellung    (1<<REFS0)
#define ADC_Sollwert    2
#define ADC_Sensor_1    1
#define ADC_Sensor_2    0

Für den Sollwert:

ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
ADMUX = ADC_Einstellung | ADC_Sollwert;
ADCSRA |=(1<<ADSC);              while (ADCSRA & (1<<ADSC));

Sollwert = ADCW;

Für Sensorwert 1:

ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
ADMUX = ADC_Einstellung | ADC_Sensor_1;
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC));
Sensor_1 = ADCW;

Für Sensorwert 2:

ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
ADMUX = ADC_Einstellung | ADC_Sensor_2;
ADCSRA |= (1<<ADSC);

Sensor_2 = ADCW;


Ich habe den Fehler gefunden! Ich habe für Sensor 2 nicht gewartet, bis 
die Umwandlunge fertig war!
while (ADCSRA & (1<<ADSC));
hat bei dem zweitem Sensor gefehlt. Dann hat der prozessor also den 
Wert, der sich in ADCW befand genommen, da der aktuelle noch nicht 
volag!

MfG

von Karl H. (kbuchegg)


Lesenswert?

Stephan W. schrieb:


> Ich habe den Fehler gefunden! Ich habe für Sensor 2 nicht gewartet, bis
> die Umwandlunge fertig war!

Und .. du hast rausgefunden, warum es vernünftig ist, sich für 
Teilaufgaben, überhaupt wenn es immer die gleiche Teilaufgabe ist, sich 
Funktionen zu machen
1
uint16_t GetADC( uint8_t channel )
2
{
3
  ADMUX = ADC_COMMON | channel;
4
5
  ADCSRA |= ...
6
  while( ADCSRA ... )
7
    ;
8
9
  return ADCW;
10
}
11
12
int main()
13
{
14
  lcd_init();
15
16
  while( 1 ) {
17
18
    Soll = GetADC( ADC_SOLL );
19
    Ist1 = GetADC( ADC_COMPARE_1 );
20
    Ist2 = GetADC( ADC_COMPARE_2 );
21
22
    zb
23
    sprintf( buffer, "%04d %04d %04d", Soll, Ist1, Ist2);
24
    lcd_gotoxy( 0, 0 );
25
    lcd_puts( buffer );
26
  }
27
}

Nicht nur wird das Programm kürzer. Es wird auch übersichtlicher und 
wenn die Funktion für den einen Kanal funktioniert, funktioniert sie 
auch für die anderen.

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.