Forum: Mikrocontroller und Digitale Elektronik Auswertung von ADCL via LEDs


von Stefan G. (atomkaktus)


Lesenswert?

Hallo.

Mein Ziel:

Um den ADC zu testen habe ich ein Poti (10kOhm) an einen ATMEGA8a 
angeschlossen(PC0/ADC0). Programiert habe ich die ADC Ansteuerung nach 
der ->
(https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe) 
Vorlage. Das Ergebnis soll über PORTB ausgegeben werden.


Code:
1
#include <avr/io.h>
2
#include <stdint.h>  
3
4
void ADC_Init (void)
5
{
6
  ADMUX |= (1<<REFS0);            //Interne Referenzspannung (5V) einschalten
7
  ADCSRA |= (1<<ADPS0)  | (1<<ADPS1);    
8
//1MHz/0,2MHz=5 -> Prescaler = 8 
9
  ADCSRA |= (1<<ADEN);            //ADW Start
10
  
11
  ADCSRA |= (1<<ADSC);            //warte auf Ende der Messung
12
  while (ADCSRA & (1<<ADSC)){          
13
  }
14
  (void) ADCW;                       //?????????
15
}
16
17
18
uint16_t ADC_Mess (uint8_t chanel)
19
{
20
  ADMUX = (ADMUX & ~(0x1F)) | (chanel & 0x1F);    
21
//Kanalwahl  
22
  ADCSRA = (1<<ADSC);  
23
//ADW Start
24
  while (ADCSRA & (1<<ADSC)){      
25
  }
26
//warte auf Ende der Messung
27
  
28
  return ADCW;
29
//Rückgabe von Messsignal
30
}
31
32
33
int main (void) {
34
  
35
  uint8_t chanel = 0;    //ADW Kanal (PC0/ADC0) = 0
36
  uint16_t Messwert;
37
  
38
  DDRB = 0xFF;      //PORTB wird Ausgang
39
  PORTB = 0xFF;      //alle PINs hight (LEDs aus)
40
  
41
42
  ADC_Init();      //ADW initialisieren
43
  
44
  while (1)
45
  {
46
    Messwert = ADC_Mess(chanel);    
47
//Mess-Funktion-Start
48
  
49
    uint8_t low = Messwert;      
50
    uint8_t hight = (Messwert>>8);
51
//16bit Var. in 2x 8bit Var.
52
  
53
    if (PIND&(1<<PIND0))    //wenn Taster an PD0=1,
54
      {               //
55
      PORTB &= ~low;  //PORTB und inv. "low"    
56
                  }    //->LEDs leuchten
57
      
58
        
59
      
60
    if (PIND&(1<<PIND1))  //
61
    {      //wenn Taste an PD1=1,
62
    PORTB = 0xFF;    //Alle LEDs aus
63
    }             //
64
  }  
65
  return 0;
66
}
Problembeschreibung:

1. Die AD-Wandlung wird nur einmal durchgeführt (nach dem 
Build-Vorgang).
   Die LEDs Leuchten dann entsprechend der eingestellten Spannung am ADC
   korrekt auf.
   Ich bin davon ausgegangen, dass der ADC beim nächsten Schleifenumlauf
   erneut startet und einen neuen Wert in ADCL und ADCH schreibt?!

2. Beim Drücken vom Taster an:

        a) PD0 werden die Ausgänge (PORTB) auf hight gesetzt
           (U_LED=0,0V -> LEDs gehen aus).

        b) PD1 weden die Ausgägne (PORTB) auf low gesetzt
           (U_LED=4,0V -> LEDs gehen aus).

  Wenn keine taste gedrückt ist liegt über den LED konstnt eine Spannung
  von 0,26V! Also die (richtigen) LEDs leuchten ganz schwach.

3. Ab einer Bestimmten Spannung (U_ADC=50mV) am ADC fängt an mein AVRISP
   mkII die Orange LED an zu blinken.
   Da dies etwas mit der RESET LINE zutun hat habe ich den Weg von 
AVRISP
   zum IC geprüft. Alles i.O. Verbindung besteht, Pull-Up liegt an hight
   und der Pufferkondensator auf low (wie hier->
   https://www.mikrocontroller.net/articles/AVR-Tutorial:_Equipment
   beschrieben).


Ich bitte um Rat.

ps: Die Links zu den Tutorials kenn ich ;) . Bei Verweisen dahin bitte 
ich um genauere Ausführungen. Danke.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

in ADC_Mess:
1
...
2
  ADCSRA = (1<<ADSC);  
3
...

Gratuliere. Du hast dir soeben die restliche Konfiguration in ADCSRA 
zerstört.

Sagtest du nicht, du hättest dich an den Tutorial Routinen orientiert? 
Warum hast du die denn nicht erst mal einfach 1:1 übernommen (mit 
Ausnahme der Referenzspannungseinstellung). Nur so, um zu sehen ob auch 
alles so funktioniert wie vorgesehen und ERST DANN eigene Funktionen 
geschrieben?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Stefan Gl. schrieb:

>   Wenn keine taste gedrückt ist liegt über den LED konstnt eine Spannung
>   von 0,26V! Also die (richtigen) LEDs leuchten ganz schwach.

Wie sind deine Taster angeschlossen?

Es ist ungewöhnlich, dass man Taster so anschliest, dass sie eine 1 
liefern, wenn der Taster gedrückt wird. Denn dann braucht man einen 
externen Pulldown Widerstand.
Normal wird ein Taster so angeschlossen, dass er eine 0 liefert wenn er 
gedrückt wird, denn dann kann man den internen Pullup Widerstand einfach 
auf den Portpin zuschalten und hat damit immer einen gesicherten 
Port-Pin Zustand.


Also: wie sind deine Taster angeschlossen und hast du externe 
Pullup/Pulldown Widerstände verbaut?
Und nein, das ist nicht egal. Denn wenn da kein Pullup/Pulldown 
Widerstand ist, der dem Pin bei nicht gedrücktem Taster einen Pegel 
aufzwingt, dann ist es zufällig ob der Pin 0 oder 1 liefert. D.h. nicht 
ganz zufällig, sondern der Pin fängt sich jedes dahergelaufene 
elektromagnetische Feld ein, dass in der näheren Umgebung rumschwirrt. 
Und davon haben wir jede Menge rund um uns. Der/die Taster liefern dann 
unter Umständen in den Hauptschliefendurchgängen nicht einfach nur 0, 
sondern ab und auch mal eine 1. Und die siehst du dann, weil dein Code 
ja dann die Ausgänge 'einschaltet' nur um sie ein paar µs später wieder 
abzuschalten. Dein Multimeter kann dir so schnelle Vorgänge aber nicht 
zeigen, in zeitlichen Mittel ergibt sich aber auf die Art eine kleine 
Spannung, nach dem Muster: ist der Pin bei 100 mal nachsehen 98 mal auf 
0 (also 0V) und 2 mal auf 1 (also 5V), dann ist das im zeitlichen Mittel 
auch eine Spannung von 0.1V

: Bearbeitet durch User
von Stefan G. (atomkaktus)


Lesenswert?

Karl Heinz schrieb:
> Gratuliere. Du hast dir soeben die restliche Konfiguration in ADCSRA
> zerstört.

Danke XD.

Oh, da fehlt ein | .
Das heißt, dass ich nicht bitweise oder-verknüpft habe. Was habe ich den 
jetzt damit bewirkt?
Ist der Schaden irreperabel?

Karl Heinz schrieb:
> Warum hast du die denn nicht erst mal einfach 1:1 übernommen (mit
> Ausnahme der Referenzspannungseinstellung).

Weil bei 1:1 der Lerneffekt nicht so groß ist. Und wenn der IC futsch 
ist, ist das Lehrgeld (1,51€) ;) .


Karl Heinz schrieb:
> Es ist ungewöhnlich, dass man Taster so anschliest, dass sie eine 1
> liefern, wenn der Taster gedrückt wird. Denn dann braucht man einen
> externen Pulldown Widerstand.

Genau da liegt mein Problem nr.2 . Bei anderen Programmen (z.B.Licht n 
leuchtet bei Tastendruck n) liefert der Ausgang mir eine 0 beim 
Tastendruck.

Karl Heinz schrieb:
> wie sind deine Taster angeschlossen und hast du externe
> Pullup/Pulldown Widerstände verbaut?

Die Taster sind zwischen PIN und GND, die externen Pull-Ups zwischen PIN 
und vcc (dieser -> 
https://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen 
Quelle nachempfunden).

Karl Heinz schrieb:
> Denn wenn da kein Pullup/Pulldown
> Widerstand ist, der dem Pin bei nicht gedrücktem Taster einen Pegel
> aufzwingt, dann ist es zufällig ob der Pin 0 oder 1 liefert.
...

Klingt nachvollziehbar und logisch. hab den ext. Pull-up geprüft: Er hat 
kontakt zu den Pins.

: Bearbeitet durch User
von Stefan G. (atomkaktus)


Lesenswert?

Achso... und kann mir jemand erklären was

Stefan Gl. schrieb:
> (void) ADCW;

<-diese Zeile macht?

Ich hätte erstmal auf einen Rückgabewert getippt. Das sieht jedoch meist 
so aus: return (Wert);

Wenn ich das richtig verstanden habe ist void ein Platzhalter für den 
Fall, dass nichts zurückgegeben werden soll!?

von Stefan G. (atomkaktus)


Lesenswert?

Nach der Korrektur des Codes "ADCSRA |= (1<<ADEN);" ist Problem nr.1 
(nur eine Messung pro Build) gelöst. Karl Heinz, danke dafür :).

Den Controller habe ich mit einem einfachen Programm gefüttert:

#include <avr/io.h>

int main (void) {

  DDRB = 0xFF;
  PORTB = 0xFF;

  DDRD = 0x00;

  int n;

  while(1)
  {
    for (n=0;n<=3;n++)
    {
    if (PIND&(1<<n))
      PORTB |= (1<<n);
      else PORTB &= ~(1<<n);
    }
  }

  return 0;
}

Also der Controller reagiert noch.
Ob ADCSRA unwiederruflich defekt ist kann ich nicht beurteilen.

Ich habe das Programm auch noch mit einem zweiten amega8a getestet 
(nachdem ich den Code korregiert habe). Die gleichen Symptome.

Die LEDs glimmen weiter vor sich hin. Mit PD1 Schalte ich alles ein, mit 
PD0 aus (sollte ja eigendlich anders herum sein). Und auch der AVRISP 
blinkt weiterhin ab 50mV.

Sind denn die Ausgabebefehle korrekt?

Die Spannung am PC0 Messe ich gegen Masse gemessen (da ich gelesen habe, 
dass die Spannung am ADC GRND<U_ADC<U_ref sein soll). Sie liegt zwischen 
0V<U<4,8V.

: Bearbeitet durch User
von Stefan G. (atomkaktus)


Lesenswert?

Problemlösung:

Karl Heinz schrieb:
> Es ist ungewöhnlich, dass man Taster so anschliest, dass sie eine 1
> liefern, wenn der Taster gedrückt wird.

Oder anders gesagt: Normaler Weise (kein Pull-down) liefert ein 
gedrückter Taster eine 0.

Bei der Taster-Abfrage habe ich jedoch eine 1 abgefragt:

Stefan Gl. schrieb:
> if (PIND&(1<<PIND0))    //wenn Taster an PD0=1,
>       {               //
>       PORTB &= ~low;  //PORTB und inv. "low"
>                   }    //->LEDs leuchten
>
>
>
>     if (PIND&(1<<PIND1))  //
>     {      //wenn Taste an PD1=1,
>     PORTB = 0xFF;    //Alle LEDs aus
>     }             //

Dies hat zur Folge, dass sowohl der einschalt Prozess (über PD0) als 
auch der ausschalt Prozess (über PD1) dauerhaft durchlaufen.
Wenn ich nun den Taster an PD0 betätige ziehe ich ihn auf 0 und die 
erste if Schleife wird ausgeklammert (LEDs werden nur noch 
ausgeschaltet). Analog gilt das gleiche für die zweite if Schleife 
(PD1).

Das glimmen der LEDs bei ungedrückter Taste lässt sich wie folgt 
erklären:

Der ADC unterscheidet nicht mit 100%tiger Genauigkeit darüber ob eine 
bestimmte Spannung Bit n oder Bit n+1 ist. Es gibt Übergänge.
Da der Controller mehrmals pro Sek. misst und ein Ergebnis ausgibt 
(welches halt nicht genaue grenzen zu dem nächst höheren Wert hat) wird 
der ausgang sehr schnell zwischen ein und aus hin und her geschaltet. 
Ähnlich wie bei dem Eingang ohne Pull-up/Pull-down oben von Karl Heinz 
beschrieben:

Karl Heinz schrieb:
> Der/die Taster liefern dann
> unter Umständen in den Hauptschliefendurchgängen nicht einfach nur 0,
> sondern ab und auch mal eine 1. Und die siehst du dann, weil dein Code
> ja dann die Ausgänge 'einschaltet' nur um sie ein paar µs später wieder
> abzuschalten. Dein Multimeter kann dir so schnelle Vorgänge aber nicht
> zeigen, in zeitlichen Mittel ergibt sich aber auf die Art eine kleine
> Spannung, nach dem Muster: ist der Pin bei 100 mal nachsehen 98 mal auf
> 0 (also 0V) und 2 mal auf 1 (also 5V), dann ist das im zeitlichen Mittel
> auch eine Spannung von 0.1V

Auch hier nochmal vielen Dank. Der oben beschriebene Tipp hat mich auf 
die Lösung gebracht!

So muss die Ausgabe aussehen:

if (!(PIND&(1<<PIND0))) //Wenn PD0=0 (Taste gedrückt)
{
    PORTB = 0xFF;     //Setz alle Ausgangsbits auf 1 (LEDs aus)
    PORTB &= ~low;  //und dann alle Bits vom ADC in PORTB auf0(LEDs an)
}

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.