Forum: Mikrocontroller und Digitale Elektronik Analog eingang bsp.


von Knoddelpusch (Gast)


Lesenswert?

Hallo,

ich bin am verzweifeln, probiere nun schon Wochen einen Atmege8 
Analogeingang zu Programmieren aber er will nicht so richtig.
Wenn ich ganz ehrlich bin es tut sich eigentlich gar nichts.

Hier mein C-Code

#define F_CPU 1e8

#include <util/delay.h>  // Include Datei für die Verzögerungsfunktion
#include <avr/io.h>


int main (void)

{
  int sample,value;   // Varieblen defination

 DDRB = 0xFF;        // PORTB als Ausgabeport

 ADMUX = (0<<REFS1 |(0<<REFS0)); // Exterme Referenzspannung
 ADMUX = (0<<MUX0 | (0<<MUX1 | (0<<MUX2 |(0<<MUX3))));  //Kanal0,Pin PC0


  while (1)
  {
    sample=0;      // setzt den Sampelwert auf 0

    ADCSRA |= (1<<ADSC);   // ADC einschalten
    value = ADCW;

    if (value<0)
    PORTB=0x04;
  }
}

Hoffe es kann mir einer weiter Helfen

Schon mal Danke im vorraus.

: Verschoben durch User
von Timmo H. (masterfx)


Lesenswert?


von Knoddelpusch (Gast)


Lesenswert?

Hallo,

habe das jetzt schon ein paar mal durchgelesen ausprobiert und komme 
trotzdem nicht weiter.

Ich weiß einfach nicht weiter.

Wäre nett wenn mir noch einer ein paar Tipps oder Programm 
Verbesserungen sagen bzw. was falsch ist.

von Paul B. (paul_baumann)


Lesenswert?

Den ADC aktivieren kann man mit ADEN =1. Ich weiß aber nicht, wie das in
"C" formuliert werden muss.

Das sehe ich nicht im Programm. Eventuell liegt es daran.

MfG Paul

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

> #define F_CPU 1e8

Du lässt den Mega8 mit 100 Mhz laufen?

>   while (1)
>   {
>     sample=0;      // setzt den Sampelwert auf 0

Wozu benötigst du die Variable "sample"? Ich vermute, dass du hier nicht 
den kompletten Code geposted hast.

>     ADCSRA |= (1<<ADSC);   // ADC einschalten

Vielleicht solltest du den ADC auch enablen (ADEN).

>     value = ADCW;

Bevor du versuchst das Wandlungsergebnis auszulesen musst du erst einmal 
das Ende der Wandlung abwarten.

>     if (value<0)

Die Variable "value" ist ein Integer (ohne Vorzeichen). Diese Variable 
kann also niemals kleiner 0 sein.

>     PORTB=0x04;

Somit wird diese Anweisung auch nie ausgeführt werden.

von Timmo H. (masterfx)


Lesenswert?

Knoddelpusch schrieb:
> Hallo,
>
> habe das jetzt schon ein paar mal durchgelesen ausprobiert und komme
> trotzdem nicht weiter.

Hast du offensichtlich nicht. Denn im Beispiel-Code, den du quasi 1:1 
hättest übernehmen können, steht doch:
1
ADCSRA |= (1<<ADEN);   // ADC aktivieren
2
... 
3
ADCSRA |= (1<<ADSC);   // eine ADC-Wandlung
das hätte dich zumindest mal kurz zum nachdenken bringen müssen. Denn 
ADEN hast du gar nicht verwendet und hinter "ADCSRA |= (1<<ADSC);" steht 
irgendwie ein Kommentar das bei dir anders aussieht. Und im Datenblatt 
hättest du auch gesehen, dass das so nicht ganz richtig sein kann.

von Knoddelpusch (Gast)


Lesenswert?

Hallo,

Sind 100 Mhz zu viel?
Habe jetzt alles noch mal nach geschaut und habe diverse abänderungen 
gemacht.
Ich habe hier jetzt noch ein mal das überarbeitete Programm.

#define F_CPU 1e8

#include <util/delay.h>  // Include Datei für die Verzögerungsfunktion
#include <avr/io.h>


int main (void)

{
  int value;    // Varieblen defination

 DDRB = 0xFF;      // PORTB als Ausgabeport

 ADMUX = (0<<REFS1 |(0<<REFS0)); // Exterme Referenzspannung
 ADMUX = (0<<MUX0 | (0<<MUX1 | (0<<MUX2 |(0<<MUX3))));  // Kanal 0, Pin 
PC0


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

    while (ADCSRA & (1<<ADSC) ) {}
              // auf Abschluss der Konvertierung warten
    value = ADCW;

    if (value>0)
    PORTB=0x04;
  }
}

Bekomme es aber immer noch nicht zu laufen.
Den Frequenzvorteiler brauch man ja bei dem Programm nicht oder?

Möchte eine Eingangsspannung von 2,5 V abfragen bzw. wenn eine Spannung 
am Eingang liegt soll eine Lampe angehen.

von Floh (Gast)


Lesenswert?

Knoddelpusch schrieb:
> #define F_CPU 1e8
Bitte tu dir den Gefallen und arbeite erstmal da Tuttorial durch.
Und solange du nicht sattelfest in der Materie bist, würde ich dir 
raten, die Beispiele 1 zu 1 aus dem Tutorial kopieren und testen, BEVOR 
du sie veränderst.

von Liberty Limerix (Gast)


Lesenswert?

Was denkst du bewirkt eine Anweisung wie (0<<soundsoviel)?

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Knoddelpusch schrieb:
> Sind 100 Mhz zu viel?

Dein ATmega8 wird bestimmt nicht mit 100 MHz laufen.

> #define F_CPU 1e8

Warum immer noch?

> #include <util/delay.h>  // Include Datei für die Verzögerungsfunktion

Wozu bindest du krampfhaft die Delay-Lib ein, wenn du sie nicht benutzt?

>   while (1)
>   {
>     ADCSRA = ADEN;             // ADC einschalten

Das "ADCSRA = ADEN;" setzt du noch VOR den Endlos Loop.

>     if (value>0)
>     PORTB=0x04;

> Möchte eine Eingangsspannung von 2,5 V abfragen bzw. wenn eine Spannung
> am Eingang liegt soll eine Lampe angehen.

Das Wandlungsergebnis auf >0 zu prüfen ist dann ziemlicher Quatsch. Wie 
groß ist die von dir extern zur Verfügung gestellte Referenzspannung?

> Bekomme es aber immer noch nicht zu laufen.

Wundert mich nicht.

> Den Frequenzvorteiler brauch man ja bei dem Programm nicht oder?

Der ADC-Takt sollte für die volle 10 Bit Auflösung <= 200 kHz sein. Wenn 
du den Prescaler mit "0" fütterst, teilt dieser durch 2. Das bedeutet, 
dass dein Prozessortakt nicht größer als 400 kHz sein darf.

--> Mit welchem Takt versorgst du den Controller?

von Floh (Gast)


Lesenswert?

> Das "ADCSRA = ADEN;" setzt du noch VOR den Endlos Loop.

Die Position wäre ja egal, er kann den ADC ja beliebig of einschalten. 
Allerdings funktioniert das so nicht, da es
ADCSRA = (1<<ADEN);
sein sollte, da ADEN nur die Bitnummer ist.

Den ADC kann man auch übertakten, wenn man möchte, die Genauigkeit geht 
halt flöten.

Allerdings verstehe ich den TO nicht. Er könnte einfach mal das Beispiel 
aus dem Tutorial kopieren und ausprobieren. Danach kann er es ja von mir 
aus ändern und zwischendurch austesten, ob es noch läuft.
Allgemein denke ich aber, dass da massiv Grundlagen in Form der 
vorhergegangenen Tutorialkapiteln fehlt.
:-)

von Michael H. (michael_h45)


Lesenswert?

Timmo H. schrieb:
> 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe

Knoddelpusch schrieb:
> habe das jetzt schon ein paar mal durchgelesen ausprobiert und komme
> trotzdem nicht weiter.

das is halt schlichtweg gelogen...


> Wäre nett wenn mir noch einer ein paar Tipps oder Programm
> Verbesserungen sagen bzw. was falsch ist.
deine vorgehensweise.
LIES das tutorial und zwar von anfang an!

von Steven S. (virus)


Lesenswert?

Hallo,

auch ich habe ein Problem mit dem Programm...

Unter dem AVR Studio 4 bricht er mit dem fehler ab, dass adcw nicht 
definiert ist... im avr studio 6 kommt folgende fehlermeldung:

------ Build started: Project: Batterieprüfer, Configuration: Debug AVR 
------
Build started.
Project "Batterieprüfer.cproj" (default targets):
Target "PreBuildEvent" skipped, due to false condition; 
('$(PreBuildEvent)'!='') was evaluated as (''!='').
Target "CoreBuild" in file "D:\Programme\Atmel\Atmel Studio 
6.0\Vs\Compiler.targets" from project 
"C:\Users\Steven\Desktop\Batterieprüfer\Batterieprüfer\Batterieprüfer.cp 
roj"  (target "Build" depends on it):
  Using "RunCompilerTask" task from assembly "D:\Programme\Atmel\Atmel 
Studio 6.0\Vs\Compiler.Task.dll".
  Task "RunCompilerTask"
    D:\Programme\Atmel\Atmel Studio 6.0\make\make.exe all
    make: *** No rule to make target `Batteriepr├╝fer.o', needed by 
`Batteriepr├╝fer.elf'.  Stop.
  Done executing task "RunCompilerTask" -- FAILED.
Done building target "CoreBuild" in project "Batterieprüfer.cproj" -- 
FAILED.
Done building project "Batterieprüfer.cproj" -- FAILED.

Build FAILED.
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped 
==========

Ideen?

von Michael H. (michael_h45)


Lesenswert?

Steven S. schrieb:
> No rule to make target `Batteriepr├╝fer.o'

...

von Steven S. (virus)


Lesenswert?

ja, und auf deutsch?

von Stefan (Gast)


Lesenswert?

Vermeide bei

- Dateinamen
- Verzeichnisse
- Make Targets
- Variablen
- Funktionen
- Definitionen

Leerzeichen, Sonderzeichen und alle Zeichen, die nicht im 7Bit US-ASCII 
Zeichensatz enthalten sind.

Also beschränke Dich auf 0-9, A_Z, a-z und _.

von Bernhard S. (b_spitzer)


Lesenswert?

Eben nicht auf Deutsch. Also KEINE Umlaute in Datei- oder 
Verzeichnisnamen!

von Bernhard S. (b_spitzer)


Lesenswert?

Das gilt übrigens auch für den Windows-Benutzernamen, wenn man unbedingt 
auf dem Dektop arbeiten muss...

von Steven S. (virus)


Lesenswert?

Hallo,

habe das jetzt soweit umgebastelt... aber irgendwie gibt er mir als 
ergebnis immer 0 aus... Habe ein Stk 500 und einen AtMega16
1
#include <avr/io.h>
2
#include <inttypes.h>
3
4
5
6
void ADC_Init(void) {
7
 
8
  uint16_t result;
9
 
10
  // interne Referenzspannung als Refernz für den ADC wählen:
11
  ADMUX = (1<<REFS1) | (1<<REFS0);
12
  
13
  // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
14
  // schon auf 0, also single conversion
15
  ADCSRA = (1<<ADPS1) | (1<<ADPS0);     // Frequenzvorteiler
16
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
17
 
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
 
21
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
22
  while (ADCSRA & (1<<ADSC) ) {         // auf Abschluss der Konvertierung warten
23
  }
24
  /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
25
     Wandlung nicht übernommen. */
26
  result = ADCW;
27
}
28
 
29
/* ADC Einzelmessung */
30
unsigned int ADC_Read( unsigned char channel )
31
{
32
33
  // Kanal waehlen, ohne andere Bits zu beeinflußen
34
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
35
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
36
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung warten
37
  }
38
  return ADCW;                    // ADC auslesen und zurückgeben
39
}
40
41
/* Beispielaufrufe: */
42
 
43
int main()
44
{
45
  DDRB = 255;
46
  PORTB = 0;
47
  PORTB = ~PORTB;
48
49
  unsigned int Ergebnis;
50
  ADC_Init();
51
 
52
  while( 1 ) {
53
    
54
  Ergebnis = ADC_Read(0);  // Kanal 0
55
    // mach was mit adcval
56
57
         if (Ergebnis<100)
58
         {
59
           PORTB|=(0<<PB0);
60
         }    
61
  }
62
}

von EGS_TI (Gast)


Lesenswert?

Wie wärs mit einem Arduino???

von Steven S. (virus)


Lesenswert?

EGS_TI schrieb:
> Wie wärs mit einem Arduino???

Wieso?

von Michael H. (michael_h45)


Lesenswert?

Steven S. schrieb:
> ja, und auf deutsch?
das bisschen nachdenken war wohl zu anstrengen.
keine minute nach dem hinweis schon die frage - gratuliere.

wie naiv zu erwarten, du würdest zu
Steven S. schrieb:
> habe das jetzt soweit umgebastelt... aber irgendwie gibt er mir als
> ergebnis immer 0 aus... Habe ein Stk 500 und einen AtMega16
noch eine fehlermeldung posten. nein, die müssen wir schon erraten...

http://www.zeit.de/wissen/2009-9/vorurteile-namen-grundschullehrer
du darfst dich hier gleich einreihen...

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Steven S. schrieb:
> habe das jetzt soweit umgebastelt... aber irgendwie gibt er mir als
> ergebnis immer 0 aus... Habe ein Stk 500 und einen AtMega16

Ich habe mir der Einfachheit halber jetzt nur mal deine main() 
angesehen.

Deine Abfrage

>          if (Ergebnis<100)
>          {
>            PORTB|=(0<<PB0);
>          }

setzt dir den Portpin auf 1 sobald auch nur ein einziges 
Wandlungsergebnis kleiner als 100 ist. Der Portpin wird jedoch niemals 
wieder auf 0 gesetzt wenn die Wandlung ein Ergebnis >= 100 liefert!

Versuche es mal mit

if (Ergebnis<100)
{
  PORTB|=(0<<PB0);
}
else
{
  PORTB&= ~(0<<PB0);
}

von Karl H. (kbuchegg)


Lesenswert?

Magnus M. schrieb:

> Deine Abfrage
>
>>          if (Ergebnis<100)
>>          {
>>            PORTB|=(0<<PB0);
>>          }
>
> setzt dir den Portpin auf 1

Nope.

Das setzt überhaupt nichts auf 1.

An den Port kann er 0 zuweisen bis er schwarz wird. Der Pin wird niemals 
1 (bzw. 0, was wohl die eigentliche Absicht gewesen sein dürfte). Egal 
was vom ADC kommt.

@Frager
Womit wir wieder beim Punkt angelangt wären:

Lies das Tutorial von Anfang an!
Es ist sinnlos, sich mit komplizierteren Projekten zu befassen, solange 
du nicht die allerersten, einfachsten Grundlagen sicher im Griff hast. 
Einen Pin gezielt auf 0 oder 1 zu setzen ist etwas, das DARF dir keine 
Probleme mehr verursachen!

Bitmanipulation

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Magnus M. schrieb:
>
>> Deine Abfrage
>>
>>>          if (Ergebnis<100)
>>>          {
>>>            PORTB|=(0<<PB0);
>>>          }
>>
>> setzt dir den Portpin auf 1
>
> Nope.
>
> Das setzt überhaupt nichts auf 1.

Oh shit.... ich hatte doch glatt die "0<<" übersehen... Wie auch immer: 
selbst wenn dort "1<<" gestanden hätte, wäre es murks gewesen.

von Steven S. (virus)


Lesenswert?

So, Problemchen hat sich erledigt... Habe das wie folgt gemacht. Und so 
läuft das Programm ohne probleme ;-)


#include <avr/io.h>


    int main()
    {

      DDRB = 255;                    //make portB all output
    PORTD = 0;
    PORTD = ~PORTD;
      ADMUX=(1<<REFS0)|(1<<ADLAR); //Make AVcc the reference, make the


      //bit value left aligned and select

      //ADC0 channel.

      ADCSRA=(1<<ADEN)|(1<<ADCSRA)|(1<<ADPS2); //Enable Analog 
convertor,

      //set prescaler to 16

      //and free running mode

      while(1)

      {
      uint16_t Wert;
      uint8_t Ausg;

        ADCSRA|=(1<<ADSC); //start conversion

      Wert = ADCW;

    Ausg = 0;
    if (Wert>15000)
    {
      Ausg |= (1 << 0);
    }

    if (Wert>15500)
    {
      Ausg |= (1 << 1);
    }

    if (Wert>16000)
    {
      Ausg |= (1 << 2);
    }

    if (Wert>16500)
    {
      Ausg |= (1 << 3);
    }

    if (Wert>17000)
    {
      Ausg |= (1 << 4);
    }

    if (Wert>18000)
    {
      Ausg |= (1 << 5);
    }

    if (Wert>19000)
    {
      Ausg |= (1 << 6);
    }

    if (Wert>20000)
    {
      Ausg |= (1 << 7);
    }

    PORTB = ~Ausg;

      }


      return 1;

    }

von Karl H. (kbuchegg)


Lesenswert?

Das ist Murks
1
       ADCSRA|=(1<<ADSC); //start conversion
2
3
      Wert = ADCW;

wenn du eine Wandlung startest, musst du schon auch abwarten bis die 
Wandlung fertig ist.

Gut, bei dir spielt das jetzt keine große Rolle, weil dann eben das 
Ergebnis der aktuell gestarteten Wandlung im nächsten Durchlauf zur 
Verfügung steht (und dann die nächste Wandlung schon wieder läuft). Aber 
spätestens dann, wenn du mehrere Wandlungen auf bunt gemixten 
ADC-Eingängen brauchst, gibt das Ergebnis-Salat.

Wenn schon dann machs lieber so rum ...
1
      Wert = ADCW;       // Ergebnis der letzten Wandlung holen ...
2
      ADCSRA|=(1<<ADSC); // und gleich die nächste Wandlung starten ...
3
                         // dann kann der ADC Wandler arbeiten, während
4
                         // das Ergebnis der letzten Wandlung ausgewertet
5
                         // wird

... denn dann ist auch klar, dass diese Parallelverarbeitung 
beabsichtigt ist.

aber ganz ehrlich: um ein paar LED zu schalten, spielen die paar 
ADC-Takte Verzögerung, die man mit 'Wandlung starten - Ergebnis abwarten 
- Ergebnis holen' hat nicht wirklich die große Rolle.

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.