Forum: Mikrocontroller und Digitale Elektronik ADC und Atmega8 = Problem?


von JTR (Gast)


Lesenswert?

Hallo,

also es geht um folgendes. Ich habe 2 Spannungen zu messen. Die eine 
steht für eine Leistung (entsprechend vorbereitet) und die andere steht 
für die Richtigkeit der ersten Spannung (wegen der Linearität des IC der 
die erste Spannung erzeugt).

Nun wandle ich die beiden Spannungen und entscheide dann was zu tun ist.

Hier is der Code dazu:
1
#include <avr/io.h>
2
#include <stdint.h>
3
#include <lcd.h>
4
5
//Funktionsdeklaration (Prototypen)
6
7
//ADC Init.
8
void vinitADU_8Bit(unsigned short int);
9
10
int igetADU_8Bit(unsigned short int);
11
12
13
void main (void)
14
{//Variablen Definition
15
  char cPuffer[100];
16
  int iPuffer=0,iWait=0;
17
18
 //Deklaration der PORTS --> "Richtung"
19
  DDRD = 0xff;    //0xff --> Ausgang
20
  DDRC = 0x00;    //0x00 --> Eingang
21
  DDRB = 0xff;
22
  PORTB = 0xff;
23
24
25
 //Initialisierung des ADCs
26
  vinitADU_8Bit(0);
27
28
29
    /* Initialisiere Display, Cursor aus*/
30
    lcd_init(LCD_DISP_ON);
31
  
32
  /* loesche das LCD Display und Cursor auf 1 Zeile, 1 Spalte */
33
    lcd_clrscr();
34
        
35
    /* String auf Display anzeigen */
36
    lcd_puts("Willkommen");
37
 
38
   for (iWait;iWait<30000;iWait++);
39
    iWait=0;
40
41
   while(1) 
42
   {
43
    if (igetADU_8Bit(2)<5)
44
    {
45
      iPuffer=(4000*igetADU_8Bit(0))/51;
46
      //Typ konvertierung für "lcd_puts"- Funktion
47
      itoa(iPuffer,cPuffer, 10);  //(int Variable, char Variable, Basis (binär, dezimal, hex)
48
49
      lcd_clrscr();
50
      lcd_puts(cPuffer);
51
    }
52
53
  else if (igetADU_8Bit(2)>50)
54
    {  PORTB = 0xff;
55
      lcd_clrscr();
56
      lcd_puts("Betrieb");
57
    }
58
59
60
   }   
61
}
62
63
64
65
//Funktionen
66
67
void vinitADU_8Bit(unsigned short int usimux)
68
{//Eigene Funktion zur ADU Initialisierung damit diese nicht ständig ausgeführt werden muss
69
int iresult;
70
ADMUX = usimux;     // Kanal waehlen
71
ADMUX |= 0x60;     // AVCC als Referenzspannung nutzen und Ergebnis soll linksbündig sein (nur ADCH)
72
ADCSRA |= 0x85;   // Frequenzvorteiler
73
          // setzen auf 8 (1) und ADC aktivieren (1)
74
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
75
also einen Wert und verwirft diesen, um den ADC "warmlaufen" zu lassen*/
76
77
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
78
79
  while(ADCSRA&(1<<ADSC)) 
80
    {
81
     // auf Abschluss der Konvertierung warten
82
    }
83
iresult = ADCH;  // ADCH muss einmal gelesen werden,
84
        // sonst wird Ergebnis der nächsten Wandlung
85
        // nicht übernommen.
86
ADCSRA &= ~(1<<ADEN); // ADC deaktivieren
87
88
PORTB=0x00;
89
90
iresult = 0;
91
}
92
93
94
int igetADU_8Bit(unsigned short int usimux)
95
{  int iresult;
96
  ADMUX = usimux;     // Kanal waehlen
97
  ADCSRA |= 0x80;     //ADC aktivieren (1)
98
99
100
  ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
101
    while ( ADCSRA & (1<<ADSC) ) 
102
      {
103
      // auf Abschluss der Konvertierung warten
104
      iresult = ADCH; // Wandlungsergebnisse abholen
105
      }
106
107
  ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
108
109
  return iresult;
110
}

Was übersehe ich? Das Problem ist nämlich das ich nie in den zweiten 
Zweig komme :(.

MFG

von Karl H. (kbuchegg)


Lesenswert?

1
int igetADU_8Bit(unsigned short int usimux)
2
{  int iresult;
3
  ADMUX = usimux;     // Kanal waehlen

Tja. Damit ist dann die Einstellung der Referenzspannung hinfällig 
geworden.

von Karl H. (kbuchegg)


Lesenswert?

1
  ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
2
    while ( ADCSRA & (1<<ADSC) ) 
3
      {
4
      // auf Abschluss der Konvertierung warten
5
      iresult = ADCH; // Wandlungsergebnisse abholen
6
      }

Ähm. Welche Vorstellung hast du vom Begriff 'Warten'? Was wird man 
sinnvollerweise tun, während man wartet? Den ADC auslesen? Eher nicht. 
Denn ADC wird man auslesen, nachdem das Warten vorbei ist. Denn das war 
ja der Sinn des Wartens: den ADC in Ruhe seine Arbeit machen lassen. Ist 
er fertig, meldet er sich. Die Warterei hat ein Ende und man kann sich 
den Wert holen.

Weiter gehts
1
  ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)

Aha. Wer schaltet eigentlich im nächsten Schleifendurchlauf, beim 
nächsten Aufruf der get Funktion, den ADC wieder ein?

von Karl H. (kbuchegg)


Lesenswert?

1
   while(1) 
2
   {
3
    if (igetADU_8Bit(2)<5)
4
    {
5
      iPuffer=(4000*igetADU_8Bit(0))/51;
6
      //Typ konvertierung für "lcd_puts"- Funktion
7
      itoa(iPuffer,cPuffer, 10);  //(int Variable, char Variable, Basis (binär, dezimal, hex)
8
9
      lcd_clrscr();
10
      lcd_puts(cPuffer);
11
    }
12
13
  else if (igetADU_8Bit(2)>50)

bist du sicher, dass du hier in jedem Durchlauf durch die Schleife den 
ADC-Kanal 2 tatsächlich 2 mal neu abfragen willst?
Im schlimmsten (zugegeben konstruierten) Fall liefert der erste Aufruf 
den Wert 51 und der zweite Aufruf den Wert 4. Und trotzdem wird dann 
keiner der Werte korrekt ausgewertet.

von Karl H. (kbuchegg)


Lesenswert?

JTR schrieb:

> Was übersehe ich? Das Problem ist nämlich das ich nie in den zweiten
> Zweig komme :(.

Noch ein Hinweis:
Du hast ein LCD zur Verfügung.
Niemand hindert dich daran, es in der Entwicklungsphase auch dazu zu 
benutzen, sich Werte anzeigen zu lassen, wie zb die Werte, die der ADC 
liefert (ohne Umrechnung, so wie der ADC den Wert auswirft).
Solche Hilfsausgaben, die natürlich wieder entfernt werden wenn alles 
ferig ist, sind oft sehr hilfreich um zu verstehen, was in einem 
Programm abgeht und um Problemen auf die Spur kommen zu können.

von JTR (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> int igetADU_8Bit(unsigned short int usimux)
1
{  int iresult;
2
   ADMUX = usimux;     // Kanal waehlen
>
>
> Tja. Damit ist dann die Einstellung der Referenzspannung hinfällig
> geworden.

Also was du damit meinst ist mir nicht klar?!


1
 ADCSRA |= 0x80;     //ADC aktivieren (1)

Damit wird der ADU in jedem Durschlauf wieder aktiviert!


Karl heinz Buchegger schrieb:
> bist du sicher, dass du hier in jedem Durchlauf durch die Schleife den
> ADC-Kanal 2 tatsächlich 2 mal neu abfragen willst?
> Im schlimmsten (zugegeben konstruierten) Fall liefert der erste Aufruf
> den Wert 51 und der zweite Aufruf den Wert 4. Und trotzdem wird dann
> keiner der Werte korrekt ausgewertet.


Naja, die Spannung die gewandelt wird, wird über ein Poti eingestellt 
(zur Zeit noch). Das stell ich ein mal ein und dann greif ich es nicht 
mehr an. Mit Voltmeter gemessen: am Kanal 2 liegen zB 2,5V an
Trotzdem geht er nicht in den 2. Zweig, obwohl 2,5V etwa 127 ergeben 
sollte.

Ich verwende das LCD sehr wohl! :D

So, mal ein riesen Danke an dich Karl Heinz, dass du mir so genau Tipps 
gegeben hast. Ich komme leider erst morgen dazu deine Tipps aus zu 
probieren.

von Karl H. (kbuchegg)


Lesenswert?

JTR schrieb:
> Karl heinz Buchegger schrieb:
>> int igetADU_8Bit(unsigned short int usimux)
>
1
{  int iresult;
2
>    ADMUX = usimux;     // Kanal waehlen
>>
>>
>> Tja. Damit ist dann die Einstellung der Referenzspannung hinfällig
>> geworden.
>
> Also was du damit meinst ist mir nicht klar?!


  i = 5;
  i = 8;

welchen Wert hat i, nachdem diese beiden Anweisungen durchgelaufen sind? 
Überlebt irgendein Bit von i = 5 die Zuweisung von 8? Wohl eher nicht.

Nach
      ADMUX = usimux;     // Kanal waehlen[/c]

sind alle anderen Bits die du vorher so mühsam in der init Funktion in 
ADMUX gesetzt hast, wieder auf 0. Und damit ist die Einstellung für die 
Referenzspannung, die ebenfalls über ADMUX gemacht wird, futsch bzw. 
eine andere als du bei einem Blick auf die init Funktion denkst.

>
1
 ADCSRA |= 0x80;     //ADC aktivieren (1)
>
> Damit wird der ADU in jedem Durschlauf wieder aktiviert!

mein Fehler.
Hab den Code nur nach ADEN abgesucht und nicht gefunden.
SChreib das doch bitte als

   ADCSRA |= ( 1 << ADEN );

so wie du das beim Ausschalten auch machst. Dann übersieht man das nicht 
so leicht.

> Trotzdem geht er nicht in den 2. Zweig, obwohl 2,5V etwa 127 ergeben
> sollte.

Sollte!
Hast du das kontrolliert?
Wechen Wert liefert der ADC?

> Ich verwende das LCD sehr wohl! :D
Das war auch mehr als Hinweis gedacht, was du tun kannst, wenn du nicht 
verstehst, warum ein if nicht funktioniert oder eine Berechnung nicht ds 
erwartete Ergebnis liefert.
Viele Programmierer haben aus irgendeinem nicht verständlichen Grund 
Angst davor, sich Zwischenergebnisse ausgeben zu lassen. Dabei würde ein 
Blick auf ein paar Variablen sofort Licht ins Dunkel bringen. Aber aus 
irgendeinem Grund schrecken sie davor zurück kurzzeitig ein paar printf 
(bei dir eben Ausgaben aufs LCD) einzubauen, die danach wieder entfernt 
werden. Es scheint fast so, dass sie lieber im Nebel stochern als die 15 
Sekunden Zusatzarbeit zu machen.

von Justus S. (jussa)


Lesenswert?

JTR schrieb:
> Karl heinz Buchegger schrieb:
>> int igetADU_8Bit(unsigned short int usimux)
>
1
{  int iresult;
2
>    ADMUX = usimux;     // Kanal waehlen
>>
>>
>> Tja. Damit ist dann die Einstellung der Referenzspannung hinfällig
>> geworden.
>
> Also was du damit meinst ist mir nicht klar?!

schau dir doch in deinem Code mal an, wie du die Ref auswählst...


> Damit wird der ADU in jedem Durschlauf wieder aktiviert!

und das ist einer der Gründe, warum man sowas

> ADCSRA |= 0x80;

nicht macht!

von JTR (Gast)


Lesenswert?

Für was Initialisier ich den ADU denn überhaupt?
Ich muss doch nicht jedes mal meine ref. Spannung einstellen.
Dazu ist diese Funktion:
1
void vinitADU_8Bit(unsigned short int usimux)



>und das ist einer der Gründe, warum man sowas
> ADCSRA |= 0x80;
>nicht macht!

Was nicht macht?
Du redest ihn Rätseln....

von Karl H. (kbuchegg)


Lesenswert?

JTR schrieb:
> Für was Initialisier ich den ADU denn überhaupt?
> Ich muss doch nicht jedes mal meine ref. Spannung einstellen.

Genau darum geht es im Grunde ja :-)

Mittels
   ADMUX = usimux

stellst du eine neue Referenzspannung ein!
Unabsichtlich! Ich bin sicher du woltest das gar nicht. Aber du tust es! 
Du setzt alle Bits, die die Referenzspannung einstellen auf 0!

>
>>und das ist einer der Gründe, warum man sowas
>> ADCSRA |= 0x80;
>>nicht macht!
>
> Was nicht macht?
> Du redest ihn Rätseln....

vergleiche
1
   ADSCRA |= 0x80;
2
3
   ...
4
5
   ADCSRA &= ~( 1<<ADEN );

mit
1
   ADCSRA |= (1<<ADEN);
2
3
   ...
4
5
   ADCSRA &= ~( 1<<ADEN );

bei welcher Version sieht auch ein Blinder, dass die eine Operation die 
Umkehrung der anderen ist?

von JTR (Gast)


Lesenswert?

Jetzt ist mir alles klar.
Werde, die Tipps morgen probieren und euch berichten.
Ich hoffe, dass es laufen wird :).

MFG

von JTR (Gast)


Lesenswert?

Scheint so weit zu funktionieren! Danke!
War wohl die Änderung der ref. Spannung und, dass zu frühe abholen des 
Ergebnisses.

1
  ADMUX &= 0xF0;
2
  ADMUX |= usimux;     // Kanal waehlen
3
  ADCSRA |= 0x80;     //ADC aktivieren (1)

Hab es nun so gelöst :).
Und das Abholen des Ergebnisses hab ich einfach außerhalb der Schleife 
gemacht.

MFG

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.