Forum: Mikrocontroller und Digitale Elektronik Ermittlung maximal Spanung mit atmega


von smith (Gast)


Lesenswert?

habe einen ATmega16 und würde gerne 4 Spannungen miteinander
vergleichen.und aus die vier spannungen die maximale spannung ermitteln 
und damit Led ansteuern.
das problem :microcontroller speichert die maximal wert.und berechnet 
nicht neu die maximal wert aus die vier spannungen,sonst bleibt die 
maximal spannung gespeichert bis eine spannung höher als die 
gespeicherte spanung.
1
while(1){    // Endlosschleife zur kontinuierlichen 
2
        //Auswertung der Eingangsspannung (am ADC)
3
4
5
6
        }
7
c=maximum();
8
if((c>=0x00)&&(c<=0x9E)){    
9
PORTD=0x01;                          
10
}
11
12
else if((c>0x9E)&&(c<=0x176)){
13
PORTD=0x02;
14
15
}
16
17
else if((c>0x176)&&(c<=0x3FF)){
18
PORTD=0x04              ;
19
20
}
21
}
22
23
24
unsigned short adc(unsigned char admux) 
25
{ 
26
unsigned short val;
27
unsigned char i;
28
    ADCSRA  =  (1<<ADEN)  | (1<<ADPS1) | (1<<ADPS0); 
29
  //ADC aktivieren und Teilungsfaktor stellen
30
31
    ADMUX   =  admux; //Kanal des Multiplexers wählen
32
33
    ADMUX  &= ~ (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
34
35
    // Den ADC initialisieren und einen sog. Dummyreadout machen
36
  ADCSRA |= (1<<ADSC);
37
38
    while      (ADCSRA    & (1<<ADSC));
39
   
40
  for(i=0; i<3; i++) {
41
  ADCSRA |=  (1<<ADSC);  // eine ADC-Wandlung
42
   while      (ADCSRA    & (1<<ADSC)); // auf Abschluss der Konvertierung warten
43
     val     += ADCW; 
44
45
    }
46
  ADCSRA &= ~(1<<ADEN); //// ADC wieder deaktivieren
47
  val/=3;
48
49
    return val; // ADC auslesen und zurückgeben
50
}
51
52
53
unsigned short maximum(void)
54
{
55
unsigned char i;
56
unsigned short max=adc(0);
57
for(i=1;i<4;i++){
58
  if(adc(i)>max)
59
  max=adc(i);
60
    }
61
  return max;
62
}

von Micha H. (mlh) Benutzerseite


Lesenswert?

Aus Deinem konfusen Satzbau rate ich, Du möchtest den Max-Wert bei jedem 
Durchlauf neu berechnen? Dann setze ein

max = 0;

hinter den Funktionsaufruf in der main().

von Karl H. (kbuchegg)


Lesenswert?

formatier erst mal deinen Code vernünftig.
Einrückungen konsistent machen!

Ansonsten suchen wir hier Fehler, die in deinem Code überhaupt nicht 
existieren.

Oder ist das Absicht, dass deine Hauptschleife leer ist? Da wundert es 
mich nicht, dass dein Programm keine Arbeit mehr verrichtet.
1
while(1){    // Endlosschleife zur kontinuierlichen 
2
        //Auswertung der Eingangsspannung (am ADC)
3
4
5
6
        }

PS: Das ist mit Abstand die scheuslichste und unübersichtlichste 
Code-Formatierung die ich je gesehen habe. Und ich habe schon viel 
gesehen. Das du keine Fehler findest wundert mich nicht.

von smith (Gast)


Lesenswert?

die max hab ich schon mit 0 initialisiert
unsigned short c,max=0x00;

danke für die Antwort

von Karl H. (kbuchegg)


Lesenswert?

Ist jetzt zwar nicht dein Problem.
Aber: Das geht so nicht
1
unsigned short maximum(void)
2
{
3
  unsigned char i;
4
  unsigned short max = adc( 0 );
5
6
  for( i = 1; i < 4; i++ )
7
  {
8
    if( adc( i ) > max )
9
      max = adc( i );
10
  }
11
12
  return max;
13
}

Du kannst nicht adc(i) mit max vergleichen und dann zur Zuweisung an max 
erneut adc aufrufen. Der zweite Aufruf könnte ein ganz anderes Ergebnis 
bringen als der erste!
1
unsigned short maximum(void)
2
{
3
  unsigned char i;
4
  unsigned short adcValue;
5
  unsigned short max = adc( 0 );
6
7
  for( i = 1; i < 4; i++ )
8
  {
9
    adcValue = adc( i );
10
    if( adcValue > max )
11
      max = adcValue;
12
  }
13
14
  return max;
15
}

von smith (Gast)


Lesenswert?

Danke Karl heinz.jetzt ermittlet die maximal spannung daraus.nun hab 
noch ein problem dass LED an den PORTD 0x04 immer an auch wenn ich keine 
spannung anlege

von Karl H. (kbuchegg)


Lesenswert?

smith schrieb:
> Danke Karl heinz.jetzt ermittlet die maximal spannung daraus.nun hab
> noch ein problem dass LED an den PORTD 0x04 immer an auch wenn ich keine
> spannung anlege

Hast du dein Programm bereinigt?
Zeig noch mal den bereinigten Code.

Wie gesagt: Dein ursprünglich geposteter Code konnte nicht 
funktionieren, weil sich innerhalb der Arbeitsschleife keine Anweisungen 
befinden.

Das kann jetzt natürlich ein Postingfehler sein. Nur das kann ich nicht 
raten, das will ich sehen.

PS:
Hat es eigentlich einen speziellen Grund, warum du bei den Vergleichen 
Hexadezimalzahlen benutzt?

von smith (Gast)


Lesenswert?

Ich hoffe dass es genung gereinigt:-)

#include <avr/io.h>
#include <stdint.h>



unsigned short adc(unsigned char admux) ;
unsigned short maximum(void);
void init_ports();



void main(){
unsigned short c,max;
unsigned char i;    // Variablen definitionn
init_ports();

while(1){    // Endlosschleife







c=maximum();

if((c>=0x00)&&(c<=0x9E)){

PORTD=0x01;
}

else if((c>0x9E)&&(c<=0x176)){

PORTD=0x02;
}

else if((c>0x176)&&(c<=0x3FF)){

PORTD=0x04;
}

else if((c>0x3FF)||(c<0x00)){
PORTD=0x10;
}
}
}

void init_ports()
{
DDRD=0xFF; //PORTD als Ausgang
PORTD =0x00;
}

unsigned short adc(unsigned char admux)
{
  unsigned short val;
  unsigned char i;
    ADCSRA  =  (1<<ADEN)  | (1<<ADPS1) | (1<<ADPS0);
  //ADC aktivieren und Teilungsfaktor stellen

    ADMUX   =  admux; //Kanal des Multiplexers wählen

    ADMUX  &= ~ (1<<REFS1) | (1<<REFS0); // interne Referenzspannung 
nutzen

    // Den ADC initialisieren und einen sog. Dummyreadout machen
  ADCSRA |= (1<<ADSC);

    while      (ADCSRA    & (1<<ADSC));

  for(i=0; i<3; i++) {
  ADCSRA |=  (1<<ADSC);  // eine ADC-Wandlung
   while      (ADCSRA    & (1<<ADSC)); // auf Abschluss der 
Konvertierung warten
     val     += ADCW;

    }
  ADCSRA &= ~(1<<ADEN); //// ADC wieder deaktivieren
  val/=3;

    return val; // ADC auslesen und zurückgeben
}

unsigned short maximum(void)
{
  unsigned char i;
  unsigned short adcValue;
  unsigned short max = adc( 0 );

  for( i = 1; i < 4; i++ )
  {
    adcValue = adc( i );
    if( adcValue  > max )
      max = adcValue;
  }

  return max;
}

von smith (Gast)


Lesenswert?

ne kein speziellen grund.

von kleinscreiber (Gast)


Lesenswert?

smith schrieb:
> nun hab
> noch ein problem dass LED an den PORTD 0x04 immer an auch wenn ich keine
> spannung anlege

Dein Problem ist, dass niemand dein konfusen Sätze versteht. Gib dir 
wenigstens ein bisschen Mühe beim Formulieren und benutze die 
Schift-Tase wo es nötig ist!

von Karl H. (kbuchegg)


Lesenswert?

So sollte dein Code aussehen!

Eine halbwegs schöne und ansprechende und vor allen Dingen konsistente 
Formatierung ist ein Instrument mit dem man Fehler sehen kann!
1
#define LED1  PD0
2
#define LED2  PD1
3
#define LED3  PD2
4
5
6
int main()
7
{
8
  ...
9
10
11
  while( 1 )    // Endlosschleife zur kontinuierlichen 
12
                //Auswertung der Eingangsspannung (am ADC)
13
14
  {
15
    c = maximum();
16
17
    if( c <= 158 )
18
      PORTD = ( 1 << LED1 );
19
20
    else if( c <= 374)
21
      PORTD = ( 1 << LED2 );
22
23
    else
24
      PORTD = ( 1 << LED3 );
25
  }
26
}

Lektionen:
* Achte darauf, dass die schliessende } immer in derselben Spalte steht, 
wie die öffnende {

* Mach Leerzeichen rein!
  Wenn du Text liest, bist du daran gewöhnt, dass zwischen den Wörtern 
ein Leerraum ist. Der Leerraum hilft dir beim Lesen! Nur weil C 
grundsätzlich erlaubt, alles in einer Wurst zu schreiben, muss man das 
nicht tun!

* In deiner Prüfkette: Prüfe nicht Dinge, die sowieso nicht sein können. 
Ein unsigned short Datentyp ist immer größer als 0. Das muss man nicht 
prüfen. Wenn ein Wert schon kleiner als 159 ist, dann kann er im 
nächsten else if, welches geprüft wird nicht größer sein. Das muss man 
daher auch nicht prüfen.

* Sieh zu, dass du auch mit Fehlern arbeiten kannst. Eine if - else if 
Kette sollte immer ein abschliessendes else haben, in welchem 'alles 
andere' sinnvoll behandlet wird. Genauso wie ein switch immer ein 
default haben soll.

* verstecke die Hardwarebelegung der Pins nicht im Code! Benutze #define 
um die Hardware im Code zu abstrahieren.

* Nimm das Zahlensystem, welches intuitiv zur Aufgabenstellung passt. 
Wenn du konzeptionell mit Dezimalzahlen hantierst, dann benutze auch 
Dezimalzahlen und verschleire Werte nicht hinter Hexadezimalzahlen wenn 
es keinen Grund dafür gibt.

von Hc Z. (mizch)


Lesenswert?

Ist es Absicht, dass die LEDs zwar an-, aber nirgendwo ausgeschaltet 
werden?  Könnte immerhin sein, da es eine Maximalwertanzeige ist, auch 
wenn ich es nicht vermute.

von Justus S. (jussa)


Lesenswert?

Hc Zimmerer schrieb:
> Ist es Absicht, dass die LEDs zwar an-, aber nirgendwo ausgeschaltet
> werden?  Könnte immerhin sein, da es eine Maximalwertanzeige ist, auch
> wenn ich es nicht vermute.

es wird ja immer nur umgeschaltet...

von Hc Z. (mizch)


Lesenswert?

Sind eigentlich die Editoren, die die Einrückungen selbst 
vorschlagen/machen, völlig aus der Mode gekommen?  Das ist auch schon 
während des Schreibens eine gute Hilfe bei der Fehlererkennung.

Da lob' ich mir doch meinen guten alten Emacs.

von Hc Z. (mizch)


Lesenswert?

Justus Skorps schrieb:
> es wird ja immer nur umgeschaltet...

Ja, richtig.  Das habe ich übersehen.

von smith (Gast)


Lesenswert?

Danke für die Lektionen.
also das hat sich nicht geändert LED3 ist immer an

von Karl H. (kbuchegg)


Lesenswert?

Es ist auch immer eine gute Idee, sich auf nichts zu verlassen.
Ehe man da eine Auswertung macht, ist es meistens eine gute Idee, sich 
die Messwerte direkt anzusehen.

Eventuell liegt ja auch ein Hardwareproblem vor und vom ADC kommt 
tatsächlich ständig ein Messwert von 1024

von Karl H. (kbuchegg)


Lesenswert?

smith schrieb:
> Danke für die Lektionen.
> also das hat sich nicht geändert LED3 ist immer an

Dann sieh dir erst mal an, was dein ADC tatsächlich für Werte von sich 
gibt.

Nur 1 Kanal auswerten. Den Messwert durch 4 dividieren (damit er von 
1024 nach 256 runter kommt) und direkt auf den Port ausgeben. Dann kann 
man mal nachsehen, welcher Messwert gemessen wird und ob sich der 
überhaupt ändert, wenn sich die zu messende Spannung ändert.

Dasselbe Spielchen dann mit den anderen Kanälen.

von smith (Gast)


Lesenswert?

wenn ich die spannung lese ohne die maximum funkton zu verwenden läuft 
ganz gut.Fehler tritt ein erst wenn ich die Funktion Maximum benutze!!!

von Karl H. (kbuchegg)


Lesenswert?

Das hier

    ADMUX  &= ~ (1<<REFS1) | (1<<REFS0);

macht mit einiger Sicherheit nicht das, was du erwartest, was immer das
auch sein mag.

Entweder du wolltest das hier:

    ADMUX  &= ~ ( (1<<REFS1) | (1<<REFS0) );

   Das schaltet auf externe Referenzspannung.
   Hast du überhaupt an AREF eine Referenzspannung angeschlossen?

Oder du wolltest das hier

    ADMUX  &= ~ (1<<REFS1);
    ADMUX  |=   (1<<REFS0);

  Das schaltet die Referenzspannung auf AVcc

Also: Welche der beiden Versionen soll es sein?

von smith (Gast)


Lesenswert?

ich will halt  interne Referenzspannung nutzen und die AREF und AVCC 
sind beide angeschlossen

von smith (Gast)


Lesenswert?

bin verwirtt.hab AVCC und AREF an den externe 5v angeschlossen

von Karl H. (kbuchegg)


Lesenswert?

smith schrieb:
> ich will halt  interne Referenzspannung nutzen

Welche interne Referenzspannung?

Es gibt 2 davon
   AVcc
   eine generierte Referenzspannung von 2.56 Volt

> und die AREF und AVCC
> sind beide angeschlossen

Wie?

Hör mal:
  Du gibst dir keine Mühe beim Schreiben deiner Beiträge

  Genauso hingeschludert sehen auch deine Programm aus

  Man muss dir jede Kleinigkeit aus der Nase ziehen

  Von alleine kommt von dir keine Info, von der du denken könntest
  das man die als Helfer eventuell brauchen könnte



Entweder du stellst dein Verhalten um, oder ich bin ganz schnell aus dem 
Thread raus.

von Karl H. (kbuchegg)


Lesenswert?

smith schrieb:
> bin verwirtt.hab AVCC und AREF an den externe 5v angeschlossen

Ganz schlecht.

An Avcc kann man per Software als Referenzspannung auswählen.
Von daher gibt es keinen Grund an AREF eine SPannung anzuschliessen.

An AREF gehört im Normalfall einfach nur ein 100nF Kondensator, der ARF 
nach GND abblockt.

Steht aber alles auch im Tutorial.

von smith (Gast)


Lesenswert?

bin halt Anfänger in diesem Bereich und bei jeder Frage muss ich 
überlegen und ich bedanke mich für jede Antwort bei dir bzw bei alle 
anderen.das hat nix mit Verhalten zu tun

ich hab Aref und AVcc mit 5V angeschlossen.
ich verstehe nicht wraum alles läuft ganz gut nur wenn ich die maximal 
funktion benutze dann wird nur LED dauernd angeschaltet

von smith (Gast)


Lesenswert?

LED3

von smith (Gast)


Angehängte Dateien:

Lesenswert?

Hierbei mein Grundschaltung

von Karl H. (kbuchegg)


Lesenswert?

smith schrieb:
> Hierbei mein Grundschaltung

Dann muss es so lauten
1
#define NR_SAMPLES 3    // Anzahl der Messungen, die gemittelt werden
2
unsigned short adc(unsigned char admux)
3
{
4
  unsigned short val = 0;
5
  unsigned char i;
6
7
  ADCSRA  =  (1<<ADEN)  | (1<<ADPS1) | (1<<ADPS0);
8
  //ADC aktivieren und Teilungsfaktor stellen
9
10
  ADMUX = admux; //Kanal des Multiplexers wählen
11
12
  ADMUX  &= ~ ( (1<<REFS1) | (1<<REFS0) ); // externr Referenzspannung AREF nutzen
13
14
  // Den ADC initialisieren und einen sog. Dummyreadout machen
15
  ADCSRA |= (1<<ADSC);
16
  while( ADCSRA & (1<<ADSC) )
17
    ;
18
19
  for( i = 0; i < NR_SAMPLES; i++ )
20
  {
21
    ADCSRA |= (1<<ADSC);         // eine ADC-Wandlung
22
    while( ADCSRA & (1<<ADSC) )
23
      ;                          // auf Abschluss der Konvertierung warten
24
    val += ADCW;
25
  }
26
27
  ADCSRA &= ~(1<<ADEN); //// ADC wieder deaktivieren
28
29
  val /= NR_SAMPLES;
30
  return val; // ADC auslesen und zurückgeben
31
}

Änderungen:
  Referenzspannung mit Sicherheit auf AREF eingestellt

  val mit 0 initialisiert. Du kannst nicht davon ausgehen, dass eine
  lokale Variable irgendeinen vernünftigen Wert hat, wenn die Funktion
  betreten wird.


Insbesondere der letzter Punkt könnte für dein Problem verantwortlich 
sein.

von smith (Gast)


Lesenswert?

->An AREF gehört im Normalfall einfach nur ein 100nF Kondensator, der 
ARF
nach GND abblockt.

wenn ich das mache dann funktioniert nix mehr auch wenn ich direkt von 
adc() lese.
sonst wenn ich das mache wie in Grundschaltung oben tritt wieder gleiche 
Problem wenn ich maximum Funktion einsetze

von Karl H. (kbuchegg)


Lesenswert?

smith schrieb:
> ->An AREF gehört im Normalfall einfach nur ein 100nF Kondensator, der
> ARF
> nach GND abblockt.
>
> wenn ich das mache dann funktioniert nix mehr auch wenn ich direkt von
> adc() lese.

Klar.
Dann muss die Referenzspannungseinstellung in ADMUX eine andere sein.

Lies dir mal das hier durch
http://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Der_interne_ADC_im_AVR

von Karl H. (kbuchegg)


Lesenswert?

smith schrieb:

> sonst wenn ich das mache wie in Grundschaltung oben tritt wieder gleiche
> Problem wenn ich maximum Funktion einsetze


AREF hast du jetzt wie bschaltet?
Wie sieht jetzt dein Programm aus?

von smith (Gast)


Angehängte Dateien:

Lesenswert?

also ich hab es probiert wie du es geschrieben hast

#include <avr/io.h>
#include <stdint.h>
#define NR_SAMPLES 3    // Anzahl der Messungen, die gemittelt werden


#define LED1  PD0
#define LED2  PD1
#define LED3  PD2

unsigned short adc(unsigned char admux) ;
unsigned short maximum(void);
void init_ports();


int main()
{
  unsigned short c;    // Variablen definitionn
  init_ports();


  while( 1 )    // Endlosschleife zur kontinuierlichen
                //Auswertung der Eingangsspannung (am ADC)

  {
    c = maximum();

        if( c <= 158 )
      PORTD = ( 1 << LED1 );

    else if( c <= 374)
      PORTD = ( 1 << LED2 );

    else
      PORTD = ( 1 << LED3 );





  }
}

void init_ports()
{
DDRD=0xFF; //PORTD als Ausgang
PORTD =0x00;
}


unsigned short adc(unsigned char admux)
{
  unsigned short val = 0;
  unsigned char i;

  ADCSRA  =  (1<<ADEN)  | (1<<ADPS1) | (1<<ADPS0);
  //ADC aktivieren und Teilungsfaktor stellen

  ADMUX = admux; //Kanal des Multiplexers wählen

  ADMUX  &= ~ ( (1<<REFS1) | (1<<REFS0) ); // externr Referenzspannung 
AREF nutzen

  // Den ADC initialisieren und einen sog. Dummyreadout machen
  ADCSRA |= (1<<ADSC);
  while( ADCSRA & (1<<ADSC) )
    ;

  for( i = 0; i < NR_SAMPLES; i++ )
  {
    ADCSRA |= (1<<ADSC);         // eine ADC-Wandlung
    while( ADCSRA & (1<<ADSC) )
      ;                          // auf Abschluss der Konvertierung 
warten
    val += ADCW;
  }

  ADCSRA &= ~(1<<ADEN); //// ADC wieder deaktivieren

  val /= NR_SAMPLES;
  return val; // ADC auslesen und zurückgeben
}


unsigned short maximum(void)
{
  unsigned char i;
  unsigned short adcValue;
  unsigned short max = adc( 0 );

  for( i = 1; i < 4; i++ )
  {
    adcValue = adc( i );
    if( adcValue  > max )
      max = adcValue;
  }

  return max;
}



LED3 ist immer an auch wenn ich die spannung ändere 0 bis 5V.

von Karl H. (kbuchegg)


Lesenswert?

smith schrieb:

> LED3 ist immer an auch wenn ich die spannung ändere 0 bis 5V.

"die Spannung"?

Leider hast du nicht eingezeichnet, was eigentlich an den ADC Eingängen 
hängt.

Überprüf mal die Einzelkanäle. Einer davon wird höchst wahrscheinlich 
einen hohen Wert liefern.
1
unsigned short maximum(void)
2
{
3
  unsigned char i;
4
  unsigned short adcValue;
5
  unsigned short max = 0;
6
7
  for( i = 0; i < 4; i++ )
8
  {
9
    adcValue = adc( i );
10
11
    if( i == 0 )
12
    {
13
      if( adcValue  > max )
14
        max = adcValue;
15
    }
16
  }
17
18
  return max;
19
}

Beim if tauscht du den Vergleich nacheinander gegen 0, 1, 2, 3 aus.
Dadurch kann dann immer nur 1 Kanal zum Maximum beitragen. Die ganze 
restliche Programmlogik, inklusive ADC-Kanalwechsel, ändert sich aber 
nicht. Und das ist wichtig! Zum Testen wollen wir alles andere möglichst 
gleich lassen.

So kannst du jeden Kanal überprüfen, ob er der Übeltäter ist, dessen 
Messwert alle anderen überstimmt.

von smith (Gast)


Lesenswert?

ich Lege an die adc(0) eine spannung von 1v und an adc(1) 5 v
normalweise soll LED3 anleuchten das tut sie nicht sondern wird immer 
LED2 an
an adc(2) und adc(3) lass ich halt 0v dran.

ich hab alle kanäle von adc0 bis adc3 überprüft durch änderung von i und 
alle funktionieren ganz gut.

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.