Forum: Mikrocontroller und Digitale Elektronik Spannungen vergleichen


von Hans P. (gableguy2000)


Lesenswert?

Hallo,

ich habe ien C Programm geschrieben, welches 2 Spannungen mittel sdes 
internen Komperator vergleicht.
Kompilieren klappt, aber könntet Ihr trotzdem mal drüberschauen?
Habe es mit der Hilfe von dem Tutorila erstellt.
1
#include <avr/io.h>
2
#include <stdint.h>
3
4
int main (void)
5
{
6
ACSR &= ~(1<<ACD) | (1<<ACBG);  //ACE einschalten und externe Ref Spannung
7
DDRB |= (1<<DDB0);       //DDRB als Ausgang
8
9
10
while (1)
11
  {
12
  if (ACSR & (1<<ACO)==1)    //wenn IST < SOLL
13
    PORTB |= (1<<PB0);    //PORT B auf einschalten
14
  }
15
 
16
17
18
}

Danke

von Peter (Gast)


Lesenswert?

und wann soll Port B wieder ausgehen?

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

gute Frage :-).
Wenn ACO also IST > SOLL.
Würde es gerne so machen, das wenn ACO = 1 (IST < SOLL) dann PB0 
einschalten (grüne LED brennt), und wenn ACO = 0, dann PB1 einschalten 
(rote LED).

Habe das mal programmiert:
1
#include <avr/io.h>
2
#include <stdint.h>
3
4
int main (void)
5
{
6
ACSR &= ~(1<<ACD) | (1<<ACBG);  //ACE einschalten und externe Ref Spannung
7
DDRB |= (1<<DDB0) | (1<<DDB1);       //DDRB als Ausgang
8
9
10
while (1)
11
  {
12
  if (ACSR & (1<<ACO)==1)    //wenn IST < SOLL
13
    PORTB |= (1<<PB0);    //PORT B0 auf einschalten
14
    PORTB &=~(1<<PB1);    //und B1 auf 0
15
  else                   //wenn IST > SOLL
16
    PORTB |= (1<<PB1);  //B1 einschalten
17
    PORTB &=~(1<<PB0);  //B0 ausschalten( auf 0)
18
  
19
  
20
  
21
  }
22
 
23
24
25
}

LG

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:

>
1
>   if (ACSR & (1<<ACO)==1)    //wenn IST < SOLL
2
>

Da gibt es 2 Fallen:
  Operatorenreihenfolge
  Der linke Teilausdruck muss nicht notwendigerweise 1 ergeben
  (nach der Syntaxkorrektur)

Der C-Compiler sieht diesen Ausdruck als
1
    ACSR & ( (1 << AC0) == 1 )
und das ist nicht ganz das was du haben willst. Du willst
1
    ( ACSR & (1 << AC0) ) == 1



Generell: Lass diese Vergleiche mit == 1 oder != 1 überhaupt weg. Die 
funktionieren nämlich meistens sowieso nicht, es sei denn AC0 ist 
zufällig genau 1
1
   if( ACSR & (1<<AC0) )
macht das Gewünschst und du laufst nicht Gefahr, dass dir da die 
Operatorenreihenfolge reinpfuscht. Die Umkehrung allerdings erfordert 
eine Klammer mehr
1
   if( !(ACSR & (1<<AC0) ) )
allenfalls, wenn du explizit sein möchtest, kannst du noch schreiben
1
    if( ( ACSR & (1<<AC0) ) == 0 )    // Bit nicht gesetzt
1
    if( ( ACSR & (1<<AC0) ) != 0 )    // Bit gesetzt
aber hüte dich davor, anzunehmen dass bei gesetztem Bit der ganze linke 
Ausdruck dann zu 1 wird! Das wird er nämlich nicht.

Nicht umsonst ist die C Definition für logisch wahr: alles was nicht 0 
ist. Daher: derartige Auswertungen immer so formulieren, dass auf 0 
Bezug genommen wird.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Hans Peter schrieb:
>
1
>   if (ACSR & (1<<ACO)==1)    //wenn IST < SOLL
2
>     PORTB |= (1<<PB0);    //PORT B0 auf einschalten
3
>     PORTB &=~(1<<PB1);    //und B1 auf 0
4
>   else                   //wenn IST > SOLL
5
>     PORTB |= (1<<PB1);  //B1 einschalten
6
>     PORTB &=~(1<<PB0);  //B0 ausschalten( auf 0)

Einrückungen zu machen reicht nicht aus, um dem Compiler zu sagen, dass 
die ersten 2 Zeilen zum "if" gehören und die anderen zum "else".

Richtig wäre Klammerung mit "{" und "}'":
1
  if (ACSR & (1<<ACO)==1)    //wenn IST < SOLL
2
  {
3
    PORTB |= (1<<PB0);    //PORT B0 auf einschalten
4
    PORTB &=~(1<<PB1);    //und B1 auf 0
5
  }
6
  else                   //wenn IST > SOLL
7
  {
8
    PORTB |= (1<<PB1);  //B1 einschalten
9
    PORTB &=~(1<<PB0);  //B0 ausschalten( auf 0)
10
  }

> Habe das mal programmiert:

Was verstehst Du unter "programmieren"? Zumindest ein compilieren sollte 
schon dazugehören, um festzustellen, ob wenigstens syntaktisch alles in 
Ordnung ist. Deine Version kann eigentlich kein Compiler schlucken, weil 
dieser das "if" zum "else" ohne Klammern gar nicht finden kann...

Gruß,

Frank

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

habe in einem C-Buch nachgeschaut.
Wenn ich nach dem if nur einen Befehl habe, dann brauche ich keine 
Klammern, da ich aber zwei Zeilen habe, brauche ich bei if und auch bei 
else klammern, oder nicht?
Wenn ich es bei AVR Studio durchlaufen lasse, dann bekomme ich weder 
Fehler noch Warnungen, dann müsste es doch laut Compiler syntaktisch 
richtig sein, oder?
Aber es geht ja auch um die Funktion. Würde es so wie ich es geschrieben 
haben funktionieren, oder habe ich wasa grundlegendes falsch gemacht 
oder vergessen?

LG

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:
> Hallo,
>
> habe in einem C-Buch nachgeschaut.
> Wenn ich nach dem if nur einen Befehl habe, dann brauche ich keine
> Klammern, da ich aber zwei Zeilen habe, brauche ich bei if und auch bei
> else klammern, oder nicht?


Ja
Und zwar deshalb, weil das hier

   {
      Anweisung
      Anweisung
      Anweisung
      ...
   }

(also eine Abfolge von Anweisungen eingeshlossen in { }, ein sog. Block) 
selbst wieder als eine Anweisung gilt.

Die Syntax vom if ist ganz einfach

   if( Ausdruck )
     Anweisung

Es kann also nur eine einzige Anweisung innerhalb des auszuführenden 
Teils geben. Aber man kann ja einen Block benutzen um eine Abfolge von 
Anweisungen als nur eine einzige Anweisung zu verkaufen.

> Wenn ich es bei AVR Studio durchlaufen lasse, dann bekomme ich weder
> Fehler noch Warnungen, dann müsste es doch laut Compiler syntaktisch
> richtig sein, oder?

Im letzten Fall nicht. Und zwar deshalb, weil die vollständige if-Syntax 
lautet

   if( Ausdruck )
     Anweisung
   else
     Anweisung

(wobei der else Teil auch entfallen kann)

Bei dem was du geschrieben hast, hängt das else aber in der Luft.
Das wird der Compiler monieren.

> Aber es geht ja auch um die Funktion. Würde es so wie ich es geschrieben
> haben funktionieren, oder habe ich wasa grundlegendes falsch gemacht
> oder vergessen?

Siehe weiter oben

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

verstehe ich nicht so ganz.
Durch meine Klammern, bei if und bei else, sage ich Ihm, dass es ein 
Block von Anweisungen ist, die werden doch dann beide abgearbeitet, 
oder?
Warum hängt else in der Luft?
Wenn die if Bedingung nicht zutrifft, dann wechselt er doch in den else 
Teil.
also wenn die Spannungen so sind, dann mache das ansonsten mach das.

Oder soll ich zwei If - Schleifen untereinander machen?


LG

von Sven aus D. (Gast)


Lesenswert?

ein beispiel:

if(D)
 B=1;
 C=1;

wenn du das so machst meckert kein compiler. nur mach der daraus das 
hier:

if(D)
{
 B=1;
}

C=1;

das heißt das C=1 nicht mehr in der if ist und immer(!) nach der if 
abfrage ausgeführt wird.
der nimmt nur die erste zeile, die weiteren sind dann eigene befehle...
also bei einem oder mehr immer klammern setzen!

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:
> Hallo,
>
> verstehe ich nicht so ganz.
> Durch meine Klammern, bei if und bei else, sage ich Ihm, dass es ein
> Block von Anweisungen ist, die werden doch dann beide abgearbeitet,
> oder?

Du hast aber keine Klammern gemacht.

Zitat
1
   if (ACSR & (1<<ACO)==1)    //wenn IST < SOLL
2
     PORTB |= (1<<PB0);    //PORT B0 auf einschalten
3
     PORTB &=~(1<<PB1);    //und B1 auf 0
4
   else                   //wenn IST > SOLL
5
     PORTB |= (1<<PB1);  //B1 einschalten
6
     PORTB &=~(1<<PB0);  //B0 ausschalten( auf 0)

Für den COmpiler ist das
1
   if (ACSR & (1<<ACO)==1)    //wenn IST < SOLL
2
     PORTB |= (1<<PB0);    //PORT B0 auf einschalten
3
4
   PORTB &=~(1<<PB1);    //und B1 auf 0
5
6
   else                   //wenn IST > SOLL
7
     PORTB |= (1<<PB1);  //B1 einschalten
8
9
   PORTB &=~(1<<PB0);  //B0 ausschalten( auf 0)

Das ist ist daher mit dem
     PORTB |= (1<<PB0);    //PORT B0 auf einschalten
zu Ende. Das
   PORTB &=~(1<<PB1);    //und B1 auf 0
gehört schon nicht mehr dazu.

Aber: Zu welchem if gehört denn jetzt das else. Da ist kein if mehr zu 
dem es gehören könnte. Denn das if war ja schon nach dem
     PORTB |= (1<<PB0);    //PORT B0 auf einschalten
zu Ende.

von Hans P. (gableguy2000)


Lesenswert?

Das ist mir klar, aber ich habe doch Klammern gesetzt, sowohl bei if und 
auch bei else, oder?

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:
> Das ist mir klar, aber ich habe doch Klammern gesetzt, sowohl bei if und
> auch bei else, oder?

Wo?

Schau dir doch noch einmal deinen Code an!
1
while (1)
2
  {
3
  if (ACSR & (1<<ACO)==1)    //wenn IST < SOLL
4
    PORTB |= (1<<PB0);    //PORT B0 auf einschalten
5
    PORTB &=~(1<<PB1);    //und B1 auf 0
6
  else                   //wenn IST > SOLL
7
    PORTB |= (1<<PB1);  //B1 einschalten
8
    PORTB &=~(1<<PB0);  //B0 ausschalten( auf 0)
9
  }

Wo sind da die beiden Anweisungen die vom if abhängen sollen mit einer { 
} geblockt worden?

von Hans P. (gableguy2000)


Lesenswert?

1
#include <avr/io.h>
2
#include <stdint.h>
3
4
int main (void)
5
{
6
ACSR &= ~(1<<ACD) | (1<<ACBG);  //ACE einschalten und externe Ref Spannung
7
DDRB |= (1<<DDB0) | (1<<DDB1);       //DDRB als Ausgang
8
9
10
while (1)
11
  {
12
  if ((ACSR & (1<<ACO))==1)   //wenn IST < SOLL
13
    {
14
    PORTB |= (1<<PB0);    //PORT B auf einschalten
15
    PORTB &=~(1<<PB1);
16
    }
17
  else
18
    {
19
    PORTB |= (1<<PB1);
20
    PORTB &=~(1<<PB0);
21
    }
22
  }
23
}

Also so?

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:

> Also so?

Ja.

Aber wenn ich dir einen Formatiertip geben darf.
Lass die { } auf derselben Einrückungstiefe, wie die Anweisung 
deretwegen du sie gemacht hast und rücke nach der { um 2 Zeichen ein und 
beim } wieder um 2 Zeichen aus.
1
int main (void)
2
{
3
  ACSR &= ~(1<<ACD) | (1<<ACBG);  //ACE einschalten und externe Ref Spannung
4
  DDRB |= (1<<DDB0) | (1<<DDB1);       //DDRB als Ausgang
5
6
7
  while (1)
8
  {
9
    if ((ACSR & (1<<ACO))==1)   //wenn IST < SOLL
10
    {
11
      PORTB |= (1<<PB0);    //PORT B auf einschalten
12
      PORTB &=~(1<<PB1);
13
    }
14
    else
15
    {
16
      PORTB |= (1<<PB1);
17
      PORTB &=~(1<<PB0);
18
    }
19
  }
20
}

So ist es optisch einfacher, die zu einem } gehörende öffnende { zu 
finden. Die { und  } gehen dann nicht so leicht unter.

von Karl H. (kbuchegg)


Lesenswert?

Und lies dir das hier
Beitrag "Re: Spannungen vergleichen"
noch einmal durch!

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

habe jetzt alles mal auf meinem Breadboard aufgebaut und zwei 
verschiedene Spannungen drangelegt.
Die Spannung an AIN0 (SOLL) hat ca. 2,4V und die Spannung an AIN1 hat 
1,8V.
Das heißt Soll>IST und somit soll er doch laut meinem Code den Ausgang 
PB0 schalten, aber er setzt PB1 auf eins, es brennt die andere LED.
Wo ist der Denkfehler?

von Karl H. (kbuchegg)


Lesenswert?

Wie sieht dein Code jetzt aus?

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

so:
1
#include <avr/io.h>
2
#include <stdint.h>
3
4
int main (void)
5
{
6
ACSR &= ~(1<<ACD) | (1<<ACBG);  //ACE einschalten und externe Ref Spannung
7
DDRB |= (1<<DDB0) | (1<<DDB1);       //DDRB als Ausgang
8
9
10
while (1)
11
  {
12
  if (ACSR & (1<<ACO))   //wenn IST < SOLL   (1)
13
    {
14
    PORTB |= (1<<PB0);    //PORT B auf einschalten
15
    PORTB &=~(1<<PB1);
16
    }
17
  else
18
    {
19
    PORTB |= (1<<PB1);
20
    PORTB &=~(1<<PB0);
21
    }
22
  }
23
}
Bemerkung: Habe bei (1) die Null bzw. 1 weggemacht, jetzt macht er es 
richtig.

von Hans P. (gableguy2000)


Lesenswert?

Ich habe da noch was, ich würde gerne den AD Wandler benutzen.
Also erstmal testen. Ich habe da an eine Schaltung gedacht, wo ich 8 
LED´s ansteuere.
Die erste hat die Wertigkeit 2^0, 2^1 usw.
damit möchte ich dann die Zahl 256 darstellen, also 8 Bit.
Hat das jemand schon gemacht, oder habt Ihr eine andere Idee, wie ich 
einen Einstieg in den AD Wandler bekomme (Tutorial habe ich schon 
gelesen), ich hätte gerne ein Bsp. Programm, an dem ich noch testen 
kann.

LG

Wollte dafür keinen neuen Beitrag schreiben, hoffe es ist O.K..

von Karl H. (kbuchegg)


Lesenswert?

Das hier

ACSR &= ~(1<<ACD) | (1<<ACBG);  //ACE einschalten und externe Ref 
Spannung

macht nicht das was du denkst.

Ironischerweise ist der ADC von Haus schon so konfiguriert, dass er 
genau das macht, was du eigentlich erreichen willst:
  Er ist eingeschaltet   und
  er vergleicht die Pins AIN0 und AIN1 miteinander

Wenn du ihn also einfach nur in Ruhe gelassen hättest, hättest du das 
gewünschte Ergebnis.


Mit obigen schaltest du den ADC so, dass die Referenzspannung die 
interne Referenz ist.

  ~(1<<ACD) | (1<<ACBG)

wird vom Compiler geparst als

  (~(1<<ACD)) | (1<<ACBG)

du bräuchtest aber:

   ~( (1<<ACD) | (1<<ACBG) )

Daher noch einmal der Aufruf: Wenn du dir über Opertorenreihenfolge 
nicht sicher bist, dann verwende Klammern!

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:

> einen Einstieg in den AD Wandler bekomme (Tutorial habe ich schon
> gelesen)

und, wo ist dann das Problem.
Im Tutorial gibt es eine schöne Routine, die dir den Wert vom AD Wandler 
holt. Was du dann mit dem Wert machst bleibt deiner Phantasie 
überlassen.

von Hans P. (gableguy2000)


Lesenswert?

Ja, aber es fängt ja schon beim Schaltungsaufbau an.
Verbessert mich bitte.
Also ich würde ein Poti an PA0 z.B. anschliessen.
5V auf das Poti und die Spannung die an PA0 ankommt über den AD Wandler 
wandeln, mit 8 Bit aber, damit die Zahl nicht so riesig wird (wie ich 
mit 8 Bit anstatt 10 wandle, ist mir aber auch noch nicht klar).
Dann kann ich ja sagen, 5V / 256 = 19,53 mV. Das sind ja dann meine 
Schritte, denen ich Zahlenwerte zuweisen kann, das wird im Tutorial 
genauso gemacht.
0-19,53mV = 0
19,53mV - 39,06mV = 1
usw.

Dann würde ich gerne aber diese Zahlen irgendwie da ich kein Display 
habe über LED´s ausgeben. 2^0, 2^1, 2^2 usw.
Da hängt es aber auch schon. (Schaltungs und Programmiertechnisch)


LG

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:

> Also ich würde ein Poti an PA0 z.B. anschliessen.
> 5V auf das Poti

Für den Anfang:
ARef an das Poti.
Und das andere Ende des Potis kommt an GND

> und die Spannung die an PA0 ankommt über den AD Wandler

Der MIttenabgriff des Potis kommt an PA0

> wandeln, mit 8 Bit aber, damit die Zahl nicht so riesig wird (wie ich
> mit 8 Bit anstatt 10 wandle, ist mir aber auch noch nicht klar).

Wandle mit 10 Bit. Was du hast, hast du. Die Zahl kleiner machen (zb 
indem man durch 4 dividiert) kann man immer noch.

> Dann kann ich ja sagen, 5V / 256 = 19,53 mV. Das sind ja dann meine
> Schritte, denen ich Zahlenwerte zuweisen kann, das wird im Tutorial
> genauso gemacht.
> 0-19,53mV = 0
> 19,53mV - 39,06mV = 1
> usw.

Gib für den Anfang einfach nur den Wert vom ADC (geteilt durch 4) an 
deine 8 Leds aus. Ohne Umrechnung, ohne irgendwas. Einfach nur
   PORTB = adc_wert / 4;

(adc_wert ist das Ergbnis welches dir die ADC-routine aus dem Tutorial 
gegeben hat)

von Hans P. (gableguy2000)


Lesenswert?

Alles klar,

dannist ja PA0 mein Eingang (AD-Wanlder Eingang) und die Ausgänge, die 
sind ja egal, ob ich B oder C nehmen, oder?

LG

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:
> Alles klar,
>
> dannist ja PA0 mein Eingang (AD-Wanlder Eingang) und die Ausgänge, die
> sind ja egal, ob ich B oder C nehmen, oder?

Dort wo du LEDs drann hast

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

O.K., ist klar.
Habe jetzt mal aus dem Tutorial die ersten Zeieln übernommen und 
abgeändert.
Komme aber trotzdem nicht so richig weiter.
Hier mal der Quelltext:
1
#include <avr/io.h>
2
#include <stdint.h>
3
4
int main(void)
5
{
6
uint8_t i;
7
uint16_t adc_wert;
8
9
10
11
DDRB = (1 << DDB0) | (1 << DDB1) | (1 << DDB2) | (1 << DDB3) | (1 << DDB4)| (1 << DDB5) | (1 << DDB6) | (1 << DDB7); //Datenrichtung Ausgang
12
13
  ADMUX &= ~(1<<REFS1);//auf Null setzen
14
  ADMUX |= (1<<REFS0); // auf eins setzen wegen der exteren Ref Spannung
15
 
16
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
17
                               // setzen auf 8 (1) und ADC aktivieren (1)
18
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
19
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
20
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
21
22
while ( ADCSRA & (1<<ADSC) ) {
23
     ;     // auf Abschluss der Konvertierung warten 
24
  }
25
  adc_wert = ADCW;  // ADCW muss einmal gelesen werden,
26
                  // sonst wird Ergebnis der nächsten Wandlung
27
                  // nicht übernommen.
28
adc_wert = 0; 
29
  for( i=0; i<4; i++ )
30
  {
31
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
32
    while ( ADCSRA & (1<<ADSC) ) {
33
      ;   // auf Abschluss der Konvertierung warten
34
    }
35
    adc_wert += ADCW;        // Wandlungsergebnisse aufaddieren
36
  }
37
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)
38
 
39
  PORTB=adc_wert/4;                    // Summe durch vier teilen = arithm. Mittelwert
40
 
41
  
42
}
Habe halt ziemlich viel aus dem Tutorial genommen, weis aber nicht, ob 
es passt.
Jetzt muss ich doch irgendwie noch mehrere If abfragen reiinmachen, 
damit ich bei bestimmten Werten, die verschiedenen Ausgänge ansteuern 
kann, oder?
Gibt es da noch eine andere Lösung, wie ich das machen kann?
Ist ja ganz schöne Schreibarbeit.
Verstehe es auch nicht so ganz, warum ich den Mittelwert bilden soll, 
wegen der Genauigkeit oder warum?
Ich habe mir jetzt hier auf einem Blatt mal angefangen die Werte 
aufzuschreiben, 0V-...V = 0 usw.
Das sind ja ziemlich viele Werte, muss ich jetzt für jeden Wert den ich 
ausgeben will, eine Zeile schreiben?


LG

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:
> Hallo,
>
> O.K., ist klar.
> Habe jetzt mal aus dem Tutorial die ersten Zeieln übernommen und
> abgeändert.

Warum tust du das?
Im Tutorial ist eine fix und fertige Funktion. Die musst du für deine 
ersten Schritte nur aus dem Tutorial per Cut&Paste in deinen Code 
einsetzen und in main() einen Aufruf der Funktion in die Hauptschleife 
einbauen.

Machst du dir selbst absichtlich das Leben schwer?

Zuerst nimmt man was man kriegen kann. Dann bringt man es zum Laufen. 
Und erst dann fängt man an, die Funktionen zu modifizieren.

> Ist ja ganz schöne Schreibarbeit.

Was ist an ...
1
#include <avr/io.h>
2
3
.... Hier die ReadChannel Funktion aus dem Tut per Cut&Paste
4
5
int main()
6
{
7
  DDRB = 0xFF;
8
9
  while( 1 )
10
  {
11
    PORTB = ReadChannel( 0 ) / 4;
12
  }
13
}

... viel Schreibarbeit?

von Hans P. (gableguy2000)


Lesenswert?

Oh man, das ist ja ienfach als ich gedacht habe.
Hier jetzt der Code mit der Funktion aus dem Tutorial und dem Aufruf in 
der main
1
#include <avr/io.h>
2
#include <stdint.h>
3
4
uint8_t i;
5
uint16_t adc_wert;
6
7
8
uint16_t ReadChannel(uint8_t mux)
9
10
{
11
  uint8_t i;
12
  uint16_t result;
13
 
14
  ADMUX = mux;                      // Kanal waehlen
15
  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
16
 
17
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
18
                               // setzen auf 8 (1) und ADC aktivieren (1)
19
 
20
  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
21
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
22
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
23
  while ( ADCSRA & (1<<ADSC) ) {
24
     ;     // auf Abschluss der Konvertierung warten 
25
  }
26
  result = ADCW;  // ADCW muss einmal gelesen werden,
27
                  // sonst wird Ergebnis der nächsten Wandlung
28
                  // nicht übernommen.
29
 
30
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
31
  result = 0; 
32
  for( i=0; i<4; i++ )
33
  {
34
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
35
    while ( ADCSRA & (1<<ADSC) ) {
36
      ;   // auf Abschluss der Konvertierung warten
37
    }
38
    result += ADCW;        // Wandlungsergebnisse aufaddieren
39
  }
40
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)
41
 
42
  result /= 4;                     // Summe durch vier teilen = arithm. Mittelwert
43
 
44
  return result;
45
}
46
47
int main()
48
{
49
  DDRB = 0xFF;
50
51
  while( 1 )
52
  {
53
    PORTB = ReadChannel( 0 ) / 4;
54
  }
55
}
Mit Schreibarbeit habe ich das auswerten von dem Messwert gemeint.
Ich muss doch jetzt sagen, welchen Ausgang von PORTB ich ansteuern will, 
oder?

Ich glaube ich denke in eine falsche Richtung oder zu umständlich.

Sorry

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:

> Mit Schreibarbeit habe ich das auswerten von dem Messwert gemeint.
> Ich muss doch jetzt sagen, welchen Ausgang von PORTB ich ansteuern will,
> oder?

Für deine ersten Tests reicht es völlig dem PORTB als Ganzes ein neues 
Bitmuster zu verpassen.
Genau das macht diese Zuweisung :-)

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

wollte noch mal fragen, mit dem anschliessen.
Ich gehe von der Spannungsquelle an das Poti und an den AREF.
Mit dem Poti GND gehe ich zum Pin 31, also der GND unter AREF.
Dann gehe ich mit den 5V an Pin 10 Vcc und Pin 11 GND.
Muss ich it dem GND vom POTI auch noch auf den GND von der 
Spannungsquelle gehen, oder sind die GND von Pin31 mit dem Pin 11 intern 
gebrückt?


MfG

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:
> Hallo,
>
> wollte noch mal fragen, mit dem anschliessen.
> Ich gehe von der Spannungsquelle an das Poti und an den AREF.

Nein.
Du gehst nicht an den ARef.

Du schaltest den Mega per Software so (das macht die ReadChanel), dass 
der Mega seine Versorgungsspannung als Referenzspannung hernimmt. Diese 
Referenzspannung stellt dir der Mega freundlicherweise am Pin ARef zur 
Verfügung.

Du schaltest also ganz einfach nur das Poti an den ARef und der Mega 
beaufschlagt das Poti mir der Spannung.

> Mit dem Poti GND gehe ich zum Pin 31, also der GND unter AREF.
> Dann gehe ich mit den 5V an Pin 10 Vcc und Pin 11 GND.
> Muss ich it dem GND vom POTI auch noch auf den GND von der
> Spannungsquelle gehen, oder sind die GND von Pin31 mit dem Pin 11 intern
> gebrückt?


Du machst dir das jetzt kompliziert (und ich hab jetzt keine Lust das 
auseinanderzudröseln)
Stinknormale Prozessorbeschaltung, so dass er läuft: Alle GND mit GND 
der Spannungsquelle verbunden. Alle Vcc, AVcc mit Vcc der 
Spannungsquelle verbunden. BLockkondensatoren wie gehabt.

Also -> ganz normale Arbeitskonfiguration des Prozessors.

Dann nimmst du dein Poti.
Das eine Ende (der 3 Anschlüsse) kommt an GND, das andere Ende an ARef 
und der mittlere Potianschluss an PA0.

Achte noch darauf, dass an ARef ein 100n Kondensator zur Abblockung der 
vom Mega zur Verfügung gestellten Spannung ist, und schon kanns 
losgehen.

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

habe es angeschlossen, und es leuchtet nix.
Ich kann das Poti drehen wie ich will, da tut sich nix.
Verschaltung:
Poti:
Plus vom Poti über 100n an AREF
Mittelabgriff an PA0
GND an GND vom mC (Pin 31)

ATmega
Vcc von der Sapnnungsquelle
GND mit GND der Spannungsquelle verbunden (PIN 11)
PB0 bis PB7 über Widerstände an LEDs,

LED´s
Anode mC
Kathode GND von Spannungsquelle.


LG

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:
>
> ATmega
> Vcc von der Sapnnungsquelle

Was ist mit AVcc?
AVcc versorgt den Port A (also den Port an dem die ADC sind) mit Saft

von Hans P. (gableguy2000)


Lesenswert?

Da habe ich nix dran.
Wird Port A nicht durch den Mittelabgriff des Potis versorgt.
Ich habe mal angeschlossen und gemessen, am Ausgang von Port B habe ich 
eine Spannung anliegen. Vom Ausgnag PB0 bis zum Widerstand auch noch, 
aber auf der anderen Seite des Widerstandes ist 0 V.
Hat das was mit den internen Pull up Widerständen zu tun?
Kann das sein?

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:
> Da habe ich nix dran.

Dann mal schnell.

> Wird Port A nicht durch den Mittelabgriff des Potis versorgt.

Nein.
AVcc liefert die Energie, damit der ADC überhaupt arbeiten kann. 
Arbeiten bedeutet dann, dass der ADC die Spannung misst, die an einem 
bestimmten Pin anliegt.

Das wäre wohl ein wenig fatal, wenn das Messgerät die zu messende Größe 
dadurch beeinflusst, indem die Messgröße auch noch das Messgerät 
versorgen muss.

> Hat das was mit den internen Pull up Widerständen zu tun?
> Kann das sein?

Nein.
SChliess endlich Avcc an.
Und dann liest du das Assembler Tutorial von Anfang an durch. Auch wenn 
du nicht Assembler programmierst, so finden sich darin viele Hinweise, 
die auch für dich als C-Programmierer wichtig sind.

Und ich klinke mich jetzt aus.

von Hans P. (gableguy2000)


Lesenswert?

Hallo,

AVCC ist angeschlossen, habe auch noch einen Fehler im Prog gehabt, habe 
die interne Ref Spannung verwendet, was ja falsch ist, ich lege ja eine 
externe an.
Ich habe bis zu 5V an PCB0 aber einen Strom von 20mA. Die LED macht nix, 
nicht mal aufleuchten.


LG

von Hans P. (gableguy2000)


Lesenswert?

Alles klar,
es funktioniert, war mein Fehler.


Danke

von Michael M. (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Und ich klinke mich jetzt aus.
Respekt für deine Engelsgeduld.

@Hans Peter:
Is nicht böse gemeint, aber n bisschen mehr Eigeninitiative wär schon 
angebracht gewesen.

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.