www.mikrocontroller.net

Forum: Compiler & IDEs ADC geht nicht


Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo
mein ADC-Code funktioniert nicht.
In Assembler habe ich es hinbekommen, das er funktioniert.
Nun wollte ich es in C probieren.
Weiß jemand warum dieser Code nicht funktioniert ?

#include <avr/io.h>        
#define F_CPU 3686400
#include <util/delay.h>

int main (void) 
{          
unsigned int x;
DDRB  = 0xff; 
ADMUX = (0 << MUX0) | (0 << MUX1) | (0 << MUX2) | (0 << MUX3) ;
ADMUX = (1 << REFS0) | (1 << REFS1) | (0 << ADLAR) ;
ADCSRA =(1 << ADEN) ; 
ADCSRA = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0) ;        
while(1)
{       

ADCSRA =(1<<ADSC);
loop_until_bit_is_clear (ADCSRA,ADSC);
x = ADCL + ADCH * 256;
if (x<20)
{
PORTB = 0x00;
}
else
{
PORTB = 0x01;
} 
}                         
return 0;                 
}

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spuckt der compiler medlungen aus?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ADCSRA =(1 << ADEN) ;
> ADCSRA = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0) ;

Du überschreibst mit der 2. Zeile die Einstellung von der 1. Zeile. Und 
in der Endlosschleife überschreibst du es wieder.

"=" -> "|="

http://www.mikrocontroller.net/articles/Bitmanipulation

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guenter B. wrote:
> Hallo
> mein ADC-Code funktioniert nicht.
> In Assembler habe ich es hinbekommen, das er funktioniert.
> Nun wollte ich es in C probieren.
> Weiß jemand warum dieser Code nicht funktioniert ?
Ich kann es mir zumindest denken, auch wenn Du in mehrfacher Hinsicht 
selbst gegen einfachste Forenregeln verstoßen hast (Controllertyp 
angeben, erzählen, was nicht funktioniert bzw. wie sich das 
nicht-Funktionieren manifestiert usw.)...
x = ADCL + ADCH * 256;
...Wenn Du in Assembler programmiert hast, dann weißt Du ja, dass beim 
Auslesen der ADC-Datenregister eine ganz bestimmte Reihenfolge 
einzuhalten ist (warum das so ist, steht im Datenblatt und im 
AVR-GCC-Tutorial, bitte dort nachlesen, falls noch nicht 
geschehen!). Bei dieser Zeile ist aber nicht definiert, in welcher 
Reihenfolge die Operanden ausgewertet werden, weshalb das mit ca. 
50-prozentiger Wahrscheinlichkeit schiefgeht.

Mit Deinem C-Compiler (ich vermute in mangels Angaben von Deiner 
Seite, dass es sich um den AVR-GCC handelt) kann Dir die Arbeit mit der 
richtigen Reihenfolge aber abnehmen. Dazu musst Du anstelle von ADCH und 
ADCL das 16-Bit-Register ADCW auslesen. Und lies Dir die betreffenden 
Abschnitte im AVR-GCC-Tutorial durch.

EDIT:
...und lies Dir das Posting von Stefan ganz genau durch...

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan
Also ich hatte folgende Zeile immer so interpretiert:

ADCSRA = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0) ;
Setzte ADPS2 in ADCSRA auf 1
Setzte ADPS1 in ADCSRA auf 0
Setzte ADPS0 in ADCSRA auf 1

unabhängig von der Reihenfolge.

Also als einfache Zuweisung nicht als Schiebevorgang.
In Assembler hatte ich mit sbi und cbi gearbeitet.

@Johannes
Ich hatte es auch schon mit
{x = ADCL;Y = ADCH;}
usw versucht.

Die Zeile {x = ADCL + ADCH * 256;} hatte ich in einem Buch gefunden.

Meine Verstöße gegen die Forenregeln vergebt mir bitte.
Da ich vermutet habe, daß die Erfahrerenen hier die Fehler in
meinen simplen Code Umgebungs- und Controllerunabhängig sofort erkennen,
habe ich diese Angaben für unnötig gehalten.

Ich danke euch für die schnelle Hilfe.

Gruß

Günter

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Zeile {x = ADCL + ADCH * 256;} hatte ich in einem Buch gefunden.

Dann würde ich dem Buch nicht mehr vertrauen. Such mal im von Johannes 
genannten AVR-GCC-Tutorial nach "ADCW". Die Lösung ist sehr einfach, du 
brauchst dafür ADCL und ADCH überhaupt nicht.


> ADCSRA = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0) ;
> Setzte ADPS2 in ADCSRA auf 1
> Setzte ADPS1 in ADCSRA auf 0
> Setzte ADPS0 in ADCSRA auf 1

(0 << ADPS1) ist das gleiche wie 0. Deine Zuweisung setzt also nicht nur 
ADPS1 auf 0, sondern auch alle anderen Bits, ausgenommen ADPS2 und 
ADPS0. Du musst bedenken, dass = in C für eine Variablenzuweisung steht, 
bei der grundsätzlich die komplette Variable mit dem überschrieben wird, 
was rechts vom = steht. Da ADCSRA ein 8-Bit-Register ist, werden durch 
deine Zuweisung auch 8 Bits überschrieben.

Wenn du stattdessen schreibst:
ADCSRA |= (1 << ADPS2) | (1 << ADPS0);
(also |= statt = )
dann werden tatsächlich nur die Bits ADPS2 und ADPS0 selektiv gesetzt. 
ADPS1 und alle anderen Bits werden nicht angefasst. Um dann ADPS1 zu 
löschen, kannst du sowas nehmen:
ADCSRA &= ~(1 << ADPS1);

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guenter B. wrote:
> @Stefan
> Also ich hatte folgende Zeile immer so interpretiert:
>
> ADCSRA = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0) ;
> Setzte ADPS2 in ADCSRA auf 1
> Setzte ADPS1 in ADCSRA auf 0
> Setzte ADPS0 in ADCSRA auf 1

Genau, und implizit noch dazu: setze den nicht erwähnten Rest auch auf 
0, also in dieser Zeile auch ADEN.

> unabhängig von der Reihenfolge.

Habe ich irgendetwas von der Reihenfolge innerhalb der Zeile 
geschrieben?

> Also als einfache Zuweisung nicht als Schiebevorgang.

Wo war denn von einem Schiebevorgang die Rede?

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Chris

Es lag nicht am Buch sondern an meiner Interpretation.
Es stand dort nämlich:

"Der effektive Messwert ergibt sich dann zu
x = ADCL + ADCH * 256 "

Weiter oben im Text stand dann auch, daß man ADCL unbedingt zuerst 
auslesen muß. Allerdings hatte ich es ja wie gesagt schon auf anderem 
Wege (erfolglos) versucht.

Inzwischen funktioniert das Programm.

Autor: Guenter B. (gbl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan

hier ein Auszug aus dem Tutorial dessen Link du angehängt hattest:

[Tutorial-Auszug]

Die letzte Zeile "entschlüsselt":

   1. (1 << n) : Zuerst wird durch die '<<'-Ausdrücke eine "1" n-mal 
nach links geschoben. Dies ergibt somit (in Binärschreibweise) 
0b00000001 für (1 << MEINBIT0) und 0b00000100 für (1 << MEINBIT2).

[/Tutorial-Auszug]

Hier mein vorläufiger Workarround:

ADMUX = 192;
ADCSRA =133;

:-)

Gruß

Günter

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Zeile {x = ADCL + ADCH * 256;} hatte ich in einem Buch gefunden.
Das das der Compiler selber richtig, wenn ich schreibe
x = ADC;
oder
x = ADCW;

Siehe auch Beitrag "Re: ADC Conversion"

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.