Problem mit A/D-Wandlung

#1251978
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
#1252060
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...
#1252466
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?
#1253294
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren