Forum: Compiler & IDEs Atmega32 LCD Kommastelle


von Stipo (Gast)


Lesenswert?

He Leute,

Meine Hardware:
Atmega32
LCD HD44780
Hilfe aus diesen Tut genommen:
http://www.mikrocontroller.net/articles/FAQ#itoa.28.29_.28utoa.28.29.2C_ltoa.28.29.2C_ultoa.28.29.2C_ftoa.28.29_.29

Habe es zum laufen gebracht auch danke der hilfe dieses Forums =)

Aber ein neues Problem tut sich auf.
Ich will eine Zahl mit 2 Kommastellen am LCD ausgeben.
Das Programm dazu habe ich selbstgeschrieben und es tut unter Windows 
auch das was es soll.

Rechenwert = 9,77 diesen multipliziere ich mit 100 und bekomme so 977.

Wenn ich den Rechenwert dann mit einem analogen Wert (der korrekt 
eingelesen wird 0-1023) multipliziere erhalte ich das 100fache und somit 
2 Kommastellen.

So ist es auch im genannten Tut.

Hier mein Code:
Das Programm mit dem das Komma gesetzt wird:
1
void komma(long z, int rechenwert, char* Fertig)
2
{
3
    int i=1,j=1;
4
5
    char Buffer[20] = {0};
6
7
8
  
9
  z=z*rechenwert;
10
    if (z<0) {        //Vorzeichen kontrolle
11
        Buffer[0]='-';    //wenn - dann in [0] '-' schreiben
12
        z *= -1;      //z auf postiven Wert bringen
13
    }
14
    else
15
        Buffer[0]=' ';    //wenn + dann Vorzeichen weglassen
16
17
    for (i=i;z>0;i++) {      
18
        Buffer[i] = '0' + z % 10;  //Restwert in Buffer[i] schreiben, so 
19
                                   //wird der Wert verkehrt in Buffer
20
                                   //geschrieben
21
        z = z / 10;          
22
    }
23
24
    Fertig[0] = Buffer[0];      //Fertig = Fertig für die Ausgabe, hier wird das Vorzeichenübernommen
25
26
    for (i=19;i>0;i--) {      //Hier wird der Wert wieder richtig gestellet (umgedreht)
27
        if (Buffer[i]>0) {
28
            Fertig[j] = Buffer[i];
29
            j++;
30
            }
31
        }
32
33
    for (i=19;i>0;i--) {        //Hier werden die letzten 2 Ziffern in "Fertig" gesucht um 1 Array verschoben
34
        if (Fertig[i]>0) {        //und ein Punkt/Komma gesetzt
35
            j = i+1;
36
            Fertig[j] = Fertig[i];
37
            i--;
38
            j = i+1;
39
            Fertig[j] = Fertig[i];
40
            j--;
41
            Fertig[j] = '.';
42
            break;
43
            }
44
        }
45
46
47
48
}
49
50
Hier die main();
51
52
#include <avr/io.h>
53
#include <util/delay.h>
54
#include <stdlib.h>
55
56
#include "analog.h"
57
#include "lcd-routines.h"
58
#include "komma.h"
59
60
61
#define Schalter PA3
62
63
64
#define LED1 PC0
65
#define LED2 PC1
66
#define LED3 PC2
67
#define LED4 PC3
68
#define LED5 PC4
69
#define LED6 PC5
70
#define LED7 PC6
71
#define LED8 PC7
72
73
#define BitmaskP0 0b00000001
74
#define BitmaskP1 0b00000010
75
#define BitmaskP2 0b00000100
76
#define BitmaskP3 0b00001000
77
#define BitmaskP4 0b00010000
78
#define BitmaskP5 0b00100000
79
#define BitmaskP6 0b01000000
80
#define BitmaskP7 0b10000000
81
82
83
 
84
int main( void )
85
{
86
  
87
  uint16_t adcval;
88
 
89
  
90
  ADC_Init();
91
  lcd_init();
92
  
93
  
94
  lcd_setcursor( 0, 1);
95
  lcd_string("Wert:");
96
  lcd_setcursor( 0, 2);
97
  //lcd_string("Temp:");
98
  //lcd_setcursor( 6, 2);
99
  
100
 
101
  //temp[0]='1'; temp[1]='1'; temp[2]='.'; temp[3]='1'; temp[4]='1';  //So gibt er die Ziffern einzeln mit Komma aus.
102
103
104
  while( 1 ) {
105
106
  adcval = ADC_Read(4);  // Kanal 0
107
108
109
  
110
  lcd_setcursor( 6, 1);
111
  char Buffer[20];
112
  itoa( adcval, Buffer, 10);
113
  lcd_string( Buffer );
114
  
115
  char temp[20];
116
  lcd_setcursor( 0, 2);  
117
  komma( adcval, 977, temp);
118
  lcd_string( temp );
119
  
120
  _delay_ms(200);
121
  lcd_setcursor( 6, 1);
122
    lcd_string("          ");
123
  lcd_setcursor( 6, 2);
124
  lcd_string("          ");
125
  
126
  }
127
}
Aber aus irgendeinen Grund läuft das Programm zwar unter Windows am PC 
richtig, wenn ich in der Konsole starte, aber am Atmega32 nicht.
Vorzeichen stimmt immer.
Die Zahl selbst auch.
Vom errechneten Wert werden alle Ziffern ausgeben.
Wenn der analog Wert 700 ist, ergibt sich somit 6839,00.
Am LCD steht dann 683900 und 3 weitere unleseliche Zeichen.

Woran liegt das ?
Und sry falls mein Programm für manche vlt schrecklich aussieht, weil es 
auch einfacher gehen würde :o

Danke für eure Lehren =)

: Verschoben durch User
von Stipo (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch ein Foto vom LCD

von Avr N. (balze)


Lesenswert?

Hallo Stipo,
1
    for (i=i;z>0;i++) {
2
        Buffer[i] = '0' + z % 10;  //Restwert in Buffer[i] schreiben, so
3
                                   //wird der Wert verkehrt in Buffer
4
                                   //geschrieben
5
        z = z / 10;


z bleibt sehr lange groesser 0!

6839 / 10 = 683,9 > 0
683,9 / 10 = 68,39 > 0
68,39 / 10 = 6,839 > 0
6,839 / 10 = 0,6839 > 0
0,6839 / 10 = 0,06839 > 0
...
...

Vermutlich mehr als 20 Schleifendurchläufe. Denn ob der Index kleiner 20 
bleibt pruesft Du nicht.

MfG

Balze aka AVR Noob

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Avr Noob schrieb:
> z bleibt sehr lange groesser 0!

nein, denn ein Long kann keine nachkomma stellen speichern.

6839 / 10 = 683,9 > 0
683 /  10 = 68 > 0
68 / 10 = 6 > 0
6 / 10 = 0

von Karl H. (kbuchegg)


Lesenswert?

Bei derartigen Dingen
1
    for (i=19;i>0;i--) {      //Hier wird der Wert wieder richtig gestellet (umgedreht)

müssen bei dir die Alarmglocken zu schrillen anfangen.
Es geht um die 19 hier.
Du weißt doch aus der vorhergehenden Zerlegeschleife, wieviele Zeichen 
du generiert hast. Dein i enthält genau diese Information. Benutze sie! 
Und mach nicht solche Spielchen wie 'Ich geh durch das Array als ganzes 
durch und nur wenn der char größer 0 ist, dann ...'. Denn wenn du ein 
Array in einer Schleife mehrmals benutzt, dann werden da eben CHaracter 
Leichen nach dem eigentlichen String noch im Array stehen.

> Am LCD steht dann 683900 und 3 weitere unleseliche Zeichen.

So was ist meistens ein Indiz für eine von 2 Möglichkeiten
* die 0-Terminierung des Strings stimmt nicht (und ich sehe nicht, das 
bzw. wie du dich in deiner Komma Funktion darum kümmern würdest)
* oder aber der Effekt entsteht dadurch, dass am LCD ein Text durch 
einen anderen, kürzeren Text überschrieben wird.

Bei dir ist es aber wahrscheinlich die fehlende bzw. inkorrekte 
0-Terminierung. Wenn du in einem Array nach und nach einzelne Zeichen zu 
einem String zusammenbaust, dann darfst du nicht vergessen, dass nach 
dem letzten Zeichen noch ein Zeichen mit dem Wert '\0' kommen muss, 
welches allen String-verarbeitenden Funktionen anzeigt, dass hier der 
String zu Ende ist.

von Avr N. (balze)


Lesenswert?

BTW
1
for (i=i;z>0;i++)

i mit i zu initialisieren koennte zu prblemen fuehren.

von Karl H. (kbuchegg)


Lesenswert?

Avr Noob schrieb:
> BTW
>
>
1
> for (i=i;z>0;i++)
2
>
>
> i mit i zu initialisieren koennte zu prblemen fuehren.

?
Nämlich zu welchen?

von Avr N. (balze)


Lesenswert?

Peter II schrieb:
> Avr Noob schrieb:
>> z bleibt sehr lange groesser 0!
>
> nein, denn ein Long kann keine nachkomma stellen speichern.
>
> 6839 / 10 = 683,9 > 0
> 683 /  10 = 68 > 0
> 68 / 10 = 6 > 0
> 6 / 10 = 0

UUUPS, sorry, alles zurueck!

Natuerlich, ich hatte double im kopf.

von Avr N. (balze)


Lesenswert?

Das man die Schleife wiederverwendet und nicht an die Initialisierung 
von i denkt.

von Karl H. (kbuchegg)


Lesenswert?

`PS:

Das hier
1
    for (i=19;i>0;i--) {      //Hier wird der Wert wieder richtig gestellet (umgedreht)
2
        if (Buffer[i]>0) {
3
            Fertig[j] = Buffer[i];
4
            j++;
5
            }
6
        }
7
8
    for (i=19;i>0;i--) {        //Hier werden die letzten 2 Ziffern in "Fertig" gesucht um 1 Array verschoben
9
        if (Fertig[i]>0) {        //und ein Punkt/Komma gesetzt
10
            j = i+1;
11
            Fertig[j] = Fertig[i];
12
            i--;
13
            j = i+1;
14
            Fertig[j] = Fertig[i];
15
            j--;
16
            Fertig[j] = '.';
17
            break;
18
            }
19
        }

ist deutlich zu kompliziert.
Du könntest den Dezimalpunkt auch in der ersten Schleife mit wenig 
Aufwand einfach an der richtigen Stelle einbauen und dann gleich auch 
noch das Problem beseitigen, dass du hast, wenn deine auszugebende Zahl 
zb eine glatte 0 mit keinen Nachkommastellen ist.
Wobei eine glatte 0 in der Ausgabe sowieso noch Probleme macht, denn 
hier
1
    for (i=i;z>0;i++) {
wird das überhaupt nicht berücksichtigt und du erhälst aus der 
Ziffern-Zerlegung einen leeren String.

: Bearbeitet durch User
von Stipo (Gast)


Lesenswert?

wow, da kamen viele Antworten auf einmal =)

Danke an jeden einzelnen!!!

Ja die Arrays habe ich nicht geleert und deswegen stand da auch immer 
wieder viel unsinniges am LCD!
Habe es so gelöst (nicht schön aber wirkt)
1
void komma(long z, int rechenwert, char* Fertig)
2
{
3
    int i=0,j=0,v;
4
5
    char Buffer[20] = {0};
6
7
  for (i=19;i>0;i--) {
8
        Fertig[i] = ' ';
9
    Buffer[i] = ' ';
10
    }
11
  
12
  z=z*rechenwert;
13
    if (z<0) {        //Vorzeichen kontrolle
14
        Buffer[0]='-';    //wenn - dann in [0] '-' schreiben
15
        z *= -1;      //z auf postiven Wert bringen
16
    v=0;    
17
    i=1;
18
    j=1;        
19
    }
20
    else
21
        v=-1;
22
23
    for (i=i;z>0;i++) {      
24
        Buffer[i] = '0' + z % 10;  //Restwert in Buffer[i] schreiben, 
25
        z = z / 10;          //so wird der Wert verkehrt in Buffer geschrieben
26
    }
27
28
    Fertig[0] = Buffer[0];      //Fertig = Fertig für die Ausgabe, 
29
                  //
30
    for (i=19;i>v;i--) {      //Hier wird der Wert wieder richtig gestellet (umgedreht)
31
        if (Buffer[i]!=' ') {
32
            Fertig[j] = Buffer[i];
33
            j++;
34
            }
35
        }
36
37
    for (i=19;i>v;i--) {        //Hier werden die letzten 2 Ziffern in "Fertig" gesucht um 1 Array verschoben
38
        if (Fertig[i]!=' ') {        //und ein Punkt/Komma gesetzt
39
            j = i+1;
40
            Fertig[j] = Fertig[i];
41
            i--;
42
            j = i+1;
43
            Fertig[j] = Fertig[i];
44
            j--;
45
            Fertig[j] = '.';
46
            break;
47
            }
48
        }
49
}
Das mit dem for (i=i;... ist wirklich nicht gut, ich weis.
Führt leicht zu fehlern wenn man die Schleife wieder verwendet aber hier 
stört es soweit nicht.

Bin am lernen also bei Learning by doing ^^
Ist ewig her, dass ich programmiert habe und somit habe ich vieles 
vergessen.

Werde aufjedenfall noch das Programm erweitern bzw. verfeinern.

Danke jeden der sich die mühe gemacht hat =)

Weiter vorschläge nehme ich gerne an.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Stipo schrieb:

> Weiter vorschläge nehme ich gerne an.

zb die Verwendung von Funktionen, die du sowieso schon vorrätig hast.

Noch ausbaufähig, aber ...
1
void komma(long z, int rechenwert, char* Fertig)
2
{
3
  char tmp[20];
4
  size_t len;
5
  
6
  z = z * rechenwert;
7
  ltoa( z, tmp, 10 );
8
  
9
  len = strlen( tmp );
10
  if( len > 2 ) {
11
    strncpy( Fertig, tmp, len - 2 );
12
    Fertig[len-2] = '\0';
13
    strcat( Fertig, "." );
14
    strcat( Fertig, &tmp[len-2] );
15
  }
16
}

von Falk B. (falk)


Lesenswert?

@ Stipo (Gast)

>    3 MB, 63 Downloads

"Tolles" Bild

-> Bildformate

Ansonsten, siehe Festkommaarithmetik, dort steht alles drin.

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.