Forum: Compiler & IDEs ADC auslesen und auf display ausgeben


von Starfire (Gast)


Lesenswert?

Hallo ihr lieben Profis,

ich bins mal wieder:

Folgendes Problem: Ich habe ein Display, auf dem ich Texte anzeigen kann 
(Programmiert mit den Routinen aus dem Tutorial). An Pin PA0 liegt die 
Datenleitung eines Sensors, deren Wert ausgegeben werden soll.
Das Auslesen des ADC habe ich mit Hilfe dieses Tutorials gelöst:
http://www.rn-wissen.de/index.php/ADC_(Avr)
Weiterhin habe ich mich für die Anzeige an den Festkommaarithmetik 
Artikel gehalten.
Als Referenzspannung habe ich meine 5V Versorgungsspannung an AREF und 
AVCC gelegt.
Ich habe das ganze mal mit einem Multimeter gemessen und mein Sensor 
gibt an den uC eine Spannung zwischen 0 und 5V aus.
Ich arbeite mit einem ATMEGA32, der mit einem Takt von 1Mhz läuft.

Hier mein Code (In auszügen):
1
//Quelle für die folgende Methode: www.rn-wissen.de/index.php/ADC_(Avr)
2
3
long readADC(uint8_t channel){
4
  uint8_t i;
5
  uint16_t result=0;
6
  //Den ADC aktivieren und den Teilungsfaktor auf 8 stellen
7
  ADCSRA =(1<<ADEN)| (1<<ADPS0)|(1<<ADPS1);
8
  
9
  //Kanal des Multiplexers wählen
10
  //Interne Referenzspannung verwenden (also 2,56V)
11
  ADMUX = channel|(1<<REFS1)|(1<<REFS0);
12
  
13
  //Den ADC initialisieren und einen sog. Dummyreadout machen
14
  ADCSRA |= (1<<ADSC);
15
  while(ADCSRA &(1<<ADSC));
16
  
17
  //Jetzt 3x die Spannung an Kanal channel auslesen und dann einen Durchschnittswert berechnen
18
  for (i=0; i<3; i++){
19
    //Eine Wandlung
20
    ADCSRA |= (1<< ADSC);
21
    //Auf Ergebnis waren...
22
    while (ADCSRA & (1<<ADSC));
23
    
24
    result += ADCW;
25
  }
26
  //ADC wiederdeaktivieren 
27
  ADCSRA &= ~(1<<ADEN);
28
  result /= 3;
29
  return result;
30
} 
31
32
33
/*Funktion zur Anzeigeeiner 32Bit Zahl im Stringformat auf einem LCD
34
Quele: mikrocontroller.net/articles/Festkommaarithmetik
35
Parameter: 
36
37
char* string  :  Zeiger aud den String, welcher mit my_itoa erzeugt wurde
38
uint8_t start :  Offset im String, ab der die Zahl ausgegeben werden soll, 
39
         das ist notwendig, wenn Zahlen mit begrenztem Zahlenbereich 
40
         ausgegeben werden sollen. 
41
         Vorzeichenslose Zahlen:     0..10
42
         Vorzeichenbehaftete Zahlen:  1..11
43
uint8_t komma :  Offset im String, zeigt aud die Stelle an welcher das virtuelle 
44
         Komma steht (erste Nachkommastelle)
45
         Komma muss immer größer oder gleich start sein
46
uint8_t frac  :  Anzahl der Nachkommastellen
47
48
*/
49
void schreibe_Zahl(char* string, uint8_t start, uint8_t komma, uint8_t frac){
50
  uint8_t i;          //Zähler
51
  uint8_t flag =0;     //Merker für führende Nullen
52
53
  //Vorzeichen ausgeben
54
  if (string[0]=='-')
55
    lcd_data('-');
56
  else
57
    lcd_data(' ');
58
59
  //Vorkommastellen ohne führende Nullen ausgeben
60
  for(i=start; i<komma; i++){
61
    if (flag==1||string[i]!='0'){
62
      lcd_data(string[i]);
63
      flag =1;
64
    }
65
    else lcd_data(' ');
66
  }
67
  lcd_data('.');
68
  //Nachkommastellen ausgeben
69
  for(; i<(komma+frac);i++) lcd_data(string[i]);
70
}
71
72
73
...................................................................
74
75
76
//Schleife, aus der das Ganze aufgerufen wird:
77
78
while(1)
79
  {
80
  long result = readADC(0);
81
  long spannung = result*(long)5000; //Ermitteln des digitalen Wertes der gemessenen Größe Referenzspannung: 5V
82
  spannung = spannung/1024; //Umrechnen, wegen 10Bit auflösung
83
        //Die nun errechnete Spannung soll auf 1000el genau (also 3 Nachkommastellen) ausgeben werden.
84
        uint8_t i;
85
  char string[11];     //String Terminator
86
  string[11] ='\0';
87
  if(spannung<0){        //ist die Zahl negativ?
88
    string[0] ='-';
89
    spannung = -spannung;
90
  }
91
92
  else string[0] = ' ';  //Die Zahl ist positiv
93
  for(i=10; i>=1; i--){
94
    string[i] = (spannung%10) +'0'; //Modulo rechnen, dan den ASCII Code von '0'addieren
95
    spannung/=10;
96
  }
97
  utoa(spannung, string, 10);
98
  schreibe_Zahl(string, 2, 5, 3);
99
  _delay_ms(3000);
100
}


Das Display zeigt nun aber keine Zahlen zwischen 0 und 4.8 an, wie 
gewünscht, sondern Zahlen wie .004.
Wird der Sensor ausgelöst, verändern sich die Zahlen, zum Beispiel zu 
.002 oder .001
Gebe ich für meinen string zur Ausgabe eine manuelle Zahl ein, dann wird 
diese aber korrekt angezeigt.

Folglich muss ich also iwo vorher einen Fehler gemacht haben...

Ich hoffe ihr könnt mir helfen!

Liebe Grüße

Eure Starfire

von MWS (Gast)


Lesenswert?

Sieht alles etwas durcheinander aus, ein offensichtlicher Fehler ist ein 
11 Zeichen Char-Array mit 12 Zeichen beschreiben zu wollen.

von Karl H. (kbuchegg)


Lesenswert?

künstle da fürs erst nicht lange rum, sondern nimm für eine 
Erstimplementierung die einfachste Variante
1
int main()
2
{
3
  char Buffer[20];
4
5
  ...
6
7
  while(1)
8
  {
9
    long result = readADC(0);
10
    long spannung = result*(long)5000; //Ermitteln des digitalen Wertes der gemessenen Größe Referenzspannung: 5V
11
    spannung = spannung/1024; //Umrechnen, wegen 10Bit auflösung
12
13
    sprintf( Buffer, "%d.%03d", spannung / 1000, spannung % 1000 );
14
    lcd_gotoxy( 0, 0 );
15
    lcd_string( Buffer );
16
17
    _delay_ms(3000);
18
  }
19
}

wenn du sowieso einen Delay rein machst, spielt es keine Rolle ob 
sprintf ein wenig länger rumpfriemelt oder nicht.

von Volkmar D. (volkmar)


Lesenswert?

Hallo,

abgesehen von dem Hinweis von MWS habe ich zusätzlich folgendes gesehen:

Hier setzt Du Deine Zahl in einen String um:
Starfire schrieb:
> for(i=10; i>=1; i--){
>     string[i] = (spannung%10) +'0'; //Modulo rechnen, dan den ASCII Code von 
'0'addieren
>     spannung/=10;
>   }

Um den String gleich darauf wieder zu überschreiben:
>   utoa(spannung, string, 10);

Da hier die Variable Spannung 10 mal durch 10 geteilt wurde, steht wohl 
nur noch die erste Ziffer drin. Du mußt Dich entscheiden, entweder die 
eine oder die andere Variante.

von Karl H. (kbuchegg)


Lesenswert?

Und vergiss die "schreibe_Zahl" Funktion.
Die ist schwer beschädigt. Wenn du der nicht einen String so 
reinschiebst, wie sie ihn haben will, dann kracht sie ganz gewaltig.

von Karl H. (kbuchegg)


Lesenswert?

>
1
>  for(i=10; i>=1; i--){
2
>    string[i] = (spannung%10) +'0'; //Modulo rechnen, dan den ASCII Code von '0'addieren
3
>     spannung/=10;
4
>  }
5
>  utoa(spannung, string, 10);
6
>

entweder DU wandelst die Zahl selber in eine Textdarstellung oder du 
lässt das utoa machen, aber nicht beides (und wenn du es selber machst, 
dann musst du das auch richtig machen). Vor allen Dingen dann nicht, 
wenn deine eigene Wandlung die Zahl bis auf die Einerstelle reduziert 
(durch die fortgesetzte Division durch 10).

von Starfire (Gast)


Lesenswert?

Lieber Karl Heinz,

warum einfach, wenn es auch kompliziert geht :D

Ich habe mal den Müll, den ich gemacht habe raus genommen und nur deinen 
Code einprogrammiert...

Danke dafür, es Funktioniert! Mir hat wahrscheinlich lediglich die 
Kenntniss von sprintf gefehlt... wieder was gelernt :)

Vielen Dank!

Starfire

von Volkmar D. (volkmar)


Lesenswert?

Starfire schrieb:
> Mir hat wahrscheinlich lediglich die Kenntniss von sprintf gefehlt...

sprintf() ist sehr mächtig, benötigt aber auch etlichen Speicherplatz. 
Wenn man verschiedene Darstellungsvarianten benötigt oder genug Platz 
hat, OK. Ansonsten sind die itoa-Funktionen nicht zu verachten.

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.