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


von Santigua .. (santigua)


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:

1
#include <avr/io.h>          
2
#include <util/delay.h>         
3
#include <stdint.h>
4
#include <stdlib.h>
5
6
 
7
int main (void) {            
8
 
9
  int sample,i,value;
10
  DDRB=0xFF;                     // alle Pins an PORTB als Ausgabeport
11
  ADMUX=( 1 << REFS0 )|( 0 << MUX0 )|( 0 << MUX1 )|( 0 << MUX2 )|( 0 << MUX3 );
12
  // Referenz also VCC und als Eingang ADC0 ausgewählt
13
  ADCSRA=( 1 << ADEN )|( 0 << ADFR )|( 0 << ADPS0 )|( 0 << ADPS1 );
14
  // AD-Wandler Enabled, Freerunnning aus, keinen Prescaler
15
  while(1)
16
  {
17
   sample=0;
18
    for(i=0;i<5;i++)
19
    {
20
       ADCSRA = (1<<ADSC);       //single conversion mode ein
21
       while(ADCSRA & ADSC);     //warten bis konvertierung abgeschlosen
22
       sample+=ADCW;       //aufsummierung der samplewerte
23
    }
24
    value=(sample/5);            //aritmethisches mittel der samplewerte
25
    //value=700;                 // Wenn ich hier einen Wert vorgebe, dann wird auch am Mega8 die richtige LED wie erwartet beschaltet
26
    if (value<300) {
27
       PORTB = ( 1 << PB0 )|( 0 << PB1 )|( 0 << PB2 );
28
    }
29
    else if (value>=300&& value<600) {
30
       PORTB = ( 0 << PB0 )|( 1 << PB1 )|( 0 << PB2 );
31
    }
32
    else {
33
       PORTB = ( 0 << PB0 )|( 0 << PB1 )|( 1 << PB2 );
34
    }
35
  }
36
 
37
   while(1) {                
38
     // "leere" Schleife;  
39
   }                         
40
 
41
   // wird nie erreicht 
42
   return 0;                
43
}


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

1
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

1
    ADCSRA = (1<<ADSC);       //single conversion mode ein
2
    while(ADCSRA & ADSC);     //warten bis konvertierung abgeschlosen
3
    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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Patric .. wrote:

Vorbildliche Problembeschreibung!

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

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-Tutorial#Aktivieren_des_ADC

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 |=

von Santigua .. (santigua)


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

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


geändert in

1
ADCSRA |= (1<<ADSC);           // single conversion mode ein
2
while(ADCSRA & (1<<ADSC));     //warten bis konvertierung abgeschlosen
3
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:
1
   if (value<200) {
2
    PORTB = ( 1 << PB0 )|( 0 << PB1 )|( 0 << PB2 )|( 0 << PB3 )|( 0 << PB4 );
3
    }
4
    else if (value>=200 && value<400) {
5
    PORTB = ( 0 << PB0 )|( 1 << PB1 )|( 0 << PB2 )|( 0 << PB3 )|( 0 << PB4 );
6
    }
7
    else if (value>=400 && value<600) {
8
    PORTB = ( 0 << PB0 )|( 0 << PB1 )|( 1 << PB2 )|( 0 << PB3 )|( 0 << PB4 );
9
    }
10
    else if (value>=600 && value<800) {
11
    PORTB = ( 0 << PB0 )|( 0 << PB1 )|( 0 << PB2 )|( 1 << PB3 )|( 0 << PB4 );
12
    }
13
    else {
14
    PORTB = ( 0 << PB0 )|( 0 << PB1 )|( 0 << PB2 )|( 0 << PB3 )|( 1 << PB4 );
15
    }
16
  }

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

von Santigua .. (santigua)


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! :)

von Michael Wilhelm (Gast)


Lesenswert?

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

MW

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich sehe keine Problemstellen im Sourcecode
1
   // Anm.: int value
2
3
   if (value < 200) {
4
       PORTB = (1 << PB0);
5
   }
6
   else if (value >= 200 && value < 400) {
7
       PORTB = (1 << PB1);
8
   }
9
   else if (value >= 400 && value < 600) {
10
       // Problemfall LED geht nie an
11
       PORTB = (1 << PB2);
12
   }
13
   else if (value >= 600 && value < 800) {
14
       // Problemfall LED geht nie an
15
       PORTB = (1 << PB3);
16
   }
17
   else /* value >= 800 */ {
18
       PORTB = (1 << PB4);
19
   }

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?

von Santigua .. (santigua)


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! :)

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.