www.mikrocontroller.net

Forum: Compiler & IDEs ATmega8 ADC unerwartete Werte


Autor: Stundenblume (Sebastian) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Forum,

ich versuche mich gerade im Umgang mit MC, für einen Maschbauer gar 
nicht so einfach. ;-)

Also, ich habe einen ATmega8 
(http://www.kramann.info/87_Archiv_Mikrocontroller/...) 
mit zwei Temperatursensoren (KTY) und jeweils einem Spannungsteiler an 
PC3 und PC4. Dort kommen bei -20°C 2,4V und bei RT 1,9V an. Nun möchte 
ich mit dem ADC die Spannungen auslesen. Referenzspannung sind die 
internen 2,56V.

Aus irgend einem Grund erhalte ich allerdings immer für beide Eingänge 
den selben Wert (zwischen 452 - 457). Selbst wenn die Sensoren definitiv 
unterschiedliche Temperaturen haben. Auch wenn ich die Referenzspannung 
auf AVCC lege ändert sich daran nichts. Dann sollte der Wert ja 
eigentlich nur halb so groß sein. Z.zt. bekommt die ganze Schaltung 
Spannung über den Programmer (4,5V) wenn ich über einen 7805 speise und 
die Spannung auf 5V steigt erhalte ich an den Eingängen Werte um 617.

Ich gehe davon aus, dass ich einen Bock im Code habe. Vielleicht hat ja 
jemand eine Idee.


Vielen Dank im voraus

Sebastian
#include <avr/io.h>
#include "lcd.h"
#include <stdio.h>
#include <util/delay.h>


int main(void)
{
  // Variablen definieren
  uint16_t temp1,temp2,i;
  uint8_t buffer1[4];
  uint8_t buffer2[4];


  //Ausgänge definieren
  DDRD |= (1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);

  //ACD einrichten
  ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);  // Frequenzvorteiler auf 8
  ADMUX |= (1<<REFS0) | (1<<REFS1);        //Interne 2,56 Volt als Referenzspannung

  //LCD aktivieren
  lcd_init(LCD_DISP_ON);

  
  //Endlose Schleife
  for (;;) 
  {

    PORTD = 0;                  //LEDs aus


    //1. Messung
    ADMUX |= PC3;                //Kanal für Messung wählen
    ADCSRA |= (1<<ADSC);            //Messung starten
    while ( ADCSRA & (1<<ADSC) ) {}        //warten bis Messung bestätigt
    temp1 = ADCW;                //Ergebnis abholen

    //2. Messung
    ADMUX |= PC4;                //gleiches Vorgehen
    ADCSRA |= (1<<ADSC);
    while ( ADCSRA & (1<<ADSC) ) {}
    temp2 = ADCW;

    
    //Übergabe an LCD
    lcd_home();
    
    sprintf(buffer1,"a%d",temp1);
    lcd_puts(buffer1);
    
    sprintf(buffer2,"b%d",temp2);
    lcd_puts(buffer2);

    
    // zusäztliche Visualisierung an LEDs
    if(temp1>temp2){PORTD |= (1<<PD5);}
    else if(temp1<temp2){PORTD |= (1<<PD7);}
    else if(temp1==temp2){PORTD |= (1<<PD5)|(1<<PD7);}


    //Warten und neuen Schleifendurchlauf durch LED anzeigen
    for (i=0;i<=5;i++)
    {
      _delay_ms(222);
    }
    
    PORTD |= (1<<PD6);
    
    _delay_ms(1);
  }
}

Autor: Tilo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du die Spannungen an den ADC gemessen? Eventuell ist es ein 
Schaltuns- und kein Programmierproblem.

Autor: Marco S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ADMUX |= x ist nicht so toll, kann nur Bits setzen.
#define VOLTAGE 7
#define set_adc(mux) ADMUX = (1<<REFS1) | (1<<REFS0) | (0x1F & (mux))

set_adc(VOLTAGE);

Autor: Roman K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Code habe ich mir jetzt nicht angeguckt.
Aber du kannst diesen ganz einfach testen wenn du mit einem 
Potentiometer an die ADC eingänge gehst.
Ich habe das Gefühl du kennst dich ganz gut aus, trotzdem nochmal:

Potentiometer hat 3 Pins. die beiden äußeren kommen an Spannung und 
Ground
der Pin in der Mitte an den ADC Eingang.
Jetzt kannst du die Spannung am ADC über das Poti einstellen.

Bitte stell die elektrische Schaltung auch mal rein,
also wie der Spannungsteiler an dem KTY angeschlossen ist.

Autor: Sebastian S. (stundenblume)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@Tilo
Im Moment habe ich den einen Sensor unter meinem Laptop und den anderen 
frei im Raum. An PC3 sind es 1,84V und an PC4 1,78V.


@Roman
die Schaltung schaut so aus:

5V---KTY1----R1---GND
           |
           PC3

@Marco
Das verstehe ich noch nicht so ganz. Versuche mich aber daran...

Autor: Marco S (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit der |= (oder-gleich) setzt du nur Bits in ADMUX. Du setzt einmalig 
die Ref-Bits. Danach oderst du 0x03 hinzu (PC3), danach 0x04 (PC4). Dass 
heißt, du wählst kontinuierlich ADC7 aus.

Autor: Lutz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist zwar eine Auswertungssache, aber Du solltest die Spannung über dem 
KTY messen und nicht über dem "Vor"widerstand. Das erklärt auch, warum 
Deine gemessene Spannung mit der steigender Temperatur fällt.

Und wie Marco schon geschrieben hatte, mußt Du zum Wählen des 
ADC-Eingangskanals die MUX-bits in ADMUX nehmen und nicht die "normalen" 
Port-bits.

Autor: Sebastian S. (stundenblume)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

vielen Dank für die Hilfe. Es läuft :-) Ich habe es zwar noch nicht so 
ganz verstanden weshalb, aber das kommt hoffentlich noch.

Ich habe durch eure Beispiele das Tutorial zum ADC besser nachvollziehen 
können und habe meinen Code entsprechend umgebaut. Nun wird der ADC für 
jede Messung neu eingerichtet und das funktioniert. Was ich noch nicht 
verstehe, ist weshalb ich dem kompletten Register ADMUX die Kanalnummer 
gebe (ADMUX=3;)?!?


Gruß

Sebastian

#include <avr/io.h>
#include "lcd.h"
#include <stdio.h>
#include <util/delay.h>


int main(void)
{
  // Variablen definieren
  uint16_t temp1,temp2,i;
  uint8_t buffer1[4];
  uint8_t buffer2[4];


  //Ausgänge definieren
  DDRD |= (1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);

  //LCD aktivieren
  lcd_init(LCD_DISP_ON);

  
  //Endlose Schleife
  for (;;) 
  {

    PORTD = 0;                            //LEDs aus


    //1. Messung
    ADMUX = 3;                            //Kanal für Messung wählen
    //ACD einrichten
    ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);  // Frequenzvorteiler auf 8
    ADMUX |= (1<<REFS0) | (1<<REFS1);            //Interne 2,56 Volt als Referenzspannung
    ADCSRA |= (1<<ADSC);                    //Messung starten
    while ( ADCSRA & (1<<ADSC) ) {}              //warten bis Messung bestätigt
    temp1 = ADCW;                          //Ergebnis abholen
    ADCSRA &= ~(1<<ADEN);                     // ADC deaktivieren

    //2. Messung
    ADMUX = 4;                            //gleiches Vorgehen
    //ACD einrichten
    ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);  // Frequenzvorteiler auf 8
    ADMUX |= (1<<REFS0) | (1<<REFS1);            //Interne 2,56 Volt als Referenzspannung
    ADCSRA |= (1<<ADSC);
    while ( ADCSRA & (1<<ADSC) ) {}
    temp2 = ADCW;
    ADCSRA &= ~(1<<ADEN);                     // ADC deaktivieren

    
    //Übergabe an LCD
    lcd_home();
    
    sprintf(buffer1,"a%d",temp1);
    lcd_puts(buffer1);
    
    sprintf(buffer2,"b%d",temp2);
    lcd_puts(buffer2);

    
    // zusäztliche Visualisierung an LEDs
    if(temp1>temp2){PORTD |= (1<<PD5);}
    else if(temp1<temp2){PORTD |= (1<<PD7);}
    else if(temp1==temp2){PORTD |= (1<<PD5)|(1<<PD7);}


    //Warten und neuen Schleifendurchlauf durch LED anzeigen
    for (i=0;i<=5;i++)
    {
      _delay_ms(222);
    }
    
    PORTD |= (1<<PD6);
    
    _delay_ms(1);
  }
}

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian S. wrote:
> Was ich noch nicht
> verstehe, ist weshalb ich dem kompletten Register ADMUX die Kanalnummer
> gebe (ADMUX=3;)?!?
Das verstehe ich auch nicht, weil Du damit jedes Mal die 
Referenzspannungsauswahl löschst und sie zwei Zeilen weiter jeweils 
wieder setzen musst. Übersichtlicher und ohne Änderung der 
Referenzspannung wäre es z.B. mit
ADMUX = (ADMUX & 0xF0) | channel;
Dabei bleiben die oberen 4 Bits unberührt. channel wäre hier dann die 
Kanalnummer.

Autor: Sebastian S. (stundenblume)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich hab den Code jetzt nochmal nach Deinem Vorschlag verändert und auch 
des ewige einrichten abgeschafft. Funktioniert.

Gruß

#include <avr/io.h>
#include "lcd.h"
#include <stdio.h>
#include <util/delay.h>


int main(void)
{
  // Variablen definieren
  uint16_t temp1,temp2,i;
  uint8_t buffer1[4];
  uint8_t buffer2[4];


  //Ausgänge definieren
  DDRD |= (1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);

  //ADC einrichten
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);  // Frequenzvorteiler setzen auf 8 und ADC aktivieren
  ADMUX |= (1<<REFS1) | (1<<REFS0);         // interne Referenzspannung nutzen

  //LCD aktivieren
  lcd_init(LCD_DISP_ON);


  uint16_t KanalMessen(uint8_t KanalX)
  {
      ADMUX = (ADMUX & 0xF8)| KanalX;                 // Kanal wählen
 
      ADCSRA |= (1<<ADEN);              // ADC aktivieren
 
       ADCSRA |= (1<<ADSC);                    // eine Wandlung statren
      while ( ADCSRA & (1<<ADSC) ) {}
      ADCSRA &= ~(1<<ADEN);                     // ADC deaktivieren
 
 
      return ADCW;
  }
  

  //Endlose Schleife
  for (;;) 
  {

    PORTD = 0;                    //alle LEDs aus


    //1. Messung
    temp1 = KanalMessen(3);              //Kanal 3 wandeln

    //2. Messung
    temp2 = KanalMessen(4)+2;            //Kanal 4 wandeln

    
    //Übergabe an LCD
    lcd_home();
    
    sprintf(buffer1,"a%d",temp1);
    lcd_puts(buffer1);
    
    sprintf(buffer2,"b%d",temp2);
    lcd_puts(buffer2);

    
    // zusäztliche Visualisierung an LEDs
    if(temp1>temp2){PORTD |= (1<<PD5);}          //LED 1 ein
    else if(temp1<temp2){PORTD |= (1<<PD7);}      //LED 3 ein
    else if(temp1==temp2){PORTD |= (1<<PD5)|(1<<PD7);}  //LED 1 und 3 ein


    //Warten und neuen Schleifendurchlauf durch LED anzeigen
    for (i=0;i<=5;i++)
    {
      _delay_ms(222);
    }
    
    PORTD |= (1<<PD6);                  //LED 2 ein
    
    _delay_ms(1);
  }
}

Autor: lkmiller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Es läuft :-) Ich habe es zwar noch nicht so
>ganz verstanden weshalb...
War das nicht bei Frankenstein auch so???  ;-)

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.