Forum: Mikrocontroller und Digitale Elektronik ADC misst immer 5V


von Hans Wurst (Gast)


Angehängte Dateien:

Lesenswert?

1
#include <avr/io.h>
2
3
4
/* ADC initialisieren */
5
void ADC_Init(void) 
6
{
7
 
8
  uint16_t result;
9
 
10
   ADMUX = (0<<REFS1) | (1<<REFS0) | (1<<MUX1);    // AVCC als Referenzspannung nutzen
11
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
12
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
13
 
14
  /* Dummy-Readout */
15
 
16
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
17
  while (ADCSRA & (1<<ADSC) );          // auf Abschluss der Konvertierung warten
18
  /* ADC einmal lesen  */
19
  result = ADC;
20
}
21
 
22
/* ADC Einzelmessung */
23
uint16_t ADC_Read(uint8_t channel)
24
{
25
  // Kanal waehlen, ohne andere Bits zu beeinflußen
26
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
27
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
28
  while (ADCSRA & (1<<ADSC) ); 
29
                                 // auf Abschluss der Konvertierung warten
30
  return ADC;                    // ADC auslesen und zurückgeben
31
  main=ADC;
32
}
33
 
34
/* ADC Mehrfachmessung mit Mittelwertbbildung */
35
uint16_t ADC_Read_Avg(uint8_t channel, uint8_t average)
36
{
37
  uint32_t result;
38
 
39
  // Kanal waehlen, ohne andere Bits zu beeinflußen
40
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
41
  
42
 
43
  /* Eigentliche Messung - Mittelwert aus 'average' aufeinanderfolgenden Wandlungen */
44
  result = 0; 
45
 
46
  for (uint8_t i = average; i>0; i-- ) {
47
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
48
    while (1);    // auf Abschluss der Konvertierung warten
49
    result += ADC;                 // Wandlungsergebnisse aufaddieren
50
  }
51
 
52
  result /= average;               // arithmethischer Mittelwert
53
  return (uint16_t)result;
54
}
55
 
56
57
 
58
/* Beispielaufrufe: */
59
 
60
61
62
void main(void)
63
{
64
65
66
DDRD=0xff;         /* PortD als ausgang defnieren*/
67
68
  uint16_t adcval;
69
  ADC_Init();
70
  adcval = ADC_Read_Avg(1, 4);  // Kanal 1, Mittelwert aus 4 Messungen 
71
 
72
PORTD &= ~(1<<PD0); /* PD0 auf 0 setzen */
73
PORTD &= ~(1<<PD1); /* PD1 auf 0 setzen */
74
 
75
if (adcval < 314)           /* 314 entspricht 1.5V*/
76
  
77
  {
78
  PORTD |= (1<<PD1);      /* PD1 high wenn adcval größer 314 rot  */
79
  }
80
81
  
82
if (adcval > 314)     
83
  
84
  {
85
  PORTD |= (1<<PD0);      /* PD1 high wenn adcval kleiner 314 grün  */
86
  }
87
88
}


Hallo zusammen,
hat jemand ne idee warum mein adc immer nur 5V misst und nicht die 
Spannung die über den Widerstand R5 abfällt?
Die Schaltung an sich soll so funktionieren dass die Rote Led leuchtet 
wenn der ADC eine Spannung unter einem bestimmten Wert misst und Grün 
wenn sie über einem bestimmten Spannung liegt Rot leuchtet. Für den 
Anfang würd es mir aber mal reichen das der ADC überhaupt mal was misst 
;).

von Karl H. (kbuchegg)


Lesenswert?

1
for (uint8_t i = average; i>0; i-- ) {
2
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
3
    while (1);    // auf Abschluss der Konvertierung warten
4
    result += ADC;                 // Wandlungsergebnisse aufaddieren
5
  }

was macht die Endlosschleife da drinnen?


Du hast eine ADC_Read Funktion. Warum benutzt du sie nicht um damit auch 
die mittelnde Version aufzubauen, sondern programmierst dort wieder 
alles aus? Klassisches Beispiel dafür, wie man es nicht macht.

1
/* ADC Mehrfachmessung mit Mittelwertbbildung */
2
uint16_t ADC_Read_Avg(uint8_t channel, uint8_t average)
3
{
4
  uint32_t result = 0;
5
 
6
  for( uint8_t i = 0; i < average; ++i )
7
    result += ADC_Read( channel );
8
9
  return result / average;
10
}

von Hans Wurst (Gast)


Lesenswert?

1
for (uint8_t i = average; i>0; i-- ) {
2
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
3
    while (ADCSRA & (1<<ADSC) );    // auf Abschluss der Konvertierung warten
4
    result += ADC;                 // Wandlungsergebnisse aufaddieren
5
  }


Besser? Hab da was versucht und hab wohl vergessen das wieder zu ändern. 
Mein Fehler misst aber immer noch 5 V.


Karl heinz Buchegger schrieb:
> Du hast eine ADC_Read Funktion. Warum benutzt du sie nicht um damit auch
> die mittelnde Version aufzubauen, sondern programmierst dort wieder
> alles aus?



Weil es in meinem Beispielcode auch so gemacht wurde und ich nicht 
soviel  ändern wollte. Aber eigentlich müsste das doch kein Problem 
sein?

von Karl H. (kbuchegg)


Lesenswert?

Wie sieht deine Aussenbeschaltung aus?
Hast du am Optokoppler was angeschlossen?


Hast du mit einem Voltmeter kontrolliert, welche Spannung tatsächlich am 
ADC Eingang anliegt?


Beim schnellen Drüberschauen über den Code hab ich so jetzt erst mal 
nichts mehr gesehen. IMHO ist die Konfiguration des ADC vernünftig.

von Hans Wurst (Gast)


Lesenswert?

An ADC 1 liegen 1,5V sprich Opto ist beschalten der Transistor schaltet 
es leuchtet.

hmm hab ich den Eingangskanal richtig eingestellt mir kommts sovor uC 
ihrgendwas anderes misst.

Stimmt es das dass register beim Atmega 32 ADC heißt und nicht ADCW?

von Hans Wurst (Gast)


Lesenswert?

1
uint16_t ADC_Read(uint8_t channel)
2
{
3
  // Kanal waehlen, ohne andere Bits zu beeinflußen
4
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
5
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
6
  while (ADCSRA & (1<<ADSC) ); 
7
                                 // auf Abschluss der Konvertierung warten
8
  return ADC;                    // ADC auslesen und zurückgeben
9
  main=ADC;
10
}
change to

uint16_t ADC_Read(uint8_t channel)
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) );    // auf Abschluss der Konvertierung 
warten
  return ADC;                    // ADC auslesen und zurückgeben
}

Ich mess aber immer noch 5 V

von Karl H. (kbuchegg)


Lesenswert?

Hans Wurst schrieb:

> Stimmt es das dass register beim Atmega 32 ADC heißt und nicht ADCW?

Sollte genauso ADCW heissen.

von Karl H. (kbuchegg)


Lesenswert?

Ähm.
Ich vermisse in deiner main() die obligatorische while(1) Hauptschleife. 
Dein ADC misst einmal und das wars dann auch.

von Malte (Gast)


Lesenswert?

1
  ADMUX = (0<<REFS1) | (1<<REFS0) | (1<<MUX1);    // AVCC als Referenzspannung nutzen

Datenblatt Seite 214

Hast du nicht 2,56V Intern als Referenz?
1
  ADMUX = (1<<REFS0) | (1<<MUX1);    // AVCC als Referenzspannung nutzen

so sollte das doch aussehen wenn ich mich nicht irre?!

von Karl H. (kbuchegg)


Lesenswert?

1
void main(void)
2
{
3
  uint16_t adcval;
4
5
  DDRD = 0xff;         /* PortD als ausgang defnieren*/
6
  PORTD &= ~(1<<PD0);  /* PD0 auf 0 setzen */
7
  PORTD &= ~(1<<PD1);  /* PD1 auf 0 setzen */
8
9
  ADC_Init();
10
11
  while( 1 ) {
12
    adcval = ADC_Read_Avg(1, 4);  // Kanal 1, Mittelwert aus 4 Messungen 
13
  
14
    if (adcval < 314) {           /* 314 entspricht 1.5V*/
15
      PORTD &= ~(1<<PD0);
16
      PORTD |=  (1<<PD1);      /* PD1 high wenn adcval größer 314 rot  */
17
    }
18
 
19
    else if (adcval > 314) {
20
      PORTD |=  (1<<PD0);      /* PD1 high wenn adcval kleiner 314 grün  */
21
      PORTD &= ~(1<<PD1);
22
    }
23
  }
24
}

von Karl H. (kbuchegg)


Lesenswert?

Malte schrieb:
>
1
  ADMUX = (0<<REFS1) | (1<<REFS0) | (1<<MUX1);    // AVCC als
2
> Referenzspannung nutzen
3
>
>
> Datenblatt Seite 214
>
> Hast du nicht 2,56V Intern als Referenz?
>
>
1
  ADMUX = (1<<REFS0) | (1<<MUX1);    // AVCC als Referenzspannung
2
> nutzen
3
>
>
> so sollte das doch aussehen wenn ich mich nicht irre?!

Ist egal.
Kommt aufs selbe raus.  0<<REFS1  ist eine glatte 0 und stört somit 
nicht weiter beim verodern der Einzelterme.

Man kanns raus nehmen oder man kanns drinnen lassen um zu dokumentieren, 
dass man REFS1 absichtlich auf 0 haben will.

von pschober (Gast)


Lesenswert?

Wenn die Schaltung so gebaut ist wie auf dem Schaltplan, kann das gar 
nicht funktionieren.
Gnd (Pin31) hängt in der Luft

von Hans Wurst (Gast)


Lesenswert?

> Datenblatt Seite 214
>
> Hast du nicht 2,56V Intern als Referenz?


REFS1 REFS0 Voltage Reference Selection
0       0         AREF, Internal Vref turned off
0       1         AVCC with external capacitor at AREF pin
1       0         Reserved
1       1        Internal 2.56V Voltage Reference with external 
capacitor at AREF  pin

ADMUX = (0<<REFS1) | (1<<REFS0) | (1<<MUX1);
ähm Ich wäle doch AVCC aus. Das 0 REFS1 ist zur doku


Laut Datenblatt muss es ADC heißen ADCW taucht nicht einmal auf.

von Karl H. (kbuchegg)


Lesenswert?

Hans Wurst schrieb:
>> Datenblatt Seite 214
>>
>> Hast du nicht 2,56V Intern als Referenz?
>
>
> REFS1 REFS0 Voltage Reference Selection
> 0       0         AREF, Internal Vref turned off
> 0       1         AVCC with external capacitor at AREF pin
> 1       0         Reserved
> 1       1        Internal 2.56V Voltage Reference with external
> capacitor at AREF  pin
>
> ADMUX = (0<<REFS1) | (1<<REFS0) | (1<<MUX1);
> ähm Ich wäle doch AVCC aus. Das 0 REFS1 ist zur doku
>
>
> Laut Datenblatt muss es ADC heißen ADCW taucht nicht einmal auf.

In dem Fall gilt ausnahmsweise nicht das Datenblatt, sondern die 
Compilerdoku. Hauptsächlich deshalb, weil der gcc eine Erweiterung für 
alle Pseudo-16 Bit Register enthält, auf die mit dem Registernamen in 
einem Rutsch (anstelle von HighByte/LowByte) zugegriffen werden kann.

ADCW wurde gewählt, weil sonst Verwechslungsgefahr mit der 
Assembler-Anweisung ADC (Add with Carry) besteht. Es ist aber beides 
definiert: ADC und ADCW. Und beide bezeichnen im gcc auch dasselbe: das 
Pseudo-16 Bit Register mit dem Ergebnis der Wandlung.


Wie ist der momentane Zustand
* GND durchverbunden
* neues Hauptprogramm

von Hans Wurst (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ich vermisse in deiner main() die obligatorische while(1) Hauptschleife.
> Dein ADC misst einmal und das wars dann auch.

hmmm das stimmt aber wenn ich Schleife einfüge (der Vorschlag von dir) 
leuchtet gar nix mehr. Sehr komisch

pschober schrieb:
> Wenn die Schaltung so gebaut ist wie auf dem Schaltplan, kann das gar
> nicht funktionieren.
> Gnd (Pin31) hängt in der Luft

Ja die Masse hängt in der Luft das stimmt und ist beabsichtigt die 
Schaltung wird mit 180V betrieben. Das geht nicht und anderst und 
funktioniert, ich bekomm eine saubere 1.5 V Spannung. Sei auch mal dahin 
gestellt es geht um den ADC

von Vlad T. (vlad_tepesch)


Lesenswert?

ich versteh die Beschaltung des 2. GND anschlusses nicht (was nicht 
heißen muss, dass sie falsch ist)

edit: was ist denn T2 für ein Bauteil?

von Hans Wurst (Gast)


Lesenswert?

Ok das habe ich nicht gewusste danke für die Erklärung.

Aktueller Stand:
ADC in ADCW geändert
Hauptprogramm geändert.
An Pin 31 hab ich nichts geändert kann ich den einfach an GND des uC 
anschließen?

Misst 5V

von Hans Wurst (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> ich versteh die Beschaltung des 2. GND anschlusses nicht (was nicht
> heißen muss, dass sie falsch ist)
>
> edit: was ist denn T2 für ein Bautei

Light Duty Radial Leaded Arrestor

oder einfach gesagt ein Überspannungschutz/ableiter

http://www.alldatasheet.com/datasheet-pdf/pdf/274136/LUMEX/GT-RLSA140SS.html

von Hans Wurst (Gast)


Lesenswert?

Mein Fehler die Schleife funktioniert.

von Karl H. (kbuchegg)


Lesenswert?

Da die beiden GND Anschlüsse Chipintern höchst wahrscheinlich irgendwo 
zusammengeführt sind, wird sich die fehlende Verbindung erst mal nicht 
grossartig auswirken. Nichtsdestotrotz muss sie gemacht werden.


Ich hatte in meinem Hauptprogramm weiter oben noch einen Fehler. Hast du 
den gesehen (Ich hatte die ~ bei den Verundungen vergessen)?

Denn das hier:
> aber wenn ich Schleife einfüge (der Vorschlag von dir)
> leuchtet gar nix mehr.
kann dann nur mehr sein, wenn der ADC von anfang an und ständig 317 
liefert. Ich hab diese Möglichkeit nicht ausgebaut, weil ich dachte dass 
eine kleine Hysterese nicht schaden kann. Aber seis drum
1
 while( 1 ) {
2
    adcval = ADC_Read_Avg(1, 4);  // Kanal 1, Mittelwert aus 4 Messungen 
3
  
4
    if (adcval < 314) {           /* 314 entspricht 1.5V*/
5
      PORTD &= ~(1<<PD0);
6
      PORTD |=  (1<<PD1);      /* PD1 high wenn adcval größer 314 rot  */
7
    }
8
 
9
    else {
10
      PORTD |=  (1<<PD0);      /* PD1 high wenn adcval kleiner 314 grün  */
11
      PORTD &= ~(1<<PD1);
12
    }
13
  }

eine der beiden LED MUSS leuchten!

Ich würde mir zum testen ehrlich gesagt auch die Auswerteschaltung 
abklemmen und durch ein stink normales Poti als Spannungsteiler 
ersetzen. Dann kann ich am Poti drehen und einfach sehen ob die 
Umschaltung klappt. Ausserdem bin ich dann nicht darauf angewiesen, dass 
diese Eingangsbeschaltung auch tatsächlich funktioniert.

von Hans Wurst (Gast)


Lesenswert?

hmm ich glaup ich hab die Ursache gefunden egal was ich anschließ es wir 
mir aus 5 V hochgezoegn. Vorher hab ich das nicht gemessen weil der uC 
aus war und die Maße nicht verbunden. wenn ich an den ADC1 und GND 1 V 
anschließ zieht es die auf 5V hoch warum hab ich noch nicht gefunden.

von Hand Wurst (Gast)


Lesenswert?

Hmm ich hab die Schaltung jetzt über nen Spannungsteiler Widerstand+ 
Poti gemacht. Aber der ADC misst immer noch ihrgend nen mist. An PIn 1 
liegt 1,5 V.
Au man . Jemand nen Vorschlag?

von ic (Gast)


Lesenswert?

Irgendwelche Pullups etc. noch aktiviert auf dem Eingang? Eingang 
explizit als Eingang Definieren und alles was interne Pullups/downs 
betrifft nochmal festnageln.

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.