mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ADC und Atmega8 = Problem?


Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

also es geht um folgendes. Ich habe 2 Spannungen zu messen. Die eine 
steht für eine Leistung (entsprechend vorbereitet) und die andere steht 
für die Richtigkeit der ersten Spannung (wegen der Linearität des IC der 
die erste Spannung erzeugt).

Nun wandle ich die beiden Spannungen und entscheide dann was zu tun ist.

Hier is der Code dazu:
#include <avr/io.h>
#include <stdint.h>
#include <lcd.h>

//Funktionsdeklaration (Prototypen)

//ADC Init.
void vinitADU_8Bit(unsigned short int);

int igetADU_8Bit(unsigned short int);


void main (void)
{//Variablen Definition
  char cPuffer[100];
  int iPuffer=0,iWait=0;

 //Deklaration der PORTS --> "Richtung"
  DDRD = 0xff;    //0xff --> Ausgang
  DDRC = 0x00;    //0x00 --> Eingang
  DDRB = 0xff;
  PORTB = 0xff;


 //Initialisierung des ADCs
  vinitADU_8Bit(0);


    /* Initialisiere Display, Cursor aus*/
    lcd_init(LCD_DISP_ON);
  
  /* loesche das LCD Display und Cursor auf 1 Zeile, 1 Spalte */
    lcd_clrscr();
        
    /* String auf Display anzeigen */
    lcd_puts("Willkommen");
 
   for (iWait;iWait<30000;iWait++);
    iWait=0;

   while(1) 
   {
    if (igetADU_8Bit(2)<5)
    {
      iPuffer=(4000*igetADU_8Bit(0))/51;
      //Typ konvertierung für "lcd_puts"- Funktion
      itoa(iPuffer,cPuffer, 10);  //(int Variable, char Variable, Basis (binär, dezimal, hex)

      lcd_clrscr();
      lcd_puts(cPuffer);
    }

  else if (igetADU_8Bit(2)>50)
    {  PORTB = 0xff;
      lcd_clrscr();
      lcd_puts("Betrieb");
    }


   }   
}



//Funktionen

void vinitADU_8Bit(unsigned short int usimux)
{//Eigene Funktion zur ADU Initialisierung damit diese nicht ständig ausgeführt werden muss
int iresult;
ADMUX = usimux;     // Kanal waehlen
ADMUX |= 0x60;     // AVCC als Referenzspannung nutzen und Ergebnis soll linksbündig sein (nur ADCH)
ADCSRA |= 0x85;   // Frequenzvorteiler
          // setzen auf 8 (1) und ADC aktivieren (1)
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen" zu lassen*/

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

  while(ADCSRA&(1<<ADSC)) 
    {
     // auf Abschluss der Konvertierung warten
    }
iresult = ADCH;  // ADCH muss einmal gelesen werden,
        // sonst wird Ergebnis der nächsten Wandlung
        // nicht übernommen.
ADCSRA &= ~(1<<ADEN); // ADC deaktivieren

PORTB=0x00;

iresult = 0;
}


int igetADU_8Bit(unsigned short int usimux)
{  int iresult;
  ADMUX = usimux;     // Kanal waehlen
  ADCSRA |= 0x80;     //ADC aktivieren (1)


  ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) 
      {
      // auf Abschluss der Konvertierung warten
      iresult = ADCH; // Wandlungsergebnisse abholen
      }

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

  return iresult;
}

Was übersehe ich? Das Problem ist nämlich das ich nie in den zweiten 
Zweig komme :(.

MFG

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int igetADU_8Bit(unsigned short int usimux)
{  int iresult;
  ADMUX = usimux;     // Kanal waehlen


Tja. Damit ist dann die Einstellung der Referenzspannung hinfällig 
geworden.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
  ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) 
      {
      // auf Abschluss der Konvertierung warten
      iresult = ADCH; // Wandlungsergebnisse abholen
      }

Ähm. Welche Vorstellung hast du vom Begriff 'Warten'? Was wird man 
sinnvollerweise tun, während man wartet? Den ADC auslesen? Eher nicht. 
Denn ADC wird man auslesen, nachdem das Warten vorbei ist. Denn das war 
ja der Sinn des Wartens: den ADC in Ruhe seine Arbeit machen lassen. Ist 
er fertig, meldet er sich. Die Warterei hat ein Ende und man kann sich 
den Wert holen.

Weiter gehts
  ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)


Aha. Wer schaltet eigentlich im nächsten Schleifendurchlauf, beim 
nächsten Aufruf der get Funktion, den ADC wieder ein?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
   while(1) 
   {
    if (igetADU_8Bit(2)<5)
    {
      iPuffer=(4000*igetADU_8Bit(0))/51;
      //Typ konvertierung für "lcd_puts"- Funktion
      itoa(iPuffer,cPuffer, 10);  //(int Variable, char Variable, Basis (binär, dezimal, hex)

      lcd_clrscr();
      lcd_puts(cPuffer);
    }

  else if (igetADU_8Bit(2)>50)

bist du sicher, dass du hier in jedem Durchlauf durch die Schleife den 
ADC-Kanal 2 tatsächlich 2 mal neu abfragen willst?
Im schlimmsten (zugegeben konstruierten) Fall liefert der erste Aufruf 
den Wert 51 und der zweite Aufruf den Wert 4. Und trotzdem wird dann 
keiner der Werte korrekt ausgewertet.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JTR schrieb:

> Was übersehe ich? Das Problem ist nämlich das ich nie in den zweiten
> Zweig komme :(.

Noch ein Hinweis:
Du hast ein LCD zur Verfügung.
Niemand hindert dich daran, es in der Entwicklungsphase auch dazu zu 
benutzen, sich Werte anzeigen zu lassen, wie zb die Werte, die der ADC 
liefert (ohne Umrechnung, so wie der ADC den Wert auswirft).
Solche Hilfsausgaben, die natürlich wieder entfernt werden wenn alles 
ferig ist, sind oft sehr hilfreich um zu verstehen, was in einem 
Programm abgeht und um Problemen auf die Spur kommen zu können.

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> int igetADU_8Bit(unsigned short int usimux)
{  int iresult;
   ADMUX = usimux;     // Kanal waehlen
>
>
> Tja. Damit ist dann die Einstellung der Referenzspannung hinfällig
> geworden.

Also was du damit meinst ist mir nicht klar?!


 ADCSRA |= 0x80;     //ADC aktivieren (1)

Damit wird der ADU in jedem Durschlauf wieder aktiviert!


Karl heinz Buchegger schrieb:
> bist du sicher, dass du hier in jedem Durchlauf durch die Schleife den
> ADC-Kanal 2 tatsächlich 2 mal neu abfragen willst?
> Im schlimmsten (zugegeben konstruierten) Fall liefert der erste Aufruf
> den Wert 51 und der zweite Aufruf den Wert 4. Und trotzdem wird dann
> keiner der Werte korrekt ausgewertet.


Naja, die Spannung die gewandelt wird, wird über ein Poti eingestellt 
(zur Zeit noch). Das stell ich ein mal ein und dann greif ich es nicht 
mehr an. Mit Voltmeter gemessen: am Kanal 2 liegen zB 2,5V an
Trotzdem geht er nicht in den 2. Zweig, obwohl 2,5V etwa 127 ergeben 
sollte.

Ich verwende das LCD sehr wohl! :D

So, mal ein riesen Danke an dich Karl Heinz, dass du mir so genau Tipps 
gegeben hast. Ich komme leider erst morgen dazu deine Tipps aus zu 
probieren.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JTR schrieb:
> Karl heinz Buchegger schrieb:
>> int igetADU_8Bit(unsigned short int usimux)
>
{  int iresult;
>    ADMUX = usimux;     // Kanal waehlen
>>
>>
>> Tja. Damit ist dann die Einstellung der Referenzspannung hinfällig
>> geworden.
>
> Also was du damit meinst ist mir nicht klar?!


  i = 5;
  i = 8;

welchen Wert hat i, nachdem diese beiden Anweisungen durchgelaufen sind? 
Überlebt irgendein Bit von i = 5 die Zuweisung von 8? Wohl eher nicht.

Nach
      ADMUX = usimux;     // Kanal waehlen[/c]

sind alle anderen Bits die du vorher so mühsam in der init Funktion in 
ADMUX gesetzt hast, wieder auf 0. Und damit ist die Einstellung für die 
Referenzspannung, die ebenfalls über ADMUX gemacht wird, futsch bzw. 
eine andere als du bei einem Blick auf die init Funktion denkst.

>
 ADCSRA |= 0x80;     //ADC aktivieren (1)
>
> Damit wird der ADU in jedem Durschlauf wieder aktiviert!

mein Fehler.
Hab den Code nur nach ADEN abgesucht und nicht gefunden.
SChreib das doch bitte als

   ADCSRA |= ( 1 << ADEN );

so wie du das beim Ausschalten auch machst. Dann übersieht man das nicht 
so leicht.

> Trotzdem geht er nicht in den 2. Zweig, obwohl 2,5V etwa 127 ergeben
> sollte.

Sollte!
Hast du das kontrolliert?
Wechen Wert liefert der ADC?

> Ich verwende das LCD sehr wohl! :D
Das war auch mehr als Hinweis gedacht, was du tun kannst, wenn du nicht 
verstehst, warum ein if nicht funktioniert oder eine Berechnung nicht ds 
erwartete Ergebnis liefert.
Viele Programmierer haben aus irgendeinem nicht verständlichen Grund 
Angst davor, sich Zwischenergebnisse ausgeben zu lassen. Dabei würde ein 
Blick auf ein paar Variablen sofort Licht ins Dunkel bringen. Aber aus 
irgendeinem Grund schrecken sie davor zurück kurzzeitig ein paar printf 
(bei dir eben Ausgaben aufs LCD) einzubauen, die danach wieder entfernt 
werden. Es scheint fast so, dass sie lieber im Nebel stochern als die 15 
Sekunden Zusatzarbeit zu machen.

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JTR schrieb:
> Karl heinz Buchegger schrieb:
>> int igetADU_8Bit(unsigned short int usimux)
>
{  int iresult;
>    ADMUX = usimux;     // Kanal waehlen
>>
>>
>> Tja. Damit ist dann die Einstellung der Referenzspannung hinfällig
>> geworden.
>
> Also was du damit meinst ist mir nicht klar?!

schau dir doch in deinem Code mal an, wie du die Ref auswählst...


> Damit wird der ADU in jedem Durschlauf wieder aktiviert!

und das ist einer der Gründe, warum man sowas

> ADCSRA |= 0x80;

nicht macht!

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für was Initialisier ich den ADU denn überhaupt?
Ich muss doch nicht jedes mal meine ref. Spannung einstellen.
Dazu ist diese Funktion:
void vinitADU_8Bit(unsigned short int usimux)



>und das ist einer der Gründe, warum man sowas
> ADCSRA |= 0x80;
>nicht macht!

Was nicht macht?
Du redest ihn Rätseln....

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JTR schrieb:
> Für was Initialisier ich den ADU denn überhaupt?
> Ich muss doch nicht jedes mal meine ref. Spannung einstellen.

Genau darum geht es im Grunde ja :-)

Mittels
   ADMUX = usimux

stellst du eine neue Referenzspannung ein!
Unabsichtlich! Ich bin sicher du woltest das gar nicht. Aber du tust es! 
Du setzt alle Bits, die die Referenzspannung einstellen auf 0!

>
>>und das ist einer der Gründe, warum man sowas
>> ADCSRA |= 0x80;
>>nicht macht!
>
> Was nicht macht?
> Du redest ihn Rätseln....

vergleiche
   ADSCRA |= 0x80;

   ...

   ADCSRA &= ~( 1<<ADEN );

mit
   ADCSRA |= (1<<ADEN);

   ...

   ADCSRA &= ~( 1<<ADEN );

bei welcher Version sieht auch ein Blinder, dass die eine Operation die 
Umkehrung der anderen ist?

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt ist mir alles klar.
Werde, die Tipps morgen probieren und euch berichten.
Ich hoffe, dass es laufen wird :).

MFG

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Scheint so weit zu funktionieren! Danke!
War wohl die Änderung der ref. Spannung und, dass zu frühe abholen des 
Ergebnisses.

  ADMUX &= 0xF0;
  ADMUX |= usimux;     // Kanal waehlen
  ADCSRA |= 0x80;     //ADC aktivieren (1)

Hab es nun so gelöst :).
Und das Abholen des Ergebnisses hab ich einfach außerhalb der Schleife 
gemacht.

MFG

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.