Atmega88 ADC auf Display ausgeben

Gast #3561241
Lesenswert?

Hallo zusammen,

ich habe mir ein kleines Programm geschrieben, bei dem ich zwei AD-Werte 
auslese und auf einen LCD ausgeben will. Es funktioniert alles, bis auf 
die aktualisierung der AD-Werte. Wenn ich Spannung an die Schaltung lege 
wird am Display der aktuelle AD-Wert angezeigt, drehe ich am Poti des 
AD-Wandlers bleibt der Wert am Display gleich. Nehme ich die Spannung 
weg und klemme sie wieder an, wird wieder der momentan eingestellte 
AD-Wert angezeigt, aber während der Laufzeit wird er nicht mehr 
aktualisiert.

Hier der Code:

1
#define F_CPU 8000000
2

3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include <lcd-routines.h>
6
#include <lcd-routines.c>
7

8

9

10
uint16_t ADC_C0;
11
uint16_t ADC_C1;
12
uint8_t ADCL_C0;
13
uint8_t ADCH_C0;
14
uint8_t ADCL_C1;
15
uint8_t ADCH_C1;
16
char ADC_StringC0 [16];
17
char ADC_StringC1 [16];
18

19

20

21
void ADC_Init (void)
22
{
23
  
24
  ADMUX |= (1<<REFS0);
25
  ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADEN) | (1<<ADSC);
26
  
27
  while (ADCSRA & (1<<ADSC));
28
  ADCL_C0 = ADCL;
29
  ADCH_C0 = ADCH;
30
  
31
}
32

33

34
void ADC_Read (void)
35
{
36
  
37
  ADMUX &= (0<<MUX0);
38
  
39
  while (ADCSRA & (1<<ADSC)){}
40
    ADCL_C0 = ADCL;
41
    ADCH_C0 = ADCH;
42
  
43
  ADMUX |= (1<<MUX0);  
44
  while (ADCSRA & (1<<ADSC)){}
45
    ADCL_C1 = ADCL;
46
    ADCH_C1 = ADCH;
47
  
48
  ADC_C0 = ADCL_C0 + (ADCH_C0 * 256);
49
  ADC_C1 = ADCL_C1 + (ADCH_C1 * 256);
50
  
51
}
52

53

54

55
void LCD_Write (void)
56
{
57
  lcd_clear();
58
  
59
  itoa (ADC_C0, ADC_StringC0, 10);
60
  itoa (ADC_C1, ADC_StringC1, 10);
61
  
62
  lcd_setcursor(0,1);
63
  lcd_string("ADC0      ADC1");
64
  lcd_setcursor(0,2);
65
  lcd_string(ADC_StringC0);
66
  lcd_setcursor(9,2);
67
  lcd_string(ADC_StringC1);
68
    
69
  
70
}
71

72

73

74

75

76
int main(void)
77
{
78
  ADC_Init();
79
  lcd_init();
80
  
81
  
82
  
83
  
84
  
85
    while(1)
86
    {
87
        ADC_Read();
88
  LCD_Write();
89
  _delay_ms(100)
90
    }
91
}
Gast #3561271
Lesenswert?

1
void ADC_Read (void)
2
{
3
  
4
  ADMUX &= (0<<MUX0);
5
  
6
  while (ADCSRA & (1<<ADSC)){}
7
    ADCL_C0 = ADCL;
8
    ADCH_C0 = ADCH;
9
  
10
  ADMUX |= (1<<MUX0);  
11
  while (ADCSRA & (1<<ADSC)){}
12
    ADCL_C1 = ADCL;
13
    ADCH_C1 = ADCH;
14
  
15
  ADC_C0 = ADCL_C0 + (ADCH_C0 * 256);
16
  ADC_C1 = ADCL_C1 + (ADCH_C1 * 256);
17
  
18
}


In dieser Funktion liegt das Problem (eigentlich mehrere Probleme).

ADMUX &= (0<<MUX0);

Diese Zeile löscht ADMUX komplett.
Entspricht also
ADMUX = 0x00;

Das willst du aber sicherlich nicht

Bits löschen geht so:
ADMUX &= ~(1<<MUX0);


Nächstes Problem:
while (ADCSRA & (1<<ADSC)){}

du wartest hier zwar brav, bis die Messung beendet ist, hast aber 
überhaupt keine Messung gestartet!


teste mal die veränderte Funktion:
1
void ADC_Read (void)
2
{
3
  
4
  ADMUX &= ~(1<<MUX0);
5
  
6
  ADCSRA |= (1<<ADSC);   // start conversion
7
  while (ADCSRA & (1<<ADSC)){}
8
    ADCL_C0 = ADCL;
9
    ADCH_C0 = ADCH;
10
  
11
  ADMUX |= (1<<MUX0);  
12
  ADCSRA |= (1<<ADSC);   // start conversion
13
  while (ADCSRA & (1<<ADSC)){}
14
    ADCL_C1 = ADCL;
15
    ADCH_C1 = ADCH;
16
  
17
  ADC_C0 = ADCL_C0 + (ADCH_C0 * 256);
18
  ADC_C1 = ADCL_C1 + (ADCH_C1 * 256);
19
  
20
}
#3562842
Lesenswert?

Ist auch egal.
Solange du 2 Eingänge abfragen willst, bringt dich der free-Running 
Modus sowieso nicht weiter.

Du hast nur EINEN ADC!
Den kannst du auf verschiedene Eingänge schalten. Aber die eigentliche 
ADC Hardware gibt es nur ein eiziges mal. D.h. du willst die volle 
Kontroller darüber haben, welchen Kanal der ADC gerade bearbeitet und 
auch wann er das tut.
In dem Moment, in dem du Free Running Modus und "warten aufs Ergebnis" 
im selben Programm benutzt, machst du etwas grundsätzliches falsch.
#3562857
Lesenswert?

> Das mit der Hardware ist mir bewusst

Scheint nicht so zu sein.
Denn sonst wüsstest du, dass du die MUX Bits nicht einfach so ändern 
kannst. Eine Änderung der MUX Bits wird nämlich erst dann wirksam, wenn 
der ADC den laufenden Zyklus beendet hat. Sobald du aber auf das Beenden 
des Zykluses wartest um dir das Ergebnis zu holen, startet der ADC schon 
wieder neu während das gerade ermittelte Ergebnis ausgelesen wird. D.h. 
deine danach erfolgende Änderung der MUX bits wirkt sich dann erst auf 
das übernächste Messergebnis aus.
Free Running Modus mit Kanalwechsel ist tricky.

Wie gesagt: benutze ihn konventionell
1
  MUX Bits einstellen
2
  ADC Starten
3
  warten auf Fertigstellung
4
  Wert holen
und du hast weniger Probleme. Zeitmässig schenkt sich das sowieso 
nichts. Das Programm wird dadurch auch nicht langsamer. Dafür aber 
zuverlässiger :-)

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