Forum: Mikrocontroller und Digitale Elektronik Devision und Restbildung


von Bert (Gast)


Lesenswert?

Hallo
möchte in einem Programm zur Anzeige eines Messwertes eine vierstellige 
Zahl in seine Ziffern zerlegen. Habe das Beispiel in Mikro.. gefunden 
und es so progarmmiert:
1
spannung_anz1 = spannung_anz % 10;    // 4. Zahl
2
    spannung_anz2 = spannung_anz / 10;
3
    spannung_anz3 = spannung_anz2 % 10;    // 3. Zahl
4
    spannung_anz4 = spannung_anz2 / 10;
5
    spannung_anz5 = spannung_anz4 % 10;    // 2. Zahl
6
    spannung_anz6 = spannung_anz4 / 10;
7
    spannung_anz7 = spannung_anz6 % 10;    // 1. Zahl
8
    spannung_anz8 = spannung_anz6 / 10;
9
    
10
    itoa(spannung_anz7, Buffer, 10 );
11
    lcd_printlc(4,9," ");
12
    lcd_printlc(4,9,Buffer);
13
    
14
    itoa(spannung_anz5, Buffer, 10 );
15
    lcd_printlc(4,11," ");
16
    lcd_printlc(4,11,Buffer);
17
    
18
    itoa(spannung_anz3, Buffer, 10 );
19
    lcd_printlc(4,13," ");
20
    lcd_printlc(4,13,Buffer);
21
    
22
    itoa(spannung_anz1, Buffer, 10 );    // 4. letzte Zahl stimmt
23
    lcd_printlc(4,15," ");
24
    lcd_printlc(4,15,Buffer);
Es wird nur die 4. Stelle korrekt angezeigt. Die 1. bis 3. Stelle 
verändert sich nicht. Was mach ich falsch?
C, AVR GCC

Bert

von Dirk B. (dirkb2)


Lesenswert?

Wie ist Buffer definiert?

Das Ganz ist zu kompliziert gemacht.

von Bert (Gast)


Lesenswert?

Den Buffer habe ich so angegeben

char Buffer[30];

von Bert (Gast)


Lesenswert?

Kennst du eine einfache Lösung?

von rbx (Gast)


Lesenswert?

um Ärger mit Division und Datentypen o.ä. aus dem Weg zu gehen helfen 
u.a. logische Operationen.

von Dirk B. (dirkb2)


Lesenswert?

Bert schrieb:
> Kennst du eine einfache Lösung?

Was ist denn dein eigentliches Problem?

itoa kann auch Werte über 9 richtig umwandeln.

von Keiner N. (nichtgast)


Lesenswert?

Du kannst deinem itoa einfach den ganzen Wert zum Fraß vorwerfen. Du 
must deine spannung_anz nicht vorher klein schnipseln.

von Carl D. (jcw2)


Lesenswert?

Bert schrieb:
> Kennst du eine einfache Lösung?

Itoa kann auch mehrstellige Zahlen bearbeiten.

PS: nicht alles, was man im Internet findet, taugt was.

von Harry L. (mysth)


Lesenswert?

Viel sinnvoller ist in so einem Fall Festkomma-Arithmetik.
https://www.mikrocontroller.net/articles/Festkommaarithmetik

Und es heißt Division!

von Peter D. (peda)


Lesenswert?

Warum so umständlich?
1
    sprintf( Buffer, "%4d", spannung_anz );
2
    lcd_printlc(4,9,Buffer);

von Bert (Gast)


Lesenswert?

Das eigentliche Ziel bei der Wandlung ist, die Zahl (Messwert) zu 
zerlegen.
Bekomme z.B. den Wert von 4237 zurück. Diesen möchte ich in mV und V 
anzeigen. Mit der vorher durchgeführten Teilung sind es 4237 mV. Diesen 
Wert möchte ich auch in V anzeigen lassen. Es geht dabei um den 
spannungbereich von ca. 4,5V bis 12,5V und das richtige setzen des 
Kommars.

von Carl D. (jcw2)


Lesenswert?

Bert schrieb:
> Das eigentliche Ziel bei der Wandlung ist, die Zahl (Messwert) zu
> zerlegen.
> Bekomme z.B. den Wert von 4237 zurück. Diesen möchte ich in mV und V
> anzeigen. Mit der vorher durchgeführten Teilung sind es 4237 mV. Diesen
> Wert möchte ich auch in V anzeigen lassen. Es geht dabei um den
> spannungbereich von ca. 4,5V bis 12,5V und das richtige setzen des
> Kommars.

Aber wenn die 4 Ziffern der mV's im Puffer stehen, dann würdest du die 
V's und ihre Nachkommastellen darin schon finden, oder?

von Och Nee (Gast)


Lesenswert?

Bert schrieb:
> Bekomme z.B. den Wert von 4237 zurück. Diesen möchte ich in mV und V
> anzeigen. Mit der vorher durchgeführten Teilung sind es 4237 mV. Diesen
> Wert möchte ich auch in V anzeigen lassen. Es geht dabei um den
> spannungbereich von ca. 4,5V bis 12,5V und das richtige setzen des
> Kommars.

Och mönsch ....
1
   sprintf( Buffer, "%2d.%03d", spannung_anz/1000, spannung_anz%1000);

Ich weiss nicht was lcd_printlc macht aber das kriegst
du schon noch hin ....

Spannung darf dabei nicht negativ sein sonst muss man noch
Vorkehrungen treffen ...

von m.n. (Gast)


Lesenswert?

rbx schrieb:
> um Ärger mit Division und Datentypen o.ä. aus dem Weg zu gehen helfen
> u.a. logische Operationen.

Oder einfach nur Subtraktion und Addition.
Beitrag "schnelle Wandlung long -> ASCII"

von Michael B. (laberkopp)


Lesenswert?

Peter D. schrieb:
> Warum so umständlich?
>     sprintf( Buffer, "%4d", spannung_anz );
>     lcd_printlc(4,9,Buffer);

Ach du Scheisse, das Monster printf auffahren um eine GANZZAHL 
auszugeben ? Das nennt man aber Resourcenverschwendung par excellence.

Bert schrieb:
> Bekomme z.B. den Wert von 4237 zurück. Diesen möchte ich in mV und V
> anzeigen. Mit der vorher durchgeführten Teilung sind es 4237 mV. Diesen
> Wert möchte ich auch in V anzeigen lassen. Es geht dabei um den
> spannungbereich von ca. 4,5V bis 12,5V und das richtige setzen des
> Kommars.

Wahrscheinlich Kommas, aber das geht doch auch hinterher, wenn in buffer 
erst mal die 4-stellige Zahl steht. Einfach die erste Stelle ausgeben, 
dann ein Komma, dann die letzten 3 Stellen.

von Peter D. (peda)


Lesenswert?

Michael B. schrieb:
> Ach du Scheisse, das Monster printf auffahren um eine GANZZAHL
> auszugeben ? Das nennt man aber Resourcenverschwendung par excellence.

Für ungenutzten Flash gibt es kein Geld zurück. Die MCs haben heutzutage 
typisch ab 32kB aufwärts, da spielt das keine Rolle mehr.
Zu Zeiten des ATtiny2313, ATtiny15 hatte ich mir auch Gedanken zum Flash 
sparen gemacht, aber das ist schon ewig her.
Heutzutage ich viel wichtiger, das man Code schnell, fehlerfrei und 
wartbar erstellen kann.
Und wenn es keine triftigen Gründe dagegen gibt, würde ich Kommazahlen 
einfach als float darstellen:
1
    sprintf( Buffer, "%6.3f", spannung_anz / 1e3 );
2
    lcd_printlc(4,9,Buffer);

von Εrnst B. (ernst)


Lesenswert?

Auch wenn das bei einer für Menschen gedachten Ausgabe völlig irrelevant 
ist ...


Och Nee schrieb:
> sprintf( Buffer, "%2d.%03d", spannung_anz/1000, spannung_anz%1000);

Kann man noch optimieren und Quotient + Rest in einem Durchlauf 
berechnen:
1
#include <stdlib.h>
2
#include <stdio.h>
3
4
5
void print_mV(uint16_t mV) {
6
  div_t splitted=div(mV,1000);
7
  printf("%3d.%03d\n",splitted.quot,splitted.rem);
8
}
(Statt printf einfach die Wunsch-Ausgabefunktion verwenden).

Wird dann zu:
1
print_mV:
2
/* prologue: function */
3
/* frame size = 0 */
4
/* stack size = 0 */
5
.L__stack_usage = 0
6
        ldi r22,lo8(-24)
7
        ldi r23,lo8(3)
8
        rcall __divmodhi4
9
..... prinf-Aufruf-gedöns .....

Also ein call einer handoptimierten ASM-Routine aus der lib und fertig.

Und nachdem die "div"-Funktion mit dem div_t Rückgabewert zum 
C89-Standard gehört, ist das auch kein unportables Gefrickel.


Nachtrag:
Hab dem GCC mal wieder zu wenig zugetraut. Mit Optimierung macht er 
dasselbe aus mV/1000, mV%1000 ...
also lohnt es nicht, umständlich mit der "div"-Funktion zu hantieren

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Michael B. schrieb:
> Ach du Scheisse, das Monster printf auffahren um eine GANZZAHL
> auszugeben ? Das nennt man aber Resourcenverschwendung par excellence.

Der Peter kennt nix besseres. Zum Beispiel kennt er <math.h> wohl 
garnicht. Deshalb kommt er auf sowas nicht - genauso wie der TO:
1
  long   L; // Variable hier rein
2
  ldiv_t T;
3
  int    i;
4
  char   Buffer[soviel wie gewünscht];
5
6
  i = soweit nach rechts wie gewünscht;
7
  while(i)
8
  { T = ldiv(L,10);
9
    L = T.quot;
10
    Buffer[i--] = '0'+T.rem;
11
  }

W.S.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Zum Beispiel kennt er <math.h> wohl garnicht.

Für die Verwendung von ldiv() ist stdlib.h und nicht math.h 
obligatorisch.

>   while(i)
>   { T = ldiv(L,10);
>     L = T.quot;
>     Buffer[i--] = '0'+T.rem;
>   }

Buffer wird nicht terminiert:

$ cat ldiv.c
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
int main ()
5
{
6
    long   L = 12345;
7
    ldiv_t T;
8
    int    i;
9
    char   Buffer[20];
10
11
    i = 10;
12
13
    while(i)
14
    {
15
        T = ldiv(L,10);
16
        L = T.quot;
17
        Buffer[i--] = '0'+T.rem;
18
    }
19
    puts (Buffer);
20
21
    return 0;
22
}
1
$ cc ldiv.c -o ldiv && ./ldiv
2
0000012345▒\▒▒▒W▒

Aua.

: Bearbeitet durch Moderator
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

... probiert mal und ersetze

spannung_anz4 = spannung_anz %10;
spannung_anz3 = spannung_anz /10%10;
spannung_anz2 = spannung_anz /100%10;
spannung_anz1 = spannung_anz /1000%10;

das thema hatte ich auch schon und hat nur so funktioniert?!

mt

von W.S. (Gast)


Lesenswert?

Frank M. schrieb:
> Aua.

Und wieso aua?
Für copy&paste ohne eigenes Nachdenken? Ach nö. Ich will den Leuten den 
Weg aufzeigen und ihnen nicht den Brei mit dem Löffel in den Mund 
füttern.

Man hätte sowas schon vor Jahren in der Lernbetty nachlesen können. Aber 
stattdessen kommt immer wieder sowas wie Peters Vorschlag hier in die 
Threads. Seine Ansicht:

Peter D. schrieb:
> Für ungenutzten Flash gibt es kein Geld zurück. Die MCs haben heutzutage
> typisch ab 32kB aufwärts, da spielt das keine Rolle mehr.

kann ich wirklich NICHT teilen. Richtig ist, daß es für dutlich 
weniger Flash-Verbrauch tatsächlich Geld gibt, nämlich das, was man beim 
Chipkauf eingespart hat. Selbst für nen Bastler spring was dabei heraus: 
Wer sich nicht zu blöd anstellt, kriegt mit der 32K-Bastlerversion des 
Keil mehr auf die Reihe als jemand, der statt nachzudenken immer nur 
nach der übernächst größeren Version greift und sich dann auch noch mit 
dem vom Gcc erzeugten Code befassen muß.

W.S.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Und wieso aua? Für copy&paste ohne eigenes Nachdenken?

Stimmt, beim Copy&Paste hier in Deinen Beitrag hast Du offentbar 
tatsächlich nicht nachgedacht.

Der Source hält nicht, was Du vollmundig versprichst. Nicht nur, dass Du 
mit fehlerhaftem Code einen Anfänger in die Irre führst, er setzt auch 
keinen Dezimal-Punkt bzw. Komma. Dein Code konvertiert nur Integer. Da 
ist Peters Einzeiler hundertmal besser.

> Ach nö. Ich will
> den Leuten den Weg aufzeigen und ihnen nicht den Brei mit dem Löffel in
> den Mund füttern.

Mit fehlerhaftem Code? Ist das Dein Ernst?

> Man hätte sowas schon vor Jahren in der Lernbetty nachlesen können.

Warum sollte man das tun? Ist die Lernbetty der ultimative Code, der 
alle Fragen des Universums beantwortet? Offenbar nicht. Der 
Lernbetty-Code scheint nämlich einen Terminierungsfehler zu haben, der 
bei Dir glücklicherweise nicht zutage tritt. Dein Codefetzen ermuntert 
mich jedenfalls nicht zum Studium des Lernbetty-Codes - ganz im 
Gegenteil.

: Bearbeitet durch Moderator
von Manfred (Gast)


Lesenswert?

Bert schrieb:
> Bekomme z.B. den Wert von 4237 zurück. Diesen möchte ich in mV und V anzeigen.

Etwas in der Art habe ich gerade gebaut, um beim Schreiben eines 
Floatwertes auf eine SD-Karte den Dezimalpunkt los zu werden und durch 
ein Komma zu ersetzen.

Wert durch 1000 geteilt und zum Integer gemacht, hat der Integerwert die 
vollen Volt.

Schreibe Volt, schreibe Komma.

Wert durch 1000 minus den Integerwert habe ich die Millivolt.

Wenn Millivolt kleiner 100 schreibe eine Null raus.
Wenn Millivolt kleiner 10 schreibe noch eine Null raus.
Schreibe Millivolt.

Wenn Du Zeit hast, kannst Du das wirklich kleckerweise zum Display 
rausschreiben. Hat der Prozessor vorrangig andere Dinge zu tun, musst' 
einen String basteln und diesen in einem Zuge zum Display senden.

Peter D. schrieb:
>> Ach du Scheisse, das Monster printf auffahren um eine GANZZAHL
>> auszugeben ? Das nennt man aber Resourcenverschwendung par excellence.
> Für ungenutzten Flash gibt es kein Geld zurück. Die MCs haben heutzutage
> typisch ab 32kB aufwärts, da spielt das keine Rolle mehr.

Schön für Dich. Ich habe mich neulich in die Situation manövriert, dass 
32k nicht genügen wollten und ein Umbau der Hardware sehr aufwendig 
geworden wäre. Ich habe dabei eine Menge gelernt, anstatt 
hingeschissenen 60k läuft das nun mit 30k und hat auch eingermaßen 
Struktur bekommen. Aber schon klar, Speicher zahlt der Kunde, da kann 
der Programmierer nach Belieben mit herumaasen.

von Peter D. (peda)


Lesenswert?

Wenns denn unbedingt schnell und klein sein muß:
Beitrag "Formatierte Zahlenausgabe in C"

von Peter D. (peda)


Lesenswert?

Manfred schrieb:
> Aber schon klar, Speicher zahlt der Kunde, da kann
> der Programmierer nach Belieben mit herumaasen.

Nö, ein guter Programmierer weiß schon ganz genau, worauf es ankommt. In 
der Regel kommt ein hoher Speicherverbrauch nur durch eine unüberlegte 
Aneinanderreihung von unnützen Funktionsaufrufen.
Der Code des TO zeigt sehr eindrucksvoll, wie man es nicht macht. Es 
wird 8* lcd_printlc aufgerufen, wo 1* völlig gereicht hätte.

Viel einsparen kann man daher, wenn man den Code etwas aufräumt und vor 
allem erstmal überlegt und nicht wie wild drauflos tippt. Ich nehme oft 
erstmal Papier und Bleistift, um mir vom Programmablauf einen Plan zu 
machen.
Der Verzicht auf Standardlibs bringt dagegen oft nur wenig Einsparung 
bezogen auf die gesamte Applikation. Er macht aber das ganze sehr 
unübersichtlich und damit fehleranfällig. Das wirst Du mit der Zeit aber 
auch noch merken.

An dem obigen Link sieht man doch schön, wie sich mein Programmierstil 
in den 9 Jahren geändert hat.

: Bearbeitet durch User
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.