www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Mega8 und Werte aus ADCW werden nicht übernommen


Autor: Santigua .. (santigua)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, ich bin langsam am verzweifeln...

Die SuFu hat leider auch nicht zur Lösung beigetragen, lediglich das 
Problem konnte ich eingrenzen...

Also: Ich habe hier einen Mega8 auf nem STK500 und progge mit 
AVRStudio4.

Ziel ist es den ADC zu verwenden eine Spannung einzulesen und dann über 
3 LEDs auszugeben in welchem Drittel sich die Spannung befindet.
Also etwa so:
LED1 = 0...1/3*5V
LED2 = 1/3*5...2/3*5V
LED3 = 2/3*5...5V

Dazu habe ich den GND, VCC und ADC0 auf ein ProjectBoard geführt und 
folgende Schaltung gesteckt:


VCC
--
  |      10K-Poti
  |     /
  ---
  | |
  | | --- ADC0
  | |
  ---
  |
  |
--
GND

Also ein einfacher Spannungsteiler mit einem 10K-Poti.

Dazu habe ich folgenden Code:


#include <avr/io.h>          
#include <util/delay.h>         
#include <stdint.h>
#include <stdlib.h>

 
int main (void) {            
 
  int sample,i,value;
  DDRB=0xFF;                     // alle Pins an PORTB als Ausgabeport
  ADMUX=( 1 << REFS0 )|( 0 << MUX0 )|( 0 << MUX1 )|( 0 << MUX2 )|( 0 << MUX3 );
  // Referenz also VCC und als Eingang ADC0 ausgewählt
  ADCSRA=( 1 << ADEN )|( 0 << ADFR )|( 0 << ADPS0 )|( 0 << ADPS1 );
  // AD-Wandler Enabled, Freerunnning aus, keinen Prescaler
  while(1)
  {
   sample=0;
    for(i=0;i<5;i++)
    {
       ADCSRA = (1<<ADSC);       //single conversion mode ein
       while(ADCSRA & ADSC);     //warten bis konvertierung abgeschlosen
       sample+=ADCW;       //aufsummierung der samplewerte
    }
    value=(sample/5);            //aritmethisches mittel der samplewerte
    //value=700;                 // Wenn ich hier einen Wert vorgebe, dann wird auch am Mega8 die richtige LED wie erwartet beschaltet
    if (value<300) {
       PORTB = ( 1 << PB0 )|( 0 << PB1 )|( 0 << PB2 );
    }
    else if (value>=300&& value<600) {
       PORTB = ( 0 << PB0 )|( 1 << PB1 )|( 0 << PB2 );
    }
    else {
       PORTB = ( 0 << PB0 )|( 0 << PB1 )|( 1 << PB2 );
    }
  }
 
   while(1) {                
     // "leere" Schleife;  
   }                         
 
   // wird nie erreicht 
   return 0;                
}



Nun ist es aber leider so, dass die Variable sample bzw dann auch value 
stets den Initialwert behält, also null. Kommentiere ich die Zeile


value=700;



wiede ein, so wird auch die richtige LED beschaltet, somit scheint der 
Teil zumindest zu funktionieren.

Aber der muC liest halt einfach keine Werte ein, daher vermute ich mal, 
dass mein Fehler irgendwie in der For-Schleife, also in dem Abschnittt

    ADCSRA = (1<<ADSC);       //single conversion mode ein
    while(ADCSRA & ADSC);     //warten bis konvertierung abgeschlosen
    sample+=ADCW;       //aufsummierung der samplewerte


zu finden sein sollte...

Vielleicht kann ja mal jemand drüber schaun was ich falsch mache,...
...denn das der Mega8 defekt sein soll, will/kann ich irgendwie nicht 
glauben... (andere Programme führt er nämlich tadellos aus, nur mit dem 
ADC hab ich mich scheinbar verkracht.)

Danke schon mal im Voraus, ich bin für jeden Tipp dankbar.

Grüße Santigua

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patric .. wrote:

Vorbildliche Problembeschreibung!

>
>     ADCSRA = (1<<ADSC);       //single conversion mode ein
>     while(ADCSRA & ADSC);     //warten bis konvertierung abgeschlosen
>     sample+=ADCW;       //aufsummierung der samplewerte
> 

Drekfuhler!

Korrigiere

      while(ADCSRA & ADSC);     //warten bis konvertierung abgeschlosen

in

      while(ADCSRA & (1<<ADSC));     //warten bis konvertierung 
abgeschlosen

Vergleiche auch
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

ADD: bei ADCSRA = (1<<ADSC); steckt auch ein Fehler. Nicht die Zuweisung 
des gesamten Registers ist gefordert sondern nur des einen Bits. Das 
geht mit dem bitweisen ODER |=

Autor: Santigua .. (santigua)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DANKE Du bist mein HELD für heute...  :)




Ich musste in der Tat die genannte Zeile korrigieren - plus - in der 
Zeile davor eine Pipe einfügen...

also

ADCSRA = (1<<ADSC);       //single conversion mode ein
while(ADCSRA & ADSC);     //warten bis konvertierung abgeschlosen
sample+=ADCW;             //aufsummierung der samplewerte


geändert in

ADCSRA |= (1<<ADSC);           // single conversion mode ein
while(ADCSRA & (1<<ADSC));     //warten bis konvertierung abgeschlosen
sample+=ADCW;                  //aufsummierung der samplewerte

Nun liest der ADC auch meine Werte ein....

SUPER!! :)

Allerdings, nun habe ich den LED-Ausgabe-Teil etwas erweitert und nun 
macht er etwas ganz Lustiges....

Ich habe die If-Abfrage nun noch etwas erweitert, um meine Spannung grob 
in 20%-Schritten ausgegeben zu bekommen...

Also:
   if (value<200) {
    PORTB = ( 1 << PB0 )|( 0 << PB1 )|( 0 << PB2 )|( 0 << PB3 )|( 0 << PB4 );
    }
    else if (value>=200 && value<400) {
    PORTB = ( 0 << PB0 )|( 1 << PB1 )|( 0 << PB2 )|( 0 << PB3 )|( 0 << PB4 );
    }
    else if (value>=400 && value<600) {
    PORTB = ( 0 << PB0 )|( 0 << PB1 )|( 1 << PB2 )|( 0 << PB3 )|( 0 << PB4 );
    }
    else if (value>=600 && value<800) {
    PORTB = ( 0 << PB0 )|( 0 << PB1 )|( 0 << PB2 )|( 1 << PB3 )|( 0 << PB4 );
    }
    else {
    PORTB = ( 0 << PB0 )|( 0 << PB1 )|( 0 << PB2 )|( 0 << PB3 )|( 1 << PB4 );
    }
  }

Drehe ich nun an meinem Poti funktioniert bei LED0, LED1 und LED4 alles 
prima, aber das Intervall für LED2 und LED3, value liegt also im 
Intervall [400,800) da scheint er nie reinzugehen...

Fehler im Code?
Ungenauigkeit?
Oder hängt das evt mit dem Prescaler zusammen?
Oder was könnte es noch für Gründe geben, dass value in das o.g. 
Intervall nicht reingeht?

Übrigens: Ich muss das Poti wirklich um gut 40% drehen, damit die 
Anzeige von LED1 auf LED4 umspringt...

Grüße Santigua

Autor: Santigua .. (santigua)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kommando zurück, das "Lustige" verhalten entsteht dann, wenn man zur 
"Kontrolle" zwischen ADC0 und GND noch eine LED anschließt.

Denn, dadurch nimmt man quasi eine DiodenKennlinie auf....

=> LED raus und schon skaliert mein Poti nahezu linear über die 5 LEDs


DANKE NOCHMALS für Deine Hilfe! :)

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aber dieses ganze 0 geshifte kannst du dir in der LED Ausgabe trotzdem 
sparen.

MW

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sehe keine Problemstellen im Sourcecode

   // Anm.: int value

   if (value < 200) {
       PORTB = (1 << PB0);
   }
   else if (value >= 200 && value < 400) {
       PORTB = (1 << PB1);
   }
   else if (value >= 400 && value < 600) {
       // Problemfall LED geht nie an
       PORTB = (1 << PB2);
   }
   else if (value >= 600 && value < 800) {
       // Problemfall LED geht nie an
       PORTB = (1 << PB3);
   }
   else /* value >= 800 */ {
       PORTB = (1 << PB4);
   }
 

Hast du die Hardware kontrolliert, z.B. mal beim Fall <200 und 400bis600 
mal die LED im Programm getauscht? Hängt in der Schaltung noch was 
anderes an PB2 oder PB3? PB2 und PB3 sind laut Datenblatt Atmega8 
I/O-Pins?

Autor: Santigua .. (santigua)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Siehe oben:

...das "Lustige" Verhalten entsteht dann, wenn man zur
"Kontrolle" zwischen ADC0 und GND noch eine LED anschließt.

Denn, dadurch nimmt man quasi eine DiodenKennlinie auf... ;)

=> LED raus und schon skaliert mein Poti nahezu linear über die 5 LEDs


DANKE NOCHMALS für Deine Hilfe! :)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.