Forum: Mikrocontroller und Digitale Elektronik Atmega88 ADC auf Display ausgeben


von Christian (Gast)


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
}

von chris (Gast)


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
}

von Christian (Gast)


Lesenswert?

Erstmal Danke für deine schnelle Antwort.
Das mit der 0 hatte ich nicht gewusst. Ich dachte das wäre rechnerisch 
das selbe.
Zum anderen mit der Messung: Ich habe auf Free Running modus gestellt, 
sollte da nicht automatisch eine neue Messung starten?

von Christian (Gast)


Lesenswert?

Bitte nochmal um Antwort

von spess53 (Gast)


Lesenswert?

Hi

>Zum anderen mit der Messung: Ich habe auf Free Running modus gestellt,
>sollte da nicht automatisch eine neue Messung starten?

Wo hast du das eingestellt? Ich sehe keine Stelle, an der ADATE gesetzt 
wird.

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

Nachtrag:

>  while (ADCSRA & (1<<ADSC))

Wird dich im Free Running Mode nicht weiter bringen, da ADSC dort 
ständig High ist. Dort musst du ADIF abfragen und das auch wieder per 
Hand löschen. Oder du nutzt den ADC Complete Interrupt.

MfG Spess

von Christian (Gast)


Lesenswert?

Ich habe mir das Datenblatt mal angesehen und habe weder ADATE noch ADIF 
gefunden. Ich habe hoffentlich nich das falsche Datenblatt.

von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Christian (Gast)


Lesenswert?

Das mit der Hardware ist mir bewusst

von Christian (Gast)


Lesenswert?

Welchen modus sollte ich demnach verwenden?

von spess53 (Gast)


Lesenswert?

Hi

>Ich habe mir das Datenblatt mal angesehen und habe weder ADATE noch ADIF
>gefunden.

ADATE: Bit5 in  ADCSRA
ADIF:  Bit4 in  ADCSRA

>Ich habe hoffentlich nich das falsche Datenblatt.

http://www.atmel.com/Images/doc2545.pdf

MfG Spess

von Karl H. (kbuchegg)


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 :-)

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> nichts. Das Programm wird dadurch auch nicht langsamer.

Vor allen Dingen dann nicht, solange ein
>   _delay_ms(100)
mit im Programm ist.

von Christian (Gast)


Lesenswert?

Der Free running modus ist aber standardmäßig eingestellt. ADTS2 -ADTS0 
= 0.

von Karl H. (kbuchegg)


Lesenswert?

Christian schrieb:
> Der Free running modus ist aber standardmäßig eingestellt.

Das wär uns allen aber neu.

Solange ADATE in ACSRA auf 0 bleibt, is nix mit Auto Trigger. Und ohne 
Auto Trigger kein Free Running.

Datenblatt, Mega88 Seite 256 und folgende.

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>Der Free running modus ist aber standardmäßig eingestellt. ADTS2 -ADTS0
>= 0.

Läuft aber nur, wenn ADATE ( AD Auto Trigger Enable) gesetzt ist.

MfG Spess

von Christian (Gast)


Lesenswert?

Aha jetzt hab ichs kappiert. Vielen Dank für eure Hilfe.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.