Forum: Compiler & IDEs Hilfe bei einem kleinen C-Programm (AD-Wandler)


von Bastian (Gast)


Lesenswert?

Hy,
habe das Programm in AVR Studio geschrieben und ist für den Mega8 
bestimmt. Auf der Platine habe ich alles nachgemessen und das stimmt 
soweit.
Das Programm soll Bits setzen wenn der ADC1 und der ADC2 
unterschiedliche Werte haben. Leider werden die Bits nicht gesetzt. Kann 
mir vielleicht jemand weiterhelfe? Wäre super.

#include <avr/io.h>

void reset();

int main (void) {
    reset();

    int adclow;
    int vertikallinks;
    int vertikalrechts;
  while(1)
  {

    ADMUX= 1;
          ADCSRA = (1<<ADSC);     //Start der Wandlung
    while ( ADCSRA & (1<<ADSC) ) // auf Abschluss der     Konvertierung 
warten
    {
    }
    adclow=ADCL;
    vertikallinks=ADCH;

    ADMUX=2;
    ADCSRA = (1<<ADSC);     //Start der Wandlung
    while ( ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung 
warten
    {
    }
    adclow=ADCL;
    vertikalrechts=ADCH;
    int ergebnis=vertikallinks-vertikalrechts;
    if(-1>ergebnis||1<ergebnis)
    {
      if(-1>ergebnis)
      {
        PORTB = (1<<PB2) | (0<<PB3);
      }
      else
      {
        PORTB = (0<<PB2) | (1<<PB3);
      }
    }
    else
    {
    PORTB=(0<<PB2)|(0<<PB3);
    }
  }  main();

   return 0;
}


void reset(){
        DDRD= 0xff;
    DDRB= 0x00;

    ADMUX= (0<<REFS1)|(1<<REFS0)|(1<<ADLAR);
    ADCSRA= (1<<ADEN)|(1<<ADPS2)|(ADPS1)|(ADPS0);
}

von Stefan (Gast)


Lesenswert?

Du vergleichst ja nur die oberen 8 Bit (ADCH) und verwirfst die unteren 
8 Bit (ADCL).

Dementsprechend hast du nur eine Chance, wenn wenn sich die 
digitalisierten Werte genügend unterscheiden.

Wie wäre es mit einer Nutzung der vollen Digitalisierungswerte?

    adclow = ADCL;
    vertikallinks = ADCH;
    vertikallinks = (vertikallinks << 8) | adclow;
    ...
    adclow = ADCL;
    vertikalrechts = ADCH;
    vertikalrechts = (vertikalrechts << 8) | adclow;
    ...

von Karl H. (kbuchegg)


Lesenswert?

Was mir auf die Schnelle auffällt:

Du konfigurierst hier

 ADCSRA= (1<<ADEN)|(1<<ADPS2)|(ADPS1)|(ADPS0);

den ADC. Leider zerstörst du dir hier

    ADCSRA = (1<<ADSC);     //Start der Wandlung

die Konfiguration. Wenn du dem Register ADCSRA etwas
zuweist, wird das komplette Register neu beschrieben,
nicht nur das ADSC Bit

  ADCSRA |= ( 1 << ADSC );


Mit ADMUX machst du genau den gleichen Fehler.

Eine extrem gute Idee ist es auch, sich einfach nur den
eingelesenen Wert einmal ausgeben zu lassen. Zuerst
mit dem einen Kanal und erst dann mit dem anderen.

In der Programmkette

  Eingabe
  Verarbeitung
  Ausgabe

kann man in jeder Stufe Fehler machen. Es hat keinen Sinn
daran zu glauben, dass man selbst jede Stufe hinkriegt.
Wenn das Gesamtsystem nicht funktioniert, dann muss jede
Stufe überprüft werden. Sinnvollerweise fängt man mal
damit an, ob die Eingabe überhaupt klappt. In deinem
Fall heist das: Welche Werte kommen den eigentlich vom ADC?

von Bastian (Gast)


Lesenswert?

Ich habe halt dadurch nur ein 8-Bit Wandler. Beim Vergleichen ist das 
doch eigentlich egal, oder?

von Bastian (Gast)


Lesenswert?

 @ Karl heinz Buchegger
Ei klaro, da hab ich ja gar nicht dran gedacht. Hab es geändert und es 
funktioniert. Falls es interresiert, hier noch mal das Programm:

#include <avr/io.h>

void reset();

int main (void) {
    reset();

    int adclow;
    int vertikallinks;
    int vertikalrechts;
  while(1)
  {

  ADMUX= (0<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(1<<MUX0)|(0<<MUX1);
  ADCSRA= (1<<ADEN)|(0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADSC);
    while ( ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung 
warten
    {
    }
    adclow=ADCL;
    vertikallinks=ADCH;

  ADMUX= (0<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(0<<MUX0)|(1<<MUX1);
  ADCSRA= (1<<ADEN)|(0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADSC);
    while ( ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung 
warten
    {
    }
    adclow=ADCL;
    vertikalrechts=ADCH;
    int ergebnis=vertikallinks-vertikalrechts;
    if(-1>ergebnis||1<ergebnis)
    {
      if(-1>ergebnis)
      {
        PORTB = (1<<PB2) | (0<<PB3);
      }
      else
      {
        PORTB = (0<<PB2) | (1<<PB3);
      }
    }
    else
    {
    PORTB=(0<<PB2)|(0<<PB3);
    }

  }  main();

   return 0;
}


void reset(){
        DDRD= 0xff;
    DDRB= 0x00;

}

von Stefan (Gast)


Lesenswert?

Aber dann nimm zum Vergleich die unteren 8 Bit. Im Moment wird ein 
Unterschied nur erkannt (Einwand von Karl heinz beachten!), wenn sich 
die Werte um mindestens 256 (8 Bit) unterscheiden. Es ist die Frage, ob 
du so grosse Änderungen anlegst.

Eine weitere Sache: Du holst dauernd frische Werte und du reagierst nur 
auf Änderungen von eben nach jetzt. Wenn sich nix ändert, werden die 
Bits von dir zurückgesetzt. Denk daran so ein µC ist sau schnell. Wenn 
die Bits z.B. eine LED steuern - du wirst das kurze Aufflackern nicht 
sehen!

von Karl H. (kbuchegg)


Lesenswert?

> wenn sich die Werte um mindestens 256 (8 Bit) unterscheiden.

Er hat ADLAR gesetzt.

von Bastian (Gast)


Lesenswert?

@Stefan
Danke für die Tips. War mein erstes C-Programm und mein erster 
AD-Wandler Einsatz (soll kein Ausrede sein;) ). Aber der obere Absatz 
verstehe ich nicht ganz. Es sollen einfach Spannungen von ca. 0V bis ca. 
3V gegeneinander verglichen werden. Und das mit einer Hysterese.

von Karl H. (kbuchegg)


Lesenswert?

Ich denke Stefan hat das ADLAR Bit übersehen.
Wenn es dir nichts ausmacht die untersten 2 Bits nicht
zu berücksichtigen, dann passt das schon.

von Stefan (Gast)


Lesenswert?

> Er hat ADLAR gesetzt.

Das habe ich nicht gesehen. Dann werden ja nur die zwei der 
niedrigwertigsten Bits weggeworfen.

x/X sind die 10 relevanten Bits für 0V..3V

ADCH     ADCL
xxxxxxxx XX000000

Mit voller 10-Bit Auflösung hätte man 3V / 2^10 = 2,93 mV 
Digitalisierauflösung. Ohne die Bits X hat man dann eine vierfach (2^2) 
gröbere Auflösung (11,72 mV).

Ich dachte es werden 8 Bits in ADCL weggeworfen. Das wäre eine 
Verminderung der Digitalisierauflösung um den Faktor 256 (2^8), d.h. ein 
Wert zum nächsten müsste sich um die 256er Stufe unterscheiden, um als 
anderer Wert erkannt zu werden.

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.