ADC geht nicht

OP #990856
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 ?

1
#include <avr/io.h>        
2
#define F_CPU 3686400
3
#include <util/delay.h>
4

5
int main (void) 
6
{          
7
unsigned int x;
8
DDRB  = 0xff; 
9
ADMUX = (0 << MUX0) | (0 << MUX1) | (0 << MUX2) | (0 << MUX3) ;
10
ADMUX = (1 << REFS0) | (1 << REFS1) | (0 << ADLAR) ;
11
ADCSRA =(1 << ADEN) ; 
12
ADCSRA = (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0) ;        
13
while(1)
14
{       
15

16
ADCSRA =(1<<ADSC);
17
loop_until_bit_is_clear (ADCSRA,ADSC);
18
x = ADCL + ADCH * 256;
19
if (x<20)
20
{
21
PORTB = 0x00;
22
}
23
else
24
{
25
PORTB = 0x01;
26
} 
27
}                         
28
return 0;                 
29
}
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.)...
1
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...
OP
@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
Gast
> 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);
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?
OP
@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.
OP
@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

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 18 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.