Hallo, stehe gerade vor dem Problem, dass mein hex File für den AtTiny26 obwohl im eigentlichen Programm nicht viel getan wird durch die LCD Ausgabe viel zu groß wird (9kB), gibt es da eine ganz abgespeckte Version für die Ausgabe am LCD (HD44780U komp. 2x16 LCD), die ich im Tiny verwenden könnte, oder wie macht ihr das?
Selber schreiben ;) ist ja eigentlich auch kein akt. oder du nimmst dir aus den sourcen nur das was du brauchst.
Hi, hab meine (die ich normalerweise verwende) selbst geschrieben, aber aus Zeitgründen dachte ich, vielleicht hat ja jemand eine abgespeckte Version für den Tiny parat!
Da kann man nix abspecken. Da kann an nur das rauswerfen was man nicht braucht....
was brauchst du denn für Befehle an dein LCD? und welche Sprache? mfg Karl
Im Grunde brauch ich nur eine Ausgabe von Strings und vielleicht eine für int. Das ganze natürlich in C.
sowas kommt eh nicht in die lcd-libary. Da werden nur funktionen mit dem namen putc und puts nach ausen zur verfügung gestellt....
Hi, das ist schon klar, aber in meiner lcd.c muss ich die Sachen ja auch ausprogrammieren! Habe jetzt einige Sachen auch meiner lcd.h und lcd.c gelöscht, die Größe des hex-Files ist jedoch nicht kleiner geworden. Wie verhält es sich eigentlich mit dem einbinden von Headerfiles, wenn ich z.B. nur itoa() aus stdlib verwende, wird dann auch nur der Code itoa() ins hexfile aufgenommen, oder alle Funktionen von stdlib?
>wird dann auch nur der Code itoa() ins hexfile aufgenommen
und das, was itoa() zum wandeln braucht.
Könnte ich vielleicht übers Makefile noch was rausholen, verwende nämlich ein Standard Hex File von MFile generiert, habs mal angehängt!
Zeich doch mal deinen Code! Da lässt sich vielleicht an Stellen drehen, wo du es selber nicht siehst (ist einfach so, passiert mir und anderen genauso). ("Zeich" = Kielerisch/Norddeutsch für "zeig")
Float-Berechnung kostet natürlich auch Speicher... "dtostrf" erscheint mir sehr, sogar zu mächtig... Und dann schluckt die LCD-Library vermutlich auch eine ganze Menge Speicher. Sehe ich es richtig, dass du eine (Spannung) bzw. zwei (Strom) Stellen vor und 2 nach dem Komma darstellen willst? Das mache ich so: zehner = '0'; einer = '0'; zehntel = '0'; hundertstel = '0'; f = spg; while (f>0.0) {f -= 1.0; einer++;) while (f>0.1) {f -= 0.1; zehntel++;} while (f>0.01) {f-= 0.01; hundertstel++;) Die Zehner-Stelle genauso... Durch '0' wird die float gleich in ASCII-Zeichen gewandelt. Führende Nullen kann man auch noch herausfiltern...
Hi, es wird in der ersten Zeile einfach ein Stromwert (zur Zeit auch noch der dazu gehörige ADC WErt) angezeigt und in der zweiten Zeile der Spannungswert. Entstehen dann in den char Variablen zehner, einer,... die einzelnen Ziffern als Character? Würde das für die Zehnerstelle so aussehen? while (f>10.0) {f -= 10.0; zehner++;) Solll ich statt double dann auch lieber float nehmen?
> Und dann schluckt die LCD-Library vermutlich auch eine ganze Menge > Speicher. Das ist aber nicht viel. Die Fleury Lib ist ziemlich einfach gestrickt: Basisfunktionen zur Byte-Ausgabe Initialisierung Ausgabe eines Charcater Ausgabe eines String Mit ein paar Zig Bytes ist man da dabei. Das meiste wird wohl durch die floating point Arithmetik + die Formatierfunktionen draufgehen.
>Würde das für die Zehnerstelle so aussehen? >while (f>10.0) {f -= 10.0; zehner++;) ja.
> Solll ich statt double dann auch lieber float nehmen?
Das bringt mit gcc nichts.
float und double sind dort gleich gross und haben
daher auch dieselbe Implementierung.
Wenn du die floating point Library wegbekommen willst,
dann musst du komplett auf float bzw. double verzichten.
Ist aber kein Problem:
Deine Berechnung sieht so aus:
spg = (adc_str * 5.0) / 1024.0;
Das kannst du auch mit Fixkommaarithmetik im long
Bereich machen:
spg = ( adc_str * 500L ) / 1024;
(spg ist dann eine int Variable. Die long Rechnerei braucht
man nur deshalb, damit adc_str * 500 nicht den int Zahlen-
bereich überläuft).
Anstatt Zahlen im Bereich 0 bis 5 (als float) kommen da
jetzt Zahlen im Bereich 0 bis 500 heraus. Die Zehner- und
Einerstelle sind dabei deine ursprünglichen Nachkommastellen.
D.h. Wenn du jetzt bei der Ausgabe zwischen Hunderterstelle
und Zehnerstelle ein '.' einschmuggelst dann sieht die
Ausgabe aus wie vorher. Nur halt ohne Floating Point
berechnet.
lcd_putint( spg / 100 );
lcd_putc( '.' );
lcd_putint( spg % 100 );
Was ähnliches kann man noch mit der anderen Berechnung machen
und schon fällt die Floting Point Library aus deinem Program
raus.
Sehe gerade, dass in deiner 2-ten Berechnung auch Tausendstel vorkommen, und dass die aus spg ausgerechnet werden. Anstatt '*100' bietet es sich dann an, einfach alles *1000 zu nehmen um überall ganze Zahlen zu haben.
Wenn ich mir die Größe der beiden Module hd44780.o und lcd.o aus dem stdiodemo der avr-libc ansehe, dann sind das:
1 | % avr-size *.o |
2 | text data bss dec hex filename |
3 | 210 0 0 210 d2 hd44780.o |
4 | 102 0 1 103 67 lcd.o |
Sollte also durchaus auch in einen ATtiny26 passen.
Hallo, danke erstmal für eure super Ratschläge! Deine Idee gefällt mir sehr gut Karl Heinz, hättest du die das bei der zweiten Berechnung so vorgestellt? strom = ((spg - 2.5) *1000L) / 0.025;
Hab das mit dem Strom jetzt mal so gelöst: strom = ((spg - 250) ) / 0.025; lcd_gotoxy(11, 0); lcd_putint( strom / 100 ); lcd_putc( '.' ); lcd_putint( strom % 100 ); Bin jetzt immerhin von 9kB auf 6kB runter gekommen! Ich benutze in meiner lcd.c auch noch stdlib für itoa, kann(soll) ich das auch noch rausbekommen? Hier mal meine Ausgabe für int am lcd: void lcd_putint(int value) { char string[4]; itoa(value, string, 10); lcd_puts(string); }
> strom = ((spg - 2.5) *1000L) / 0.025;
Denk nach. Da sind immer noch Kommazahlen drinn!
Ich geh mal davon aus, dass du
spg = ( adc_str * 5000L ) / 1024;
gemacht hast. spg hat also einen Wertebereich 0 bis 5000
Aus den 2.5 muessen dann klarerweise 2500 werden
spg - 2500
sind dann Zahlen im Bereich -2500 bis +2500
Die durch 25 dividieren ( 0.025 * 1000) liefert
-100 bis +100.
Wenn ich mich jetzt nicht vertan habe (Chef war am
Telefon), dann sind das -0.1 Ampere bis +0.1 Ampere.
D.h. '.' wieder an der richtigen Stelle einschmuggeln.
> Bin jetzt immerhin von 9kB auf 6kB runter gekommen!
Wenn du floating point komplett weg hast, müsstest
du nochmal einen grossen Sprung sehen.
itoa()
Ich denke, wenn floating point weg ist, hast du keine
Notwendigkeit mehr darüber nachzudenken. Ausserdem:
itoa() ist nicht soooo teuer. Irgendeine Umwandlung
brauchst du sowieso und ob du die jetzt selbst schreibst
oder ob du itoa() benutzt sollte Jacke wie Hose sein.
Hallo, habe die Änderungen noch übernommen und bin jetzt auf 5kB. Habe mir jetzt auch einmal die Größe anzeigen lassen, nur in was wird da gemessen, Byte? I:\AVR Programme\UILogger>avr-size *.o text data bss dec hex filename 458 0 0 458 1ca lcd.o 566 17 3 586 24a uilogger.o
Ja, Byte
> habe die Änderungen noch übernommen und bin jetzt auf 5kB.
Wo liest du die 5K ab?
Doch hoffentlich nicht von der Größe der .hex Datei.
Wenn ich dein Pgm jetzt durch meinen Compiler jage,
dann lande ich bei
Program: 1218 bytes (59.5% Full)
Data: 25 bytes (19.5% Full)
Das reicht dann schon um gebrannt werden zu können.
Mit Floating Point waren die Daten übrigens:
Program: 5916 bytes (288.9% Full)
Data: 33 bytes (25.8% Full)
Kleine Umstellung, grosse Wirkung
Ich glaube die Ausgaben ans LCD fressen so viel Platz, denn wenn ich alle Ausgaben wegmache komme ich auf 3kB runter, wenn ich rein Strom und Spannungswert ausgebe bin ich auf 4 kB
Bernd Edlinger wrote: > Ich glaube die Ausgaben ans LCD fressen so viel Platz, denn wenn ich > alle Ausgaben wegmache komme ich auf 3kB runter, wenn ich rein Strom und > Spannungswert ausgebe bin ich auf 4 kB Nochmal: Du darfst nicht nach der Größe des .hex Files gehen. Dein Program ist zur Zeit 1218 Bytes gross und füllt den Tiny zu rund 60% aus.
Mann bin ich blöd... Danke für den Hinweis, dann werd ich es gleich mal testen. Wie sehe ich denn die Größe beim Compiler?
Ich benutze den WinAVR im Rahmen des AVR-Studios. Dessen Build Funktion gibt die Statistik im Abschluss aus.
Noch zwei Sachen: Du verwendest alle globalen Variablen als volatile -soweit OK. 1. Du beschreibst "adc_str" in einem Interrupt - das ist eine 16Bit Variable. Wenn die Anzeige einigermaßen Zuverlässig sein sollte, musst du die Interrupts deaktiveren bevor du die an die LCD Libray übergibst. Sonst könnte es in seltenen Fällen dazu kommen dass die erste Hälfte es alten Wertes mit dr zweiten 8 Bit Hälfte des neuen Wertes auf dem Display angezeigt wird. 2. Wenn du volatile Variablen lokal mehrfach verwendet lohnt es sich eine lokale Kopie anzulegen um unnötige RAM Zugriffe zu vermeiden. Also:
1 | cli(); |
2 | uint16_t adc_str_l = adc_str; |
3 | sei(); |
4 | lcd_putint(adc_str_l); |
Bei 8 Bit Variablen ist das natürlich nicht unbedingt nötig.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.