Beiträge von KaiR

    Um noch etwas über Quarze zu berichten. Ich experimentiere momentan selber mit MSP430-µControllern mit einem externen Uhrenquarz als Taktgeber. Warum? Weil die Dinger dann seeehr wenig Strom verbrauchen aber dennoch einige nützliche (Mess-)Funktionen ausführen können.


    Ich hatte hier ja schon einmal kurz im Thread "Pendeluhr" berichtet, wie ich einen simplen Versuch mit der DIP-Variante des µControlers durchgeführt habe. Das funktionierte auch reibungslos. Dem Controller können intern per Software verschiedene Kapazitäten zugeschaltet werden. Ich hatte 6pF eingestellt und die Schaltung funktionierte sehr gut, auch ohne externe Kondensatoren.


    simple_clock_pwm.png

    µController mit externem Uhrenquarz (32,768 kHz)


    Dasselbe habe ich mit einer SMD Variante (TSSOP) versucht, einfach weil ich wissen wollte, ob sich der Controller gleich verhält wie die DIP-Variante. Für den Fall, dass der Controller in einer dauerhaften Schaltung eingesetzt werden soll, würde ich nämlich ein PCB mit der kleinen SMD Variante vorziehen.


    Oszillator-PCBAdapter.jpg

    PCB-Adapter für SMD-Komponenten


    Also habe ich den Controller auf einen SMD-Adapter aufgelötet und diesen statt der DIP-Variante für die oben dargestellte Breadbord-Schaltung benutzt. Diese Adapter-PCBs gibt es recht günstig im Onlinehandel für verschiedenstes IC-Bauformen (Footprints). Auf dem Foto sieht man links, wie so ein Adapter aufgebaut ist. Er hat auf Ober- und Unterseite Leitungsbahnen für zwei verschiedene Footprints, welche die Pins eines µControllers mit an beiden Seiten einlötbaren Steckleisten verbindet.


    Mein erster Versuch mit solch einem Adapter schlug jedoch fehl. Der Oszillator wollte einfach nicht zu schwingen anfangen. Also habe ich auf dem Breadboard externe Kondensatoren zwischen den beiden Quarzanschlüssen und GND eingesetzt (15pF). Es hat nichts genutzt.


    Die Leitungswege zwischen Quarz und den XTAL Anschlüssen waren recht lang. Durch den Adapter kann der Schwingquarz auf einem Breadboard nicht so dicht an den Pins angebracht werden wie bei einem µController in DIP Bauform. Also habe ich den Chip auf einen anderen Adapter aufgelötet und die XTAL Pins nicht mit einem Steckleistenanschluss versehen, sondern den Quarz direkt an die µController Anschlüsse angelötet (Foto Mitte). Dafür habe ich die Lötlöcher verwendet, die eigentlich für die Steckleistenpins gedacht sind. Aber auch das hat nichts gebracht. Ich bekam keinen Arbeitstakt.


    Externe Kondensatoren mit einer Seite direkt an den Quarz zu löten und die andere Seite mit GND auf dem Breadboard zu verbinden, war ebenfalls erfolglos. Ich bekam einfach keinen Takt. Dann habe ich noch die Leiterbahnen auf der Unterseite des Adapters in Quarznähe weggekratzt, weil ich vermutete, dass die evtl. noch einen Einfluss haben. Es hat nicht geholfen.


    Darum habe ich einen eigenen Adapter entworfen (Foto rechts, Screenshot unten), der die Pads für das Auflöten von zwei SMD-Kondensatoren mitbringt. Diese sind auf der Unterseite (blau) angebracht, damit die Leiterbahnen von den µController-Pins, die nichts mit dem Quarz zu tun haben, ohne Umweg an die Steckleistenpins geführt werden können. Ansonsten besteht die Unterseite nur aus einer Kupferlage die an GND angeschlossen ist.


    MSP430X2XXX-PCB-Adapter.png

    PCB-Adapter


    Nachdem ich den µController abermals umgelötet habe (der hält ganz schön was aus - Foto oben rechts), hat mein erster Versuch ohne externe Kondensatoren auf Anhieb funktioniert. Ich hatte sofort einen passenden Takt. Aber nur einmal! ;(


    Nach dem Ausschalten und erneuten Anschalten bekam ich wieder keinen Takt. Ich habe erst versucht die verschiedenen internen Kapazitäten per Software zu verwenden aber es hat einfach nicht funktioniert. Also habe ich zwei 15pF Kondensatoren auf die dafür vorgesehenen Pads aufgelötet. Seit dem funktioniert der Oszillator anstandslos und stabil. Auch nach mehrmaligen An- und Ausschalten schwingt sich der Quarz zuverlässig ein.


    Der Einschwingvorgang dauert recht lange.


    Einschwingzeit.png

    Einschwingvorgang Uhrenquarz


    Wie man auf dem Oszillogramm sehen kann, erfolgte bei ca. -7,5 Sek. der Einschaltvorgang (0 auf 3V). Es steht ein Minus vor der Zahl, weil der Trigger rechts eingestellt ist. Dann passiert ca. zwei Sekunden erst einmal gar nichts, bis endlich bei ca. -5,4 Sek. der Oszillator zu schwingen beginnt. Allerdings ist das am Anfang auch noch nicht der endgültige Takt. Der stellt sich erst nach weiteren ca. 4,5 Sekunden ein. Danach schwingt der Oszillator sehr genau (gleichmäßig), in meinem Fall aber ein wenig zu schnell. Das sieht man an folgendem Maskentest


    Maskentest-1.png

    Maskentest


    Der Test lief eine halbe Stunde lang. Die weiße Umrandung ist der Rahmen in dem sich ein Signal bewegen kann. Das abgebildete Signal wird durch einen Timer einmal pro Sekunde erzeugt. Es ist nichts anderes als ein PWM-Signal. Käme es zu zeitlichen Schwankungen oder anderen Störungen, würde der Rahmen "verlassen" und ein Fehler erzeugt. Wie man sieht, ist in dem Messzeitraum kein Fehler aufgetreten, aber es ist ein Signal zu viel vorhanden.


    Es ist also noch etwas Feintuning angesagt und das muss ich noch genauer untersuchen.


    Fazit: Mit externen Taktquellen kann es komplizierter werden als man im ersten Moment denkt, weil da doch einiges zu beachten ist. Es sind zwar in Datenblättern und/oder Literatur Formeln zur Berechnung von Kondensatoren angegeben, nur, wie soll man mit seinem Heimequipment beispielsweise die Kapazität einer Leiterbahn messen? Die angegebenen Werte sind schwer zu fassen. Darum ist meiner bisherigen Erfahrung nach, einiges an Experimentierlust notwendig.


    Wenn man Quarze dann noch in irgendeinem Chinashop oder beim Onlinehändler ohne Datenblatt kauft, wird es auch nicht einfacher.

    Seit wann ist eine Zahl ablesen "rechnen" ?:/


    Aber um das noch zu ergänzen, Wenn man Dein Beispiel mit dem LM7805 nimmt, der ist für bis 35V und bis 1A Strom angegeben, wenn ich mich richtig erinnere. Die Eingangsspannung ist mit 12V angegeben. Alleine daraus ergeben sich schon Anhaltswerte für den P-Channel Mosfet...

    Bau die Schaltung ohne Verpolungsschutz. Dann kannst Du ja messen für wieviel Last Du den Schutz auslegen musst.

    Normalerweise weiß man aber schon vorher in welcher Größenordnung die Werte liegen werden, wenn man weiß für welchen Zweck die Schaltung gebaut wird und welche Teile in der Schaltung verbaut weden.

    Zitat

    Ich suche eine Lösung die so wenig wie möglich an Verlustleistung hat.

    Nimm verpolungssichere Stecker (USB, JST Stecker o.ä.).

    Zitat

    Wie funktioniert das wenn ich einen Oszillator mit 16MHz verbaut habe und den IC jetzt nur mit 8 MHz laufen lassen möchte.

    Mann kann ja z.B. bei einem Arduino Board wo 16MHz verbaut sind auch auf 8 MHz problemlos runter regeln.

    Wirklich? Wie kommst du da drauf? Wenn man einen AVR-Controller auf 8 Mhz mit einem externen Quarz takten möchte, dann nimmt man auch einen 8Mhz Quarz.


    Zitat

    Dazu werden ja die Fuse-Bit verändert nur was wird hier genau im IC gemacht ?

    Die Fuse Bits werden verändert, um den Controller auf die externe Taktquelle einzustellen. Wenn die Einstellung gemacht wurde, wird der Controller ohne den Quarz nicht mehr funktionieren.


    Zitat

    Wir der Takt einfach von 16MHz auf 8 MHz per Software geteilt ?

    Oder wie funktioniert das genau ?

    Es funktioniert gar nicht. Jedenfalls nicht so, wie Du dir das vorstellst. Man kann die AVR-Controller mit verschiedenen Taktfrequenzen betreiben, wenn der interne RC- Oszillator verwendet wird. Ist ein externer Quarz angeschlossen, gibt der auch den Takt vor und der ist fest.


    Man kann allenfalls interne Funktionen wie z.B. Timer/ AD-Wandler usw. durch Taktteiler mit verschiedenen Taktfrequenzen betreiben. Der Haupttakt, ändert sich dadurch aber nicht. Die Teiler werden über Register per Software gesteuert.

    Zitat

    Nochmals zur Sicherheit, wenn ich einen Oszillator verbaue kann ich die 2 Kondensatoren die ein Quarz immer benötigt weglassen da der Oszillator diese bereits intern im Gehäuse verbaut hat richtig ?

    Ja. Der Oszillator wird, zumindest bei den gängigen AVR-Controllern, mit dem XTAL1 Anschluss verbunden. XTAL2 wird dann, im Gegensatz zur Schwingquarz-Variante, nicht beschaltet. Zu dem Thema Quarz an einem AVR-Controller gibt es gefühlt ungefähr eine „quadrillionen“ Webseiten mit sehr vielen Beispielen. Sogar hier im Forum (Thread Pendeluhr).

    Zitat

    Normal sollte es ja auch kein Problem sein einen normalen Quarz zu nutzen da im Datenblatt ja fast immer die empfohlenen Kondensatoren Werte mit dabei stehen.

    Wenn du die von Hans64 verlinkten Dokumente mal in Ruhe durchliest, wird Dir vielleicht klar, dass es auch auf den verwendeten Quarz ankommt, wenn man es genau haben will. Aber die in den Bauanleitungen / Datenblätter der Atmega angegebenen 12-22pf sind ein Wert, mit denen die gängigen Quarze zu schwingen beginnen sollten. Es kommt aber auch darauf an, wie der Quarz angeschlossen wird. Siehe verlinkte Literatur.


    Bei vielen Anwendungen ist es aber auch relativ egal, ob der Quarz nun mit genau 8 Mhz oder nur mit 7,99 Mhz schwingt.

    Ich habe hier im Forum ja schon ein wenig über die TI MSP430 µController geschrieben. Da einige Modelle sehr wenig Speicher haben, ist es nicht so leicht Daten auf einer seriellen Konsole auszugeben. Standard Funktionen wie wie sie aus der Arduino "Welt" bekannt sind (z.B. Serial.print) funktionieren bei Controllern mit wenig Speichern nicht, weil diese Standardfunktionen zu viel Platz verbrauchen. Momentan experimentiere ich mit einem MS430F2013, der nur zwei KB Flashspeicher hat. Um dennoch (Debug-)Ausgaben zu ermöglichen habe ich eine mini I2C C-Lib für MSP430 µController erstellt (MSP430X20XX Reihe), die nur über ein USI Modul verfügen.


    Der MSP430-Controller wird damit zu einem I2C-Slave der von einem "größeren" Controller (I2C-Master) ausgelesen werden kann. Der Master arbeitet dann als I2C to Serial-Gateway. Dadurch ist es möglich z.B. Register-/Messwerte auf der am Master angeschlossenen Konsole auszugeben. Um mögl. wenig Speicherplatz zu verbrauchen kann dieser Slave nur senden, aber keine Daten empfangen. Man kann die Funktionalität aber auch erweitern, sodass z.B. ein Befehlsbyte empfangen wird, mit dem die Datenausgabe oder anderes auf dem Slave gesteuert werden kann.


    Falls es einen interessiert, der Code und ein Bild mit Beispielaufbau ist auf Github zu finden. Ich habe das Ganze mit einem Raspberry Pico als Master getestet, man könnte aber auch einen Arduino Nano oder Uno (-Clone) oder ESP32 usw. verwenden.

    Zu Schwingquarz und Oszillator hat der Hans64 ja schon einiges verlinkt. Da steht alles drin was man wissen muss/kann.


    Das Oszillatoren weniger anfällig für Temperaturschwankungen sind als Quarze, stimmt so pauschal nicht. In Verbindung mit dem µController bilden die externen Quarze ja auch einen Oszillator (logisch). Es gibt aber TCXO (Temperature Compensated Crystal Oscillator) für die das zutrifft.


    Die Kompatibilität bezüglich CMOS und TTL bezieht sich auf Logikbausteine. (H)CMOS (4XXX) die von 3-15V betrieben werden können und TTL Bausteine (74XXX, 74LSXXX usw.) die mit 5V betrieben werden. Außerdem gibt es noch Unterschiede beim Stromverbrauch und den Schaltzeiten. Genaueres dazu gibt es hier (Elektroniktutor) zu lesen.


    Was ICs oder eher Mikrocontroller/CPUs betrifft, ist die Angabe der Taktfrequenz i.d.R. ein Maximalwert, für den der Hersteller garantiert, dass das Device damit funktioniert, ohne Schaden zu nehmen. Natürlich kann man auch niedrigere Frequenzen nutzen. Das wird auch oft gemacht, wenn Schaltungen mögl. wenig Strom verbrauchen sollen. Weil mit steigender Taktfrequenz steigt die benötigte Leistung und Wärmeentwicklung.


    Man kann demnach µController/ CPUs auch mit einer höheren Taktfrequenz als angegeben betreiben (Übertakten). Allerdings hat das eine erhöhte Leistungsaufnahme und Wärmeentwicklung zur Folge, was den Kühlungsbedarf erhöht und sehr wahrscheinlich die Lebensdauer verringert.


    Es geht jetzt nicht mehr um das eigentliche "itoa" Problem. Vielmehr möchte ich beschreiben, was ich bei diesem kleinen Projekt gelernt habe. Um es vorweg zu nehmen, vermeintliche Kleinigkeiten können ordentlich Speicherplatz sparen.


    Zuerst nochmal der Quelltext mit dem ich probiert habe:


    Wenn man den Code der diese Funktion enthält compiliert, wird das Programm 678 Bytes groß. Ich hatte in meinem Programm eine Konstante BASE definiert, welche der Zahl 10 (U)nsigned entspricht. Geht man nun hin und macht aus der Definition #define BASE 10U ein #define BASE 10UL, so wird es nach einer erneuten Compilierung nur noch 614 Byte groß sein. Also nur, weil ein "unsigned" Wert (16 Bit Datentyp) zu einem unsigned long Wert (32 Bit Datentyp) gemacht wurde, wird das Programm kleiner. Das erscheint doch erst einmal widersinnig!


    Wenn man nun vergleicht, was der Compiler aus den beiden Versionen macht, wird aber klar, warum das so ist. Im Folgenden ist ein Auszug über die Speichernutzung dargestellt. Die Zahlen geben den Speicherplatzverbrauch in Byte an:


    Die 10U Variante:


    678 Bytes gesamt


    Offenbar werden hier zwei Unterprogramme für die Division verwendet div32u.asm.obj und div32s.asm.obj. Schaut man sich Speicheraufteilung der 10UL Variante an, sieht das so aus:


    614 Bytes gesamt


    Sofort fällt auf, dass nur noch eine Routine für die Division (div32u.asm.obj) verwendet wird. Dadurch, das ein Unterprogramm wegfällt, werden 64Byte eingespart. Nur durch einen einzigen zusätzlichen Buchstaben im Quellcode.


    Es ist in C/C++ also entscheidend auf Datentypen zu achten. Auch wenn man Konstanten verwendet. Eine sorgfältige Programmierung und die Kenntnis der "Feinheiten" einer Programmiersprache helfen effektiveren Code zu schreiben, was ja gerade bei µControllern mit ihren i.d.R. nicht gerade üppigen Speicherressourcen, viel ausmacht. Man sollte also nicht nur darauf achten, ob sich ein Programm fehlerfrei compilieren lässt, sondern auch noch andere Aspekte betrachten.


    Die itoa32 Funktion ist ja in einem Mainprogramm eingebettet. Es wurde aber nur an dieser Funktion eine Änderung vorgenommen. Betrachtet man jetzt die 28 Byte für die itoa32 Routine zuzüglich der 152 Byte für die benötigten Divisionsfunktionen (erste Version = 180 Byte gesamt) und vergleicht das mit 28 Byte + 88 Byte = 116 Byte (zweite Version), so wurde eine Ersparnis von immerhin gut 35%, nur durch die Anpassung eines Datentyps, erreicht.


    Und man kann auch gut erkennen wieviel Ressourcen Divisionen "fressen". Also wenn es geht -> vermeiden oder zumindest reduzieren.


    Pius hat also durchaus recht mit seiner Aussage, dass die Compiler schon sehr effektiv sind. Jedenfalls ist mein Programm, welches ich weiter unten in Beitrag #9 als Assembler Variante geschrieben habe, auch nicht mehr kleiner als diese C-Version mit dem angepassten Datentyp. Und das liegt daran, dass genau diese Umstellung auf eine Divisionsroutine in meinem Assemblercode die Ersparnis ausgemacht hat. Alles andere drum herum lässt sich (zumindest bei diesem Beispiel) auch in Assembler nicht, oder nur unwesentlich verkleinern.

    Ich nehme an, dass der im Screenshot abgebildete WLAN-Router/Accesspoint Netzwerkeinstellungen hat, die zu Deinem Netzbereich passen.

    Da offensichtlich auf Deinem Computer im "Netzwerk- und Freigabecenter" die Netzwerkerkennung eingeschaltet ist, tauchen alle Geräte auf, die zu Deiner Netzwerkkonfiguration passen. Wenn das Gerät nicht immer auftaucht, ist es vielleicht nicht permanent angeschaltet oder dessen Signal ist von schwankender Stärke.


    Es könnte evtl. auch ein Smartphone sein. Check mal die Geräte in Deinem Umfeld.


    Es ist nicht unbedingt ein Zeichen dafür, dass Dein Computer gehackt wurde.

    Ich habe gerade noch einmal etwas probiert und eine Variante ohne Konstanten-Array ausprobiert. Der Divisor wird bei jeder Ziffer neu ermittelt.

    Das erhöht der Rechenaufwand, erspart aber das Array mit immerhin 10 konstanten 32 Bit Werten.



    Nun hat das Gesamtprogramm (inkl. UART Konfiguration) mit der Funktion wie sie in #11 gepostet wurde 588 Bytes, mit dieser Variante hier hat es 566Bytes. Wirklich wichtig ist es, die "divisor" Variable als unsigned long zu definieren! Definiert man sie als (signed) long, wird das Programm 646Bytes groß =O! Diese Variante hier, dürfte auch um einiges langsamer sein. Beim Testen ist das aber nicht merklich gewesen. Sie ist bis jetzt, speicherplatzmäßig, die sparsamste.


    Viel mehr ist da wohl nicht mehr drin... nehme ich an.

    Unsere Antworten haben sich überschnitten. Die Fragen zum Assembler: Die Parameter einer C/C++ Funktion werden immer ab dem Register R12 bis R15 übernommen. Reicht das nicht aus, wird zusätzlich der Stack mitbenutzt. Zumindest ist das in der CCS Umgebung so.


    Am Ende einer ASM-Funktion kann man Rückgabewerte ab R12 schreiben. Das "landet" dann wieder in einer C-Variable, um es mal platt auszudrücken.

    Bei itoa32 und uitoa32 habe ich so den Stringpufferwert zurückgegeben, damit man Konstruktionen wie *pPuffer = itoa32(char* puffer, uint32_t zahl) schreiben kann.


    Ist aber gut das Du fragst. Dadurch ist mir aufgefallen, dass ich vergessen habe jenes Dokument zu verlinken, in dem genau das beschrieben ist (SLAA140A).


    Ich habe die übergebenen Werte, je nach Funktion, in R6-R9 kopiert, um später wieder darauf zurückgreifen zu können, weil die Registerwerte zwischenzeitlich verändert und an anderer Stelle aber wieder benötigt werden.


    Dein Einwand bezüglich *.B(yte) und *.W(ord) ist berechtigt. Das war etwas inkonsequent von mir. Weil es sich um einen 16Bit Controller handelt ist

    *.W eigentlich Standard und müsste gar nicht benutzt werden. Darum funktioniert PUSH und PUSH.W genau gleich. Wie du richtig vermutet hast, steht *.B für byteweise Operationen. Ich habe das W (fast immer) drangehangen weil ich dachte es ist dann offensichtlicher, dass es sich um eine Wordoperation handelt. Bei den PUSH Befehlen habe ich es schlicht vergessen. Ich bin da noch nicht stilsicher ;)


    Ich habe den Code zugegebener Maßen nicht von der Pike auf gebaut. Der Disassembler hat mir da schon viel geholfen. Ohne, hätte ich das nie hinbekommen. Und auch da sind die Ausdrücke nicht konsequent mit Erweiterung aufgeführt. Ich wäre spätestens bei der Division gescheitert. Aber durch die Namen der disassembelten Sprungadressen habe ich die Literatur zum EABI gefunden. Die hat mir weiter geholfen. Außerdem hätte ich wesentlich mehr Zeit benötigt.

    Hallo Pius,


    das macht richtig Freude mit Dir Gedanken auszutauschen. Da lerne ich doch immer wieder dazu. An die Variante, den Funktionszeiger der Ausgabefunktion mit an die "Umwandlungsroutine" zu geben, habe ich gar nicht gedacht. Wunderbar und ziemlich elegant. Super :):thumbup:.


    Ich habe deinen Code in einer 32 Bit Variante ausprobiert und es funktioniert sehr gut. Allerdings geht der Aufwand für die Divisor-Bestimmung sehr nach oben. Darum habe ich mir eine Variante mit einem Array ausgedacht. Das erspart auch eine Division, weil man den Array-Index als "Schalter" für die nächstkleinere 10er Potenz verwenden kann:

    Ich wüsste momentan aber nicht, wie man um den Speicherplatzverbrauch für die Konstanten herumkommt. Es sei denn, man rechnet wieder...


    Auch die gezeigte Division mit dem Bit-Shiften ist ja extrem gewitzt. Sowas hätte ich mir nie ausdenken können. Aber ich glaube, solche Tricks sind nicht notwendig. Dennoch sehr interessant.

    @Pius: ich hätte ja nicht gedacht, dass ich damit nochmal anfange, aber ich habe das Ganze mal in Assembler umgesetzt.

    Hab wieder viel gelernt :). Es wundert mich, dass ich das überhaupt in der recht kurzen Zeit hinbekommen habe.

    Es gilt ja in "Tonnen" von Dokumentation die richtigen Abschnitte zu finden. Demnächst nehme ich Dir deine letzte Variante mal vor. Momentan qualmt mir aber noch der Kopf.


    Ich habe drei Assembler Routinen gebaut, die auch aus C/C++ heraus aufrufbar sind.

    Die Funktionen sind:


    char* itoa32(char*, int32_t val);

    char* uitoa32(char*, uint32_t);

    void strrev(char*, uint8_t);


    Der itoa Befehl ist zwar auch in der MSP430 Toolchain vorhanden, allerdings

    - kann er nur bis 16 Bit verwendet werden

    - Die Funktion ist nur für signed int geeignet. Ein Wertebereich außerhalb von +32767/-32768 ist nicht darstellbar.

    - Die Funktion erzeugt Buchstabensalat wenn ein Zahlenüberlauf bei negativen Zahlen auftritt.


    Darum habe ich zwei Funktionen itoa32() und uitoa32() gebaut mit denen größere Wertebereiche dargestellt werden können. Einschränkung: Es funktioniert nur das dezimale Zahlensystem als Ausgabe. Die Funktion strrev() wird von beiden Funktionen benötigt, kann aber auch unabhängig davon verwendet werden. Die Funktion erledigt das schon in einem anderen Thread diskutierte Vertauschen einer Zeichenkette.


    Beim Assemblercode handelt sich um eine Umsetzung der itoa() Funktion zu dem in diesem Thread vom Knisterbein ein Teil des C-Codes gepostet wurde. Der Assemblercode spart noch ein paar Byte im Vergleich zur C-Variante ein (62 Byte). Das klingt nicht viel aber bei 2kb Flash, 128 Byte RAM kann es auf jedes Byte ankommen;). Die unsigned Variante uitoa32() ist wegen der nicht notwendigen Vorzeichenbehandlung noch etwas kleiner.


    Das itoa32 Objektfile ist 146 Byte groß, strrev braucht 26Byte und jetzt kommt es ... die 32 Bit Division braucht 88 Byte :/. Die Maindatei mit dem UART "Gedöhns" ist 224 Byte groß.


    Wen es interessiert:

    Hier ist der Code auf Github mit ein bisschen Beschreibung: MSP430-itoa32


    Es ist ein Beispielprogramm dabei, das Zeichen von einer seriellen Konsole entgegen nimmt und wenn ein "a" eingegeben wurde, wird eine Integerzahl in einen String umgewandelt und auf der Konsole angezeigt.


    Es wurde alles mit dem frei erhältlichen CCS (Code Composer Studio) von Texas Instruments umgesetzt. Doku zur Umsetzung ist in der README.md verlinkt.

    @Pius,


    ich habe Deine Vorschläge weitestgehend umgesetzt. Mit dem Puffer muss ich nochmal schauen. Es sind jetzt zwei Hilfsfunktionen herausgekommen. Eine für signed long int und eine für unsigned long int. Beide Funktionen sind nach dem von dir geposteten itoa Beispiel umgesetzt.


    Die Funktion, welche den String umdreht, dürfte Dir auch bekannt vorkommen ;).


    Das Ganze sieh jetzt so aus:



    Hallo Pius,


    vielen vielen Dank für deine Ausführungen und die Anmerkungen in den zwei Dateien. Da habe ich erst mal etwas damit zu tun mir das anzuschauen. :thumbup:


    Ich habe zwischenzeitlich auf Github gesucht und mir ein paar Quellcodes angeschaut. Dabei musste ich feststellen, dass doch viele im Wesentlichen die itoa Variante benutzten. Ich habe es in meinem Code versucht anders herum zu machen, damit am Ende der "String" nicht umgedreht werden muss. Aber bei unterschiedlichen Wortlängen ist das umständlicher, weil der Divisor jedes mal angepasst werden muss (int, long int usw.).


    Darum werde ich auf die von Dir vorgeschlagene Version umsteigen. Wie man effektiv ein Array umdreht, hatten wir hier ja schon in einem anderen Thread ;).


    Was den Speicher betrifft, erschien mir eine "dynamische" Variante zu aufwändig. Letztendlich muss der Speicher verfügbar sein, sei es statisch oder dynamisch. Ich vermute Du meinst mit "Buffer auf dem Stack anlegen" die "malloc" Funktion. Jedenfalls muss man sich hier auch wieder um die Freigabe des Speichers kümmern. Ausprobiert habe ich das aber noch nicht.

    Ob der Buffer jetzt lokal oder global ist, sehe ich jetzt recht leidenschaftslos. Ich habe es bei meinem Versuch lokal gemacht, weil ich sonst keinen Buffer brauchte. Außerdem ist es in der Funktion gekapselt und man muss sich "außerhalb" keine Gedanken drum machen.


    Meine Intension ist tatsächlich nur eine oder mehrere Hilfsfunktionen für die serielle Ausgabe. Ich denke das funktioniert ohne Zwischenspeicher, wenn man die UART Ausgabe direkt bei der Zahlenkonvertierung durchführt. An einem Beispiel bin ich natürlich interessiert.


    Aber ich werde mir jetzt erst mal Deine Dateien anschauen.


    Danke noch einmal :).

    Hallo zusammen,


    da µController oft sehr wenig Speicher haben muss man doch so manches selber erledigen, weil fertige Bibliotheksfunktionen zu viel Speicher benötigen.

    Bisher habe ich es mir bei der seriellen Übertagung recht einfach gemacht, indem ich mir einen String mit der sprintf Funktion zusammen gebaut habe, wenn ich Integer-Variablen auf der seriellen Konsole ausgeben wollte. Oder ich habe das allseits bekannte Serial.print() vom Arduino Framework verwendet.


    Nun habe ich aber einen µController der sehr wenig Speicher hat und deshalb keine Systembibliotheken verwendet werden können. Um dennoch Werte seriell ausgeben zu können, muss ich mir selber aus Integer-Variablen einen String bauen.


    Beispiel:


    Diesen Code angewandt, kann ich beispielsweiser mit:

    eine Integer-Variable über eine serielle Schnittstelle ausgeben.


    Meine Frage bezieht sich auf obigen Quellcode. Geht das noch besser, schneller, kürzer? Hat jemand einen Tipp für mich?