ATmega8 ADC unerwartete Werte

Gast #924793
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/02_Programmierer/atmega8.png) 
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
1
#include <avr/io.h>
2
#include "lcd.h"
3
#include <stdio.h>
4
#include <util/delay.h>
5

6

7
int main(void)
8
{
9
  // Variablen definieren
10
  uint16_t temp1,temp2,i;
11
  uint8_t buffer1[4];
12
  uint8_t buffer2[4];
13

14

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

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

22
  //LCD aktivieren
23
  lcd_init(LCD_DISP_ON);
24

25
  
26
  //Endlose Schleife
27
  for (;;) 
28
  {
29

30
    PORTD = 0;                  //LEDs aus
31

32

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

39
    //2. Messung
40
    ADMUX |= PC4;                //gleiches Vorgehen
41
    ADCSRA |= (1<<ADSC);
42
    while ( ADCSRA & (1<<ADSC) ) {}
43
    temp2 = ADCW;
44

45
    
46
    //Übergabe an LCD
47
    lcd_home();
48
    
49
    sprintf(buffer1,"a%d",temp1);
50
    lcd_puts(buffer1);
51
    
52
    sprintf(buffer2,"b%d",temp2);
53
    lcd_puts(buffer2);
54

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

61

62
    //Warten und neuen Schleifendurchlauf durch LED anzeigen
63
    for (i=0;i<=5;i++)
64
    {
65
      _delay_ms(222);
66
    }
67
    
68
    PORTD |= (1<<PD6);
69
    
70
    _delay_ms(1);
71
  }
72
}
Gast
ADMUX |= x ist nicht so toll, kann nur Bits setzen.
1
#define VOLTAGE 7
2
#define set_adc(mux) ADMUX = (1<<REFS1) | (1<<REFS0) | (0x1F & (mux))
3

4
set_adc(VOLTAGE);
Gast
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.
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...
Gast
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.
Gast
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.
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

1
#include <avr/io.h>
2
#include "lcd.h"
3
#include <stdio.h>
4
#include <util/delay.h>
5

6

7
int main(void)
8
{
9
  // Variablen definieren
10
  uint16_t temp1,temp2,i;
11
  uint8_t buffer1[4];
12
  uint8_t buffer2[4];
13

14

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

18
  //LCD aktivieren
19
  lcd_init(LCD_DISP_ON);
20

21
  
22
  //Endlose Schleife
23
  for (;;) 
24
  {
25

26
    PORTD = 0;                            //LEDs aus
27

28

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

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

49
    
50
    //Übergabe an LCD
51
    lcd_home();
52
    
53
    sprintf(buffer1,"a%d",temp1);
54
    lcd_puts(buffer1);
55
    
56
    sprintf(buffer2,"b%d",temp2);
57
    lcd_puts(buffer2);
58

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

65

66
    //Warten und neuen Schleifendurchlauf durch LED anzeigen
67
    for (i=0;i<=5;i++)
68
    {
69
      _delay_ms(222);
70
    }
71
    
72
    PORTD |= (1<<PD6);
73
    
74
    _delay_ms(1);
75
  }
76
}
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
1
ADMUX = (ADMUX & 0xF0) | channel;
Dabei bleiben die oberen 4 Bits unberührt. channel wäre hier dann die 
Kanalnummer.
Hi,

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

Gruß

1
#include <avr/io.h>
2
#include "lcd.h"
3
#include <stdio.h>
4
#include <util/delay.h>
5

6

7
int main(void)
8
{
9
  // Variablen definieren
10
  uint16_t temp1,temp2,i;
11
  uint8_t buffer1[4];
12
  uint8_t buffer2[4];
13

14

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

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

22
  //LCD aktivieren
23
  lcd_init(LCD_DISP_ON);
24

25

26
  uint16_t KanalMessen(uint8_t KanalX)
27
  {
28
      ADMUX = (ADMUX & 0xF8)| KanalX;                 // Kanal wählen
29
 
30
      ADCSRA |= (1<<ADEN);              // ADC aktivieren
31
 
32
       ADCSRA |= (1<<ADSC);                    // eine Wandlung statren
33
      while ( ADCSRA & (1<<ADSC) ) {}
34
      ADCSRA &= ~(1<<ADEN);                     // ADC deaktivieren
35
 
36
 
37
      return ADCW;
38
  }
39
  
40

41
  //Endlose Schleife
42
  for (;;) 
43
  {
44

45
    PORTD = 0;                    //alle LEDs aus
46

47

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

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

54
    
55
    //Übergabe an LCD
56
    lcd_home();
57
    
58
    sprintf(buffer1,"a%d",temp1);
59
    lcd_puts(buffer1);
60
    
61
    sprintf(buffer2,"b%d",temp2);
62
    lcd_puts(buffer2);
63

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

70

71
    //Warten und neuen Schleifendurchlauf durch LED anzeigen
72
    for (i=0;i<=5;i++)
73
    {
74
      _delay_ms(222);
75
    }
76
    
77
    PORTD |= (1<<PD6);                  //LED 2 ein
78
    
79
    _delay_ms(1);
80
  }
81
}

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 18 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.