ATmega8 ADC unerwartete Werte

Gast #924793
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/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 #924817
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.
Gast #925225
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.
#925693
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

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
}
#925705
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
1
ADMUX = (ADMUX & 0xF0) | channel;
Dabei bleiben die oberen 4 Bits unberührt. channel wäre hier dann die 
Kanalnummer.
#925732
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren