Analogsignal auf AVR

Gast #843742
Lesenswert?

Hallo Zusammen

Sehr gerne würde ich ein Analogsignal z.B. 0V-5V mit einem 
Mikrokontroller auswerten.

1. Mit welchem Kontroller kann ich das machen? ATMEGA8, ATTINY45 ?
2. Wie kann ich das Signal an den PC schicken und dort auswerten?

Ich habe bereits einen Sensor für Methanol über ein USB-Interface 
angeschlossen und eine Umgebung programmiert. Ist es möglich, z.B. mit 
RS232 oder über USB das Signal auszuwerten? Bis jetzt weiss ich nicht so 
viel über AVR-Controller, aber ich mache Fortschritte!

Danke für die Antwort

Gruss Fox
Gast #843749
Lesenswert?

Für diese anwendung gibt es einen ganzen haufen möglichkeiten bei den 
avr's

anforderungen: du brauchst einen AVR mit internem ADC (ATTINY2313 hat 
z.B. KEINEN DC), die meisten allerdings verfügen über einen.
du kannst das ganze entweder über rs232, oder usb (rs232->usb wandler, 
da die AVR's über keine interne USB-Anbindung verfügen)
Gast #843789
Lesenswert?

Das tönt ja super!

Wie kann ich den AnalogDigital ansprechen mit C?

Weiss jemand eine Schaltung und Code für die Auswertung auf RS232?
Habe noch ein MAX232 oder so etwas rumliegen. Habe ich mal vor Jahren 
gekauft und nie gebraucht.

Bis jetzt kenne ich nur so grundlegende Elemente wie:
1
#include <avr/io.h>
2
#define F_CPU 1000000UL     /* Quarz mit 1Mhz  */
3
#include <util/delay.h>
4

5
int x = 0;         
6
 
7
int main (void) {           
8
 
9
   DDRB = 0b00110111;             // Pin 3 = Eingang
10
   PORTB = 0b00101111;             // Pin 4 = LOW
11

12

13

14
  while(x==0){
15

16
  if ( !(PINB & (1<<PINB3)) ){
17

18

19
PORTB |= (1<<PB4);
20
x = 1;
21
_delay_ms(200); 
22

23
}
24
}
25
  while(x==1){
26

27
  if ( !(PINB & (1<<PINB3)) ){
28

29
PORTB &= ~(1<<PB4);  
30
x = 0;
31
_delay_ms(200); 
32
}
33
}
34
                          
35
    return main();               
36
}
Gast #844237
Lesenswert?

@ Axel,

mach das in deinem Code mit 32 Werten, die Divisionsroutine wird 
schneller Wert = Wert >> 5,

aber nur wenn das RAM reicht. Ansonsten finde ich die Schreibweise:

Register = (1 << Bitname)

wesentlich aussagefähiger. Wer weiß nach einiger zeit noch was z. B.:
Register = 0x84

eigentlich bewirkt.

Außerdem wird dir dann hier auch leichter geholfen, weil nicht jeder die 
Maske überstülpen und nachrechnen muss.

MW
Gast #844372
Lesenswert?

Ok ich formuliere die Frage mal anders:

Ich würde gerne, ein Signal von 0-5V mit dem AVR verarbeiten. Am 
einfachsten, um das Ganze zu lernen, wäre es sinvoll, einen Eingang 
gleich wieder auf einen Ausgang zu schalten.

z.B. Eingang PB3 0-5V auf Ausgang PB0 0-5V. (falls so möglich)

oder: Eingang PB3 0-5V dabei wird ein eingeschalten 1V PB0, 2V PB1, 3V 
PB2, 4V PB4

Wie muss ich das mit C realisierien?
Gast #844532
Lesenswert?

So und jetzt noch Festlegen der Ports:

Das ist ja für IO etc.
1
 #include <avr/io.h>
2
#define F_CPU 9600000UL     /* Quarz mit 9.6Mhz */
3
#include <util/delay.h>
4
         
5
 
6
int main (void) {           
7
 
8
   DDRB = 0b00110111;             // Pin 3 = Eingang
9
   PORTB = 0b00001000;             // Pin 4 = LOW
10

11
int value;
12

13
if (value>787)  PORTB |= _BV(1);
14

15
else PORTB &=~_BV(1);
16

17

18

19
                          
20
    return main();               
21
}
Gast #844547
Lesenswert?

So hab mal ein wenig probiert aber ohne Erfolg. Es fehlt noch eine 
Kleinigkeit: Irgendwie muss ich die Ports korrekt zuordnen. PB3 = 
Eingang Analog --> Wie???
1
  #include <avr/io.h>
2
#define F_CPU 9600000UL     /* Quarz mit 9.6Mhz */
3
#include <util/delay.h>
4
         
5
 
6
int main (void) {           
7
 
8
   DDRB = 0b00111111;             // Pin 3 = Eingang
9
   PORTB = 0b00001000;             // Pin 4 = LOW
10

11

12
ADMUX=0x02;    // PortB4 = ADC2 = Analog Eingang
13
ADCSRB=0x00;
14
ADCSRA=0x84;  // ADEN =1 / Prescaler = 16
15

16

17

18

19

20
int value;
21

22
if (value>787)  PORTB |= _BV(1);
23

24
else PORTB &=~_BV(1);
25

26

27

28
                          
29
    return main();               
30
}
Gast #844650
Lesenswert?

Hallo: Wie muss ich den Analog-Eingang korrekt definieren?

Ist das korrekt? Kann ich direkt 5V auf den Eingang geben?
1
ADMUX=0x02;    // PortB4 = ADC2 = Analog Eingang
2
ADCSRB=0x00;
3
ADCSRA=0x84;  // ADEN =1 / Prescaler = 16
#844662
Lesenswert?

Wer hat dir denn den Müll gezeigt?
1
int main (void) {
2

3
   ...
4

5
   return main();
6
}

Das läuft in 0 Komma Nix auf einen Stack-Overflow hinaus. Das
blöde dabei ist nur, daß nach einem Stack Overflow so ziemlich
alles oder nichts passieren kann.

Was ist falsch an der guten alten Mainloop, so wie sie Millionen
Programmierer weltweit benutzen?
1
int main() {
2

3
  .... hier die Initialisierungen des Programms, die Hardware
4
  .... wird entsprechend den Anforderungen konfiguriert
5

6
  while( 1 ) {      // die klassische Hauptschleife. Aus ihr kommt
7
                    // der Prozessor bis zum nächsten Reset bzw.
8
                    // Stromabschalten nicht mehr heraus
9

10
    ....   Programmlogik, Hardware abfragen, Ports lesen, Ports auf
11
    ....   neue Ausgabewerte setzen, etc
12
  }
13
}

Richtig. Gar nichts ist damit falsch.
Gast #844700
Lesenswert?

Ich arbeite mich mal durch das ganze Tutorial. Danach werde ich mich 
wieder melden. Zum Teil fehlen mir die Beispiele, es hat zwar viele 
Erklährungen im Tutorial, jedoch kann ich z.B. mit den nichts anfange, 
da ich nicht weiss was man do aktivieren muss etc.

  ADMUX = mux;                      // Kanal waehlen

ja was für ein Kanal etc.
#844716
Lesenswert?

Fox wrote:
> Ich arbeite mich mal durch das ganze Tutorial. Danach werde ich mich
> wieder melden. Zum Teil fehlen mir die Beispiele, es hat zwar viele
> Erklährungen im Tutorial, jedoch kann ich z.B. mit den nichts anfange,
> da ich nicht weiss was man do aktivieren muss etc.
>
>   ADMUX = mux;                      // Kanal waehlen
>
> ja was für ein Kanal etc.


Ich vergass:
Das Tutorial alleine ist zuwenig. Du brauchst auch noch das
Datenblatt zu deinem Prozessor. Dieses kriegst du bei www.atmel.com
Gast #849585
Lesenswert?

So habe mich mal in den letzten Tagen hinter das Tutorial gemacht. Komme 
nicht mehr weiter, ich brauche Hilfe. Mit dem unten stehenden Programm, 
möchte ich ein Potentiometer an PinB4 (ADC2) anhängen, welches mir 0-5V 
gibt. Danach möchte ich z.B. ab 2V alle LEDs anfangen zu leuchten.

So schwer ist dass doch nicht? könnt ihr mir helfen bei diesem, für 
euch, trivialen Problem?

Gruss Fox
1
#include <avr/io.h>
2
#define F_CPU 9600000UL     /* Quarz mit 9.6Mhz */
3
#include <util/delay.h>
4

5

6

7

8
int main (void) {           
9
 
10
     DDRB = 0b11101111;             // Pin 4 = Eingang
11
     PORTB = 0b00010000;             // Pin 4 = High
12

13
  ADC = 0b11010000;
14
  ADMUX = 0b01010000;
15

16

17

18
while(1) {               
19

20

21
int value;
22

23
if (value>200)  PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
24

25
else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
26

27

28

29
}
30
                          
31
    return 0;               
32
}
#849614
Lesenswert?

Ich habe jetzt gerade die ADC-Initialisierung nicht im Kopf, aber wie 
genau hast du das Poti angeschlossen?

Eine Fehlerbeschreibung wie "geht nicht" kann zwischen "alle LEDs 
bleiben aus" und "LEDs samt Board brennen lichterloh" alles bedeuten.

Funktionieren die LEDs prinzipiell?

Der Kommentar hier ist irreführend:
statt:
  PORTB = 0b00010000; // Pin 4 = High
besser:
  PORTB |= 1 << PB4; // Pin 4 - internen Pull-Up aktivieren

Das wäre treffender, da du den Pin zuvor ja als Eingang konfiguriert 
hast.

Hier nochmal einen Vorschlag für ein lesbares Quelltext-Layout mit 
einigen Fragezeichen als Hausaufgabe ;) :
1
#include <avr/io.h>
2
#define F_CPU 9600000UL     /* Quarz mit 9.6Mhz */
3
#include <util/delay.h>
4

5
int main (void)
6
{
7
    int value; // Was ist das für eine Variable? Wer befüllt die?
8

9
    DDRB = 0b11101111;             // Pin 4 = Eingang
10
    PORTB = 0b00010000;             // Pin 4 = High
11

12
    // Hier wäre ein Kommentar angebracht, was du damit
13
    // eigentlich bezwecken willst:
14
    ADC = 0b11010000;
15
    ADMUX = 0b01010000;
16

17
    while(1)
18
    {
19
        // Wo wird value verändert?
20
        if (value > 200)
21
        {
22
            // Was soll diese Zeile tun?
23
            PORTB |= ((1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3));
24
        }
25
        else
26
        {
27
            // Was soll diese Zeile tun?
28
            PORTB &= ~((1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3));
29
        }
30
    }
31

32
    return 0;               
33
}
#849623
Lesenswert?

Auweia. Ich frage mich, ob das Tutorial tatsächlich dermaßen schlecht 
verständlich ist, dass man nach tagelangem Studium desselben so was 
schreibt...

Erstens ist es kontraproduktiv bzw. tödlich, an einem Analog-Eingang den 
Pull-Up einzuschalten. Zweitens muss man auch irgendwo auf das Ende der 
Wandlung warten und dann die Ergebnisregister auslesen! Und wie das geht 
steht alles im Tutorial, inklusive Beispielcode!
Gast #849625
Lesenswert?

Hallo!

Ja die LEDs kann ich anschalten und abschalten. Diese habe ich sogar 
über einem Transistor gesteuert. Alles bestens.

Den Poti habe ich bei GND und +5V angehägt. Der Variable Pin geht an den 
Eingang ADC2. Dort hatte ich vorher einen Schalter und konnte auf 
Knofdruck die LEDs anschalten und wieder abschalten.

Das mit der Variable value war für mich auch unklar, diese habe ich von 
Axel übernommen. Am Besten wäre hier eine Direktzuweisung. Wie PORTB |= 
( (1<<PB0) oder so. Kenne aber den Befehl nicht.

Stimmen die Zusweisungen für ADC und ADMUX braucht ich noch etwas mehr?
#849631
Lesenswert?

Fox wrote:
> Das mit der Variable value war für mich auch unklar, diese habe ich von
> Axel übernommen. Am Besten wäre hier eine Direktzuweisung. Wie PORTB |=
> ( (1<<PB0) oder so. Kenne aber den Befehl nicht.
"Befehle" gibt es in C nicht, nur Anweisungen und Operatoren. Und wie 
das mit den Bitzugriffen funktioniert ist ebenfalls im 
AVR-GCC-Tutorial, das Du ja angeblich durchgearbeitet hast, 
erläutert!
Gast #849640
Lesenswert?

Wie wäre es einfach mal mit einer Lösung?!?

Du kannst nicht erwarten, dass ich bei allem draus komme, für mich ist 
das neu. Ein kleines einfaches Beispiel wäre hier sinnvoller als die 
vielen Verweise auf das Tutorial. Ich kann es auch noch 10x durchlesen 
und komme nicht weiter.
Gast #849654
Lesenswert?

value = übernommen von Axel wie schon geschrieben, wäre es besser eine 
Direktanweisung, von welcher ich nicht weiss wie sie aussieht.




DDRB muss gesetzt werden ob Eingang oder Ausgang. Dabei von links nach
rechts PB0 bis PB6. 1= Ausgang; 0=Eingang.
PORTB definiert ob der Eingang an den interne Pullup geschalten wird
oder nicht.
!(PINB & (1<<PB4)) = Abfragen von Taster High or Low
Pin zu High: PORTB |= (1<<PB4);
Pin zu LowL: PORTB &= ~(1<<PB4);

So mit dem kann man nämlich arbeiten.

Jetzt wie sieht das für den ADC aus? Eventuell könnte mir jemand ein
kleines Beispielprogramm senden? Ein Analoger Eingang schaltet ein
Ausgang ab einem gewissen Bitwert. Ist das so viel verlangt?
Gast #849656
Lesenswert?

Ich versuch's auch mal und beziehe mich auf deinen Versauch vom 22.4.
um 17:29:

>     DDRB = 0b11101111;             // Pin 4 = Eingang

Bis zu dieser Zeile ist noch alles ok.

>  PORTB = 0b00010000;             // Pin 4 = High

Diese Zeile aktiviert den internen Pullup-Widerstand von PB4. Das
möchtest du sicher nicht, weil er den Spannungswert des
(wahrscheinlich als Spannungsteiler) geschalteten Potentiometers
verfälscht. Lass die Zeile einfach weg.

>  ADC = 0b11010000;

Das ADC-Register ist read-only. Da steht hinterher der gemessene Wert
drin. Lass die Zeile ebenfalls weg.

>  ADMUX = 0b01010000;

ADMUX enthält in den oberen 4 Bits u.a. die Auswahl der
Referenzspannung, in den unteren 4 Bits den A/D-Kanal. Du willst als
Referenzspannung VCC (5V) und den Kanal 2 (ADC2, PB4). Das ergibt

  ADMUX = 0b00000010;

oder einfach
1
  ADMUX = 2; // Kanalnummer

Das hattest du weiter oben aber schon mal richtig.

Jetzt fehlt noch die Initialisierung des ADC über das ADCSRA-Register:
1
  ADCSRA = 1<<ADEN | 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0;

ADEN aktiviert den ADC. Über die ADPSx-Bits wird die ADC-Taktfrequenz
gesetzt, in diesem Fall auf 1/128 der Controller-Taktfrequenz (für den
Anfang lieber etwas zu langsam als zu schnell).

> while(1) {
> int value;
> if (value>200)  PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );

Wo wird value beschrieben? Nirgends, deswegen steht Müll in der
Variable.

Das mit der Endlosschleife ist aber schon mal eine gute Idee, da du ja
periodisch den Spannungswert einlesen möchtest.
1
  while(1) {
2
    int value;

Erst einmal muss der ADC gestartet werden, dies geschieht durch setzen
des ADSC-Bits:
1
    ADCSRA |= ADSC;

Jetzt dauert es eine Weile bis der ADC den Spannungswert umgesetzt
hat. Wenn er fertig ist, setzt er das ADSC-Bit wieder zurück. So lange
lassen wir den Prozessor einfach im Kreis drehen:
1
    while(ADCSRA & ADSC);

Nach Verlassen der Schleife kann das Ergebnis gelesen werden:

    value = ADC;

Jetzt (und erst jetzt) kannst du value auswerten, bspw. mit der
if-Abfrage in deinem Programm:
1
    if (value>200)
2
      PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
3
    else
4
      PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
5
  }

Ich habe das oben Geschriebene nicht getestet, deswegen funktioniert
es möglicherweise nicht sofort. Zumindest zeigt es die grundsätzlichen
Schritte, die man für den Betrieb des ADC braucht.
#849663
Lesenswert?

Fox wrote:
> value = übernommen von Axel wie schon geschrieben, wäre es besser eine
> Direktanweisung, von welcher ich nicht weiss wie sie aussieht.

Was ist so schwer daran das so zu schreiben
1
int main()
2
{
3
  DDRB = 0b11101111;
4

5
  while( 1 ) {
6
    if( ReadChannel( 2 ) > 200 )
7
      PORTB |= ( 1 << PB0 ) | ( 1 << PB1 ) | ( 1 << PB2 ) | ( 1 << PB3 );
8
    else
9
      PORTB &= ~( ( 1 << PB0 ) | ( 1 << PB1 ) | ( 1 << PB2 ) | ( 1 << PB3 ) );
10
  }
11
}

und die ReadChannel Funktion übernimmst du erst mal aus
dem Tutorial so wie sie dort steht. Mglw. gibt es dann dort
noch eine Fehlermeldung weil die Register oder Steuerbits anders
heissen. Das ist aber nichts was sich nicht mit dem Datenblatt
des Tiny aus der Welt schaffen ließe.
Gast #849686
Lesenswert?

So klappt noch nicht ganz.

Habe herausgefunden, dass der Controller im while(ADCSRA & ADSC) hängen 
bleibt. Wenn ich das ausschalten, geht es auch noch nicht. Irgend etwas 
stimmt noch nicht.
1
#include <avr/io.h>
2
#define F_CPU 9600000UL     /* Quarz mit 9.6Mhz */
3
#include <util/delay.h>
4

5

6
/* Dieses Programm wandelt das analoge Signal auf PB4 (ADC2) in ein digitales um. Bei einem Bitwert z.B. ab 200 werden die Ausgänge
7
  PB0 bis PB3 aktiviert */
8

9
int main (void) {           
10
 
11
     DDRB = 0b11101111;                           // Pin 4 = Eingang
12

13
  ADMUX = 2;                          // auch ADMUX = 2; (Kanalnummer) oder ADMUX = 0b00000010;
14
  ADCSRA = 1<<ADEN | 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0;    // Initialisierung des ADC über das ADCSRA-Register
15
                      
16

17

18

19
while(1) {               
20

21
int value;
22
value = ADC;
23
ADCSRA |= ADSC;                       // ADC starten
24

25
while(ADCSRA & ADSC){                    // ADC wird gestartet
26
PORTB |= (1<<PB0);
27
}
28

29

30

31
if (value>200)  PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
32

33
else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
34

35

36

37
}
38
                          
39
    return 0;               
40
}
#849697
Lesenswert?

yalu wrote:
>
> Nach Verlassen der Schleife kann das Ergebnis gelesen werden:
>
>     value = ADC;

Man mag mich steinigen, aber:
Müsste das nicht

    value = ADCW;

heissen.
Wenn ich mich recht erinnere, ist das die große Ausnahme
unter den 16 Bit Registern, weil es eine Assembler Instruktion
namens ADC gibt.
#849698
Lesenswert?

Fox wrote:
> lol!!!
>
> Ok habs geändert, klappt trotzdem noch nicht.
>
>
1
> int value;
2
> 
3
> ADCSRA |= ADSC;                       // ADC starten
4
> while(ADCSRA & ADSC){                    // ADC wird gestartet
5
> PORTB |= (1<<PB0);
6
> }
7
> 
8
> value = ADC;
9
>

Aus dem Tutorial (und um Variablennamen nachgebessert)
1
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
2
  while ( ADCSRA & (1<<ADSC) ) {
3
     ;     // auf Abschluss der Konvertierung warten 
4
  }
5
  value = ADCW;

Sieh dir die Unterschiede genau an!
#849700
Lesenswert?

Hallo,

ohne auf den Rest einzugehen: Du hast offenbar ein Problem, Dir die 
Abläufe vorzustellen.
Spiele einfach AVR und gehe Dein Programm schrittweise durch.

Dabei sollte Dir z.B. auffallen, daß die Folge

value = ADC;
ADCSRA |= ADSC;                       // ADC starten

einfach Unsinn ist.

Du liest ERST den Wert aus dem ADC und startest DANACH erst die 
Wandlung.

Falls Du Auto fährst: fährst Du auch ERST los und startest DANACH den 
Motor?

Gruß aus Berlin
Michael
#849708
Lesenswert?

ich habe noch nie in C programmiert (bin noch mit Assembler beschäftigt) 
aber ich kann dir sagen wo dein Fehler liegt
1
....
2
ADCSRA |= ADSC;                     // ADC starten
3

4
while(ADCSRA & ADSC){                    // ADC wird gestartet
5
PORTB |= (1<<PB0);
6
}
7

8
value = ADC;
9
...

value kannst du erst dann zuweisen wenn der ADC mit der Wandlung fertig 
ist. d.h. erst wenn du aus der while(ADCSRA & ADSC){... raus bist.

Grundsätzlich funktioniert adc so:
1.ADC konfigurieren
2.ADC starten
3. warten bis der ADC mit der Wandlung fertig ist
4. wert auslesen
#849714
Lesenswert?

Mr K. wrote:
> ich habe noch nie in C programmiert (bin noch mit Assembler beschäftigt)
> aber ich kann dir sagen wo dein Fehler liegt
>
>
1
> ....
2
> ADCSRA |= ADSC;                     // ADC starten
3
> 
4
> while(ADCSRA & ADSC){                    // ADC wird gestartet
5
> PORTB |= (1<<PB0);
6
> }
7
> 
8
> value = ADC;
9
> ...
10
>
>

Nur der Vollständigkeit halber (Fox scheint den einfachen Weg zu
gehen und alles zu übernehmen was hier so gepostet wird ohne
darüber nachzudenken ob das so stimmen kann):
Bits werden in einem Register anders gesetzt. ADSC ist der
Name eines Bits. Folgerichtig muss es zb. heissen

  ADCSRA |= ( 1 << ADSC );                // ADC starten

Steht aber auch alles in Form einer getesteten Funktion im
Tutorial, welches Fox angeblich ja studiert hat.
Gast #849727
Lesenswert?

Danke für die Hilfe. Ich weiss ich bin am ausprobieren durch die 
Verzweiflung, ich beschäftige mich jetzt mit diesem einfachen Problem 
seit Tagen.

Es klappt jetzt so weit gut. Habe das Programm noch erweitert, dass es 
stufenweise die LEDs einschaltet. Das Problem ist allerdings, dass bei 
den ersten 3 IF die LEDs nur schwach leuchten. Die 4 Leuchtet dafür 
voll.

Also bis value 1000 = LEDs flackern, ab 1000 LED leuchten hell

Habe ich nur ein IF dann leuchten die LEDs hell.

[c]

#include <avr/io.h>
#define F_CPU 9600000UL     /* Quarz mit 9.6Mhz */
#include <util/delay.h>


/* Dieses Programm wandelt das analoge Signal auf PB4 (ADC2) in ein 
digitales um. Bei einem Bitwert z.B. ab 200 werden die Ausgänge
  PB0 bis PB3 aktiviert */

int main (void) {

     DDRB = 0b11101111;                           // Pin 4 = Eingang


  ADMUX = 2;                          // auch ADMUX = 2; (Kanalnummer) 
oder ADMUX = 0b00000010;
  ADCSRA = 1<<ADEN | 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0;    // 
Initialisierung des ADC über das ADCSRA-Register




while(1) {

int value;

  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
  while ( ADCSRA & (1<<ADSC) ) {

     ;     // auf Abschluss der Konvertierung warten
  }

  value = ADCW;



if (value<400)  PORTB |= ( (1<<PB0) );

else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );


if (value>400 & value<800)  PORTB |= ( (1<<PB0) | (1<<PB1)  );

else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );


if (value>800 & value<1000)  PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2) 
);

else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );


if (value>1000)  PORTB |= ( (1<<PB0) | (1<<PB1)  | (1<<PB3) | (1<<PB4) 
);

else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );


}

    return 0;
}

[c]
#849731
Lesenswert?

Hab mir nicht alles geschaut weil als C-Laie hätte ich sowieso nicht 
alle Fehler finden können aber solche Fehler wie sie Fox ständig am 
fliesenden Band produziert zu finden braucht man noch nicht mal 
irgendeine Programmiersprache zu können.

@Fox: Selber denken/lernen/verstehen wird man dir hier nicht abnehmen 
können. Hab auch gerade vor zwei tagen mit ADC angefangen aber dank des 
tutorial hier + Datenblätter + Forum Beiträge + google konnte ich viel 
lernen und verstehen.
#849738
Lesenswert?

Fox wrote:

> Es klappt jetzt so weit gut. Habe das Programm noch erweitert, dass es
> stufenweise die LEDs einschaltet. Das Problem ist allerdings, dass bei
> den ersten 3 IF die LEDs nur schwach leuchten. Die 4 Leuchtet dafür
> voll.

Dann denk dir einen Wert aus, zb 900 und geh mal durch deine
if in Gedanken durch. Achte darauf ob der if oder das else genommen
wird und überlege, welche Konsequenzen sich daraus für deinen
Port ergeben.
Achte insbesondere darauf, wann und wo ein Portbit ausgeschaltet
wird nur um im nächsten if dann wieder eingeschaltet zu werden
(deine Led blinkt dann sehr schnell)

Insebsondere kannst du dir ja mal überlegen, warum eigentlich
der if, der den Wert gegen 1000 abprüft sich am Pin 0 zu schaffen
macht. Pin 0 ist doch bei allen Werten die größer als 200 sind
sowieso immer eingeschaltet.
1
  PORTB = 1 << PB0;        // PB0 ist immer ein. Egal bei welcher Spannung
2

3
  if( value > 400 )        // wenn größer als 400, also zb auch bei 900
4
    PORTB |= ( 1 << PB1 ); // dann brennt PB1 auf jeden Fall
5
  else
6
    PORTB &= ~( 1 << PB1 );
7

8
  if( value > 800 )
9
    PORTB |= ( 1 << PB2 );
10
  else
11
    PORTB &= ( 1 << PB2 );
12

13
  if( value > 1000 )
14
    PORTB |= ( 1 << PB3 );
15
  else
16
    PORTB &= ( 1 << PB3 );
#849747
Lesenswert?

korigiert mich wenn ich falsch liege aber bei 400 würde die else der 
ersten if angenommen also alle LED an. ich denke das ist nicht gewollt 
oder?
1
if (value<400)  PORTB |= ( (1<<PB0) );
2

3
else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
4

5

6
if (value>400 & value<800)  PORTB |= ( (1<<PB0) | (1<<PB1)  );
7

8
else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
9

10

11
if (value>800 & value<1000)  PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2)
12
);
13

14
else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
15

16

17
if (value>1000)  PORTB |= ( (1<<PB0) | (1<<PB1)  | (1<<PB3) | (1<<PB4)
18
);
19

20
else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
Gast #849748
Lesenswert?

So Leute, ich entschuldige mich für die Stürmerei und Ungeduld von mir. 
Trozdem habe ich sehr viel gelernt. Mein Programm konnte ich jetzt 
selber fertig stellen. Ich kann es jetzt nach belieben anpassen, 
verändern etc.

Jetzt funktioniert es so wie es sollte! Ich Danke euch nochmals ganz 
herzlich für die Hilfe.

Hier mein Programm! Für alle die, die mal Probleme mit ADC haben.  Hier 
ist ein Code der funktioniert.
1
#include <avr/io.h>
2
#define F_CPU 9600000UL     /* Quarz mit 9.6Mhz */
3
#include <util/delay.h>
4

5

6
/* Dieses Programm wandelt das analoge Signal auf PB4 (ADC2) in ein digitales um. Bei einem Bitwert z.B. ab 200 werden die Ausgänge
7
  PB0 bis PB3 aktiviert */
8

9
int main (void) {           
10
 
11
     DDRB = 0b11101111;                           // Pin 4 = Eingang
12

13

14
  ADMUX = 2;                          // auch ADMUX = 2; (Kanalnummer) oder ADMUX = 0b00000010;
15
  ADCSRA = 1<<ADEN | 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0;    // Initialisierung des ADC über das ADCSRA-Register
16
                      
17

18

19

20
while(1) {               
21

22
int value;
23

24
  ADCSRA |= (1<<ADSC);                          // eine ADC-Wandlung 
25
  while ( ADCSRA & (1<<ADSC) ) {                // auf Abschluss der Konvertierung warten 
26
  }
27

28
  value = ADCW;
29

30

31

32
while (value<400){
33
  PORTB |= ( (1<<PB0) );
34
  ADCSRA |= (1<<ADSC);                          // eine ADC-Wandlung 
35
  while ( ADCSRA & (1<<ADSC) ) {                // auf Abschluss der Konvertierung warten 
36
  value = ADCW;
37
  }
38
}
39

40

41
while (value>400 & value<800){  
42
  PORTB |= ( (1<<PB0) | (1<<PB1)  );
43
  ADCSRA |= (1<<ADSC);                          // eine ADC-Wandlung 
44
  while ( ADCSRA & (1<<ADSC) ) {                // auf Abschluss der Konvertierung warten 
45
  value = ADCW;
46
  }
47
}
48

49

50
while (value>800 & value<1000){  
51
  PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2) );
52
  ADCSRA |= (1<<ADSC);                          // eine ADC-Wandlung 
53
  while ( ADCSRA & (1<<ADSC) ) {                // auf Abschluss der Konvertierung warten 
54
  value = ADCW;
55
  }
56
}
57

58

59
while (value>1000){  
60
   PORTB |= ( (1<<PB0) | (1<<PB1)  | (1<<PB2) | (1<<PB3) );
61
  ADCSRA |= (1<<ADSC);                          // eine ADC-Wandlung 
62
  while ( ADCSRA & (1<<ADSC) ) {                // auf Abschluss der Konvertierung warten 
63
  value = ADCW;
64
  }
65
}
66

67

68
PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
69

70
}
71
                          
72
    return 0;               
73
}
#849751
Lesenswert?

Mr K. wrote:

>
1
> if (value<400)  PORTB |= ( (1<<PB0) );
2
> 
3
> else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
4
> 
5
> 
6
> if (value>400 & value<800)  PORTB |= ( (1<<PB0) | (1<<PB1)  );
7
> 
8
> else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
9
> 
10
> 
11
> if (value>800 & value<1000)  PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2)
12
> );
13
> 
14
> else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
15
> 
16
> 
17
> if (value>1000)  PORTB |= ( (1<<PB0) | (1<<PB1)  | (1<<PB3) | (1<<PB4)
18
> );
19
> 
20
> else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
21
>

Das würde ganauso flimmern.
Ein Wert von 900 für value würde hier
1
  if (value>400 & value<800)  PORTB |= ( (1<<PB0) | (1<<PB1)  );
2
  else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );

dafür sorgen, dass erst mal alle LED ausgeschaltet werden, denn
900 ist ja nicht größer als 400 und kleiner als 800. Also wird
hier der else genommen und der schaltet alles aus.

Nur damit kurz darauf
1
  if (value>800 & value<1000)  PORTB |= ( (1<<PB0) | (1<<PB1) | (1<<PB2) );
2
  else PORTB &= ~( (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) );
hier die LEDs wieder eingeschaltet werden.

Die Leds werden also ständig ein / aus geschaltet, was natürlich
dunkler erscheint als wie wenn die LED ständig durchleuchtet.

Siehe den Beitrag weiter oben von mir, wie man sowas richtig
macht. Der Schlüssel liegt darin, dass man ab einem bestimmten
Wert immer nur eine einzige Led zu oder abschaltet. 900 ist
größer als 400, also ist die PB1 einzuschalten. 900 ist aber auch
größer als 800, also ist auch die PB2 noch dazuzuschalten. Aber
900 ist nicht größer als 1000, also ist die PB3 abzuschalten.
Daraus ergibt sich ganz von alleine, dass bei einem Wert von 900
die PB1 und die PB2 zu leuchten haben aber nicht PB3.

Code von hier:
Beitrag "Re: Analogsignal auf AVR"
#849770
Lesenswert?

Mr K. wrote:
> warum werde ich zitiert?

Oh Verzeihung.
Ich dachte, das wäre eine Antwort auf seine Frage warum einige
Led dunkler leuchten als andere.

Um ehrlich zu sein, hab ich mir den Code nicht näher angesehen
(weder sein Original, noch deine Modifikation). In dem Moment
in dem da auf einen Bereich abgefragt wurde, war schon alles
klar, dass es hier irgendwelche Probleme geben würde.

> ich hätte die if-abfrage auch anders gestaltet.
Wahrscheinlich nicht nur du und ich :-)
Gast #849790
Lesenswert?

Fox wrote:
> Kann ich auch ein Analoges Signal ausgeben?
dazu brauchst du einen DAC.

> Wenn ich den ATTiny z.B. mit 3V betreibe, kann ich eine Spannung
> anhängen an ADC, welche 5V hat?
nein, spannungsteilen. deine zu messende spannung darf die 
referenzspannung nicht übersteigen.
#849792
Lesenswert?

>> Kann ich auch ein Analoges Signal ausgeben?
>dazu brauchst du einen DAC.

Im einfachsten Fall sowas hier:
http://de.wikipedia.org/wiki/R2R

>> Wenn ich den ATTiny z.B. mit 3V betreibe, kann ich eine Spannung
>> anhängen an ADC, welche 5V hat?
>nein, spannungsteilen. deine zu messende spannung darf die
>referenzspannung nicht übersteigen.

Ich glaube, die darf überschritten werden aber nicht >Vcc... steht aber 
irgendwo im Forum ausgiebig diskutiert und zur Not wie immer im 
Datenblatt.
Gast #849796
Lesenswert?

Kai Giebeler wrote:
>>nein, spannungsteilen. deine zu messende spannung darf die
>>referenzspannung nicht übersteigen.
>
> Ich glaube, die darf überschritten werden aber nicht >Vcc... steht aber
> irgendwo im Forum ausgiebig diskutiert und zur Not wie immer im
> Datenblatt.
man kann die versorgungsspannung als referenzspannung wählen - daher, 
ja. wie weit man über die versorgungsspannung hinaus anlegen darf, steht 
wohl im datenblatt irgendwo bei den dc-characteristics.
Gast #850187
Lesenswert?

Ist jetzt zwar schon hunderte von Beiträgen her, trotzdem noch eine
kleine Anmerkung:

Karl heinz Buchegger schrieb:

>>     value = ADC;
>
> Man mag mich steinigen, aber:
> Müsste das nicht
>
>     value = ADCW;
>
> heissen.

Der offizielle Name des Doppelregisters laut Datenblatt ist ADC. Wie
von Karl heinz bereits erwähnt, führt dies in Assemblerprogrammen
(aber nur diesen) zum Konflikt mit dem gleichlautenden
Prozessorbefehl, weswegen der ADCW als Workaround eingeführt wurde.

Die Headerfiles in der AVR-Libc sind so gestrickt, dass für
Assemblerprogramme nur ADCW, für C-Programme sowohl ADC als auch ADCW
als Synonyme definiert werden. In C-Programmen würde ich die
offizielle Variante ADC vorziehen. Dies vermeidet nebenbei auch Fragen
der Art

  "Wo kann ich die ganzen Registerdefinitionen nachlesen die nicht im
  DB stehen. z.B. das ADCH und ADCL = ADCW ist."

wie vor kurzem hier im Forum gestellt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren