Forum: Mikrocontroller und Digitale Elektronik Problem mit A/D-Wandlung


von Michael M. (robertt)


Lesenswert?

Hallo an alle!

Ich versuche mich gerade neu am Microcontroller programmieren.
Mein Ziel ist es, eine Spannung, abgegriffen über ein Potentiometer
(o-5V), in ein digitales Signal umzuwandeln, und je nach dem, wie hoch
die Spannung ist, möchte ich, dasss erst keine, dann eine, dann zwei und
schließlich 3 LEDs leuchten.
Ich habe ein Atmega8 (myAVR Board USB2.0), dabei habe ich das
Potentiometer an PortC.0 angeschlossen, dies entspricht dem Channel0 im
A/D-Wandler. Als Ausgabe dienen normal die Ports B.0 bis B.2.

Hier mein kleines Programm:

#define F_CPU 3686400
#include <avr\io.h>
#include <avr/interrupt.h>
#include <inttypes.h>


ISR (ADC_vect)
{
  int wert;
  wert = ADC;                             //Konvertierte Zahl wird in
ADC gechrieben

  if (0b0000000000 < wert <= 0b0100000000)//0V - 1,25V
    PORTB = 0b00000000;
  if (0b0100000000 < wert <= 0b1000000000)//1,25V - 2,5V
    PORTB = 0b00000001;
  if (0b1000000000 < wert <= 0b1100000000)//2,5V - 3,75V
    PORTB = 0b00000011;
  if (0b1100000000 < wert <= 0b1111111111)//3,75V - 5V
    PORTB = 0b00000111;

  sbi (ADCSRA,6);

}

void initADC()
{
  ADMUX  = 0;                             // Kanal 0
  ADCSRA = 0xDD;                          //enable, free run,
intterrupt, runtergetaktet(da adu langsamer als CPU)
}

int main (void)
{

  DDRB = 0xFF;                            // Port B = Ausgang
  PORTB= 0xFF;
  initADC();
  sei ();                                 // Interupts erlauben
  do { } while(true);

}


Ich habe die 5V in 4 Bereiche eingeteilt und diese dann in etwa ins
binäre 10Bit umgerechnet, da laut Datenblatt 0V 0000000000b entsprechen
und 5V 1111111111b. Wie man sieht ist ein 10bit AD-Umwandler vorhanden.

Mein Problem ist nun, dass immer alle 3 LED leuchten, egal wie ich das
Potentiometer drehe. Könnte es vllt. Probleme mit der 10bit gewandelten
Zahl geben?

Vielen Dank für eure Hilfe
Viele Grüße

von Justus S. (jussa)


Lesenswert?

AREF nicht angeschlossen?

von Michael M. (robertt)


Lesenswert?

da nimmt er die boardspannung, müsste ich denke ich nicht extra 
anschließen, laut datenblatt;

von Justus S. (jussa)


Lesenswert?

Michael M. schrieb:
> da nimmt er die boardspannung, müsste ich denke ich nicht extra
> anschließen, laut datenblatt;

nö, du stellst doch auf AREF, und wenn da nix anliegt, ist dein Wandler 
doch immer auf Maximalwert...

von Michael M. (robertt)


Lesenswert?

also ich hab gerade noch mal geschaut, aref ist mit dem potentiometer 
verbunden

von Justus S. (jussa)


Lesenswert?

Michael M. schrieb:
> also ich hab gerade noch mal geschaut, aref ist mit dem potentiometer
> verbunden

AREF geht über einen Kondensator an GND laut Schaltplan...

von Michael M. (robertt)


Lesenswert?

und das heißt jetzt für mich? ( wenn ich die leiteruüge an der 
boarunterseite weiter verfolge, komme ich zum potentiometer :()

von Justus S. (jussa)


Lesenswert?

Michael M. schrieb:
> ( wenn ich die leiteruüge an der
> boarunterseite weiter verfolge, komme ich zum potentiometer :()

ein Blick in den Schaltplan wäre sinnvoller...

und wenn ich mal davon ausgehe, dass du einen Poti auf dem Board 
benutzt, bei denen eh schon VCC anliegt, wäre es irgendwie praktisch, 
die Spannung auch als Referenz zu wählen...

übrigens wäre es auch nett von dir, wenn du Schaltpläne etc und was du 
wie angeschlossen hast von Anfang an preisgibst und dir nicht alles aus 
der Nase ziehen lässt...irgendwie geht jeder zweite Fragesteller hier 
davon aus, dass alle anderen Kristallkugeln zu Hause haben...

von Michael M. (robertt)


Lesenswert?

Es tut mir leid, dass ich mich hier noch nicht so auskenne. Ich versuche 
mich gerade in die Thematik tiefer einzusteigen.

Verbunden ist es, keine Änderung. Ich denke, dass es am Programm liegt.

von Karl H. (kbuchegg)


Lesenswert?

Michael M. schrieb:
> also ich hab gerade noch mal geschaut, aref ist mit dem potentiometer
> verbunden

Und? Hängt da sonst noch was an AREF?

So wie du ADMUX programmiert hast, musst du eine externe Spannung an 
AREF anschliessen.

Man kann über ADMUX den AREF Pin auch so programmieren, dass sich der µC 
selbst eine Referenzspannung erzeugt.

>  ADCSRA = 0xDD;                          //enable, free run,

Mach das nicht.
Kein Mensch hat Lust dazu, 0xDD im Kopf in eine binäre Darstellung 
umzuwandeln um mit dem Datenblatt zu recherchieren, welche Bits du da 
gesetzt hast.
0xDD = 0b11011101
Das ist ADEN, ADSC, ADIF, ADIE, ADPS2, ADPS0 gesetzt.

Schreib das auch im Code so!

   ADCSRA = ( 1 << ADEN ) | ( 1 << ADSC ) |
            ( 1 << ADIF ) | ( 1 << ADIE ) |
            ( 1 << ADPS2 ) | ( 1 << ADPS0 );

Damit sieht man auch im Code zumindest mal, welche Bits im Control 
Register gesetzt werden und muss nicht mühsam eine Hex-Zahl 
auseinanderpfriemeln.

Ich seh nirgends, wo du ADATE setzt um den Free Running Mode zu 
aktivieren.

Das hier
1
  if (0b0000000000 < wert <= 0b0100000000)//0V - 1,25V
2
    PORTB = 0b00000000;
3
  if (0b0100000000 < wert <= 0b1000000000)//1,25V - 2,5V
4
    PORTB = 0b00000001;
5
  if (0b1000000000 < wert <= 0b1100000000)//2,5V - 3,75V
6
    PORTB = 0b00000011;
7
  if (0b1100000000 < wert <= 0b1111111111)//3,75V - 5V
8
    PORTB = 0b00000111;

ist falsch. Du kannst Vergleiche nicht so kaskadieren, wie du dir das 
vorstellst. Ein Vergleichsoperator hat im Regelfall immer links von sich 
einen Wert und rechts von sich einen Wert. Mehrere Vergleiche werden mit 
&& bzw. || miteinander verknüpft. Das was du da geschrieben hast, ist 
zwar nach den C-Regeln durchaus erlaubt und syntaktisch korrekt, macht 
aber ganz was Anderes als du vermutest. Auch gibt es nun wirklich keinen 
Grund da Binärzahlen für die Werte zu verwenden. Dein ADC liefert Werte 
von 0 bis 1023. Die Binärdarstellung interessiert normalerweise 
niemanden. Interessant ist praktisch immer das Verhältnis des ADC Wertes 
zu 1023, da es eine Aussage darüber erlaubt in welchem Verhältnis die 
gemessene Spannung zu AREF steht. AREF kennt man und daher kann man 
zurückrechnen, welche Spannung am Messeingang anliegt. Das sind aber 
alles Berechnungen. Da interessieren Zahlen und keine einzelnen Bits. 
Wenn du zum setzen der Portbits für die Anzeige Binärdarstellung 
benutzt, dann geht das in Ordnung (auch wenn es da eine bessere 
Schreibweise gibt): Dort ist jedes einzelne Bit wichtig, weil jedes Bit 
für eine LED steht. Und in einer Binärdarstellung sieht man wiederrum 
besser welches Bit gesetzt wird und welches nicht - vulgo: welche LED 
eingeschaltet wird und welche nicht. Die Wahl der Darstellung einer 
Zahl, dezimal hex oder binär, passt man dem Verwendungszweck an und 
welcher Aspekt davon wichtig ist.

besser so:
1
  unsigned int wert;     // wert kann per Definition nicht negativ sein
2
  wert = ADCW;           // Konvertierte Zahl wird in
3
4
  if ( wert <= 256 )     // 0V - 1,25V
5
    PORTB = 0b00000000;
6
7
  else if ( wert <= 512 ) // 1,25V - 2,5V
8
    PORTB = 0b00000001;
9
10
  else if ( wert <= 768 ) // 2,5V - 3,75V
11
    PORTB = 0b00000011;
12
13
  else
14
    PORTB = 0b00000111;

PS: Warum verwendest du für deine ersten Versuche nicht die 
funktionierende ADC Routine aus dem Tutorial?

von Michael M. (robertt)


Lesenswert?

Hab vielen Dank, jetzt funktioniert es, super ;). Mir war nich bewusst, 
dass mein Vergleich mit dem Wert so nicht geht. Ich dachte, dass meine 
Syntax funktioniert.

Hab auch vielen Dank für deine konstruktive Kritik, ich wusste auch 
nicht, dass ich ADCSRA auf deinem Weg initialisieren kann. So erscheint 
es natürlich logischer und nachvollziehbarer.
Ich werde bei meinem nächsten Problem versuchen, es verständlicher zu 
machen. Ich dachte eben, dass ich solche Kniffe von Profis hier lerne 
und nicht schon wissen muss und nicht als Neuling (auch im Forum) gleich 
angeraunt werde.

Vielen Grüße

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.