Forum: Compiler & IDEs ADC Code (Hilfe)


von Kevin H. (raeak)


Lesenswert?

Hallo Leute,

ich habe eine Platine mit einem ATMEGA329V.
Ich bin gerade dabei ein ADC zu Programmieren bin aber auf ein Problem 
gestoßen, wo ich einfach nicht weiter kommen. Vielleicht könnt ihr mir 
ja helfen?!


#include <avr/io.h>

#define F_CPU 4915200        // Quarzfrequenz



void ADC_Init(void)
{
  uint16_t ergebnis;

ADMUX  = 0b01100000;      // Externe Spannung (AREF) AVCC
ADCSRA |= ( 1<<ADPS2 ) | ( 0<<ADPS1 ) | ( 1<<ADPS0 ); // Division Factor 
ADCSRA |= ( 1<<ADEN );              // ADC Enable



ADCSRA |= ( 1<<ADSC );        // ADC Start Conversion
  while (ADCSRA & (1<<ADSC))
  {
  }
  ergebnis = ADCW;

}


void main(void)
{
  ADC_Init();
  DDRC = 0xFF;

  while( 1 )
   {
    ADCSRA |= ( 1<<ADSC );

    if( ADC > 1023 )
    {
      PORTD = ( 1<<PD1 );
    }

    else
    {
      PORTD = ( 1<<PD0 );
    }

  }
}



So hier ist das Programm was ich geschrieben habe.

Problem:

ADCSRA |= ( 1<<ADSC );        // ADC Start Conversion
  while (ADCSRA & (1<<ADSC))
  {
  }
  ergebnis = ADCW;


Dies soll ja ein "Warmlauf" sein, habe ich heute erst bei der Tutorial 
gelesen. Den Grund habe ich verstanden wieso man diesen Warmlauf macht, 
aber wenn ich diesen Code anwende springt er beim debuggen nicht mehr 
aus der while Schleife raus bzw. übergibt keinen Wert.


Der Untere Teil, die main bin ich mir auch nicht ganz sicher ob dies so 
funktioniert. Komme ja mit dem debuggen nicht weiter.

void main(void)
{
  ADC_Init();
  DDRC = 0xFF;

  while( 1 )
   {
    ADCSRA |= ( 1<<ADSC );

    if( ADC > 1023 )
    {
      PORTD = ( 1<<PD1 );
    }

    else
    {
      PORTD = ( 1<<PD0 );
    }
  }
}


Zu guter letzt habe ich noch die Frage zum Free Running mode / Single 
Conversion mode.
Im Datenblatt ist es für mich nicht ersichtlich wie ich diese auswähle. 
Also entweder oder.


Grüße

von Karl H. (kbuchegg)


Lesenswert?

Kevin Honey schrieb:


> Dies soll ja ein "Warmlauf" sein, habe ich heute erst bei der Tutorial
> gelesen. Den Grund habe ich verstanden wieso man diesen Warmlauf macht,
> aber wenn ich diesen Code anwende springt er beim debuggen nicht mehr
> aus der while Schleife raus bzw. übergibt keinen Wert.


Moment.
Debuggen

Womit debuggst du?
Der im AVR-Studio eingebaute Debugger simuliert nicht alle Aspekte des 
realen IC. Wenn du im Simulator da raus kommen willst, kannst du immer 
noch händisch mit einem Mausklick das entsprechende Bit löschen.


>     ADCSRA |= ( 1<<ADSC );
>
>     if( ADC > 1023 )

das muss aber wieder genau gleich funktionieren.
Du setzt das ADSC Bits, der ADC beginnt zu arbeiten.
Wenn der ADC fertig ist, löscht er das Bit wieder und erst dann kannst 
du dir das Wandlungsergebnis abholen.

> Zu guter letzt habe ich noch die Frage zum Free Running mode / Single
> Conversion mode.
> Im Datenblatt ist es für mich nicht ersichtlich wie ich diese auswähle.
> Also entweder oder.

Ganz ehrlich.
Sieh erst mal zu, dass du den Single Shot in Betrieb kriegst. Für 90% 
aller Fälle langt der dicke.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

>> Zu guter letzt habe ich noch die Frage zum Free Running mode / Single
>> Conversion mode.
>> Im Datenblatt ist es für mich nicht ersichtlich wie ich diese auswähle.
>> Also entweder oder.
>
> Ganz ehrlich.
> Sieh erst mal zu, dass du den Single Shot in Betrieb kriegst. Für 90%
> aller Fälle langt der dicke.

Hab mich mal im Datenblatt schlau gemacht.
Den klassischen Free-Running Modus gibt es so direkt nicht mehr. Der 
wurde durch etwas universelleres ersetzt. Das nennt sich bei diesem µC 
"Auto Trigger" und eine Variante davon ist der Free-Running Mode, bei 
dem sich der ADC selber den Auto-Trigger verpasst, sobald er erst mal 
läuft (die erste Wandlung muss man 'per Hand' starten)

von Kevin H. (raeak)


Angehängte Dateien:

Lesenswert?

Vielen Dank für deine schnelle Antwort!


Karl Heinz Buchegger schrieb:
> das muss aber wieder genau gleich funktionieren.
> Du setzt das ADSC Bits, der ADC beginnt zu arbeiten.
> Wenn der ADC fertig ist, löscht er das Bit wieder und erst dann kannst
> du dir das Wandlungsergebnis abholen.

Korrigier mich wenn ich falsch liege.

Das Wandlungsergebnis ist im ADCL and ADCH – The ADC Data Register 
geschrieben wenn ich das richtig gelesen habe.

Das warten bis der ADC die Coversion fertig hat mache ich mit
(ADCSRA & (1<<ADSC));   richtig?

Muss der Code dann wie folgt aussehen?

void main(void)
{
  ADC_Init();
  DDRD = 0xFF;

  while( 1 )
   {
    ADCSRA |= ( 1<<ADSC );
    (ADCSRA & (1<<ADSC));

    if( ADC > 1023 )
    {
      PORTD = ( 1<<PD1 );
    }

    else
    {
      PORTD = ( 1<<PD0 );
    }

  }
}



Mir ist gerade aufgefallen dass ich nicht direkt gesagt habe was ich 
eigentlich vor habe.
Ich will durch ein Poti das an ADC0 angeschlossen ist über den Schleifer 
den Analogen Wert auslesen und Digitaltalisieren. Das wiederum visuell 
ausgeben.

von Kevin H. (raeak)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Hab mich mal im Datenblatt schlau gemacht.
> Den klassischen Free-Running Modus gibt es so direkt nicht mehr. Der
> wurde durch etwas universelleres ersetzt. Das nennt sich bei diesem µC
> "Auto Trigger" und eine Variante davon ist der Free-Running Mode, bei
> dem sich der ADC selber den Auto-Trigger verpasst, sobald er erst mal
> läuft (die erste Wandlung muss man 'per Hand' starten)



Ah okay alles klar, ich bin da nicht so ganz durch gestiegen.
Ich habe gesehen dass ich den Free Runing Mode im ADCSRB – ADC Control 
and Status Register B einstellen kann unter ADC Auto Trigger Source 
Selections.
Bin nur irretiert gewesen weil unter ADSC: ADC Start Conversion stand:

In Single Conversion mode, write this bit to one to start each 
conversion.

Ich dachte ich muss ein Bit setzen um auszuwählen ob ich Free runing 
Mode oder Single Conversion haben will.

Aber dann ist standartmäßig einfach Single Conversion.

Vielen Dank :)

von Karl H. (kbuchegg)


Lesenswert?

Kevin Honey schrieb:

> Korrigier mich wenn ich falsch liege.
>
> Das Wandlungsergebnis ist im ADCL and ADCH

richtig.

> – The ADC Data Register
> geschrieben wenn ich das richtig gelesen habe.

Das ist ein Service, den dir der C-Compiler anbietet.
Du schreibst

   i = ADC;
(bzw. i = ADCW;)

und der COmpiler kümmert sich darum, dass ADCH und ADCL in der richtigen 
Reihenfolge ausgelesen werden und die beiden Bytes zu einem 16 Bit Wert 
zusammengesetzt werden.


> Das warten bis der ADC die Coversion fertig hat mache ich mit
> (ADCSRA & (1<<ADSC));   richtig?

genau so wie du es in der Init Funktion auch gemacht hast.

> Muss der Code dann wie folgt aussehen?
>
> void main(void)
> {
>   ADC_Init();
>   DDRD = 0xFF;
>
>   while( 1 )
>    {
>     ADCSRA |= ( 1<<ADSC );
>     (ADCSRA & (1<<ADSC));

nö

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

'Auf etwas warten' impliziert, dass es da irgendeine Form von Schleife 
geben muss, in der regelmässig überprüft wird, ob das Ereignis schon 
eingetreten ist.

Ich dachte, du hättest das Tutorial bzw. den Tutorialscode studiert?


> Mir ist gerade aufgefallen dass ich nicht direkt gesagt habe was ich
> eigentlich vor habe.
> Ich will durch ein Poti das an ADC0 angeschlossen ist über den Schleifer
> den Analogen Wert auslesen und Digitaltalisieren. Das wiederum visuell
> ausgeben.

Schon ok.
Single Shot ist da schnell genug. So schnell kannst du nicht am Poti 
drehen, dass du den µC da in Verlegenheit bringen könntest.


Und: Funktionen machen!
Genauso wie es eine Init Funktion gibt, solltest du dir eine 
Auslese-Funktion machen. Siehe zb den Tutoriumscode.

von Kevin H. (raeak)


Lesenswert?

Also habe jetzt noch einmal mein Hirn angestrengt...


#include <avr/io.h>

#define F_CPU 4915200                              // Quarzfrequenz

void ADCInit();
void init();
void Ausgabe();


void main(void)
{

  ADCInit();
  init();
  Ausgabe();


  while (1)
   {
     ADCSRA |= ( 1<<ADSC );
     while (ADCSRA & (1<<ADSC))
     {
      PORTC = 0xFF;

      if( Ausgabe > 5*1023/5 )
      {
        PORTD = ( 1<<PD1 );
      }

      else
      {
        PORTD = ( 1<<PD0 );
      }
     }
  }
}

void ADCInit()
{
  uint16_t ergebnis;

  ADMUX  = 0b01000000;                // Externe Spannung (AREF) AVCC
  ADCSRA |= ( 1<<ADPS2 ) | ( 0<<ADPS1 ) | ( 1<<ADPS0 );//Division Factor 
32
  ADCSRA |= ( 1<<ADEN );                            // ADC Enable


  ADCSRA |= ( 1<<ADSC );                            // ADC Start 
Conversion
  while (ADCSRA & (1<<ADSC))
  {
  }
  ergebnis = ADCW;

}


void init()
{
  DDRD = 0xFF;
  DDRC = 0xFF;
}

void Ausgabe()
{
  int Ausgabe;
  Ausgabe = ADCW;
}


An PD0 wird mir jetzt eine Spannung ausgegeben. Habe aber ein Fehler am 
Board festgestellt, habe eine Unterbrechung vom Schleifer zum ADC0, 
somit können keine 0..5V am ADC0 anliegen.
Werde es morgen auf Arbeit ausbessern und dann berichten.

Vielen Dank dir!

von Walter S. (avatar)


Lesenswert?

sorry, aber das Programm ist kompletter Käse und wird sich nicht Mal 
übersetzen lassen.
Geh es im Kopf Schritt für Schritt durch und überleg dir was passiert.
oder nimm einfach den Code aus dem Tutorial.

von Karl H. (kbuchegg)


Lesenswert?

Walter S. schrieb:
> sorry, aber das Programm ist kompletter Käse

Dem stimme ich zu.

> und wird sich nicht Mal
> übersetzen lassen.

Doch. Übersetzen lässt es sich. Ich denke allerdings nicht, dass der TO 
auch nur den Hauch eines Schimmer hat, was er da aus Sicht seines 
Compilers geschrieben hat.

Das hier

      if( Ausgabe > 5*1023/5 )

so seltsam es auch aussieht, wird zu einer Warnung führen. Aber es ist 
erst mal kein Syntax Error. Es macht zwar nicht das, was er sich 
vorgestellt hat, noch nicht mal annähernd, aber es ist compilierbar. 
Denn: Auch Funktionen haben Adressen. Und die kann man vergleichen.

> Geh es im Kopf Schritt für Schritt durch und überleg dir was passiert.
> oder nimm einfach den Code aus dem Tutorial.

Wo denkst du hin?
Das wär doch viel zu einfach. Und wenn man dann auch noch C erst mal 
zumindest ein wenig gelernt hätte, dann könnte man die 
himmelschreiendsten Fehler sogar selber sehen.

Sowas:
1
void Ausgabe()
2
{
3
  int Ausgabe;
4
  Ausgabe = ADCW;
5
}
ist natürlich ein Kleinod im kabarettistischen Himmel des Unsinns.

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.