Forum: Mikrocontroller und Digitale Elektronik Suche Komplettporgramm für ADC in C


von Dominik (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
seit einigen Wochen schaue ich mir hier eure Beiträge an.
Nun bin ich zur Zeit dabei das Tut durchzuarbeiten und hänge gerade an 
dem ADC des Atmega32.
Der wird mit 16Mhz betrieben und der Vorteiler entsprechend auf 128 
gesetzt.
Der Smartprog2 dient mir hierbei als Brenner.

Jetzt hab ich das Problem das ich gerne ein Programm hätte, mit dem ich 
die Werte des ADCL Registers direkt auf einen Port ausgeben möchte.

Anbei habe ich einen Anhang über den Versuch einen Vorhandenen Quellcode 
zu nutzen.

Der Quellcode im Tut liest ja nur einen Wert aus und Speichert ihn in 
der Variablen "result".

Meine Kenntnisse in C sind nicht gerade gut, so viel sei gesagt ;)

Danke schonmal für eure Hilfe.

von gast (Gast)


Lesenswert?

Hallo,

was passiert wenn du das "return (0);" rausnimmst?

von Dominik (Gast)


Lesenswert?

es passiert rein  gar nichts.

Die Pins 0-3 von PortB leuchten, vorher Pin 4-7.

Ich habe vergessen zu erwähnen das ich lediglich ein Poti messen will.

Auch am Poti drehen bringt nichts.

von Tim (Gast)


Lesenswert?

1
  // Jetzt 4x die analoge Spannung and Kanal channel auslesen
2
  // und dann Durchschnittswert ausrechnen.
3
  for(i=0; i<4; i++) {
4
    // Eine Wandlung
5
    ADCSRA |= (1<<ADSC);
6
    // Die Wandlung abwarten
7
    while(ADCSRA & (1<<ADSC));
8
    
9
    resulthigh = ADCW;
10
  }
11
  // ADC wieder deaktivieren
12
  ADCSRA = (0<<ADEN);
13
  resulthigh /= 4;

Funktioniert nicht, weil bei resulthigh = ADCW; die
addition fehlt. Der Code mist 4x und überschreibt das letzte
Ergebnis immer mit dem neuen. Danach teilt er das durch 4.
Dabei kommt dann etwas zwischen 0 und 255 raus, Was ja
deutlich kleiner als 700 ist.
Mach mal resulthigh += ADCW; draus, damit der aufsummiert.
Ausserdem musst du vor den 4 Messungen noch resulthigh auf 0
Setzen, da darin ja bereits der Dummy read gespeichert ist.

Dann sollte das gehen.

wenn nicht, Prüfe mal bitte ob der ADC im 8 Bit mode Arbeitet.

Wenn du den ADC wert Binär auf einem Port sehen willst
mach in main() sowas wie

PORTB = resulthigh / 4;

(Durch 4 da der AD 0..1023 misst, dein Port aber nur 0..255 anzeigen 
kann)

von Dominik (Gast)


Lesenswert?

hallo,
danke erstmal an die schnelle Hilfe. Habe ehrlich gesagt nicht damit 
gerechnet.
Werde mich heute nachmittag erst da rangeben können weil es ein Projekt 
für die Ausbildung sein soll

von Dominik (Gast)


Angehängte Dateien:

Lesenswert?

Hallo mal wieder,
bin heute noch dazu gekommen den Vorschlag von Tim durchzugehen, 
allerdings ohne erfolg.

Das Programm habe ich angepasst, nochmal nachgeschaut ob auch alles 
richtig verkabelt ist, allerdings tut sich rein gar nichts wenn ich das 
Poti ändere.

Aber ich habe es doch richtig verstanden das das Prog immer in einer 
Endlosschleife Werte vom ADC ließt und dann an die Variable übergibt.

Vielleicht noch jemand eine andere Idee?
Habs auch schon mit nem anderen ATMEGA32 getestet ohne Erfolg.

Den Code habe ich nochmal angehangen

von Johannes M. (johnny-m)


Lesenswert?

Hier setzt Du den Kanal:
>  ADMUX = channel;
>  //AREF als Spannungsquelle des ADC
...und hier löschst Du ADMUX komplett!
>  ADMUX = (0<<REFS0) | (0<<REFS1);
>  ADMUX = (0<<ADLAR);  //ergebnis rechtsb�ndig ausrichten
Das kann man auch einfach "ADMUX = 0;" schreiben. Überlege bitte mal, 
was "0 << IRGENDWAS" ergibt...

OK, in Deinem Fall ist dieser Klops fast egal, weil sowieso Kanal 0 
gewandelt wird, aber das solltest Du in Zukunft anders machen.

Gleiches gilt natürlich für die Zeile "ADCSRA = (0 << ADEN);". Es gibt 
unendlich viele Möglichkeiten, eine Null zu schreiben, aber es gibt in 
den meisten Fällen keinen Grund, nicht die kürzeste und einfachste zu 
nehmen.

von Johannes M. (johnny-m)


Lesenswert?

Das hier
> DDRA = 0xff;
...schaltet den kompletten Port A als Ausgang. Da beim ATMega32 aber 
die Analog-Eingänge an Port A liegen, ist das sehr wenig sinnvoll...

von Gast (Gast)


Lesenswert?

Ist das "return (0);" nicht böse zur while Schleife?

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> Ist das "return (0);" nicht böse zur while Schleife?
Richtig, das return hat in der while-Schleife nichts zu suchen!

von Dominik (Gast)


Lesenswert?

@johannes

So hatte ich das aus dem Tut herauskopiert. Anscheinend läuft es auch 
mit diesen Einstellungen.

Das man "0" auch anders schreiben kann vor allem in registern ist mir 
bewusst ;)
Hatte es irgendwann mal getestet und ist dann leider auch so hängen 
geblieben. Danke für den Tip.

Die Sache mit den Eingängen schalten wird es wohl sein, leider habe ich 
die sachen nicht hier.

@gast
return(0) wird in dieser Funktion nie erreicht. Man kann es genausogut 
weglassen, ändert aber beim µC gar nichts. Zumindest habe ich nix 
festgestellt.

Danke euch vielmals. Werde mich morgen wieder melden wenn ich die Sachen 
ausprobiert habe.

von M. M. (miszou)


Lesenswert?

Hi

das return(0) gehört aber nach der schließenden Klammer vom while (1), 
bzw. es gehört zum int main(void) und wird deshalb nie erreicht, weil du 
die while (1) Schleife nicht verläßt. So stehts auch im Tut.

Gruß MISZOU

von Johannes M. (johnny-m)


Lesenswert?

Dominik wrote:
> @johannes
>
> So hatte ich das aus dem Tut herauskopiert. Anscheinend läuft es auch
> mit diesen Einstellungen.
Was läuft? Das Tutorial auf dieser Seite ist für einen ATMega8 
geschrieben. Bei dem liegen die Analog-Eingänge an Port C. Beim ATMega32 
sind sie an Port A, wie ein Blick ins Datenblatt auch Dir offenbaren 
wird.

> @gast
> return(0) wird in dieser Funktion nie erreicht.
Doch, in Deinem Fall wird es erreicht! Es steht in der while-Schleife 
und wird nach der if-Abfrage erreicht...

von Karl H. (kbuchegg)


Lesenswert?

Johannes M. wrote:

> Doch, in Deinem Fall wird es erreicht! Es steht in der while-Schleife
> und wird nach der if-Abfrage erreicht...

Und ich möchte hinzufügen: Eine vernnftige und konsistente 
Einrückstrategie hätte das auch klar und deutlich gezeigt.

Wieder mal ein Fall, indem eine saubere Codeformatierung Wunder wirken 
kann.

von Dominik (Gast)


Lesenswert?

Ich danke euch vielmals für die Hilfe.
Das Programm funktioniert nun einwandfrei.

Anbei möchte ich nochmals anmerken das ich wirklich blutiger Anfänger 
bin.
Den Code hänge ich später noch an.

von Dominik (Gast)


Angehängte Dateien:

Lesenswert?

So hier im Anhang befindet sich wie versprochen ein kleines Programm, 
mit dem der ADC in 50er Schritten jeweils eine LED weiter schaltet.

Vielen Dank nochmals für eure Hilfe

von Rainer I. (raih)


Lesenswert?

Hallo Dominik,

um die ganzen if Abfragen zu vereinfachen kannst Du auch modulo rechnen.
1
  while(1)
2
  {
3
    PORTD = (readADC(0) % 50) + 1
4
  }

von Johannes M. (johnny-m)


Lesenswert?

Rainer I. wrote:
> um die ganzen if Abfragen zu vereinfachen kannst Du auch modulo rechnen.
Wieso Modulo ? Du weißt, was Modulo macht? Hier muss, wenn überhaupt, 
dann eine normale Division her. Der Rest der Division interessiert 
hier nicht.

von Rainer I. (raih)


Lesenswert?

Sorry, hast Recht. Hab mich vertan.
1
while(1)
2
  {
3
    PORTD = (readADC(0) / 50) + 1
4
  }

von Dominik (Gast)


Lesenswert?

Mit dieser Zeile geht vergleicht er immer "result" in 50er Schritten und 
addiert dann in Binärform eine LED weiter?

von Johannes M. (johnny-m)


Lesenswert?

Dominik wrote:
> Mit dieser Zeile geht vergleicht er immer "result" in 50er Schritten und
> addiert dann in Binärform eine LED weiter?
Genau! Er will schließlich, dass schon bei 0 < result < 50 eine LED 
leuchtet. Da käme bei der Division aber 0 raus, deshalb muss das 
Divisionsergebnis um eins erhöht werden.

von Dominik (Gast)


Lesenswert?

Hallo
Habe es gerade ausprobiert.
Die Version von Johannes Funktioniert super.

von Johannes M. (johnny-m)


Lesenswert?

Dominik wrote:
> Die Version von Johannes Funktioniert super.
Welche Version von mir?

von Dominik (Gast)


Lesenswert?

while(1)
  {
    PORTD = (readADC(0) / 50) + 1
  }

;)

von Johannes M. (johnny-m)


Lesenswert?

Dominik wrote:
> while(1)
>   {
>     PORTD = (readADC(0) / 50) + 1
>   }
>
Naja, geschrieben hat es Rainer, nur die Korrektur kam von mir...

von Dominik (Gast)


Lesenswert?

ja gut
an alle ein Dankeschön

von Gast (Gast)


Lesenswert?

ich habe hierzu mal eine frage:

wenn ich AREF mit VCC verbinde und ADMUX = 0 setze funktioniert mein 
programm nicht mehr, setze ich ADMUX = (1<<REFS0) funktioniert es. woran 
liegt das? muss ich AREF überhaupt mit VCC verbinden?

VCC = 5 V bei einem ATMEGA168

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> wenn ich AREF mit VCC verbinde und ADMUX = 0 setze funktioniert mein
> programm nicht mehr, setze ich ADMUX = (1<<REFS0) funktioniert es. woran
> liegt das? muss ich AREF überhaupt mit VCC verbinden?
Das musst Du nicht nur nicht tun, das solltest Du sogar besser sein 
lassen!

AREF ist ausschließlich zum Anschließen einer Referenzspannung, die 
nicht vom Controller intern zur Verfügung gestellt werden kann. AVCC 
kann aber intern ausgewählt werden.

von Gast (Gast)


Lesenswert?

gut danke erstmal. also löte ich das wieder ab und lasse AREF frei oder 
muss ich den irgendwie beschalten? ich werde dann VCC und AVCC mit 5V 
beschalten und dann ADMUX = 0 setzen. an meinen ADC eingängen hängt ein 
10 kohm poti mit max 5V dran. gibts daran was zu verändern? ich will 
werte von 0 - kleiner 5V einlesen.

achso: ich hatte mal einen schaltplan gesehen, wo AREF mit VCC über eine 
induktivität (10µH?) miteinander verbunden war. was spricht den 
eigentlich dagegen?

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> gut danke erstmal. also löte ich das wieder ab und lasse AREF frei oder
> muss ich den irgendwie beschalten?
An AREF normalerweise 100 nF gegen GND.

> ich werde dann VCC und AVCC mit 5V
> beschalten und dann ADMUX = 0 setzen. an meinen ADC eingängen hängt ein
> 10 kohm poti mit max 5V dran. gibts daran was zu verändern? ich will
> werte von 0 - kleiner 5V einlesen.
Wenn das Poti auch an AVCC hängt, ist das kein Problem.

> achso: ich hatte mal einen schaltplan gesehen, wo AREF mit VCC über eine
> induktivität (10µH?) miteinander verbunden war. was spricht den
> eigentlich dagegen?
Wo hast Du das denn gesehen? Normalerweise wird AVCC mit VCC über 
einen LC-Tiefpass verbunden. AREF sollte mit einem 100nF-Kondensator 
nach GND beschaltet werden, sonst nichts, außer Du willst eine externe 
Referenzquelle verwenden. Gegen eine Verbindung von AREF und AVCC 
spricht (neben der o.g. Sinnlosigkeit) auch, dass man ja vielleicht auch 
mal eine andere Referenzquelle auswählen möchte, was dann nicht mehr 
geht.

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.